KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_symbol_library_manager.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 (C) 2023 Wayne Stambaugh <[email protected]>
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software: you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation, either version 3 of the License, or (at your
10 * option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 */
20
25
27
28// Code under test
31#include <sch_field.h>
34#include <sch_io/sch_io_mgr.h>
35#include <richio.h>
36
37#include <wx/filename.h>
38
46
47
48BOOST_FIXTURE_TEST_SUITE( SymbolLibraryManager, SYMBOL_LIBRARY_MANAGER_TEST_FIXTURE )
49
50
51
54BOOST_AUTO_TEST_CASE( SymbolBuffer )
55{
56 std::unique_ptr<LIB_SYMBOL> symbol = std::make_unique<LIB_SYMBOL>( wxS( "Symbol" ) );
57 std::unique_ptr<SCH_SCREEN> screen = std::make_unique<SCH_SCREEN>();
58
59 LIB_SYMBOL& symbolRef = *symbol;
60
61 SYMBOL_BUFFER buffer( std::move( symbol ), std::move( screen ) );
62
63 BOOST_CHECK( !buffer.IsModified() );
64 BOOST_CHECK( &buffer.GetSymbol() == &symbolRef );
65 BOOST_CHECK( buffer.GetOriginal() == symbolRef );
66
67 buffer.GetScreen()->SetContentModified();
68 BOOST_CHECK( buffer.IsModified() );
69
70 std::unique_ptr<LIB_SYMBOL> originalSymbol =
71 std::make_unique<LIB_SYMBOL>( wxS( "OriginalSymbol" ) );
72 LIB_SYMBOL& originalSymbolRef = *originalSymbol;
73
74 buffer.SetOriginal( std::move( originalSymbol ) );
75
76 BOOST_CHECK( &buffer.GetOriginal() == &originalSymbolRef );
77 BOOST_CHECK( buffer.GetOriginal() == originalSymbolRef );
78 BOOST_CHECK( &buffer.GetSymbol() != &buffer.GetOriginal() );
79}
80
81
86{
87 wxArrayString symbolNames;
88 LIB_BUFFER libBuffer( wxS( "TestLibrary" ) );
89
90 BOOST_CHECK( !libBuffer.IsModified() );
91 BOOST_CHECK_EQUAL( libBuffer.GetHash(), 1 );
92
93 auto parentSymbol1 = std::make_unique<LIB_SYMBOL>( wxS( "Parent1" ) );
94 // A but clunky, but real code would get symbol from the LIB_BUFFER
95 // via GetSymbol etc, rather than retaining a reference after construction.
96 LIB_SYMBOL& parentSymbol1Ref = *parentSymbol1;
97
98 BOOST_CHECK_EQUAL( libBuffer.GetSymbol( parentSymbol1->GetName() ), nullptr );
99
100 parentSymbol1->GetValueField().SetText( parentSymbol1->GetName() );
101 libBuffer.CreateBuffer( std::move( parentSymbol1 ), std::make_unique<SCH_SCREEN>() );
102 BOOST_CHECK( libBuffer.GetSymbol( parentSymbol1Ref.GetName() ) == &parentSymbol1Ref );
103 BOOST_CHECK( !libBuffer.HasDerivedSymbols( parentSymbol1Ref.GetName() ) );
104 BOOST_CHECK_EQUAL( libBuffer.GetHash(), 2 );
105
106 libBuffer.GetSymbolNames( symbolNames );
107 BOOST_CHECK_EQUAL( symbolNames.GetCount(), 1 );
108 BOOST_CHECK_EQUAL( symbolNames[0], parentSymbol1Ref.GetName() );
109
110 symbolNames.Clear();
111 libBuffer.GetSymbolNames( symbolNames, SYMBOL_NAME_FILTER::ROOT_ONLY );
112 BOOST_CHECK_EQUAL( symbolNames.GetCount(), 1 );
113 BOOST_CHECK_EQUAL( symbolNames[0], parentSymbol1Ref.GetName() );
114
115 symbolNames.Clear();
116 libBuffer.GetSymbolNames( symbolNames, SYMBOL_NAME_FILTER::DERIVED_ONLY );
117 BOOST_CHECK_EQUAL( symbolNames.GetCount(), 0 );
118
119 auto childSymbol1 = std::make_unique<LIB_SYMBOL>( wxS( "Child1" ) );
120 LIB_SYMBOL& childSymbol1Ref = *childSymbol1;
121
122 childSymbol1->SetParent( &parentSymbol1Ref );
123 childSymbol1->GetValueField().SetText( childSymbol1->GetName() );
124 libBuffer.CreateBuffer( std::move( childSymbol1 ), std::make_unique<SCH_SCREEN>() );
125 BOOST_CHECK( libBuffer.GetSymbol( childSymbol1Ref.GetName() ) == &childSymbol1Ref );
126 BOOST_CHECK( libBuffer.HasDerivedSymbols( parentSymbol1Ref.GetName() ) );
127 BOOST_CHECK_EQUAL( libBuffer.GetHash(), 3 );
128
129 symbolNames.Clear();
130 libBuffer.GetSymbolNames( symbolNames );
131 BOOST_CHECK_EQUAL( symbolNames.GetCount(), 2 );
132 BOOST_CHECK_EQUAL( symbolNames[0], parentSymbol1Ref.GetName() );
133 BOOST_CHECK_EQUAL( symbolNames[1], childSymbol1Ref.GetName() );
134
135 symbolNames.Clear();
136 libBuffer.GetSymbolNames( symbolNames, SYMBOL_NAME_FILTER::DERIVED_ONLY );
137 BOOST_CHECK_EQUAL( symbolNames.GetCount(), 1 );
138 BOOST_CHECK_EQUAL( symbolNames[0], childSymbol1Ref.GetName() );
139
140 symbolNames.Clear();
141
142 BOOST_CHECK_EQUAL( libBuffer.GetDerivedSymbolNames( parentSymbol1Ref.GetName(), symbolNames ),
143 1 );
144 BOOST_CHECK_EQUAL( symbolNames[0], childSymbol1Ref.GetName() );
145
146 std::shared_ptr<SYMBOL_BUFFER> buf = libBuffer.GetBuffer( parentSymbol1Ref.GetName() );
147
148 LIB_SYMBOL tmp( parentSymbol1Ref );
149 tmp.GetDescriptionField().SetText( wxS( "Description" ) );
150
151 libBuffer.UpdateBuffer( *buf, tmp );
152 BOOST_CHECK_EQUAL( libBuffer.GetHash(), 4 );
153 BOOST_CHECK( *libBuffer.GetSymbol( parentSymbol1Ref.GetName() ) == tmp );
154
155 const bool deletedOk = libBuffer.DeleteBuffer( *buf );
156 BOOST_CHECK( deletedOk );
157 BOOST_CHECK( libBuffer.GetBuffers().empty() );
158}
159
160
164BOOST_AUTO_TEST_CASE( NewSymbolCreation )
165{
167
168 props.name = wxS( "Standalone" );
169 props.reference = wxS( "U" );
170 props.unitCount = 2;
171 props.pinNameInside = true;
172 props.pinTextPosition = 2;
173 props.powerSymbol = false;
174 props.showPinNumber = true;
175 props.showPinName = true;
176 props.unitsInterchangeable = false;
177 props.includeInBom = true;
178 props.includeOnBoard = true;
179 props.alternateBodyStyle = false;
180
181 std::unique_ptr<LIB_SYMBOL> standalone =
183
184 BOOST_CHECK_EQUAL( standalone->GetReferenceField().GetText(), props.reference );
185 BOOST_CHECK_EQUAL( standalone->GetUnitCount(), props.unitCount );
186 BOOST_CHECK( standalone->GetPinNameOffset() > 0 );
187
188 auto parent = std::make_unique<LIB_SYMBOL>( wxS( "Parent" ) );
189 parent->GetValueField().SetText( parent->GetName() );
190 SCH_FIELD* user = new SCH_FIELD( parent.get(), FIELD_T::USER, wxS( "UF" ) );
191 user->SetText( wxS( "V" ) );
192 parent->AddField( user );
193
194 props.name = wxS( "Child" );
195 props.parentSymbolName = parent->GetName();
196 props.keepFootprint = false;
197 props.keepDatasheet = false;
198 props.transferUserFields = true;
199 props.keepContentUserFields = false;
200
201 std::unique_ptr<LIB_SYMBOL> child =
202 LIB_SYMBOL_LIBRARY_MANAGER::CreateSymbol( props, parent.get() );
203
204 BOOST_CHECK( child->GetParent().lock().get() == parent.get() );
205 BOOST_CHECK( child->GetFootprintField().GetText().IsEmpty() );
206 BOOST_CHECK( child->GetDatasheetField().GetText().IsEmpty() );
207
208 std::vector<SCH_FIELD*> childFields;
209 child->GetFields( childFields );
210
211 bool found = false;
212
213 for( SCH_FIELD* field : childFields )
214 {
215 if( field->GetId() == FIELD_T::USER )
216 {
217 found = true;
218 BOOST_CHECK( field->GetText().IsEmpty() );
219 }
220 }
221
222 BOOST_CHECK( found );
223}
224
225
234BOOST_AUTO_TEST_CASE( DeletedSymbolsAreRemovedFromFile )
235{
236 // Create a temporary directory and library file
237 wxString tempDir = wxFileName::CreateTempFileName( wxS( "kicad_test_" ) );
238 wxRemoveFile( tempDir );
239 wxFileName::Mkdir( tempDir );
240 wxString libPath = wxFileName( tempDir, wxS( "test_lib.kicad_sym" ) ).GetFullPath();
241
242 // Step 1: Create a library with a parent and derived symbol using the plugin directly
243 {
244 IO_RELEASER<SCH_IO> plugin( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_KICAD ) );
245 plugin->CreateLibrary( libPath );
246
247 // Create parent symbol
248 std::unique_ptr<LIB_SYMBOL> parentSymbol = std::make_unique<LIB_SYMBOL>( wxS( "Parent" ) );
249 parentSymbol->GetValueField().SetText( wxS( "Parent" ) );
250 parentSymbol->GetReferenceField().SetText( wxS( "U" ) );
251
252 LIB_SYMBOL* parentPtr = parentSymbol.get();
253 plugin->SaveSymbol( libPath, new LIB_SYMBOL( *parentSymbol ) );
254
255 // Create derived symbol
256 std::unique_ptr<LIB_SYMBOL> derivedSymbol = std::make_unique<LIB_SYMBOL>( wxS( "Derived" ) );
257 derivedSymbol->GetValueField().SetText( wxS( "Derived" ) );
258 derivedSymbol->SetParent( parentPtr );
259
260 plugin->SaveSymbol( libPath, new LIB_SYMBOL( *derivedSymbol ) );
261 plugin->SaveLibrary( libPath );
262 }
263
264 // Step 2: Verify both symbols exist in the library
265 {
266 IO_RELEASER<SCH_IO> plugin( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_KICAD ) );
267 LIB_SYMBOL* parent = plugin->LoadSymbol( libPath, wxS( "Parent" ) );
268 LIB_SYMBOL* derived = plugin->LoadSymbol( libPath, wxS( "Derived" ) );
269
270 BOOST_REQUIRE( parent != nullptr );
271 BOOST_REQUIRE( derived != nullptr );
272 BOOST_CHECK( derived->IsDerived() );
273 }
274
275 // Step 3: Load symbols into LIB_BUFFER and delete the derived symbol
276 LIB_BUFFER libBuffer( wxS( "TestLibrary" ) );
277
278 {
279 IO_RELEASER<SCH_IO> plugin( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_KICAD ) );
280 LIB_SYMBOL* loadedParent = plugin->LoadSymbol( libPath, wxS( "Parent" ) );
281 LIB_SYMBOL* loadedDerived = plugin->LoadSymbol( libPath, wxS( "Derived" ) );
282
283 BOOST_REQUIRE( loadedParent != nullptr );
284 BOOST_REQUIRE( loadedDerived != nullptr );
285
286 // Set up parent relationship
287 loadedDerived->SetParent( loadedParent );
288
289 // Create buffers (parent first, then derived)
290 libBuffer.CreateBuffer( std::make_unique<LIB_SYMBOL>( *loadedParent ),
291 std::make_unique<SCH_SCREEN>() );
292
293 std::unique_ptr<LIB_SYMBOL> derivedCopy = std::make_unique<LIB_SYMBOL>( *loadedDerived );
294 derivedCopy->SetParent( libBuffer.GetSymbol( wxS( "Parent" ) ) );
295 libBuffer.CreateBuffer( std::move( derivedCopy ), std::make_unique<SCH_SCREEN>() );
296 }
297
298 // Verify buffer state before deletion
299 BOOST_CHECK_EQUAL( libBuffer.GetBuffers().size(), 2 );
300 BOOST_CHECK( libBuffer.GetSymbol( wxS( "Parent" ) ) != nullptr );
301 BOOST_CHECK( libBuffer.GetSymbol( wxS( "Derived" ) ) != nullptr );
302
303 // Delete the derived symbol from the buffer
304 std::shared_ptr<SYMBOL_BUFFER> derivedBuf = libBuffer.GetBuffer( wxS( "Derived" ) );
305 BOOST_REQUIRE( derivedBuf != nullptr );
306
307 bool deleteResult = libBuffer.DeleteBuffer( *derivedBuf );
308 BOOST_CHECK( deleteResult );
309
310 // Verify buffer state after deletion
311 BOOST_CHECK_EQUAL( libBuffer.GetBuffers().size(), 1 );
312 BOOST_CHECK( libBuffer.GetSymbol( wxS( "Parent" ) ) != nullptr );
313 BOOST_CHECK( libBuffer.GetSymbol( wxS( "Derived" ) ) == nullptr );
314
315 // Step 4: Save the library using the same pattern as SYMBOL_LIBRARY_MANAGER::SaveLibrary
316 {
317 IO_RELEASER<SCH_IO> plugin( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_KICAD ) );
318 std::map<std::string, UTF8> properties;
319 properties.emplace( SCH_IO_KICAD_SEXPR::PropBuffering, "" );
320
321 // Save remaining buffers (just Parent)
322 for( const std::shared_ptr<SYMBOL_BUFFER>& symbolBuf : libBuffer.GetBuffers() )
323 {
324 libBuffer.SaveBuffer( *symbolBuf, libPath, &*plugin, true );
325 }
326
327 // Delete symbols that were removed from the buffer (this is the fix for the bug)
328 for( const std::shared_ptr<SYMBOL_BUFFER>& deletedBuf : libBuffer.GetDeletedBuffers() )
329 {
330 const wxString& originalName = deletedBuf->GetOriginal().GetName();
331
332 if( plugin->LoadSymbol( libPath, originalName ) )
333 plugin->DeleteSymbol( libPath, originalName, &properties );
334 }
335
336 plugin->SaveLibrary( libPath );
337 libBuffer.ClearDeletedBuffer();
338 }
339
340 // Step 5: Reload the library and verify the derived symbol is gone
341 {
342 IO_RELEASER<SCH_IO> plugin( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_KICAD ) );
343
344 LIB_SYMBOL* parent = plugin->LoadSymbol( libPath, wxS( "Parent" ) );
345 LIB_SYMBOL* derived = plugin->LoadSymbol( libPath, wxS( "Derived" ) );
346
347 BOOST_CHECK( parent != nullptr );
348 // This is the actual check for the bug - the derived symbol should be deleted
349 BOOST_CHECK_MESSAGE( derived == nullptr,
350 "Derived symbol should have been deleted from the library file" );
351 }
352
353 // Cleanup
354 if( wxFileName::DirExists( tempDir ) )
355 {
356 wxFileName::Rmdir( tempDir, wxPATH_RMDIR_RECURSIVE );
357 }
358}
359
360
372BOOST_AUTO_TEST_CASE( SaveLibraryAsToNewFile )
373{
374 wxString tempDir = wxFileName::CreateTempFileName( wxS( "kicad_test_" ) );
375 wxRemoveFile( tempDir );
376 wxFileName::Mkdir( tempDir );
377
378 wxString srcPath = wxFileName( tempDir, wxS( "source.kicad_sym" ) ).GetFullPath();
379 wxString dstPath = wxFileName( tempDir, wxS( "destination.kicad_sym" ) ).GetFullPath();
380
381 // Create a source library with two symbols (one parent, one derived)
382 {
383 IO_RELEASER<SCH_IO> plugin( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_KICAD ) );
384 plugin->CreateLibrary( srcPath );
385
386 auto parent = std::make_unique<LIB_SYMBOL>( wxS( "Parent" ) );
387 parent->GetValueField().SetText( wxS( "Parent" ) );
388 parent->GetReferenceField().SetText( wxS( "U" ) );
389 LIB_SYMBOL* parentPtr = parent.get();
390
391 plugin->SaveSymbol( srcPath, new LIB_SYMBOL( *parent ) );
392
393 auto derived = std::make_unique<LIB_SYMBOL>( wxS( "Derived" ) );
394 derived->GetValueField().SetText( wxS( "Derived" ) );
395 derived->SetParent( parentPtr );
396
397 plugin->SaveSymbol( srcPath, new LIB_SYMBOL( *derived ) );
398 plugin->SaveLibrary( srcPath );
399 }
400
401 // Simulate "Save Library As" to a new file that does not exist yet.
402 // This mirrors the else-branch in SYMBOL_LIBRARY_MANAGER::SaveLibrary.
403 {
404 IO_RELEASER<SCH_IO> srcPlugin( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_KICAD ) );
405 IO_RELEASER<SCH_IO> dstPlugin( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_KICAD ) );
406 std::map<std::string, UTF8> properties;
407 properties.emplace( SCH_IO_KICAD_SEXPR::PropBuffering, "" );
408
409 LIB_SYMBOL* loadedParent = srcPlugin->LoadSymbol( srcPath, wxS( "Parent" ) );
410 LIB_SYMBOL* loadedDerived = srcPlugin->LoadSymbol( srcPath, wxS( "Derived" ) );
411 BOOST_REQUIRE( loadedParent != nullptr );
412 BOOST_REQUIRE( loadedDerived != nullptr );
413
414 // Buffer symbols into the destination plugin using the target path (which
415 // does not exist yet). This must not throw.
416 BOOST_CHECK_NO_THROW(
417 dstPlugin->SaveSymbol( dstPath, new LIB_SYMBOL( *loadedParent ), &properties ) );
418
419 LIB_SYMBOL* newDerived = new LIB_SYMBOL( *loadedDerived );
420 LIB_SYMBOL* dstParent = dstPlugin->LoadSymbol( dstPath, wxS( "Parent" ), &properties );
421 BOOST_REQUIRE( dstParent != nullptr );
422 newDerived->SetParent( dstParent );
423
424 BOOST_CHECK_NO_THROW(
425 dstPlugin->SaveSymbol( dstPath, newDerived, &properties ) );
426
427 BOOST_CHECK_NO_THROW( dstPlugin->SaveLibrary( dstPath ) );
428 }
429
430 // Reload the destination library and verify both symbols are present
431 {
432 IO_RELEASER<SCH_IO> plugin( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_KICAD ) );
433
434 LIB_SYMBOL* parent = plugin->LoadSymbol( dstPath, wxS( "Parent" ) );
435 LIB_SYMBOL* derived = plugin->LoadSymbol( dstPath, wxS( "Derived" ) );
436
437 BOOST_CHECK_MESSAGE( parent != nullptr,
438 "Parent symbol should exist in the saved-as library" );
439 BOOST_CHECK_MESSAGE( derived != nullptr,
440 "Derived symbol should exist in the saved-as library" );
441
442 if( derived )
443 BOOST_CHECK( derived->IsDerived() );
444 }
445
446 if( wxFileName::DirExists( tempDir ) )
447 wxFileName::Rmdir( tempDir, wxPATH_RMDIR_RECURSIVE );
448}
449
450
460BOOST_AUTO_TEST_CASE( SetParentKeepsParentNameInSync )
461{
462 auto parent = std::make_unique<LIB_SYMBOL>( wxS( "BaseSymbol" ) );
463
464 LIB_SYMBOL derived( wxS( "DerivedSymbol" ) );
465 BOOST_CHECK( derived.GetParentName().IsEmpty() );
466
467 derived.SetParent( parent.get() );
468 BOOST_CHECK( derived.IsDerived() );
469 BOOST_CHECK_EQUAL( derived.GetParentName(), wxS( "BaseSymbol" ) );
470
471 // Detaching the live pointer must not erase the recorded name, so a derived symbol whose live
472 // parent has been lost can still be serialized by name.
473 derived.SetParent( static_cast<LIB_SYMBOL*>( nullptr ) );
474 BOOST_CHECK_EQUAL( derived.GetParent().lock(), nullptr );
475 BOOST_CHECK_EQUAL( derived.GetParentName(), wxS( "BaseSymbol" ) );
476}
477
478
491BOOST_AUTO_TEST_CASE( SerializeDerivedSymbolUsesParentName )
492{
493 auto parent = std::make_unique<LIB_SYMBOL>( wxS( "BaseSymbol" ) );
494 parent->GetValueField().SetText( wxS( "BaseSymbol" ) );
495 parent->GetReferenceField().SetText( wxS( "U" ) );
496
497 LIB_SYMBOL derived( wxS( "DerivedSymbol" ) );
498 derived.SetParent( parent.get() );
499 derived.GetValueField().SetText( wxS( "DerivedSymbol" ) );
500
501 BOOST_REQUIRE( derived.IsDerived() );
502
503 // Force the recorded name to differ from the live parent's name. The writer must emit the
504 // recorded name, proving it does not read through the live (potentially dangling) pointer.
505 derived.SetParentName( wxS( "RecordedParent" ) );
506
507 STRING_FORMATTER formatter;
508
509 BOOST_REQUIRE_NO_THROW(
510 SCH_IO_KICAD_SEXPR_LIB_CACHE::SaveSymbol( &derived, formatter, wxEmptyString, true ) );
511
512 const std::string out = formatter.GetString();
513
514 BOOST_CHECK_MESSAGE( out.find( "(extends \"RecordedParent\")" ) != std::string::npos,
515 "Derived symbol should serialize (extends ...) using the recorded parent name" );
516}
517
518
525BOOST_AUTO_TEST_CASE( SaveCopyAsDerivedSymbolToNewLibrary )
526{
527 wxString tempDir = wxFileName::CreateTempFileName( wxS( "kicad_test_" ) );
528 wxRemoveFile( tempDir );
529 wxFileName::Mkdir( tempDir );
530
531 wxString dstPath = wxFileName( tempDir, wxS( "copy_target.kicad_sym" ) ).GetFullPath();
532
533 // Build an in-memory parent/derived pair like the symbol editor holds while editing.
534 auto parent = std::make_unique<LIB_SYMBOL>( wxS( "BaseSymbol" ) );
535 parent->GetValueField().SetText( wxS( "BaseSymbol" ) );
536 parent->GetReferenceField().SetText( wxS( "U" ) );
537
538 auto derived = std::make_unique<LIB_SYMBOL>( wxS( "DerivedSymbol" ) );
539 derived->SetParent( parent.get() );
540 derived->SetParentName( parent->GetName() );
541 derived->GetValueField().SetText( wxS( "DerivedSymbol" ) );
542
543 // Save the parent then the child to a brand new library, mirroring SYMBOL_SAVE_AS_HANDLER.
544 {
545 IO_RELEASER<SCH_IO> plugin( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_KICAD ) );
546 std::map<std::string, UTF8> properties;
547 properties.emplace( SCH_IO_KICAD_SEXPR::PropBuffering, "" );
548
549 BOOST_CHECK_NO_THROW(
550 plugin->SaveSymbol( dstPath, new LIB_SYMBOL( *parent ), &properties ) );
551
552 LIB_SYMBOL* dstParent = plugin->LoadSymbol( dstPath, wxS( "BaseSymbol" ), &properties );
553 BOOST_REQUIRE( dstParent != nullptr );
554
555 LIB_SYMBOL* newChild = new LIB_SYMBOL( *derived );
556 newChild->SetParent( dstParent );
557 newChild->SetParentName( dstParent->GetName() );
558
559 BOOST_CHECK_NO_THROW( plugin->SaveSymbol( dstPath, newChild, &properties ) );
560 BOOST_CHECK_NO_THROW( plugin->SaveLibrary( dstPath ) );
561 }
562
563 // Reload and verify the derived symbol survived with a valid parent.
564 {
565 IO_RELEASER<SCH_IO> plugin( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_KICAD ) );
566
567 LIB_SYMBOL* reloadedParent = plugin->LoadSymbol( dstPath, wxS( "BaseSymbol" ) );
568 LIB_SYMBOL* reloadedChild = plugin->LoadSymbol( dstPath, wxS( "DerivedSymbol" ) );
569
570 BOOST_CHECK( reloadedParent != nullptr );
571 BOOST_REQUIRE( reloadedChild != nullptr );
572 BOOST_CHECK( reloadedChild->IsDerived() );
573 BOOST_CHECK_EQUAL( reloadedChild->GetParent().lock().get(), reloadedParent );
574 }
575
576 if( wxFileName::DirExists( tempDir ) )
577 wxFileName::Rmdir( tempDir, wxPATH_RMDIR_RECURSIVE );
578}
579
580
void SetContentModified(bool aModified=true)
Definition base_screen.h:55
Store a working copy of a library.
size_t GetDerivedSymbolNames(const wxString &aSymbolName, wxArrayString &aList)
Fetch all of the symbols derived from a aSymbolName into aList.
bool CreateBuffer(std::unique_ptr< LIB_SYMBOL > aCopy, std::unique_ptr< SCH_SCREEN > aScreen)
Create a new buffer to store a symbol. LIB_BUFFER takes ownership of aCopy.
bool IsModified() const
bool DeleteBuffer(const SYMBOL_BUFFER &aSymbolBuf)
Delete the given symbol buffer from the library buffer.
void GetSymbolNames(wxArrayString &aSymbolNames, SYMBOL_NAME_FILTER aFilter=SYMBOL_NAME_FILTER::ALL)
Fetch a list of root symbols names from the library buffer.
const std::deque< std::shared_ptr< SYMBOL_BUFFER > > & GetDeletedBuffers() const
Return the deleted symbol buffers that need to be removed from the library file.
bool SaveBuffer(SYMBOL_BUFFER &aSymbolBuf, const wxString &aFileName, SCH_IO *aPlugin, bool aBuffer)
Save stored modifications using a plugin.
const std::deque< std::shared_ptr< SYMBOL_BUFFER > > & GetBuffers() const
Return all buffered symbols.
std::shared_ptr< SYMBOL_BUFFER > GetBuffer(const wxString &aAlias) const
Return a symbol buffer with LIB_SYMBOL holding a symbolic alias.
LIB_SYMBOL * GetSymbol(const wxString &aAlias) const
Return the working copy of a LIB_SYMBOL root object with specified alias.
bool HasDerivedSymbols(const wxString &aParentName) const
Check to see any symbols in the buffer are derived from a parent named aParentName.
bool UpdateBuffer(SYMBOL_BUFFER &aSymbolBuf, const LIB_SYMBOL &aCopy)
Update the buffered symbol with the contents of aCopy.
static std::unique_ptr< LIB_SYMBOL > CreateSymbol(const NEW_SYMBOL_PROPERTIES &aProps, LIB_SYMBOL *aParent)
Define a library symbol object.
Definition lib_symbol.h:79
SCH_FIELD & GetDescriptionField()
Return reference to the description field.
Definition lib_symbol.h:345
std::weak_ptr< LIB_SYMBOL > & GetParent()
Definition lib_symbol.h:110
bool IsDerived() const
Definition lib_symbol.h:196
void SetParent(LIB_SYMBOL *aParent=nullptr)
wxString GetName() const override
Definition lib_symbol.h:141
SCH_FIELD & GetValueField()
Return reference to the value field.
Definition lib_symbol.h:329
const wxString & GetParentName() const
Definition lib_symbol.h:853
void SetParentName(const wxString &aParentName)
Definition lib_symbol.h:852
void SetText(const wxString &aText) override
static void SaveSymbol(LIB_SYMBOL *aSymbol, OUTPUTFORMATTER &aFormatter, const wxString &aLibName=wxEmptyString, bool aIncludeData=true)
static const char * PropBuffering
The property used internally by the plugin to enable cache buffering which prevents the library file ...
Implement an OUTPUTFORMATTER to a memory buffer.
Definition richio.h:418
const std::string & GetString()
Definition richio.h:441
LIB_SYMBOL & GetSymbol() const
SCH_SCREEN * GetScreen() const
LIB_SYMBOL & GetOriginal() const
void SetOriginal(std::unique_ptr< LIB_SYMBOL > aSymbol)
std::unique_ptr< T > IO_RELEASER
Helper to hold and release an IO_BASE object when exceptions are thrown.
Definition io_mgr.h:33
@ USER
The field ID hasn't been set yet; field is invalid.
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_AUTO_TEST_SUITE_END()
BOOST_CHECK_MESSAGE(totalMismatches==0, std::to_string(totalMismatches)+" board(s) with strategy disagreements")
BOOST_AUTO_TEST_CASE(SymbolBuffer)
Test the SYMBOL_BUFFER object.
BOOST_CHECK_EQUAL(result, "25.4")