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, see <https://www.gnu.org/licenses/>.
18 */
19
20#include <boost/test/unit_test.hpp>
21
24
25#include <algorithm>
26#include <set>
27#include <vector>
28
29#include <connection_graph.h>
30#include <kiid.h>
31#include <locale_io.h>
32#include <schematic.h>
33#include <sch_netchain.h>
35
36
38{
40
42 std::unique_ptr<SCHEMATIC> m_schematic;
43
44 void Load( const wxString& aFixtureName )
45 {
46 m_settingsManager.LoadProject( wxString() );
48 m_schematic->ConnectionGraph()->Recalculate(
49 m_schematic->BuildSheetListSortedByPageNumbers(), /*aUnconditional=*/true );
50 }
51
52 // Locate the largest potential chain in the graph. Most fixtures we use here
53 // produce a single dominant chain; tying tests to a specific name keeps them
54 // brittle, so we just take the biggest.
56 {
57 SCH_NETCHAIN* best = nullptr;
58
59 for( const auto& sig : m_schematic->ConnectionGraph()->GetPotentialNetChains() )
60 {
61 if( !sig )
62 continue;
63
64 if( !best || sig->GetNets().size() > best->GetNets().size() )
65 best = sig.get();
66 }
67
68 return best;
69 }
70};
71
72
73BOOST_FIXTURE_TEST_SUITE( SchNetChainOrderedNets, ORDERED_NETS_FIXTURE )
74
75
76// A four-net linear chain (R-R-R between three nets in series, total four nets).
77// GetOrderedNets must return every member, with terminal A's net at the head and
78// terminal B's net at the tail.
79BOOST_AUTO_TEST_CASE( LinearChainCoversEveryMemberWithTerminalsAtEnds )
80{
82 Load( wxS( "net_chains_four_nets" ) );
83
84 SCH_NETCHAIN* chain = FindLargestPotentialChain();
85 BOOST_REQUIRE_MESSAGE( chain, "Fixture must contain at least one inferred chain" );
86 BOOST_REQUIRE_EQUAL( chain->GetNets().size(), 4u );
87
88 CONNECTION_GRAPH* graph = m_schematic->ConnectionGraph();
89 const std::vector<wxString>& ordered = chain->GetOrderedNets( graph );
90
91 // Every member appears exactly once.
92 BOOST_REQUIRE_EQUAL( ordered.size(), chain->GetNets().size() );
93
94 std::set<wxString> seen( ordered.begin(), ordered.end() );
95 BOOST_CHECK( seen == chain->GetNets() );
96
97 // Terminal nets land at the ends.
98 wxString termA = chain->GetTerminalNetName( 0, graph );
99 wxString termB = chain->GetTerminalNetName( 1, graph );
100 BOOST_REQUIRE( !termA.IsEmpty() );
101 BOOST_REQUIRE( !termB.IsEmpty() );
102 BOOST_CHECK_EQUAL( ordered.front(), termA );
103 BOOST_CHECK_EQUAL( ordered.back(), termB );
104}
105
106
107// Second call must return the cached vector unchanged (same content, same order).
108BOOST_AUTO_TEST_CASE( SecondCallReturnsIdenticalCachedVector )
109{
111 Load( wxS( "net_chains_four_nets" ) );
112
113 SCH_NETCHAIN* chain = FindLargestPotentialChain();
115 CONNECTION_GRAPH* graph = m_schematic->ConnectionGraph();
116
117 std::vector<wxString> first = chain->GetOrderedNets( graph );
118 std::vector<wxString> second = chain->GetOrderedNets( graph );
119
120 BOOST_CHECK( first == second );
121}
122
123
124// Mutating the chain (AddNet) must invalidate the cache and surface the new net.
125BOOST_AUTO_TEST_CASE( AddNetInvalidatesCache )
126{
128 Load( wxS( "net_chains_four_nets" ) );
129
130 SCH_NETCHAIN* chain = FindLargestPotentialChain();
132 CONNECTION_GRAPH* graph = m_schematic->ConnectionGraph();
133
134 const std::vector<wxString> before = chain->GetOrderedNets( graph );
135 const wxString sentinel = wxS( "__ordered_nets_test_sentinel__" );
136
137 chain->AddNet( sentinel );
138
139 const std::vector<wxString>& after = chain->GetOrderedNets( graph );
140
141 BOOST_CHECK( std::find( after.begin(), after.end(), sentinel ) != after.end() );
142 BOOST_CHECK_GT( after.size(), before.size() );
143}
144
145
146// Branched chain (Y or T topology): the shortest path between the two terminals
147// is the prefix; any off-path member nets are appended alphabetically. Whatever
148// the fixture's specific topology, the contract is:
149// 1. every member appears exactly once
150// 2. terminal A's net is at index 0
151// 3. terminal B's net appears (somewhere) before any off-path nets
152BOOST_AUTO_TEST_CASE( BranchedChainPlacesPathBeforeOffPathNets )
153{
155 Load( wxS( "net_chains_branching_longer" ) );
156
157 SCH_NETCHAIN* chain = FindLargestPotentialChain();
159 BOOST_REQUIRE_GE( chain->GetNets().size(), 3u );
160
161 CONNECTION_GRAPH* graph = m_schematic->ConnectionGraph();
162 const std::vector<wxString>& ordered = chain->GetOrderedNets( graph );
163
164 BOOST_REQUIRE_EQUAL( ordered.size(), chain->GetNets().size() );
165
166 std::set<wxString> seen( ordered.begin(), ordered.end() );
167 BOOST_CHECK( seen == chain->GetNets() );
168
169 wxString termA = chain->GetTerminalNetName( 0, graph );
170 wxString termB = chain->GetTerminalNetName( 1, graph );
171 BOOST_REQUIRE( !termA.IsEmpty() );
172 BOOST_REQUIRE( !termB.IsEmpty() );
173 BOOST_CHECK_EQUAL( ordered.front(), termA );
174
175 // termB must appear somewhere; off-path nets are appended after it.
176 auto itB = std::find( ordered.begin(), ordered.end(), termB );
177 BOOST_CHECK( itB != ordered.end() );
178}
179
180
181// Null graph and unset terminals must yield an empty result without caching, so
182// that a subsequent call once state is valid still rebuilds.
183BOOST_AUTO_TEST_CASE( NullGraphReturnsEmpty )
184{
186 Load( wxS( "net_chains_four_nets" ) );
187
188 SCH_NETCHAIN* chain = FindLargestPotentialChain();
190
191 const std::vector<wxString>& empty = chain->GetOrderedNets( nullptr );
192 BOOST_CHECK( empty.empty() );
193
194 // A subsequent valid call must still populate.
195 const std::vector<wxString>& populated = chain->GetOrderedNets( m_schematic->ConnectionGraph() );
196 BOOST_CHECK( !populated.empty() );
197}
198
199
200// A standalone SCH_NETCHAIN with no symbols and no terminals returns empty and
201// stays dirty so future, properly-set-up calls will populate.
202BOOST_AUTO_TEST_CASE( StandaloneEmptyChainStaysDirty )
203{
204 SCH_NETCHAIN bare;
205 const std::vector<wxString>& first = bare.GetOrderedNets( nullptr );
206 BOOST_CHECK( first.empty() );
207
208 bare.AddNet( wxS( "A" ) );
209 bare.AddNet( wxS( "B" ) );
210
211 // Still empty: no graph, no symbols, no terminals. Returns empty without crashing.
212 const std::vector<wxString>& second = bare.GetOrderedNets( nullptr );
213 BOOST_CHECK( second.empty() );
214}
215
216
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:37
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")