KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_net_chain_rollback.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 <connection_graph.h>
27#include <sch_netchain.h>
28#include <sch_label.h>
29#include <sch_screen.h>
30#include <sch_symbol.h>
31#include <schematic.h>
33#include <locale_io.h>
34
35#include <algorithm>
36#include <functional>
37#include <stdexcept>
38
39
41{
43
45 {
46 // Defensive cleanup so a failing test never leaks a hook into a sibling test.
48 }
49
51 std::unique_ptr<SCHEMATIC> m_schematic;
52};
53
54
55// A failed candidate must not publish newly committed chains or signal readiness.
56BOOST_FIXTURE_TEST_CASE( NetChain_RebuildFailureDiscardsCandidate,
58{
60 KI_TEST::LoadSchematic( m_settingsManager, wxString( "net_chains_four_nets" ),
61 m_schematic );
62
63 CONNECTION_GRAPH* graph = m_schematic->ConnectionGraph();
64 BOOST_REQUIRE( graph );
65
66 SCH_SHEET_LIST sheets = m_schematic->BuildSheetListSortedByPageNumbers();
67
68 graph->Recalculate( sheets, /*aUnconditional=*/true );
69 BOOST_REQUIRE( graph->NetChainsBuilt() );
70
71 const std::size_t baselineCount = graph->GetCommittedNetChains().size();
72 std::map<SCH_SYMBOL*, wxString> symbolNames;
73
74 for( const SCH_SHEET_PATH& path : sheets )
75 {
76 for( SCH_ITEM* item : path.LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
77 {
78 auto* symbol = static_cast<SCH_SYMBOL*>( item );
79 symbolNames.emplace( symbol, symbol->GetNetChainName() );
80 }
81 }
82
83 BOOST_REQUIRE( std::any_of( symbolNames.begin(), symbolNames.end(),
84 []( const auto& entry ) { return !entry.second.IsEmpty(); } ) );
85
86 bool hookFired = false;
89 {
90 hookFired = true;
91 BOOST_CHECK_THROW( candidate.Rebuild( {} ), std::logic_error );
92
93 BOOST_REQUIRE( !candidate.GetPotentialNetChains().empty() );
94 SCH_NETCHAIN* stray = candidate.CreateNetChainFromPotential(
95 candidate.GetPotentialNetChains().front().get(), "ROLLBACK_PARTIAL" );
96 BOOST_REQUIRE( stray );
97 BOOST_REQUIRE_GT( candidate.GetCommittedNetChains().size(), 0u );
98
99 throw std::runtime_error( "rollback test injected throw" );
100 };
101
102 BOOST_CHECK_THROW( graph->Recalculate( sheets, true ), std::runtime_error );
103
105
106 BOOST_CHECK( hookFired );
107 BOOST_CHECK_EQUAL( graph->GetCommittedNetChains().size(), baselineCount );
108 BOOST_CHECK( !graph->NetChainsBuilt() );
109 BOOST_CHECK( graph->GetNetChainByName( "ROLLBACK_PARTIAL" ) == nullptr );
110 BOOST_CHECK( !m_schematic->NetChains().GetNetChainMemberNetOverrides().contains( "ROLLBACK_PARTIAL" ) );
111 BOOST_CHECK( !m_schematic->NetChains().GetNetChainTerminalRefOverrides().contains( "ROLLBACK_PARTIAL" ) );
112
113 for( const auto& [symbol, name] : symbolNames )
114 BOOST_CHECK_EQUAL( symbol->GetNetChainName(), name );
115}
116
117
118// Unconditional graph reset leaves derived state empty until a rebuild succeeds.
119BOOST_FIXTURE_TEST_CASE( NetChain_RebuildFailureLeavesResetGraphUnbuilt,
121{
123 KI_TEST::LoadSchematic( m_settingsManager, wxString( "net_chains_four_nets" ),
124 m_schematic );
125
126 CONNECTION_GRAPH* graph = m_schematic->ConnectionGraph();
127 BOOST_REQUIRE( graph );
128
129 SCH_SHEET_LIST sheets = m_schematic->BuildSheetListSortedByPageNumbers();
130
131 BOOST_REQUIRE( graph->NetChainsBuilt() );
132 const std::size_t baselineCount = graph->GetCommittedNetChains().size();
133
134 bool hookFired = false;
137 {
138 hookFired = true;
139 throw std::runtime_error( "no-growth rollback test throw" );
140 };
141
142 BOOST_CHECK_THROW( graph->Recalculate( sheets, true ), std::runtime_error );
143
145
146 BOOST_CHECK( hookFired );
147
148 BOOST_CHECK( !graph->NetChainsBuilt() );
149 BOOST_CHECK_EQUAL( graph->GetCommittedNetChains().size(), baselineCount );
150 BOOST_CHECK( graph->GetPotentialNetChains().empty() );
151}
152
153
154BOOST_FIXTURE_TEST_CASE( NetChain_FailedRefreshPreservesCommittedPayload,
156{
157 LOCALE_IO locale;
158 KI_TEST::LoadSchematic( m_settingsManager, "net_chains_four_nets_labeled", m_schematic );
159 auto* graph = m_schematic->ConnectionGraph();
160 auto& chains = m_schematic->NetChains();
161 BOOST_REQUIRE( !chains.GetPotentialNetChains().empty() );
162 SCH_NETCHAIN* committed = chains.CreateNetChainFromPotential(
163 chains.GetPotentialNetChains().front().get(), "ATOMIC_CHAIN" );
164 BOOST_REQUIRE( committed );
165 const auto originalNets = committed->GetNets();
166 const auto originalMembers = chains.GetNetChainMemberNetOverrides();
167 const SCH_SHEET_LIST sheets = m_schematic->Hierarchy();
168 SCH_LABEL* renamed = nullptr;
169
170 for( const SCH_SHEET_PATH& path : sheets )
171 {
172 for( SCH_ITEM* item : path.LastScreen()->Items().OfType( SCH_LABEL_T ) )
173 {
174 auto* label = static_cast<SCH_LABEL*>( item );
175 auto* connection = label->Connection( &path );
176
177 if( connection && originalNets.contains( connection->Name() ) )
178 {
179 renamed = label;
180 break;
181 }
182 }
183
184 if( renamed )
185 break;
186 }
187
188 BOOST_REQUIRE( renamed );
189 renamed->SetText( "ATOMIC_RENAMED" );
190 bool hookFired = false;
193 {
194 hookFired = true;
195 throw std::runtime_error( "existing chain refresh failure" );
196 };
197
198 BOOST_CHECK_THROW( graph->Recalculate( sheets, true ), std::runtime_error );
199
201 BOOST_CHECK( hookFired );
202 BOOST_CHECK( chains.GetNetChainByName( "ATOMIC_CHAIN" ) == committed );
203 BOOST_CHECK( committed->GetNets() == originalNets );
204 // Graph reset retires raw symbol pointers before the manager transaction begins.
205 BOOST_CHECK( committed->GetSymbols().empty() );
206 BOOST_CHECK( chains.GetNetChainMemberNetOverrides() == originalMembers );
207 graph->Recalculate( sheets, true );
208 BOOST_CHECK( committed->GetNets().contains( "/ATOMIC_RENAMED" ) );
209 BOOST_CHECK( chains.GetNetChainMemberNetOverrides().at( "ATOMIC_CHAIN" ).contains( "/ATOMIC_RENAMED" ) );
210}
211
212
213BOOST_FIXTURE_TEST_CASE( NetChain_RebuildPublishesExistingAndNewChains, NETCHAIN_ROLLBACK_FIXTURE )
214{
215 LOCALE_IO locale;
216 KI_TEST::LoadSchematic( m_settingsManager, "net_chains_four_nets", m_schematic );
217 auto& chains = m_schematic->NetChains();
218 BOOST_REQUIRE( !chains.GetPotentialNetChains().empty() );
219 auto* original = chains.CreateNetChainFromPotential( chains.GetPotentialNetChains().front().get(),
220 "ORIGINAL_CHAIN" );
221 BOOST_REQUIRE( original );
223 {
224 BOOST_REQUIRE( !candidate.GetPotentialNetChains().empty() );
225 BOOST_REQUIRE( candidate.CreateNetChainFromPotential( candidate.GetPotentialNetChains().front().get(),
226 "ADDED_CHAIN" ) );
227 };
228 m_schematic->ConnectionGraph()->Recalculate( m_schematic->Hierarchy(), true );
230 BOOST_CHECK( chains.GetNetChainByName( "ORIGINAL_CHAIN" ) == original );
231 BOOST_CHECK( chains.GetNetChainByName( "ADDED_CHAIN" ) );
232 BOOST_CHECK( chains.NetChainsBuilt() );
233}
const char * name
Calculate the connectivity of a schematic and generate netlists.
SCH_NETCHAIN * GetNetChainByName(const wxString &aName)
static std::function< void(SCH_CONNECTIVITY::NETCHAIN_MANAGER &)> & RebuildNetChainsTestHook()
QA hook receives candidate state before publication and may throw to test rollback.
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...
bool NetChainsBuilt() const
Returns true once RebuildNetChains() has completed at least once on this graph.
const std::vector< std::unique_ptr< SCH_NETCHAIN > > & GetCommittedNetChains() const
Return user-created (committed) net chains (legacy accessor retained under net-chain API).
virtual void SetText(const wxString &aText)
Definition eda_text.cpp:231
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
Definition locale_io.h:37
Persistent chain configuration and the derived chains for one schematic.
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:165
SCH_CONNECTION * Connection(const SCH_SHEET_PATH *aSheet=nullptr) const
Retrieve the connection associated with this object in the given sheet.
Definition sch_item.cpp:503
A net chain is a collection of nets that are connected together through passive components.
const std::set< wxString > & GetNets() const
const std::set< class SCH_SYMBOL * > & GetSymbols() const
A container for handling SCH_SHEET_PATH objects in a flattened hierarchy.
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
Schematic symbol object.
Definition sch_symbol.h:75
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())
std::string path
BOOST_FIXTURE_TEST_CASE(NetChain_RebuildFailureDiscardsCandidate, NETCHAIN_ROLLBACK_FIXTURE)
BOOST_CHECK_EQUAL(result, "25.4")
@ SCH_SYMBOL_T
Definition typeinfo.h:168
@ SCH_LABEL_T
Definition typeinfo.h:163