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
37
39{
40public:
42 {
43 if( !m_schematic )
44 return nullptr;
45
46 SCH_SCREEN* screen = m_schematic->RootScreen();
47
48 if( !screen )
49 return nullptr;
50
51 for( SCH_ITEM* item : screen->Items().OfType( SCH_SYMBOL_T ) )
52 {
53 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
54
55 if( symbol )
56 return symbol;
57 }
58
59 return nullptr;
60 }
61
64};
65
66
70BOOST_FIXTURE_TEST_SUITE( SchSymbol, TEST_SCH_SYMBOL_FIXTURE )
71
72
73
76BOOST_AUTO_TEST_CASE( DefaultProperties )
77{
78}
79
80
85{
86 TRANSFORM t = m_symbol.GetTransform();
87
88 m_symbol.SetOrientation( SYM_ORIENT_90 );
89 t = m_symbol.GetTransform();
90 m_symbol.SetTransform( TRANSFORM() );
91 m_symbol.SetOrientation( SYM_ORIENT_180 );
92 t = m_symbol.GetTransform();
93 m_symbol.SetTransform( TRANSFORM() );
94 m_symbol.SetOrientation( SYM_ORIENT_270 );
95 t = m_symbol.GetTransform();
96}
97
98
102BOOST_AUTO_TEST_CASE( SchSymbolVariantTest )
103{
104 wxFileName fn;
105 fn.SetPath( KI_TEST::GetEeschemaTestDataDir() );
106 fn.AppendDir( wxS( "variant_test" ) );
107 fn.SetName( wxS( "variant_test" ) );
109
110 LoadSchematic( fn.GetFullPath() );
111
112 SCH_SYMBOL* symbol = GetFirstSymbol();
113 BOOST_CHECK( symbol );
114
115 // Test for an empty (non-existant) variant.
116 wxString variantName = wxS( "Variant1" );
117 std::optional<SCH_SYMBOL_VARIANT> variant = symbol->GetVariant( m_schematic->Hierarchy()[0], variantName );
118 BOOST_CHECK( !variant );
119
120 // Test DNP property variant.
121 BOOST_CHECK( !symbol->GetDNP() );
122 symbol->SetDNP( true, &m_schematic->Hierarchy()[0], variantName );
123 BOOST_CHECK( symbol->GetDNP( &m_schematic->Hierarchy()[0], variantName ) );
124
125 // Test exclude from BOM property variant.
126 BOOST_CHECK( !symbol->GetExcludedFromBOM() );
127 symbol->SetExcludedFromBOM( true, &m_schematic->Hierarchy()[0], variantName );
128 BOOST_CHECK( symbol->GetExcludedFromBOM( &m_schematic->Hierarchy()[0], variantName ) );
129
130 // Test exclude from simulation property variant.
131 BOOST_CHECK( !symbol->GetExcludedFromSim() );
132 symbol->SetExcludedFromSim( true, &m_schematic->Hierarchy()[0], variantName );
133 BOOST_CHECK( symbol->GetExcludedFromSim( &m_schematic->Hierarchy()[0], variantName ) );
134
135 // Test exclude from board property variant.
136 BOOST_CHECK( !symbol->GetExcludedFromBoard() );
137 symbol->SetExcludedFromBoard( true, &m_schematic->Hierarchy()[0], variantName );
138 BOOST_CHECK( symbol->GetExcludedFromBoard( &m_schematic->Hierarchy()[0], variantName ) );
139
140 // Test exclude from position files property variant.
141 BOOST_CHECK( !symbol->GetExcludedFromPosFiles() );
142 symbol->SetExcludedFromPosFiles( true, &m_schematic->Hierarchy()[0], variantName );
143 BOOST_CHECK( symbol->GetExcludedFromPosFiles( &m_schematic->Hierarchy()[0], variantName ) );
144
145 // Test a value field variant change.
146 BOOST_CHECK( symbol->GetField( FIELD_T::VALUE )->GetShownText( &m_schematic->Hierarchy()[0],
147 false, 0 ) == wxS( "1K" ) );
148 symbol->GetField( FIELD_T::VALUE )->SetText( wxS( "10K" ), &m_schematic->Hierarchy()[0], variantName );
149 BOOST_CHECK( symbol->GetField( FIELD_T::VALUE )->GetShownText( &m_schematic->Hierarchy()[0],
150 false, 0, variantName ) == wxS( "10K" ) );
151 // BOOST_CHECK( symbol->GetFieldText( FIELD_T::VALUE, &m_schematic->Hierarchy()[0], variantName ) == wxS( "10K" ) );
152}
153
154
160BOOST_AUTO_TEST_CASE( FieldAdditionByName )
161{
162 wxFileName fn;
163 fn.SetPath( KI_TEST::GetEeschemaTestDataDir() );
164 fn.AppendDir( wxS( "variant_test" ) );
165 fn.SetName( wxS( "variant_test" ) );
167
168 LoadSchematic( fn.GetFullPath() );
169
170 SCH_SYMBOL* symbol = GetFirstSymbol();
171 BOOST_REQUIRE( symbol );
172
173 wxString newFieldName = wxS( "Sim.Library" );
174
175 // GetField by name should return null for non-existent field
176 const SCH_FIELD* existing = symbol->GetField( newFieldName );
177 BOOST_CHECK( existing == nullptr );
178
179 // Create a field to add
180 SCH_FIELD newField( symbol, FIELD_T::USER, newFieldName );
181 newField.SetText( wxS( "test_model.lib" ) );
182
183 // AddField should add the field and return a valid pointer
184 SCH_FIELD* addedField = symbol->AddField( newField );
185 BOOST_REQUIRE( addedField != nullptr );
186
187 // After setting the parent, verify the field is correctly configured
188 addedField->SetParent( symbol );
189 BOOST_CHECK( addedField->GetParent() == symbol );
190
191 // Now GetField should find the newly added field
192 const SCH_FIELD* found = symbol->GetField( newFieldName );
193 BOOST_REQUIRE( found != nullptr );
194 BOOST_CHECK( found->GetText() == wxS( "test_model.lib" ) );
195}
196
197
201BOOST_AUTO_TEST_CASE( VariantDescription )
202{
203 wxFileName fn;
204 fn.SetPath( KI_TEST::GetEeschemaTestDataDir() );
205 fn.AppendDir( wxS( "variant_test" ) );
206 fn.SetName( wxS( "variant_test" ) );
208
209 LoadSchematic( fn.GetFullPath() );
210 BOOST_REQUIRE( m_schematic );
211
212 wxString variantName = wxS( "TestVariant" );
213 wxString description = wxS( "This is a test variant description" );
214
215 // Add a variant
216 m_schematic->AddVariant( variantName );
217 BOOST_CHECK( m_schematic->GetVariantNames().contains( variantName ) );
218
219 // Set description
220 m_schematic->SetVariantDescription( variantName, description );
221 BOOST_CHECK_EQUAL( m_schematic->GetVariantDescription( variantName ), description );
222
223 // Empty description for non-existent variant
224 BOOST_CHECK( m_schematic->GetVariantDescription( wxS( "NonExistent" ) ).IsEmpty() );
225
226 // Clear description
227 m_schematic->SetVariantDescription( variantName, wxEmptyString );
228 BOOST_CHECK( m_schematic->GetVariantDescription( variantName ).IsEmpty() );
229}
230
231
235BOOST_AUTO_TEST_CASE( TextVariableVARIANT )
236{
237 wxFileName fn;
238 fn.SetPath( KI_TEST::GetEeschemaTestDataDir() );
239 fn.AppendDir( wxS( "variant_test" ) );
240 fn.SetName( wxS( "variant_test" ) );
242
243 LoadSchematic( fn.GetFullPath() );
244 BOOST_REQUIRE( m_schematic );
245
246 wxString variantName = wxS( "MilitaryGrade" );
247
248 // Add a variant and set it as current
249 m_schematic->AddVariant( variantName );
250 m_schematic->SetCurrentVariant( variantName );
251
252 // Test that ${VARIANT} resolves to the current variant name
253 wxString token = wxS( "VARIANT" );
254 bool resolved = m_schematic->ResolveTextVar( &m_schematic->Hierarchy()[0], &token, 0 );
255 BOOST_CHECK( resolved );
256 BOOST_CHECK_EQUAL( token, variantName );
257
258 // Also test VARIANTNAME (legacy/alias)
259 token = wxS( "VARIANTNAME" );
260 resolved = m_schematic->ResolveTextVar( &m_schematic->Hierarchy()[0], &token, 0 );
261 BOOST_CHECK( resolved );
262 BOOST_CHECK_EQUAL( token, variantName );
263
264 // Empty variant
265 m_schematic->SetCurrentVariant( wxEmptyString );
266 token = wxS( "VARIANT" );
267 resolved = m_schematic->ResolveTextVar( &m_schematic->Hierarchy()[0], &token, 0 );
268 BOOST_CHECK( resolved );
269 BOOST_CHECK( token.IsEmpty() );
270}
271
272
276BOOST_AUTO_TEST_CASE( TextVariableVARIANT_DESC )
277{
278 wxFileName fn;
279 fn.SetPath( KI_TEST::GetEeschemaTestDataDir() );
280 fn.AppendDir( wxS( "variant_test" ) );
281 fn.SetName( wxS( "variant_test" ) );
283
284 LoadSchematic( fn.GetFullPath() );
285 BOOST_REQUIRE( m_schematic );
286
287 wxString variantName = wxS( "IndustrialVariant" );
288 wxString description = wxS( "Industrial temperature range components" );
289
290 // Add a variant with description and set it as current
291 m_schematic->AddVariant( variantName );
292 m_schematic->SetVariantDescription( variantName, description );
293 m_schematic->SetCurrentVariant( variantName );
294
295 // Test that ${VARIANT_DESC} resolves to the variant description
296 wxString token = wxS( "VARIANT_DESC" );
297 bool resolved = m_schematic->ResolveTextVar( &m_schematic->Hierarchy()[0], &token, 0 );
298 BOOST_CHECK( resolved );
299 BOOST_CHECK_EQUAL( token, description );
300
301 // Test with no description set
302 m_schematic->SetVariantDescription( variantName, wxEmptyString );
303 token = wxS( "VARIANT_DESC" );
304 resolved = m_schematic->ResolveTextVar( &m_schematic->Hierarchy()[0], &token, 0 );
305 BOOST_CHECK( resolved );
306 BOOST_CHECK( token.IsEmpty() );
307}
308
309
313BOOST_AUTO_TEST_CASE( RenameVariantPreservesData )
314{
315 wxFileName fn;
316 fn.SetPath( KI_TEST::GetEeschemaTestDataDir() );
317 fn.AppendDir( wxS( "variant_test" ) );
318 fn.SetName( wxS( "variant_test" ) );
320
321 LoadSchematic( fn.GetFullPath() );
322 BOOST_REQUIRE( m_schematic );
323
324 SCH_SYMBOL* symbol = GetFirstSymbol();
325 BOOST_REQUIRE( symbol );
326
327 wxString oldName = wxS( "OriginalVariant" );
328 wxString newName = wxS( "RenamedVariant" );
329 wxString description = wxS( "Original description" );
330
331 // Set up the variant with data
332 m_schematic->AddVariant( oldName );
333 m_schematic->SetVariantDescription( oldName, description );
334 m_schematic->SetCurrentVariant( oldName );
335
336 // Set symbol variant properties
337 symbol->SetDNP( true, &m_schematic->Hierarchy()[0], oldName );
338 symbol->GetField( FIELD_T::VALUE )->SetText( wxS( "100K" ), &m_schematic->Hierarchy()[0], oldName );
339
340 // Verify the data is set
341 BOOST_CHECK( symbol->GetDNP( &m_schematic->Hierarchy()[0], oldName ) );
342 BOOST_CHECK_EQUAL( symbol->GetField( FIELD_T::VALUE )->GetShownText( &m_schematic->Hierarchy()[0],
343 false, 0, oldName ), wxS( "100K" ) );
344
345 // Rename the variant
346 m_schematic->RenameVariant( oldName, newName );
347
348 // Verify old name is gone
349 BOOST_CHECK( !m_schematic->GetVariantNames().contains( oldName ) );
350
351 // Verify new name exists
352 BOOST_CHECK( m_schematic->GetVariantNames().contains( newName ) );
353
354 // Verify description was preserved
355 BOOST_CHECK_EQUAL( m_schematic->GetVariantDescription( newName ), description );
356
357 // Verify current variant was updated
358 BOOST_CHECK_EQUAL( m_schematic->GetCurrentVariant(), newName );
359
360 // Verify symbol variant data was preserved
361 BOOST_CHECK( symbol->GetDNP( &m_schematic->Hierarchy()[0], newName ) );
362 BOOST_CHECK_EQUAL( symbol->GetField( FIELD_T::VALUE )->GetShownText( &m_schematic->Hierarchy()[0],
363 false, 0, newName ), wxS( "100K" ) );
364}
365
366
370BOOST_AUTO_TEST_CASE( CopyVariantCreatesIndependentCopy )
371{
372 wxFileName fn;
373 fn.SetPath( KI_TEST::GetEeschemaTestDataDir() );
374 fn.AppendDir( wxS( "variant_test" ) );
375 fn.SetName( wxS( "variant_test" ) );
377
378 LoadSchematic( fn.GetFullPath() );
379 BOOST_REQUIRE( m_schematic );
380
381 SCH_SYMBOL* symbol = GetFirstSymbol();
382 BOOST_REQUIRE( symbol );
383
384 wxString sourceVariant = wxS( "SourceVariant" );
385 wxString copyVariant = wxS( "CopiedVariant" );
386 wxString description = wxS( "Source description" );
387
388 // Set up the source variant
389 m_schematic->AddVariant( sourceVariant );
390 m_schematic->SetVariantDescription( sourceVariant, description );
391
392 // Set symbol variant properties for source
393 symbol->SetDNP( true, &m_schematic->Hierarchy()[0], sourceVariant );
394 symbol->SetExcludedFromBOM( true, &m_schematic->Hierarchy()[0], sourceVariant );
395 symbol->SetExcludedFromBoard( true, &m_schematic->Hierarchy()[0], sourceVariant );
396 symbol->SetExcludedFromPosFiles( true, &m_schematic->Hierarchy()[0], sourceVariant );
397 symbol->GetField( FIELD_T::VALUE )->SetText( wxS( "47K" ), &m_schematic->Hierarchy()[0], sourceVariant );
398
399 // Copy the variant
400 m_schematic->CopyVariant( sourceVariant, copyVariant );
401
402 // Verify both variants exist
403 BOOST_CHECK( m_schematic->GetVariantNames().contains( sourceVariant ) );
404 BOOST_CHECK( m_schematic->GetVariantNames().contains( copyVariant ) );
405
406 // Verify description was copied
407 BOOST_CHECK_EQUAL( m_schematic->GetVariantDescription( copyVariant ), description );
408
409 // Verify symbol properties were copied
410 BOOST_CHECK( symbol->GetDNP( &m_schematic->Hierarchy()[0], copyVariant ) );
411 BOOST_CHECK( symbol->GetExcludedFromBOM( &m_schematic->Hierarchy()[0], copyVariant ) );
412 BOOST_CHECK( symbol->GetExcludedFromBoard( &m_schematic->Hierarchy()[0], copyVariant ) );
413 BOOST_CHECK( symbol->GetExcludedFromPosFiles( &m_schematic->Hierarchy()[0], copyVariant ) );
414 BOOST_CHECK_EQUAL( symbol->GetField( FIELD_T::VALUE )->GetShownText( &m_schematic->Hierarchy()[0],
415 false, 0, copyVariant ), wxS( "47K" ) );
416
417 // Modify the copy and verify source is unchanged
418 symbol->SetDNP( false, &m_schematic->Hierarchy()[0], copyVariant );
419 symbol->GetField( FIELD_T::VALUE )->SetText( wxS( "100K" ), &m_schematic->Hierarchy()[0], copyVariant );
420
421 // Source should still have original values
422 BOOST_CHECK( symbol->GetDNP( &m_schematic->Hierarchy()[0], sourceVariant ) );
423 BOOST_CHECK_EQUAL( symbol->GetField( FIELD_T::VALUE )->GetShownText( &m_schematic->Hierarchy()[0],
424 false, 0, sourceVariant ), wxS( "47K" ) );
425
426 // Copy should have modified values
427 BOOST_CHECK( !symbol->GetDNP( &m_schematic->Hierarchy()[0], copyVariant ) );
428 BOOST_CHECK_EQUAL( symbol->GetField( FIELD_T::VALUE )->GetShownText( &m_schematic->Hierarchy()[0],
429 false, 0, copyVariant ), wxS( "100K" ) );
430}
431
432
436BOOST_AUTO_TEST_CASE( VariantFieldDifferenceDetection )
437{
438 wxFileName fn;
439 fn.SetPath( KI_TEST::GetEeschemaTestDataDir() );
440 fn.AppendDir( wxS( "variant_test" ) );
441 fn.SetName( wxS( "variant_test" ) );
443
444 LoadSchematic( fn.GetFullPath() );
445 BOOST_REQUIRE( m_schematic );
446
447 SCH_SYMBOL* symbol = GetFirstSymbol();
448 BOOST_REQUIRE( symbol );
449
450 wxString variantName1 = wxS( "DiffTestVariant1" );
451 wxString variantName2 = wxS( "DiffTestVariant2" );
452
453 // Get the default value
454 wxString defaultValue = symbol->GetField( FIELD_T::VALUE )->GetShownText( &m_schematic->Hierarchy()[0],
455 false, 0 );
456 BOOST_CHECK_EQUAL( defaultValue, wxS( "1K" ) );
457
458 // Add a variant and set a different value
459 m_schematic->AddVariant( variantName1 );
460 symbol->GetField( FIELD_T::VALUE )->SetText( wxS( "2.2K" ), &m_schematic->Hierarchy()[0], variantName1 );
461
462 // Get variant value
463 wxString variantValue = symbol->GetField( FIELD_T::VALUE )->GetShownText( &m_schematic->Hierarchy()[0],
464 false, 0, variantName1 );
465 BOOST_CHECK_EQUAL( variantValue, wxS( "2.2K" ) );
466
467 // Verify values differ
468 BOOST_CHECK( defaultValue != variantValue );
469
470 // Add another variant with same value as default to verify equality detection
471 m_schematic->AddVariant( variantName2 );
472 symbol->GetField( FIELD_T::VALUE )->SetText( wxS( "1K" ), &m_schematic->Hierarchy()[0], variantName2 );
473 wxString variantValue2 = symbol->GetField( FIELD_T::VALUE )->GetShownText( &m_schematic->Hierarchy()[0],
474 false, 0, variantName2 );
475
476 // Second variant should have the same value as default
477 BOOST_CHECK_EQUAL( defaultValue, variantValue2 );
478}
479
480
484BOOST_AUTO_TEST_CASE( VariantDNPFiltering )
485{
486 wxFileName fn;
487 fn.SetPath( KI_TEST::GetEeschemaTestDataDir() );
488 fn.AppendDir( wxS( "variant_test" ) );
489 fn.SetName( wxS( "variant_test" ) );
491
492 LoadSchematic( fn.GetFullPath() );
493 BOOST_REQUIRE( m_schematic );
494
495 SCH_SYMBOL* symbol = GetFirstSymbol();
496 BOOST_REQUIRE( symbol );
497
498 wxString variantName = wxS( "DNPVariant" );
499
500 // By default, symbol should not be DNP
501 BOOST_CHECK( !symbol->GetDNP() );
502 BOOST_CHECK( !symbol->GetDNP( &m_schematic->Hierarchy()[0], wxEmptyString ) );
503
504 // Add a variant where symbol is DNP
505 m_schematic->AddVariant( variantName );
506 symbol->SetDNP( true, &m_schematic->Hierarchy()[0], variantName );
507
508 // Default should still not be DNP
509 BOOST_CHECK( !symbol->GetDNP() );
510 BOOST_CHECK( !symbol->GetDNP( &m_schematic->Hierarchy()[0], wxEmptyString ) );
511
512 // Variant should be DNP
513 BOOST_CHECK( symbol->GetDNP( &m_schematic->Hierarchy()[0], variantName ) );
514
515 // Test exclude from BOM as well
516 BOOST_CHECK( !symbol->GetExcludedFromBOM() );
517 symbol->SetExcludedFromBOM( true, &m_schematic->Hierarchy()[0], variantName );
518 BOOST_CHECK( symbol->GetExcludedFromBOM( &m_schematic->Hierarchy()[0], variantName ) );
519 BOOST_CHECK( !symbol->GetExcludedFromBOM( &m_schematic->Hierarchy()[0], wxEmptyString ) );
520
521 // Test exclude from board as well
522 BOOST_CHECK( !symbol->GetExcludedFromBoard() );
523 symbol->SetExcludedFromBoard( true, &m_schematic->Hierarchy()[0], variantName );
524 BOOST_CHECK( symbol->GetExcludedFromBoard( &m_schematic->Hierarchy()[0], variantName ) );
525 BOOST_CHECK( !symbol->GetExcludedFromBoard( &m_schematic->Hierarchy()[0], wxEmptyString ) );
526
527 // Test exclude from position files as well
528 BOOST_CHECK( !symbol->GetExcludedFromPosFiles() );
529 symbol->SetExcludedFromPosFiles( true, &m_schematic->Hierarchy()[0], variantName );
530 BOOST_CHECK( symbol->GetExcludedFromPosFiles( &m_schematic->Hierarchy()[0], variantName ) );
531 BOOST_CHECK( !symbol->GetExcludedFromPosFiles( &m_schematic->Hierarchy()[0], wxEmptyString ) );
532}
533
534
538BOOST_AUTO_TEST_CASE( GetVariantNamesForUI )
539{
540 wxFileName fn;
541 fn.SetPath( KI_TEST::GetEeschemaTestDataDir() );
542 fn.AppendDir( wxS( "variant_test" ) );
543 fn.SetName( wxS( "variant_test" ) );
545
546 LoadSchematic( fn.GetFullPath() );
547 BOOST_REQUIRE( m_schematic );
548
549 // Add some variants
550 m_schematic->AddVariant( wxS( "Zebra" ) );
551 m_schematic->AddVariant( wxS( "Alpha" ) );
552 m_schematic->AddVariant( wxS( "Beta" ) );
553
554 wxArrayString variantNames = m_schematic->GetVariantNamesForUI();
555
556 // Should have at least 4 items (default + 3 variants)
557 BOOST_CHECK( variantNames.GetCount() >= 4 );
558
559 // First item should be the default placeholder
560 // The actual string may vary but should represent "default"
561 BOOST_CHECK( !variantNames[0].IsEmpty() );
562
563 // Remaining items should be sorted
564 // Alpha, Beta, Zebra
565 bool foundAlpha = false;
566 bool foundBeta = false;
567 bool foundZebra = false;
568
569 for( size_t i = 1; i < variantNames.GetCount(); i++ )
570 {
571 if( variantNames[i] == wxS( "Alpha" ) )
572 foundAlpha = true;
573 else if( variantNames[i] == wxS( "Beta" ) )
574 foundBeta = true;
575 else if( variantNames[i] == wxS( "Zebra" ) )
576 foundZebra = true;
577 }
578
579 BOOST_CHECK( foundAlpha );
580 BOOST_CHECK( foundBeta );
581 BOOST_CHECK( foundZebra );
582}
583
584
590BOOST_AUTO_TEST_CASE( SetValueFieldTextPersistsVariantValue )
591{
592 wxFileName fn;
593 fn.SetPath( KI_TEST::GetEeschemaTestDataDir() );
594 fn.AppendDir( wxS( "variant_test" ) );
595 fn.SetName( wxS( "variant_test" ) );
597
598 LoadSchematic( fn.GetFullPath() );
599 BOOST_REQUIRE( m_schematic );
600
601 SCH_SYMBOL* symbol = GetFirstSymbol();
602 BOOST_REQUIRE( symbol );
603
604 wxString variantName = wxS( "PersistenceTest" );
605 wxString newValue = wxS( "4.7K" );
606 wxString defaultValue = symbol->GetField( FIELD_T::VALUE )->GetText();
607
608 // Add the variant
609 m_schematic->AddVariant( variantName );
610
611 // Set value using SetValueFieldText (the function that had the bug)
612 symbol->SetValueFieldText( newValue, &m_schematic->Hierarchy()[0], variantName );
613
614 // Verify that the variant value was actually saved by reading it back
615 std::optional<SCH_SYMBOL_VARIANT> variant = symbol->GetVariant( m_schematic->Hierarchy()[0], variantName );
616 BOOST_REQUIRE( variant.has_value() );
617
618 wxString fieldName = symbol->GetField( FIELD_T::VALUE )->GetName();
619 BOOST_CHECK( variant->m_Fields.contains( fieldName ) );
620 BOOST_CHECK_EQUAL( variant->m_Fields.at( fieldName ), newValue );
621
622 // Verify through GetValue method as well
623 wxString retrievedValue = symbol->GetValue( false, &m_schematic->Hierarchy()[0], false, variantName );
624 BOOST_CHECK_EQUAL( retrievedValue, newValue );
625
626 // Verify default value is unchanged
627 wxString retrievedDefault = symbol->GetValue( false, &m_schematic->Hierarchy()[0], false, wxEmptyString );
628 BOOST_CHECK_EQUAL( retrievedDefault, defaultValue );
629}
630
631
635BOOST_AUTO_TEST_CASE( SetFieldTextAndSetValueFieldTextConsistency )
636{
637 wxFileName fn;
638 fn.SetPath( KI_TEST::GetEeschemaTestDataDir() );
639 fn.AppendDir( wxS( "variant_test" ) );
640 fn.SetName( wxS( "variant_test" ) );
642
643 LoadSchematic( fn.GetFullPath() );
644 BOOST_REQUIRE( m_schematic );
645
646 SCH_SYMBOL* symbol = GetFirstSymbol();
647 BOOST_REQUIRE( symbol );
648
649 wxString variantName1 = wxS( "MethodTest1" );
650 wxString variantName2 = wxS( "MethodTest2" );
651 wxString value1 = wxS( "10K" );
652 wxString value2 = wxS( "22K" );
653 wxString fieldName = symbol->GetField( FIELD_T::VALUE )->GetName();
654
655 m_schematic->AddVariant( variantName1 );
656 m_schematic->AddVariant( variantName2 );
657
658 // Set variant 1 using SetValueFieldText
659 symbol->SetValueFieldText( value1, &m_schematic->Hierarchy()[0], variantName1 );
660
661 // Set variant 2 using SetFieldText
662 symbol->SetFieldText( fieldName, value2, &m_schematic->Hierarchy()[0], variantName2 );
663
664 // Both methods should produce the same result structure
665 std::optional<SCH_SYMBOL_VARIANT> variant1 = symbol->GetVariant( m_schematic->Hierarchy()[0], variantName1 );
666 std::optional<SCH_SYMBOL_VARIANT> variant2 = symbol->GetVariant( m_schematic->Hierarchy()[0], variantName2 );
667
668 BOOST_REQUIRE( variant1.has_value() );
669 BOOST_REQUIRE( variant2.has_value() );
670
671 BOOST_CHECK( variant1->m_Fields.contains( fieldName ) );
672 BOOST_CHECK( variant2->m_Fields.contains( fieldName ) );
673
674 BOOST_CHECK_EQUAL( variant1->m_Fields.at( fieldName ), value1 );
675 BOOST_CHECK_EQUAL( variant2->m_Fields.at( fieldName ), value2 );
676
677 // Verify through GetValue
678 BOOST_CHECK_EQUAL( symbol->GetValue( false, &m_schematic->Hierarchy()[0], false, variantName1 ), value1 );
679 BOOST_CHECK_EQUAL( symbol->GetValue( false, &m_schematic->Hierarchy()[0], false, variantName2 ), value2 );
680
681 // Verify through GetFieldText
682 BOOST_CHECK_EQUAL( symbol->GetFieldText( fieldName, &m_schematic->Hierarchy()[0], variantName1 ), value1 );
683 BOOST_CHECK_EQUAL( symbol->GetFieldText( fieldName, &m_schematic->Hierarchy()[0], variantName2 ), value2 );
684}
685
686
691BOOST_AUTO_TEST_CASE( VariantNameHandling )
692{
693 wxFileName fn;
694 fn.SetPath( KI_TEST::GetEeschemaTestDataDir() );
695 fn.AppendDir( wxS( "variant_test" ) );
696 fn.SetName( wxS( "variant_test" ) );
698
699 LoadSchematic( fn.GetFullPath() );
700 BOOST_REQUIRE( m_schematic );
701
702 SCH_SYMBOL* symbol = GetFirstSymbol();
703 BOOST_REQUIRE( symbol );
704
705 wxString variantName = wxS( "ProductionVariant" );
706
707 // Add variant with specific casing
708 m_schematic->AddVariant( variantName );
709
710 // Set DNP on variant
711 symbol->SetDNP( true, &m_schematic->Hierarchy()[0], variantName );
712
713 // Verify with exact case - this should work
714 BOOST_CHECK( symbol->GetDNP( &m_schematic->Hierarchy()[0], wxS( "ProductionVariant" ) ) );
715
716 // Verify variant exists
717 BOOST_CHECK( m_schematic->GetVariantNames().contains( wxS( "ProductionVariant" ) ) );
718
719 // Set and get current variant
720 m_schematic->SetCurrentVariant( variantName );
721 BOOST_CHECK_EQUAL( m_schematic->GetCurrentVariant(), variantName );
722
723 // Unknown variant should return base DNP (false)
724 BOOST_CHECK( !symbol->GetDNP( &m_schematic->Hierarchy()[0], wxS( "NonExistentVariant" ) ) );
725}
726
727
731BOOST_AUTO_TEST_CASE( VariantDeletionCascade )
732{
733 wxFileName fn;
734 fn.SetPath( KI_TEST::GetEeschemaTestDataDir() );
735 fn.AppendDir( wxS( "variant_test" ) );
736 fn.SetName( wxS( "variant_test" ) );
738
739 LoadSchematic( fn.GetFullPath() );
740 BOOST_REQUIRE( m_schematic );
741
742 SCH_SYMBOL* symbol = GetFirstSymbol();
743 BOOST_REQUIRE( symbol );
744
745 wxString variantName = wxS( "DeleteMe" );
746
747 // Add variant and set properties
748 m_schematic->AddVariant( variantName );
749 symbol->SetDNP( true, &m_schematic->Hierarchy()[0], variantName );
750 symbol->GetField( FIELD_T::VALUE )->SetText( wxS( "DeletedValue" ), &m_schematic->Hierarchy()[0], variantName );
751
752 // Verify data is set
753 BOOST_CHECK( symbol->GetDNP( &m_schematic->Hierarchy()[0], variantName ) );
754 std::optional<SCH_SYMBOL_VARIANT> variant = symbol->GetVariant( m_schematic->Hierarchy()[0], variantName );
755 BOOST_CHECK( variant.has_value() );
756
757 // Delete the variant
758 m_schematic->DeleteVariant( variantName );
759
760 // Variant should no longer exist at schematic level
761 BOOST_CHECK( !m_schematic->GetVariantNames().contains( variantName ) );
762
763 // After deletion, querying DNP for non-existent variant should return base value
764 BOOST_CHECK( !symbol->GetDNP( &m_schematic->Hierarchy()[0], variantName ) );
765}
766
767
771BOOST_AUTO_TEST_CASE( VariantFieldUnicodeAndSpecialChars )
772{
773 wxFileName fn;
774 fn.SetPath( KI_TEST::GetEeschemaTestDataDir() );
775 fn.AppendDir( wxS( "variant_test" ) );
776 fn.SetName( wxS( "variant_test" ) );
778
779 LoadSchematic( fn.GetFullPath() );
780 BOOST_REQUIRE( m_schematic );
781
782 SCH_SYMBOL* symbol = GetFirstSymbol();
783 BOOST_REQUIRE( symbol );
784
785 wxString variantName = wxS( "UnicodeTest" );
786 m_schematic->AddVariant( variantName );
787
788 // Test Unicode characters in field values
789 wxString unicodeValue = wxS( "1kΩ ±5% 日本語" );
790 symbol->GetField( FIELD_T::VALUE )->SetText( unicodeValue, &m_schematic->Hierarchy()[0], variantName );
791
792 wxString retrieved = symbol->GetField( FIELD_T::VALUE )->GetShownText( &m_schematic->Hierarchy()[0],
793 false, 0, variantName );
794 BOOST_CHECK_EQUAL( retrieved, unicodeValue );
795
796 // Test special characters
797 wxString specialChars = wxS( "R<1K>\"test\"'value'" );
798 symbol->GetField( FIELD_T::VALUE )->SetText( specialChars, &m_schematic->Hierarchy()[0], variantName );
799
800 retrieved = symbol->GetField( FIELD_T::VALUE )->GetShownText( &m_schematic->Hierarchy()[0],
801 false, 0, variantName );
802 BOOST_CHECK_EQUAL( retrieved, specialChars );
803
804 // Test empty string
805 symbol->GetField( FIELD_T::VALUE )->SetText( wxEmptyString, &m_schematic->Hierarchy()[0], variantName );
806 retrieved = symbol->GetField( FIELD_T::VALUE )->GetShownText( &m_schematic->Hierarchy()[0],
807 false, 0, variantName );
808 BOOST_CHECK( retrieved.IsEmpty() );
809
810 // Test description with unicode
811 wxString unicodeDesc = wxS( "Variante für Produktion — 测试" );
812 m_schematic->SetVariantDescription( variantName, unicodeDesc );
813 BOOST_CHECK_EQUAL( m_schematic->GetVariantDescription( variantName ), unicodeDesc );
814}
815
816
820BOOST_AUTO_TEST_CASE( VariantSpecificFieldDereferencing )
821{
822 wxFileName fn;
823 fn.SetPath( KI_TEST::GetEeschemaTestDataDir() );
824 fn.AppendDir( wxS( "variant_test" ) );
825 fn.SetName( wxS( "variant_test" ) );
827
828 LoadSchematic( fn.GetFullPath() );
829 BOOST_REQUIRE( m_schematic );
830
831 SCH_SYMBOL* symbol = GetFirstSymbol();
832 BOOST_REQUIRE( symbol );
833
834 wxString variantName = wxS( "MilitaryGrade" );
835 wxString variantValue = wxS( "1K-MIL" );
836 wxString defaultValue = wxS( "1K" );
837
838 // Create a variant with a different value field
839 m_schematic->AddVariant( variantName );
840 symbol->GetField( FIELD_T::VALUE )->SetText( variantValue, &m_schematic->Hierarchy()[0], variantName );
841
842 // Verify default value
843 BOOST_CHECK_EQUAL( symbol->GetField( FIELD_T::VALUE )->GetShownText( &m_schematic->Hierarchy()[0], false, 0 ),
844 defaultValue );
845
846 // Get the symbol's reference (R1) for cross-reference testing
847 wxString symbolRef = symbol->GetRef( &m_schematic->Hierarchy()[0], false );
848
849 // Test 1: ResolveCrossReference with variant syntax - should return variant-specific value
850 wxString token = symbolRef + wxS( ":VALUE:" ) + variantName;
851 bool resolved = m_schematic->ResolveCrossReference( &token, 0 );
852 BOOST_CHECK( resolved );
853 BOOST_CHECK_EQUAL( token, variantValue );
854
855 // Test 2: ResolveCrossReference without variant - should return default value
856 token = symbolRef + wxS( ":VALUE" );
857 resolved = m_schematic->ResolveCrossReference( &token, 0 );
858 BOOST_CHECK( resolved );
859 BOOST_CHECK_EQUAL( token, defaultValue );
860
861 // Test 3: ResolveCrossReference with non-existent variant - should return default value
862 token = symbolRef + wxS( ":VALUE:NonExistentVariant" );
863 resolved = m_schematic->ResolveCrossReference( &token, 0 );
864 BOOST_CHECK( resolved );
865 BOOST_CHECK_EQUAL( token, defaultValue );
866
867 // Test 4: ResolveTextVar with variant parameter directly
868 token = wxS( "VALUE" );
869 resolved = symbol->ResolveTextVar( &m_schematic->Hierarchy()[0], &token, variantName, 0 );
870 BOOST_CHECK( resolved );
871 BOOST_CHECK_EQUAL( token, variantValue );
872
873 // Test 5: ResolveTextVar with empty variant - should return default
874 token = wxS( "VALUE" );
875 resolved = symbol->ResolveTextVar( &m_schematic->Hierarchy()[0], &token, wxEmptyString, 0 );
876 BOOST_CHECK( resolved );
877 BOOST_CHECK_EQUAL( token, defaultValue );
878}
879
880
886BOOST_AUTO_TEST_CASE( FootprintFieldVariantSupport )
887{
888 wxFileName fn;
889 fn.SetPath( KI_TEST::GetEeschemaTestDataDir() );
890 fn.AppendDir( wxS( "variant_test" ) );
891 fn.SetName( wxS( "variant_test" ) );
893
894 LoadSchematic( fn.GetFullPath() );
895 BOOST_REQUIRE( m_schematic );
896
897 SCH_SYMBOL* symbol = GetFirstSymbol();
898 BOOST_REQUIRE( symbol );
899
900 wxString variantName = wxS( "FootprintVariant" );
901 wxString baseFootprint = wxS( "Resistor_SMD:R_0805_2012Metric" );
902 wxString variantFootprint = wxS( "Resistor_SMD:R_0402_1005Metric" );
903 wxString fieldName = symbol->GetField( FIELD_T::FOOTPRINT )->GetName();
904
905 // Set a base footprint first
906 symbol->SetFootprintFieldText( baseFootprint );
907 BOOST_CHECK_EQUAL( symbol->GetFootprintFieldText( false, nullptr, false ), baseFootprint );
908
909 // Add the variant
910 m_schematic->AddVariant( variantName );
911
912 // Set a different footprint for the variant using SetFieldText
913 symbol->SetFieldText( fieldName, variantFootprint, &m_schematic->Hierarchy()[0], variantName );
914
915 // Verify base footprint is unchanged
916 wxString retrievedBase = symbol->GetFootprintFieldText( false, nullptr, false );
917 BOOST_CHECK_EQUAL( retrievedBase, baseFootprint );
918
919 // Verify GetFieldText with no variant returns base footprint
920 wxString retrievedDefault = symbol->GetFieldText( fieldName, &m_schematic->Hierarchy()[0], wxEmptyString );
921 BOOST_CHECK_EQUAL( retrievedDefault, baseFootprint );
922
923 // Verify GetFieldText with variant returns variant-specific footprint
924 wxString retrievedVariant = symbol->GetFieldText( fieldName, &m_schematic->Hierarchy()[0], variantName );
925 BOOST_CHECK_EQUAL( retrievedVariant, variantFootprint );
926
927 // Verify that the variant data structure contains the footprint override
928 std::optional<SCH_SYMBOL_VARIANT> variant = symbol->GetVariant( m_schematic->Hierarchy()[0], variantName );
929 BOOST_REQUIRE( variant.has_value() );
930 BOOST_CHECK( variant->m_Fields.contains( fieldName ) );
931 BOOST_CHECK_EQUAL( variant->m_Fields.at( fieldName ), variantFootprint );
932}
933
934
939BOOST_AUTO_TEST_CASE( FootprintFieldVariantNoOpWhenSame )
940{
941 wxFileName fn;
942 fn.SetPath( KI_TEST::GetEeschemaTestDataDir() );
943 fn.AppendDir( wxS( "variant_test" ) );
944 fn.SetName( wxS( "variant_test" ) );
946
947 LoadSchematic( fn.GetFullPath() );
948 BOOST_REQUIRE( m_schematic );
949
950 SCH_SYMBOL* symbol = GetFirstSymbol();
951 BOOST_REQUIRE( symbol );
952
953 wxString variantName = wxS( "NoOpTest" );
954 wxString baseFootprint = wxS( "Resistor_SMD:R_0805_2012Metric" );
955 wxString fieldName = symbol->GetField( FIELD_T::FOOTPRINT )->GetName();
956
957 // Set a base footprint first
958 symbol->SetFootprintFieldText( baseFootprint );
959
960 // Add the variant
961 m_schematic->AddVariant( variantName );
962
963 // Set the same footprint value for the variant
964 symbol->SetFieldText( fieldName, baseFootprint, &m_schematic->Hierarchy()[0], variantName );
965
966 // Verify that no variant override was created since the value is the same
967 std::optional<SCH_SYMBOL_VARIANT> variant = symbol->GetVariant( m_schematic->Hierarchy()[0], variantName );
968
969 // Either no variant was created, or it exists but doesn't have a footprint override
970 if( variant.has_value() )
971 {
972 BOOST_CHECK( !variant->m_Fields.contains( fieldName ) );
973 }
974}
975
976
virtual void SetParent(EDA_ITEM *aParent)
Definition eda_item.h:113
EDA_ITEM * GetParent() const
Definition eda_item.h:112
EE_TYPE OfType(KICAD_T aType) const
Definition sch_rtree.h:241
A generic fixture for loading schematics and associated settings for qa tests.
std::unique_ptr< SCHEMATIC > m_schematic
virtual const wxString & GetText() const override
Return the string associated with the text object.
Definition sch_field.h:118
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:167
EE_RTREE & Items()
Get the full RTree, usually for iterating.
Definition sch_screen.h:118
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
bool GetExcludedFromBOM(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const override
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
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)
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
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
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)
@ 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()
BOOST_AUTO_TEST_CASE(DefaultProperties)
Declare the test suite.
BOOST_CHECK_EQUAL(result, "25.4")
@ SCH_SYMBOL_T
Definition typeinfo.h:176
Definition of file extensions used in Kicad.