KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_issue20173_paste_subsheet.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 3
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
37
40
41#include <connection_graph.h>
42#include <schematic.h>
43#include <sch_sheet.h>
44#include <sch_screen.h>
45#include <sch_symbol.h>
47#include <locale_io.h>
48
49
51{
54
56 std::unique_ptr<SCHEMATIC> m_schematic;
57};
58
59
64std::map<KIID, wxString> GetSymbolReferences( const SCH_SHEET_PATH& aPath )
65{
66 std::map<KIID, wxString> refs;
67
68 if( !aPath.LastScreen() )
69 return refs;
70
71 for( SCH_ITEM* item : aPath.LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
72 {
73 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
74
75 // Skip power symbols (references starting with #)
76 wxString ref = symbol->GetRef( &aPath );
77
78 if( !ref.IsEmpty() && ref[0] != '#' )
79 refs[symbol->m_Uuid] = ref;
80 }
81
82 return refs;
83}
84
85
92BOOST_FIXTURE_TEST_CASE( Issue20173PruningAfterPaste, ISSUE20173_FIXTURE )
93{
95
96 KI_TEST::LoadSchematic( m_settingsManager, "issue20173/issue20173", m_schematic );
97
98 SCH_SHEET_LIST sheets = m_schematic->BuildSheetListSortedByPageNumbers();
99
100 // Find the ch1 subsheet
101 SCH_SHEET_PATH ch1Path;
102 SCH_SHEET* ch1Sheet = nullptr;
103
104 for( const SCH_SHEET_PATH& path : sheets )
105 {
106 if( path.size() > 1 )
107 {
108 ch1Path = path;
109 ch1Sheet = path.Last();
110 break;
111 }
112 }
113
114 BOOST_REQUIRE( ch1Sheet != nullptr );
115
116 SCH_SCREEN* sharedScreen = ch1Sheet->GetScreen();
117 BOOST_REQUIRE( sharedScreen != nullptr );
118
119 // Set up proper instances for ch1 (in case the loaded data has stale UUIDs)
120 std::map<KIID, wxString> originalRefs;
121
122 for( SCH_ITEM* item : sharedScreen->Items().OfType( SCH_SYMBOL_T ) )
123 {
124 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
125 wxString ref = symbol->GetField( FIELD_T::REFERENCE )->GetText();
126
127 if( ref.IsEmpty() || ref[0] == '#' )
128 continue;
129
130 symbol->SetRef( &ch1Path, ref );
131 originalRefs[symbol->m_Uuid] = ref;
132 }
133
134 // Create ch2 with shared screen (simulating paste)
135 SCH_SHEET* ch2Sheet = new SCH_SHEET( m_schematic.get() );
136 ch2Sheet->GetField( FIELD_T::SHEET_NAME )->SetText( "ch2" );
137 ch2Sheet->GetField( FIELD_T::SHEET_FILENAME )->SetText( ch1Sheet->GetFileName() );
138 ch2Sheet->SetScreen( sharedScreen );
139 ch2Sheet->SetPosition( ch1Sheet->GetPosition() + VECTOR2I( schIUScale.MilsToIU( 1000 ), 0 ) );
140
141 // Add to root and refresh hierarchy
142 m_schematic->RootScreen()->Append( ch2Sheet );
143 m_schematic->RefreshHierarchy();
144
145 // Get updated hierarchy
146 sheets = m_schematic->BuildSheetListSortedByPageNumbers();
147 SCH_SHEET_PATH ch2Path;
148
149 for( const SCH_SHEET_PATH& path : sheets )
150 {
151 if( path.size() > 1 && path.Last() == ch2Sheet )
152 {
153 ch2Path = path;
154 break;
155 }
156 }
157
158 BOOST_REQUIRE( ch2Path.size() > 1 );
159
160 // Add ch2 instances with different references
161 for( SCH_ITEM* item : sharedScreen->Items().OfType( SCH_SYMBOL_T ) )
162 {
163 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
164 wxString ch1Ref = symbol->GetRef( &ch1Path );
165
166 if( ch1Ref.IsEmpty() || ch1Ref[0] == '#' )
167 continue;
168
169 // Create ch2 reference (R1 -> R101)
170 wxString ch2Ref = ch1Ref;
171
172 if( ch2Ref.length() > 1 )
173 {
174 wxString prefix = ch2Ref.substr( 0, 1 );
175 long num = 0;
176
177 if( ch2Ref.substr( 1 ).ToLong( &num ) )
178 ch2Ref = prefix + wxString::Format( "%ld", num + 100 );
179 }
180
181 symbol->SetRef( &ch2Path, ch2Ref );
182 }
183
184 // Verify instances are set up correctly before pruning
185 BOOST_TEST_MESSAGE( "Before pruning:" );
186
187 for( SCH_ITEM* item : sharedScreen->Items().OfType( SCH_SYMBOL_T ) )
188 {
189 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
190
191 if( symbol->GetRef( &ch1Path )[0] == '#' )
192 continue;
193
194 BOOST_TEST_MESSAGE( " " << symbol->m_Uuid.AsString() << " ch1=" << symbol->GetRef( &ch1Path )
195 << " ch2=" << symbol->GetRef( &ch2Path ) );
196 break;
197 }
198
199 // Now call the pruning that happens after paste
200 // This is what SCH_EDITOR_CONTROL::Paste does at line 2615
201 SCH_SCREENS allScreens( m_schematic->Root() );
202 allScreens.PruneOrphanedSymbolInstances( m_schematic->Project().GetProjectName(), sheets );
203
204 BOOST_TEST_MESSAGE( "After pruning:" );
205
206 // Verify ch1 instances are still intact after pruning
207 bool ch1InstancesIntact = true;
208
209 for( const auto& [uuid, originalRef] : originalRefs )
210 {
211 // Find the symbol
212 SCH_SYMBOL* symbol = nullptr;
213
214 for( SCH_ITEM* item : sharedScreen->Items().OfType( SCH_SYMBOL_T ) )
215 {
216 if( item->m_Uuid == uuid )
217 {
218 symbol = static_cast<SCH_SYMBOL*>( item );
219 break;
220 }
221 }
222
223 if( !symbol )
224 continue;
225
226 wxString ch1RefAfter = symbol->GetRef( &ch1Path );
227 wxString ch2RefAfter = symbol->GetRef( &ch2Path );
228
229 BOOST_TEST_MESSAGE( " " << uuid.AsString() << " ch1=" << ch1RefAfter << " ch2="
230 << ch2RefAfter << " (original=" << originalRef << ")" );
231
232 if( ch1RefAfter != originalRef )
233 {
234 BOOST_TEST_MESSAGE( " MISMATCH: ch1 reference changed from " << originalRef << " to "
235 << ch1RefAfter );
236 ch1InstancesIntact = false;
237 }
238 }
239
240 BOOST_CHECK_MESSAGE( ch1InstancesIntact,
241 "CH1 instances should be preserved after paste and pruning" );
242}
243
244
251BOOST_FIXTURE_TEST_CASE( Issue20173ClearAnnotationFieldCorruption, ISSUE20173_FIXTURE )
252{
254
255 KI_TEST::LoadSchematic( m_settingsManager, "issue20173/issue20173", m_schematic );
256
257 SCH_SHEET_LIST sheets = m_schematic->BuildSheetListSortedByPageNumbers();
258
259 // Find the ch1 subsheet
260 SCH_SHEET_PATH ch1Path;
261 SCH_SHEET* ch1Sheet = nullptr;
262
263 for( const SCH_SHEET_PATH& path : sheets )
264 {
265 if( path.size() > 1 )
266 {
267 ch1Path = path;
268 ch1Sheet = path.Last();
269 break;
270 }
271 }
272
273 BOOST_REQUIRE( ch1Sheet != nullptr );
274
275 SCH_SCREEN* sharedScreen = ch1Sheet->GetScreen();
276 BOOST_REQUIRE( sharedScreen != nullptr );
277
278 // Set up proper instances for ch1 (fix any stale UUID issues from loading)
279 std::map<KIID, wxString> ch1OriginalRefs;
280
281 for( SCH_ITEM* item : sharedScreen->Items().OfType( SCH_SYMBOL_T ) )
282 {
283 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
284 wxString ref = symbol->GetField( FIELD_T::REFERENCE )->GetText();
285
286 if( ref.IsEmpty() || ref[0] == '#' )
287 continue;
288
289 symbol->SetRef( &ch1Path, ref );
290 ch1OriginalRefs[symbol->m_Uuid] = ref;
291 }
292
293 // Create ch2 with shared screen
294 SCH_SHEET* ch2Sheet = new SCH_SHEET( m_schematic.get() );
295 ch2Sheet->GetField( FIELD_T::SHEET_NAME )->SetText( "ch2" );
296 ch2Sheet->GetField( FIELD_T::SHEET_FILENAME )->SetText( ch1Sheet->GetFileName() );
297 ch2Sheet->SetScreen( sharedScreen );
298
299 m_schematic->RootScreen()->Append( ch2Sheet );
300 m_schematic->RefreshHierarchy();
301
302 sheets = m_schematic->BuildSheetListSortedByPageNumbers();
303
304 SCH_SHEET_PATH ch2Path;
305
306 for( const SCH_SHEET_PATH& path : sheets )
307 {
308 if( path.size() > 1 && path.Last() == ch2Sheet )
309 {
310 ch2Path = path;
311 break;
312 }
313 }
314
315 BOOST_REQUIRE( ch2Path.size() > 1 );
316
317 // Add ch2 instances and call ClearAnnotation (simulating paste with !forceKeepAnnotations)
318 for( SCH_ITEM* item : sharedScreen->Items().OfType( SCH_SYMBOL_T ) )
319 {
320 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
321 wxString ch1Ref = symbol->GetRef( &ch1Path );
322
323 if( ch1Ref.IsEmpty() || ch1Ref[0] == '#' )
324 continue;
325
326 // Add instance for ch2 (like updatePastedSymbol does)
327 symbol->SetRef( &ch2Path, ch1Ref );
328
329 // Now call ClearAnnotation for ch2 path (like updatePastedSymbol does when !forceKeepAnnotations)
330 symbol->ClearAnnotation( &ch2Path, false );
331 }
332
333 // Verify ch1 references are unchanged after ClearAnnotation on ch2
334 bool ch1RefsPreserved = true;
335
336 for( const auto& [uuid, originalRef] : ch1OriginalRefs )
337 {
338 SCH_SYMBOL* symbol = nullptr;
339
340 for( SCH_ITEM* item : sharedScreen->Items().OfType( SCH_SYMBOL_T ) )
341 {
342 if( item->m_Uuid == uuid )
343 {
344 symbol = static_cast<SCH_SYMBOL*>( item );
345 break;
346 }
347 }
348
349 if( !symbol )
350 continue;
351
352 wxString ch1RefAfter = symbol->GetRef( &ch1Path );
353
354 if( ch1RefAfter != originalRef )
355 {
356 BOOST_TEST_MESSAGE( "Symbol " << uuid.AsString() << " ch1 reference changed from "
357 << originalRef << " to " << ch1RefAfter
358 << " after ClearAnnotation on ch2" );
359 ch1RefsPreserved = false;
360 }
361 }
362
363 BOOST_CHECK_MESSAGE( ch1RefsPreserved,
364 "CH1 references should be preserved after ClearAnnotation on CH2" );
365}
366
367
375BOOST_FIXTURE_TEST_CASE( Issue20173FieldTextCorruption, ISSUE20173_FIXTURE )
376{
378
379 KI_TEST::LoadSchematic( m_settingsManager, "issue20173/issue20173", m_schematic );
380
381 SCH_SHEET_LIST sheets = m_schematic->BuildSheetListSortedByPageNumbers();
382
383 // Find the ch1 subsheet
384 SCH_SHEET_PATH ch1Path;
385 SCH_SHEET* ch1Sheet = nullptr;
386
387 for( const SCH_SHEET_PATH& path : sheets )
388 {
389 if( path.size() > 1 )
390 {
391 ch1Path = path;
392 ch1Sheet = path.Last();
393 break;
394 }
395 }
396
397 BOOST_REQUIRE( ch1Sheet != nullptr );
398
399 SCH_SCREEN* sharedScreen = ch1Sheet->GetScreen();
400 BOOST_REQUIRE( sharedScreen != nullptr );
401
402 // Capture original field text values (these are what GetRef falls back to)
403 std::map<KIID, wxString> originalFieldText;
404
405 for( SCH_ITEM* item : sharedScreen->Items().OfType( SCH_SYMBOL_T ) )
406 {
407 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
408 wxString ref = symbol->GetField( FIELD_T::REFERENCE )->GetText();
409
410 if( !ref.IsEmpty() && ref[0] != '#' )
411 originalFieldText[symbol->m_Uuid] = ref;
412 }
413
414 BOOST_REQUIRE( originalFieldText.size() > 0 );
415
416 BOOST_TEST_MESSAGE( "Original field text values:" );
417
418 for( const auto& [uuid, ref] : originalFieldText )
419 BOOST_TEST_MESSAGE( " " << uuid.AsString() << " -> " << ref );
420
421 // Create ch2 with shared screen (simulating paste)
422 SCH_SHEET* ch2Sheet = new SCH_SHEET( m_schematic.get() );
423 ch2Sheet->GetField( FIELD_T::SHEET_NAME )->SetText( "ch2" );
424 ch2Sheet->GetField( FIELD_T::SHEET_FILENAME )->SetText( ch1Sheet->GetFileName() );
425 ch2Sheet->SetScreen( sharedScreen );
426
427 m_schematic->RootScreen()->Append( ch2Sheet );
428 m_schematic->RefreshHierarchy();
429
430 sheets = m_schematic->BuildSheetListSortedByPageNumbers();
431
432 SCH_SHEET_PATH ch2Path;
433
434 for( const SCH_SHEET_PATH& path : sheets )
435 {
436 if( path.size() > 1 && path.Last() == ch2Sheet )
437 {
438 ch2Path = path;
439 break;
440 }
441 }
442
443 BOOST_REQUIRE( ch2Path.size() > 1 );
444
445 // Simulate what updatePastedSymbol does:
446 // 1. Add instance for new path
447 // 2. Call ClearAnnotation for new path
448 for( SCH_ITEM* item : sharedScreen->Items().OfType( SCH_SYMBOL_T ) )
449 {
450 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
451 wxString fieldRef = symbol->GetField( FIELD_T::REFERENCE )->GetText();
452
453 if( fieldRef.IsEmpty() || fieldRef[0] == '#' )
454 continue;
455
456 // Add instance for ch2 (like AddHierarchicalReference does)
457 symbol->SetRef( &ch2Path, fieldRef );
458
459 // Now call ClearAnnotation for ch2 path (like updatePastedSymbol does)
460 symbol->ClearAnnotation( &ch2Path, false );
461 }
462
463 // Check if field text is corrupted
464 BOOST_TEST_MESSAGE( "Field text after ClearAnnotation on ch2:" );
465
466 bool fieldTextCorrupted = false;
467
468 for( const auto& [uuid, originalRef] : originalFieldText )
469 {
470 SCH_SYMBOL* symbol = nullptr;
471
472 for( SCH_ITEM* item : sharedScreen->Items().OfType( SCH_SYMBOL_T ) )
473 {
474 if( item->m_Uuid == uuid )
475 {
476 symbol = static_cast<SCH_SYMBOL*>( item );
477 break;
478 }
479 }
480
481 if( !symbol )
482 continue;
483
484 wxString currentFieldText = symbol->GetField( FIELD_T::REFERENCE )->GetText();
485
486 BOOST_TEST_MESSAGE( " " << uuid.AsString() << " -> " << currentFieldText
487 << " (was " << originalRef << ")" );
488
489 if( currentFieldText != originalRef )
490 {
491 fieldTextCorrupted = true;
492 BOOST_TEST_MESSAGE( " CORRUPTED!" );
493 }
494 }
495
496 // The bug: ClearAnnotation modifies field text even when called for a specific path
497 // This causes GetRef to return wrong value when falling back to field text
498 BOOST_CHECK_MESSAGE( !fieldTextCorrupted,
499 "Field text should NOT be corrupted by ClearAnnotation on different path" );
500}
501
502
509BOOST_FIXTURE_TEST_CASE( Issue20173SharedScreenInstances, ISSUE20173_FIXTURE )
510{
512
513 KI_TEST::LoadSchematic( m_settingsManager, "issue20173/issue20173", m_schematic );
514
515 SCH_SHEET_LIST sheets = m_schematic->BuildSheetListSortedByPageNumbers();
516
517 // Find the ch1 subsheet
518 SCH_SHEET_PATH ch1Path;
519 SCH_SHEET* ch1Sheet = nullptr;
520
521 for( const SCH_SHEET_PATH& path : sheets )
522 {
523 if( path.size() > 1 )
524 {
525 ch1Path = path;
526 ch1Sheet = path.Last();
527 break;
528 }
529 }
530
531 BOOST_REQUIRE( ch1Sheet != nullptr );
532
533 SCH_SCREEN* sharedScreen = ch1Sheet->GetScreen();
534 BOOST_REQUIRE( sharedScreen != nullptr );
535
536 // Get root path for adding new sheet
537 SCH_SHEET_PATH rootPath;
538 rootPath.push_back( &m_schematic->Root() );
539
540 // Create ch2 with shared screen
541 SCH_SHEET* ch2Sheet = new SCH_SHEET( m_schematic.get() );
542 ch2Sheet->GetField( FIELD_T::SHEET_NAME )->SetText( "ch2" );
543 ch2Sheet->GetField( FIELD_T::SHEET_FILENAME )->SetText( ch1Sheet->GetFileName() );
544 ch2Sheet->SetScreen( sharedScreen );
545 ch2Sheet->SetPosition( ch1Sheet->GetPosition() + VECTOR2I( schIUScale.MilsToIU( 1000 ), 0 ) );
546
547 // Manually add ch2 to root screen
548 m_schematic->RootScreen()->Append( ch2Sheet );
549 m_schematic->RefreshHierarchy();
550
551 // Rebuild sheets after adding ch2
552 sheets = m_schematic->BuildSheetListSortedByPageNumbers();
553
554 // Find ch2 path from the hierarchy (don't construct manually)
555 SCH_SHEET_PATH ch2Path;
556
557 for( const SCH_SHEET_PATH& path : sheets )
558 {
559 if( path.size() > 1 && path.Last() == ch2Sheet )
560 {
561 ch2Path = path;
562 break;
563 }
564 }
565
566 BOOST_REQUIRE_MESSAGE( ch2Path.size() > 1, "Should find ch2 in hierarchy" );
567
568 // First, ensure all symbols have proper instances for ch1Path
569 // (The loaded schematic might have stale instance data with old sheet UUIDs)
570 int symbolIndex = 0;
571
572 for( SCH_ITEM* item : sharedScreen->Items().OfType( SCH_SYMBOL_T ) )
573 {
574 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
575
576 // Skip power symbols
577 wxString currentRef = symbol->GetField( FIELD_T::REFERENCE )->GetText();
578
579 if( currentRef.IsEmpty() || currentRef[0] == '#' )
580 continue;
581
582 // Set up proper ch1 reference using the current field text
583 symbol->SetRef( &ch1Path, currentRef );
584 symbolIndex++;
585 }
586
587 BOOST_TEST_MESSAGE( "Set up " << symbolIndex << " symbols with ch1 instances" );
588
589 // Now set different references for ch2
590 for( SCH_ITEM* item : sharedScreen->Items().OfType( SCH_SYMBOL_T ) )
591 {
592 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
593
594 wxString ch1Ref = symbol->GetRef( &ch1Path );
595
596 // Skip power symbols
597 if( ch1Ref.IsEmpty() || ch1Ref[0] == '#' )
598 continue;
599
600 // Add a different reference for ch2 (R1 -> R101, D1 -> D101, etc.)
601 wxString ch2Ref = ch1Ref;
602
603 if( ch2Ref.length() > 1 )
604 {
605 wxString prefix = ch2Ref.substr( 0, 1 );
606 long num = 0;
607
608 if( ch2Ref.substr( 1 ).ToLong( &num ) )
609 ch2Ref = prefix + wxString::Format( "%ld", num + 100 );
610 }
611
612 symbol->SetRef( &ch2Path, ch2Ref );
613
614 // Verify ch1 reference is unchanged
615 wxString ch1RefAfter = symbol->GetRef( &ch1Path );
616 BOOST_CHECK_MESSAGE( ch1Ref == ch1RefAfter,
617 "Setting ch2 reference should not change ch1 reference for symbol "
618 << symbol->m_Uuid.AsString() );
619
620 // Verify ch2 has its own reference
621 wxString ch2RefAfter = symbol->GetRef( &ch2Path );
622 BOOST_CHECK_MESSAGE( ch2Ref == ch2RefAfter,
623 "ch2 should have its own reference for symbol "
624 << symbol->m_Uuid.AsString() );
625 }
626
627 // Debug: Print ch1 and ch2 paths
628 BOOST_TEST_MESSAGE( "ch1Path: " << ch1Path.Path().AsString() );
629 BOOST_TEST_MESSAGE( "ch2Path: " << ch2Path.Path().AsString() );
630
631 // Debug: Print instances for first non-power symbol before UpdateAllScreenReferences
632 BOOST_TEST_MESSAGE( "Before UpdateAllScreenReferences:" );
633
634 for( SCH_ITEM* item : sharedScreen->Items().OfType( SCH_SYMBOL_T ) )
635 {
636 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
637
638 if( symbol->GetRef( &ch1Path )[0] == '#' )
639 continue;
640
641 BOOST_TEST_MESSAGE( "Symbol " << symbol->m_Uuid.AsString() << " instances:" );
642
643 for( const SCH_SYMBOL_INSTANCE& inst : symbol->GetInstances() )
644 {
645 BOOST_TEST_MESSAGE( " Path: " << inst.m_Path.AsString() << " -> " << inst.m_Reference );
646 }
647
648 BOOST_TEST_MESSAGE( " Field text: " << symbol->GetField( FIELD_T::REFERENCE )->GetText() );
649 BOOST_TEST_MESSAGE( " GetRef(ch1): " << symbol->GetRef( &ch1Path ) );
650 BOOST_TEST_MESSAGE( " GetRef(ch2): " << symbol->GetRef( &ch2Path ) );
651 break; // Only print first symbol for brevity
652 }
653
654 // Now test UpdateAllScreenReferences doesn't corrupt the other instance
656
657 BOOST_TEST_MESSAGE( "After ch2Path.UpdateAllScreenReferences():" );
658
659 for( SCH_ITEM* item : sharedScreen->Items().OfType( SCH_SYMBOL_T ) )
660 {
661 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
662
663 if( symbol->GetRef( &ch1Path )[0] == '#' )
664 continue;
665
666 BOOST_TEST_MESSAGE( " Field text: " << symbol->GetField( FIELD_T::REFERENCE )->GetText() );
667 BOOST_TEST_MESSAGE( " GetRef(ch1): " << symbol->GetRef( &ch1Path ) );
668 BOOST_TEST_MESSAGE( " GetRef(ch2): " << symbol->GetRef( &ch2Path ) );
669 break;
670 }
671
673
674 BOOST_TEST_MESSAGE( "After ch1Path.UpdateAllScreenReferences():" );
675
676 for( SCH_ITEM* item : sharedScreen->Items().OfType( SCH_SYMBOL_T ) )
677 {
678 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
679
680 if( symbol->GetRef( &ch1Path )[0] == '#' )
681 continue;
682
683 BOOST_TEST_MESSAGE( " Field text: " << symbol->GetField( FIELD_T::REFERENCE )->GetText() );
684 BOOST_TEST_MESSAGE( " GetRef(ch1): " << symbol->GetRef( &ch1Path ) );
685 BOOST_TEST_MESSAGE( " GetRef(ch2): " << symbol->GetRef( &ch2Path ) );
686 break;
687 }
688
689 // Verify references are still correct after switching
690 for( SCH_ITEM* item : sharedScreen->Items().OfType( SCH_SYMBOL_T ) )
691 {
692 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
693
694 if( symbol->GetRef( &ch1Path )[0] == '#' )
695 continue;
696
697 // Check that instances exist and are different
698 wxString ch1Ref = symbol->GetRef( &ch1Path );
699 wxString ch2Ref = symbol->GetRef( &ch2Path );
700
701 // Since we set ch2 = ch1 + 100, they should be different
702 BOOST_CHECK_MESSAGE( ch1Ref != ch2Ref,
703 "ch1 and ch2 should have different references after navigation" );
704 }
705}
constexpr EDA_IU_SCALE schIUScale
Definition base_units.h:123
const KIID m_Uuid
Definition eda_item.h:531
EE_TYPE OfType(KICAD_T aType) const
Definition sch_rtree.h:221
wxString AsString() const
Definition kiid.cpp:393
wxString AsString() const
Definition kiid.cpp:242
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
Definition locale_io.h:37
virtual const wxString & GetText() const override
Return the string associated with the text object.
Definition sch_field.h:128
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
Container class that holds multiple SCH_SCREEN objects in a hierarchy.
Definition sch_screen.h:746
void PruneOrphanedSymbolInstances(const wxString &aProjectName, const SCH_SHEET_LIST &aValidSheetPaths)
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...
KIID_PATH Path() const
Get the sheet path as an KIID_PATH.
void UpdateAllScreenReferences() const
Update all the symbol references for this sheet path.
SCH_SCREEN * LastScreen()
void push_back(SCH_SHEET *aSheet)
Forwarded method from std::vector.
size_t size() const
Forwarded method from std::vector.
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition sch_sheet.h:44
wxString GetFileName() const
Return the filename corresponding to this sheet.
Definition sch_sheet.h:370
SCH_FIELD * GetField(FIELD_T aFieldType)
Return a mandatory field in this sheet.
void SetPosition(const VECTOR2I &aPosition) override
SCH_SCREEN * GetScreen() const
Definition sch_sheet.h:139
VECTOR2I GetPosition() const override
Definition sch_sheet.h:490
void SetScreen(SCH_SCREEN *aScreen)
Set the SCH_SCREEN associated with this sheet to aScreen.
Schematic symbol object.
Definition sch_symbol.h:69
const std::vector< SCH_SYMBOL_INSTANCE > & GetInstances() const
Definition sch_symbol.h:128
void SetRef(const SCH_SHEET_PATH *aSheet, const wxString &aReference)
Set the reference for the given sheet path for this symbol.
void ClearAnnotation(const SCH_SHEET_PATH *aSheetPath, bool aResetPrefix)
Clear exiting symbol annotation.
const wxString GetRef(const SCH_SHEET_PATH *aSheet, bool aIncludeUnit=false) const override
SCH_FIELD * GetField(FIELD_T aFieldType)
Return a mandatory field in this symbol.
void LoadSchematic(SETTINGS_MANAGER &aSettingsManager, const wxString &aRelPath, std::unique_ptr< SCHEMATIC > &aSchematic)
std::vector< FAB_LAYER_COLOR > dummy
std::unique_ptr< SCHEMATIC > m_schematic
A simple container for schematic symbol instance information.
@ REFERENCE
Field Reference of part, i.e. "IC21".
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_FIXTURE_TEST_CASE(Issue20173PruningAfterPaste, ISSUE20173_FIXTURE)
Test that simulates the paste flow more closely, including instance pruning.
std::map< KIID, wxString > GetSymbolReferences(const SCH_SHEET_PATH &aPath)
Helper function to get all symbol references for a given sheet path.
std::string path
BOOST_CHECK_MESSAGE(totalMismatches==0, std::to_string(totalMismatches)+" board(s) with strategy disagreements")
BOOST_TEST_MESSAGE("\n=== Real-World Polygon PIP Benchmark ===\n"<< formatTable(table))
@ SCH_SYMBOL_T
Definition typeinfo.h:169
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683