KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_erc_hierarchy_connectivity.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
20#include <wx/filename.h>
23
24#include <advanced_config.h>
25#include <api/schematic/schematic_rules.pb.h>
26#include <erc/erc_exclusion.h>
27#include <erc/erc_report.h>
28#include <json_common.h>
29#include <connection_graph.h>
31#include <erc/erc.h>
32#include <erc/erc_settings.h>
33#include <locale_io.h>
34#include <sch_label.h>
35#include <sch_marker.h>
36#include <sch_sheet.h>
37#include <sch_sheet_pin.h>
38#include <sch_symbol.h>
39#include <schematic.h>
41#include <map>
42#include <set>
43#include <tuple>
44#include <scoped_set_reset.h>
45
46
47BOOST_AUTO_TEST_CASE( ERCHierarchyMismatchesUseCapturedConnectivity )
48{
49 LOCALE_IO locale;
50 auto& enabled = const_cast<ADVANCED_CFG&>( ADVANCED_CFG::GetCfg() ).m_ConnectivityEngine;
51 SCOPED_SET_RESET restore( enabled, false );
52 SETTINGS_MANAGER settings;
53 std::unique_ptr<SCHEMATIC> schematic;
54 KI_TEST::LoadSchematic( settings, "issue24201/issue24201", schematic );
55 SCH_LABEL_BASE* renamed = nullptr;
56
57 for( const SCH_SHEET_PATH& path : schematic->Hierarchy() )
58 {
59 if( path.size() > schematic->Hierarchy().front().size() )
60 {
61 auto labels = path.LastScreen()->Items().OfType( SCH_HIER_LABEL_T );
62
63 if( labels.begin() != labels.end() )
64 renamed = static_cast<SCH_LABEL_BASE*>( *labels.begin() );
65 }
66 }
67
68 BOOST_REQUIRE( renamed );
69 renamed->SetText( "ERC_UNMATCHED_PORT" );
70
71 for( auto& [code, severity] : schematic->ErcSettings().m_ERCSeverities )
73
74 using DIAGNOSTICS = std::map<std::pair<KIID_PATH, KIID>, VECTOR2I>;
75 const auto collect = [&]()
76 {
77 DIAGNOSTICS result;
78
79 for( const SCH_SHEET_PATH& path : schematic->Hierarchy() )
80 {
81 for( SCH_ITEM* item : path.LastScreen()->Items().OfType( SCH_MARKER_T ) )
82 {
83 auto* marker = static_cast<SCH_MARKER*>( item );
84 const auto error = std::static_pointer_cast<ERC_ITEM>( marker->GetRCItem() );
85 BOOST_CHECK_EQUAL( error->GetErrorCode(), ERCE_HIERACHICAL_LABEL );
86 BOOST_CHECK( error->MainItemHasSheetPath() );
87 BOOST_CHECK( !error->AuxItemHasSheetPath() );
88 result.emplace( std::pair{ error->GetSpecificSheetPath().PathRef(), error->GetMainItemID() },
89 marker->GetPosition() );
90 }
91 }
92
93 return result;
94 };
95 schematic->RebuildConnectivity();
96 BOOST_REQUIRE_EQUAL( schematic->ConnectionGraph()->RunERC(), 2 );
97 const auto expected = collect();
98 BOOST_REQUIRE_EQUAL( expected.size(), 2 );
99
100 const auto clearMarkers = [&]()
101 {
102 for( const SCH_SHEET_PATH& path : schematic->Hierarchy() )
103 {
104 std::vector<SCH_ITEM*> markers;
105
106 for( SCH_ITEM* item : path.LastScreen()->Items().OfType( SCH_MARKER_T ) )
107 markers.push_back( item );
108
109 for( SCH_ITEM* marker : markers )
110 path.LastScreen()->DeleteItem( marker );
111 }
112 };
113 clearMarkers();
114
115 enabled = true;
116 schematic->RebuildConnectivity();
117 schematic->ConnectionGraph()->Reset();
119 BOOST_CHECK( collect() == expected );
120}
121
122
123BOOST_AUTO_TEST_CASE( ERCRootHierarchyLabelsKeepEveryItemAndRespectSeverity )
124{
125 LOCALE_IO locale;
126 auto& enabled = const_cast<ADVANCED_CFG&>( ADVANCED_CFG::GetCfg() ).m_ConnectivityEngine;
127 SCOPED_SET_RESET restore( enabled, true );
128 SETTINGS_MANAGER settings;
129 std::unique_ptr<SCHEMATIC> schematic;
130 KI_TEST::LoadSchematic( settings, "issue24201/issue24201", schematic );
131 const SCH_SHEET_PATH root = schematic->Hierarchy().front();
132 SCH_LABEL_BASE* source = nullptr;
133
134 for( const SCH_SHEET_PATH& path : schematic->Hierarchy() )
135 {
136 for( SCH_ITEM* item : path.LastScreen()->Items().OfType( SCH_HIER_LABEL_T ) )
137 source = static_cast<SCH_LABEL_BASE*>( item );
138 }
139
140 BOOST_REQUIRE( source );
141 std::set<KIID> expected;
142
143 for( int index = 0; index < 2; ++index )
144 {
145 auto* label = static_cast<SCH_LABEL_BASE*>( source->Duplicate( false ) );
146 const VECTOR2I position( 100000000 + index * 1000000, 100000000 );
147 label->SetText( "ERC_ROOT_PORT" );
148 label->Move( position - label->GetPosition() );
149 root.LastScreen()->Append( label );
150 expected.insert( label->m_Uuid );
151 }
152
153 enabled = false;
154
155 for( auto& [code, severity] : schematic->ErcSettings().m_ERCSeverities )
157
158 schematic->RebuildConnectivity();
159 schematic->ConnectionGraph()->RunERC();
160 std::vector<SCH_ITEM*> legacyMarkers;
161
162 for( SCH_ITEM* item : root.LastScreen()->Items().OfType( SCH_MARKER_T ) )
163 {
164 auto* marker = static_cast<SCH_MARKER*>( item );
165 legacyMarkers.push_back( marker );
166
167 if( expected.contains( marker->GetRCItem()->GetMainItemID() ) )
168 marker->SetExcluded( true, "Retained root port" );
169 }
170
171 schematic->RecordERCExclusions();
172 BOOST_REQUIRE_EQUAL( schematic->ErcSettings().m_ErcExclusions.size(), 2 );
173
174 for( SCH_ITEM* marker : legacyMarkers )
175 root.LastScreen()->DeleteItem( marker );
176
177 using SIGNATURE = std::tuple<KIID, int, bool, KIID_PATH, bool, size_t, int, int, bool, wxString>;
178
179 for( bool pinEnabled : { false, true } )
180 {
181 for( auto& [code, severity] : schematic->ErcSettings().m_ERCSeverities )
182 {
183 severity = code == ERCE_HIERACHICAL_LABEL || ( pinEnabled && code == ERCE_PIN_NOT_CONNECTED )
185 }
186
187 std::multiset<SIGNATURE> legacy;
188
189 for( bool backend : { false, true } )
190 {
191 BOOST_TEST_CONTEXT( "pinEnabled=" << pinEnabled << "; backend=" << backend )
192 {
193 enabled = backend;
194 schematic->RebuildConnectivity();
195 schematic->ConnectionGraph()->RunERC();
196
197 if( pinEnabled )
198 schematic->ResolveERCExclusionsPostUpdate();
199
200 std::multiset<SIGNATURE> actual;
201 size_t pinMarkers = 0;
202 std::vector<SCH_ITEM*> markers;
203
204 for( SCH_ITEM* item : root.LastScreen()->Items().OfType( SCH_MARKER_T ) )
205 {
206 auto* marker = static_cast<SCH_MARKER*>( item );
207 markers.push_back( marker );
208 const auto error = std::static_pointer_cast<ERC_ITEM>( marker->GetRCItem() );
209
210 // Legacy creates root-label markers even when their severity hides them from users
211 if( !expected.contains( error->GetMainItemID() )
212 || schematic->ErcSettings().GetSeverity( error->GetErrorCode() ) == RPT_SEVERITY_IGNORE )
213 continue;
214
215 if( error->GetErrorCode() == ERCE_PIN_NOT_CONNECTED )
216 {
217 BOOST_CHECK( marker->IsExcluded() );
218 BOOST_CHECK_EQUAL( marker->GetComment(), wxString( "Retained root port" ) );
219 ++pinMarkers;
220 }
221
222 actual.emplace( error->GetMainItemID(), error->GetErrorCode(), error->IsSheetSpecific(),
223 error->IsSheetSpecific() ? error->GetSpecificSheetPath().PathRef() : KIID_PATH(),
224 error->MainItemHasSheetPath(), error->GetIDs().size(), marker->GetPosition().x,
225 marker->GetPosition().y, marker->IsExcluded(), marker->GetComment() );
226 }
227
228 if( !backend )
229 legacy = actual;
230
231 BOOST_CHECK_EQUAL( pinMarkers, pinEnabled ? expected.size() : 0 );
232 BOOST_CHECK( actual == legacy );
233
234 for( SCH_ITEM* marker : markers )
235 root.LastScreen()->DeleteItem( marker );
236 }
237 }
238 }
239}
240
241BOOST_AUTO_TEST_CASE( ERCHierarchySheetPinDanglingUsesCapturedContacts )
242{
243 LOCALE_IO locale;
244 auto& enabled = const_cast<ADVANCED_CFG&>( ADVANCED_CFG::GetCfg() ).m_ConnectivityEngine;
245 SCOPED_SET_RESET restore( enabled, false );
246 SETTINGS_MANAGER settings;
247 std::unique_ptr<SCHEMATIC> schematic;
248 KI_TEST::LoadSchematic( settings, "issue24201/issue24201", schematic );
249 const SCH_SHEET_PATH root = schematic->Hierarchy().front();
250 auto sheets = root.LastScreen()->Items().OfType( SCH_SHEET_T );
251 BOOST_REQUIRE( sheets.begin() != sheets.end() );
252 auto* sheet = static_cast<SCH_SHEET*>( *sheets.begin() );
253 BOOST_REQUIRE( !sheet->GetPins().empty() );
254 SCH_SHEET_PIN* pin = sheet->GetPins().front();
255 sheet->Move( VECTOR2I( 100000000, 100000000 ) );
256
257 for( auto& [code, severity] : schematic->ErcSettings().m_ERCSeverities )
259
260 schematic->RebuildConnectivity();
261 schematic->ConnectionGraph()->RunERC();
262 std::vector<SCH_ITEM*> legacyMarkers;
263
264 for( SCH_ITEM* item : root.LastScreen()->Items().OfType( SCH_MARKER_T ) )
265 {
266 auto* marker = static_cast<SCH_MARKER*>( item );
267 legacyMarkers.push_back( marker );
268
269 if( marker->GetRCItem()->GetMainItemID() == pin->m_Uuid )
270 marker->SetExcluded( true, "Retained sheet pin" );
271 }
272
273 schematic->RecordERCExclusions();
274 BOOST_REQUIRE_EQUAL( schematic->ErcSettings().m_ErcExclusions.size(), 1 );
275
276 for( SCH_ITEM* marker : legacyMarkers )
277 root.LastScreen()->DeleteItem( marker );
278
279 using SIGNATURE = std::tuple<int, wxString, int, int, bool, KIID_PATH, bool, bool, size_t, bool, wxString>;
280 std::multiset<SIGNATURE> legacy;
281
282 for( bool backend : { false, true } )
283 {
284 BOOST_TEST_CONTEXT( "backend=" << backend )
285 {
286 enabled = backend;
287 schematic->RebuildConnectivity();
288 schematic->ConnectionGraph()->RunERC();
289 schematic->ResolveERCExclusionsPostUpdate();
290 std::multiset<SIGNATURE> actual;
291 std::vector<SCH_ITEM*> markers;
292
293 for( SCH_ITEM* item : root.LastScreen()->Items().OfType( SCH_MARKER_T ) )
294 {
295 auto* marker = static_cast<SCH_MARKER*>( item );
296 markers.push_back( marker );
297 const auto error = std::static_pointer_cast<ERC_ITEM>( marker->GetRCItem() );
298
299 if( error->GetMainItemID() != pin->m_Uuid )
300 continue;
301
302 BOOST_CHECK( marker->IsExcluded() );
303 BOOST_CHECK_EQUAL( marker->GetComment(), wxString( "Retained sheet pin" ) );
304 actual.emplace( error->GetErrorCode(), error->GetErrorMessage( true ), marker->GetPosition().x,
305 marker->GetPosition().y, error->IsSheetSpecific(),
306 error->IsSheetSpecific() ? error->GetSpecificSheetPath().PathRef() : KIID_PATH(),
307 error->MainItemHasSheetPath(), error->AuxItemHasSheetPath(), error->GetIDs().size(),
308 marker->IsExcluded(), marker->GetComment() );
309 }
310
311 if( !backend )
312 legacy = actual;
313
314 BOOST_CHECK_EQUAL( actual.size(), 1 );
315 BOOST_CHECK( actual == legacy );
316
317 for( SCH_ITEM* marker : markers )
318 root.LastScreen()->DeleteItem( marker );
319 }
320 }
321}
322
323
324BOOST_AUTO_TEST_CASE( ERCSimulationModelsBindAffectedSharedInstances )
325{
326 LOCALE_IO locale;
327 auto& enabled = const_cast<ADVANCED_CFG&>( ADVANCED_CFG::GetCfg() ).m_ConnectivityEngine;
328 SCOPED_SET_RESET restore( enabled, enabled );
329 SETTINGS_MANAGER settings;
330 std::unique_ptr<SCHEMATIC> schematic;
331 KI_TEST::LoadSchematic( settings, "legacy_hierarchy/legacy_hierarchy", schematic );
332 schematic->ErcSettings().SetSeverity( ERCE_SIMULATION_MODEL, RPT_SEVERITY_WARNING );
333 const auto refresh = [&]
334 {
335 schematic->RebuildConnectivity();
336
337 if( enabled )
338 schematic->Connectivity().PrepareSimulationModels( *schematic );
339 };
340 std::vector<SCH_SHEET_PATH> paths;
341
342 for( const SCH_SHEET_PATH& path : schematic->Hierarchy() )
343 {
344 if( path.LastScreen()->GetFileName().EndsWith( "ampli_ht.kicad_sch" ) )
345 paths.push_back( path );
346 }
347
348 BOOST_REQUIRE_EQUAL( paths.size(), 2 );
349 BOOST_REQUIRE( paths[0].LastScreen() == paths[1].LastScreen() );
350 paths[0].SetPageNumber( wxS( "2" ) );
351 paths[1].SetPageNumber( wxS( "3" ) );
352 SCH_SYMBOL* symbol = nullptr;
353
354 for( SCH_ITEM* item : paths[0].LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
355 {
356 auto* candidate = static_cast<SCH_SYMBOL*>( item );
357
358 if( candidate->GetRef( &paths[0] ).StartsWith( wxS( "D" ) ) )
359 {
360 symbol = candidate;
361 break;
362 }
363 }
364
365 BOOST_REQUIRE( symbol );
366 const wxString library = wxFileName( wxString::FromUTF8( KI_TEST::GetEeschemaTestDataDir() )
367 + wxS( "spice_netlists/rectifier/diode.lib" ) ).GetFullPath();
368
369 for( const auto& [name, value] : std::vector<std::pair<wxString, wxString>>{
370 { wxS( "Sim.Device" ), wxS( "D" ) }, { wxS( "Sim.Library" ), library },
371 { wxS( "Sim.Name" ), wxS( "DIODE1" ) }, { wxS( "Sim.Pins" ), wxS( "1=K 2=A" ) } } )
372 {
373 if( !symbol->GetField( name ) )
374 symbol->AddField( SCH_FIELD( symbol, FIELD_T::USER, name ) );
375
376 symbol->GetField( name )->SetText( value );
377 }
378
379 for( bool backend : { false, true } )
380 {
381 enabled = backend;
382 std::map<KIID_PATH, int> validCounts;
383
384 for( const wxString& name : { wxString( "DIODE1" ), wxString( "MISSING_NATIVE_MODEL" ),
385 wxString( "DIODE${#}" ) } )
386 {
387 symbol->GetField( wxS( "Sim.Name" ) )->SetText( name );
388 refresh();
389
390 for( const SCH_SHEET_PATH& displayed : paths )
391 {
392 schematic->SetCurrentSheet( displayed );
393 ERC_TESTER tester( schematic.get() );
394 const int reported = tester.TestSimModelIssues();
395 std::set<KIID_PATH> affected;
396 size_t count = 0;
397 std::vector<SCH_MARKER*> markers;
398
399 for( SCH_ITEM* item : paths[0].LastScreen()->Items().OfType( SCH_MARKER_T ) )
400 {
401 auto* marker = static_cast<SCH_MARKER*>( item );
402 markers.push_back( marker );
403 auto error = std::static_pointer_cast<ERC_ITEM>( marker->GetRCItem() );
404
405 if( error->GetErrorCode() != ERCE_SIMULATION_MODEL || error->GetMainItemID() != symbol->m_Uuid )
406 continue;
407
408 ++count;
409 BOOST_CHECK( error->IsSheetSpecific() );
410 BOOST_CHECK( error->MainItemHasSheetPath() );
411 BOOST_CHECK( !error->AuxItemHasSheetPath() );
412 BOOST_CHECK( marker->GetPosition() == symbol->GetPosition() );
413
414 if( error->IsSheetSpecific() && error->MainItemHasSheetPath() )
415 {
416 BOOST_CHECK( error->GetSpecificSheetPath() == error->GetMainItemSheetPath() );
417 BOOST_CHECK( affected.insert( error->GetSpecificSheetPath().PathRef() ).second );
418 }
419 }
420
421 const size_t expected = name == wxS( "DIODE1" ) ? 0 : name == wxS( "DIODE${#}" ) ? 1 : 2;
422 BOOST_CHECK_EQUAL( count, expected );
423 BOOST_CHECK_EQUAL( affected.size(), expected );
424
425 if( expected == 2 )
426 BOOST_CHECK( ( affected == std::set<KIID_PATH>{ paths[0].PathRef(), paths[1].PathRef() } ) );
427
428 if( name == wxS( "DIODE1" ) )
429 validCounts[displayed.PathRef()] = reported;
430 else
431 BOOST_CHECK_EQUAL( reported - validCounts.at( displayed.PathRef() ), expected );
432
433 if( name == wxS( "DIODE${#}" ) )
434 BOOST_CHECK( affected.contains( paths[1].PathRef() ) );
435
436 for( SCH_MARKER* marker : markers )
437 paths[0].LastScreen()->DeleteItem( marker );
438 }
439 }
440 }
441}
442
443
444BOOST_AUTO_TEST_CASE( ERCDuplicateSheetsBindSharedParentInstances )
445{
446 LOCALE_IO locale;
447 auto& enabled = const_cast<ADVANCED_CFG&>( ADVANCED_CFG::GetCfg() ).m_ConnectivityEngine;
448 SCOPED_SET_RESET restore( enabled, enabled );
449 SETTINGS_MANAGER settings;
450 std::unique_ptr<SCHEMATIC> schematic;
451 KI_TEST::LoadSchematic( settings, "issue25112/issue25112", schematic );
452 schematic->ErcSettings().SetSeverity( ERCE_DUPLICATE_SHEET_NAME, RPT_SEVERITY_ERROR );
453 std::vector<SCH_SHEET_PATH> parents;
454
455 for( const SCH_SHEET_PATH& path : schematic->Hierarchy() )
456 {
457 if( wxFileName( path.LastScreen()->GetFileName() ).GetFullName() == wxS( "level1.kicad_sch" ) )
458 parents.push_back( path );
459 }
460
461 BOOST_REQUIRE_EQUAL( parents.size(), 2 );
462 BOOST_REQUIRE( parents[0].LastScreen() == parents[1].LastScreen() );
463 SCH_SCREEN* screen = parents[0].LastScreen();
464 std::vector<SCH_SHEET*> children;
465
466 for( SCH_ITEM* item : screen->Items().OfType( SCH_SHEET_T ) )
467 children.push_back( static_cast<SCH_SHEET*>( item ) );
468
469 BOOST_REQUIRE_EQUAL( children.size(), 2 );
470 const std::set<KIID_PATH> expectedPaths{ parents[0].PathRef(), parents[1].PathRef() };
471 const auto checkReport = [&]( size_t expected )
472 {
473 ERC_REPORT report( schematic.get(), EDA_UNITS::MM );
474 wxString text = report.GetTextReport();
475 BOOST_CHECK( text.Contains( children[0]->GetName() ) );
476 const wxString message = ERC_ITEM::Create( ERCE_DUPLICATE_SHEET_NAME )->GetErrorMessage( true );
477 BOOST_CHECK_EQUAL( text.Replace( message, wxEmptyString ), expected );
478 };
479
480 for( bool backend : { false, true } )
481 {
482 enabled = backend;
483 children[0]->SetName( wxS( "DuplicateChild" ) );
484 children[1]->SetName( wxS( "DistinctChild" ) );
485 schematic->RebuildConnectivity();
486 ERC_TESTER valid( schematic.get() );
487 BOOST_CHECK_EQUAL( valid.TestDuplicateSheetNames( false ), 0 );
488 BOOST_CHECK_EQUAL( valid.TestDuplicateSheetNames( true ), 0 );
489 auto initialMarkers = screen->Items().OfType( SCH_MARKER_T );
490 BOOST_CHECK( initialMarkers.begin() == initialMarkers.end() );
491 children[1]->SetName( wxS( "duplicatechild" ) );
492
493 // Export and highlight preflight checks run before connectivity refresh
494 ERC_TESTER preflight( schematic.get() );
495 BOOST_CHECK_EQUAL( preflight.TestDuplicateSheetNames( false ), 2 );
496 auto preflightMarkers = screen->Items().OfType( SCH_MARKER_T );
497 BOOST_CHECK( preflightMarkers.begin() == preflightMarkers.end() );
498 schematic->RebuildConnectivity();
499
500 for( const SCH_SHEET_PATH& displayed : parents )
501 {
502 schematic->SetCurrentSheet( displayed );
503 ERC_TESTER tester( schematic.get() );
504 BOOST_CHECK_EQUAL( tester.TestDuplicateSheetNames( true ), 2 );
505 std::set<KIID_PATH> actualPaths;
506 std::vector<SCH_MARKER*> markers;
507
508 for( SCH_ITEM* item : screen->Items().OfType( SCH_MARKER_T ) )
509 {
510 auto* marker = static_cast<SCH_MARKER*>( item );
511 markers.push_back( marker );
512 const auto error = std::static_pointer_cast<ERC_ITEM>( marker->GetRCItem() );
513 BOOST_CHECK_EQUAL( error->GetErrorCode(), ERCE_DUPLICATE_SHEET_NAME );
514 BOOST_CHECK( error->GetMainItemID() == children[0]->m_Uuid );
515 BOOST_CHECK( error->GetAuxItemID() == children[1]->m_Uuid );
516 BOOST_CHECK( error->IsSheetSpecific() );
517 BOOST_CHECK( error->MainItemHasSheetPath() );
518 BOOST_CHECK( error->AuxItemHasSheetPath() );
519 BOOST_CHECK( marker->GetPosition() == children[0]->GetPosition() );
520
521 if( error->IsSheetSpecific() && error->MainItemHasSheetPath() && error->AuxItemHasSheetPath() )
522 {
523 BOOST_CHECK( error->GetSpecificSheetPath() == error->GetMainItemSheetPath() );
524 BOOST_CHECK( error->GetSpecificSheetPath() == error->GetAuxItemSheetPath() );
525 BOOST_CHECK( actualPaths.insert( error->GetSpecificSheetPath().PathRef() ).second );
526 }
527 }
528
529 BOOST_CHECK_EQUAL( markers.size(), 2 );
530 checkReport( 2 );
531 BOOST_CHECK( actualPaths == expectedPaths );
532 BOOST_CHECK( schematic->CurrentSheet() == displayed );
533
534 for( SCH_MARKER* marker : markers )
535 screen->DeleteItem( marker );
536 }
537
538 children[0]->SetName( wxS( "Child42" ) );
539 children[1]->SetName( wxS( "Child${#}" ) );
540
541 for( size_t i = 0; i < parents.size(); ++i )
542 {
543 SCH_SHEET_PATH childPath = parents[i];
544 childPath.push_back( children[1] );
545 childPath.SetPageNumber( i == 0 ? wxString( "42" ) : wxString( "43" ) );
546 BOOST_REQUIRE_EQUAL( children[1]->GetField( FIELD_T::SHEET_NAME )->GetShownText( &parents[i], RESOLVED ),
547 i == 0 ? wxString( "Child42" ) : wxString( "Child43" ) );
548 }
549
550 schematic->RebuildConnectivity();
551
552 for( const SCH_SHEET_PATH& displayed : parents )
553 {
554 schematic->SetCurrentSheet( displayed );
555 ERC_TESTER tester( schematic.get() );
556 BOOST_CHECK_EQUAL( tester.TestDuplicateSheetNames( false ), 1 );
557 BOOST_CHECK_EQUAL( tester.TestDuplicateSheetNames( true ), 1 );
558 std::vector<SCH_MARKER*> markers;
559
560 for( SCH_ITEM* item : screen->Items().OfType( SCH_MARKER_T ) )
561 {
562 auto* marker = static_cast<SCH_MARKER*>( item );
563 markers.push_back( marker );
564 const auto error = std::static_pointer_cast<ERC_ITEM>( marker->GetRCItem() );
565 BOOST_CHECK( marker->GetPosition() == children[0]->GetPosition() );
566 BOOST_CHECK( error->IsSheetSpecific() );
567
568 if( error->IsSheetSpecific() )
569 BOOST_CHECK( error->GetSpecificSheetPath().PathRef() == parents[0].PathRef() );
570 }
571
572 BOOST_CHECK_EQUAL( markers.size(), 1 );
573 checkReport( 1 );
574 BOOST_CHECK( schematic->CurrentSheet() == displayed );
575
576 for( SCH_MARKER* marker : markers )
577 screen->DeleteItem( marker );
578 }
579 }
580
581 children[0]->SetName( wxS( "DuplicateChild" ) );
582 children[1]->SetName( wxS( "duplicatechild" ) );
583 const auto targetMarkers = [&]
584 {
585 std::vector<SCH_MARKER*> result;
586
587 for( SCH_ITEM* item : screen->Items().OfType( SCH_MARKER_T ) )
588 {
589 auto* marker = static_cast<SCH_MARKER*>( item );
590
591 if( marker->GetRCItem()->GetErrorCode() == ERCE_DUPLICATE_SHEET_NAME
592 && marker->GetRCItem()->GetMainItemID() == children[0]->m_Uuid )
593 {
594 result.push_back( marker );
595 }
596 }
597
598 return result;
599 };
600 auto& exclusions = schematic->ErcSettings().m_ErcExclusions;
601
602 for( const SCH_SHEET_PATH& target : parents )
603 {
604 for( int format : { 0, 1, 2, 3, 4 } )
605 {
606 const bool pathless = format != 0;
607 const bool mixed = format == 2;
608 const bool legacyString = format >= 3;
609 exclusions.clear();
610 schematic->ErcSettings().m_ErcExclusionsLegacy.clear();
611 enabled = false;
612 schematic->RebuildConnectivity();
613 ERC_TESTER tester( schematic.get() );
614 tester.TestDuplicateSheetNames( true );
615 BOOST_REQUIRE_EQUAL( targetMarkers().size(), 2 );
616
617 for( SCH_MARKER* marker : targetMarkers() )
618 {
619 const auto error = std::static_pointer_cast<ERC_ITEM>( marker->GetRCItem() );
620 BOOST_REQUIRE( error->IsSheetSpecific() );
621
622 if( error->GetSpecificSheetPath().PathRef() != target.PathRef() )
623 continue;
624
625 auto proto = ERC_EXCLUSION::FromMarker( *marker ).ToProto();
626
627 if( mixed )
628 {
629 auto scoped = ERC_EXCLUSION::FromProto( proto );
630 scoped.SetComment( wxS( "Scoped duplicate-sheet exclusion" ) );
631 const nlohmann::json saved = scoped;
632 exclusions.insert( saved.get<ERC_EXCLUSION>() );
633 }
634
635 if( pathless )
636 {
637 proto.mutable_marker()->clear_sheet_specific_path();
638 proto.mutable_marker()->clear_main_item_sheet_path();
639 proto.mutable_marker()->clear_aux_item_sheet_path();
640 }
641
642 auto exclusion = ERC_EXCLUSION::FromProto( proto );
643 exclusion.SetComment( wxS( "Retained duplicate-sheet exclusion" ) );
644 if( legacyString )
645 {
646 wxString data = wxString::Format( wxS( "duplicate_sheet_names|%d|%d|%s|%s" ),
647 children[0]->GetPosition().x, children[0]->GetPosition().y,
648 children[0]->m_Uuid.AsString(), children[1]->m_Uuid.AsString() );
649
650 if( format == 3 )
651 data += wxS( "|||" );
652
653 BOOST_CHECK( ERC_EXCLUSION::FromLegacyStrings( schematic->Hierarchy(), data,
654 exclusion.GetComment() ) == exclusion );
655 schematic->ErcSettings().m_ErcExclusionsLegacy.emplace( data, exclusion.GetComment() );
656 }
657 else
658 {
659 const nlohmann::json saved = exclusion;
660 exclusions.insert( saved.get<ERC_EXCLUSION>() );
661 }
662 }
663
664 BOOST_REQUIRE_EQUAL( exclusions.size(), legacyString ? 0 : mixed ? 2 : 1 );
665 const auto savedExclusions = exclusions;
666 const auto savedLegacy = schematic->ErcSettings().m_ErcExclusionsLegacy;
667
668 for( SCH_MARKER* marker : targetMarkers() )
669 screen->DeleteItem( marker );
670
671 for( bool backend : { true, false } )
672 {
673 exclusions = savedExclusions;
674 schematic->ErcSettings().m_ErcExclusionsLegacy = savedLegacy;
675 enabled = backend;
676 schematic->RebuildConnectivity();
677 ERC_TESTER rescan( schematic.get() );
678 rescan.TestDuplicateSheetNames( true );
679 schematic->ResolveERCExclusionsPostUpdate();
680 BOOST_CHECK_EQUAL( targetMarkers().size(), 2 );
681 size_t excluded = 0;
682
683 for( SCH_MARKER* marker : targetMarkers() )
684 {
685 const auto error = std::static_pointer_cast<ERC_ITEM>( marker->GetRCItem() );
686 BOOST_CHECK( error->IsSheetSpecific() );
687 BOOST_CHECK( error->MainItemHasSheetPath() );
688 BOOST_CHECK( error->AuxItemHasSheetPath() );
689
690 if( error->IsSheetSpecific() && error->MainItemHasSheetPath() && error->AuxItemHasSheetPath() )
691 {
692 BOOST_CHECK( error->GetMainItemSheetPath() == error->GetSpecificSheetPath() );
693 BOOST_CHECK( error->GetAuxItemSheetPath() == error->GetSpecificSheetPath() );
694 const bool expected = pathless || error->GetSpecificSheetPath() == target;
695 BOOST_CHECK_EQUAL( marker->IsExcluded(), expected );
696 const wxString comment = mixed && error->GetSpecificSheetPath() == target
697 ? wxString( "Scoped duplicate-sheet exclusion" )
698 : expected ? wxString( "Retained duplicate-sheet exclusion" ) : wxString();
699 BOOST_CHECK_EQUAL( marker->GetComment(), comment );
700 }
701
702 excluded += marker->IsExcluded();
703 }
704
705 BOOST_CHECK_EQUAL( excluded, pathless ? 2 : 1 );
706
707 for( SCH_MARKER* marker : targetMarkers() )
708 screen->DeleteItem( marker );
709 }
710 }
711 }
712}
int index
const char * name
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
const KIID m_Uuid
Definition eda_item.h:597
virtual void SetText(const wxString &aText)
Definition eda_text.cpp:231
EE_TYPE OfType(KICAD_T aType) const
Definition sch_rtree.h:248
Container for an ERC exclusion, which is a SCH_MARKER plus an optional comment.
static ERC_EXCLUSION FromLegacyStrings(const SCH_SHEET_LIST &aSheetList, const wxString &aMarkerData, const wxString &aComment)
const kiapi::schematic::ErcExclusion & ToProto() const
static ERC_EXCLUSION FromMarker(const SCH_MARKER &aMarker)
static ERC_EXCLUSION FromProto(const kiapi::schematic::ErcExclusion &aMessage)
static std::shared_ptr< ERC_ITEM > Create(int aErrorCode)
Constructs an ERC_ITEM for the given error code.
Definition erc_item.cpp:309
wxString GetTextReport()
Returns the ERC report in "text" (human readable) format in the C-locale.
Runs the electrical rules checks and adds a SCH_MARKER for each violation.
Definition erc.h:60
static int TestConnectivity(SCHEMATIC &aSchematic)
Definition erc.cpp:2215
int TestDuplicateSheetNames(bool aCreateMarker)
Inside a given sheet, one cannot have sheets with duplicate names (file names can be duplicated).
Definition erc.cpp:350
int TestSimModelIssues()
Test SPICE models for various issues.
Definition erc.cpp:3070
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
Definition locale_io.h:37
virtual wxString GetErrorMessage(bool aTranslate) const
Definition rc_item.cpp:37
void SetText(const wxString &aText) override
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:170
SCH_ITEM * Duplicate(bool addToParentGroup, SCH_COMMIT *aCommit=nullptr, bool doClone=false) const
Routine to create a new copy of given item.
Definition sch_item.cpp:186
void Append(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
EE_RTREE & Items()
Get the full RTree, usually for iterating.
Definition sch_screen.h:122
void DeleteItem(SCH_ITEM *aItem)
Remove aItem from the linked list and deletes the object.
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
SCH_SCREEN * LastScreen()
void SetPageNumber(const wxString &aPageNumber)
Set the sheet instance user definable page number.
void push_back(SCH_SHEET *aSheet)
Forwarded method from std::vector.
Define a sheet pin (label) used in sheets to create hierarchical schematics.
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition sch_sheet.h:48
Schematic symbol object.
Definition sch_symbol.h:74
VECTOR2I GetPosition() const override
Definition sch_symbol.h:896
SCH_FIELD * AddField(const SCH_FIELD &aField)
Add a field to the symbol.
SCH_FIELD * GetField(FIELD_T aFieldType)
Return a mandatory field in this symbol.
RAII class that sets an value at construction and resets it to the original value at destruction.
@ RESOLVED
Definition common.h:93
@ ERCE_PIN_NOT_CONNECTED
Pin not connected and not no connect symbol.
@ ERCE_SIMULATION_MODEL
An error was found in the simulation model.
@ ERCE_DUPLICATE_SHEET_NAME
Duplicate sheet names within a given sheet.
@ ERCE_HIERACHICAL_LABEL
Mismatch between hierarchical labels and pins sheets.
void LoadSchematic(SETTINGS_MANAGER &aSettingsManager, const wxString &aRelPath, std::unique_ptr< SCHEMATIC > &aSchematic)
std::string GetEeschemaTestDataDir()
Get the configured location of Eeschema test data.
@ RPT_SEVERITY_WARNING
@ RPT_SEVERITY_ERROR
@ RPT_SEVERITY_IGNORE
@ USER
The field ID hasn't been set yet; field is invalid.
BOOST_AUTO_TEST_CASE(ERCHierarchyMismatchesUseCapturedConnectivity)
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
std::string path
KIBIS_PIN * pin
VECTOR3I expected(15, 30, 45)
BOOST_TEST_CONTEXT("Test Clearance")
int actual
wxString result
Test unit parsing edge cases and error handling.
BOOST_CHECK_EQUAL(result, "25.4")
@ SCH_SYMBOL_T
Definition typeinfo.h:168
@ SCH_SHEET_T
Definition typeinfo.h:171
@ SCH_MARKER_T
Definition typeinfo.h:154
@ SCH_HIER_LABEL_T
Definition typeinfo.h:165
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683