53 std::unique_ptr<SCHEMATIC> schematic;
59 if(
path.size() > schematic->Hierarchy().front().size() )
63 if( labels.begin() != labels.end() )
69 renamed->
SetText(
"ERC_UNMATCHED_PORT" );
71 for(
auto& [code, severity] : schematic->ErcSettings().m_ERCSeverities )
74 using DIAGNOSTICS = std::map<std::pair<KIID_PATH, KIID>,
VECTOR2I>;
75 const auto collect = [&]()
83 auto* marker =
static_cast<SCH_MARKER*
>( item );
84 const auto error = std::static_pointer_cast<ERC_ITEM>( marker->GetRCItem() );
86 BOOST_CHECK( error->MainItemHasSheetPath() );
87 BOOST_CHECK( !error->AuxItemHasSheetPath() );
88 result.emplace( std::pair{ error->GetSpecificSheetPath().PathRef(), error->GetMainItemID() },
89 marker->GetPosition() );
95 schematic->RebuildConnectivity();
96 BOOST_REQUIRE_EQUAL( schematic->ConnectionGraph()->RunERC(), 2 );
98 BOOST_REQUIRE_EQUAL(
expected.size(), 2 );
100 const auto clearMarkers = [&]()
104 std::vector<SCH_ITEM*> markers;
107 markers.push_back( item );
110 path.LastScreen()->DeleteItem( marker );
116 schematic->RebuildConnectivity();
117 schematic->ConnectionGraph()->Reset();
119 BOOST_CHECK( collect() ==
expected );
129 std::unique_ptr<SCHEMATIC> schematic;
146 const VECTOR2I position( 100000000 +
index * 1000000, 100000000 );
147 label->SetText(
"ERC_ROOT_PORT" );
148 label->Move( position - label->GetPosition() );
155 for(
auto& [code, severity] : schematic->ErcSettings().m_ERCSeverities )
158 schematic->RebuildConnectivity();
159 schematic->ConnectionGraph()->RunERC();
160 std::vector<SCH_ITEM*> legacyMarkers;
164 auto* marker =
static_cast<SCH_MARKER*
>( item );
165 legacyMarkers.push_back( marker );
167 if(
expected.contains( marker->GetRCItem()->GetMainItemID() ) )
168 marker->SetExcluded(
true,
"Retained root port" );
171 schematic->RecordERCExclusions();
172 BOOST_REQUIRE_EQUAL( schematic->ErcSettings().m_ErcExclusions.size(), 2 );
174 for(
SCH_ITEM* marker : legacyMarkers )
177 using SIGNATURE = std::tuple<KIID, int, bool, KIID_PATH, bool, size_t, int, int, bool, wxString>;
179 for(
bool pinEnabled : {
false,
true } )
181 for(
auto& [code, severity] : schematic->ErcSettings().m_ERCSeverities )
187 std::multiset<SIGNATURE> legacy;
189 for(
bool backend : {
false,
true } )
194 schematic->RebuildConnectivity();
195 schematic->ConnectionGraph()->RunERC();
198 schematic->ResolveERCExclusionsPostUpdate();
200 std::multiset<SIGNATURE>
actual;
201 size_t pinMarkers = 0;
202 std::vector<SCH_ITEM*> markers;
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() );
211 if( !
expected.contains( error->GetMainItemID() )
217 BOOST_CHECK( marker->IsExcluded() );
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() );
232 BOOST_CHECK(
actual == legacy );
247 std::unique_ptr<SCHEMATIC> schematic;
252 auto* sheet =
static_cast<SCH_SHEET*
>( *sheets.begin() );
255 sheet->Move(
VECTOR2I( 100000000, 100000000 ) );
257 for(
auto& [code, severity] : schematic->ErcSettings().m_ERCSeverities )
260 schematic->RebuildConnectivity();
261 schematic->ConnectionGraph()->RunERC();
262 std::vector<SCH_ITEM*> legacyMarkers;
266 auto* marker =
static_cast<SCH_MARKER*
>( item );
267 legacyMarkers.push_back( marker );
269 if( marker->GetRCItem()->GetMainItemID() ==
pin->m_Uuid )
270 marker->SetExcluded(
true,
"Retained sheet pin" );
273 schematic->RecordERCExclusions();
274 BOOST_REQUIRE_EQUAL( schematic->ErcSettings().m_ErcExclusions.size(), 1 );
276 for(
SCH_ITEM* marker : legacyMarkers )
279 using SIGNATURE = std::tuple<int, wxString, int, int, bool, KIID_PATH, bool, bool, size_t, bool, wxString>;
280 std::multiset<SIGNATURE> legacy;
282 for(
bool backend : {
false,
true } )
287 schematic->RebuildConnectivity();
288 schematic->ConnectionGraph()->RunERC();
289 schematic->ResolveERCExclusionsPostUpdate();
290 std::multiset<SIGNATURE>
actual;
291 std::vector<SCH_ITEM*> markers;
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() );
299 if( error->GetMainItemID() !=
pin->m_Uuid )
302 BOOST_CHECK( marker->IsExcluded() );
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() );
315 BOOST_CHECK(
actual == legacy );
330 std::unique_ptr<SCHEMATIC> schematic;
335 schematic->RebuildConnectivity();
338 schematic->Connectivity().PrepareSimulationModels( *schematic );
340 std::vector<SCH_SHEET_PATH> paths;
344 if(
path.LastScreen()->GetFileName().EndsWith(
"ampli_ht.kicad_sch" ) )
345 paths.push_back(
path );
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" ) );
356 auto* candidate =
static_cast<SCH_SYMBOL*
>( item );
358 if( candidate->GetRef( &paths[0] ).StartsWith( wxS(
"D" ) ) )
367 + wxS(
"spice_netlists/rectifier/diode.lib" ) ).GetFullPath();
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" ) } } )
379 for(
bool backend : {
false,
true } )
382 std::map<KIID_PATH, int> validCounts;
384 for(
const wxString&
name : { wxString(
"DIODE1" ), wxString(
"MISSING_NATIVE_MODEL" ),
385 wxString(
"DIODE${#}" ) } )
392 schematic->SetCurrentSheet( displayed );
395 std::set<KIID_PATH> affected;
397 std::vector<SCH_MARKER*> markers;
401 auto* marker =
static_cast<SCH_MARKER*
>( item );
402 markers.push_back( marker );
403 auto error = std::static_pointer_cast<ERC_ITEM>( marker->GetRCItem() );
409 BOOST_CHECK( error->IsSheetSpecific() );
410 BOOST_CHECK( error->MainItemHasSheetPath() );
411 BOOST_CHECK( !error->AuxItemHasSheetPath() );
412 BOOST_CHECK( marker->GetPosition() == symbol->
GetPosition() );
414 if( error->IsSheetSpecific() && error->MainItemHasSheetPath() )
416 BOOST_CHECK( error->GetSpecificSheetPath() == error->GetMainItemSheetPath() );
417 BOOST_CHECK( affected.insert( error->GetSpecificSheetPath().PathRef() ).second );
421 const size_t expected =
name == wxS(
"DIODE1" ) ? 0 :
name == wxS(
"DIODE${#}" ) ? 1 : 2;
426 BOOST_CHECK( ( affected == std::set<KIID_PATH>{ paths[0].PathRef(), paths[1].PathRef() } ) );
428 if(
name == wxS(
"DIODE1" ) )
429 validCounts[displayed.PathRef()] = reported;
433 if(
name == wxS(
"DIODE${#}" ) )
434 BOOST_CHECK( affected.contains( paths[1].PathRef() ) );
437 paths[0].LastScreen()->DeleteItem( marker );
450 std::unique_ptr<SCHEMATIC> schematic;
453 std::vector<SCH_SHEET_PATH> parents;
457 if( wxFileName(
path.LastScreen()->GetFileName() ).GetFullName() == wxS(
"level1.kicad_sch" ) )
458 parents.push_back(
path );
461 BOOST_REQUIRE_EQUAL( parents.size(), 2 );
462 BOOST_REQUIRE( parents[0].LastScreen() == parents[1].LastScreen() );
464 std::vector<SCH_SHEET*> children;
467 children.push_back(
static_cast<SCH_SHEET*
>( item ) );
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 )
475 BOOST_CHECK(
text.Contains( children[0]->GetName() ) );
480 for(
bool backend : {
false,
true } )
483 children[0]->SetName( wxS(
"DuplicateChild" ) );
484 children[1]->SetName( wxS(
"DistinctChild" ) );
485 schematic->RebuildConnectivity();
490 BOOST_CHECK( initialMarkers.begin() == initialMarkers.end() );
491 children[1]->SetName( wxS(
"duplicatechild" ) );
497 BOOST_CHECK( preflightMarkers.begin() == preflightMarkers.end() );
498 schematic->RebuildConnectivity();
502 schematic->SetCurrentSheet( displayed );
505 std::set<KIID_PATH> actualPaths;
506 std::vector<SCH_MARKER*> markers;
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() );
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() );
521 if( error->IsSheetSpecific() && error->MainItemHasSheetPath() && error->AuxItemHasSheetPath() )
523 BOOST_CHECK( error->GetSpecificSheetPath() == error->GetMainItemSheetPath() );
524 BOOST_CHECK( error->GetSpecificSheetPath() == error->GetAuxItemSheetPath() );
525 BOOST_CHECK( actualPaths.insert( error->GetSpecificSheetPath().PathRef() ).second );
531 BOOST_CHECK( actualPaths == expectedPaths );
532 BOOST_CHECK( schematic->CurrentSheet() == displayed );
538 children[0]->SetName( wxS(
"Child42" ) );
539 children[1]->SetName( wxS(
"Child${#}" ) );
541 for(
size_t i = 0; i < parents.size(); ++i )
545 childPath.
SetPageNumber( i == 0 ? wxString(
"42" ) : wxString(
"43" ) );
547 i == 0 ? wxString(
"Child42" ) : wxString(
"Child43" ) );
550 schematic->RebuildConnectivity();
554 schematic->SetCurrentSheet( displayed );
558 std::vector<SCH_MARKER*> markers;
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() );
568 if( error->IsSheetSpecific() )
569 BOOST_CHECK( error->GetSpecificSheetPath().PathRef() == parents[0].PathRef() );
574 BOOST_CHECK( schematic->CurrentSheet() == displayed );
581 children[0]->SetName( wxS(
"DuplicateChild" ) );
582 children[1]->SetName( wxS(
"duplicatechild" ) );
583 const auto targetMarkers = [&]
585 std::vector<SCH_MARKER*>
result;
589 auto* marker =
static_cast<SCH_MARKER*
>( item );
592 && marker->GetRCItem()->GetMainItemID() == children[0]->m_Uuid )
594 result.push_back( marker );
600 auto& exclusions = schematic->ErcSettings().m_ErcExclusions;
604 for(
int format : { 0, 1, 2, 3, 4 } )
606 const bool pathless = format != 0;
607 const bool mixed = format == 2;
608 const bool legacyString = format >= 3;
610 schematic->ErcSettings().m_ErcExclusionsLegacy.clear();
612 schematic->RebuildConnectivity();
615 BOOST_REQUIRE_EQUAL( targetMarkers().size(), 2 );
619 const auto error = std::static_pointer_cast<ERC_ITEM>( marker->GetRCItem() );
622 if( error->GetSpecificSheetPath().PathRef() != target.PathRef() )
630 scoped.SetComment( wxS(
"Scoped duplicate-sheet exclusion" ) );
631 const nlohmann::json saved = scoped;
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();
643 exclusion.SetComment( wxS(
"Retained duplicate-sheet exclusion" ) );
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() );
651 data += wxS(
"|||" );
654 exclusion.GetComment() ) == exclusion );
655 schematic->ErcSettings().m_ErcExclusionsLegacy.emplace( data, exclusion.GetComment() );
659 const nlohmann::json saved = exclusion;
664 BOOST_REQUIRE_EQUAL( exclusions.size(), legacyString ? 0 : mixed ? 2 : 1 );
665 const auto savedExclusions = exclusions;
666 const auto savedLegacy = schematic->ErcSettings().m_ErcExclusionsLegacy;
671 for(
bool backend : {
true,
false } )
673 exclusions = savedExclusions;
674 schematic->ErcSettings().m_ErcExclusionsLegacy = savedLegacy;
676 schematic->RebuildConnectivity();
679 schematic->ResolveERCExclusionsPostUpdate();
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() );
690 if( error->IsSheetSpecific() && error->MainItemHasSheetPath() && error->AuxItemHasSheetPath() )
692 BOOST_CHECK( error->GetMainItemSheetPath() == error->GetSpecificSheetPath() );
693 BOOST_CHECK( error->GetAuxItemSheetPath() == error->GetSpecificSheetPath() );
694 const bool expected = pathless || error->GetSpecificSheetPath() == target;
696 const wxString comment = mixed && error->GetSpecificSheetPath() == target
697 ? wxString(
"Scoped duplicate-sheet exclusion" )
698 :
expected ? wxString(
"Retained duplicate-sheet exclusion" ) : wxString();
702 excluded += marker->IsExcluded();