KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_pin_map.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 modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation, either version 3 of the License, or (at your
9 * option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
21
22#include <core/utf8.h>
23#include <pin_map.h>
24#include <lib_symbol.h>
25
26
27namespace
28{
29LIB_ID makeFp( const wxString& aLibNick, const wxString& aName )
30{
31 LIB_ID id;
32 id.SetLibNickname( aLibNick );
33 id.SetLibItemName( aName );
34 return id;
35}
36} // namespace
37
38
40
41
42BOOST_AUTO_TEST_CASE( EntrySetGetClear )
43{
44 PIN_MAP map( wxS( "STD-8" ) );
45
46 BOOST_CHECK( map.IsEmpty() );
47 BOOST_CHECK( !map.HasEntry( wxS( "1" ) ) );
48
49 map.SetEntry( wxS( "1" ), wxS( "1" ) );
50 map.SetEntry( wxS( "4" ), wxS( "[4,9]" ) );
51
52 BOOST_CHECK( map.HasEntry( wxS( "1" ) ) );
53 BOOST_CHECK_EQUAL( map.GetPadNumber( wxS( "1" ) ), wxS( "1" ) );
54 BOOST_CHECK_EQUAL( map.GetPadNumber( wxS( "4" ) ), wxS( "[4,9]" ) );
55 BOOST_CHECK_EQUAL( map.GetEntries().size(), 2u );
56
57 // GetPadNumber on a missing pin returns empty, never throws.
58 BOOST_CHECK( map.GetPadNumber( wxS( "99" ) ).IsEmpty() );
59
60 // Replace, not duplicate.
61 map.SetEntry( wxS( "1" ), wxS( "8" ) );
62 BOOST_CHECK_EQUAL( map.GetEntries().size(), 2u );
63 BOOST_CHECK_EQUAL( map.GetPadNumber( wxS( "1" ) ), wxS( "8" ) );
64
65 map.ClearEntry( wxS( "1" ) );
66 BOOST_CHECK( !map.HasEntry( wxS( "1" ) ) );
67 BOOST_CHECK_EQUAL( map.GetEntries().size(), 1u );
68
69 // Clearing a missing entry is a no-op.
70 map.ClearEntry( wxS( "99" ) );
71 BOOST_CHECK_EQUAL( map.GetEntries().size(), 1u );
72}
73
74
76{
77 const std::vector<wxString> pins = { wxS( "1" ), wxS( "2" ), wxS( "4" ) };
78
79 PIN_MAP empty( wxS( "Empty" ) );
80 BOOST_CHECK( empty.IsIdentity( pins ) );
81
82 PIN_MAP straight( wxS( "Straight" ) );
83 straight.SetEntry( wxS( "1" ), wxS( "1" ) );
84 straight.SetEntry( wxS( "2" ), wxS( "2" ) );
85 BOOST_CHECK( straight.IsIdentity( pins ) );
86
87 PIN_MAP swap( wxS( "Swap" ) );
88 swap.SetEntry( wxS( "1" ), wxS( "2" ) );
89 swap.SetEntry( wxS( "2" ), wxS( "1" ) );
90 BOOST_CHECK( !swap.IsIdentity( pins ) );
91
92 // A bracketed multi-pad entry is never identity even when one expanded pad
93 // matches the pin number.
94 PIN_MAP stacked( wxS( "Stacked" ) );
95 stacked.SetEntry( wxS( "4" ), wxS( "[4,9]" ) );
96 BOOST_CHECK( !stacked.IsIdentity( pins ) );
97}
98
99
100BOOST_AUTO_TEST_CASE( SetAddOrReplaceAndFind )
101{
102 PIN_MAP_SET set;
103
104 set.AddOrReplace( PIN_MAP( wxS( "STD-8" ) ) );
105 set.AddOrReplace( PIN_MAP( wxS( "DFN-8-EP" ) ) );
106
107 BOOST_CHECK_EQUAL( set.GetAll().size(), 2u );
108 BOOST_REQUIRE( set.FindByName( wxS( "STD-8" ) ) );
109 BOOST_CHECK_EQUAL( set.FindByName( wxS( "STD-8" ) )->GetName(), wxS( "STD-8" ) );
110 BOOST_CHECK( set.FindByName( wxS( "missing" ) ) == nullptr );
111
112 // Replace by name preserves count and order, and overwrites the entries.
113 PIN_MAP replacement( wxS( "STD-8" ) );
114 replacement.SetEntry( wxS( "1" ), wxS( "1" ) );
115 set.AddOrReplace( std::move( replacement ) );
116 BOOST_CHECK_EQUAL( set.GetAll().size(), 2u );
117 BOOST_CHECK_EQUAL( set.GetAll().front().GetName(), wxS( "STD-8" ) );
118 BOOST_CHECK( set.FindByName( wxS( "STD-8" ) )->HasEntry( wxS( "1" ) ) );
119
120 set.Remove( wxS( "DFN-8-EP" ) );
121 BOOST_CHECK_EQUAL( set.GetAll().size(), 1u );
122 BOOST_CHECK( set.FindByName( wxS( "DFN-8-EP" ) ) == nullptr );
123}
124
125
126BOOST_AUTO_TEST_CASE( SharedNamedMapReuse )
127{
128 // Two associated footprints can bind to one named map by name; editing the
129 // map changes both bindings because the map is stored once.
130 PIN_MAP_SET set;
131 set.AddOrReplace( PIN_MAP( wxS( "STD-8" ) ) );
132
133 ASSOCIATED_FOOTPRINT soic{ makeFp( wxS( "Package_SO" ), wxS( "SOIC-8" ) ), wxS( "STD-8" ) };
134 ASSOCIATED_FOOTPRINT vssop{ makeFp( wxS( "Package_SO" ), wxS( "VSSOP-8" ) ), wxS( "STD-8" ) };
135
136 BOOST_CHECK_EQUAL( soic.m_MapName, vssop.m_MapName );
137
138 set.FindByName( wxS( "STD-8" ) )->SetEntry( wxS( "1" ), wxS( "1" ) );
139
140 BOOST_CHECK( set.FindByName( soic.m_MapName )->HasEntry( wxS( "1" ) ) );
141 BOOST_CHECK( set.FindByName( vssop.m_MapName )->HasEntry( wxS( "1" ) ) );
142}
143
144
145BOOST_AUTO_TEST_CASE( LegacyPinMapConversion )
146{
147 // The database and HTTP backends both feed equal payloads through MakeLegacyPinMap, so they
148 // build identical PIN_MAPs. Multi-pad assignments become bracketed stacked notation.
149 std::unordered_map<wxString, std::vector<wxString>> assignments;
150 assignments[wxS( "1" )] = { wxS( "1" ) };
151 assignments[wxS( "4" )] = { wxS( "4" ), wxS( "9" ) };
152 assignments[wxS( "7" )] = {}; // empty assignment is skipped
153
154 PIN_MAP map = MakeLegacyPinMap( wxS( "Database" ), assignments );
155
156 BOOST_CHECK_EQUAL( map.GetName(), wxS( "Database" ) );
157 BOOST_CHECK_EQUAL( map.GetPadNumber( wxS( "1" ) ), wxS( "1" ) );
158 BOOST_CHECK_EQUAL( map.GetPadNumber( wxS( "4" ) ), wxS( "[4,9]" ) );
159 BOOST_CHECK( !map.HasEntry( wxS( "7" ) ) );
160 BOOST_CHECK_EQUAL( map.GetEntries().size(), 2u );
161
162 PIN_MAP httpMap = MakeLegacyPinMap( wxS( "Database" ), assignments );
163 BOOST_CHECK( map == httpMap );
164}
165
166
167BOOST_AUTO_TEST_CASE( OverrideDefaultsAndDelegate )
168{
170 BOOST_CHECK( ov.IsDefault() );
171 BOOST_CHECK( !ov.IsDelegate() );
172
173 ov.m_Edits.push_back( { wxS( "1" ), wxS( "8" ) } );
174 BOOST_CHECK( !ov.IsDefault() );
175
176 ov.m_Edits.clear();
178 ov.m_ActiveMapName = wxS( "X" );
179 BOOST_CHECK( !ov.IsDefault() );
180 BOOST_CHECK( !ov.IsDelegate() );
181
183 BOOST_CHECK( ov.IsDelegate() );
184 BOOST_CHECK( !ov.IsDefault() );
185}
186
187
188BOOST_AUTO_TEST_CASE( EqualityIsValueBased )
189{
190 PIN_MAP a( wxS( "M" ) );
191 PIN_MAP b( wxS( "M" ) );
192 BOOST_CHECK( a == b );
193
194 a.SetEntry( wxS( "1" ), wxS( "1" ) );
195 BOOST_CHECK( !( a == b ) );
196
197 b.SetEntry( wxS( "1" ), wxS( "1" ) );
198 BOOST_CHECK( a == b );
199
200 // The map name is part of identity.
201 b.SetName( wxS( "N" ) );
202 BOOST_CHECK( !( a == b ) );
203
204 // Associated footprints compare by both LIB_ID and map name.
205 ASSOCIATED_FOOTPRINT fa{ makeFp( wxS( "L" ), wxS( "F" ) ), wxS( "STD" ) };
206 ASSOCIATED_FOOTPRINT fb{ makeFp( wxS( "L" ), wxS( "F" ) ), wxS( "STD" ) };
207 BOOST_CHECK( fa == fb );
208
209 fb.m_MapName = wxS( "OTHER" );
210 BOOST_CHECK( !( fa == fb ) );
211}
212
213
214namespace
215{
216PIN_MAP_SET makeSet( const wxString& aMapName )
217{
218 PIN_MAP_SET set;
219 PIN_MAP map( aMapName );
220 map.SetEntry( wxS( "1" ), wxS( "8" ) );
221 set.AddOrReplace( std::move( map ) );
222 return set;
223}
224} // namespace
225
226
227BOOST_AUTO_TEST_CASE( CoupledInheritanceThreeLevels )
228{
229 // root holds the bundle; mid and leaf are empty and inherit it as one unit.
230 LIB_SYMBOL root( wxS( "root" ) );
231 root.SetPinMaps( makeSet( wxS( "ROOT-MAP" ) ) );
232 root.SetAssociatedFootprints( { { makeFp( wxS( "Package_SO" ), wxS( "SOIC-8" ) ), wxS( "ROOT-MAP" ) } } );
233
234 LIB_SYMBOL mid( wxS( "mid" ) );
235 mid.SetParent( &root );
236
237 LIB_SYMBOL leaf( wxS( "leaf" ) );
238 leaf.SetParent( &mid );
239
240 BOOST_REQUIRE( leaf.IsDerived() );
241
242 // Empty leaf inherits both halves of the bundle from the root.
243 BOOST_REQUIRE( leaf.GetEffectivePinMaps().FindByName( wxS( "ROOT-MAP" ) ) );
245 BOOST_CHECK_EQUAL( leaf.GetEffectiveAssociatedFootprints().front().m_MapName, wxS( "ROOT-MAP" ) );
246
247 // The leaf defines only its own association (no maps). Because the bundle is coupled, the
248 // leaf's (empty) map set replaces the parent's maps too - it does not keep ROOT-MAP.
249 leaf.SetAssociatedFootprints( { { makeFp( wxS( "Package_SO" ), wxS( "VSSOP-8" ) ), wxS( "LEAF-MAP" ) } } );
250
251 BOOST_CHECK( leaf.GetEffectivePinMaps().IsEmpty() );
253 BOOST_CHECK_EQUAL( leaf.GetEffectiveAssociatedFootprints().front().m_MapName, wxS( "LEAF-MAP" ) );
254
255 // mid still inherits the unchanged root bundle.
256 BOOST_REQUIRE( mid.GetEffectivePinMaps().FindByName( wxS( "ROOT-MAP" ) ) );
257}
258
259
260BOOST_AUTO_TEST_CASE( FlattenIsSelfContained )
261{
262 LIB_SYMBOL root( wxS( "root" ) );
263 root.SetPinMaps( makeSet( wxS( "ROOT-MAP" ) ) );
264 root.SetAssociatedFootprints( { { makeFp( wxS( "Package_SO" ), wxS( "SOIC-8" ) ), wxS( "ROOT-MAP" ) } } );
265
266 LIB_SYMBOL leaf( wxS( "leaf" ) );
267 leaf.SetParent( &root );
268
269 std::unique_ptr<LIB_SYMBOL> flat = leaf.Flatten();
270
271 BOOST_REQUIRE( flat );
272 BOOST_CHECK( !flat->IsDerived() );
273 BOOST_REQUIRE( flat->GetPinMaps().FindByName( wxS( "ROOT-MAP" ) ) );
274 BOOST_CHECK_EQUAL( flat->GetAssociatedFootprints().size(), 1u );
275}
276
277
278BOOST_AUTO_TEST_CASE( SharedMapReuseOnSymbol )
279{
280 LIB_SYMBOL sym( wxS( "dual" ) );
281 sym.PinMaps().AddOrReplace( PIN_MAP( wxS( "STD-8" ) ) );
283 { makeFp( wxS( "Package_SO" ), wxS( "SOIC-8" ) ), wxS( "STD-8" ) },
284 { makeFp( wxS( "Package_SO" ), wxS( "VSSOP-8" ) ), wxS( "STD-8" ) },
285 } );
286
287 // Editing the one named map is seen through both associations.
288 sym.PinMaps().FindByName( wxS( "STD-8" ) )->SetEntry( wxS( "1" ), wxS( "1" ) );
289
290 for( const ASSOCIATED_FOOTPRINT& assoc : sym.GetAssociatedFootprints() )
291 BOOST_CHECK( sym.GetPinMaps().FindByName( assoc.m_MapName )->HasEntry( wxS( "1" ) ) );
292}
293
294
295BOOST_AUTO_TEST_CASE( CompareDetectsBundleDifferences )
296{
297 // Compare a symbol against an exact copy so the baseline is genuinely equal; then mutate the
298 // pin-map bundle and confirm Compare() now reports a difference (otherwise rescue/diff/
299 // library-mismatch ERC would silently ignore map edits).
300 LIB_SYMBOL a( wxS( "part" ) );
301 a.SetPinMaps( makeSet( wxS( "M" ) ) );
302
303 LIB_SYMBOL b( a );
304 BOOST_CHECK_EQUAL( a.Compare( b ), 0 );
305
306 a.PinMaps().FindByName( wxS( "M" ) )->SetEntry( wxS( "2" ), wxS( "7" ) );
307 BOOST_CHECK( a.Compare( b ) != 0 );
308
309 LIB_SYMBOL c( b );
310 BOOST_CHECK_EQUAL( b.Compare( c ), 0 );
311
312 c.SetAssociatedFootprints( { { makeFp( wxS( "L" ), wxS( "F" ) ), wxS( "M" ) } } );
313 BOOST_CHECK( b.Compare( c ) != 0 );
314}
315
316
A logical library item identifier and consists of various portions much like a URI.
Definition lib_id.h:45
int SetLibNickname(const UTF8 &aLibNickname)
Override the logical library name portion of the LIB_ID to aLibNickname.
Definition lib_id.cpp:113
Define a library symbol object.
Definition lib_symbol.h:80
const std::vector< ASSOCIATED_FOOTPRINT > & GetEffectiveAssociatedFootprints() const
Definition lib_symbol.h:256
bool IsDerived() const
Definition lib_symbol.h:197
int Compare(const LIB_SYMBOL &aRhs, int aCompareFlags=0, REPORTER *aReporter=nullptr) const
Comparison test that can be used for operators.
void SetAssociatedFootprints(std::vector< ASSOCIATED_FOOTPRINT > aList)
Definition lib_symbol.h:228
void SetParent(LIB_SYMBOL *aParent=nullptr)
void SetPinMaps(const PIN_MAP_SET &aPinMaps)
Definition lib_symbol.h:224
const PIN_MAP_SET & GetEffectivePinMaps() const
Definition lib_symbol.h:241
const PIN_MAP_SET & GetPinMaps() const
Pin-to-pad mapping (issue #2282).
Definition lib_symbol.h:222
std::unique_ptr< LIB_SYMBOL > Flatten() const
Return a flattened symbol inheritance to the caller.
PIN_MAP_SET & PinMaps()
Definition lib_symbol.h:223
const std::vector< ASSOCIATED_FOOTPRINT > & GetAssociatedFootprints() const
Definition lib_symbol.h:226
A symbol-owned ordered set of named pin maps.
Definition pin_map.h:123
bool IsEmpty() const
Definition pin_map.h:139
const std::vector< PIN_MAP > & GetAll() const
Definition pin_map.h:138
void AddOrReplace(PIN_MAP aMap)
Insert aMap, replacing any existing entry with the same name.
Definition pin_map.cpp:113
void Remove(const wxString &aName)
Remove the map with the given name.
Definition pin_map.cpp:122
const PIN_MAP * FindByName(const wxString &aName) const
Definition pin_map.cpp:133
A named pin map.
Definition pin_map.h:64
void SetName(const wxString &aName)
Definition pin_map.h:70
const wxString & GetPadNumber(const wxString &aPinNumber) const
Definition pin_map.cpp:85
const std::vector< PIN_MAP_ENTRY > & GetEntries() const
Definition pin_map.h:91
const wxString & GetName() const
Definition pin_map.h:69
bool IsEmpty() const
Definition pin_map.h:93
bool HasEntry(const wxString &aPinNumber) const
Definition pin_map.cpp:79
void ClearEntry(const wxString &aPinNumber)
Remove the entry for aPinNumber.
Definition pin_map.cpp:70
bool IsIdentity(const std::vector< wxString > &aPinNumbers) const
Definition pin_map.cpp:95
void SetEntry(const wxString &aPinNumber, const wxString &aPadNumber)
Set the pad number for a symbol pin.
Definition pin_map.cpp:59
static bool empty(const wxTextEntryBase *aCtrl)
PIN_MAP MakeLegacyPinMap(const wxString &aName, const std::unordered_map< wxString, std::vector< wxString > > &aAssignments)
Build a single named PIN_MAP from a legacy symbol-pin to footprint-pad(s) assignment table (the flat ...
Definition pin_map.cpp:151
A first-class footprint choice on a LIB_SYMBOL, tied to a named pin map.
Definition pin_map.h:158
Per-instance override of the active pin map and a sparse delta on top.
Definition pin_map.h:199
std::vector< PIN_MAP_ENTRY > m_Edits
Definition pin_map.h:202
bool IsDefault() const
Definition pin_map.h:209
PIN_MAP_OVERRIDE_MODE m_Mode
Definition pin_map.h:200
bool IsDelegate() const
Definition pin_map.h:218
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_AUTO_TEST_SUITE(CadstarPartParser)
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_AUTO_TEST_SUITE_END()
BOOST_AUTO_TEST_CASE(EntrySetGetClear)
BOOST_CHECK_EQUAL(result, "25.4")