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