KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_net_chain_ordered_nets.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, you may find one here:
18 * https://www.gnu.org/licenses/gpl-3.0.en.html
19 */
20
21#include <boost/test/unit_test.hpp>
22
25
26#include <algorithm>
27#include <set>
28#include <vector>
29
30#include <connection_graph.h>
31#include <kiid.h>
32#include <locale_io.h>
33#include <schematic.h>
34#include <sch_netchain.h>
36
37
39{
41
43 std::unique_ptr<SCHEMATIC> m_schematic;
44
45 void Load( const wxString& aFixtureName )
46 {
47 m_settingsManager.LoadProject( wxString() );
49 m_schematic->ConnectionGraph()->Recalculate(
50 m_schematic->BuildSheetListSortedByPageNumbers(), /*aUnconditional=*/true );
51 }
52
53 // Locate the largest potential chain in the graph. Most fixtures we use here
54 // produce a single dominant chain; tying tests to a specific name keeps them
55 // brittle, so we just take the biggest.
57 {
58 SCH_NETCHAIN* best = nullptr;
59
60 for( const auto& sig : m_schematic->ConnectionGraph()->GetPotentialNetChains() )
61 {
62 if( !sig )
63 continue;
64
65 if( !best || sig->GetNets().size() > best->GetNets().size() )
66 best = sig.get();
67 }
68
69 return best;
70 }
71};
72
73
74BOOST_FIXTURE_TEST_SUITE( SchNetChainOrderedNets, ORDERED_NETS_FIXTURE )
75
76
77// A four-net linear chain (R-R-R between three nets in series, total four nets).
78// GetOrderedNets must return every member, with terminal A's net at the head and
79// terminal B's net at the tail.
80BOOST_AUTO_TEST_CASE( LinearChainCoversEveryMemberWithTerminalsAtEnds )
81{
83 Load( wxS( "net_chains_four_nets" ) );
84
85 SCH_NETCHAIN* chain = FindLargestPotentialChain();
86 BOOST_REQUIRE_MESSAGE( chain, "Fixture must contain at least one inferred chain" );
87 BOOST_REQUIRE_EQUAL( chain->GetNets().size(), 4u );
88
89 CONNECTION_GRAPH* graph = m_schematic->ConnectionGraph();
90 const std::vector<wxString>& ordered = chain->GetOrderedNets( graph );
91
92 // Every member appears exactly once.
93 BOOST_REQUIRE_EQUAL( ordered.size(), chain->GetNets().size() );
94
95 std::set<wxString> seen( ordered.begin(), ordered.end() );
96 BOOST_CHECK( seen == chain->GetNets() );
97
98 // Terminal nets land at the ends.
99 wxString termA = chain->GetTerminalNetName( 0, graph );
100 wxString termB = chain->GetTerminalNetName( 1, graph );
101 BOOST_REQUIRE( !termA.IsEmpty() );
102 BOOST_REQUIRE( !termB.IsEmpty() );
103 BOOST_CHECK_EQUAL( ordered.front(), termA );
104 BOOST_CHECK_EQUAL( ordered.back(), termB );
105}
106
107
108// Second call must return the cached vector unchanged (same content, same order).
109BOOST_AUTO_TEST_CASE( SecondCallReturnsIdenticalCachedVector )
110{
112 Load( wxS( "net_chains_four_nets" ) );
113
114 SCH_NETCHAIN* chain = FindLargestPotentialChain();
116 CONNECTION_GRAPH* graph = m_schematic->ConnectionGraph();
117
118 std::vector<wxString> first = chain->GetOrderedNets( graph );
119 std::vector<wxString> second = chain->GetOrderedNets( graph );
120
121 BOOST_CHECK( first == second );
122}
123
124
125// Mutating the chain (AddNet) must invalidate the cache and surface the new net.
126BOOST_AUTO_TEST_CASE( AddNetInvalidatesCache )
127{
129 Load( wxS( "net_chains_four_nets" ) );
130
131 SCH_NETCHAIN* chain = FindLargestPotentialChain();
133 CONNECTION_GRAPH* graph = m_schematic->ConnectionGraph();
134
135 const std::vector<wxString> before = chain->GetOrderedNets( graph );
136 const wxString sentinel = wxS( "__ordered_nets_test_sentinel__" );
137
138 chain->AddNet( sentinel );
139
140 const std::vector<wxString>& after = chain->GetOrderedNets( graph );
141
142 BOOST_CHECK( std::find( after.begin(), after.end(), sentinel ) != after.end() );
143 BOOST_CHECK_GT( after.size(), before.size() );
144}
145
146
147// Branched chain (Y or T topology): the shortest path between the two terminals
148// is the prefix; any off-path member nets are appended alphabetically. Whatever
149// the fixture's specific topology, the contract is:
150// 1. every member appears exactly once
151// 2. terminal A's net is at index 0
152// 3. terminal B's net appears (somewhere) before any off-path nets
153BOOST_AUTO_TEST_CASE( BranchedChainPlacesPathBeforeOffPathNets )
154{
156 Load( wxS( "net_chains_branching_longer" ) );
157
158 SCH_NETCHAIN* chain = FindLargestPotentialChain();
160 BOOST_REQUIRE_GE( chain->GetNets().size(), 3u );
161
162 CONNECTION_GRAPH* graph = m_schematic->ConnectionGraph();
163 const std::vector<wxString>& ordered = chain->GetOrderedNets( graph );
164
165 BOOST_REQUIRE_EQUAL( ordered.size(), chain->GetNets().size() );
166
167 std::set<wxString> seen( ordered.begin(), ordered.end() );
168 BOOST_CHECK( seen == chain->GetNets() );
169
170 wxString termA = chain->GetTerminalNetName( 0, graph );
171 wxString termB = chain->GetTerminalNetName( 1, graph );
172 BOOST_REQUIRE( !termA.IsEmpty() );
173 BOOST_REQUIRE( !termB.IsEmpty() );
174 BOOST_CHECK_EQUAL( ordered.front(), termA );
175
176 // termB must appear somewhere; off-path nets are appended after it.
177 auto itB = std::find( ordered.begin(), ordered.end(), termB );
178 BOOST_CHECK( itB != ordered.end() );
179}
180
181
182// Null graph and unset terminals must yield an empty result without caching, so
183// that a subsequent call once state is valid still rebuilds.
184BOOST_AUTO_TEST_CASE( NullGraphReturnsEmpty )
185{
187 Load( wxS( "net_chains_four_nets" ) );
188
189 SCH_NETCHAIN* chain = FindLargestPotentialChain();
191
192 const std::vector<wxString>& empty = chain->GetOrderedNets( nullptr );
193 BOOST_CHECK( empty.empty() );
194
195 // A subsequent valid call must still populate.
196 const std::vector<wxString>& populated = chain->GetOrderedNets( m_schematic->ConnectionGraph() );
197 BOOST_CHECK( !populated.empty() );
198}
199
200
201// A standalone SCH_NETCHAIN with no symbols and no terminals returns empty and
202// stays dirty so future, properly-set-up calls will populate.
203BOOST_AUTO_TEST_CASE( StandaloneEmptyChainStaysDirty )
204{
205 SCH_NETCHAIN bare;
206 const std::vector<wxString>& first = bare.GetOrderedNets( nullptr );
207 BOOST_CHECK( first.empty() );
208
209 bare.AddNet( wxS( "A" ) );
210 bare.AddNet( wxS( "B" ) );
211
212 // Still empty: no graph, no symbols, no terminals. Returns empty without crashing.
213 const std::vector<wxString>& second = bare.GetOrderedNets( nullptr );
214 BOOST_CHECK( second.empty() );
215}
216
217
KICAD_PLUGIN_EXPORT SCENEGRAPH * Load(char const *aFileName)
Read a model file and creates a generic display structure.
Calculate the connectivity of a schematic and generates netlists.
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
Definition locale_io.h:41
A net chain is a collection of nets that are connected together through passive components.
const std::set< wxString > & GetNets() const
const std::vector< wxString > & GetOrderedNets(CONNECTION_GRAPH *aGraph) const
Return the chain's member nets ordered from terminal pin A's net to terminal pin B's net along the sh...
void AddNet(const wxString &aNet)
static bool empty(const wxTextEntryBase *aCtrl)
void LoadSchematic(SETTINGS_MANAGER &aSettingsManager, const wxString &aRelPath, std::unique_ptr< SCHEMATIC > &aSchematic)
std::vector< FAB_LAYER_COLOR > dummy
void Load(const wxString &aFixtureName)
std::unique_ptr< SCHEMATIC > m_schematic
SCH_NETCHAIN * FindLargestPotentialChain() const
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_AUTO_TEST_SUITE_END()
BOOST_AUTO_TEST_CASE(LinearChainCoversEveryMemberWithTerminalsAtEnds)
const SHAPE_LINE_CHAIN chain
BOOST_CHECK_EQUAL(result, "25.4")