21#include <boost/test/data/test_case.hpp>
52const char*
const ORACLE_FIXTURES[] = {
53 "incremental_test",
"issue10430",
"issue10926_1",
"issue11926",
"issue12505",
"issue12814",
54 "issue13112",
"issue13162",
"issue13212",
"issue13431",
"issue13591",
"issue16223",
"issue6588",
"issue9367"
57const char*
const PARITY_FIXTURES[] = {
58 "incremental_test",
"issue10430",
"issue10926_1",
"issue11926",
"issue12505",
"issue12814",
59 "issue13112",
"issue13162",
"issue13212",
"issue13431",
"issue13591",
"issue16223",
"issue6588",
"issue9367",
60 "issue18346",
"unconnected_bus_entry_qa",
"netlist_exporter_unit_metadata_per_unit",
61 "netlists/multinetclasses/multinetclasses",
"issue22286/bugtest",
"issue7203",
"netlists/jumpers/jumpers",
62 "issue23058/issue23058",
"netlists/bus_junctions/bus_junctions",
63 "netlists/prefix_bus_alias/prefix_bus_alias",
64 "issue9673/issue9673",
"erc_directive_label_not_connected",
"netlists/legacy_power/legacy_power",
65 "same_local_global_power",
"issue1768/issue1768",
"issue18092/issue18092",
"issue22864/Test_Move_Grid",
66 "issue23840/BusAndVectors"
70void EraseDrivers( nlohmann::json& aValue )
72 if( aValue.is_object() )
74 aValue.erase(
"driver" );
75 aValue.erase(
"driver_path" );
78 if( aValue.is_structured() )
80 for(
auto& child : aValue )
81 EraseDrivers( child );
99 auto& facade = schematic->Connectivity();
100 facade.Update( *schematic );
103 auto classes = schematic->Project().GetProjectFile().NetSettings();
104 classes->SetNetclassLabelAssignment(
"/NET_1", {
"CORRUPTED" } );
105 classes->ClearCacheForNet(
"/NET_1" );
113 LegacyAndEngineDumpsMatch,
114 boost::unit_test::data::make( PARITY_FIXTURES ), fixture )
122 auto& facade = schematic->Connectivity();
123 facade.Update( *schematic );
126 EraseDrivers( legacy );
127 EraseDrivers( engine );
128 BOOST_CHECK_MESSAGE( legacy == engine, nlohmann::json::diff( legacy, engine ).
dump( 2 ) );
135 using KEY = std::pair<std::string, std::string>;
137 auto& facade = schematic->Connectivity();
138 facade.Update( *schematic );
139 const auto& keys = facade.Keys();
142 std::map<KEY, std::set<KEY>> legacyBuses;
143 std::map<int, std::set<KEY>> legacyNets;
144 std::map<KEY, const nlohmann::json*> shadowRows;
146 for(
const auto& row : shadow )
147 shadowRows.emplace( KEY{ row.at(
"path" ), row.at(
"item" ) }, &row );
149 for(
const auto& row : legacy )
151 const KEY key{ row.at(
"path" ), row.at(
"item" ) };
152 const auto path = schematic->Hierarchy().GetSheetPathByKIIDPath(
153 KIID_PATH( wxString::FromUTF8( key.first ) ) );
155 const auto* item =
path->LastScreen()->GetConnectivityItem(
KIID( key.second ) );
157 const auto* connection = item->Connection( &*
path );
159 if( !connection || !connection->Driver() )
162 if( connection->IsBus() )
163 legacyBuses[KEY{ row.at(
"driver_path" ), row.at(
"driver" ) }].insert( key );
164 else if( connection->IsNet() )
166 BOOST_REQUIRE_GT( connection->NetCode(), 0 );
167 legacyNets[connection->NetCode()].insert( key );
168 const auto after = shadowRows.find( key );
170 BOOST_CHECK( row.at(
"name" ) == after->second->at(
"name" ) );
171 BOOST_CHECK( row.at(
"type" ) == after->second->at(
"type" ) );
175 const auto itemKeys = [&](
const auto& items )
180 result.emplace( keys.Instance( item.inst ).AsString().ToStdString(),
181 item.item.AsString().ToStdString() );
185 const auto checkFields = [](
const auto& before,
const auto& after )
187 for(
const char* field : {
"name",
"local_name",
"type",
"netclasses" } )
188 BOOST_CHECK_MESSAGE( before.at( field ) == after.at( field ), field );
190 const auto checkMembers = [&](
const auto& self,
const auto& before,
const auto& after ) ->
void
192 BOOST_REQUIRE_EQUAL( before.size(), after.size() );
194 for(
size_t i = 0; i < before.size(); ++i )
196 checkFields( before[i], after[i] );
197 self( self, before[i].at(
"members" ), after[i].at(
"members" ) );
201 for(
const char*
name : {
"/{FOO BAR HAM EGGS}",
"/{MIXED_BUS}",
"/A[0..4]",
"/D[0..7]" } )
203 const auto row = std::find_if( legacy.begin(), legacy.end(),
204 [&](
const auto& value ) { return value.at(
"name" ) == name; } );
206 const auto path = schematic->Hierarchy().GetSheetPathByKIIDPath(
207 KIID_PATH( wxString::FromUTF8( row->at(
"path" ).get<std::string>() ) ) );
209 const KIID itemId( row->at(
"item" ).get<std::string>() );
210 const auto instance = keys.FindInstance(
path->Path() );
214 const auto result = facade.Published().Rows().find(
ITEM_KEY{ itemId, *instance } );
216 const auto& component = facade.Published().Components().at(
result->second.component );
218 const auto actual = itemKeys( component.content->items );
219 const auto& expectedItems = legacyBuses.at( KEY{ row->at(
"driver_path" ), row->at(
"driver" ) } );
220 BOOST_CHECK_MESSAGE(
actual == expectedItems, nlohmann::json(
actual ).
dump()
221 <<
" expected " << nlohmann::json( expectedItems ).
dump() );
224 for(
const auto& before : legacy )
226 const KEY key{ before.at(
"path" ), before.at(
"item" ) };
228 if( !expectedItems.contains( key ) )
231 const auto after = shadowRows.find( key );
234 checkFields( before, *after->second );
235 checkMembers( checkMembers, before.at(
"members" ), after->second->at(
"members" ) );
240 for(
const auto& [code, items] : legacyNets )
242 const KEY& first = *items.begin();
243 const auto instance = keys.FindInstance(
KIID_PATH( wxString::FromUTF8( first.first ) ) );
247 const auto row = facade.Published().Rows().find(
ITEM_KEY{
KIID( first.second ), *instance } );
249 const auto& component = facade.Published().Components().at( row->second.component );
250 BOOST_CHECK( itemKeys( component.content->items ) == items );
254 BOOST_CHECK_GT( legacyNets.size(), 0u );
260 using KEY = std::pair<std::string, std::string>;
262 for(
const char* fixture : {
"netlists/hierarchy_aliases/hierarchy_aliases",
263 "netlists/multinetclasses/multinetclasses" } )
268 auto& facade = schematic->Connectivity();
269 facade.Update( *schematic );
270 const auto& keys = facade.Keys();
273 BOOST_REQUIRE_EQUAL( legacy.size(), shadow.size() );
275 for(
size_t i = 0; i < legacy.size(); ++i )
277 BOOST_REQUIRE( legacy[i].at(
"path" ) == shadow[i].at(
"path" ) );
278 BOOST_REQUIRE( legacy[i].at(
"item" ) == shadow[i].at(
"item" ) );
281 const auto paths = schematic->Hierarchy();
282 std::map<int, std::set<KEY>> nets;
283 std::map<int, std::string> names;
285 for(
const auto& row : legacy )
287 const KEY key{ row.at(
"path" ), row.at(
"item" ) };
288 const auto path = paths.GetSheetPathByKIIDPath(
KIID_PATH( wxString::FromUTF8( key.first ) ) );
290 const auto* item =
path->LastScreen()->GetConnectivityItem(
KIID( key.second ) );
292 const auto* connection = item->Connection( &*
path );
294 if( connection && connection->IsNet() && connection->Driver() )
296 BOOST_REQUIRE_GT( connection->NetCode(), 0 );
297 nets[connection->NetCode()].insert( key );
298 names[connection->NetCode()] = connection->Name().ToStdString( wxConvUTF8 );
302 for(
const auto& [code, items] : nets )
304 const auto& first = *items.begin();
305 const auto instance = keys.FindInstance(
KIID_PATH( wxString::FromUTF8( first.first ) ) );
307 const auto row = facade.Published().Rows().find(
ITEM_KEY{
KIID( first.second ), *instance } );
309 const auto& component = facade.Published().Components().at( row->second.component );
312 for(
const ITEM_KEY& item : component.content->items )
313 actual.emplace( keys.Instance( item.
inst ).AsString().ToStdString(),
316 BOOST_CHECK_MESSAGE(
actual == items,
"Net code " << code );
318 BOOST_CHECK_EQUAL( keys.Name( component.name ).ToStdString( wxConvUTF8 ), names.at( code ) );
329 for(
bool engine : {
false,
true } )
333 config.m_ConnectivityEngine = engine;
335 schematic->RebuildConnectivity();
336 SCH_SCREEN* screen = schematic->GetCurrentScreen();
337 const KIID junction(
"2934c2df-d750-4949-9bb5-2d5234f61386" );
338 auto* wire =
dynamic_cast<SCH_LINE*
>(
340 auto* upper =
dynamic_cast<SCH_LINE*
>(
342 auto* lower =
dynamic_cast<SCH_LINE*
>(
348 BOOST_REQUIRE( wire->IsEndPoint( position ) && upper->IsEndPoint( position )
349 && lower->IsEndPoint( position ) );
350 BOOST_REQUIRE_EQUAL( screen->
GetBusesAndWires( position,
false ).size(), 3u );
351 const std::set<int> directions{ wire->GetAngleFrom( position ), upper->GetAngleFrom( position ),
352 lower->GetAngleFrom( position ) };
353 BOOST_REQUIRE_EQUAL( directions.size(), 3u );
354 const VECTOR2I start = upper->GetStartPoint();
357 auto subscription = schematic->Connectivity().Subscribe(
364 manager.
SetEnvironment( schematic.get(),
nullptr,
nullptr,
nullptr,
nullptr );
366 schematic->CleanUp( &
move, screen );
370 move.Modify( wire, screen );
371 wire->Move(
VECTOR2I( 10000000, 10000000 ) );
373 BOOST_REQUIRE( upper->IsEndPoint( position ) && lower->IsEndPoint( position ) );
374 BOOST_REQUIRE_NE( upper->GetAngleFrom( position ), lower->GetAngleFrom( position ) );
375 BOOST_REQUIRE_EQUAL( screen->
GetBusesAndWires( position,
false ).size(), 2u );
385 if(
auto* line =
dynamic_cast<SCH_LINE*
>( item );
386 line && line->
IsEndPoint( start ) && line->IsEndPoint(
end ) )
391 const auto dump = [&]()
396 const std::string incremental =
dump();
397 schematic->RebuildConnectivity();
405 PreviouslyDisabledFixturesMatchFullAndFreshRebuildsAfterCommits,
406 boost::unit_test::data::make( ORACLE_FIXTURES ), fixture )
411 config.m_ConnectivityEngine =
true;
412 config.m_IncrementalConnectivity =
true;
416 manager.
SetEnvironment( schematic.get(),
nullptr,
nullptr,
nullptr,
nullptr );
420 schematic->RebuildConnectivity();
442 std::set<SCH_SCREEN*> seenScreens;
444 const auto isGeometry =
447 return item->IsConnectable()
453 std::vector<std::pair<SCH_SCREEN*, std::unique_ptr<SCH_ITEM>>> geometry;
457 if( !seenScreens.insert(
path.LastScreen() ).second )
462 if( isGeometry( item ) )
465 geometry.emplace_back(
path.LastScreen(),
static_cast<SCH_ITEM*
>( item->Clone() ) );
470 std::sort( geometry.begin(), geometry.end(),
471 [](
const auto& a,
const auto& b )
473 return a.second->m_Uuid < b.second->m_Uuid;
476 const VECTOR2I offset( 10000000, 10000000 );
478 rebuilt.
Update( *schematic,
true );
485 for(
SCH_ITEM* item : screen->Items() )
488 "Cleanup left a deleted item on the screen: "
489 << item->m_Uuid.AsString().ToStdString() );
494 rebuilt.
Update( *schematic,
true );
498 fresh.
Update( *schematic,
true );
500 std::map<int, int> toFresh;
501 std::map<int, int> fromFresh;
502 const auto& current = schematic->Connectivity();
504 for(
const auto& [key, row] : current.Published().Rows() )
506 const auto&
path = current.Keys().Instance( key.inst );
507 const auto actual = current.Connection( key.item,
path );
513 const auto forward = toFresh.emplace(
actual->NetCode(),
empty->NetCode() ).first;
514 const auto reverse = fromFresh.emplace(
empty->NetCode(),
actual->NetCode() ).first;
522 const auto restoreGeometry =
528 std::vector<SCH_ITEM*> removed;
529 std::vector<std::pair<SCH_SCREEN*, std::unique_ptr<SCH_ITEM>>> added;
533 for(
SCH_ITEM* item : screen->Items() )
535 if( isGeometry( item ) )
537 restore.
Remove( item, screen );
538 removed.push_back( item );
543 for(
const auto& [screen,
source] : geometry )
547 restore.
Add(
copy.get(), screen );
548 added.emplace_back( screen, std::move(
copy ) );
553 for(
auto& [screen, item] : added )
570 commit.
Modify( symbol, screen );
571 symbol->
Move( movement );
573 BOOST_CHECK( !schematic->Connectivity().Published().Changes().Empty() );
580 auto symbolReplacement = std::make_unique<SCH_SYMBOL>( *symbol );
582 removal.
Remove( symbol, symbolScreen );
590 addition.
Add( symbolReplacement.get(), symbolScreen );
593 symbolReplacement.release();
597 std::vector<SCH_LABEL_BASE*> labels;
601 for(
SCH_ITEM* item : screen->Items() )
608 std::sort( labels.begin(), labels.end(),
609 [](
const auto* a,
const auto* b )
611 return a->m_Uuid < b->m_Uuid;
616 const wxString originalText = label->GetText();
618 for(
const wxString&
text : { wxString(
"ORACLE_" ) + originalText, originalText } )
621 rename.
Modify( label, label->GetParentScreen() );
622 label->SetText(
text );
628 for(
const auto& [screen,
source] : geometry )
634 SCH_ITEM* item = screen->GetConnectivityItem(
id );
639 move.Modify( item, screen );
640 item->
Move( offset );
641 BOOST_CHECK( item->
GetPosition() == expectedPosition );
643 BOOST_CHECK( !schematic->Connectivity().Published().Changes().Empty() );
647 item = screen->GetConnectivityItem(
id );
650 removal.
Remove( item, screen );
662 BOOST_TEST_MESSAGE( fixture <<
": checked " << labels.size() <<
" native label renames and restores, and "
663 << geometry.size() <<
" native geometry move/remove/restore sequences" );
666 schematic->RebuildConnectivity();
672 boost::unit_test::data::make( {
"issue7203",
"netlists/hierarchy_aliases/hierarchy_aliases" } ),
676 const auto hierarchy = schematic->Hierarchy();
677 SCH_SCREEN* screen = hierarchy.front().LastScreen();
679 for(
const auto&
path : hierarchy )
683 const auto instances = std::ranges::count_if( hierarchy, [&](
const auto& other )
685 return other.LastScreen() == candidate;
688 if( instances > 1 && labels.begin() != labels.end() )
692 std::vector<SCH_SHEET_PATH> affected;
694 for(
const auto&
path : hierarchy )
696 if(
path.LastScreen() == screen )
697 affected.push_back(
path );
700 BOOST_REQUIRE_EQUAL( affected.size(), hierarchy.size() == 1 ? 1u : 2u );
701 std::vector<SCH_ITEM*> sources;
704 sources.push_back( item );
709 incremental.
Update( *schematic );
714 std::vector<std::unique_ptr<SCH_ITEM>> items;
718 for(
const auto& item : items )
721 screen->
Remove( item.get(),
false );
724 } batch{ screen, {} };
725 batch.items.reserve( 500 );
727 for(
size_t i = 0; i < 500; ++i )
729 std::unique_ptr<SCH_ITEM>
copy( sources[i % sources.size()]->Duplicate(
false ) );
730 copy->SetParentGroup(
nullptr );
731 batch.items.push_back( std::move(
copy ) );
736 for(
int cycle = 0; cycle < 2; ++cycle )
738 for(
const auto& item : batch.items )
739 screen->
Append( item.get(),
false );
741 incremental.Update( *schematic );
743 for(
const auto&
path : affected )
745 for(
const auto& item : batch.items )
750 BOOST_CHECK_NE( edited, baseline );
751 rebuilt.
Update( *schematic,
true );
754 for(
const auto& item : batch.items )
757 incremental.Update( *schematic );
760 for(
const auto&
path : affected )
762 for(
const auto& item : batch.items )
763 BOOST_CHECK( !incremental.Connection( item->m_Uuid,
path.Path() ) );
766 rebuilt.
Update( *schematic,
true );
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
COMMIT & Remove(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Remove a new item from the model.
COMMIT & Modify(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr, RECURSE_MODE aRecurse=RECURSE_MODE::NO_RECURSE)
Modify a given item in the model.
COMMIT & Add(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Add a new item to the model.
virtual VECTOR2I GetPosition() const
virtual EDA_GROUP * GetParentGroup() const
EE_TYPE OfType(KICAD_T aType) const
wxString AsString() const
Commit for the schematic and symbol editors.
void Push(const wxString &aMessage=wxEmptyString, int aCommitFlags=0) override
Execute the changes.
Model-owned source resolver.
void Update(SCHEMATIC &aSchematic, bool aRebuild=false)
std::optional< ITEM_VIEW > Connection(const KIID &aItem, const KIID_PATH &aPath) const
Base class for any item which can be embedded within the SCHEMATIC container class,...
SCH_SCREEN * GetParentScreen() const
virtual void Move(const VECTOR2I &aMoveVector)
Move the item by aMoveVector to a new position.
Segment description base class to describe items which have 2 end points (track, wire,...
bool IsEndPoint(const VECTOR2I &aPoint) const override
Test if aPt is an end point of this schematic object.
void Append(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
std::vector< SCH_LINE * > GetBusesAndWires(const VECTOR2I &aPosition, bool aIgnoreEndpoints=false) const
Return buses and wires passing through aPosition.
EE_RTREE & Items()
Get the full RTree, usually for iterating.
bool Remove(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
Remove aItem from the schematic associated with this screen.
SCH_ITEM * GetConnectivityItem(const KIID &aId) const
Resolve a drawing item or a connectable child on this screen; ambiguous IDs return null.
bool CheckIfOnDrawList(const SCH_ITEM *aItem) const
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
void Move(const VECTOR2I &aMoveVector) override
Move the item by aMoveVector to a new position.
std::vector< const SCH_PIN * > GetPins(const SCH_SHEET_PATH *aSheet) const
Retrieve a list of the SCH_PINs for the given sheet path.
bool IsPower() const override
RAII class that sets an value at construction and resets it to the original value at destruction.
static bool empty(const wxTextEntryBase *aCtrl)
static std::string ToStdString(const wxString &aStr)
#define STRUCT_DELETED
flag indication structures to be erased
void LoadSchematic(SETTINGS_MANAGER &aSettingsManager, const wxString &aRelPath, std::unique_ptr< SCHEMATIC > &aSchematic)
Value keys and the key session of the schematic connectivity engine.
std::string Dump(SCHEMATIC &aSchematic)
Canonical, pointer-free connectivity rows for migration and rebuild comparisons.
constexpr uint32_t INVALID_ID
Marks an unset handle.
#define SKIP_CONNECTIVITY
#define DELETE_REMOVED_ITEMS
SETTINGS_MANAGER settings
std::unique_ptr< SCHEMATIC > schematic
Difference between two publications.
One item or pin in one sheet instance.
KIID item
The item or pin KIID.
INST_ID inst
The sheet instance that shows the item.
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_AUTO_TEST_CASE(ShadowDumpResolvesClassesWithoutLegacyAssignments)
BOOST_DATA_TEST_CASE_F(CONNECTIVITY_DUMP_FIXTURE, LegacyAndEngineDumpsMatch, boost::unit_test::data::make(PARITY_FIXTURES), fixture)
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_AUTO_TEST_SUITE_END()
BOOST_TEST_CONTEXT("Test Clearance")
BOOST_TEST_MESSAGE("Polyline has "<< chain.PointCount()<< " points")
wxString result
Test unit parsing edge cases and error handling.
BOOST_CHECK_EQUAL(result, "25.4")
wxString dump(const wxArrayString &aArray)
Debug helper for printing wxArrayString contents.
VECTOR2< int32_t > VECTOR2I