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();
427 auto* candidate =
static_cast<SCH_SYMBOL*
>( item );
429 if( !candidate->IsPower() && !candidate->GetPins( &
path ).empty() )
442 std::set<SCH_SCREEN*> seenScreens;
443 const auto isGeometry = [](
const SCH_ITEM* item )
445 return item->IsConnectable()
450 std::vector<std::pair<SCH_SCREEN*, std::unique_ptr<SCH_ITEM>>> geometry;
454 if( !seenScreens.insert(
path.LastScreen() ).second )
459 if( isGeometry( item ) )
462 geometry.emplace_back(
path.LastScreen(),
static_cast<SCH_ITEM*
>( item->Clone() ) );
467 std::sort( geometry.begin(), geometry.end(),
468 [](
const auto& a,
const auto& b ) { return a.second->m_Uuid < b.second->m_Uuid; } );
469 const VECTOR2I offset( 10000000, 10000000 );
471 rebuilt.
Update( *schematic,
true );
472 const auto verify = [&]()
476 for(
SCH_ITEM* item : screen->Items() )
479 "Cleanup left a deleted item on the screen: "
480 << item->m_Uuid.AsString().ToStdString() );
485 rebuilt.
Update( *schematic,
true );
489 fresh.
Update( *schematic,
true );
491 std::map<int, int> toFresh;
492 std::map<int, int> fromFresh;
493 const auto& current = schematic->Connectivity();
495 for(
const auto& [key, row] : current.Published().Rows() )
497 const auto&
path = current.Keys().Instance( key.inst );
498 const auto actual = current.Connection( key.item,
path );
504 const auto forward = toFresh.emplace(
actual->NetCode(),
empty->NetCode() ).first;
505 const auto reverse = fromFresh.emplace(
empty->NetCode(),
actual->NetCode() ).first;
512 const auto restoreGeometry = [&]()
517 std::vector<SCH_ITEM*> removed;
518 std::vector<std::pair<SCH_SCREEN*, std::unique_ptr<SCH_ITEM>>> added;
522 for(
SCH_ITEM* item : screen->Items() )
524 if( isGeometry( item ) )
526 restore.
Remove( item, screen );
527 removed.push_back( item );
532 for(
const auto& [screen, source] : geometry )
534 auto copy = std::unique_ptr<SCH_ITEM>(
static_cast<SCH_ITEM*
>( source->Clone() ) );
536 restore.
Add(
copy.get(), screen );
537 added.emplace_back( screen, std::move(
copy ) );
542 for(
auto& [screen, item] : added )
559 commit.
Modify( symbol, screen );
560 symbol->
Move( movement );
562 BOOST_CHECK( !schematic->Connectivity().Published().Changes().Empty() );
569 auto symbolReplacement = std::make_unique<SCH_SYMBOL>( *symbol );
571 removal.
Remove( symbol, symbolScreen );
579 addition.
Add( symbolReplacement.get(), symbolScreen );
582 symbolReplacement.release();
586 std::vector<SCH_LABEL_BASE*> labels;
590 for(
SCH_ITEM* item : screen->Items() )
598 std::sort( labels.begin(), labels.end(),
599 [](
const auto* a,
const auto* b ) { return a->m_Uuid < b->m_Uuid; } );
603 const wxString originalText = label->GetText();
605 for(
const wxString&
text : { wxString(
"ORACLE_" ) + originalText, originalText } )
608 rename.
Modify( label, label->GetParentScreen() );
609 label->SetText(
text );
615 for(
const auto& [screen, source] : geometry )
617 const KIID&
id = source->m_Uuid;
621 SCH_ITEM* item = screen->GetConnectivityItem(
id );
626 move.Modify( item, screen );
627 item->
Move( offset );
628 BOOST_CHECK( item->
GetPosition() == expectedPosition );
630 BOOST_CHECK( !schematic->Connectivity().Published().Changes().Empty() );
634 item = screen->GetConnectivityItem(
id );
637 removal.
Remove( item, screen );
649 BOOST_TEST_MESSAGE( fixture <<
": checked " << labels.size() <<
" native label renames and restores, and "
650 << geometry.size() <<
" native geometry move/remove/restore sequences" );
653 schematic->RebuildConnectivity();
659 boost::unit_test::data::make( {
"issue7203",
"netlists/hierarchy_aliases/hierarchy_aliases" } ),
663 const auto hierarchy = schematic->Hierarchy();
664 SCH_SCREEN* screen = hierarchy.front().LastScreen();
666 for(
const auto&
path : hierarchy )
670 const auto instances = std::ranges::count_if( hierarchy, [&](
const auto& other )
672 return other.LastScreen() == candidate;
675 if( instances > 1 && labels.begin() != labels.end() )
679 std::vector<SCH_SHEET_PATH> affected;
681 for(
const auto&
path : hierarchy )
683 if(
path.LastScreen() == screen )
684 affected.push_back(
path );
687 BOOST_REQUIRE_EQUAL( affected.size(), hierarchy.size() == 1 ? 1u : 2u );
688 std::vector<SCH_ITEM*> sources;
691 sources.push_back( item );
696 incremental.
Update( *schematic );
701 std::vector<std::unique_ptr<SCH_ITEM>> items;
705 for(
const auto& item : items )
708 screen->
Remove( item.get(),
false );
711 } batch{ screen, {} };
712 batch.items.reserve( 500 );
714 for(
size_t i = 0; i < 500; ++i )
716 std::unique_ptr<SCH_ITEM>
copy( sources[i % sources.size()]->Duplicate(
false ) );
717 copy->SetParentGroup(
nullptr );
718 batch.items.push_back( std::move(
copy ) );
723 for(
int cycle = 0; cycle < 2; ++cycle )
725 for(
const auto& item : batch.items )
726 screen->
Append( item.get(),
false );
728 incremental.Update( *schematic );
730 for(
const auto&
path : affected )
732 for(
const auto& item : batch.items )
737 BOOST_CHECK_NE( edited, baseline );
738 rebuilt.
Update( *schematic,
true );
741 for(
const auto& item : batch.items )
744 incremental.Update( *schematic );
747 for(
const auto&
path : affected )
749 for(
const auto& item : batch.items )
750 BOOST_CHECK( !incremental.Connection( item->m_Uuid,
path.Path() ) );
753 rebuilt.
Update( *schematic,
true );
wxString result
Test unit parsing edge cases and error handling.
BOOST_CHECK_EQUAL(result, "25.4")