KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_symbol_import_reconciler.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
20#include <memory>
21#include <vector>
22
23#include <qa_utils/file_utils.h>
25
26#include <wx/dir.h>
27#include <wx/file.h>
28#include <wx/filefn.h>
29#include <wx/filename.h>
30
31#include <lib_id.h>
32#include <lib_symbol.h>
33#include <pgm_base.h>
34#include <project.h>
35#include <project_sch.h>
36#include <reporter.h>
37#include <schematic.h>
38#include <sch_io/sch_io.h>
39#include <sch_io/sch_io_mgr.h>
40#include <sch_screen.h>
41#include <sch_sheet.h>
42#include <sch_sheet_path.h>
43#include <sch_symbol.h>
49
51
52
53namespace
54{
56struct STAGED_PROJECT_FIXTURE
57{
58 STAGED_PROJECT_FIXTURE() :
59 m_staged( Pgm().GetSettingsManager(), wxS( "symreconcile-qa" ), wxS( "symreconcile" ) )
60 {
61 Pgm().GetLibraryManager().LoadProjectTables( m_staged.Project().GetProjectDirectory() );
62 }
63
64 KI_TEST::SCOPED_TEMP_PROJECT m_staged;
65};
66
67
68wxString easyEdaProV3Archive()
69{
70 return wxString::FromUTF8( KI_TEST::GetTestDataRootDir()
71 + "pcbnew/plugins/easyedapro/ProProject_LS2K0300Core_2025-11-14.epro2" );
72}
73
74
76bool hasSymbolLib( const wxString& aPath )
77{
78 wxDir dir( aPath );
79 wxString name;
80
81 if( !dir.IsOpened() )
82 return false;
83
84 wxString spec = wxS( "*." ) + wxString( FILEEXT::KiCadSymbolLibFileExtension );
85
86 return dir.GetFirst( &name, spec, wxDIR_FILES );
87}
88
89
91struct IMPORTED_SAMPLE
92{
93 IO_RELEASER<SCH_IO> m_plugin;
94 std::unique_ptr<SCHEMATIC> m_schematic;
95 std::vector<std::unique_ptr<LIB_SYMBOL>> m_definitions;
96 wxString m_sourceDir;
97};
98
99
100IMPORTED_SAMPLE importSample( PROJECT& aProject )
101{
102 IMPORTED_SAMPLE sample;
103
104 wxString sep = wxFileName::GetPathSeparator();
105 sample.m_sourceDir = aProject.GetProjectPath() + wxT( "import-src" );
106 BOOST_REQUIRE( wxFileName::Mkdir( sample.m_sourceDir, wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL ) );
107
108 wxFileName archiveFile( sample.m_sourceDir + sep, wxS( "sample" ), wxS( "epro2" ) );
109 BOOST_REQUIRE( wxCopyFile( easyEdaProV3Archive(), archiveFile.GetFullPath() ) );
110
111 sample.m_schematic = std::make_unique<SCHEMATIC>( nullptr );
112 sample.m_schematic->SetProject( &aProject );
113
114 sample.m_plugin.reset( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_EASYEDAPRO_V3 ) );
115 BOOST_REQUIRE( sample.m_plugin );
116
117 SCH_SHEET* rootSheet = nullptr;
118 BOOST_REQUIRE_NO_THROW( rootSheet = sample.m_plugin->LoadSchematicFile(
119 archiveFile.GetFullPath(), sample.m_schematic.get() ) );
120 BOOST_REQUIRE( rootSheet );
121
122 sample.m_schematic->RefreshHierarchy();
123
124 for( LIB_SYMBOL* symbol : sample.m_plugin->GetImportedCachedLibrarySymbols() )
125 sample.m_definitions.emplace_back( symbol );
126
127 BOOST_REQUIRE_GT( sample.m_definitions.size(), 0 );
128
129 return sample;
130}
131
132
133std::vector<SCH_SYMBOL*> placedSymbols( SCHEMATIC& aSchematic )
134{
135 std::vector<SCH_SYMBOL*> symbols;
136
137 for( const SCH_SHEET_PATH& sheetPath : aSchematic.Hierarchy() )
138 {
139 if( SCH_SCREEN* screen = sheetPath.LastScreen() )
140 {
141 for( SCH_ITEM* item : screen->Items().OfType( SCH_SYMBOL_T ) )
142 symbols.push_back( static_cast<SCH_SYMBOL*>( item ) );
143 }
144 }
145
146 return symbols;
147}
148
149
151void publishLibrary( PROJECT& aProject, SYMBOL_LIBRARY_ADAPTER& aAdapter, const wxString& aNickname,
152 const wxString& aFileStem, const LIB_SYMBOL& aSymbol )
153{
154 wxFileName libFn( aProject.GetProjectPath(), aFileStem, FILEEXT::KiCadSymbolLibFileExtension );
155
156 IO_RELEASER<SCH_IO> pi( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_KICAD ) );
157 BOOST_REQUIRE( pi );
158
159 pi->CreateLibrary( libFn.GetFullPath() );
160
161 auto copy = std::make_unique<LIB_SYMBOL>( aSymbol );
162 copy->SetLibId( LIB_ID( aNickname, copy->GetName() ) );
163 pi->SaveSymbol( libFn.GetFullPath(), std::move( copy ) );
164
165 LIBRARY_TABLE* table = aAdapter.ProjectTable().value_or( nullptr );
167
168 LIBRARY_TABLE_ROW& row = table->InsertRow();
169 row.SetNickname( aNickname );
170 row.SetURI( wxS( "${KIPRJMOD}/" ) + libFn.GetFullName() );
171 row.SetType( wxS( "KiCad" ) );
173
174 BOOST_REQUIRE( table->Save().has_value() );
175 aAdapter.LoadOne( aNickname );
176}
177
178
180struct COLLISION_CANDIDATE
181{
182 SCH_SYMBOL* m_symbol = nullptr;
183 LIB_SYMBOL* m_definition = nullptr;
184 wxString m_nickname;
185 wxString m_name;
186};
187
188
189COLLISION_CANDIDATE findCandidate( IMPORTED_SAMPLE& aSample )
190{
191 COLLISION_CANDIDATE candidate;
192
193 for( SCH_SYMBOL* symbol : placedSymbols( *aSample.m_schematic ) )
194 {
195 wxString nick = symbol->GetLibId().GetUniStringLibNickname();
196 wxString name = symbol->GetLibId().GetUniStringLibItemName();
197
198 if( nick.IsEmpty() || name.IsEmpty() )
199 continue;
200
201 for( const std::unique_ptr<LIB_SYMBOL>& def : aSample.m_definitions )
202 {
203 if( def->GetLibId().GetUniStringLibItemName() != name
204 || def->GetGraphicalPins( ALL_UNITS, ALL_BODY_STYLES ).empty() )
205 {
206 continue;
207 }
208
209 candidate.m_symbol = symbol;
210 candidate.m_definition = def.get();
211 candidate.m_nickname = nick;
212 candidate.m_name = name;
213
214 return candidate;
215 }
216 }
217
218 return candidate;
219}
220} // namespace
221
222
223BOOST_FIXTURE_TEST_SUITE( SymbolImportReconciler, STAGED_PROJECT_FIXTURE )
224
225
226// EasyEDA Pro v3 hands definitions over the standard hook, leaving the source directory untouched
227// fails on revert, since LoadSchematicFile then publishes its own .kicad_sym beside the archive
228BOOST_AUTO_TEST_CASE( EasyEdaProV3SchematicResolvesToGeneratedCache )
229{
230 PROJECT& project = m_staged.Project();
231
232 IMPORTED_SAMPLE sample = importSample( project );
233 SCHEMATIC& schematic = *sample.m_schematic;
234
235 // the importer must not have published anything of its own beside the archive
236 BOOST_CHECK_MESSAGE( !hasSymbolLib( sample.m_sourceDir ),
237 "LoadSchematicFile wrote a library into the source directory" );
238
240 BOOST_REQUIRE( adapter );
241
242 const wxString cacheNick = wxS( "ls2k0300-import-syms" );
243 SYMBOL_IMPORT_RECONCILER reconciler( *adapter, project.GetProjectPath() );
244
246 reconciler.Reconcile( &schematic, std::move( sample.m_definitions ), cacheNick, {} );
247
248 // the cache lands in the project directory, not next to the source archive
249 BOOST_CHECK_EQUAL( result.m_cacheNickname, cacheNick );
250 BOOST_CHECK_GT( result.m_savedToCache, 0 );
251
252 wxFileName cacheFile( project.GetProjectPath(), cacheNick,
254 BOOST_CHECK_MESSAGE( wxFileExists( cacheFile.GetFullPath() ),
255 "Generated .kicad_sym was not published into the project" );
256
257 LIBRARY_TABLE* projectTable = adapter->ProjectTable().value_or( nullptr );
258 BOOST_REQUIRE( projectTable );
259 BOOST_CHECK( projectTable->HasRow( cacheNick ) );
260
261 // every placed symbol resolves through the adapter after reconciliation
262 int resolved = 0;
263
264 for( const SCH_SHEET_PATH& sheetPath : schematic.Hierarchy() )
265 {
266 SCH_SCREEN* screen = sheetPath.LastScreen();
267
268 if( !screen )
269 continue;
270
271 for( SCH_ITEM* item : screen->Items().OfType( SCH_SYMBOL_T ) )
272 {
273 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
274 wxString name = symbol->GetLibId().GetUniStringLibItemName();
275
276 if( name.IsEmpty() )
277 continue;
278
279 wxString nick = symbol->GetLibId().GetUniStringLibNickname();
280
281 BOOST_CHECK_MESSAGE( !nick.IsEmpty(),
282 wxString::Format( "Symbol '%s' left with empty nickname", name ) );
283 BOOST_CHECK_MESSAGE( adapter->LoadSymbol( nick, name ) != nullptr,
284 wxString::Format( "LIB_ID '%s:%s' does not resolve after "
285 "reconciliation", nick, name ) );
286 resolved++;
287 }
288 }
289
290 BOOST_CHECK_GT( resolved, 0 );
291 BOOST_CHECK_EQUAL( result.m_unresolved, 0 );
292}
293
294
295// EasyEDA Pro v2 wrote its .kicad_sym beside the source archive, exactly as v3 did
296BOOST_AUTO_TEST_CASE( EasyEdaProV2LeavesSourceDirectoryClean )
297{
298 PROJECT& project = m_staged.Project();
299
300 wxString sep = wxFileName::GetPathSeparator();
301 wxString srcDir = project.GetProjectPath() + wxT( "import-src" );
302 BOOST_REQUIRE( wxFileName::Mkdir( srcDir, wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL ) );
303
304 wxString source = wxString::FromUTF8(
306 + "pcbnew/plugins/easyedapro/ProProject_Yuzuki Chameleon_2023-09-02.epro" );
307 BOOST_REQUIRE( wxFileExists( source ) );
308
309 wxFileName archiveFile( srcDir + sep, wxS( "sample" ), wxS( "epro" ) );
310 BOOST_REQUIRE( wxCopyFile( source, archiveFile.GetFullPath() ) );
311
312 SCHEMATIC schematic( nullptr );
313 schematic.SetProject( &project );
314
315 IO_RELEASER<SCH_IO> plugin( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_EASYEDAPRO ) );
316 BOOST_REQUIRE( plugin );
317
318 SCH_SHEET* rootSheet = nullptr;
319 BOOST_REQUIRE_NO_THROW(
320 rootSheet = plugin->LoadSchematicFile( archiveFile.GetFullPath(), &schematic ) );
321 BOOST_REQUIRE( rootSheet );
322
323 BOOST_CHECK_MESSAGE( !hasSymbolLib( srcDir ),
324 "LoadSchematicFile wrote a library into the source directory" );
325
326 // the definitions still reach the reconciler through the standard hook
327 std::vector<LIB_SYMBOL*> raw = plugin->GetImportedCachedLibrarySymbols();
328 BOOST_CHECK_GT( raw.size(), 0 );
329
330 for( LIB_SYMBOL* symbol : raw )
331 delete symbol;
332}
333
334
335// An unrelated library that happens to carry the nickname the importer emitted must not swallow
336// the imported definition; without the provenance check the symbol relinks to the wrong part
337BOOST_AUTO_TEST_CASE( CollidingNicknameDoesNotStealTheLink )
338{
339 PROJECT& project = m_staged.Project();
340
341 IMPORTED_SAMPLE sample = importSample( project );
342 COLLISION_CANDIDATE candidate = findCandidate( sample );
343 BOOST_REQUIRE( candidate.m_symbol );
344
346 BOOST_REQUIRE( adapter );
347
348 // a pinless namesake registered under the importer's nickname: same name, different part
349 LIB_SYMBOL impostor( candidate.m_name );
351 publishLibrary( project, *adapter, candidate.m_nickname, wxS( "impostor" ), impostor );
352
353 const wxString cacheNick = wxS( "collide-import-syms" );
354 SYMBOL_IMPORT_RECONCILER reconciler( *adapter, project.GetProjectPath() );
355
357 sample.m_schematic.get(), std::move( sample.m_definitions ), cacheNick, {} );
358
359 BOOST_CHECK_EQUAL( result.m_cacheNickname, cacheNick );
360
361 // the imported definition is kept in the cache rather than dropped for the namesake
362 BOOST_CHECK_EQUAL( candidate.m_symbol->GetLibId().GetUniStringLibNickname(), cacheNick );
363
364 LIB_SYMBOL* linked = adapter->LoadSymbol( cacheNick, candidate.m_name );
365 BOOST_REQUIRE( linked );
366 BOOST_CHECK_GT( linked->GetGraphicalPins( ALL_UNITS, ALL_BODY_STYLES ).size(), 0 );
367}
368
369
370// The same nickname collision resolves the other way when the library really does hold the part,
371// so the equivalence escape hatch keeps a genuine match out of the generated cache
372BOOST_AUTO_TEST_CASE( EquivalentNamesakeTakesTheLink )
373{
374 PROJECT& project = m_staged.Project();
375
376 IMPORTED_SAMPLE sample = importSample( project );
377 COLLISION_CANDIDATE candidate = findCandidate( sample );
378 BOOST_REQUIRE( candidate.m_symbol );
379
381 BOOST_REQUIRE( adapter );
382
383 publishLibrary( project, *adapter, candidate.m_nickname, wxS( "genuine" ),
384 *candidate.m_definition );
385
386 const wxString cacheNick = wxS( "equivalent-import-syms" );
387 wxString sourceNick = candidate.m_nickname;
388 SYMBOL_IMPORT_RECONCILER reconciler( *adapter, project.GetProjectPath() );
389
391 sample.m_schematic.get(), std::move( sample.m_definitions ), cacheNick, {} );
392
393 BOOST_CHECK_EQUAL( candidate.m_symbol->GetLibId().GetUniStringLibNickname(), sourceNick );
394 BOOST_CHECK_GT( result.m_linkedToSource, 0 );
395}
396
397
398// Two source libraries supplying different symbols under one bare name must both survive the
399// cache; keying the cache by the bare name alone dropped the second and relinked its instance
400BOOST_AUTO_TEST_CASE( SameNameFromDifferentLibrariesKeepsBothDefinitions )
401{
402 PROJECT& project = m_staged.Project();
403
404 IMPORTED_SAMPLE sample = importSample( project );
405
406 // two real imported symbols that a pin count tells apart
407 SCH_SYMBOL* firstPlaced = nullptr;
408 SCH_SYMBOL* secondPlaced = nullptr;
409
410 for( SCH_SYMBOL* symbol : placedSymbols( *sample.m_schematic ) )
411 {
412 const std::unique_ptr<LIB_SYMBOL>& part = symbol->GetLibSymbolRef();
413
414 if( !part || part->GetGraphicalPins( ALL_UNITS, ALL_BODY_STYLES ).empty() )
415 continue;
416
417 if( !firstPlaced )
418 {
419 firstPlaced = symbol;
420 }
421 else if( part->GetGraphicalPins( ALL_UNITS, ALL_BODY_STYLES ).size()
422 != firstPlaced->GetLibSymbolRef()->GetGraphicalPins( ALL_UNITS, ALL_BODY_STYLES ).size() )
423 {
424 secondPlaced = symbol;
425 }
426
427 if( secondPlaced )
428 break;
429 }
430
431 BOOST_REQUIRE( firstPlaced );
432 BOOST_REQUIRE( secondPlaced );
433
434 const wxString sharedName = wxS( "SHARED_SYM" );
435 const size_t firstPins = firstPlaced->GetLibSymbolRef()->GetGraphicalPins( ALL_UNITS, ALL_BODY_STYLES ).size();
436 const size_t secondPins = secondPlaced->GetLibSymbolRef()->GetGraphicalPins( ALL_UNITS, ALL_BODY_STYLES ).size();
437
438 std::vector<std::unique_ptr<LIB_SYMBOL>> defs;
439
440 // the same bare name under two source libraries, both placed and defined
441 auto relabel = [&]( SCH_SYMBOL* aSymbol, const wxString& aNickname )
442 {
443 auto def = std::make_unique<LIB_SYMBOL>( *aSymbol->GetLibSymbolRef() );
444 def->SetName( sharedName );
445 def->SetLibId( LIB_ID( aNickname, sharedName ) );
446 defs.push_back( std::move( def ) );
447
448 aSymbol->SetLibId( LIB_ID( aNickname, sharedName ) );
449 };
450
451 relabel( firstPlaced, wxS( "libAlpha" ) );
452 relabel( secondPlaced, wxS( "libBeta" ) );
453
455 BOOST_REQUIRE( adapter );
456
457 const wxString cacheNick = wxS( "namecollide-import-syms" );
459 SYMBOL_IMPORT_RECONCILER reconciler( *adapter, project.GetProjectPath(), reporter );
460
462 reconciler.Reconcile( sample.m_schematic.get(), std::move( defs ), cacheNick, {} );
463
464 BOOST_CHECK_EQUAL( result.m_cacheNickname, cacheNick );
465
466 LIB_ID firstId = firstPlaced->GetLibId();
467 LIB_ID secondId = secondPlaced->GetLibId();
468
469 BOOST_CHECK_EQUAL( firstId.GetUniStringLibNickname(), cacheNick );
470 BOOST_CHECK_EQUAL( secondId.GetUniStringLibNickname(), cacheNick );
471 BOOST_CHECK_MESSAGE( firstId.GetUniStringLibItemName() != secondId.GetUniStringLibItemName(),
472 "Symbols from two source libraries share one cache item name" );
473
474 // each instance still resolves to the symbol it was imported as
475 LIB_SYMBOL* firstLinked = adapter->LoadSymbol( cacheNick, firstId.GetUniStringLibItemName() );
476 LIB_SYMBOL* secondLinked = adapter->LoadSymbol( cacheNick, secondId.GetUniStringLibItemName() );
477
478 BOOST_REQUIRE( firstLinked );
479 BOOST_REQUIRE( secondLinked );
480 BOOST_CHECK_EQUAL( firstLinked->GetGraphicalPins( ALL_UNITS, ALL_BODY_STYLES ).size(), firstPins );
481 BOOST_CHECK_EQUAL( secondLinked->GetGraphicalPins( ALL_UNITS, ALL_BODY_STYLES ).size(), secondPins );
482
483 // the user is told which symbol the cache renamed
484 const wxString renamed = firstId.GetUniStringLibItemName() == sharedName ? secondId.GetUniStringLibItemName()
485 : firstId.GetUniStringLibItemName();
486
487 BOOST_CHECK_MESSAGE( reporter.GetMessages().Contains( wxString::Format( wxS( "renamed to '%s'" ), renamed ) ),
488 "Cache rename was not reported" );
489}
490
491
492// A project row already owning the cache nickname is a user library even when no file sits at the
493// generated path, so publishing must not rewrite its URI
494BOOST_AUTO_TEST_CASE( ExistingUserRowIsNotRepurposed )
495{
496 PROJECT& project = m_staged.Project();
497
498 IMPORTED_SAMPLE sample = importSample( project );
499
501 BOOST_REQUIRE( adapter );
502
503 const wxString cacheNick = wxS( "row-import-syms" );
504
505 // the user's row owns the nickname but points at a file of its own
506 LIB_SYMBOL owned( wxS( "UserPart" ) );
507 publishLibrary( project, *adapter, cacheNick, wxS( "user-owned" ), owned );
508
509 LIBRARY_TABLE* table = adapter->ProjectTable().value_or( nullptr );
511
512 LIBRARY_TABLE_ROW* row = table->Row( cacheNick ).value_or( nullptr );
513 BOOST_REQUIRE( row );
514
515 const wxString uriBefore = row->URI();
516
517 SYMBOL_IMPORT_RECONCILER reconciler( *adapter, project.GetProjectPath() );
518
520 sample.m_schematic.get(), std::move( sample.m_definitions ), cacheNick, {} );
521
522 BOOST_CHECK( result.m_cacheNickname.IsEmpty() );
523 BOOST_CHECK_EQUAL( row->URI(), uriBefore );
524
525 wxFileName cacheFile( project.GetProjectPath(), cacheNick, wxString( FILEEXT::KiCadSymbolLibFileExtension ) );
526 BOOST_CHECK_MESSAGE( !wxFileExists( cacheFile.GetFullPath() ),
527 "Published a cache over a nickname the user already owns" );
528}
529
530
531// A cache whose table row cannot be persisted is gone on restart, so it must not be claimed
532BOOST_AUTO_TEST_CASE( UnsavableTableLeavesCacheUnclaimed )
533{
534 PROJECT& project = m_staged.Project();
535
537 BOOST_REQUIRE( adapter );
538
539 LIBRARY_TABLE* table = adapter->ProjectTable().value_or( nullptr );
541 BOOST_REQUIRE( table->Save().has_value() );
542
543 wxFileName tableFn( table->Path() );
544 tableFn.SetPermissions( wxS_IRUSR | wxS_IRGRP | wxS_IROTH );
545
546 // CI containers commonly run as root, where the permission bits do not deny access
547 if( tableFn.IsFileWritable() )
548 {
549 BOOST_TEST_MESSAGE( "Skipping read-only table check; file remains writable (running as root?)" );
550 tableFn.SetPermissions( wxS_IRUSR | wxS_IWUSR );
551 return;
552 }
553
554 IMPORTED_SAMPLE sample = importSample( project );
555
556 const wxString cacheNick = wxS( "rotable-import-syms" );
557 SYMBOL_IMPORT_RECONCILER reconciler( *adapter, project.GetProjectPath() );
558
559 SYMBOL_IMPORT_RECONCILE_RESULT result = reconciler.Reconcile( sample.m_schematic.get(),
560 std::move( sample.m_definitions ),
561 cacheNick, {} );
562
563 BOOST_CHECK( result.m_cacheNickname.IsEmpty() );
564 BOOST_CHECK_EQUAL( result.m_linkedToCache, 0 );
565 BOOST_CHECK_GT( result.m_unresolved, 0 );
566
567 tableFn.SetPermissions( wxS_IRUSR | wxS_IWUSR );
568}
569
570
571// An unregistered library already sitting at the cache path must never be overwritten
572BOOST_AUTO_TEST_CASE( ExistingUserLibraryIsNotClobbered )
573{
574 PROJECT& project = m_staged.Project();
575
576 IMPORTED_SAMPLE sample = importSample( project );
577
579 BOOST_REQUIRE( adapter );
580
581 const wxString cacheNick = wxS( "victim-import-syms" );
582
583 wxFileName victim( project.GetProjectPath(), cacheNick,
585
586 const wxString sentinel = wxS( "(kicad_symbol_lib (version 20231120) (generator \"qa\"))" );
587 BOOST_REQUIRE( wxFile( victim.GetFullPath(), wxFile::write ).Write( sentinel ) );
588
589 SYMBOL_IMPORT_RECONCILER reconciler( *adapter, project.GetProjectPath() );
590
592 sample.m_schematic.get(), std::move( sample.m_definitions ), cacheNick, {} );
593
594 // the symbols stay unresolved rather than the file being taken over
595 BOOST_CHECK( result.m_cacheNickname.IsEmpty() );
596 BOOST_CHECK_GT( result.m_unresolved, 0 );
597
598 wxString contents;
599 wxFile readBack( victim.GetFullPath(), wxFile::read );
600 BOOST_REQUIRE( readBack.ReadAll( &contents ) );
601 BOOST_CHECK_EQUAL( contents, sentinel );
602}
603
604
const char * name
EE_TYPE OfType(KICAD_T aType) const
Definition sch_rtree.h:248
std::optional< LIBRARY_TABLE * > ProjectTable() const
Retrieves the project library table for this adapter type, or nullopt if one doesn't exist.
void LoadProjectTables(std::initializer_list< LIBRARY_TABLE_TYPE > aTablesToLoad={})
(Re)loads the project library tables in the given list, or all tables if no list is given
void SetNickname(const wxString &aNickname)
void SetType(const wxString &aType)
void SetURI(const wxString &aUri)
void SetScope(LIBRARY_TABLE_SCOPE aScope)
const wxString & URI() const
bool HasRow(const wxString &aNickname) const
A logical library item identifier and consists of various portions much like a URI.
Definition lib_id.h:45
const wxString GetUniStringLibItemName() const
Get strings for display messages in dialogs.
Definition lib_id.h:108
const wxString GetUniStringLibNickname() const
Definition lib_id.h:84
Define a library symbol object.
Definition lib_symbol.h:114
std::vector< SCH_PIN * > GetGraphicalPins(int aUnit=0, int aBodyStyle=0) const override
Graphical pins: Return schematic pin objects as drawn (unexpanded), filtered by unit/body.
virtual LIBRARY_MANAGER & GetLibraryManager() const
Definition pgm_base.h:125
static SYMBOL_LIBRARY_ADAPTER * SymbolLibAdapter(PROJECT *aProject)
Accessor for project symbol library manager adapter.
Container for project specific data.
Definition project.h:63
virtual const wxString GetProjectPath() const
Return the full path of the project.
Definition project.cpp:183
Holds all the data relating to one schematic.
Definition schematic.h:149
SCH_SHEET_LIST Hierarchy() const
Return the full schematic flattened hierarchical sheet list.
void SetProject(PROJECT *aPrj)
void RefreshHierarchy()
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:170
EE_RTREE & Items()
Get the full RTree, usually for iterating.
Definition sch_screen.h:122
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition sch_sheet.h:48
Schematic symbol object.
Definition sch_symbol.h:73
void SetLibId(const LIB_ID &aName)
const LIB_ID & GetLibId() const override
Definition sch_symbol.h:163
std::unique_ptr< LIB_SYMBOL > & GetLibSymbolRef()
Definition sch_symbol.h:182
Frame-independent, non-interactive service that reconciles the symbol-library references of a freshly...
SYMBOL_IMPORT_RECONCILE_RESULT Reconcile(SCHEMATIC *aSchematic, std::vector< std::unique_ptr< LIB_SYMBOL > > aDefinitions, const wxString &aCacheNickname, const std::vector< wxString > &aSourceLibNicknames)
Reconcile aSchematic against the importer definitions and the provenance source libraries.
An interface to the global shared library manager that is schematic-specific and linked to one projec...
std::optional< LIB_STATUS > LoadOne(LIB_DATA *aLib) override
Loads or reloads the given library, if it exists.
LIB_SYMBOL * LoadSymbol(const wxString &aNickname, const wxString &aName)
Load a LIB_SYMBOL having aName from the library given by aNickname.
A wrapper for reporting to a wxString object.
Definition reporter.h:242
static const std::string KiCadSymbolLibFileExtension
std::string source
std::unique_ptr< T > IO_RELEASER
Helper to hold and release an IO_BASE object when exceptions are thrown.
Definition io_mgr.h:33
@ SCH_SYMBOL
one item stream of a Schematic Symbol Library
std::string GetTestDataRootDir()
PGM_BASE & Pgm()
The global program "get" accessor.
see class PGM_BASE
Definition of the SCH_SHEET_PATH and SCH_SHEET_LIST classes for Eeschema.
Outcome of a post-import symbol-library reconciliation pass.
#define ALL_UNITS
Definition symbol.h:150
#define ALL_BODY_STYLES
Definition symbol.h:151
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_AUTO_TEST_SUITE_END()
IbisParser parser & reporter
BOOST_TEST_MESSAGE("Polyline has "<< chain.PointCount()<< " points")
BOOST_AUTO_TEST_CASE(EasyEdaProV3SchematicResolvesToGeneratedCache)
wxString result
Test unit parsing edge cases and error handling.
BOOST_CHECK_EQUAL(result, "25.4")
@ SCH_SYMBOL_T
Definition typeinfo.h:168
Definition of file extensions used in Kicad.