KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_variant_field_resolution.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 2
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 here:
18 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19 * or you may search the http://www.gnu.org website for the version 2 license,
20 * or you may write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23
25#include "eeschema_test_utils.h"
26
27#include <sch_symbol.h>
28#include <sch_sheet_path.h>
29#include <lib_id.h>
31
32
34{
35public:
37 {
38 wxFileName fn( KI_TEST::GetEeschemaTestDataDir() );
39 fn.AppendDir( wxS( "variant_field_resolution" ) );
40 fn.SetName( wxS( "variant_field_resolution" ) );
42
43 LoadSchematic( fn.GetFullPath() );
44 }
45
47 {
48 SCH_SHEET_LIST hierarchy = m_schematic->Hierarchy();
49 SCH_SCREEN* screen = m_schematic->RootScreen();
50
51 for( SCH_ITEM* item : screen->Items().OfType( SCH_SYMBOL_T ) )
52 {
53 SCH_SYMBOL* sym = static_cast<SCH_SYMBOL*>( item );
54
55 if( sym->GetRef( &hierarchy[0] ) == wxS( "R1" ) )
56 return sym;
57 }
58
59 return nullptr;
60 }
61
63 {
64 SCH_SHEET_LIST hierarchy = m_schematic->Hierarchy();
65 KIID_PATH path = hierarchy[0].Path();
66
67 auto& instances = const_cast<std::vector<SCH_SYMBOL_INSTANCE>&>(
68 aSymbol->GetInstances() );
69
70 for( SCH_SYMBOL_INSTANCE& inst : instances )
71 {
72 if( inst.m_Path == path )
73 return &inst;
74 }
75
76 return nullptr;
77 }
78
79 void SetupVariantWithSymbolOverride( SCH_SYMBOL* aSymbol, const wxString& aVariantName,
80 const wxString& aLibIdStr )
81 {
82 SCH_SYMBOL_INSTANCE* inst = GetMutableInstance( aSymbol );
83 BOOST_REQUIRE( inst );
84
85 SCH_SYMBOL_VARIANT& variant = inst->m_Variants[aVariantName];
86 LIB_ID libId;
87 BOOST_REQUIRE( libId.Parse( aLibIdStr ) == -1 );
88 variant.m_SymbolOverride = libId;
89 }
90
91 void SetVariantField( SCH_SYMBOL* aSymbol, const wxString& aVariantName,
92 const wxString& aFieldName, const wxString& aValue )
93 {
94 SCH_SYMBOL_INSTANCE* inst = GetMutableInstance( aSymbol );
95 BOOST_REQUIRE( inst );
96
97 inst->m_Variants[aVariantName].m_Fields[aFieldName] = aValue;
98 }
99
100 void ClearVariants( SCH_SYMBOL* aSymbol )
101 {
102 SCH_SYMBOL_INSTANCE* inst = GetMutableInstance( aSymbol );
103
104 if( inst )
105 inst->m_Variants.clear();
106
107 aSymbol->ClearCaches();
108 }
109};
110
111
113{
114 LoadTestSchematic();
115
116 SCH_SYMBOL* r1 = GetR1();
117 BOOST_REQUIRE( r1 );
118
119 // No variant returns base value
120 {
121 wxString value =
122 r1->GetFieldText( wxS( "Value" ), &m_schematic->Hierarchy()[0], wxEmptyString );
123 BOOST_CHECK_EQUAL( value, wxS( "100R" ) );
124 }
125
126 // Explicit variant field override takes precedence over the base value
127 {
128 ClearVariants( r1 );
129 SetVariantField( r1, wxS( "ExplicitOnly" ), wxS( "Value" ), wxS( "220R" ) );
130
131 wxString value = r1->GetFieldText( wxS( "Value" ), &m_schematic->Hierarchy()[0],
132 wxS( "ExplicitOnly" ) );
133 BOOST_CHECK_EQUAL( value, wxS( "220R" ) );
134 }
135
136 // Explicit override on multiple fields simultaneously
137 {
138 ClearVariants( r1 );
139 SetVariantField( r1, wxS( "Multi" ), wxS( "Value" ), wxS( "470R" ) );
140 SetVariantField( r1, wxS( "Multi" ), wxS( "MPN" ), wxS( "CUSTOM-MPN-123" ) );
141
142 wxString value = r1->GetFieldText( wxS( "Value" ), &m_schematic->Hierarchy()[0],
143 wxS( "Multi" ) );
144 wxString mpn =
145 r1->GetFieldText( wxS( "MPN" ), &m_schematic->Hierarchy()[0], wxS( "Multi" ) );
146
147 BOOST_CHECK_EQUAL( value, wxS( "470R" ) );
148 BOOST_CHECK_EQUAL( mpn, wxS( "CUSTOM-MPN-123" ) );
149 }
150
151 // Reference is always resolved from the base instance
152 {
153 ClearVariants( r1 );
154 SetVariantField( r1, wxS( "RefTest" ), wxS( "Value" ), wxS( "999R" ) );
155
156 wxString ref = r1->GetFieldText( wxS( "Reference" ), &m_schematic->Hierarchy()[0],
157 wxS( "RefTest" ) );
158 BOOST_CHECK_EQUAL( ref, wxS( "R1" ) );
159 }
160
161 // An unresolvable symbol override with no explicit field override falls back to the base
162 // value.
163 {
164 ClearVariants( r1 );
165 SetupVariantWithSymbolOverride( r1, wxS( "BadAlt" ),
166 wxS( "nonexistent_lib:no_such_symbol" ) );
167
168 wxString value = r1->GetFieldText( wxS( "Value" ), &m_schematic->Hierarchy()[0],
169 wxS( "BadAlt" ) );
170 BOOST_CHECK_EQUAL( value, wxS( "100R" ) );
171 }
172
173 // Non-existent variant name falls back to base
174 {
175 ClearVariants( r1 );
176
177 wxString value = r1->GetFieldText( wxS( "Value" ), &m_schematic->Hierarchy()[0],
178 wxS( "NoSuchVariant" ) );
179 BOOST_CHECK_EQUAL( value, wxS( "100R" ) );
180 }
181
182 // Footprint explicit override
183 {
184 ClearVariants( r1 );
185 SetVariantField( r1, wxS( "FPTest" ), wxS( "Footprint" ),
186 wxS( "Resistor_SMD:R_0805_2012Metric" ) );
187
188 wxString fp = r1->GetFieldText( wxS( "Footprint" ), &m_schematic->Hierarchy()[0],
189 wxS( "FPTest" ) );
190 BOOST_CHECK_EQUAL( fp, wxS( "Resistor_SMD:R_0805_2012Metric" ) );
191 }
192
193 // Footprint without variant override returns base
194 {
195 ClearVariants( r1 );
196 SetVariantField( r1, wxS( "NoFP" ), wxS( "Value" ), wxS( "330R" ) );
197
198 wxString fp = r1->GetFieldText( wxS( "Footprint" ), &m_schematic->Hierarchy()[0],
199 wxS( "NoFP" ) );
200 BOOST_CHECK_EQUAL( fp, wxS( "Resistor_SMD:R_0402_1005Metric" ) );
201 }
202
203 // Multiple variants resolve independently
204 {
205 ClearVariants( r1 );
206 SetVariantField( r1, wxS( "VarA" ), wxS( "Value" ), wxS( "1K" ) );
207 SetVariantField( r1, wxS( "VarB" ), wxS( "Value" ), wxS( "10K" ) );
208
209 wxString valueA =
210 r1->GetFieldText( wxS( "Value" ), &m_schematic->Hierarchy()[0], wxS( "VarA" ) );
211 wxString valueB =
212 r1->GetFieldText( wxS( "Value" ), &m_schematic->Hierarchy()[0], wxS( "VarB" ) );
213
214 BOOST_CHECK_EQUAL( valueA, wxS( "1K" ) );
215 BOOST_CHECK_EQUAL( valueB, wxS( "10K" ) );
216 }
217
218 // Clearing variants and re-adding must not resolve through a stale cache
219 {
220 ClearVariants( r1 );
221 SetVariantField( r1, wxS( "CacheA" ), wxS( "Value" ), wxS( "FIRST" ) );
222
223 wxString value1 = r1->GetFieldText( wxS( "Value" ), &m_schematic->Hierarchy()[0],
224 wxS( "CacheA" ) );
225 BOOST_CHECK_EQUAL( value1, wxS( "FIRST" ) );
226
227 ClearVariants( r1 );
228 SetVariantField( r1, wxS( "CacheA" ), wxS( "Value" ), wxS( "SECOND" ) );
229
230 wxString value2 = r1->GetFieldText( wxS( "Value" ), &m_schematic->Hierarchy()[0],
231 wxS( "CacheA" ) );
232 BOOST_CHECK_EQUAL( value2, wxS( "SECOND" ) );
233 }
234}
235
236
238{
239 LoadTestSchematic();
240
241 SCH_SYMBOL* r1 = GetR1();
242 BOOST_REQUIRE( r1 );
243
244 SCH_SHEET_LIST hierarchy = m_schematic->Hierarchy();
245 SCH_SHEET_PATH& sheet = hierarchy[0];
246
247 // Writing back the resolved value must not materialize an explicit override
248 {
249 ClearVariants( r1 );
250 SetupVariantWithSymbolOverride( r1, wxS( "RoundTrip" ), wxS( "variant_test_lib:R_10K" ) );
251
252 wxString resolved = r1->GetFieldText( wxS( "Value" ), &sheet, wxS( "RoundTrip" ) );
253 r1->SetFieldText( wxS( "Value" ), resolved, &sheet, wxS( "RoundTrip" ) );
254
255 std::optional<SCH_SYMBOL_VARIANT> variant = r1->GetVariant( sheet, wxS( "RoundTrip" ) );
256 BOOST_REQUIRE( variant.has_value() );
257 BOOST_CHECK( !variant->m_Fields.contains( wxS( "Value" ) ) );
258 }
259
260 // A real edit creates an override and reverting the edit erases it again
261 {
262 r1->SetFieldText( wxS( "Value" ), wxS( "EDITED" ), &sheet, wxS( "RoundTrip" ) );
263
264 std::optional<SCH_SYMBOL_VARIANT> variant = r1->GetVariant( sheet, wxS( "RoundTrip" ) );
265 BOOST_REQUIRE( variant.has_value() );
266 BOOST_CHECK( variant->m_Fields.contains( wxS( "Value" ) ) );
267
268 wxString baseValue = r1->GetFieldText( wxS( "Value" ), &sheet, wxEmptyString );
269 r1->SetFieldText( wxS( "Value" ), baseValue, &sheet, wxS( "RoundTrip" ) );
270
271 variant = r1->GetVariant( sheet, wxS( "RoundTrip" ) );
272 BOOST_REQUIRE( variant.has_value() );
273 BOOST_CHECK( !variant->m_Fields.contains( wxS( "Value" ) ) );
274 }
275}
EE_TYPE OfType(KICAD_T aType) const
Definition sch_rtree.h:221
A generic fixture for loading schematics and associated settings for qa tests.
std::unique_ptr< SCHEMATIC > m_schematic
virtual void LoadSchematic(const wxFileName &aFn)
A logical library item identifier and consists of various portions much like a URI.
Definition lib_id.h:45
int Parse(const UTF8 &aId, bool aFix=false)
Parse LIB_ID with the information from aId.
Definition lib_id.cpp:65
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:162
EE_RTREE & Items()
Get the full RTree, usually for iterating.
Definition sch_screen.h:115
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...
Variant information for a schematic symbol.
std::optional< LIB_ID > m_SymbolOverride
Alternate library symbol to substitute for the base symbol in this variant, if any.
Schematic symbol object.
Definition sch_symbol.h:69
const std::vector< SCH_SYMBOL_INSTANCE > & GetInstances() const
Definition sch_symbol.h:128
void SetFieldText(const wxString &aFieldName, const wxString &aFieldText, const SCH_SHEET_PATH *aPath=nullptr, const wxString &aVariantName=wxEmptyString)
wxString GetFieldText(const wxString &aFieldName, const SCH_SHEET_PATH *aPath=nullptr, const wxString &aVariantName=wxEmptyString) const
void ClearCaches() override
std::optional< SCH_SYMBOL_VARIANT > GetVariant(const SCH_SHEET_PATH &aInstance, const wxString &aVariantName) const
const wxString GetRef(const SCH_SHEET_PATH *aSheet, bool aIncludeUnit=false) const override
void SetVariantField(SCH_SYMBOL *aSymbol, const wxString &aVariantName, const wxString &aFieldName, const wxString &aValue)
void SetupVariantWithSymbolOverride(SCH_SYMBOL *aSymbol, const wxString &aVariantName, const wxString &aLibIdStr)
SCH_SYMBOL_INSTANCE * GetMutableInstance(SCH_SYMBOL *aSymbol)
static const std::string KiCadSchematicFileExtension
std::string GetEeschemaTestDataDir()
Get the configured location of Eeschema test data.
Definition of the SCH_SHEET_PATH and SCH_SHEET_LIST classes for Eeschema.
A simple container for schematic symbol instance information.
std::map< wxString, SCH_SYMBOL_VARIANT > m_Variants
A list of symbol variants.
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
std::string path
BOOST_CHECK_EQUAL(result, "25.4")
BOOST_FIXTURE_TEST_CASE(VariantFieldResolution, TEST_VARIANT_FIELD_RESOLUTION_FIXTURE)
@ SCH_SYMBOL_T
Definition typeinfo.h:169
Definition of file extensions used in Kicad.