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