KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_netlist_exporter_xml_stacked.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
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, you may find one at
18 * http://www.gnu.org/licenses/
19 */
20
23
24#include <set>
25#include <vector>
26
27#include <schematic.h>
30
31#include <wx/filename.h>
32#include <wx/xml/xml.h>
33
41
42static std::set<wxString> as_set( const std::initializer_list<const char*>& init )
43{
44 std::set<wxString> out;
45 for( const char* s : init )
46 out.emplace( wxString::FromUTF8( s ) );
47 return out;
48}
49
50static wxXmlNode* find_child( wxXmlNode* parent, const wxString& name )
51{
52 for( wxXmlNode* child = parent->GetChildren(); child; child = child->GetNext() )
53 {
54 if( child->GetName() == name )
55 return child;
56 }
57
58 return nullptr;
59}
60
61static std::vector<wxXmlNode*> find_children( wxXmlNode* parent, const wxString& name )
62{
63 std::vector<wxXmlNode*> out;
64
65 for( wxXmlNode* child = parent->GetChildren(); child; child = child->GetNext() )
66 {
67 if( child->GetName() == name )
68 out.push_back( child );
69 }
70
71 return out;
72}
73
74static wxXmlNode* find_component( wxXmlNode* components, const wxString& ref )
75{
76 for( wxXmlNode* comp : find_children( components, wxT( "comp" ) ) )
77 {
78 if( comp->GetAttribute( wxT( "ref" ), wxEmptyString ) == ref )
79 return comp;
80 }
81
82 return nullptr;
83}
84
85static wxXmlNode* find_unit( wxXmlNode* units, const wxString& name )
86{
87 for( wxXmlNode* unit : find_children( units, wxT( "unit" ) ) )
88 {
89 if( unit->GetAttribute( wxT( "name" ), wxEmptyString ) == name )
90 return unit;
91 }
92
93 return nullptr;
94}
95
96static std::vector<wxString> get_pin_numbers( wxXmlNode* unit )
97{
98 std::vector<wxString> pins;
99 wxXmlNode* pinList = find_child( unit, wxT( "pins" ) );
100
101 BOOST_REQUIRE( pinList );
102
103 if( !pinList )
104 return pins;
105
106 for( wxXmlNode* pin : find_children( pinList, wxT( "pin" ) ) )
107 pins.push_back( pin->GetAttribute( wxT( "num" ), wxEmptyString ) );
108
109 return pins;
110}
111
112BOOST_FIXTURE_TEST_CASE( NetlistExporterXML_StackedPinNomenclature, XML_STACKED_PIN_FIXTURE )
113{
114 // Load schematic with stacked pin numbers
115 KI_TEST::LoadSchematic( m_settingsManager, wxT( "stacked_pin_nomenclature" ), m_schematic );
116
117 // Write XML netlist to a test file next to the project
118 wxFileName netFile = m_schematic->Project().GetProjectFullName();
119 netFile.SetName( netFile.GetName() + wxT( "_xml_test" ) );
120 netFile.SetExt( wxT( "xml" ) );
121
122 if( wxFileExists( netFile.GetFullPath() ) )
123 wxRemoveFile( netFile.GetFullPath() );
124
125 WX_STRING_REPORTER reporter;
126 std::unique_ptr<NETLIST_EXPORTER_XML> exporter =
127 std::make_unique<NETLIST_EXPORTER_XML>( m_schematic.get() );
128
129 bool success = exporter->WriteNetlist( netFile.GetFullPath(), 0, reporter );
130 BOOST_REQUIRE( success && reporter.GetMessages().IsEmpty() );
131
132 // Parse the XML back
133 wxXmlDocument xdoc;
134 BOOST_REQUIRE( xdoc.Load( netFile.GetFullPath() ) );
135
136 wxXmlNode* root = xdoc.GetRoot();
137 BOOST_REQUIRE( root );
138
139 wxXmlNode* nets = find_child( root, wxT( "nets" ) );
140 BOOST_REQUIRE( nets );
141
142 // Collect pin sets for R1 on each power net
143 std::set<wxString> setA;
144 std::set<wxString> setB;
145 int foundSets = 0;
146
147 for( wxXmlNode* net : find_children( nets, wxT( "net" ) ) )
148 {
149 wxString netName = net->GetAttribute( wxT( "name" ), wxEmptyString );
150 if( netName != wxT( "VCC" ) && netName != wxT( "GND" ) )
151 continue;
152
153 std::set<wxString>* target = ( foundSets == 0 ? &setA : &setB );
154
155 for( wxXmlNode* node : find_children( net, wxT( "node" ) ) )
156 {
157 if( node->GetAttribute( wxT( "ref" ), wxEmptyString ) != wxT( "R1" ) )
158 continue;
159
160 wxString pin = node->GetAttribute( wxT( "pin" ), wxEmptyString );
161 wxString pinfunction = node->GetAttribute( wxT( "pinfunction" ), wxEmptyString );
162 wxString pintype = node->GetAttribute( wxT( "pintype" ), wxEmptyString );
163
164 // Expect pinfunction to equal the expanded number when base name is empty
165 BOOST_CHECK_EQUAL( pinfunction, pin );
166 // Expect plain passive type (no +no_connect on these nets)
167 BOOST_CHECK_EQUAL( pintype, wxT( "passive" ) );
168
169 target->insert( pin );
170 }
171
172 foundSets++;
173 }
174
175 // We should have found two power nets with R1 nodes
176 BOOST_REQUIRE_EQUAL( foundSets, 2 );
177
178 // Expect one side to be 1..5 and the other to be 6,7,9,10,11 (order independent)
179 const std::set<wxString> expectedTop = as_set( { "1", "2", "3", "4", "5" } );
180 const std::set<wxString> expectedBot = as_set( { "6", "7", "9", "10", "11" } );
181
182 bool matchA = ( setA == expectedTop && setB == expectedBot );
183 bool matchB = ( setA == expectedBot && setB == expectedTop );
184 BOOST_CHECK( matchA || matchB );
185
186 // Cleanup test artifact
187 wxRemoveFile( netFile.GetFullPath() );
188}
189
190
191// OK, this isn't really a "stacked pin" test, but it's a convenient place to verify that the XML netlist exporter is correctly
192// resolving per-unit lib symbol metadata for components with multiple placed units.
193BOOST_FIXTURE_TEST_CASE( NetlistExporterXML_UsesPerUnitResolvedLibraryMetadata, XML_STACKED_PIN_FIXTURE )
194{
195 KI_TEST::LoadSchematic( m_settingsManager, wxT( "netlist_exporter_unit_metadata_per_unit" ), m_schematic );
196
197 wxFileName netFile = m_schematic->Project().GetProjectFullName();
198 netFile.SetName( netFile.GetName() + wxT( "_xml_unit_metadata_test" ) );
199 netFile.SetExt( wxT( "xml" ) );
200
201 if( wxFileExists( netFile.GetFullPath() ) )
202 wxRemoveFile( netFile.GetFullPath() );
203
204 WX_STRING_REPORTER reporter;
205 std::unique_ptr<NETLIST_EXPORTER_XML> exporter = std::make_unique<NETLIST_EXPORTER_XML>( m_schematic.get() );
206
207 bool success = exporter->WriteNetlist( netFile.GetFullPath(), 0, reporter );
208 BOOST_REQUIRE( success && reporter.GetMessages().IsEmpty() );
209
210 wxXmlDocument xdoc;
211 BOOST_REQUIRE( xdoc.Load( netFile.GetFullPath() ) );
212
213 wxXmlNode* root = xdoc.GetRoot();
214 BOOST_REQUIRE( root );
215
216 wxXmlNode* components = find_child( root, wxT( "components" ) );
217 BOOST_REQUIRE( components );
218
219 wxXmlNode* u1 = find_component( components, wxT( "U1" ) );
220 BOOST_REQUIRE( u1 );
221
222 wxXmlNode* units = find_child( u1, wxT( "units" ) );
223 BOOST_REQUIRE( units );
224
225 wxXmlNode* unitA = find_unit( units, wxT( "A" ) );
226 wxXmlNode* unitB = find_unit( units, wxT( "B" ) );
227 wxXmlNode* unitC = find_unit( units, wxT( "C" ) );
228
229 BOOST_REQUIRE( unitA );
230 BOOST_REQUIRE( unitB );
231 BOOST_REQUIRE( unitC );
232
233 const std::vector<wxString> expectedUnitA{ wxT( "3" ), wxT( "2" ), wxT( "1" ) };
234 const std::vector<wxString> expectedUnitB{ wxT( "6" ), wxT( "5" ), wxT( "7" ) };
235 const std::vector<wxString> expectedUnitC{ wxT( "8" ), wxT( "4" ) };
236
237 BOOST_CHECK( get_pin_numbers( unitA ) == expectedUnitA );
238 BOOST_CHECK( get_pin_numbers( unitB ) == expectedUnitB );
239 BOOST_CHECK( get_pin_numbers( unitC ) == expectedUnitC );
240
241 wxRemoveFile( netFile.GetFullPath() );
242}
const char * name
A wrapper for reporting to a wxString object.
Definition reporter.h:193
const wxString & GetMessages() const
Definition reporter.cpp:105
void LoadSchematic(SETTINGS_MANAGER &aSettingsManager, const wxString &aRelPath, std::unique_ptr< SCHEMATIC > &aSchematic)
std::unique_ptr< SCHEMATIC > m_schematic
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
KIBIS_COMPONENT * comp
KIBIS_PIN * pin
static wxXmlNode * find_unit(wxXmlNode *units, const wxString &name)
BOOST_FIXTURE_TEST_CASE(NetlistExporterXML_StackedPinNomenclature, XML_STACKED_PIN_FIXTURE)
static std::vector< wxString > get_pin_numbers(wxXmlNode *unit)
static wxXmlNode * find_child(wxXmlNode *parent, const wxString &name)
static std::vector< wxXmlNode * > find_children(wxXmlNode *parent, const wxString &name)
static std::set< wxString > as_set(const std::initializer_list< const char * > &init)
static wxXmlNode * find_component(wxXmlNode *components, const wxString &ref)
BOOST_CHECK_EQUAL(result, "25.4")