KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_net_chain_recalc_refresh.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>
30#include <locale_io.h>
31
32
33// Regression for [H-1]. CONNECTION_GRAPH::Reset() clears every committed chain's
34// non-owning symbol pointer set to drop stale SCH_SYMBOL references before the rest
35// of the graph is rebuilt. RebuildNetChains() then iterates the persisted override
36// maps and used to skip any name that was already in m_committedNetChains, leaving
37// the chain with an empty m_symbols and stale derived state. Downstream consumers
38// (netlist export, the setup panel, the tuner cache) trusted those caches.
39//
40// The fix refreshes the committed chain in place during the rebuild restore pass
41// rather than skipping it. This test exercises the full Recalculate(unconditional)
42// cycle and asserts the committed chain still has populated m_symbols and m_nets
43// afterwards.
51
52
53BOOST_FIXTURE_TEST_CASE( NetChain_RefreshCommittedChainAcrossUnconditionalRecalc,
55{
57 KI_TEST::LoadSchematic( m_settingsManager, wxString( "net_chains_four_nets" ), m_schematic );
58
59 CONNECTION_GRAPH* graph = m_schematic->ConnectionGraph();
60 BOOST_REQUIRE( graph );
61
62 SCH_SHEET_LIST sheets = m_schematic->BuildSheetListSortedByPageNumbers();
63 graph->Recalculate( sheets, /*aUnconditional=*/true );
64
65 const auto& potentials = graph->GetPotentialNetChains();
66 BOOST_REQUIRE( !potentials.empty() );
67
68 SCH_NETCHAIN* potential = potentials.front().get();
69 BOOST_REQUIRE( potential );
70
71 const std::set<wxString> originalNets = potential->GetNets();
72 const std::size_t originalNetCnt = originalNets.size();
73 const std::size_t originalSymCnt = potential->GetSymbols().size();
74
75 BOOST_REQUIRE_GT( originalNetCnt, 0u );
76 BOOST_REQUIRE_GT( originalSymCnt, 0u );
77
78 SCH_NETCHAIN* committed = graph->CreateNetChainFromPotential( potential, wxT( "REFRESH_TEST" ) );
79 BOOST_REQUIRE( committed );
80 BOOST_REQUIRE_EQUAL( committed->GetNets().size(), originalNetCnt );
81 BOOST_REQUIRE_EQUAL( committed->GetSymbols().size(), originalSymCnt );
82
83 // The hazard. Recalculate(true) -> Reset() clears m_symbols on every committed chain,
84 // and the rebuild restore pass used to skip names already present in
85 // m_committedNetChains, leaving the chain permanently empty.
86 graph->Recalculate( sheets, /*aUnconditional=*/true );
87
88 SCH_NETCHAIN* refreshed = graph->GetNetChainByName( wxT( "REFRESH_TEST" ) );
89 BOOST_REQUIRE_MESSAGE( refreshed,
90 "Committed chain disappeared across unconditional Recalculate" );
91
92 BOOST_CHECK_MESSAGE( !refreshed->GetSymbols().empty(),
93 "Committed chain has empty m_symbols after unconditional Recalculate; "
94 "Reset() cleared the cache and RebuildNetChains() failed to refresh it" );
95
96 BOOST_CHECK_MESSAGE( !refreshed->GetNets().empty(),
97 "Committed chain has empty m_nets after unconditional Recalculate" );
98
99 BOOST_CHECK_EQUAL( refreshed->GetNets().size(), originalNetCnt );
100 BOOST_CHECK_EQUAL( refreshed->GetSymbols().size(), originalSymCnt );
101
102 // Terminal pin/ref data must also survive the round trip; the setup panel and the PCB
103 // tuner walk these to find the bookend pads.
104 BOOST_CHECK( !refreshed->GetTerminalRef( 0 ).IsEmpty() );
105 BOOST_CHECK( !refreshed->GetTerminalRef( 1 ).IsEmpty() );
106
107 // A second round trip must remain stable (no slow leak of derived state).
108 graph->Recalculate( sheets, /*aUnconditional=*/true );
109
110 SCH_NETCHAIN* twice = graph->GetNetChainByName( wxT( "REFRESH_TEST" ) );
111 BOOST_REQUIRE( twice );
112 BOOST_CHECK( !twice->GetSymbols().empty() );
113 BOOST_CHECK( !twice->GetNets().empty() );
114 BOOST_CHECK_EQUAL( twice->GetNets().size(), originalNetCnt );
115 BOOST_CHECK_EQUAL( twice->GetSymbols().size(), originalSymCnt );
116}
117
118
119// Companion check. User-set netclass and color overrides live on the SCH_NETCHAIN itself
120// (not in the override map) once the chain is committed. The in-place refresh must NOT
121// reset them.
122BOOST_FIXTURE_TEST_CASE( NetChain_RefreshPreservesOverridesOnCommittedChain,
124{
126 KI_TEST::LoadSchematic( m_settingsManager, wxString( "net_chains_four_nets" ), m_schematic );
127
128 CONNECTION_GRAPH* graph = m_schematic->ConnectionGraph();
129 BOOST_REQUIRE( graph );
130
131 SCH_SHEET_LIST sheets = m_schematic->BuildSheetListSortedByPageNumbers();
132 graph->Recalculate( sheets, /*aUnconditional=*/true );
133
134 const auto& potentials = graph->GetPotentialNetChains();
135 BOOST_REQUIRE( !potentials.empty() );
136
137 SCH_NETCHAIN* committed = graph->CreateNetChainFromPotential( potentials.front().get(),
138 wxT( "OVERRIDE_TEST" ) );
139 BOOST_REQUIRE( committed );
140
141 committed->SetNetClass( wxT( "DDR_DATA" ) );
142 committed->SetColor( KIGFX::COLOR4D( 1.0, 0.5, 0.25, 1.0 ) );
143
144 graph->Recalculate( sheets, /*aUnconditional=*/true );
145
146 SCH_NETCHAIN* refreshed = graph->GetNetChainByName( wxT( "OVERRIDE_TEST" ) );
147 BOOST_REQUIRE( refreshed );
148
149 BOOST_CHECK_EQUAL( refreshed->GetNetClass(), wxT( "DDR_DATA" ) );
150 BOOST_CHECK( refreshed->GetColor() != KIGFX::COLOR4D::UNSPECIFIED );
151 BOOST_CHECK_CLOSE( refreshed->GetColor().r, 1.0, 1e-6 );
152 BOOST_CHECK_CLOSE( refreshed->GetColor().g, 0.5, 1e-6 );
153 BOOST_CHECK_CLOSE( refreshed->GetColor().b, 0.25, 1e-6 );
154}
155
156
157// Regression for [H-2]. ReplaceNetChainTerminalPin writes into m_netChainTerminalOverrides,
158// and the legacy pass-4 restore loop reapplies that override to potential chains by name.
159// The new in-place refresh helpers on the committed-chain path used to copy the source
160// chain's terminal pins unconditionally, silently undoing the user's "Replace terminal pin"
161// action across an unconditional Recalculate. The fix consults the override map first.
162BOOST_FIXTURE_TEST_CASE( NetChain_RefreshPreservesTerminalPinOverride,
164{
166 KI_TEST::LoadSchematic( m_settingsManager, wxString( "net_chains_four_nets" ), m_schematic );
167
168 CONNECTION_GRAPH* graph = m_schematic->ConnectionGraph();
169 BOOST_REQUIRE( graph );
170
171 SCH_SHEET_LIST sheets = m_schematic->BuildSheetListSortedByPageNumbers();
172 graph->Recalculate( sheets, /*aUnconditional=*/true );
173
174 const auto& potentials = graph->GetPotentialNetChains();
175 BOOST_REQUIRE( !potentials.empty() );
176
177 SCH_NETCHAIN* potential = potentials.front().get();
178 BOOST_REQUIRE( potential );
179
180 SCH_NETCHAIN* committed = graph->CreateNetChainFromPotential( potential, wxT( "TERM_OVERRIDE" ) );
181 BOOST_REQUIRE( committed );
182
183 const KIID originalPinA = committed->GetTerminalPinA();
184 const KIID originalPinB = committed->GetTerminalPinB();
185 BOOST_REQUIRE( originalPinA != niluuid );
186 BOOST_REQUIRE( originalPinB != niluuid );
187
188 // Synthesize a fresh KIID and retarget the A endpoint as if the user had selected
189 // "Replace terminal pin" on a different schematic pin. We don't need the new id to
190 // resolve to a real pin in the schematic; the override map only stores the raw KIIDs.
191 const KIID newPinA;
192 BOOST_REQUIRE( newPinA != originalPinA );
193
194 graph->ReplaceNetChainTerminalPin( wxT( "TERM_OVERRIDE" ), originalPinA, newPinA );
195
196 BOOST_REQUIRE_EQUAL( committed->GetTerminalPinA().AsString(), newPinA.AsString() );
197 BOOST_REQUIRE_EQUAL( committed->GetTerminalPinB().AsString(), originalPinB.AsString() );
198
199 graph->Recalculate( sheets, /*aUnconditional=*/true );
200
201 SCH_NETCHAIN* refreshed = graph->GetNetChainByName( wxT( "TERM_OVERRIDE" ) );
202 BOOST_REQUIRE( refreshed );
203
204 BOOST_CHECK_MESSAGE( refreshed->GetTerminalPinA() == newPinA,
205 "Refresh helper overwrote the user's terminal-pin override on pin A" );
206 BOOST_CHECK_MESSAGE( refreshed->GetTerminalPinB() == originalPinB,
207 "Refresh helper changed the unaffected terminal pin B" );
208
209 // Stability across a second round trip.
210 graph->Recalculate( sheets, /*aUnconditional=*/true );
211
212 SCH_NETCHAIN* twice = graph->GetNetChainByName( wxT( "TERM_OVERRIDE" ) );
213 BOOST_REQUIRE( twice );
214 BOOST_CHECK( twice->GetTerminalPinA() == newPinA );
215 BOOST_CHECK( twice->GetTerminalPinB() == originalPinB );
216}
Calculate the connectivity of a schematic and generates netlists.
SCH_NETCHAIN * GetNetChainByName(const wxString &aName)
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 ReplaceNetChainTerminalPin(const wxString &aNetChain, const KIID &aPrev, const KIID &aNew)
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
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
Definition kiid.h:48
wxString AsString() const
Definition kiid.cpp:244
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 KIID & GetTerminalPinB() const
const std::set< wxString > & GetNets() const
const wxString & GetTerminalRef(int aIdx) const
const wxString & GetNetClass() const
const KIGFX::COLOR4D & GetColor() const
const std::set< class SCH_SYMBOL * > & GetSymbols() const
void SetNetClass(const wxString &aNetClass)
Net chains may override the netclass applied to every member net.
void SetColor(const KIGFX::COLOR4D &aColor)
Optional display color for the chain.
const KIID & GetTerminalPinA() const
A container for handling SCH_SHEET_PATH objects in a flattened hierarchy.
KIID niluuid(0)
void LoadSchematic(SETTINGS_MANAGER &aSettingsManager, const wxString &aRelPath, std::unique_ptr< SCHEMATIC > &aSchematic)
std::vector< FAB_LAYER_COLOR > dummy
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_FIXTURE_TEST_CASE(NetChain_RefreshCommittedChainAcrossUnconditionalRecalc, NETCHAIN_RECALC_REFRESH_FIXTURE)
BOOST_CHECK_MESSAGE(totalMismatches==0, std::to_string(totalMismatches)+" board(s) with strategy disagreements")
BOOST_CHECK_EQUAL(result, "25.4")