KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_lib_part.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
24
26
27// Code under test
28#include <sch_shape.h>
29#include <sch_pin.h>
30#include <lib_symbol.h>
31#include <functional>
33#include <font/font.h>
34#include <locale_io.h>
35#include <sch_file_versions.h>
36#include <sch_io/sch_io.h>
37#include <sch_io/sch_io_mgr.h>
38#include <locale_io.h>
39#include <units_provider.h>
40
41#include <wx/file.h>
42#include <wx/filename.h>
43
45
46extern void CheckDuplicatePins( LIB_SYMBOL* aSymbol, std::vector<wxString>& aMessages,
47 UNITS_PROVIDER* aUnitsProvider );
48
50{
51public:
53 m_part_no_data( "part_name", nullptr )
54 {
55 }
56
59};
60
61
66{
67public:
69 {
70 m_dir = wxFileName::CreateTempFileName( wxS( "kicad_lib_part_" ) );
71 wxRemoveFile( m_dir );
72 wxFileName::Mkdir( m_dir );
73
74 m_path = wxFileName( m_dir, wxS( "test_lib.kicad_sym" ) ).GetFullPath();
75 }
76
78 {
79 if( wxFileName::DirExists( m_dir ) )
80 wxFileName::Rmdir( m_dir, wxPATH_RMDIR_RECURSIVE );
81 }
82
83 const wxString& GetPath() const { return m_path; }
84
85private:
86 wxString m_dir;
87 wxString m_path;
88};
89
90
95{
96 int count = 0;
97
98 for( SCH_ITEM& item : aSymbol.GetDrawItems() )
99 {
100 if( item.GetBodyStyle() > BODY_STYLE::BASE )
101 count++;
102 }
103
104 return count;
105}
106
107
111static std::unique_ptr<LIB_SYMBOL> loadDeMorganSymbol()
112{
113 wxFileName libPath( KI_TEST::GetEeschemaTestDataDir() );
114 libPath.AppendDir( "libs" );
115 libPath.SetFullName( "4xxx.kicad_sym" );
116
117 IO_RELEASER<SCH_IO> pi( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_KICAD ) );
118
119 // The plugin cache owns the returned symbol, so hand back a copy
120 LIB_SYMBOL* cached = pi->LoadSymbol( libPath.GetFullPath(), wxS( "4001" ) );
121
122 return cached ? std::make_unique<LIB_SYMBOL>( *cached ) : nullptr;
123}
124
125
129static void saveToLib( const wxString& aLibPath, const LIB_SYMBOL& aSymbol )
130{
131 IO_RELEASER<SCH_IO> pi( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_KICAD ) );
132
133 pi->CreateLibrary( aLibPath );
134 pi->SaveSymbol( aLibPath, std::make_unique<LIB_SYMBOL>( aSymbol ) );
135 pi->SaveLibrary( aLibPath );
136}
137
138
142BOOST_FIXTURE_TEST_SUITE( LibPart, TEST_LIB_SYMBOL_FIXTURE )
143
144
145
148BOOST_AUTO_TEST_CASE( DefaultProperties )
149{
150 BOOST_CHECK_EQUAL( m_part_no_data.GetName(), "part_name" );
151
152 // Didn't set a library, so this is empty
153 BOOST_CHECK_EQUAL( m_part_no_data.GetLibraryName(), "" );
154 BOOST_CHECK_EQUAL( m_part_no_data.GetLib(), nullptr );
155
156 // only get the root
157 BOOST_CHECK_EQUAL( m_part_no_data.IsRoot(), true );
158 BOOST_CHECK_EQUAL( m_part_no_data.IsDerived(), false );
159 BOOST_CHECK_EQUAL( m_part_no_data.SharedPtr().use_count(), 2 );
160
161 // no sub units
162 BOOST_CHECK_EQUAL( m_part_no_data.GetUnitCount(), 1 );
163 BOOST_CHECK_EQUAL( m_part_no_data.IsMultiUnit(), false );
164
165 // single body style
166 BOOST_CHECK_EQUAL( m_part_no_data.HasDeMorganBodyStyles(), false );
167}
168
169
173BOOST_AUTO_TEST_CASE( DefaultDrawings )
174{
175 // default drawings exist
176 BOOST_CHECK_EQUAL( m_part_no_data.GetDrawItems().size(), 5 );
177 BOOST_CHECK_EQUAL( m_part_no_data.GetGraphicalPins( 0, 0 ).size(), 0 );
178}
179
180
184BOOST_AUTO_TEST_CASE( DefaultFields )
185{
186 std::vector<SCH_FIELD> fields;
187 m_part_no_data.CopyFields( fields );
188
189 // Should get the 4 default fields
191
192 // but no more (we didn't set them)
193 BOOST_CHECK_EQUAL( fields.size(), 5 );
194
195 // also check the default field accessors
197 ( m_part_no_data.GetReferenceField() )( "Reference" )( (int) FIELD_T::REFERENCE ) );
199 ( m_part_no_data.GetValueField() )( "Value" )( (int) FIELD_T::VALUE ) );
201 ( m_part_no_data.GetFootprintField() )( "Footprint" )( (int) FIELD_T::FOOTPRINT ) );
203 ( m_part_no_data.GetDatasheetField() )( "Datasheet" )( (int) FIELD_T::DATASHEET ) );
205 ( m_part_no_data.GetDescriptionField() )( "Description" )( (int) FIELD_T::DESCRIPTION ) );
206}
207
208
213{
214 std::vector<SCH_FIELD> fields;
215 m_part_no_data.CopyFields( fields );
216
217 // Ctor takes non-const ref (?!)
218 const std::string newFieldName = "new_field";
219 wxString nonConstNewFieldName = newFieldName;
220 fields.push_back( SCH_FIELD( nullptr, FIELD_T::USER, nonConstNewFieldName ) );
221
222 // fairly roundabout way to add a field, but it is what it is
223 m_part_no_data.SetFields( fields );
224
225 // Should get the 4 default fields
227
228 // and our new one
229 BOOST_REQUIRE_EQUAL( fields.size(), 6 );
230
231 // Check by-name lookup
232
233 SCH_FIELD* gotNewField = m_part_no_data.GetField( newFieldName );
234
235 BOOST_REQUIRE_NE( gotNewField, nullptr );
236 BOOST_CHECK_PREDICATE( KI_TEST::FieldNameIdMatches, ( *gotNewField )( newFieldName )( 0 ) );
237}
238
239
243BOOST_AUTO_TEST_CASE( AddedDrawItems )
244{
245 const size_t defaultCount = m_part_no_data.GetDrawItems().size();
246
247 SCH_PIN* pin = new SCH_PIN( &m_part_no_data );
248 pin->SetNumber( "1" );
249 m_part_no_data.AddDrawItem( pin );
250
251 BOOST_CHECK_EQUAL( m_part_no_data.GetDrawItems().size(), defaultCount + 1 );
252 BOOST_CHECK( pin->GetParentSymbol() == &m_part_no_data );
253 BOOST_CHECK_EQUAL( m_part_no_data.GetPinCount(), 1 );
254
255 m_part_no_data.RemoveDrawItem( pin );
256
257 BOOST_CHECK_EQUAL( m_part_no_data.GetDrawItems().size(), defaultCount );
258 BOOST_CHECK_EQUAL( m_part_no_data.GetPinCount(), 0 );
259
260 // Mandatory fields are never removable, so the accessors can't be left dangling
261 m_part_no_data.RemoveDrawItem( &m_part_no_data.GetReferenceField() );
262
263 BOOST_CHECK_EQUAL( m_part_no_data.GetDrawItems().size(), defaultCount );
264}
265
266
271BOOST_AUTO_TEST_CASE( StackedPinNumberLookup )
272{
273 SCH_PIN* pin = new SCH_PIN( &m_part_no_data );
274 pin->SetNumber( "[A1,A12,B1,B12]" );
275 m_part_no_data.AddDrawItem( pin );
276
277 BOOST_CHECK( m_part_no_data.HasPinNumber( "[A1,A12,B1,B12]" ) );
278
279 BOOST_CHECK( m_part_no_data.HasPinNumber( "A1" ) );
280 BOOST_CHECK( m_part_no_data.HasPinNumber( "A12" ) );
281 BOOST_CHECK( m_part_no_data.HasPinNumber( "B1" ) );
282 BOOST_CHECK( m_part_no_data.HasPinNumber( "B12" ) );
283
284 BOOST_CHECK( !m_part_no_data.HasPinNumber( "A2" ) );
285 BOOST_CHECK( !m_part_no_data.HasPinNumber( "[A1" ) );
286}
287
288
293BOOST_AUTO_TEST_CASE( RangeStackedPinNumberLookup )
294{
295 SCH_PIN* pin = new SCH_PIN( &m_part_no_data );
296 pin->SetNumber( "[1-4]" );
297 m_part_no_data.AddDrawItem( pin );
298
299 BOOST_CHECK( m_part_no_data.HasPinNumber( "[1-4]" ) );
300
301 BOOST_CHECK( m_part_no_data.HasPinNumber( "1" ) );
302 BOOST_CHECK( m_part_no_data.HasPinNumber( "3" ) );
303
304 BOOST_CHECK( !m_part_no_data.HasPinNumber( "5" ) );
305}
306
307
309{
312 std::string m_expSubRef;
313};
314
315
319BOOST_AUTO_TEST_CASE( SubReference )
320{
321 const std::vector<TEST_LIB_SYMBOL_SUBREF_CASE> cases = {
322 {
323 1,
324 false,
325 "A",
326 },
327 {
328 2,
329 false,
330 "B",
331 },
332 {
333 26,
334 false,
335 "Z",
336 },
337 {
338 27,
339 false,
340 "AA",
341 },
342 {
343 28,
344 false,
345 "AB",
346 },
347 {
348 53,
349 false,
350 "BA",
351 },
352 {
353 79,
354 false,
355 "CA",
356 },
357 {
358 105,
359 false,
360 "DA",
361 },
362 {
363 131,
364 false,
365 "EA",
366 },
367 {
368 157,
369 false,
370 "FA",
371 },
372 {
373 183,
374 false,
375 "GA",
376 },
377 {
378 209,
379 false,
380 "HA",
381 },
382 {
383 235,
384 false,
385 "IA",
386 },
387 {
388 261,
389 false,
390 "JA",
391 },
392 {
393 287,
394 false,
395 "KA",
396 },
397 {
398 313,
399 false,
400 "LA",
401 },
402 {
403 339,
404 false,
405 "MA",
406 },
407 {
408 365,
409 false,
410 "NA",
411 },
412 {
413 391,
414 false,
415 "OA",
416 },
417 {
418 417,
419 false,
420 "PA",
421 },
422 {
423 443,
424 false,
425 "QA",
426 },
427 {
428 469,
429 false,
430 "RA",
431 },
432 {
433 495,
434 false,
435 "SA",
436 },
437 {
438 521,
439 false,
440 "TA",
441 },
442 {
443 547,
444 false,
445 "UA",
446 },
447 {
448 573,
449 false,
450 "VA",
451 },
452 {
453 599,
454 false,
455 "WA",
456 },
457 {
458 625,
459 false,
460 "XA",
461 },
462 {
463 651,
464 false,
465 "YA",
466 },
467 {
468 677,
469 false,
470 "ZA",
471 },
472 {
473 702,
474 false,
475 "ZZ",
476 },
477 {
478 703,
479 false,
480 "AAA",
481 },
482 {
483 728,
484 false,
485 "AAZ",
486 },
487 };
488
489 for( const auto& c : cases )
490 {
492 "Subref: " << c.m_index << ", " << c.m_addSep << " -> '" << c.m_expSubRef << "'" )
493 {
494 const auto subref = LIB_SYMBOL::LetterSubReference( c.m_index, 'A' );
495 BOOST_CHECK_EQUAL( subref, c.m_expSubRef );
496 }
497 }
498}
499
500
501BOOST_AUTO_TEST_CASE( NativeBezierComparisonHandlesUnequalCaches )
502{
503 LOCALE_IO locale;
504 auto symbol = loadDeMorganSymbol();
505 BOOST_REQUIRE( symbol );
506 SCH_SHAPE* shape = nullptr;
507
508 for( SCH_ITEM& item : symbol->GetDrawItems()[SCH_SHAPE_T] )
509 {
510 shape = static_cast<SCH_SHAPE*>( &item );
511 break;
512 }
513
514 BOOST_REQUIRE( shape );
515 shape->SetShape( SHAPE_T::BEZIER );
516 shape->SetStart( VECTOR2I( 0, 0 ) );
517 shape->SetEnd( VECTOR2I( 100000, 0 ) );
518 shape->SetBezierC1( VECTOR2I( 0, 100000 ) );
519 shape->SetBezierC2( VECTOR2I( 100000, 100000 ) );
520 BOOST_REQUIRE( shape->GetBezierPoints().empty() );
521 SCH_SHAPE rebuilt( *shape );
523 BOOST_REQUIRE( !rebuilt.GetBezierPoints().empty() );
524 const auto& empty = static_cast<const EDA_SHAPE&>( *shape );
525 const auto& populated = static_cast<const EDA_SHAPE&>( rebuilt );
526 BOOST_REQUIRE_NE( empty.Compare( &populated ), 0 );
527 BOOST_CHECK_LT( empty.Compare( &populated ), 0 );
528 BOOST_CHECK_GT( populated.Compare( &empty ), 0 );
529}
530
531
532BOOST_AUTO_TEST_CASE( NativeCapturedDuplicatePinsMatchChecker )
533{
534 LOCALE_IO locale;
535 const auto original = loadDeMorganSymbol();
536 BOOST_REQUIRE( original );
538 std::vector<wxString> messages;
539 CheckDuplicatePins( original.get(), messages, &units );
540 BOOST_REQUIRE( messages.empty() );
541
542 for( int change = 0; change < 7; ++change )
543 {
544 BOOST_TEST_CONTEXT( "native duplicate pin change=" << change )
545 {
546 auto changed = std::make_unique<LIB_SYMBOL>( *original );
547 const auto pins = changed->GetGraphicalPins( 0, 0 );
548 BOOST_REQUIRE( !pins.empty() );
549 auto* extra = static_cast<SCH_PIN*>( pins.front()->Clone() );
550 changed->AddDrawItem( extra );
551
552 switch( change )
553 {
554 case 0: break;
555 case 1: extra->SetBodyStyle( 99 ); break;
556 case 2: extra->SetBodyStyle( 0 ); break;
557 case 3: extra->SetUnit( 0 ); break;
558 case 4: extra->SetNumber( wxS( "[" ) + pins.front()->GetNumber() + wxS( ",98765]" ) ); break;
559 case 5: extra->SetNumber( wxS( "[98765,98765]" ) ); break;
560 case 6: extra->SetNumber( wxS( "[malformed" ) ); break;
561 }
562
563 messages.clear();
564 CheckDuplicatePins( changed.get(), messages, &units );
565 const bool expected = change == 0 || change == 2 || change == 3 || change == 4;
566 BOOST_REQUIRE_EQUAL( !messages.empty(), expected );
567 const auto captured = SCH_CONNECTIVITY::ExtractLibrarySymbolFact( *changed );
568 BOOST_CHECK_EQUAL( captured.HasDuplicatePins(), expected );
569 }
570 }
571}
572
573
574BOOST_AUTO_TEST_CASE( NativeLibrarySnapshotsMatchLiveComparison )
575{
576 LOCALE_IO locale;
577 auto original = loadDeMorganSymbol();
578 BOOST_REQUIRE( original );
579 const auto captured = SCH_CONNECTIVITY::ExtractLibrarySymbolFact( *original );
580 using FLAGS = SCH_ITEM::COMPARE_FLAGS;
581 const int baseFlags = ~( FLAGS::UUID | FLAGS::UNIT | FLAGS::IDENTITY );
582 const std::vector<int> masks{ 0, FLAGS::PIN_VISIBILITIES, FLAGS::PIN_ALT_DEFS, FLAGS::FIELD_TEXT,
583 FLAGS::FIELD_POSITIONS, FLAGS::FIELD_SIZE_AND_STYLE, FLAGS::FIELD_VISIBILITY,
584 FLAGS::MISSING_FIELDS, FLAGS::EXTRA_FIELDS };
585
586 for( int change = 0; change < 13; ++change )
587 {
588 BOOST_TEST_CONTEXT( "native snapshot change=" << change )
589 {
590 LIB_SYMBOL changed( *original );
591 const auto pins = changed.GetGraphicalPins( 0, 0 );
592 BOOST_REQUIRE( !pins.empty() );
593 SCH_PIN* pin = pins.front();
594 SCH_FIELD* field = changed.GetField( FIELD_T::VALUE );
595 BOOST_REQUIRE( field );
596
597 switch( change )
598 {
599 case 0: break;
600 case 1: pin->SetName( pin->GetName() + "_Changed" ); break;
601 case 2: pin->SetVisible( !pin->IsVisible() ); break;
602 case 3:
603 pin->GetAlternates().emplace( wxS( "CapturedAlt" ),
604 SCH_PIN::ALT{ wxS( "CapturedAlt" ), GRAPHIC_PINSHAPE::CLOCK,
606 break;
607 case 4:
608 {
609 auto* extra = static_cast<SCH_PIN*>( pin->Clone() );
610 extra->SetNumber( wxS( "CapturedExtra" ) );
611 changed.AddDrawItem( extra );
612 break;
613 }
614 case 5: changed.AddField( new SCH_FIELD( &changed, FIELD_T::USER, wxS( "CapturedField" ) ) ); break;
615 case 6: field->SetText( field->GetText() + "_Changed" ); break;
616 case 7: field->SetPosition( field->GetPosition() + VECTOR2I( 1000, 2000 ) ); break;
617 case 8: field->SetFont( field->GetFont() ? nullptr : KIFONT::FONT::GetFont( wxString() ) ); break;
618 case 9: changed.SetKeyWords( changed.GetKeyWords() + "_Changed" ); break;
619 case 10:
621 static_cast<SCH_SHAPE&>( changed.GetDrawItems()[SCH_SHAPE_T].front() ).Move( VECTOR2I( 1000, 2000 ) );
622 break;
623 case 11: changed.GetField( FIELD_T::REFERENCE )->SetText( wxS( "ChangedReference" ) ); break;
624 case 12: field->SetVisible( !field->IsVisible() ); break;
625 }
626
627 const auto values = SCH_CONNECTIVITY::ExtractLibrarySymbolFact( changed );
628
629 for( int mask : masks )
630 {
631 const int flags = baseFlags & ~mask;
632 BOOST_CHECK_EQUAL( captured.Matches( values, flags ), original->Compare( changed, flags ) == 0 );
633 BOOST_CHECK_EQUAL( values.Matches( captured, flags ), changed.Compare( *original, flags ) == 0 );
634 }
635 }
636 }
637
638 LIB_SYMBOL baseline( *original );
639 LIB_SYMBOL derived( *original );
640 derived.SetParent( original.get() );
641 const auto inherited = SCH_CONNECTIVITY::ExtractLibrarySymbolFact( derived );
642 BOOST_REQUIRE( inherited.inheritedPins );
643 BOOST_REQUIRE( captured.Matches( inherited, baseFlags ) );
644 SCH_PIN* parentPin = original->GetGraphicalPins( 0, 0 ).front();
645 parentPin->SetLength( parentPin->GetLength() + 1 );
646 const auto editedParent = SCH_CONNECTIVITY::ExtractLibrarySymbolFact( derived );
647 BOOST_CHECK( !captured.Matches( editedParent, baseFlags ) );
648 BOOST_CHECK_NE( baseline.Compare( derived, baseFlags ), 0 );
649}
650
651
652BOOST_AUTO_TEST_CASE( NativeSymbolAttributesMatchCompareFlags )
653{
654 LOCALE_IO locale;
655 auto original = loadDeMorganSymbol();
656 BOOST_REQUIRE( original );
657 const auto captured = original->ComparisonAttributes();
658 using FLAGS = SCH_ITEM::COMPARE_FLAGS;
659 const int flags = ~( FLAGS::UUID | FLAGS::UNIT | FLAGS::IDENTITY );
660 const std::vector<std::pair<int, std::function<void( LIB_SYMBOL& )>>> changes{
661 { 0, []( auto& symbol ) { symbol.SetLocalPower(); } },
662 { 0, []( auto& symbol ) { symbol.SetUnitCount( symbol.GetUnitCount() + 1, false ); } },
663 { 0, []( auto& symbol ) { symbol.SetKeyWords( symbol.GetKeyWords() + " CapturedKeyword" ); } },
664 { 0, []( auto& symbol ) { symbol.SetPinNameOffset( symbol.GetPinNameOffset() + 1 ); } },
665 { 0, []( auto& symbol ) { symbol.LockUnits( !symbol.UnitsLocked() ); } },
666 { 0, []( auto& symbol ) { symbol.GetUnitDisplayNames()[1] = wxS( "CapturedUnit" ); } },
667 { 0, []( auto& symbol ) { symbol.SetBodyStyleNames( { wxS( "CapturedBody" ) } ); } },
668 { 0, []( auto& symbol )
669 {
670 auto filters = symbol.GetFPFilters();
671 filters.Add( wxS( "CapturedFilter*" ) );
672 symbol.SetFPFilters( filters );
673 } },
674 { FLAGS::PIN_VISIBILITIES, []( auto& symbol ) { symbol.SetShowPinNames( !symbol.GetShowPinNames() ); } },
675 { FLAGS::PIN_VISIBILITIES, []( auto& symbol ) { symbol.SetShowPinNumbers( !symbol.GetShowPinNumbers() ); } },
676 { FLAGS::EXCLUDE_FROM_SIM,
677 []( auto& symbol ) { symbol.SetExcludedFromSim( !symbol.GetExcludedFromSim() ); } },
678 { FLAGS::EXCLUDE_FROM_BOM,
679 []( auto& symbol ) { symbol.SetExcludedFromBOM( !symbol.GetExcludedFromBOM() ); } },
680 { FLAGS::EXCLUDE_FROM_BOARD,
681 []( auto& symbol ) { symbol.SetExcludedFromBoard( !symbol.GetExcludedFromBoard() ); } },
682 { FLAGS::EXCLUDE_FROM_POS_FILES,
683 []( auto& symbol ) { symbol.SetExcludedFromPosFiles( !symbol.GetExcludedFromPosFiles() ); } },
684 { FLAGS::DNP, []( auto& symbol ) { symbol.SetDNP( !symbol.GetDNP() ); } }
685 };
686
687 for( size_t i = 0; i < changes.size(); ++i )
688 {
689 BOOST_TEST_CONTEXT( "native attribute change=" << i )
690 {
691 LIB_SYMBOL changed( *original );
692 BOOST_REQUIRE( captured.Matches( changed.ComparisonAttributes(), flags ) );
693 BOOST_REQUIRE_EQUAL( original->Compare( changed, flags ), 0 );
694 const auto& [optionalFlag, mutate] = changes[i];
695 mutate( changed );
696 const auto values = changed.ComparisonAttributes();
697 BOOST_CHECK( captured != values );
698 BOOST_CHECK( !captured.Matches( values, flags ) );
699 BOOST_CHECK_NE( original->Compare( changed, flags ), 0 );
700
701 if( optionalFlag )
702 {
703 BOOST_CHECK( captured.Matches( values, flags & ~optionalFlag ) );
704 BOOST_CHECK_EQUAL( original->Compare( changed, flags & ~optionalFlag ), 0 );
705 }
706 }
707 }
708
709 original->SetDuplicatePinNumbersAreJumpers( !captured.duplicatePinNumbersAreJumpers );
710 const auto jumpers = original->ComparisonAttributes();
711 BOOST_CHECK( captured != jumpers );
712 BOOST_CHECK( captured.Matches( jumpers, flags ) );
713
714 const auto pins = original->GetGraphicalPins( 0, 0 );
715 BOOST_REQUIRE( !pins.empty() );
716 PIN_MAP map( wxS( "CapturedAttributes" ) );
717 map.SetEntry( pins.front()->GetNumber(), wxS( "CapturedPad" ) );
718 original->PinMaps().AddOrReplace( map );
719 const auto mapped = original->ComparisonAttributes();
720 BOOST_CHECK( !captured.Matches( mapped, flags ) );
721 original->PinMaps().FindByName( map.GetName() )->SetEntry( pins.front()->GetNumber(), wxS( "LaterPad" ) );
722 BOOST_CHECK( !mapped.Matches( original->ComparisonAttributes(), flags ) );
723 BOOST_CHECK_EQUAL( mapped.pinMaps.FindByName( map.GetName() )->GetPadNumber( pins.front()->GetNumber() ),
724 wxString( "CapturedPad" ) );
725
726 LIB_ID footprint;
727 footprint.SetLibNickname( wxS( "CapturedLibrary" ) );
728 footprint.SetLibItemName( wxS( "CapturedFootprint" ) );
729 original->SetAssociatedFootprints( { { footprint, map.GetName() } } );
730 const auto associated = original->ComparisonAttributes();
731 original->SetAssociatedFootprints( {} );
732 BOOST_CHECK( !associated.Matches( original->ComparisonAttributes(), flags ) );
733}
734
735
740{
741 // Identical root part to m_part_no_data sans time stamp.
742 LIB_SYMBOL testPart( "part_name" );
743
744 // Self comparison test.
745 BOOST_CHECK_EQUAL( m_part_no_data.Compare( m_part_no_data ), 0 );
746
747 // Test for identical LIB_SYMBOL.
748 BOOST_CHECK_EQUAL( m_part_no_data.Compare( testPart, ~SCH_ITEM::COMPARE_FLAGS::UUID ), 0 );
749
750 // Test name.
751 testPart.SetName( "tart_name" );
752 BOOST_CHECK( m_part_no_data.Compare( testPart ) < 0 );
753 testPart.SetName( "cart_name" );
754 BOOST_CHECK( m_part_no_data.Compare( testPart ) > 0 );
755 testPart.SetName( "part_name" );
756
757 // LIB_ID comparison tests.
758 LIB_ID id = testPart.GetLibId();
759 id.SetLibItemName( "tart_name" );
760 testPart.SetLibId( id );
761 BOOST_CHECK( m_part_no_data.Compare( testPart ) < 0 );
762 id.SetLibItemName( "cart_name" );
763 testPart.SetLibId( id );
764 BOOST_CHECK( m_part_no_data.Compare( testPart ) > 0 );
765 id.SetLibItemName( "part_name" );
766 testPart.SetLibId( id );
767
768 // Unit count comparison tests.
769 testPart.SetUnitCount( 2, true );
770 BOOST_CHECK( m_part_no_data.Compare( testPart ) < 0 );
771 testPart.SetUnitCount( 1, true );
772 m_part_no_data.SetUnitCount( 2, true );
773 BOOST_CHECK( m_part_no_data.Compare( testPart ) > 0 );
774 m_part_no_data.SetUnitCount( 1, true );
775
776 // Options flag comparison tests.
777 testPart.SetGlobalPower();
778 BOOST_CHECK( m_part_no_data.Compare( testPart ) < 0 );
779 testPart.SetNormal();
780 m_part_no_data.SetGlobalPower();
781 BOOST_CHECK( m_part_no_data.Compare( testPart ) > 0 );
782 m_part_no_data.SetNormal();
783
784 // Draw item list size comparison tests.
786 m_part_no_data.AddDrawItem( new SCH_SHAPE( SHAPE_T::RECTANGLE, LAYER_DEVICE ) );
787 BOOST_CHECK_EQUAL( m_part_no_data.Compare( testPart, ~SCH_ITEM::COMPARE_FLAGS::UUID ), 0 );
788 m_part_no_data.RemoveDrawItem( &m_part_no_data.GetDrawItems()[SCH_SHAPE_T].front() );
789 BOOST_CHECK( m_part_no_data.Compare( testPart, ~SCH_ITEM::COMPARE_FLAGS::UUID ) < 0 );
790 testPart.RemoveDrawItem( &testPart.GetDrawItems()[SCH_SHAPE_T].front() );
791 m_part_no_data.AddDrawItem( new SCH_SHAPE( SHAPE_T::RECTANGLE, LAYER_DEVICE ) );
792 BOOST_CHECK( m_part_no_data.Compare( testPart, ~SCH_ITEM::COMPARE_FLAGS::UUID ) > 0 );
793 m_part_no_data.RemoveDrawItem( &m_part_no_data.GetDrawItems()[SCH_SHAPE_T].front() );
794
795 // Draw item list contents comparison tests.
797 m_part_no_data.AddDrawItem( new SCH_SHAPE( SHAPE_T::ARC, LAYER_DEVICE ) );
798 BOOST_CHECK( m_part_no_data.Compare( testPart, ~SCH_ITEM::COMPARE_FLAGS::UUID ) > 0 );
799 m_part_no_data.RemoveDrawItem( &m_part_no_data.GetDrawItems()[SCH_SHAPE_T].front() );
800 testPart.RemoveDrawItem( &testPart.GetDrawItems()[SCH_SHAPE_T].front() );
801 m_part_no_data.AddDrawItem( new SCH_PIN( &m_part_no_data ) );
802 BOOST_CHECK( m_part_no_data.Compare( testPart, ~SCH_ITEM::COMPARE_FLAGS::UUID ) > 0 );
803 m_part_no_data.RemoveDrawItem( &m_part_no_data.GetDrawItems()[SCH_PIN_T].front() );
804
805 // Footprint filter array comparison tests.
806 wxArrayString footPrintFilters;
807 BOOST_CHECK( m_part_no_data.GetFPFilters() == footPrintFilters );
808 footPrintFilters.Add( "b" );
809 testPart.SetFPFilters( footPrintFilters );
810 BOOST_CHECK( m_part_no_data.Compare( testPart, ~SCH_ITEM::COMPARE_FLAGS::UUID ) < 0 );
811 m_part_no_data.SetFPFilters( footPrintFilters );
812 footPrintFilters.Clear();
813 testPart.SetFPFilters( footPrintFilters );
814 BOOST_CHECK( m_part_no_data.Compare( testPart, ~SCH_ITEM::COMPARE_FLAGS::UUID ) > 0 );
815 footPrintFilters.Clear();
816 m_part_no_data.SetFPFilters( footPrintFilters );
817 testPart.SetFPFilters( footPrintFilters );
818
819 // Description string tests.
820 m_part_no_data.SetDescription( "b" );
821 testPart.SetDescription( "b" );
822 BOOST_CHECK_EQUAL( m_part_no_data.Compare( testPart, ~SCH_ITEM::COMPARE_FLAGS::UUID ), 0 );
823 m_part_no_data.SetDescription( "a" );
824 BOOST_CHECK( m_part_no_data.Compare( testPart, ~SCH_ITEM::COMPARE_FLAGS::UUID ) < 0 );
825 m_part_no_data.SetDescription( "c" );
826 BOOST_CHECK( m_part_no_data.Compare( testPart, ~SCH_ITEM::COMPARE_FLAGS::UUID ) > 0 );
827 m_part_no_data.SetDescription( wxEmptyString );
828 testPart.SetDescription( wxEmptyString );
829
830 // Key word string tests.
831 m_part_no_data.SetKeyWords( "b" );
832 testPart.SetKeyWords( "b" );
833 BOOST_CHECK_EQUAL( m_part_no_data.Compare( testPart, ~SCH_ITEM::COMPARE_FLAGS::UUID ), 0 );
834 m_part_no_data.SetKeyWords( "a" );
835 BOOST_CHECK( m_part_no_data.Compare( testPart, ~SCH_ITEM::COMPARE_FLAGS::UUID ) < 0 );
836 m_part_no_data.SetKeyWords( "c" );
837 BOOST_CHECK( m_part_no_data.Compare( testPart, ~SCH_ITEM::COMPARE_FLAGS::UUID ) > 0 );
838 m_part_no_data.SetKeyWords( wxEmptyString );
839 testPart.SetKeyWords( wxEmptyString );
840
841 // Pin name offset comparison tests.
842 testPart.SetPinNameOffset( testPart.GetPinNameOffset() + 1 );
843 BOOST_CHECK( m_part_no_data.Compare( testPart, ~SCH_ITEM::COMPARE_FLAGS::UUID ) < 0 );
844 testPart.SetPinNameOffset( testPart.GetPinNameOffset() - 2 );
845 BOOST_CHECK( m_part_no_data.Compare( testPart, ~SCH_ITEM::COMPARE_FLAGS::UUID ) > 0 );
846 testPart.SetPinNameOffset( testPart.GetPinNameOffset() + 1 );
847
848 // Units locked flag comparison tests.
849 testPart.LockUnits( true );
850 BOOST_CHECK( m_part_no_data.Compare( testPart, ~SCH_ITEM::COMPARE_FLAGS::UUID ) < 0 );
851 testPart.LockUnits( false );
852 m_part_no_data.LockUnits( true );
853 BOOST_CHECK( m_part_no_data.Compare( testPart, ~SCH_ITEM::COMPARE_FLAGS::UUID ) > 0 );
854 m_part_no_data.LockUnits( false );
855
856 // Include in BOM support tests.
857 testPart.SetExcludedFromBOM( true );
858 BOOST_CHECK( m_part_no_data.Compare( testPart, ~SCH_ITEM::COMPARE_FLAGS::UUID ) > 0 );
859 testPart.SetExcludedFromBOM( false );
860 m_part_no_data.SetExcludedFromBOM( true );
861 BOOST_CHECK( m_part_no_data.Compare( testPart, ~SCH_ITEM::COMPARE_FLAGS::UUID ) < 0 );
862 m_part_no_data.SetExcludedFromBOM( false );
863
864 // Include on board support tests.
865 testPart.SetExcludedFromBoard( true );
866 BOOST_CHECK( m_part_no_data.Compare( testPart, ~SCH_ITEM::COMPARE_FLAGS::UUID ) > 0 );
867 testPart.SetExcludedFromBoard( false );
868 m_part_no_data.SetExcludedFromBoard( true );
869 BOOST_CHECK( m_part_no_data.Compare( testPart, ~SCH_ITEM::COMPARE_FLAGS::UUID ) < 0 );
870 m_part_no_data.SetExcludedFromBoard( false );
871
872 // Include in position files support tests.
873 testPart.SetExcludedFromPosFiles( true );
874 BOOST_CHECK( m_part_no_data.Compare( testPart, ~SCH_ITEM::COMPARE_FLAGS::UUID ) > 0 );
875 testPart.SetExcludedFromPosFiles( false );
876 m_part_no_data.SetExcludedFromPosFiles( true );
877 BOOST_CHECK( m_part_no_data.Compare( testPart, ~SCH_ITEM::COMPARE_FLAGS::UUID ) < 0 );
878 m_part_no_data.SetExcludedFromPosFiles( false );
879
880 // Show pin names flag comparison tests.
881 m_part_no_data.SetShowPinNames( false );
882 BOOST_CHECK( m_part_no_data.Compare( testPart, ~SCH_ITEM::COMPARE_FLAGS::UUID ) < 0 );
883 m_part_no_data.SetShowPinNames( true );
884 testPart.SetShowPinNames( false );
885 BOOST_CHECK( m_part_no_data.Compare( testPart, ~SCH_ITEM::COMPARE_FLAGS::UUID ) > 0 );
886 testPart.SetShowPinNames( true );
887
888 // Show pin numbers flag comparison tests.
889 m_part_no_data.SetShowPinNumbers( false );
890 BOOST_CHECK( m_part_no_data.Compare( testPart, ~SCH_ITEM::COMPARE_FLAGS::UUID ) < 0 );
891 m_part_no_data.SetShowPinNumbers( true );
892 testPart.SetShowPinNumbers( false );
893 BOOST_CHECK( m_part_no_data.Compare( testPart, ~SCH_ITEM::COMPARE_FLAGS::UUID ) > 0 );
894 testPart.SetShowPinNumbers( true );
895
896 // Time stamp comparison tests.
897
898 // Check to see if we broke the copy ctor.
899 LIB_SYMBOL copy( testPart );
900 BOOST_CHECK( testPart.Compare( copy ) == 0 );
901}
902
903
907BOOST_AUTO_TEST_CASE( GetUnitItems )
908{
909 // There are no unit draw items in the empty LIB_SYMBOL object.
910 BOOST_CHECK( m_part_no_data.GetUnitDrawItems( 1, 1 ).size() == 0 );
911
912 // A single unique unit with 1 pin common to all units and all body styles.
913 SCH_PIN* pin1 = new SCH_PIN( &m_part_no_data );
914 m_part_no_data.AddDrawItem( pin1 );
915 BOOST_CHECK( m_part_no_data.GetUnitDrawItems( ALL_UNITS, ALL_BODY_STYLES ).size() == 1 );
916
917 // A single unique unit with 1 pin in unit 1 and common to all body styles.
918 pin1->SetUnit( 1 );
919 BOOST_CHECK( m_part_no_data.GetUnitDrawItems( 1, ALL_BODY_STYLES ).size() == 1 );
920
921 // A single unique unit with 1 pin in unit 1 and body style 1.
922 pin1->SetBodyStyle( 1 );
923 BOOST_CHECK( m_part_no_data.GetUnitDrawItems( 1, 1 ).size() == 1 );
924
925 // Two unique units with pin 1 assigned to unit 1 and body style 1 and pin 2 assigned to
926 // unit 2 and body style 1.
927 SCH_PIN* pin2 = new SCH_PIN( &m_part_no_data );
928 m_part_no_data.SetUnitCount( 2, true );
929 pin2->SetUnit( 2 );
930 pin2->SetBodyStyle( 2 );
931 pin2->SetNumber( "4" );
932 m_part_no_data.AddDrawItem( pin2 );
933 BOOST_CHECK( m_part_no_data.GetUnitDrawItems( 2, 2 ).size() == 1 );
934
935 // Make pin 1 body style common to all body styles.
936 pin1->SetBodyStyle( ALL_BODY_STYLES );
937 BOOST_CHECK( m_part_no_data.GetUnitDrawItems( 1, 1 ).size() == 1 );
938 BOOST_CHECK( m_part_no_data.GetUnitDrawItems( 2, 1 ).size() == 1 );
939
940 m_part_no_data.RemoveDrawItem( pin2 );
941 m_part_no_data.RemoveDrawItem( pin1 );
942 m_part_no_data.RemoveDrawItem( &*m_part_no_data.GetDrawItems().begin() );
943}
944
945
949BOOST_AUTO_TEST_CASE( GetUnitDrawItems )
950{
951 // An empty symbol still reports its unit and body style so the saver writes them out
952 std::vector<struct LIB_SYMBOL_UNIT> units = m_part_no_data.GetUnitDrawItems();
953
954 BOOST_REQUIRE_EQUAL( units.size(), 1u );
955 BOOST_CHECK_EQUAL( units[0].m_unit, 1 );
956 BOOST_CHECK_EQUAL( units[0].m_bodyStyle, 1 );
957 BOOST_CHECK( units[0].m_items.empty() );
958
959 // A pin common to all units and all body styles matches no numbered unit and gets a
960 // record of its own rather than being dropped
961 SCH_PIN* pin1 = new SCH_PIN( &m_part_no_data );
962 pin1->SetNumber( "1" );
963 m_part_no_data.AddDrawItem( pin1 );
964
965 units = m_part_no_data.GetUnitDrawItems();
966
967 BOOST_REQUIRE_EQUAL( units.size(), 2u );
968 BOOST_CHECK_EQUAL( units[0].m_unit, 0 );
969 BOOST_CHECK_EQUAL( units[0].m_bodyStyle, 0 );
970 BOOST_REQUIRE_EQUAL( units[0].m_items.size(), 1u );
971 BOOST_CHECK_EQUAL( units[0].m_items[0], pin1 );
972 BOOST_CHECK_EQUAL( units[1].m_unit, 1 );
973 BOOST_CHECK_EQUAL( units[1].m_bodyStyle, 1 );
974 BOOST_CHECK( units[1].m_items.empty() );
975
976 // Units without draw items of their own are still reported
977 m_part_no_data.SetUnitCount( 3, true );
978
979 units = m_part_no_data.GetUnitDrawItems();
980
981 BOOST_REQUIRE_EQUAL( units.size(), 4u );
982 BOOST_CHECK_EQUAL( units[0].m_unit, 0 );
983 BOOST_CHECK_EQUAL( units[1].m_unit, 1 );
984 BOOST_CHECK_EQUAL( units[2].m_unit, 2 );
985 BOOST_CHECK_EQUAL( units[3].m_unit, 3 );
986 BOOST_CHECK( units[1].m_items.empty() );
987 BOOST_CHECK( units[2].m_items.empty() );
988 BOOST_CHECK( units[3].m_items.empty() );
989
990 // Both body styles of every unit are reported once De Morgan is enabled
991 m_part_no_data.SetHasDeMorganBodyStyles( true );
992
993 units = m_part_no_data.GetUnitDrawItems();
994
995 BOOST_REQUIRE_EQUAL( units.size(), 7u );
996 BOOST_CHECK_EQUAL( units[1].m_bodyStyle, 1 );
997 BOOST_CHECK_EQUAL( units[2].m_bodyStyle, 2 );
998}
999
1000
1005{
1006 std::unique_ptr<LIB_SYMBOL> parent = std::make_unique<LIB_SYMBOL>( "parent" );
1007 BOOST_CHECK( parent->IsRoot() );
1008 BOOST_CHECK_EQUAL( parent->GetInheritanceDepth(), 0 );
1009
1010 std::unique_ptr<LIB_SYMBOL> ref = std::make_unique<LIB_SYMBOL>( *parent );
1011
1012 std::unique_ptr<LIB_SYMBOL> child = std::make_unique<LIB_SYMBOL>( "child", parent.get() );
1013 BOOST_CHECK( child->IsDerived() );
1014 BOOST_CHECK_EQUAL( child->GetInheritanceDepth(), 1 );
1015
1016 std::unique_ptr<LIB_SYMBOL> grandChild = std::make_unique<LIB_SYMBOL>( "grandchild", child.get() );
1017 BOOST_CHECK( grandChild->IsDerived() );
1018 BOOST_CHECK_EQUAL( grandChild->GetInheritanceDepth(), 2 );
1019
1020 BOOST_CHECK( parent->GetRootSymbol().get() == parent.get() );
1021 BOOST_CHECK( child->GetRootSymbol().get() == parent.get() );
1022 BOOST_CHECK( grandChild->GetRootSymbol().get() == parent.get() );
1023
1024 std::shared_ptr<LIB_SYMBOL> parentRef = child->GetParent().lock();
1025 BOOST_CHECK( parentRef );
1026 BOOST_CHECK( parentRef == parent->SharedPtr() );
1027 BOOST_CHECK_EQUAL( parent->SharedPtr().use_count(), 3 );
1028
1029 std::shared_ptr<LIB_SYMBOL> childRef = grandChild->GetParent().lock();
1030 BOOST_CHECK( childRef );
1031 BOOST_CHECK( childRef == child->SharedPtr() );
1032 BOOST_CHECK_EQUAL( child->SharedPtr().use_count(), 3 );
1033
1034 BOOST_CHECK_EQUAL( child->GetUnitCount(), 1 );
1035 parent->SetUnitCount( 4, true );
1036 BOOST_CHECK_EQUAL( child->GetUnitCount(), 4 );
1037 parent->SetUnitCount( 1, true );
1038
1039 parent->GetField( FIELD_T::DATASHEET )->SetText( "https://kicad/resistors.pdf" );
1040 ref->GetField( FIELD_T::DATASHEET )->SetText( "https://kicad/resistors.pdf" );
1041
1042 BOOST_CHECK( *parent == *ref );
1043
1044 ref->SetName( "child" );
1045 SCH_FIELD* field = new SCH_FIELD( nullptr, FIELD_T::USER, "Manufacturer" );
1046 field->SetText( "KiCad" );
1047 child->AddField( field );
1048 field->SetParent( child.get() );
1049
1050 field = new SCH_FIELD( nullptr, FIELD_T::USER, "Manufacturer" );
1051 field->SetText( "KiCad" );
1052 ref->AddField( field );
1053 field->SetParent( ref.get() );
1054
1055 BOOST_CHECK( *ref == *child->Flatten() );
1056
1057 ref->SetName( "grandchild" );
1058 field = new SCH_FIELD( nullptr, FIELD_T::USER, "MPN" );
1059 field->SetText( "123456" );
1060 grandChild->AddField( field );
1061 field->SetParent( grandChild.get() );
1062
1063 field = new SCH_FIELD( nullptr, FIELD_T::USER, "MPN" );
1064 field->SetText( "123456" );
1065 ref->AddField( field );
1066 field->SetParent( ref.get() );
1067
1068 BOOST_CHECK( *ref == *grandChild->Flatten() );
1069
1070 BOOST_CHECK_EQUAL( grandChild->Flatten()->GetField( FIELD_T::DATASHEET )->GetText(),
1071 "https://kicad/resistors.pdf" );
1072
1073 child->SetParent();
1074 BOOST_CHECK_EQUAL( child->GetUnitCount(), 1 );
1075
1076 parentRef.reset();
1077 BOOST_CHECK_EQUAL( parent->SharedPtr().use_count(), 2 );
1078}
1079
1080
1084BOOST_AUTO_TEST_CASE( CopyConstructor )
1085{
1086 std::shared_ptr<LIB_SYMBOL> copy = std::make_shared<LIB_SYMBOL>( m_part_no_data );
1087 BOOST_CHECK( m_part_no_data == *copy.get() );
1088}
1089
1090
1095{
1096 std::unique_ptr<LIB_SYMBOL> symbol = std::make_unique<LIB_SYMBOL>( "power" );
1097 SCH_PIN* pin = new SCH_PIN( symbol.get() );
1098 pin->SetNumber( "1" );
1100 pin->SetVisible( false );
1101 symbol->AddDrawItem( pin );
1102
1103 BOOST_CHECK( !symbol->IsPower() );
1104 BOOST_CHECK( symbol->IsNormal() );
1105
1106 symbol->SetGlobalPower();
1107 BOOST_CHECK( symbol->IsPower() );
1108 BOOST_CHECK( !symbol->IsNormal() );
1109
1110 // symbol->SetNormal();
1111 // symbol->GetReferenceField().SetText( wxS( "#PWR" ) );
1112 // BOOST_CHECK( symbol->IsPower() );
1113
1114 // Legacy power symbols are limited to a single pin.
1115 // pin = new LIB_PIN( symbol.get() );
1116 // pin->SetNumber( "2" );
1117 // pin->SetType( ELECTRICAL_PINTYPE::PT_POWER_IN );
1118 // pin->SetVisible( false );
1119 // symbol->AddDrawItem( pin );
1120 // BOOST_CHECK( !symbol->IsPower() );
1121}
1122
1123
1133BOOST_AUTO_TEST_CASE( SetUnitCountRejectsInvalidValues )
1134{
1135 auto checkMandatoryFields = []( LIB_SYMBOL& aSymbol )
1136 {
1137 BOOST_CHECK_EQUAL( aSymbol.GetUnitCount(), 1 );
1138 BOOST_CHECK_NE( aSymbol.GetField( FIELD_T::REFERENCE ), nullptr );
1139 BOOST_CHECK_NE( aSymbol.GetField( FIELD_T::VALUE ), nullptr );
1140 BOOST_CHECK_NE( aSymbol.GetField( FIELD_T::FOOTPRINT ), nullptr );
1141 BOOST_CHECK_NE( aSymbol.GetField( FIELD_T::DATASHEET ), nullptr );
1142 BOOST_CHECK_NE( aSymbol.GetField( FIELD_T::DESCRIPTION ), nullptr );
1143
1144 // Reading the reference field text must not crash. This was the original SIGSEGV
1145 // path through CONNECTION_SUBGRAPH::GetDriverPriority() reported in issue 23788.
1146 BOOST_CHECK_NO_THROW( (void) aSymbol.GetReferenceField().GetText() );
1147 };
1148
1149 // Sanity check the freshly constructed symbol.
1150 LIB_SYMBOL baseline( wxS( "test_part" ) );
1151 checkMandatoryFields( baseline );
1152
1153 // When wxDEBUG_LEVEL > 0 the wxCHECK fires (caught by CHECK_WX_ASSERT) and the function
1154 // does not modify the symbol. With wxDEBUG_LEVEL == 0 the wxCHECK is silent and the
1155 // function returns early without modification. Cover both call paths so the test
1156 // exercises the actual SetUnitCount entry on every build configuration.
1157 LIB_SYMBOL zeroCount( wxS( "test_part" ) );
1158 CHECK_WX_ASSERT( zeroCount.SetUnitCount( 0, true ) );
1159#if wxDEBUG_LEVEL == 0
1160 zeroCount.SetUnitCount( 0, true );
1161#endif
1162 checkMandatoryFields( zeroCount );
1163
1164 LIB_SYMBOL negativeCount( wxS( "test_part" ) );
1165 CHECK_WX_ASSERT( negativeCount.SetUnitCount( -1, true ) );
1166#if wxDEBUG_LEVEL == 0
1167 negativeCount.SetUnitCount( -1, true );
1168#endif
1169 checkMandatoryFields( negativeCount );
1170}
1171
1172
1182BOOST_AUTO_TEST_CASE( DeleteDeMorganBodyStyleDrawItems )
1183{
1184 for( bool clearFlagFirst : { false, true } )
1185 {
1186 std::unique_ptr<LIB_SYMBOL> symbol = loadDeMorganSymbol();
1187 BOOST_REQUIRE( symbol );
1188 BOOST_REQUIRE( symbol->HasDeMorganBodyStyles() );
1190
1191 if( clearFlagFirst )
1192 {
1193 symbol->SetHasDeMorganBodyStyles( false );
1194 symbol->SetBodyStyleCount( 1, false, false );
1195 }
1196 else
1197 {
1198 symbol->SetBodyStyleCount( 1, false, false );
1199 symbol->SetHasDeMorganBodyStyles( false );
1200 }
1201
1202 symbol->SetBodyStyleNames( {} );
1203
1204 BOOST_CHECK_EQUAL( symbol->GetBodyStyleCount(), 1 );
1206 }
1207}
1208
1209
1214BOOST_AUTO_TEST_CASE( OrphanedBodyStyleItemsAreNotLoaded )
1215{
1216 std::unique_ptr<LIB_SYMBOL> symbol = loadDeMorganSymbol();
1217 BOOST_REQUIRE( symbol );
1218
1219 // Reproduce what a broken save left on disk: no De Morgan declaration, alternate drawings
1220 symbol->SetHasDeMorganBodyStyles( false );
1222
1223 SCOPED_TEMP_LIB tempLib;
1224 saveToLib( tempLib.GetPath(), *symbol );
1225
1226 IO_RELEASER<SCH_IO> pi( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_KICAD ) );
1227 LIB_SYMBOL* reloaded = pi->LoadSymbol( tempLib.GetPath(), wxS( "4001" ) );
1228
1229 BOOST_REQUIRE( reloaded );
1230 BOOST_CHECK_EQUAL( reloaded->GetBodyStyleCount(), 1 );
1232
1233 // The standard body style must survive the pruning
1234 BOOST_CHECK( !reloaded->GetUnitDrawItems( 1, BODY_STYLE::BASE ).empty() );
1235 BOOST_CHECK_EQUAL( reloaded->GetUnitCount(), symbol->GetUnitCount() );
1236}
1237
1238
1239BOOST_AUTO_TEST_CASE( NativeComparisonDetectsPinTypeChanges )
1240{
1241 LOCALE_IO locale;
1242 const auto original = loadDeMorganSymbol();
1243 BOOST_REQUIRE( original );
1244 LIB_SYMBOL changed( *original );
1247 BOOST_REQUIRE_EQUAL( original->Compare( changed, flags ), 0 );
1248 BOOST_REQUIRE_EQUAL( changed.Compare( *original, flags ), 0 );
1249 SCH_PIN* pin = changed.GetGraphicalPins( 0, 0 ).front();
1250 BOOST_REQUIRE( pin );
1251 const auto previous = pin->GetType();
1254 BOOST_REQUIRE( pin->GetType() != previous );
1255 BOOST_CHECK_NE( original->Compare( changed, flags ), 0 );
1256 BOOST_CHECK_NE( changed.Compare( *original, flags ), 0 );
1257}
1258
1259
1260BOOST_AUTO_TEST_CASE( NativeComparisonDetectsAddedPins )
1261{
1262 LOCALE_IO locale;
1263 const auto original = loadDeMorganSymbol();
1264 BOOST_REQUIRE( original );
1265 LIB_SYMBOL changed( *original );
1268 BOOST_REQUIRE_EQUAL( original->Compare( changed, flags ), 0 );
1269 BOOST_REQUIRE_EQUAL( changed.Compare( *original, flags ), 0 );
1270 const auto pins = original->GetGraphicalPins( 0, 0 );
1271 BOOST_REQUIRE( !pins.empty() );
1272 auto* extra = static_cast<SCH_PIN*>( pins.front()->Clone() );
1273 extra->SetNumber( "NativeExtra" );
1274 changed.AddDrawItem( extra );
1275 BOOST_REQUIRE_EQUAL( changed.GetGraphicalPins( 0, 0 ).size(), pins.size() + 1 );
1276 BOOST_CHECK_NE( original->Compare( changed, flags ), 0 );
1277 BOOST_CHECK_NE( changed.Compare( *original, flags ), 0 );
1278}
1279
1280
1281BOOST_AUTO_TEST_CASE( NativeComparisonHonorsMissingAndExtraFieldFlags )
1282{
1283 LOCALE_IO locale;
1284 const auto original = loadDeMorganSymbol();
1285 BOOST_REQUIRE( original );
1286 LIB_SYMBOL changed( *original );
1289 BOOST_REQUIRE_EQUAL( original->Compare( changed, flags ), 0 );
1290 BOOST_REQUIRE_EQUAL( changed.Compare( *original, flags ), 0 );
1291 const wxString name( "Native comparison field" );
1292 BOOST_REQUIRE( !original->GetField( name ) );
1293 changed.AddField( new SCH_FIELD( &changed, FIELD_T::USER, name ) );
1294 BOOST_REQUIRE( changed.GetField( name ) );
1295 BOOST_CHECK_EQUAL( original->Compare( changed, flags & ~SCH_ITEM::COMPARE_FLAGS::MISSING_FIELDS ), 0 );
1296 BOOST_CHECK_EQUAL( changed.Compare( *original, flags & ~SCH_ITEM::COMPARE_FLAGS::EXTRA_FIELDS ), 0 );
1297 BOOST_CHECK_NE( original->Compare( changed, flags ), 0 );
1298 BOOST_CHECK_NE( changed.Compare( *original, flags ), 0 );
1299}
1300
1301
1302BOOST_AUTO_TEST_CASE( NativeComparisonHonorsPinVisibilityFlag )
1303{
1304 LOCALE_IO locale;
1305 const auto original = loadDeMorganSymbol();
1306 BOOST_REQUIRE( original );
1307 LIB_SYMBOL changed( *original );
1310 BOOST_REQUIRE_EQUAL( original->Compare( changed, flags ), 0 );
1311 BOOST_REQUIRE_EQUAL( changed.Compare( *original, flags ), 0 );
1312 const auto pins = changed.GetGraphicalPins( 0, 0 );
1313 BOOST_REQUIRE( !pins.empty() );
1314 SCH_PIN* pin = pins.front();
1315 pin->SetVisible( !pin->IsVisible() );
1316 BOOST_CHECK_EQUAL( original->Compare( changed, flags & ~SCH_ITEM::COMPARE_FLAGS::PIN_VISIBILITIES ), 0 );
1317 BOOST_CHECK_EQUAL( changed.Compare( *original, flags & ~SCH_ITEM::COMPARE_FLAGS::PIN_VISIBILITIES ), 0 );
1318 BOOST_CHECK_NE( original->Compare( changed, flags ), 0 );
1319 BOOST_CHECK_NE( changed.Compare( *original, flags ), 0 );
1320}
1321
1322
1323BOOST_AUTO_TEST_CASE( NativeComparisonHonorsAlternateDefinitionFlag )
1324{
1325 LOCALE_IO locale;
1326 const auto original = loadDeMorganSymbol();
1327 BOOST_REQUIRE( original );
1328 LIB_SYMBOL changed( *original );
1331 BOOST_REQUIRE_EQUAL( original->Compare( changed, flags ), 0 );
1332 BOOST_REQUIRE_EQUAL( changed.Compare( *original, flags ), 0 );
1333 const auto pins = changed.GetGraphicalPins( 0, 0 );
1334 BOOST_REQUIRE( !pins.empty() );
1335 SCH_PIN* pin = pins.front();
1336 const wxString name( "Native alternate" );
1337 BOOST_REQUIRE( !pin->GetAlternates().contains( name ) );
1338 pin->GetAlternates().emplace( name, SCH_PIN::ALT{ name, GRAPHIC_PINSHAPE::LINE,
1340 BOOST_CHECK_EQUAL( original->Compare( changed, flags & ~SCH_ITEM::COMPARE_FLAGS::PIN_ALT_DEFS ), 0 );
1341 BOOST_CHECK_EQUAL( changed.Compare( *original, flags & ~SCH_ITEM::COMPARE_FLAGS::PIN_ALT_DEFS ), 0 );
1342 BOOST_CHECK_NE( original->Compare( changed, flags ), 0 );
1343 BOOST_CHECK_NE( changed.Compare( *original, flags ), 0 );
1344}
1345
1346
const char * name
constexpr EDA_IU_SCALE schIUScale
Definition base_units.h:130
virtual void SetParent(EDA_ITEM *aParent)
Definition eda_item.cpp:153
virtual void SetEnd(const VECTOR2I &aEnd)
Definition eda_shape.h:329
virtual void SetBezierC2(const VECTOR2I &aPt)
Definition eda_shape.h:367
virtual void SetBezierC1(const VECTOR2I &aPt)
Definition eda_shape.h:364
void RebuildBezierToSegmentsPointsList(int aMaxError)
Rebuild the m_bezierPoints vertex list that approximate the Bezier curve by a list of segments.
virtual void SetShape(SHAPE_T aShape)
Definition eda_shape.h:174
const std::vector< VECTOR2I > & GetBezierPoints() const
Definition eda_shape.h:491
virtual void SetStart(const VECTOR2I &aStart)
Definition eda_shape.h:279
virtual bool IsVisible() const
Definition eda_text.h:226
KIFONT::FONT * GetFont() const
Definition eda_text.h:286
virtual void SetVisible(bool aVisible)
Definition eda_text.cpp:347
void SetFont(KIFONT::FONT *aFont)
Definition eda_text.cpp:471
static FONT * GetFont(const wxString &aFontName=wxEmptyString, bool aBold=false, bool aItalic=false, const std::vector< wxString > *aEmbeddedFiles=nullptr, bool aForDrawingSheet=false)
Definition font.cpp:143
A logical library item identifier and consists of various portions much like a URI.
Definition lib_id.h:45
int SetLibItemName(const UTF8 &aLibItemName)
Override the library item name portion of the LIB_ID to aLibItemName.
Definition lib_id.cpp:124
int SetLibNickname(const UTF8 &aLibNickname)
Override the logical library name portion of the LIB_ID to aLibNickname.
Definition lib_id.cpp:113
Define a library symbol object.
Definition lib_symbol.h:114
const LIB_ID & GetLibId() const override
Definition lib_symbol.h:190
wxString GetKeyWords() const override
Definition lib_symbol.h:220
void SetGlobalPower()
std::vector< struct LIB_SYMBOL_UNIT > GetUnitDrawItems()
Return a list of SCH_ITEM objects separated by unit and convert number.
SCH_FIELD * GetField(const wxString &aFieldName)
Find a field within this symbol matching aFieldName; return nullptr if not found.
static wxString LetterSubReference(int aUnit, wxChar aInitialLetter)
void LockUnits(bool aLockUnits)
Set interchangeable the property for symbol units.
Definition lib_symbol.h:374
LIB_ITEMS_CONTAINER & GetDrawItems()
Return a reference to the draw item list.
Definition lib_symbol.h:843
void SetParent(LIB_SYMBOL *aParent=nullptr)
void SetUnitCount(int aCount, bool aDuplicateDrawItems)
Set the units per symbol count.
void SetDescription(const wxString &aDescription)
Set the Description field text value.
void SetKeyWords(const wxString &aKeyWords)
void RemoveDrawItem(SCH_ITEM *aItem)
Remove draw aItem from list.
void SetFPFilters(const wxArrayString &aFilters)
Definition lib_symbol.h:250
int GetBodyStyleCount() const override
The body styles are a property of the drawings, which a derived symbol inherits from its root symbol ...
LIB_SYMBOL_ATTRIBUTES ComparisonAttributes() const
int GetUnitCount() const override
void SetLibId(const LIB_ID &aLibId)
void AddField(SCH_FIELD *aField)
Add a field.
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.
int Compare(const LIB_SYMBOL &aRhs, int aCompareFlags=~COMPARE_FLAGS::UNIT, REPORTER *aReporter=nullptr) const
Comparison test that can be used for operators.
void AddDrawItem(SCH_ITEM *aItem, bool aSort=true)
Add a new draw aItem to the draw object list and sort according to aSort.
virtual void SetName(const wxString &aName)
void SetNormal()
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
Definition locale_io.h:37
bool empty(int aType=UNDEFINED_TYPE) const
A named pin map.
Definition pin_map.h:65
const wxString & GetName() const
Definition pin_map.h:70
void SetEntry(const wxString &aPinNumber, const wxString &aPadNumber)
Set the pad number for a symbol pin.
Definition pin_map.cpp:59
VECTOR2I GetPosition() const override
virtual const wxString & GetText() const override
Return the string associated with the text object.
Definition sch_field.h:139
void SetPosition(const VECTOR2I &aPosition) override
void SetText(const wxString &aText) override
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:170
virtual void SetBodyStyle(int aBodyStyle)
Definition sch_item.h:252
COMPARE_FLAGS
The list of flags used by various compare functions.
Definition sch_item.h:744
@ MISSING_FIELDS
Definition sch_item.h:748
@ EXTRA_FIELDS
Definition sch_item.h:749
@ PIN_ALT_DEFS
Definition sch_item.h:755
@ PIN_VISIBILITIES
Definition sch_item.h:754
virtual void SetUnit(int aUnit)
Definition sch_item.h:242
int GetLength() const
Definition sch_pin.cpp:421
void SetNumber(const wxString &aNumber)
Definition sch_pin.cpp:842
void SetLength(int aLength)
Definition sch_pin.h:119
PIN_ALTERNATE ALT
Definition sch_pin.h:63
void Move(const VECTOR2I &aOffset) override
Move the item by aMoveVector to a new position.
A temporary symbol library that is removed when it goes out of scope.
const wxString & GetPath() const
void SetExcludedFromBoard(bool aExclude, const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) override
Set or clear exclude from board netlist flag.
Definition symbol.h:210
virtual void SetShowPinNumbers(bool aShow)
Set or clear the pin number visibility flag.
Definition symbol.h:174
int GetPinNameOffset() const
Definition symbol.h:163
virtual void SetShowPinNames(bool aShow)
Set or clear the pin name visibility flag.
Definition symbol.h:168
void SetPinNameOffset(int aOffset)
Set the offset in mils of the pin name text from the pin symbol.
Definition symbol.h:162
void SetExcludedFromPosFiles(bool aExclude, const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) override
Set or clear exclude from position files flag.
Definition symbol.h:225
virtual void SetExcludedFromBOM(bool aExcludeFromBOM, const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) override
Set or clear the exclude from schematic bill of materials flag.
Definition symbol.h:195
LIB_SYMBOL m_part_no_data
Part with no extra data set.
static bool empty(const wxTextEntryBase *aCtrl)
@ RECTANGLE
Use RECTANGLE instead of RECT to avoid collision in a Windows header.
Definition eda_shape.h:57
std::unique_ptr< T > IO_RELEASER
Helper to hold and release an IO_BASE object when exceptions are thrown.
Definition io_mgr.h:33
@ LAYER_DEVICE
Definition layer_ids.h:488
Test utils (e.g.
std::string GetEeschemaTestDataDir()
Get the configured location of Eeschema test data.
bool AreDefaultFieldsCorrect(const std::vector< SCH_FIELD > &aFields)
Predicate to check that the mandatory fields look sensible.
bool FieldNameIdMatches(const SCH_FIELD &aField, const std::string &aExpectedName, int aExpectedId)
Predicate to check a field name is as expected.
LIBRARY_SYMBOL_FACT ExtractLibrarySymbolFact(const LIB_SYMBOL &aSymbol)
@ PT_INPUT
usual pin input: must be connected
Definition pin_type.h:33
@ PT_OUTPUT
usual output
Definition pin_type.h:34
@ PT_POWER_IN
power input (GND, VCC for ICs). Must be connected to a power output.
Definition pin_type.h:42
static const std::vector< std::string > filters
Definition plugin.cpp:64
@ BASE
Definition sch_item.h:64
#define ALL_UNITS
Definition symbol.h:150
#define ALL_BODY_STYLES
Definition symbol.h:151
@ USER
The field ID hasn't been set yet; field is invalid.
@ DESCRIPTION
Field Description of part, i.e. "1/4W 1% Metal Film Resistor".
@ FOOTPRINT
Field Name Module PCB, i.e. "16DIP300".
@ DATASHEET
name of datasheet
@ REFERENCE
Field Reference of part, i.e. "IC21".
@ VALUE
Field Value of part, i.e. "3.3K".
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_AUTO_TEST_SUITE_END()
KIBIS_PIN * pin1
KIBIS_PIN * pin
void CheckDuplicatePins(LIB_SYMBOL *aSymbol, std::vector< wxString > &aMessages, UNITS_PROVIDER *aUnitsProvider)
static void saveToLib(const wxString &aLibPath, const LIB_SYMBOL &aSymbol)
Write a symbol to its own library file.
static int alternateBodyStyleItemCount(LIB_SYMBOL &aSymbol)
Return the number of draw items belonging to a body style beyond the standard one.
static std::unique_ptr< LIB_SYMBOL > loadDeMorganSymbol()
Load 4001, a four unit NOR gate carrying a De Morgan alternate body style.
BOOST_AUTO_TEST_CASE(DefaultProperties)
Declare the test suite.
VECTOR3I expected(15, 30, 45)
BOOST_CHECK_PREDICATE(ArePolylineEndPointsNearCircle,(chain)(c.m_geom.m_center_point)(radius)(accuracy+epsilon))
BOOST_TEST_CONTEXT("Test Clearance")
BOOST_CHECK_EQUAL(result, "25.4")
@ SCH_SHAPE_T
Definition typeinfo.h:145
@ SCH_PIN_T
Definition typeinfo.h:149
#define CHECK_WX_ASSERT(STATEMENT)
A test macro to check a wxASSERT is thrown.
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:708