KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_connectivity_navigation.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 modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation, either version 3 of the License, or (at your
9 * option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * 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
24#include <schematic.h>
26#include <advanced_config.h>
27#include <connection_graph.h>
28#include <sch_item.h>
29#include <sch_label.h>
30#include <sch_line.h>
31#include <sch_screen.h>
32#include <sch_sheet.h>
33#include <sch_symbol.h>
34#include <algorithm>
35#include <set>
36#include <scoped_set_reset.h>
37
38using namespace SCH_CONNECTIVITY;
39
40BOOST_AUTO_TEST_SUITE( ConnectivityNavigation )
41
42BOOST_AUTO_TEST_CASE( AliasMemberQueriesMatchNativeMembership )
43{
44 auto& enabled = const_cast<ADVANCED_CFG&>( ADVANCED_CFG::GetCfg() ).m_ConnectivityEngine;
45 SCOPED_SET_RESET restore( enabled, false );
46 SETTINGS_MANAGER settings;
47 std::unique_ptr<SCHEMATIC> schematic;
48 KI_TEST::LoadSchematic( settings, "netlists/hierarchy_aliases/hierarchy_aliases", schematic );
49 schematic->RebuildConnectivity();
50 const wxString name = wxS( "/S0.BOOT.SDA" );
51 const auto legacyNames = NAVIGATION_QUERY( *schematic ).NetNames();
52 const auto direct = NAVIGATION_QUERY( *schematic ).NetItems( name, false );
53 const auto withBuses = NAVIGATION_QUERY( *schematic ).NetItems( name, true );
54 BOOST_REQUIRE( !direct.empty() );
55 BOOST_REQUIRE( !withBuses.empty() );
56 size_t directCount = 0;
57 size_t expandedCount = 0;
58
59 for( const auto& [path, items] : direct )
60 directCount += items.size();
61
62 for( const auto& [path, items] : withBuses )
63 {
64 expandedCount += items.size();
65 BOOST_CHECK_EQUAL( std::set<SCH_ITEM*>( items.begin(), items.end() ).size(), items.size() );
66 }
67
68 BOOST_REQUIRE_GT( expandedCount, directCount );
69 const auto root = schematic->Hierarchy().front();
70 std::optional<wxString> busName;
71
72 for( SCH_ITEM* item : root.LastScreen()->Items().OfType( SCH_LABEL_T ) )
73 {
74 if( static_cast<SCH_LABEL*>( item )->GetText() == wxS( "S0{ALIAS1}" ) )
75 busName = item->GetConnectionName( &root );
76 }
77
78 BOOST_REQUIRE( busName );
79 const auto busItems = NAVIGATION_QUERY( *schematic ).NetItems( *busName, true );
80 BOOST_REQUIRE( !busItems.empty() );
81 enabled = true;
82 schematic->RebuildConnectivity();
83 BOOST_CHECK( NAVIGATION_QUERY( *schematic ).NetItems( name, false ) == direct );
84 BOOST_CHECK( NAVIGATION_QUERY( *schematic ).NetItems( name, true ) == withBuses );
85 BOOST_CHECK( NAVIGATION_QUERY( *schematic ).NetItems( *busName, true ) == busItems );
86 const auto names = NAVIGATION_QUERY( *schematic ).NetNames();
87 BOOST_CHECK( names == legacyNames );
88 BOOST_CHECK( std::ranges::find( names, name ) != names.end() );
89}
90
91BOOST_AUTO_TEST_CASE( SharedScreenLocalNetsKeepTheirInstanceMembership )
92{
93 auto& enabled = const_cast<ADVANCED_CFG&>( ADVANCED_CFG::GetCfg() ).m_ConnectivityEngine;
94 SCOPED_SET_RESET restore( enabled, false );
95 SETTINGS_MANAGER settings;
96 std::unique_ptr<SCHEMATIC> schematic;
97 KI_TEST::LoadSchematic( settings, "net_chains_four_nets_labeled", schematic );
98 auto* original = schematic->GetTopLevelSheet();
99 auto copy = std::unique_ptr<SCH_SHEET>( static_cast<SCH_SHEET*>( original->Clone() ) );
100 const_cast<KIID&>( copy->m_Uuid ) = KIID();
101 copy->SetName( wxS( "Second" ) );
102 schematic->AddTopLevelSheet( copy.release() );
103 const auto paths = schematic->Hierarchy();
104 BOOST_REQUIRE_EQUAL( paths.size(), 2u );
105 BOOST_REQUIRE( paths[0].LastScreen() == paths[1].LastScreen() );
106 SCH_LABEL* label = nullptr;
107
108 for( SCH_ITEM* item : original->GetScreen()->Items().OfType( SCH_LABEL_T ) )
109 {
110 auto* candidate = static_cast<SCH_LABEL*>( item );
111
112 if( candidate->GetText() == wxS( "SIG" ) )
113 label = candidate;
114 }
115
116 BOOST_REQUIRE( label );
117
118 for( bool backend : { false, true } )
119 {
120 enabled = backend;
121 schematic->RebuildConnectivity();
122
123 for( const auto& path : paths )
124 {
125 const auto name = label->GetConnectionName( &path );
127 const auto result = NAVIGATION_QUERY( *schematic ).NetItems( *name, false );
128 BOOST_REQUIRE_EQUAL( result.size(), 1u );
129 BOOST_CHECK( result.begin()->first.Path() == path.Path() );
130 const auto& items = result.begin()->second;
131 BOOST_CHECK( std::ranges::find( items, label ) != items.end() );
132 }
133 }
134}
135
136BOOST_AUTO_TEST_CASE( UnprefixedAliasAndExpandedBusReachTheSamePhysicalItems )
137{
138 auto& enabled = const_cast<ADVANCED_CFG&>( ADVANCED_CFG::GetCfg() ).m_ConnectivityEngine;
139 SCOPED_SET_RESET restore( enabled, false );
140 SETTINGS_MANAGER settings;
141 std::unique_ptr<SCHEMATIC> schematic;
142 KI_TEST::LoadSchematic( settings, "issue9673/issue9673", schematic );
143 NET_ITEMS_BY_SHEET legacy;
144
145 for( bool backend : { false, true } )
146 {
147 enabled = backend;
148 schematic->RebuildConnectivity();
149 const NAVIGATION_QUERY query( *schematic );
150 const wxString aliasName = wxS( "/{MIXED_BUS}" );
151 const auto alias = query.NetItems( aliasName, true );
152 const auto expanded = query.NetItems( wxS( "/{FOO BAR HAM EGGS}" ), true );
153 const auto direct = query.NetItems( aliasName, false );
154 BOOST_REQUIRE( !direct.empty() );
155 BOOST_CHECK_GT( alias.size(), direct.size() );
156 BOOST_CHECK( alias == expanded );
157
158 if( backend )
159 BOOST_CHECK( alias == legacy );
160 else
161 legacy = alias;
162 }
163}
164
165BOOST_AUTO_TEST_CASE( StaleRootPreservesLiveChildMembership )
166{
167 auto& enabled = const_cast<ADVANCED_CFG&>( ADVANCED_CFG::GetCfg() ).m_ConnectivityEngine;
168 SCOPED_SET_RESET restore( enabled, true );
169 SETTINGS_MANAGER settings;
170 std::unique_ptr<SCHEMATIC> schematic;
171 KI_TEST::LoadSchematic( settings, "netlists/hierarchy_aliases/hierarchy_aliases", schematic );
172 schematic->RebuildConnectivity();
173 const wxString name = wxS( "/S0.BOOT.SDA" );
174 auto expected = NAVIGATION_QUERY( *schematic ).NetItems( name, false );
175 const auto root = schematic->Hierarchy().front();
176 BOOST_REQUIRE_EQUAL( expected.erase( root ), 1u );
177 BOOST_REQUIRE( !expected.empty() );
178 root.LastScreen()->BumpConnectivityRevision();
179 const NAVIGATION_QUERY query( *schematic );
180 BOOST_CHECK( query.NetItems( name, false ) == expected );
181 const auto names = query.NetNames();
182 BOOST_CHECK( std::ranges::find( names, name ) != names.end() );
183}
184
185BOOST_AUTO_TEST_CASE( SharedScreenGlobalNetKeepsBothSheetRows )
186{
187 auto& enabled = const_cast<ADVANCED_CFG&>( ADVANCED_CFG::GetCfg() ).m_ConnectivityEngine;
188 SCOPED_SET_RESET restore( enabled, false );
189 SETTINGS_MANAGER settings;
190 std::unique_ptr<SCHEMATIC> schematic;
191 KI_TEST::LoadSchematic( settings, "NoConnectOnLineWithGlobalLabel", schematic );
192 auto* original = schematic->GetTopLevelSheet();
193 auto copy = std::unique_ptr<SCH_SHEET>( static_cast<SCH_SHEET*>( original->Clone() ) );
194 const_cast<KIID&>( copy->m_Uuid ) = KIID();
195 copy->SetName( wxS( "Second" ) );
196 schematic->AddTopLevelSheet( copy.release() );
197 const auto paths = schematic->Hierarchy();
198 BOOST_REQUIRE_EQUAL( paths.size(), 2u );
199 BOOST_REQUIRE( paths[0].LastScreen() == paths[1].LastScreen() );
200 SCH_ITEM* label = nullptr;
201
202 for( SCH_ITEM* item : original->GetScreen()->Items().OfType( SCH_GLOBAL_LABEL_T ) )
203 {
204 if( static_cast<SCH_GLOBALLABEL*>( item )->GetText() == wxS( "test_OK" ) )
205 label = item;
206 }
207
208 BOOST_REQUIRE( label );
209
210 for( bool backend : { false, true } )
211 {
212 enabled = backend;
213 schematic->RebuildConnectivity();
214 const auto name = label->GetConnectionName( &paths.front() );
216 const auto result = NAVIGATION_QUERY( *schematic ).NetItems( *name, false );
217 BOOST_REQUIRE_EQUAL( result.size(), 2u );
218 BOOST_REQUIRE( result.contains( paths[0] ) );
219 BOOST_REQUIRE( result.contains( paths[1] ) );
220 BOOST_CHECK( result.at( paths[0] ) == result.at( paths[1] ) );
221 const auto& items = result.at( paths[0] );
222 BOOST_CHECK( std::ranges::find( items, label ) != items.end() );
223 }
224}
225
226BOOST_AUTO_TEST_CASE( BusHighlightAndCrossProbeResolveMembersWithoutLegacyRows )
227{
228 auto& enabled = const_cast<ADVANCED_CFG&>( ADVANCED_CFG::GetCfg() ).m_ConnectivityEngine;
229 SCOPED_SET_RESET restore( enabled, false );
230 SETTINGS_MANAGER settings;
231 std::unique_ptr<SCHEMATIC> schematic;
232 KI_TEST::LoadSchematic( settings, "netlists/hierarchy_aliases/hierarchy_aliases", schematic );
233 schematic->RebuildConnectivity();
234 const auto root = schematic->Hierarchy().front();
235 SCH_ITEM* busLabel = nullptr;
236
237 for( SCH_ITEM* item : root.LastScreen()->Items().OfType( SCH_LABEL_T ) )
238 {
239 if( static_cast<SCH_LABEL*>( item )->GetText() == wxS( "S0{ALIAS1}" ) )
240 busLabel = item;
241 }
242
243 BOOST_REQUIRE( busLabel );
244 const auto busName = busLabel->GetConnectionName( &root );
245 BOOST_REQUIRE( busName );
246 const std::vector<wxString> expectedSignals{ wxS( "/S0.BOOT.SCL" ), wxS( "/S0.BOOT.SDA" ) };
247 const NAVIGATION_QUERY legacyQuery( *schematic );
248 BOOST_CHECK( legacyQuery.SignalNames( *busName ) == expectedSignals );
249 const auto expectedItems = legacyQuery.NetItems( *busName, true, true );
250 const auto busItems = legacyQuery.NetItems( *busName, true );
251 BOOST_REQUIRE( expectedItems != busItems );
252 enabled = true;
253 schematic->ConnectionGraph()->Reset();
254 schematic->RebuildConnectivity();
255 const NAVIGATION_QUERY query( *schematic );
256 BOOST_CHECK( query.SignalNames( *busName ) == expectedSignals );
257 BOOST_CHECK( query.NetItems( *busName, true, true ) == expectedItems );
258 BOOST_CHECK( query.SignalNames( expectedSignals.front() )
259 == std::vector<wxString>{ expectedSignals.front() } );
260}
261
262BOOST_AUTO_TEST_CASE( DisplayingSharedScreenReferencesPreservesPublishedConnectivity )
263{
264 auto& enabled = const_cast<ADVANCED_CFG&>( ADVANCED_CFG::GetCfg() ).m_ConnectivityEngine;
265 SCOPED_SET_RESET restore( enabled, true );
266 SETTINGS_MANAGER settings;
267 std::unique_ptr<SCHEMATIC> schematic;
268 KI_TEST::LoadSchematic( settings, "net_chains_four_nets_labeled", schematic );
269 auto* original = schematic->GetTopLevelSheet();
270 auto copy = std::unique_ptr<SCH_SHEET>( static_cast<SCH_SHEET*>( original->Clone() ) );
271 const_cast<KIID&>( copy->m_Uuid ) = KIID();
272 copy->SetName( wxS( "Second" ) );
273 schematic->AddTopLevelSheet( copy.release() );
274 const auto paths = schematic->Hierarchy();
275 BOOST_REQUIRE_EQUAL( paths.size(), 2u );
276
277 for( SCH_ITEM* item : original->GetScreen()->Items().OfType( SCH_SYMBOL_T ) )
278 {
279 auto* symbol = static_cast<SCH_SYMBOL*>( item );
280 symbol->SetRef( &paths[1], symbol->GetRef( &paths[0] ) + wxS( "0" ) );
281 }
282
283 schematic->RebuildConnectivity();
284 const auto names = NAVIGATION_QUERY( *schematic ).NetNames();
285 BOOST_REQUIRE( !names.empty() );
286 std::map<wxString, NET_ITEMS_BY_SHEET> expected;
287
288 for( const wxString& name : names )
289 expected.emplace( name, NAVIGATION_QUERY( *schematic ).NetItems( name, false ) );
290
291 for( const auto& path : paths )
292 {
293 schematic->SetCurrentSheet( path );
294 path.UpdateAllScreenReferences();
295 const NAVIGATION_QUERY query( *schematic );
296 BOOST_CHECK( query.NetNames() == names );
297
298 for( const auto& [name, items] : expected )
299 BOOST_CHECK( query.NetItems( name, false ) == items );
300 }
301}
302
303BOOST_AUTO_TEST_CASE( NetclassAssignmentCandidatesUsePublishedNets )
304{
305 auto& enabled = const_cast<ADVANCED_CFG&>( ADVANCED_CFG::GetCfg() ).m_ConnectivityEngine;
306 SCOPED_SET_RESET restore( enabled, enabled );
307
308 for( const wxString& fixture : { wxString( "net_chains_four_nets_labeled" ),
309 wxString( "netlists/hierarchy_aliases/hierarchy_aliases" ) } )
310 {
311 enabled = false;
312 SETTINGS_MANAGER settings;
313 std::unique_ptr<SCHEMATIC> schematic;
314 KI_TEST::LoadSchematic( settings, fixture, schematic );
315 SCH_SCREEN* screen = schematic->Hierarchy().front().LastScreen();
316 SCH_LINE* wire = nullptr;
317 SCH_LABEL* label = nullptr;
318
319 for( SCH_ITEM* item : screen->Items().OfType( SCH_LINE_T ) )
320 {
321 if( static_cast<SCH_LINE*>( item )->IsWire() )
322 {
323 wire = static_cast<SCH_LINE*>( item->Clone() );
324 break;
325 }
326 }
327
328 for( SCH_ITEM* item : screen->Items().OfType( SCH_LABEL_T ) )
329 {
330 label = static_cast<SCH_LABEL*>( item->Clone() );
331 break;
332 }
333
334 BOOST_REQUIRE( wire );
335 BOOST_REQUIRE( label );
336 const_cast<KIID&>( wire->m_Uuid ) = KIID();
337 const_cast<KIID&>( label->m_Uuid ) = KIID();
338
339 // Far from the fixture geometry so the wire stays undriven and the vector label drives only itself
340 wire->Move( VECTOR2I( 0, 10000000 ) );
341 label->Move( VECTOR2I( 0, 20000000 ) );
342 label->SetText( wxString( "CANDIDATE_BUS[0..1]" ) );
343 screen->Append( wire );
344 screen->Append( label );
345 schematic->RebuildConnectivity();
346 const auto expected = schematic->GetNetClassAssignmentCandidates();
347 BOOST_REQUIRE( !expected.empty() );
348
349 if( fixture == wxString( "net_chains_four_nets_labeled" ) )
350 BOOST_CHECK( expected.contains( wxString( "/SIG" ) ) );
351
352 enabled = true;
353 schematic->RebuildConnectivity();
354 schematic->ConnectionGraph()->Reset();
355 const auto actual = schematic->GetNetClassAssignmentCandidates();
356 BOOST_CHECK( actual == expected );
357
358 size_t buses = 0;
359
360 for( const auto& group : schematic->Connectivity().GetNetMap() )
361 {
362 if( !group.instances.empty() && group.instances.front().IsBus() )
363 {
364 BOOST_CHECK( !actual.contains( group.name ) );
365 ++buses;
366 }
367 }
368
369 if( fixture == wxString( "netlists/hierarchy_aliases/hierarchy_aliases" ) )
370 BOOST_CHECK_GT( buses, 0u );
371 }
372}
373
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
Definition kiid.h:46
One UI operation's hierarchy index.
std::vector< wxString > SignalNames(const wxString &aName) const
NET_ITEMS_BY_SHEET NetItems(const wxString &aName, bool aIncludeBusParents, bool aIncludeBusMembers=false) const
std::vector< wxString > NetNames() const
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:170
std::optional< wxString > GetConnectionName(const SCH_SHEET_PATH *aSheet=nullptr, bool aLocal=false, bool aIgnoreSheet=false) const
Return the active connection name; absent for missing or stale published rows.
Definition sch_item.cpp:628
void Move(const VECTOR2I &aMoveVector) override
Move the item by aMoveVector to a new position.
Segment description base class to describe items which have 2 end points (track, wire,...
Definition sch_line.h:39
void Move(const VECTOR2I &aMoveVector) override
Move the item by aMoveVector to a new position.
Definition sch_line.cpp:247
void Append(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
EE_RTREE & Items()
Get the full RTree, usually for iterating.
Definition sch_screen.h:122
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
void SetRef(const SCH_SHEET_PATH *aSheet, const wxString &aReference)
Set the reference for the given sheet path for this symbol.
RAII class that sets an value at construction and resets it to the original value at destruction.
bool m_ConnectivityEngine
Use the schematic connectivity engine instead of CONNECTION_GRAPH.
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::map< SCH_SHEET_PATH, std::vector< SCH_ITEM * >, SHEET_PATH_CMP > NET_ITEMS_BY_SHEET
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_AUTO_TEST_SUITE(CadstarPartParser)
BOOST_AUTO_TEST_CASE(AliasMemberQueriesMatchNativeMembership)
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_AUTO_TEST_SUITE_END()
std::string path
VECTOR3I expected(15, 30, 45)
int actual
wxString result
Test unit parsing edge cases and error handling.
BOOST_CHECK_EQUAL(result, "25.4")
@ SCH_LINE_T
Definition typeinfo.h:159
@ SCH_SYMBOL_T
Definition typeinfo.h:168
@ SCH_LABEL_T
Definition typeinfo.h:163
@ SCH_GLOBAL_LABEL_T
Definition typeinfo.h:164
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683