KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_sch_symbol.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, you may find one here:
18 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19 * or you may search the http://www.gnu.org website for the version 2 license,
20 * or you may write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23
28
30#include "eeschema_test_utils.h"
31
32// Code under test
33#include <sch_symbol.h>
34#include <sch_edit_frame.h>
36#include <lib_symbol.h>
37#include <eda_search_data.h>
38
39
41{
42public:
44 {
45 if( !m_schematic )
46 return nullptr;
47
48 SCH_SCREEN* screen = m_schematic->RootScreen();
49
50 if( !screen )
51 return nullptr;
52
53 for( SCH_ITEM* item : screen->Items().OfType( SCH_SYMBOL_T ) )
54 {
55 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
56
57 if( symbol )
58 return symbol;
59 }
60
61 return nullptr;
62 }
63
66};
67
68
72BOOST_FIXTURE_TEST_SUITE( SchSymbol, TEST_SCH_SYMBOL_FIXTURE )
73
74
75
78BOOST_AUTO_TEST_CASE( DefaultProperties )
79{
80}
81
82
87{
88 TRANSFORM t = m_symbol.GetTransform();
89
90 m_symbol.SetOrientation( SYM_ORIENT_90 );
91 t = m_symbol.GetTransform();
92 m_symbol.SetTransform( TRANSFORM() );
93 m_symbol.SetOrientation( SYM_ORIENT_180 );
94 t = m_symbol.GetTransform();
95 m_symbol.SetTransform( TRANSFORM() );
96 m_symbol.SetOrientation( SYM_ORIENT_270 );
97 t = m_symbol.GetTransform();
98}
99
100
104BOOST_AUTO_TEST_CASE( SchSymbolVariantTest )
105{
106 wxFileName fn;
107 fn.SetPath( KI_TEST::GetEeschemaTestDataDir() );
108 fn.AppendDir( wxS( "variant_test" ) );
109 fn.SetName( wxS( "variant_test" ) );
111
112 LoadSchematic( fn.GetFullPath() );
113
114 SCH_SYMBOL* symbol = GetFirstSymbol();
115 BOOST_CHECK( symbol );
116
117 // Test for an empty (non-existant) variant.
118 wxString variantName = wxS( "Variant1" );
119 std::optional<SCH_SYMBOL_VARIANT> variant = symbol->GetVariant( m_schematic->Hierarchy()[0], variantName );
120 BOOST_CHECK( !variant );
121
122 // Test DNP property variant.
123 BOOST_CHECK( !symbol->GetDNP() );
124 symbol->SetDNP( true, &m_schematic->Hierarchy()[0], variantName );
125 BOOST_CHECK( symbol->GetDNP( &m_schematic->Hierarchy()[0], variantName ) );
126
127 // Test exclude from BOM property variant.
128 BOOST_CHECK( !symbol->GetExcludedFromBOM() );
129 symbol->SetExcludedFromBOM( true, &m_schematic->Hierarchy()[0], variantName );
130 BOOST_CHECK( symbol->GetExcludedFromBOM( &m_schematic->Hierarchy()[0], variantName ) );
131
132 // Test exclude from simulation property variant.
133 BOOST_CHECK( !symbol->GetExcludedFromSim() );
134 symbol->SetExcludedFromSim( true, &m_schematic->Hierarchy()[0], variantName );
135 BOOST_CHECK( symbol->GetExcludedFromSim( &m_schematic->Hierarchy()[0], variantName ) );
136
137 // Test exclude from board property variant.
138 BOOST_CHECK( !symbol->GetExcludedFromBoard() );
139 symbol->SetExcludedFromBoard( true, &m_schematic->Hierarchy()[0], variantName );
140 BOOST_CHECK( symbol->GetExcludedFromBoard( &m_schematic->Hierarchy()[0], variantName ) );
141
142 // Test exclude from position files property variant.
143 BOOST_CHECK( !symbol->GetExcludedFromPosFiles() );
144 symbol->SetExcludedFromPosFiles( true, &m_schematic->Hierarchy()[0], variantName );
145 BOOST_CHECK( symbol->GetExcludedFromPosFiles( &m_schematic->Hierarchy()[0], variantName ) );
146
147 // Test a value field variant change.
148 BOOST_CHECK( symbol->GetField( FIELD_T::VALUE )->GetShownText( &m_schematic->Hierarchy()[0],
149 false, 0 ) == wxS( "1K" ) );
150 symbol->GetField( FIELD_T::VALUE )->SetText( wxS( "10K" ), &m_schematic->Hierarchy()[0], variantName );
151 BOOST_CHECK( symbol->GetField( FIELD_T::VALUE )->GetShownText( &m_schematic->Hierarchy()[0],
152 false, 0, variantName ) == wxS( "10K" ) );
153 // BOOST_CHECK( symbol->GetFieldText( FIELD_T::VALUE, &m_schematic->Hierarchy()[0], variantName ) == wxS( "10K" ) );
154}
155
156
162BOOST_AUTO_TEST_CASE( FieldAdditionByName )
163{
164 wxFileName fn;
165 fn.SetPath( KI_TEST::GetEeschemaTestDataDir() );
166 fn.AppendDir( wxS( "variant_test" ) );
167 fn.SetName( wxS( "variant_test" ) );
169
170 LoadSchematic( fn.GetFullPath() );
171
172 SCH_SYMBOL* symbol = GetFirstSymbol();
173 BOOST_REQUIRE( symbol );
174
175 wxString newFieldName = wxS( "Sim.Library" );
176
177 // GetField by name should return null for non-existent field
178 const SCH_FIELD* existing = symbol->GetField( newFieldName );
179 BOOST_CHECK( existing == nullptr );
180
181 // Create a field to add
182 SCH_FIELD newField( symbol, FIELD_T::USER, newFieldName );
183 newField.SetText( wxS( "test_model.lib" ) );
184
185 // AddField should add the field and return a valid pointer
186 SCH_FIELD* addedField = symbol->AddField( newField );
187 BOOST_REQUIRE( addedField != nullptr );
188
189 // After setting the parent, verify the field is correctly configured
190 addedField->SetParent( symbol );
191 BOOST_CHECK( addedField->GetParent() == symbol );
192
193 // Now GetField should find the newly added field
194 const SCH_FIELD* found = symbol->GetField( newFieldName );
195 BOOST_REQUIRE( found != nullptr );
196 BOOST_CHECK( found->GetText() == wxS( "test_model.lib" ) );
197}
198
199
208BOOST_AUTO_TEST_CASE( UndoSwapItemDataRestoresUnitPinDisplayState )
209{
210 LoadSchematic( SchematicQAPath( wxS( "component_classes" ) ) );
211 BOOST_REQUIRE( m_schematic );
212
213 SCH_SHEET_LIST hierarchy = m_schematic->Hierarchy();
214 BOOST_REQUIRE( !hierarchy.empty() );
215
216 const SCH_SHEET_PATH& sheet = hierarchy[0];
217 SCH_SYMBOL* symbol = nullptr;
218
219 for( SCH_ITEM* item : m_schematic->RootScreen()->Items().OfType( SCH_SYMBOL_T ) )
220 {
221 SCH_SYMBOL* candidate = static_cast<SCH_SYMBOL*>( item );
222
223 if( candidate->GetRef( &sheet, false ) == wxS( "U1" )
224 && candidate->GetUnitSelection( &sheet ) == 1 )
225 {
226 symbol = candidate;
227 break;
228 }
229 }
230
231 BOOST_REQUIRE( symbol );
232
233 auto pinNumbers =
234 []( const std::vector<SCH_PIN*>& aPins )
235 {
236 std::set<wxString> numbers;
237
238 for( SCH_PIN* pin : aPins )
239 numbers.insert( pin->GetNumber() );
240
241 return numbers;
242 };
243
244 const std::set<wxString> unitAPins = { wxS( "1" ), wxS( "2" ), wxS( "3" ) };
245 const std::set<wxString> unitBPins = { wxS( "5" ), wxS( "6" ), wxS( "7" ) };
246
247 BOOST_CHECK_EQUAL( symbol->GetUnitSelection( &sheet ), 1 );
248 BOOST_CHECK_EQUAL( symbol->GetUnit(), 1 );
249 BOOST_CHECK( pinNumbers( symbol->GetLibPins() ) == unitAPins );
250
251 std::unique_ptr<SCH_SYMBOL> undoImage( static_cast<SCH_SYMBOL*>( symbol->Clone() ) );
252
253 symbol->SetUnitSelection( &sheet, 2 );
254 symbol->SetUnit( 2 );
255
256 BOOST_CHECK_EQUAL( symbol->GetUnitSelection( &sheet ), 2 );
257 BOOST_CHECK_EQUAL( symbol->GetUnit(), 2 );
258 BOOST_CHECK( pinNumbers( symbol->GetLibPins() ) == unitBPins );
259
260 symbol->SwapItemData( undoImage.get() );
261 symbol->UpdatePins();
262
263 BOOST_CHECK_EQUAL( symbol->GetUnitSelection( &sheet ), 1 );
264 BOOST_CHECK_EQUAL( symbol->GetUnit(), 1 );
265 BOOST_CHECK( pinNumbers( symbol->GetLibPins() ) == unitAPins );
266
267 BOOST_CHECK_EQUAL( undoImage->GetUnitSelection( &sheet ), 2 );
268 BOOST_CHECK_EQUAL( undoImage->GetUnit(), 2 );
269 BOOST_CHECK( pinNumbers( undoImage->GetLibPins() ) == unitBPins );
270}
271
272
285BOOST_AUTO_TEST_CASE( VariantDialogBatchCommit )
286{
287 wxFileName fn;
288 fn.SetPath( KI_TEST::GetEeschemaTestDataDir() );
289 fn.AppendDir( wxS( "variant_test" ) );
290 fn.SetName( wxS( "variant_test" ) );
292
293 LoadSchematic( fn.GetFullPath() );
294
295 SCH_SYMBOL* symbol = GetFirstSymbol();
296 BOOST_REQUIRE( symbol );
297
298 SCH_SHEET_LIST hierarchy = m_schematic->Hierarchy();
299 const SCH_SHEET_PATH& sheet = hierarchy[0];
300 wxString variantName = wxS( "DialogTest" );
301
302 // All base properties should start false.
303 BOOST_CHECK( !symbol->GetDNP() );
304 BOOST_CHECK( !symbol->GetExcludedFromBOM() );
305 BOOST_CHECK( !symbol->GetExcludedFromSim() );
306 BOOST_CHECK( !symbol->GetExcludedFromBoard() );
307 BOOST_CHECK( !symbol->GetExcludedFromPosFiles() );
308
309 // Simulate dialog_symbol_properties TransferDataFromWindow call order.
310 // ExcludeFromSim is left unchecked (false), the other four are checked (true).
311 symbol->SetExcludedFromSim( false, &sheet, variantName );
312 symbol->SetExcludedFromBOM( true, &sheet, variantName );
313 symbol->SetExcludedFromBoard( true, &sheet, variantName );
314 symbol->SetExcludedFromPosFiles( true, &sheet, variantName );
315 symbol->SetDNP( true, &sheet, variantName );
316
317 // All four checked properties must read back as true through the variant.
318 BOOST_CHECK( symbol->GetDNP( &sheet, variantName ) );
319 BOOST_CHECK( symbol->GetExcludedFromBOM( &sheet, variantName ) );
320 BOOST_CHECK( symbol->GetExcludedFromBoard( &sheet, variantName ) );
321 BOOST_CHECK( symbol->GetExcludedFromPosFiles( &sheet, variantName ) );
322 BOOST_CHECK( !symbol->GetExcludedFromSim( &sheet, variantName ) );
323
324 // Base properties must remain unchanged.
325 BOOST_CHECK( !symbol->GetDNP() );
326 BOOST_CHECK( !symbol->GetExcludedFromBOM() );
327 BOOST_CHECK( !symbol->GetExcludedFromBoard() );
328 BOOST_CHECK( !symbol->GetExcludedFromPosFiles() );
329}
330
331
335BOOST_AUTO_TEST_CASE( VariantDescription )
336{
337 wxFileName fn;
338 fn.SetPath( KI_TEST::GetEeschemaTestDataDir() );
339 fn.AppendDir( wxS( "variant_test" ) );
340 fn.SetName( wxS( "variant_test" ) );
342
343 LoadSchematic( fn.GetFullPath() );
344 BOOST_REQUIRE( m_schematic );
345
346 wxString variantName = wxS( "TestVariant" );
347 wxString description = wxS( "This is a test variant description" );
348
349 // Add a variant
350 m_schematic->AddVariant( variantName );
351 BOOST_CHECK( m_schematic->GetVariantNames().contains( variantName ) );
352
353 // Set description
354 m_schematic->SetVariantDescription( variantName, description );
355 BOOST_CHECK_EQUAL( m_schematic->GetVariantDescription( variantName ), description );
356
357 // Empty description for non-existent variant
358 BOOST_CHECK( m_schematic->GetVariantDescription( wxS( "NonExistent" ) ).IsEmpty() );
359
360 // Clear description
361 m_schematic->SetVariantDescription( variantName, wxEmptyString );
362 BOOST_CHECK( m_schematic->GetVariantDescription( variantName ).IsEmpty() );
363}
364
365
369BOOST_AUTO_TEST_CASE( TextVariableVARIANT )
370{
371 wxFileName fn;
372 fn.SetPath( KI_TEST::GetEeschemaTestDataDir() );
373 fn.AppendDir( wxS( "variant_test" ) );
374 fn.SetName( wxS( "variant_test" ) );
376
377 LoadSchematic( fn.GetFullPath() );
378 BOOST_REQUIRE( m_schematic );
379
380 wxString variantName = wxS( "MilitaryGrade" );
381
382 // Add a variant and set it as current
383 m_schematic->AddVariant( variantName );
384 m_schematic->SetCurrentVariant( variantName );
385
386 // Test that ${VARIANT} resolves to the current variant name
387 wxString token = wxS( "VARIANT" );
388 bool resolved = m_schematic->ResolveTextVar( &m_schematic->Hierarchy()[0], &token, 0 );
389 BOOST_CHECK( resolved );
390 BOOST_CHECK_EQUAL( token, variantName );
391
392 // Also test VARIANTNAME (legacy/alias)
393 token = wxS( "VARIANTNAME" );
394 resolved = m_schematic->ResolveTextVar( &m_schematic->Hierarchy()[0], &token, 0 );
395 BOOST_CHECK( resolved );
396 BOOST_CHECK_EQUAL( token, variantName );
397
398 // Empty variant
399 m_schematic->SetCurrentVariant( wxEmptyString );
400 token = wxS( "VARIANT" );
401 resolved = m_schematic->ResolveTextVar( &m_schematic->Hierarchy()[0], &token, 0 );
402 BOOST_CHECK( resolved );
403 BOOST_CHECK( token.IsEmpty() );
404}
405
406
410BOOST_AUTO_TEST_CASE( TextVariableVARIANT_DESC )
411{
412 wxFileName fn;
413 fn.SetPath( KI_TEST::GetEeschemaTestDataDir() );
414 fn.AppendDir( wxS( "variant_test" ) );
415 fn.SetName( wxS( "variant_test" ) );
417
418 LoadSchematic( fn.GetFullPath() );
419 BOOST_REQUIRE( m_schematic );
420
421 wxString variantName = wxS( "IndustrialVariant" );
422 wxString description = wxS( "Industrial temperature range components" );
423
424 // Add a variant with description and set it as current
425 m_schematic->AddVariant( variantName );
426 m_schematic->SetVariantDescription( variantName, description );
427 m_schematic->SetCurrentVariant( variantName );
428
429 // Test that ${VARIANT_DESC} resolves to the variant description
430 wxString token = wxS( "VARIANT_DESC" );
431 bool resolved = m_schematic->ResolveTextVar( &m_schematic->Hierarchy()[0], &token, 0 );
432 BOOST_CHECK( resolved );
433 BOOST_CHECK_EQUAL( token, description );
434
435 // Test with no description set
436 m_schematic->SetVariantDescription( variantName, wxEmptyString );
437 token = wxS( "VARIANT_DESC" );
438 resolved = m_schematic->ResolveTextVar( &m_schematic->Hierarchy()[0], &token, 0 );
439 BOOST_CHECK( resolved );
440 BOOST_CHECK( token.IsEmpty() );
441}
442
443
447BOOST_AUTO_TEST_CASE( RenameVariantPreservesData )
448{
449 wxFileName fn;
450 fn.SetPath( KI_TEST::GetEeschemaTestDataDir() );
451 fn.AppendDir( wxS( "variant_test" ) );
452 fn.SetName( wxS( "variant_test" ) );
454
455 LoadSchematic( fn.GetFullPath() );
456 BOOST_REQUIRE( m_schematic );
457
458 SCH_SYMBOL* symbol = GetFirstSymbol();
459 BOOST_REQUIRE( symbol );
460
461 wxString oldName = wxS( "OriginalVariant" );
462 wxString newName = wxS( "RenamedVariant" );
463 wxString description = wxS( "Original description" );
464
465 // Set up the variant with data
466 m_schematic->AddVariant( oldName );
467 m_schematic->SetVariantDescription( oldName, description );
468 m_schematic->SetCurrentVariant( oldName );
469
470 // Set symbol variant properties
471 symbol->SetDNP( true, &m_schematic->Hierarchy()[0], oldName );
472 symbol->GetField( FIELD_T::VALUE )->SetText( wxS( "100K" ), &m_schematic->Hierarchy()[0], oldName );
473
474 // Verify the data is set
475 BOOST_CHECK( symbol->GetDNP( &m_schematic->Hierarchy()[0], oldName ) );
476 BOOST_CHECK_EQUAL( symbol->GetField( FIELD_T::VALUE )->GetShownText( &m_schematic->Hierarchy()[0],
477 false, 0, oldName ), wxS( "100K" ) );
478
479 // Rename the variant
480 m_schematic->RenameVariant( oldName, newName );
481
482 // Verify old name is gone
483 BOOST_CHECK( !m_schematic->GetVariantNames().contains( oldName ) );
484
485 // Verify new name exists
486 BOOST_CHECK( m_schematic->GetVariantNames().contains( newName ) );
487
488 // Verify description was preserved
489 BOOST_CHECK_EQUAL( m_schematic->GetVariantDescription( newName ), description );
490
491 // Verify current variant was updated
492 BOOST_CHECK_EQUAL( m_schematic->GetCurrentVariant(), newName );
493
494 // Verify symbol variant data was preserved
495 BOOST_CHECK( symbol->GetDNP( &m_schematic->Hierarchy()[0], newName ) );
496 BOOST_CHECK_EQUAL( symbol->GetField( FIELD_T::VALUE )->GetShownText( &m_schematic->Hierarchy()[0],
497 false, 0, newName ), wxS( "100K" ) );
498}
499
500
504BOOST_AUTO_TEST_CASE( CopyVariantCreatesIndependentCopy )
505{
506 wxFileName fn;
507 fn.SetPath( KI_TEST::GetEeschemaTestDataDir() );
508 fn.AppendDir( wxS( "variant_test" ) );
509 fn.SetName( wxS( "variant_test" ) );
511
512 LoadSchematic( fn.GetFullPath() );
513 BOOST_REQUIRE( m_schematic );
514
515 SCH_SYMBOL* symbol = GetFirstSymbol();
516 BOOST_REQUIRE( symbol );
517
518 wxString sourceVariant = wxS( "SourceVariant" );
519 wxString copyVariant = wxS( "CopiedVariant" );
520 wxString description = wxS( "Source description" );
521
522 // Set up the source variant
523 m_schematic->AddVariant( sourceVariant );
524 m_schematic->SetVariantDescription( sourceVariant, description );
525
526 // Set symbol variant properties for source
527 symbol->SetDNP( true, &m_schematic->Hierarchy()[0], sourceVariant );
528 symbol->SetExcludedFromBOM( true, &m_schematic->Hierarchy()[0], sourceVariant );
529 symbol->SetExcludedFromBoard( true, &m_schematic->Hierarchy()[0], sourceVariant );
530 symbol->SetExcludedFromPosFiles( true, &m_schematic->Hierarchy()[0], sourceVariant );
531 symbol->GetField( FIELD_T::VALUE )->SetText( wxS( "47K" ), &m_schematic->Hierarchy()[0], sourceVariant );
532
533 // Copy the variant
534 m_schematic->CopyVariant( sourceVariant, copyVariant );
535
536 // Verify both variants exist
537 BOOST_CHECK( m_schematic->GetVariantNames().contains( sourceVariant ) );
538 BOOST_CHECK( m_schematic->GetVariantNames().contains( copyVariant ) );
539
540 // Verify description was copied
541 BOOST_CHECK_EQUAL( m_schematic->GetVariantDescription( copyVariant ), description );
542
543 // Verify symbol properties were copied
544 BOOST_CHECK( symbol->GetDNP( &m_schematic->Hierarchy()[0], copyVariant ) );
545 BOOST_CHECK( symbol->GetExcludedFromBOM( &m_schematic->Hierarchy()[0], copyVariant ) );
546 BOOST_CHECK( symbol->GetExcludedFromBoard( &m_schematic->Hierarchy()[0], copyVariant ) );
547 BOOST_CHECK( symbol->GetExcludedFromPosFiles( &m_schematic->Hierarchy()[0], copyVariant ) );
548 BOOST_CHECK_EQUAL( symbol->GetField( FIELD_T::VALUE )->GetShownText( &m_schematic->Hierarchy()[0],
549 false, 0, copyVariant ), wxS( "47K" ) );
550
551 // Modify the copy and verify source is unchanged
552 symbol->SetDNP( false, &m_schematic->Hierarchy()[0], copyVariant );
553 symbol->GetField( FIELD_T::VALUE )->SetText( wxS( "100K" ), &m_schematic->Hierarchy()[0], copyVariant );
554
555 // Source should still have original values
556 BOOST_CHECK( symbol->GetDNP( &m_schematic->Hierarchy()[0], sourceVariant ) );
557 BOOST_CHECK_EQUAL( symbol->GetField( FIELD_T::VALUE )->GetShownText( &m_schematic->Hierarchy()[0],
558 false, 0, sourceVariant ), wxS( "47K" ) );
559
560 // Copy should have modified values
561 BOOST_CHECK( !symbol->GetDNP( &m_schematic->Hierarchy()[0], copyVariant ) );
562 BOOST_CHECK_EQUAL( symbol->GetField( FIELD_T::VALUE )->GetShownText( &m_schematic->Hierarchy()[0],
563 false, 0, copyVariant ), wxS( "100K" ) );
564}
565
566
570BOOST_AUTO_TEST_CASE( VariantFieldDifferenceDetection )
571{
572 wxFileName fn;
573 fn.SetPath( KI_TEST::GetEeschemaTestDataDir() );
574 fn.AppendDir( wxS( "variant_test" ) );
575 fn.SetName( wxS( "variant_test" ) );
577
578 LoadSchematic( fn.GetFullPath() );
579 BOOST_REQUIRE( m_schematic );
580
581 SCH_SYMBOL* symbol = GetFirstSymbol();
582 BOOST_REQUIRE( symbol );
583
584 wxString variantName1 = wxS( "DiffTestVariant1" );
585 wxString variantName2 = wxS( "DiffTestVariant2" );
586
587 // Get the default value
588 wxString defaultValue = symbol->GetField( FIELD_T::VALUE )->GetShownText( &m_schematic->Hierarchy()[0],
589 false, 0 );
590 BOOST_CHECK_EQUAL( defaultValue, wxS( "1K" ) );
591
592 // Add a variant and set a different value
593 m_schematic->AddVariant( variantName1 );
594 symbol->GetField( FIELD_T::VALUE )->SetText( wxS( "2.2K" ), &m_schematic->Hierarchy()[0], variantName1 );
595
596 // Get variant value
597 wxString variantValue = symbol->GetField( FIELD_T::VALUE )->GetShownText( &m_schematic->Hierarchy()[0],
598 false, 0, variantName1 );
599 BOOST_CHECK_EQUAL( variantValue, wxS( "2.2K" ) );
600
601 // Verify values differ
602 BOOST_CHECK( defaultValue != variantValue );
603
604 // Add another variant with same value as default to verify equality detection
605 m_schematic->AddVariant( variantName2 );
606 symbol->GetField( FIELD_T::VALUE )->SetText( wxS( "1K" ), &m_schematic->Hierarchy()[0], variantName2 );
607 wxString variantValue2 = symbol->GetField( FIELD_T::VALUE )->GetShownText( &m_schematic->Hierarchy()[0],
608 false, 0, variantName2 );
609
610 // Second variant should have the same value as default
611 BOOST_CHECK_EQUAL( defaultValue, variantValue2 );
612}
613
614
618BOOST_AUTO_TEST_CASE( VariantDNPFiltering )
619{
620 wxFileName fn;
621 fn.SetPath( KI_TEST::GetEeschemaTestDataDir() );
622 fn.AppendDir( wxS( "variant_test" ) );
623 fn.SetName( wxS( "variant_test" ) );
625
626 LoadSchematic( fn.GetFullPath() );
627 BOOST_REQUIRE( m_schematic );
628
629 SCH_SYMBOL* symbol = GetFirstSymbol();
630 BOOST_REQUIRE( symbol );
631
632 wxString variantName = wxS( "DNPVariant" );
633
634 // By default, symbol should not be DNP
635 BOOST_CHECK( !symbol->GetDNP() );
636 BOOST_CHECK( !symbol->GetDNP( &m_schematic->Hierarchy()[0], wxEmptyString ) );
637
638 // Add a variant where symbol is DNP
639 m_schematic->AddVariant( variantName );
640 symbol->SetDNP( true, &m_schematic->Hierarchy()[0], variantName );
641
642 // Default should still not be DNP
643 BOOST_CHECK( !symbol->GetDNP() );
644 BOOST_CHECK( !symbol->GetDNP( &m_schematic->Hierarchy()[0], wxEmptyString ) );
645
646 // Variant should be DNP
647 BOOST_CHECK( symbol->GetDNP( &m_schematic->Hierarchy()[0], variantName ) );
648
649 // Test exclude from BOM as well
650 BOOST_CHECK( !symbol->GetExcludedFromBOM() );
651 symbol->SetExcludedFromBOM( true, &m_schematic->Hierarchy()[0], variantName );
652 BOOST_CHECK( symbol->GetExcludedFromBOM( &m_schematic->Hierarchy()[0], variantName ) );
653 BOOST_CHECK( !symbol->GetExcludedFromBOM( &m_schematic->Hierarchy()[0], wxEmptyString ) );
654
655 // Test exclude from board as well
656 BOOST_CHECK( !symbol->GetExcludedFromBoard() );
657 symbol->SetExcludedFromBoard( true, &m_schematic->Hierarchy()[0], variantName );
658 BOOST_CHECK( symbol->GetExcludedFromBoard( &m_schematic->Hierarchy()[0], variantName ) );
659 BOOST_CHECK( !symbol->GetExcludedFromBoard( &m_schematic->Hierarchy()[0], wxEmptyString ) );
660
661 // Test exclude from position files as well
662 BOOST_CHECK( !symbol->GetExcludedFromPosFiles() );
663 symbol->SetExcludedFromPosFiles( true, &m_schematic->Hierarchy()[0], variantName );
664 BOOST_CHECK( symbol->GetExcludedFromPosFiles( &m_schematic->Hierarchy()[0], variantName ) );
665 BOOST_CHECK( !symbol->GetExcludedFromPosFiles( &m_schematic->Hierarchy()[0], wxEmptyString ) );
666}
667
668
672BOOST_AUTO_TEST_CASE( GetVariantNamesForUI )
673{
674 wxFileName fn;
675 fn.SetPath( KI_TEST::GetEeschemaTestDataDir() );
676 fn.AppendDir( wxS( "variant_test" ) );
677 fn.SetName( wxS( "variant_test" ) );
679
680 LoadSchematic( fn.GetFullPath() );
681 BOOST_REQUIRE( m_schematic );
682
683 // Add some variants
684 m_schematic->AddVariant( wxS( "Zebra" ) );
685 m_schematic->AddVariant( wxS( "Alpha" ) );
686 m_schematic->AddVariant( wxS( "Beta" ) );
687
688 wxArrayString variantNames = m_schematic->GetVariantNamesForUI();
689
690 // Should have at least 4 items (default + 3 variants)
691 BOOST_CHECK( variantNames.GetCount() >= 4 );
692
693 // First item should be the default placeholder
694 // The actual string may vary but should represent "default"
695 BOOST_CHECK( !variantNames[0].IsEmpty() );
696
697 // Remaining items should be sorted
698 // Alpha, Beta, Zebra
699 bool foundAlpha = false;
700 bool foundBeta = false;
701 bool foundZebra = false;
702
703 for( size_t i = 1; i < variantNames.GetCount(); i++ )
704 {
705 if( variantNames[i] == wxS( "Alpha" ) )
706 foundAlpha = true;
707 else if( variantNames[i] == wxS( "Beta" ) )
708 foundBeta = true;
709 else if( variantNames[i] == wxS( "Zebra" ) )
710 foundZebra = true;
711 }
712
713 BOOST_CHECK( foundAlpha );
714 BOOST_CHECK( foundBeta );
715 BOOST_CHECK( foundZebra );
716}
717
718
724BOOST_AUTO_TEST_CASE( SetValueFieldTextPersistsVariantValue )
725{
726 wxFileName fn;
727 fn.SetPath( KI_TEST::GetEeschemaTestDataDir() );
728 fn.AppendDir( wxS( "variant_test" ) );
729 fn.SetName( wxS( "variant_test" ) );
731
732 LoadSchematic( fn.GetFullPath() );
733 BOOST_REQUIRE( m_schematic );
734
735 SCH_SYMBOL* symbol = GetFirstSymbol();
736 BOOST_REQUIRE( symbol );
737
738 wxString variantName = wxS( "PersistenceTest" );
739 wxString newValue = wxS( "4.7K" );
740 wxString defaultValue = symbol->GetField( FIELD_T::VALUE )->GetText();
741
742 // Add the variant
743 m_schematic->AddVariant( variantName );
744
745 // Set value using SetValueFieldText (the function that had the bug)
746 symbol->SetValueFieldText( newValue, &m_schematic->Hierarchy()[0], variantName );
747
748 // Verify that the variant value was actually saved by reading it back
749 std::optional<SCH_SYMBOL_VARIANT> variant = symbol->GetVariant( m_schematic->Hierarchy()[0], variantName );
750 BOOST_REQUIRE( variant.has_value() );
751
752 wxString fieldName = symbol->GetField( FIELD_T::VALUE )->GetName();
753 BOOST_CHECK( variant->m_Fields.contains( fieldName ) );
754 BOOST_CHECK_EQUAL( variant->m_Fields.at( fieldName ), newValue );
755
756 // Verify through GetValue method as well
757 wxString retrievedValue = symbol->GetValue( false, &m_schematic->Hierarchy()[0], false, variantName );
758 BOOST_CHECK_EQUAL( retrievedValue, newValue );
759
760 // Verify default value is unchanged
761 wxString retrievedDefault = symbol->GetValue( false, &m_schematic->Hierarchy()[0], false, wxEmptyString );
762 BOOST_CHECK_EQUAL( retrievedDefault, defaultValue );
763}
764
765
769BOOST_AUTO_TEST_CASE( SetFieldTextAndSetValueFieldTextConsistency )
770{
771 wxFileName fn;
772 fn.SetPath( KI_TEST::GetEeschemaTestDataDir() );
773 fn.AppendDir( wxS( "variant_test" ) );
774 fn.SetName( wxS( "variant_test" ) );
776
777 LoadSchematic( fn.GetFullPath() );
778 BOOST_REQUIRE( m_schematic );
779
780 SCH_SYMBOL* symbol = GetFirstSymbol();
781 BOOST_REQUIRE( symbol );
782
783 wxString variantName1 = wxS( "MethodTest1" );
784 wxString variantName2 = wxS( "MethodTest2" );
785 wxString value1 = wxS( "10K" );
786 wxString value2 = wxS( "22K" );
787 wxString fieldName = symbol->GetField( FIELD_T::VALUE )->GetName();
788
789 m_schematic->AddVariant( variantName1 );
790 m_schematic->AddVariant( variantName2 );
791
792 // Set variant 1 using SetValueFieldText
793 symbol->SetValueFieldText( value1, &m_schematic->Hierarchy()[0], variantName1 );
794
795 // Set variant 2 using SetFieldText
796 symbol->SetFieldText( fieldName, value2, &m_schematic->Hierarchy()[0], variantName2 );
797
798 // Both methods should produce the same result structure
799 std::optional<SCH_SYMBOL_VARIANT> variant1 = symbol->GetVariant( m_schematic->Hierarchy()[0], variantName1 );
800 std::optional<SCH_SYMBOL_VARIANT> variant2 = symbol->GetVariant( m_schematic->Hierarchy()[0], variantName2 );
801
802 BOOST_REQUIRE( variant1.has_value() );
803 BOOST_REQUIRE( variant2.has_value() );
804
805 BOOST_CHECK( variant1->m_Fields.contains( fieldName ) );
806 BOOST_CHECK( variant2->m_Fields.contains( fieldName ) );
807
808 BOOST_CHECK_EQUAL( variant1->m_Fields.at( fieldName ), value1 );
809 BOOST_CHECK_EQUAL( variant2->m_Fields.at( fieldName ), value2 );
810
811 // Verify through GetValue
812 BOOST_CHECK_EQUAL( symbol->GetValue( false, &m_schematic->Hierarchy()[0], false, variantName1 ), value1 );
813 BOOST_CHECK_EQUAL( symbol->GetValue( false, &m_schematic->Hierarchy()[0], false, variantName2 ), value2 );
814
815 // Verify through GetFieldText
816 BOOST_CHECK_EQUAL( symbol->GetFieldText( fieldName, &m_schematic->Hierarchy()[0], variantName1 ), value1 );
817 BOOST_CHECK_EQUAL( symbol->GetFieldText( fieldName, &m_schematic->Hierarchy()[0], variantName2 ), value2 );
818}
819
820
825BOOST_AUTO_TEST_CASE( VariantNameHandling )
826{
827 wxFileName fn;
828 fn.SetPath( KI_TEST::GetEeschemaTestDataDir() );
829 fn.AppendDir( wxS( "variant_test" ) );
830 fn.SetName( wxS( "variant_test" ) );
832
833 LoadSchematic( fn.GetFullPath() );
834 BOOST_REQUIRE( m_schematic );
835
836 SCH_SYMBOL* symbol = GetFirstSymbol();
837 BOOST_REQUIRE( symbol );
838
839 wxString variantName = wxS( "ProductionVariant" );
840
841 // Add variant with specific casing
842 m_schematic->AddVariant( variantName );
843
844 // Set DNP on variant
845 symbol->SetDNP( true, &m_schematic->Hierarchy()[0], variantName );
846
847 // Verify with exact case - this should work
848 BOOST_CHECK( symbol->GetDNP( &m_schematic->Hierarchy()[0], wxS( "ProductionVariant" ) ) );
849
850 // Verify variant exists
851 BOOST_CHECK( m_schematic->GetVariantNames().contains( wxS( "ProductionVariant" ) ) );
852
853 // Set and get current variant
854 m_schematic->SetCurrentVariant( variantName );
855 BOOST_CHECK_EQUAL( m_schematic->GetCurrentVariant(), variantName );
856
857 // Unknown variant should return base DNP (false)
858 BOOST_CHECK( !symbol->GetDNP( &m_schematic->Hierarchy()[0], wxS( "NonExistentVariant" ) ) );
859}
860
861
865BOOST_AUTO_TEST_CASE( VariantDeletionCascade )
866{
867 wxFileName fn;
868 fn.SetPath( KI_TEST::GetEeschemaTestDataDir() );
869 fn.AppendDir( wxS( "variant_test" ) );
870 fn.SetName( wxS( "variant_test" ) );
872
873 LoadSchematic( fn.GetFullPath() );
874 BOOST_REQUIRE( m_schematic );
875
876 SCH_SYMBOL* symbol = GetFirstSymbol();
877 BOOST_REQUIRE( symbol );
878
879 wxString variantName = wxS( "DeleteMe" );
880
881 // Add variant and set properties
882 m_schematic->AddVariant( variantName );
883 symbol->SetDNP( true, &m_schematic->Hierarchy()[0], variantName );
884 symbol->GetField( FIELD_T::VALUE )->SetText( wxS( "DeletedValue" ), &m_schematic->Hierarchy()[0], variantName );
885
886 // Verify data is set
887 BOOST_CHECK( symbol->GetDNP( &m_schematic->Hierarchy()[0], variantName ) );
888 std::optional<SCH_SYMBOL_VARIANT> variant = symbol->GetVariant( m_schematic->Hierarchy()[0], variantName );
889 BOOST_CHECK( variant.has_value() );
890
891 // Delete the variant
892 m_schematic->DeleteVariant( variantName );
893
894 // Variant should no longer exist at schematic level
895 BOOST_CHECK( !m_schematic->GetVariantNames().contains( variantName ) );
896
897 // After deletion, querying DNP for non-existent variant should return base value
898 BOOST_CHECK( !symbol->GetDNP( &m_schematic->Hierarchy()[0], variantName ) );
899}
900
901
905BOOST_AUTO_TEST_CASE( VariantFieldUnicodeAndSpecialChars )
906{
907 wxFileName fn;
908 fn.SetPath( KI_TEST::GetEeschemaTestDataDir() );
909 fn.AppendDir( wxS( "variant_test" ) );
910 fn.SetName( wxS( "variant_test" ) );
912
913 LoadSchematic( fn.GetFullPath() );
914 BOOST_REQUIRE( m_schematic );
915
916 SCH_SYMBOL* symbol = GetFirstSymbol();
917 BOOST_REQUIRE( symbol );
918
919 wxString variantName = wxS( "UnicodeTest" );
920 m_schematic->AddVariant( variantName );
921
922 // Test Unicode characters in field values
923 wxString unicodeValue = wxS( "1kΩ ±5% 日本語" );
924 symbol->GetField( FIELD_T::VALUE )->SetText( unicodeValue, &m_schematic->Hierarchy()[0], variantName );
925
926 wxString retrieved = symbol->GetField( FIELD_T::VALUE )->GetShownText( &m_schematic->Hierarchy()[0],
927 false, 0, variantName );
928 BOOST_CHECK_EQUAL( retrieved, unicodeValue );
929
930 // Test special characters
931 wxString specialChars = wxS( "R<1K>\"test\"'value'" );
932 symbol->GetField( FIELD_T::VALUE )->SetText( specialChars, &m_schematic->Hierarchy()[0], variantName );
933
934 retrieved = symbol->GetField( FIELD_T::VALUE )->GetShownText( &m_schematic->Hierarchy()[0],
935 false, 0, variantName );
936 BOOST_CHECK_EQUAL( retrieved, specialChars );
937
938 // Test empty string
939 symbol->GetField( FIELD_T::VALUE )->SetText( wxEmptyString, &m_schematic->Hierarchy()[0], variantName );
940 retrieved = symbol->GetField( FIELD_T::VALUE )->GetShownText( &m_schematic->Hierarchy()[0],
941 false, 0, variantName );
942 BOOST_CHECK( retrieved.IsEmpty() );
943
944 // Test description with unicode
945 wxString unicodeDesc = wxS( "Variante für Produktion — 测试" );
946 m_schematic->SetVariantDescription( variantName, unicodeDesc );
947 BOOST_CHECK_EQUAL( m_schematic->GetVariantDescription( variantName ), unicodeDesc );
948}
949
950
954BOOST_AUTO_TEST_CASE( VariantSpecificFieldDereferencing )
955{
956 wxFileName fn;
957 fn.SetPath( KI_TEST::GetEeschemaTestDataDir() );
958 fn.AppendDir( wxS( "variant_test" ) );
959 fn.SetName( wxS( "variant_test" ) );
961
962 LoadSchematic( fn.GetFullPath() );
963 BOOST_REQUIRE( m_schematic );
964
965 SCH_SYMBOL* symbol = GetFirstSymbol();
966 BOOST_REQUIRE( symbol );
967
968 wxString variantName = wxS( "MilitaryGrade" );
969 wxString variantValue = wxS( "1K-MIL" );
970 wxString defaultValue = wxS( "1K" );
971
972 // Create a variant with a different value field
973 m_schematic->AddVariant( variantName );
974 symbol->GetField( FIELD_T::VALUE )->SetText( variantValue, &m_schematic->Hierarchy()[0], variantName );
975
976 // Verify default value
977 BOOST_CHECK_EQUAL( symbol->GetField( FIELD_T::VALUE )->GetShownText( &m_schematic->Hierarchy()[0], false, 0 ),
978 defaultValue );
979
980 // Get the symbol's reference (R1) for cross-reference testing
981 wxString symbolRef = symbol->GetRef( &m_schematic->Hierarchy()[0], false );
982
983 // Test 1: ResolveCrossReference with variant syntax - should return variant-specific value
984 wxString token = symbolRef + wxS( ":VALUE:" ) + variantName;
985 bool resolved = m_schematic->ResolveCrossReference( &token, 0 );
986 BOOST_CHECK( resolved );
987 BOOST_CHECK_EQUAL( token, variantValue );
988
989 // Test 2: ResolveCrossReference without variant - should return default value
990 token = symbolRef + wxS( ":VALUE" );
991 resolved = m_schematic->ResolveCrossReference( &token, 0 );
992 BOOST_CHECK( resolved );
993 BOOST_CHECK_EQUAL( token, defaultValue );
994
995 // Test 3: ResolveCrossReference with non-existent variant - should return default value
996 token = symbolRef + wxS( ":VALUE:NonExistentVariant" );
997 resolved = m_schematic->ResolveCrossReference( &token, 0 );
998 BOOST_CHECK( resolved );
999 BOOST_CHECK_EQUAL( token, defaultValue );
1000
1001 // Test 4: ResolveTextVar with variant parameter directly
1002 token = wxS( "VALUE" );
1003 resolved = symbol->ResolveTextVar( &m_schematic->Hierarchy()[0], &token, variantName, 0 );
1004 BOOST_CHECK( resolved );
1005 BOOST_CHECK_EQUAL( token, variantValue );
1006
1007 // Test 5: ResolveTextVar with empty variant - should return default
1008 token = wxS( "VALUE" );
1009 resolved = symbol->ResolveTextVar( &m_schematic->Hierarchy()[0], &token, wxEmptyString, 0 );
1010 BOOST_CHECK( resolved );
1011 BOOST_CHECK_EQUAL( token, defaultValue );
1012}
1013
1014
1020BOOST_AUTO_TEST_CASE( FootprintFieldVariantSupport )
1021{
1022 wxFileName fn;
1023 fn.SetPath( KI_TEST::GetEeschemaTestDataDir() );
1024 fn.AppendDir( wxS( "variant_test" ) );
1025 fn.SetName( wxS( "variant_test" ) );
1027
1028 LoadSchematic( fn.GetFullPath() );
1029 BOOST_REQUIRE( m_schematic );
1030
1031 SCH_SYMBOL* symbol = GetFirstSymbol();
1032 BOOST_REQUIRE( symbol );
1033
1034 wxString variantName = wxS( "FootprintVariant" );
1035 wxString baseFootprint = wxS( "Resistor_SMD:R_0805_2012Metric" );
1036 wxString variantFootprint = wxS( "Resistor_SMD:R_0402_1005Metric" );
1037 wxString fieldName = symbol->GetField( FIELD_T::FOOTPRINT )->GetName();
1038
1039 // Set a base footprint first
1040 symbol->SetFootprintFieldText( baseFootprint );
1041 BOOST_CHECK_EQUAL( symbol->GetFootprintFieldText( false, nullptr, false ), baseFootprint );
1042
1043 // Add the variant
1044 m_schematic->AddVariant( variantName );
1045
1046 // Set a different footprint for the variant using SetFieldText
1047 symbol->SetFieldText( fieldName, variantFootprint, &m_schematic->Hierarchy()[0], variantName );
1048
1049 // Verify base footprint is unchanged
1050 wxString retrievedBase = symbol->GetFootprintFieldText( false, nullptr, false );
1051 BOOST_CHECK_EQUAL( retrievedBase, baseFootprint );
1052
1053 // Verify GetFieldText with no variant returns base footprint
1054 wxString retrievedDefault = symbol->GetFieldText( fieldName, &m_schematic->Hierarchy()[0], wxEmptyString );
1055 BOOST_CHECK_EQUAL( retrievedDefault, baseFootprint );
1056
1057 // Verify GetFieldText with variant returns variant-specific footprint
1058 wxString retrievedVariant = symbol->GetFieldText( fieldName, &m_schematic->Hierarchy()[0], variantName );
1059 BOOST_CHECK_EQUAL( retrievedVariant, variantFootprint );
1060
1061 // Verify that the variant data structure contains the footprint override
1062 std::optional<SCH_SYMBOL_VARIANT> variant = symbol->GetVariant( m_schematic->Hierarchy()[0], variantName );
1063 BOOST_REQUIRE( variant.has_value() );
1064 BOOST_CHECK( variant->m_Fields.contains( fieldName ) );
1065 BOOST_CHECK_EQUAL( variant->m_Fields.at( fieldName ), variantFootprint );
1066}
1067
1068
1073BOOST_AUTO_TEST_CASE( FootprintFieldVariantNoOpWhenSame )
1074{
1075 wxFileName fn;
1076 fn.SetPath( KI_TEST::GetEeschemaTestDataDir() );
1077 fn.AppendDir( wxS( "variant_test" ) );
1078 fn.SetName( wxS( "variant_test" ) );
1080
1081 LoadSchematic( fn.GetFullPath() );
1082 BOOST_REQUIRE( m_schematic );
1083
1084 SCH_SYMBOL* symbol = GetFirstSymbol();
1085 BOOST_REQUIRE( symbol );
1086
1087 wxString variantName = wxS( "NoOpTest" );
1088 wxString baseFootprint = wxS( "Resistor_SMD:R_0805_2012Metric" );
1089 wxString fieldName = symbol->GetField( FIELD_T::FOOTPRINT )->GetName();
1090
1091 // Set a base footprint first
1092 symbol->SetFootprintFieldText( baseFootprint );
1093
1094 // Add the variant
1095 m_schematic->AddVariant( variantName );
1096
1097 // Set the same footprint value for the variant
1098 symbol->SetFieldText( fieldName, baseFootprint, &m_schematic->Hierarchy()[0], variantName );
1099
1100 // Verify that no variant override was created since the value is the same
1101 std::optional<SCH_SYMBOL_VARIANT> variant = symbol->GetVariant( m_schematic->Hierarchy()[0], variantName );
1102
1103 // Either no variant was created, or it exists but doesn't have a footprint override
1104 if( variant.has_value() )
1105 {
1106 BOOST_CHECK( !variant->m_Fields.contains( fieldName ) );
1107 }
1108}
1109
1110
1115BOOST_AUTO_TEST_CASE( VariantSwitchInvalidatesBoundingBoxCache )
1116{
1117 wxFileName fn;
1118 fn.SetPath( KI_TEST::GetEeschemaTestDataDir() );
1119 fn.AppendDir( wxS( "variant_test" ) );
1120 fn.SetName( wxS( "variant_test" ) );
1122
1123 LoadSchematic( fn.GetFullPath() );
1124 BOOST_REQUIRE( m_schematic );
1125
1126 // GetShownText(bool) resolves variants via CurrentSheet(), so we must set it
1127 m_schematic->SetCurrentSheet( m_schematic->Hierarchy()[0] );
1128
1129 SCH_SYMBOL* symbol = GetFirstSymbol();
1130 BOOST_REQUIRE( symbol );
1131
1132 SCH_FIELD* fpField = symbol->GetField( FIELD_T::FOOTPRINT );
1133 BOOST_REQUIRE( fpField );
1134
1135 wxString variantName = wxS( "BboxVariant" );
1136 wxString shortFp = wxS( "R_0402" );
1137 wxString longFp = wxS( "Resistor_SMD:R_2512_6332Metric_Pad1.52x3.35mm_HandSolder" );
1138
1139 symbol->SetFootprintFieldText( shortFp );
1140 fpField->SetVisible( true );
1141 fpField->ClearBoundingBoxCache();
1142
1143 m_schematic->AddVariant( variantName );
1144 symbol->SetFieldText( fpField->GetName(), longFp, &m_schematic->Hierarchy()[0], variantName );
1145
1146 // Confirm variant text resolution works
1147 wxString resolvedDefault = fpField->GetShownText( &m_schematic->Hierarchy()[0], false, 0, wxEmptyString );
1148 wxString resolvedVariant = fpField->GetShownText( &m_schematic->Hierarchy()[0], false, 0, variantName );
1149 BOOST_CHECK_EQUAL( resolvedDefault, shortFp );
1150 BOOST_CHECK_EQUAL( resolvedVariant, longFp );
1151
1152 // Verify the implicit text resolution via GetShownText(bool) works for each variant
1153 m_schematic->SetCurrentVariant( wxEmptyString );
1154 wxString implicitDefault = fpField->GetShownText( false );
1155
1156 m_schematic->SetCurrentVariant( variantName );
1157 wxString implicitVariant = fpField->GetShownText( false );
1158
1159 BOOST_CHECK_EQUAL( implicitDefault, shortFp );
1160 BOOST_CHECK_EQUAL( implicitVariant, longFp );
1161
1162 // Prime the bounding box cache with the default variant (short footprint text)
1163 m_schematic->SetCurrentVariant( wxEmptyString );
1164 fpField->ClearBoundingBoxCache();
1165 BOX2I defaultTextBox = fpField->GetTextBox( nullptr );
1166
1167 // Switch to the variant with a much longer footprint string.
1168 // SetCurrentVariant must invalidate caches so the new text is reflected.
1169 m_schematic->SetCurrentVariant( variantName );
1170 BOX2I variantTextBox = fpField->GetTextBox( nullptr );
1171
1172 // The longer text must produce a wider text box. If the bounding box cache was not
1173 // invalidated on variant switch, both boxes would be identical.
1174 BOOST_CHECK_GT( variantTextBox.GetWidth(), defaultTextBox.GetWidth() );
1175
1176 // Switch back and verify it returns to the original width
1177 m_schematic->SetCurrentVariant( wxEmptyString );
1178 BOX2I restoredTextBox = fpField->GetTextBox( nullptr );
1179 BOOST_CHECK_EQUAL( restoredTextBox.GetWidth(), defaultTextBox.GetWidth() );
1180}
1181
1182
1193BOOST_AUTO_TEST_CASE( VariantAttributeInitFromSymbol )
1194{
1195 wxFileName fn;
1196 fn.SetPath( KI_TEST::GetEeschemaTestDataDir() );
1197 fn.AppendDir( wxS( "variant_test" ) );
1198 fn.SetName( wxS( "variant_test" ) );
1200
1201 LoadSchematic( fn.GetFullPath() );
1202 BOOST_REQUIRE( m_schematic );
1203
1204 SCH_SYMBOL* symbol = GetFirstSymbol();
1205 BOOST_REQUIRE( symbol );
1206
1207 // Set all default attributes to true on the symbol
1208 symbol->SetDNP( true );
1209 symbol->SetExcludedFromBOM( true );
1210 symbol->SetExcludedFromSim( true );
1211 symbol->SetExcludedFromBoard( true );
1212 symbol->SetExcludedFromPosFiles( true );
1213
1214 // Default-constructed variant has all-false attributes
1215 SCH_SYMBOL_VARIANT defaultVariant( wxS( "Default" ) );
1216 BOOST_CHECK( !defaultVariant.m_DNP );
1217 BOOST_CHECK( !defaultVariant.m_ExcludedFromBOM );
1218 BOOST_CHECK( !defaultVariant.m_ExcludedFromSim );
1219 BOOST_CHECK( !defaultVariant.m_ExcludedFromBoard );
1220 BOOST_CHECK( !defaultVariant.m_ExcludedFromPosFiles );
1221
1222 // InitializeAttributes should copy the symbol's attributes
1223 SCH_SYMBOL_VARIANT initializedVariant( wxS( "Initialized" ) );
1224 initializedVariant.InitializeAttributes( *symbol );
1225
1226 BOOST_CHECK_MESSAGE( initializedVariant.m_DNP,
1227 "InitializeAttributes should copy DNP from symbol" );
1228 BOOST_CHECK_MESSAGE( initializedVariant.m_ExcludedFromBOM,
1229 "InitializeAttributes should copy ExcludedFromBOM from symbol" );
1230 BOOST_CHECK_MESSAGE( initializedVariant.m_ExcludedFromSim,
1231 "InitializeAttributes should copy ExcludedFromSim from symbol" );
1232 BOOST_CHECK_MESSAGE( initializedVariant.m_ExcludedFromBoard,
1233 "InitializeAttributes should copy ExcludedFromBoard from symbol" );
1234 BOOST_CHECK_MESSAGE( initializedVariant.m_ExcludedFromPosFiles,
1235 "InitializeAttributes should copy ExcludedFromPosFiles from symbol" );
1236}
1237
1238
1247BOOST_AUTO_TEST_CASE( MatchesUsesInstanceFields )
1248{
1249 // Build a minimal lib symbol simulating "+5V"
1250 LIB_SYMBOL* libSym = new LIB_SYMBOL( wxS( "+5V" ) );
1251
1252 // The lib symbol value field text stays as "+5V"
1253 libSym->GetValueField().SetText( wxS( "+5V" ) );
1254 libSym->GetValueField().SetVisible( true );
1255
1256 SCH_SYMBOL symbol( *libSym, libSym->GetLibId(), nullptr, 0, 0, VECTOR2I() );
1257
1258 // Change the instance value to "+5VA" (simulating a user-derived power symbol)
1259 symbol.GetField( FIELD_T::VALUE )->SetText( wxS( "+5VA" ) );
1260
1261 SCH_SEARCH_DATA data;
1262 data.findString = wxS( "+5V" );
1264 data.searchAllFields = false;
1265
1266 // "+5VA" must NOT match a whole-word search for "+5V"
1267 BOOST_CHECK_MESSAGE( !symbol.Matches( data, nullptr ),
1268 "'+5VA' symbol must not match whole-word search for '+5V'" );
1269
1270 // "+5VA" must match a plain search for "+5V" (substring)
1272 BOOST_CHECK_MESSAGE( symbol.Matches( data, nullptr ),
1273 "'+5VA' symbol must match plain search for '+5V'" );
1274
1275 // "+5VA" must match a whole-word search for "+5VA"
1276 data.findString = wxS( "+5VA" );
1278 BOOST_CHECK_MESSAGE( symbol.Matches( data, nullptr ),
1279 "'+5VA' symbol must match whole-word search for '+5VA'" );
1280
1281 delete libSym;
1282}
1283
1284
BOX2< VECTOR2I > BOX2I
Definition box2.h:922
constexpr size_type GetWidth() const
Definition box2.h:214
EDA_ITEM * GetParent() const
Definition eda_item.h:114
virtual void SetParent(EDA_ITEM *aParent)
Definition eda_item.cpp:93
BOX2I GetTextBox(const RENDER_SETTINGS *aSettings, int aLine=-1) const
Useful in multiline texts to calculate the full text or a line area (for zones filling,...
Definition eda_text.cpp:771
virtual void SetVisible(bool aVisible)
Definition eda_text.cpp:385
virtual void ClearBoundingBoxCache()
Definition eda_text.cpp:694
EE_TYPE OfType(KICAD_T aType) const
Definition sch_rtree.h:225
A generic fixture for loading schematics and associated settings for qa tests.
std::unique_ptr< SCHEMATIC > m_schematic
Define a library symbol object.
Definition lib_symbol.h:83
const LIB_ID & GetLibId() const override
Definition lib_symbol.h:152
SCH_FIELD & GetValueField()
Return reference to the value field.
Definition lib_symbol.h:332
virtual const wxString & GetText() const override
Return the string associated with the text object.
Definition sch_field.h:126
wxString GetShownText(const SCH_SHEET_PATH *aPath, bool aAllowExtraText, int aDepth=0, const wxString &aVariantName=wxEmptyString) const
wxString GetName(bool aUseDefaultName=true) const
Return the field name (not translated).
void SetText(const wxString &aText) override
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:168
int GetUnit() const
Definition sch_item.h:239
virtual void SetUnit(int aUnit)
Definition sch_item.h:238
void SwapItemData(SCH_ITEM *aImage)
Swap data between aItem and aImage.
Definition sch_item.cpp:636
EE_RTREE & Items()
Get the full RTree, usually for iterating.
Definition sch_screen.h:119
A container for handling SCH_SHEET_PATH objects in a flattened hierarchy.
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
Variant information for a schematic symbol.
void InitializeAttributes(const SCH_SYMBOL &aSymbol)
Schematic symbol object.
Definition sch_symbol.h:76
bool GetExcludedFromSim(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const override
virtual void SetDNP(bool aEnable, const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) override
void SetFieldText(const wxString &aFieldName, const wxString &aFieldText, const SCH_SHEET_PATH *aPath=nullptr, const wxString &aVariantName=wxEmptyString)
wxString GetFieldText(const wxString &aFieldName, const SCH_SHEET_PATH *aPath=nullptr, const wxString &aVariantName=wxEmptyString) const
void SetExcludedFromSim(bool aEnable, const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) override
Set or clear the exclude from simulation flag.
std::optional< SCH_SYMBOL_VARIANT > GetVariant(const SCH_SHEET_PATH &aInstance, const wxString &aVariantName) const
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
bool GetExcludedFromBOM(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const override
bool Matches(const EDA_SEARCH_DATA &aSearchData, void *aAuxData) const override
Compare the item against the search criteria in aSearchData.
void UpdatePins()
Updates the cache of SCH_PIN objects for each pin.
const wxString GetValue(bool aResolve, const SCH_SHEET_PATH *aPath, bool aAllowExtraText, const wxString &aVariantName=wxEmptyString) const override
const wxString GetFootprintFieldText(bool aResolve, const SCH_SHEET_PATH *aPath, bool aAllowExtraText, const wxString &aVariantName=wxEmptyString) const
void SetFootprintFieldText(const wxString &aFootprint)
void SetExcludedFromPosFiles(bool aEnable, const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) override
bool ResolveTextVar(const SCH_SHEET_PATH *aPath, wxString *token, int aDepth=0) const
Resolve any references to system tokens supported by the symbol.
void SetValueFieldText(const wxString &aValue, const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString)
std::vector< SCH_PIN * > GetLibPins() const
Populate a vector with all the pins from the library object that match the current unit and bodyStyle...
bool GetExcludedFromPosFiles(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const override
SCH_FIELD * AddField(const SCH_FIELD &aField)
Add a field to the symbol.
bool GetExcludedFromBoard(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const override
int GetUnitSelection(const SCH_SHEET_PATH *aSheet) const
Return the instance-specific unit selection for the given sheet path.
void SetUnitSelection(const SCH_SHEET_PATH *aSheet, int aUnitSelection)
Set the selected unit of this symbol on one sheet.
void SetExcludedFromBOM(bool aEnable, const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) override
Set or clear the exclude from schematic bill of materials flag.
virtual bool GetDNP(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const override
Set or clear the 'Do Not Populate' flag.
const wxString GetRef(const SCH_SHEET_PATH *aSheet, bool aIncludeUnit=false) const override
void SetExcludedFromBoard(bool aEnable, const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) override
SCH_FIELD * GetField(FIELD_T aFieldType)
Return a mandatory field in this symbol.
SCH_SYMBOL * GetFirstSymbol()
SCH_SYMBOL object with no extra data set.
for transforming drawing coordinates for a wxDC device context.
Definition transform.h:46
bool m_ExcludedFromBOM
bool m_ExcludedFromPosFiles
bool m_ExcludedFromSim
bool m_ExcludedFromBoard
static const std::string KiCadSchematicFileExtension
std::string GetEeschemaTestDataDir()
Get the configured location of Eeschema test data.
static void LoadSchematic(SCHEMATIC *aSchematic, SCH_SHEET *aRootSheet, const wxString &aFileName)
EDA_SEARCH_MATCH_MODE matchMode
@ SYM_ORIENT_270
Definition symbol.h:42
@ SYM_ORIENT_180
Definition symbol.h:41
@ SYM_ORIENT_90
Definition symbol.h:40
@ USER
The field ID hasn't been set yet; field is invalid.
@ FOOTPRINT
Field Name Module PCB, i.e. "16DIP300".
@ 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 * pin
BOOST_CHECK_MESSAGE(totalMismatches==0, std::to_string(totalMismatches)+" board(s) with strategy disagreements")
BOOST_AUTO_TEST_CASE(DefaultProperties)
Declare the test suite.
BOOST_CHECK_EQUAL(result, "25.4")
@ SCH_SYMBOL_T
Definition typeinfo.h:173
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:687
Definition of file extensions used in Kicad.