KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_net_chains_class_color.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 along
17 * with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include <boost/test/unit_test.hpp>
21
24
25#include <connection_graph.h>
26#include <schematic.h>
27#include <sch_netchain.h>
28#include <sch_sheet.h>
29#include <netclass.h>
30#include <project.h>
34#include <locale_io.h>
35
36
37// Test backdoor declared in connection_graph.h; defined in test_net_chain_save_root_only.cpp.
39 std::unique_ptr<SCH_NETCHAIN> aChain );
40
41
49
50
51// Validate that the connection graph correctly applies parsed netclass and color
52// overrides to committed net chains. This exercises the writer/parser/loader
53// glue added in the e3ea709483 / 769c2efb85 / dea7492211 / 3b3863a843 commit
54// chain without touching the file-format details directly.
55BOOST_FIXTURE_TEST_CASE( NetChain_ApplyClassAndColorOverrides, SIGNALS_CLASS_COLOR_FIXTURE )
56{
58 KI_TEST::LoadSchematic( m_settingsManager, wxString( "net_chains_four_nets" ),
59 m_schematic );
60
61 CONNECTION_GRAPH* graph = m_schematic->ConnectionGraph();
62 BOOST_REQUIRE( graph );
63
64 graph->Recalculate( m_schematic->BuildSheetListSortedByPageNumbers(), true );
65
66 // Seed override maps as if they had just been parsed from the schematic.
67 std::map<wxString, wxString> classes;
68 std::map<wxString, KIGFX::COLOR4D> colors;
69 classes[wxT( "MY_CHAIN" )] = wxT( "DDR_DATA" );
70 colors[wxT( "MY_CHAIN" )] = KIGFX::COLOR4D( 1.0, 0.5, 0.25, 1.0 );
71
72 graph->SetNetChainNetClassOverrides( classes );
73 graph->SetNetChainColorOverrides( colors );
74
75 // Promote the first detected potential chain so it gets a name we control.
76 const auto& potentials = graph->GetPotentialNetChains();
77 BOOST_REQUIRE( !potentials.empty() );
78
79 SCH_NETCHAIN* potential = potentials.front().get();
80 BOOST_REQUIRE( potential );
81
82 SCH_NETCHAIN* committed = graph->CreateNetChainFromPotential( potential, wxT( "MY_CHAIN" ) );
83 BOOST_REQUIRE( committed );
84 BOOST_CHECK_EQUAL( committed->GetName(), wxT( "MY_CHAIN" ) );
85
86 // The override maps should have been consulted at promotion time and
87 // copied onto the committed chain.
88 BOOST_CHECK_EQUAL( committed->GetNetClass(), wxT( "DDR_DATA" ) );
89 BOOST_CHECK( committed->GetColor() != KIGFX::COLOR4D::UNSPECIFIED );
90 BOOST_CHECK_CLOSE( committed->GetColor().r, 1.0, 1e-6 );
91 BOOST_CHECK_CLOSE( committed->GetColor().g, 0.5, 1e-6 );
92 BOOST_CHECK_CLOSE( committed->GetColor().b, 0.25, 1e-6 );
93 BOOST_CHECK_CLOSE( committed->GetColor().a, 1.0, 1e-6 );
94}
95
96
97// Validate that promoting a chain with no override leaves the chain in
98// its default ("no override") state. This guards against an off-by-one
99// where the override application leaks default values into chains that
100// shouldn't have any.
101BOOST_FIXTURE_TEST_CASE( NetChain_NoOverrideStaysDefault, SIGNALS_CLASS_COLOR_FIXTURE )
102{
104 KI_TEST::LoadSchematic( m_settingsManager, wxString( "net_chains_four_nets" ),
105 m_schematic );
106
107 CONNECTION_GRAPH* graph = m_schematic->ConnectionGraph();
108 BOOST_REQUIRE( graph );
109
110 graph->Recalculate( m_schematic->BuildSheetListSortedByPageNumbers(), true );
111
112 // Make sure the override maps are empty.
113 graph->SetNetChainNetClassOverrides( {} );
114 graph->SetNetChainColorOverrides( {} );
115
116 const auto& potentials = graph->GetPotentialNetChains();
117 BOOST_REQUIRE( !potentials.empty() );
118
119 SCH_NETCHAIN* committed = graph->CreateNetChainFromPotential( potentials.front().get(),
120 wxT( "OTHER" ) );
121 BOOST_REQUIRE( committed );
122
123 BOOST_CHECK( committed->GetNetClass().IsEmpty() );
124 BOOST_CHECK( committed->GetColor() == KIGFX::COLOR4D::UNSPECIFIED );
125}
126
127
128// Regression for https://gitlab.com/kicad/code/kicad/-/issues/24498
129//
130// A net chain may assign a netclass to every member net. On the PCB side
131// board_netlist_updater mirrors that override into NET_SETTINGS as chain-derived pattern
132// assignments, so each member net resolves to the chain's netclass. The schematic never
133// built the equivalent assignments, so GetEffectiveNetClass() (and the status-bar "Resolved
134// Netclass" entry) ignored the chain's class. ApplyNetChainNetclasses() closes that gap.
135BOOST_FIXTURE_TEST_CASE( NetChain_NetclassResolvesForMemberNets, SIGNALS_CLASS_COLOR_FIXTURE )
136{
138 KI_TEST::LoadSchematic( m_settingsManager, wxString( "net_chains_four_nets" ), m_schematic );
139
140 CONNECTION_GRAPH* graph = m_schematic->ConnectionGraph();
141 BOOST_REQUIRE( graph );
142
143 std::shared_ptr<NET_SETTINGS> ns = m_schematic->Project().GetProjectFile().NetSettings();
144 BOOST_REQUIRE( ns );
145
146 // The override only applies if the netclass exists, matching the board-side gating.
147 std::shared_ptr<NETCLASS> highSpeed = std::make_shared<NETCLASS>( wxT( "HighSpeed" ) );
148 ns->SetNetclass( wxT( "HighSpeed" ), highSpeed );
149
150 auto chain = std::make_unique<SCH_NETCHAIN>();
151 chain->SetName( wxT( "DQ_CHAIN" ) );
152 chain->AddNet( wxT( "/NET_A" ) );
153 chain->AddNet( wxT( "/NET_B" ) );
154 chain->SetNetClass( wxT( "HighSpeed" ) );
155 boost_test_inject_committed_net_chain( *graph, std::move( chain ) );
156
157 BOOST_CHECK_EQUAL( ns->GetEffectiveNetClass( wxT( "/NET_A" ) )->GetName(), wxString( NETCLASS::Default ) );
158
160
161 BOOST_CHECK_EQUAL( ns->GetEffectiveNetClass( wxT( "/NET_A" ) )->GetName(), wxString( wxT( "HighSpeed" ) ) );
162 BOOST_CHECK_EQUAL( ns->GetEffectiveNetClass( wxT( "/NET_B" ) )->GetName(), wxString( wxT( "HighSpeed" ) ) );
163}
164
165
166// Synthetic per-run member keys (SYNTHETIC_NET_PREFIX) embed subgraph codes that never match a
167// resolved net name, so ApplyNetChainNetclasses() must skip them rather than emit a dead pattern.
168BOOST_FIXTURE_TEST_CASE( NetChain_SyntheticMemberNetSkipped, SIGNALS_CLASS_COLOR_FIXTURE )
169{
171 KI_TEST::LoadSchematic( m_settingsManager, wxString( "net_chains_four_nets" ), m_schematic );
172
173 CONNECTION_GRAPH* graph = m_schematic->ConnectionGraph();
174 BOOST_REQUIRE( graph );
175
176 std::shared_ptr<NET_SETTINGS> ns = m_schematic->Project().GetProjectFile().NetSettings();
177 BOOST_REQUIRE( ns );
178
179 std::shared_ptr<NETCLASS> highSpeed = std::make_shared<NETCLASS>( wxT( "HighSpeed" ) );
180 ns->SetNetclass( wxT( "HighSpeed" ), highSpeed );
181
182 const wxString synthetic = wxString( SCH_NETCHAIN::SYNTHETIC_NET_PREFIX ) + wxT( "42" );
183
184 auto chain = std::make_unique<SCH_NETCHAIN>();
185 chain->SetName( wxT( "DQ_CHAIN" ) );
186 chain->AddNet( wxT( "/NET_A" ) );
187 chain->AddNet( synthetic );
188 chain->SetNetClass( wxT( "HighSpeed" ) );
189 boost_test_inject_committed_net_chain( *graph, std::move( chain ) );
190
192
193 BOOST_CHECK_EQUAL( ns->GetEffectiveNetClass( wxT( "/NET_A" ) )->GetName(), wxString( wxT( "HighSpeed" ) ) );
194 BOOST_CHECK_EQUAL( ns->GetEffectiveNetClass( synthetic )->GetName(), wxString( NETCLASS::Default ) );
195}
196
197
198// A chain referencing a netclass that no longer exists must not fabricate an assignment; the
199// member nets stay on the default netclass just as the board-side updater leaves them.
200BOOST_FIXTURE_TEST_CASE( NetChain_UnknownNetclassNotApplied, SIGNALS_CLASS_COLOR_FIXTURE )
201{
203 KI_TEST::LoadSchematic( m_settingsManager, wxString( "net_chains_four_nets" ), m_schematic );
204
205 CONNECTION_GRAPH* graph = m_schematic->ConnectionGraph();
206 BOOST_REQUIRE( graph );
207
208 std::shared_ptr<NET_SETTINGS> ns = m_schematic->Project().GetProjectFile().NetSettings();
209 BOOST_REQUIRE( ns );
210
211 auto chain = std::make_unique<SCH_NETCHAIN>();
212 chain->SetName( wxT( "DQ_CHAIN" ) );
213 chain->AddNet( wxT( "/NET_A" ) );
214 chain->SetNetClass( wxT( "Ghost" ) );
215 boost_test_inject_committed_net_chain( *graph, std::move( chain ) );
216
218
219 BOOST_CHECK_EQUAL( ns->GetEffectiveNetClass( wxT( "/NET_A" ) )->GetName(), wxString( NETCLASS::Default ) );
220}
221
222
223// A full connectivity recalculation must leave the chain-derived assignments in place, so the
224// status bar is correct on load and after every edit without an explicit ApplyNetChainNetclasses()
225// call. This drives the production buildConnectionGraph() path end to end.
226BOOST_FIXTURE_TEST_CASE( NetChain_NetclassSurvivesRecalculate, SIGNALS_CLASS_COLOR_FIXTURE )
227{
229 KI_TEST::LoadSchematic( m_settingsManager, wxString( "net_chains_four_nets" ), m_schematic );
230
231 CONNECTION_GRAPH* graph = m_schematic->ConnectionGraph();
232 BOOST_REQUIRE( graph );
233
234 SCH_SHEET_LIST sheets = m_schematic->BuildSheetListSortedByPageNumbers();
235 graph->Recalculate( sheets, true );
236
237 std::shared_ptr<NET_SETTINGS> ns = m_schematic->Project().GetProjectFile().NetSettings();
238 BOOST_REQUIRE( ns );
239
240 std::shared_ptr<NETCLASS> highSpeed = std::make_shared<NETCLASS>( wxT( "HighSpeed" ) );
241 ns->SetNetclass( wxT( "HighSpeed" ), highSpeed );
242
243 std::map<wxString, wxString> overrides;
244 overrides[wxT( "MY_CHAIN" )] = wxT( "HighSpeed" );
245 graph->SetNetChainNetClassOverrides( overrides );
246
247 const auto& potentials = graph->GetPotentialNetChains();
248 BOOST_REQUIRE( !potentials.empty() );
249
250 SCH_NETCHAIN* committed = graph->CreateNetChainFromPotential( potentials.front().get(),
251 wxT( "MY_CHAIN" ) );
252 BOOST_REQUIRE( committed );
253 BOOST_REQUIRE_EQUAL( committed->GetNetClass(), wxString( wxT( "HighSpeed" ) ) );
254
255 // Real (non-synthetic) member nets are the ones the resolver can match by name.
256 std::vector<wxString> namedNets;
257
258 for( const wxString& net : committed->GetNets() )
259 {
260 if( !net.StartsWith( SCH_NETCHAIN::SYNTHETIC_NET_PREFIX ) )
261 namedNets.push_back( net );
262 }
263
264 BOOST_REQUIRE( !namedNets.empty() );
265
266 // The recalculation rebuilds connectivity from scratch; the chain override must be
267 // reapplied automatically.
268 graph->Recalculate( sheets, true );
269
270 for( const wxString& net : namedNets )
271 BOOST_CHECK_EQUAL( ns->GetEffectiveNetClass( net )->GetName(), wxString( wxT( "HighSpeed" ) ) );
272}
273
274
275// Deleting the chain's netclass (e.g. on the Net Classes page) must not leave a stale
276// chain-derived assignment behind. Re-running ApplyNetChainNetclasses() clears the prior
277// entry and re-gates on HasNetclass(), so the member net falls back to the default netclass
278// instead of resolving to a phantom implicit class.
279BOOST_FIXTURE_TEST_CASE( NetChain_DeletedNetclassClearsStaleAssignment, SIGNALS_CLASS_COLOR_FIXTURE )
280{
282 KI_TEST::LoadSchematic( m_settingsManager, wxString( "net_chains_four_nets" ), m_schematic );
283
284 CONNECTION_GRAPH* graph = m_schematic->ConnectionGraph();
285 BOOST_REQUIRE( graph );
286
287 std::shared_ptr<NET_SETTINGS> ns = m_schematic->Project().GetProjectFile().NetSettings();
288 BOOST_REQUIRE( ns );
289
290 std::shared_ptr<NETCLASS> highSpeed = std::make_shared<NETCLASS>( wxT( "HighSpeed" ) );
291 ns->SetNetclass( wxT( "HighSpeed" ), highSpeed );
292
293 auto chain = std::make_unique<SCH_NETCHAIN>();
294 chain->SetName( wxT( "DQ_CHAIN" ) );
295 chain->AddNet( wxT( "/NET_A" ) );
296 chain->SetNetClass( wxT( "HighSpeed" ) );
297 boost_test_inject_committed_net_chain( *graph, std::move( chain ) );
298
300 BOOST_CHECK_EQUAL( ns->GetEffectiveNetClass( wxT( "/NET_A" ) )->GetName(),
301 wxString( wxT( "HighSpeed" ) ) );
302
303 // The netclass is removed; re-deriving must drop the now-orphaned assignment.
304 ns->ClearNetclasses();
306
307 BOOST_CHECK_EQUAL( ns->GetEffectiveNetClass( wxT( "/NET_A" ) )->GetName(),
308 wxString( NETCLASS::Default ) );
309}
Calculate the connectivity of a schematic and generates netlists.
void SetNetChainColorOverrides(const std::map< wxString, COLOR4D > &aOverrides)
void SetNetChainNetClassOverrides(const std::map< wxString, wxString > &aOverrides)
Stash per-net-chain netclass overrides read from the schematic file.
SCH_NETCHAIN * CreateNetChainFromPotential(SCH_NETCHAIN *aPotential, const wxString &aName)
Promote a potential net chain to an actual user net chain with the provided name.
void Recalculate(const SCH_SHEET_LIST &aSheetList, bool aUnconditional=false, std::function< void(SCH_ITEM *)> *aChangedItemHandler=nullptr, PROGRESS_REPORTER *aProgressReporter=nullptr)
Update the connection graph for the given list of sheets.
const std::vector< std::unique_ptr< SCH_NETCHAIN > > & GetPotentialNetChains() const
Potential net chains are inferred groupings produced by RebuildNetChains() but not yet user-committed...
void ApplyNetChainNetclasses()
Mirror each committed net chain's netclass override into the project NET_SETTINGS as a chain-derived ...
A color representation with 4 components: red, green, blue, alpha.
Definition color4d.h:105
double r
Red component.
Definition color4d.h:393
double g
Green component.
Definition color4d.h:394
double a
Alpha component.
Definition color4d.h:396
static const COLOR4D UNSPECIFIED
For legacy support; used as a value to indicate color hasn't been set yet.
Definition color4d.h:402
double b
Blue component.
Definition color4d.h:395
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
Definition locale_io.h:41
static const char Default[]
the name of the default NETCLASS
Definition netclass.h:44
A net chain is a collection of nets that are connected together through passive components.
const std::set< wxString > & GetNets() const
const wxString & GetNetClass() const
const KIGFX::COLOR4D & GetColor() const
const wxString & GetName() const
static constexpr char SYNTHETIC_NET_PREFIX[]
Prefix used when synthesising net names for unnamed subgraphs.
A container for handling SCH_SHEET_PATH objects in a flattened hierarchy.
void LoadSchematic(SETTINGS_MANAGER &aSettingsManager, const wxString &aRelPath, std::unique_ptr< SCHEMATIC > &aSchematic)
std::vector< FAB_LAYER_COLOR > dummy
std::unique_ptr< SCHEMATIC > m_schematic
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
void boost_test_inject_committed_net_chain(CONNECTION_GRAPH &aGraph, std::unique_ptr< SCH_NETCHAIN > aChain)
BOOST_FIXTURE_TEST_CASE(NetChain_ApplyClassAndColorOverrides, SIGNALS_CLASS_COLOR_FIXTURE)
const SHAPE_LINE_CHAIN chain
BOOST_CHECK_EQUAL(result, "25.4")