KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_net_chain_hierarchical_roundtrip.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
22#include <connection_graph.h>
24#include <sch_netchain.h>
25#include <sch_screen.h>
26#include <sch_sheet.h>
27#include <schematic.h>
29#include <locale_io.h>
31
32#include <wx/ffile.h>
33#include <wx/filename.h>
34#include <wx/stdpaths.h>
35
36
37// Test backdoor declared in connection_graph.h. Pushes a fully-formed committed chain
38// into the graph so SaveSchematicFile has something to serialize.
40 std::unique_ptr<SCH_NETCHAIN> aChain );
41
42
44{
47 {
48 m_workDir.AssignDir( wxStandardPaths::Get().GetTempDir() );
49 m_workDir.AppendDir(
50 wxString::Format( wxT( "kicad_qa_netchain_hier_%lu" ),
51 static_cast<unsigned long>( wxGetProcessId() ) ) );
52
53 wxFileName::Mkdir( m_workDir.GetFullPath(), 0755, wxPATH_MKDIR_FULL );
54
55 wxString projectPath = m_workDir.GetFullPath() + wxT( "hier_roundtrip.kicad_pro" );
56 m_tempFiles.push_back( projectPath );
57
58 m_settingsManager.LoadProject( projectPath.ToStdString() );
60 }
61
63 {
64 m_schematic.reset();
65
66 for( const wxString& file : m_tempFiles )
67 {
68 if( wxFileExists( file ) )
69 wxRemoveFile( file );
70 }
71
72 if( m_workDir.DirExists() )
73 wxFileName::Rmdir( m_workDir.GetFullPath(), wxPATH_RMDIR_RECURSIVE );
74 }
75
76 wxString PathInWorkDir( const wxString& aLeaf )
77 {
78 wxString full = m_workDir.GetFullPath() + aLeaf;
79 m_tempFiles.push_back( full );
80 return full;
81 }
82
84 PROJECT* m_project = nullptr;
85 std::unique_ptr<SCHEMATIC> m_schematic;
86 wxFileName m_workDir;
87 std::vector<wxString> m_tempFiles;
88};
89
90
105BOOST_FIXTURE_TEST_CASE( NetChainHierarchicalRoundTripPreservesOverrides,
107{
109
110 const wxString chainName = wxT( "TEST_HIER_CHAIN" );
111 const wxString chainNetClass = wxT( "HighSpeed" );
112 const KIGFX::COLOR4D chainColor( 0.5, 0.25, 0.75, 1.0 );
113
114 m_schematic = std::make_unique<SCHEMATIC>( nullptr );
115 m_schematic->SetProject( m_project );
116 m_schematic->CreateDefaultScreens();
117
118 std::vector<SCH_SHEET*> topSheets = m_schematic->GetTopLevelSheets();
119 BOOST_REQUIRE( !topSheets.empty() );
120
121 SCH_SHEET* topSheet = topSheets[0];
122 SCH_SCREEN* topScreen = topSheet->GetScreen();
123 BOOST_REQUIRE( topScreen );
124
125 wxString rootFileName = PathInWorkDir( wxT( "hier_roundtrip.kicad_sch" ) );
126 wxString subFileName = PathInWorkDir( wxT( "hier_roundtrip_sub.kicad_sch" ) );
127
128 topSheet->SetFileName( wxT( "hier_roundtrip.kicad_sch" ) );
129 topScreen->SetFileName( rootFileName );
130
131 SCH_SHEET* subSheet = new SCH_SHEET( m_schematic.get() );
132 SCH_SCREEN* subScreen = new SCH_SCREEN( m_schematic.get() );
133 subSheet->SetName( wxT( "SubSheet" ) );
134 subSheet->SetFileName( wxT( "hier_roundtrip_sub.kicad_sch" ) );
135 subSheet->SetScreen( subScreen );
136 subScreen->SetFileName( subFileName );
137 topScreen->Append( subSheet );
138
139 m_schematic->RefreshHierarchy();
140
141 auto chain = std::make_unique<SCH_NETCHAIN>();
142 chain->SetName( chainName );
143 chain->AddNet( wxT( "/NET_A" ) );
144 chain->AddNet( wxT( "/NET_B" ) );
145 chain->SetTerminalRefs( wxT( "U1" ), wxT( "1" ), wxT( "U2" ), wxT( "2" ) );
146 chain->SetNetClass( chainNetClass );
147 chain->SetColor( chainColor );
148
149 boost_test_inject_committed_net_chain( *m_schematic->ConnectionGraph(), std::move( chain ) );
150
151 BOOST_REQUIRE_EQUAL( m_schematic->ConnectionGraph()->GetCommittedNetChains().size(), 1u );
152
153 SCH_IO_KICAD_SEXPR saver;
154 BOOST_REQUIRE_NO_THROW( saver.SaveSchematicFile( rootFileName, topSheet, m_schematic.get() ) );
155 BOOST_REQUIRE_NO_THROW( saver.SaveSchematicFile( subFileName, subSheet, m_schematic.get() ) );
156
157 BOOST_REQUIRE( wxFileExists( rootFileName ) );
158 BOOST_REQUIRE( wxFileExists( subFileName ) );
159
160 // Drop the in-memory schematic and reload from disk through the full IO plugin so
161 // that loadHierarchy walks both files via loadFile, exercising the gate.
162 m_schematic.reset();
163
164 auto reloaded = std::make_unique<SCHEMATIC>( nullptr );
165 reloaded->SetProject( m_project );
166
167 SCH_IO_KICAD_SEXPR loader;
168 SCH_SHEET* loadedRoot = nullptr;
169
170 BOOST_REQUIRE_NO_THROW( loadedRoot = loader.LoadSchematicFile( rootFileName, reloaded.get() ) );
171 BOOST_REQUIRE( loadedRoot );
172
173 reloaded->SetTopLevelSheets( { loadedRoot } );
174 reloaded->RefreshHierarchy();
175
176 const auto& classOverrides = reloaded->ConnectionGraph()->GetNetChainNetClassOverrides();
177 const auto& colorOverrides = reloaded->ConnectionGraph()->GetNetChainColorOverrides();
178 const auto& terminalOverrides = reloaded->ConnectionGraph()->GetNetChainTerminalRefOverrides();
179
181 classOverrides.size() == 1u,
182 "Net-chain netclass overrides were wiped during hierarchical load (size = "
183 << classOverrides.size() << ")" );
184
186 colorOverrides.size() == 1u,
187 "Net-chain color overrides were wiped during hierarchical load (size = "
188 << colorOverrides.size() << ")" );
189
191 terminalOverrides.size() == 1u,
192 "Net-chain terminal-ref overrides were wiped during hierarchical load (size = "
193 << terminalOverrides.size() << ")" );
194
195 auto classIt = classOverrides.find( chainName );
196 BOOST_REQUIRE( classIt != classOverrides.end() );
197 BOOST_CHECK_EQUAL( classIt->second, chainNetClass );
198
199 auto colorIt = colorOverrides.find( chainName );
200 BOOST_REQUIRE( colorIt != colorOverrides.end() );
201
202 // RGB channels are serialized as 0..255 integers and reconstructed by dividing by 255,
203 // so an exact equality check is not appropriate. Allow slightly more than 0.5/255 of
204 // slack to absorb rounding in either direction.
205 constexpr double colorTolerance = 1.0 / 255.0 + 1e-9;
206 BOOST_CHECK_SMALL( colorIt->second.r - chainColor.r, colorTolerance );
207 BOOST_CHECK_SMALL( colorIt->second.g - chainColor.g, colorTolerance );
208 BOOST_CHECK_SMALL( colorIt->second.b - chainColor.b, colorTolerance );
209 BOOST_CHECK_SMALL( colorIt->second.a - chainColor.a, 1e-3 );
210
211 auto termIt = terminalOverrides.find( chainName );
212 BOOST_REQUIRE( termIt != terminalOverrides.end() );
213 BOOST_CHECK_EQUAL( termIt->second.first.ref, wxT( "U1" ) );
214 BOOST_CHECK_EQUAL( termIt->second.first.pin, wxT( "1" ) );
215 BOOST_CHECK_EQUAL( termIt->second.second.ref, wxT( "U2" ) );
216 BOOST_CHECK_EQUAL( termIt->second.second.pin, wxT( "2" ) );
217
218 reloaded.reset();
219}
Calculate the connectivity of a schematic and generates netlists.
A color representation with 4 components: red, green, blue, alpha.
Definition color4d.h:101
double r
Red component.
Definition color4d.h:389
double g
Green component.
Definition color4d.h:390
double a
Alpha component.
Definition color4d.h:392
double b
Blue component.
Definition color4d.h:391
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
Definition locale_io.h:37
Container for project specific data.
Definition project.h:62
A SCH_IO derivation for loading schematic files using the new s-expression file format.
void SaveSchematicFile(const wxString &aFileName, SCH_SHEET *aSheet, SCHEMATIC *aSchematic, const std::map< std::string, UTF8 > *aProperties=nullptr) override
Write aSchematic to a storage file in a format that this SCH_IO implementation knows about,...
SCH_SHEET * LoadSchematicFile(const wxString &aFileName, SCHEMATIC *aSchematic, SCH_SHEET *aAppendToMe=nullptr, const std::map< std::string, UTF8 > *aProperties=nullptr) override
Load information from some input file format that this SCH_IO implementation knows about,...
void Append(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
void SetFileName(const wxString &aFileName)
Set the file name for this screen to aFileName.
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition sch_sheet.h:44
void SetFileName(const wxString &aFilename)
Definition sch_sheet.h:376
void SetName(const wxString &aName)
Definition sch_sheet.h:137
SCH_SCREEN * GetScreen() const
Definition sch_sheet.h:139
void SetScreen(SCH_SCREEN *aScreen)
Set the SCH_SCREEN associated with this sheet to aScreen.
std::vector< FAB_LAYER_COLOR > dummy
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(NetChainHierarchicalRoundTripPreservesOverrides, NETCHAIN_HIER_ROUNDTRIP_FIXTURE)
Regression: net-chain override maps (class, color, terminal refs) are schematic-level state owned by ...
BOOST_CHECK_MESSAGE(totalMismatches==0, std::to_string(totalMismatches)+" board(s) with strategy disagreements")
const SHAPE_LINE_CHAIN chain
BOOST_CHECK_EQUAL(result, "25.4")