KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_issue25119_bom_netlist_variant.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/*
21 * Regression test for https://gitlab.com/kicad/code/kicad/-/issues/25119
22 *
23 * The intermediate XML netlist feeding the legacy BOM tool is the flat view of the design,
24 * so it has to be resolved against the current variant. The board netlist is not: pcbnew
25 * reads the base design plus every variant and resolves it itself.
26 *
27 * Reuses the issue24217 fixture, where variant H0 overrides R1's value to 10k and R3's to
28 * 2M, and marks R2 and R3 DNP.
29 */
30
32
33#include <eeschema_helpers.h>
34#include <locale_io.h>
37#include <reporter.h>
38#include <sch_screen.h>
39#include <sch_sheet_path.h>
40#include <sch_symbol.h>
41#include <schematic.h>
42
43#include <wx/ffile.h>
44#include <wx/filename.h>
45#include <wx/xml/xml.h>
46
47
48namespace
49{
50
51wxXmlNode* findChild( wxXmlNode* aParent, const wxString& aName )
52{
53 for( wxXmlNode* child = aParent->GetChildren(); child; child = child->GetNext() )
54 {
55 if( child->GetName() == aName )
56 return child;
57 }
58
59 return nullptr;
60}
61
62
63wxXmlNode* findComponent( wxXmlNode* aRoot, const wxString& aRef )
64{
65 wxXmlNode* components = findChild( aRoot, wxT( "components" ) );
66
67 BOOST_REQUIRE( components );
68
69 for( wxXmlNode* comp = components->GetChildren(); comp; comp = comp->GetNext() )
70 {
71 if( comp->GetName() == wxT( "comp" ) && comp->GetAttribute( wxT( "ref" ) ) == aRef )
72 return comp;
73 }
74
75 return nullptr;
76}
77
78
79wxString componentValue( wxXmlNode* aRoot, const wxString& aRef )
80{
81 wxXmlNode* comp = findComponent( aRoot, aRef );
82
84
85 wxXmlNode* value = findChild( comp, wxT( "value" ) );
86
87 BOOST_REQUIRE( value );
88
89 return value->GetNodeContent();
90}
91
92
93bool hasProperty( wxXmlNode* aRoot, const wxString& aRef, const wxString& aName )
94{
95 wxXmlNode* comp = findComponent( aRoot, aRef );
96
98
99 for( wxXmlNode* prop = comp->GetChildren(); prop; prop = prop->GetNext() )
100 {
101 if( prop->GetName() == wxT( "property" ) && prop->GetAttribute( wxT( "name" ) ) == aName )
102 return true;
103 }
104
105 return false;
106}
107
108
109struct BOM_NETLIST_FIXTURE
110{
111 BOM_NETLIST_FIXTURE()
112 {
113 wxString schPath =
114 wxString::FromUTF8( KI_TEST::GetEeschemaTestDataDir() ) + wxS( "issue24217/issue24217.kicad_sch" );
115
116 m_schematic = EESCHEMA_HELPERS::LoadSchematic( schPath, true, true );
117 BOOST_REQUIRE( m_schematic );
118
119 m_netlistFile = wxFileName::CreateTempFileName( wxS( "kicad_issue25119" ) );
120 BOOST_REQUIRE( !m_netlistFile.IsEmpty() );
121 }
122
123 ~BOM_NETLIST_FIXTURE()
124 {
125 if( wxFileExists( m_netlistFile ) )
126 wxRemoveFile( m_netlistFile );
127 }
128
129 void WriteBomNetlist( wxXmlDocument& aDoc )
130 {
131 WX_STRING_REPORTER reporter;
132 NETLIST_EXPORTER_XML exporter( m_schematic );
133
134 BOOST_REQUIRE( exporter.WriteNetlist( m_netlistFile, GNL_OPT_BOM, reporter ) );
135 BOOST_REQUIRE( aDoc.Load( m_netlistFile ) );
136 BOOST_REQUIRE( aDoc.GetRoot() );
137 }
138
139 LOCALE_IO m_locale;
140 SCHEMATIC* m_schematic = nullptr;
141 wxString m_netlistFile;
142};
143
144} // namespace
145
146
147BOOST_FIXTURE_TEST_CASE( Issue25119_BomNetlistFollowsCurrentVariant, BOM_NETLIST_FIXTURE )
148{
149 m_schematic->SetCurrentVariant( wxS( "H0" ) );
150
151 BOOST_REQUIRE_EQUAL( m_schematic->GetCurrentVariant(), wxS( "H0" ) );
152
153 wxXmlDocument doc;
154 WriteBomNetlist( doc );
155
156 BOOST_CHECK_MESSAGE( !findChild( findComponent( doc.GetRoot(), wxS( "R1" ) ), wxS( "variants" ) ),
157 "resolved BOM netlist must not carry base-relative variant deltas" );
158
159 BOOST_CHECK_EQUAL( componentValue( doc.GetRoot(), wxS( "R1" ) ), wxS( "10k" ) );
160 BOOST_CHECK_EQUAL( componentValue( doc.GetRoot(), wxS( "R3" ) ), wxS( "2M" ) );
161
162 BOOST_CHECK_MESSAGE( hasProperty( doc.GetRoot(), wxS( "R2" ), wxS( "dnp" ) ), "R2 should be DNP in variant H0" );
163 BOOST_CHECK_MESSAGE( hasProperty( doc.GetRoot(), wxS( "R3" ), wxS( "dnp" ) ), "R3 should be DNP in variant H0" );
164 BOOST_CHECK_MESSAGE( !hasProperty( doc.GetRoot(), wxS( "R1" ), wxS( "dnp" ) ),
165 "R1 should not be DNP in variant H0" );
166}
167
168
169BOOST_FIXTURE_TEST_CASE( Issue25119_BomNetlistDefaultVariantUnchanged, BOM_NETLIST_FIXTURE )
170{
171 wxXmlDocument doc;
172 WriteBomNetlist( doc );
173
174 BOOST_CHECK_EQUAL( componentValue( doc.GetRoot(), wxS( "R1" ) ), wxS( "6k2" ) );
175 BOOST_CHECK_EQUAL( componentValue( doc.GetRoot(), wxS( "R3" ) ), wxS( "1M" ) );
176 BOOST_CHECK( !hasProperty( doc.GetRoot(), wxS( "R2" ), wxS( "dnp" ) ) );
177}
178
179
180BOOST_FIXTURE_TEST_CASE( Issue25119_BoardExclusionFollowsCurrentVariant, BOM_NETLIST_FIXTURE )
181{
182 SCH_SHEET_PATH sheet = m_schematic->Hierarchy().at( 0 );
183 SCH_SYMBOL* r1 = nullptr;
184
185 for( SCH_ITEM* item : sheet.LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
186 {
187 if( static_cast<SCH_SYMBOL*>( item )->GetRef( &sheet ) == wxS( "R1" ) )
188 r1 = static_cast<SCH_SYMBOL*>( item );
189 }
190
191 BOOST_REQUIRE( r1 );
193
194 // Same call the symbol properties dialog makes, so this lands on the variant only.
195 r1->SetExcludedFromBoard( true, &sheet, wxS( "H0" ) );
196
197 m_schematic->SetCurrentVariant( wxS( "H0" ) );
198 BOOST_REQUIRE_EQUAL( m_schematic->GetCurrentVariant(), wxS( "H0" ) );
199
200 wxXmlDocument doc;
201 WriteBomNetlist( doc );
202
203 BOOST_CHECK_MESSAGE( hasProperty( doc.GetRoot(), wxS( "R1" ), wxS( "exclude_from_board" ) ),
204 "R1 is excluded from the board in variant H0" );
205
206 m_schematic->SetCurrentVariant( wxEmptyString );
207
208 wxXmlDocument baseDoc;
209 WriteBomNetlist( baseDoc );
210
211 BOOST_CHECK_MESSAGE( !hasProperty( baseDoc.GetRoot(), wxS( "R1" ), wxS( "exclude_from_board" ) ),
212 "the base design must be unaffected" );
213}
214
215
216BOOST_FIXTURE_TEST_CASE( Issue25119_BoardNetlistKeepsBaseDesign, BOM_NETLIST_FIXTURE )
217{
218 m_schematic->SetCurrentVariant( wxS( "H0" ) );
219 BOOST_REQUIRE_EQUAL( m_schematic->GetCurrentVariant(), wxS( "H0" ) );
220
222 NETLIST_EXPORTER_KICAD exporter( m_schematic );
223
224 BOOST_REQUIRE( exporter.WriteNetlist( m_netlistFile, 0, reporter ) );
225
226 wxFFile file( m_netlistFile, wxS( "rb" ) );
227 wxString netlist;
228
229 BOOST_REQUIRE( file.IsOpened() );
230 BOOST_REQUIRE( file.ReadAll( &netlist ) );
231
232 BOOST_CHECK_MESSAGE( netlist.Contains( wxS( "(value \"6k2\")" ) ), "board netlist must keep R1's base value" );
233 BOOST_CHECK_MESSAGE( !netlist.Contains( wxS( "(value \"10k\")" ) ),
234 "board netlist must not resolve the variant into the base value" );
235
236 BOOST_CHECK_MESSAGE( netlist.Contains( wxS( "(name \"Value\") \"10k\"" ) ),
237 "board netlist must still carry R1's variant override for pcbnew" );
238}
static SCHEMATIC * LoadSchematic(const wxString &aFileName, bool aSetActive, bool aForceDefaultProject, PROJECT *aProject=nullptr, bool aCalculateConnectivity=true, REPORTER *aRootReporter=nullptr)
EE_TYPE OfType(KICAD_T aType) const
Definition sch_rtree.h:248
bool WriteNetlist(const wxString &aOutFileName, unsigned aNetlistOptions, REPORTER &aReporter)
Write to specified output file.
Generate the KiCad netlist format supported by Pcbnew.
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:165
EE_RTREE & Items()
Get the full RTree, usually for iterating.
Definition sch_screen.h:118
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
SCH_SCREEN * LastScreen()
SCH_SHEET * at(size_t aIndex) const
Forwarded method from std::vector.
Schematic symbol object.
Definition sch_symbol.h:75
bool GetExcludedFromBoard(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const override
void SetExcludedFromBoard(bool aEnable, const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) override
A wrapper for reporting to a wxString object.
Definition reporter.h:242
std::string GetEeschemaTestDataDir()
Get the configured location of Eeschema test data.
@ GNL_OPT_BOM
Definition of the SCH_SHEET_PATH and SCH_SHEET_LIST classes for Eeschema.
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_FIXTURE_TEST_CASE(Issue25119_BomNetlistFollowsCurrentVariant, BOM_NETLIST_FIXTURE)
std::string netlist
IbisParser parser & reporter
KIBIS_COMPONENT * comp
BOOST_CHECK_EQUAL(result, "25.4")
@ SCH_SYMBOL_T
Definition typeinfo.h:168