KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_net_chain_terminal_pad_assignment.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, you may find one here:
18 * http://www.gnu.org/licenses/gpl-3.0.html
19 * or you may search the http://www.gnu.org website for the version 3 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
24#include <boost/test/unit_test.hpp>
25#include <board.h>
26#include <footprint.h>
27#include <pad.h>
28#include <netinfo.h>
30
31namespace
32{
33
34// Mirrors the assignment block in BOARD_NETLIST_UPDATER. Refactored here so a unit test can
35// exercise the storage rule independently of the rest of the updater. Any future divergence
36// between this and the production implementation is itself a bug worth catching.
37void AssignChainTerminalPads( BOARD* aBoard, const wxString& aChain, PAD* aPads[2] )
38{
39 for( int i = 0; i < 2; ++i )
40 {
41 if( !aPads[i] )
42 continue;
43
44 NETINFO_ITEM* termNet = aPads[i]->GetNet();
45
46 if( !termNet || termNet->GetNetChain() != aChain )
47 continue;
48
49 for( NETINFO_ITEM* net : aBoard->GetNetInfo() )
50 {
51 if( net != termNet && net->GetNetChain() == aChain
52 && net->GetTerminalPad( i ) )
53 {
54 net->SetTerminalPad( i, nullptr );
55 }
56 }
57
58 termNet->SetTerminalPad( i, aPads[i] );
59 }
60}
61
62PAD* MakePad( FOOTPRINT* aFp, NETINFO_ITEM* aNet, const wxString& aNumber, const VECTOR2I& aPos )
63{
64 PAD* pad = new PAD( aFp );
65 pad->SetFrontShape( PAD_SHAPE::CIRCLE );
66 pad->SetSize( F_Cu, VECTOR2I( 1000000, 1000000 ) );
67 pad->SetPosition( aPos );
68 pad->SetNumber( aNumber );
69 pad->SetNet( aNet );
70 aFp->Add( pad );
71 return pad;
72}
73
74} // namespace
75
76
77BOOST_AUTO_TEST_SUITE( NetChainTerminalPadAssignment )
78
79// Three-net chain Net1 -- Comp1 -- Net2 -- Comp2 -- Net3 with terminals on Net1 (slot 0) and
80// Net3 (slot 1). The middle interior net (Net2) must keep both slots null so the matched-length
81// stub predicate continues to treat it as "not on trunk".
82BOOST_AUTO_TEST_CASE( TerminalsOnlyAttachToOwningNet )
83{
84 std::unique_ptr<BOARD> board = std::make_unique<BOARD>();
85
86 NETINFO_ITEM* n1 = new NETINFO_ITEM( board.get(), wxS( "Net1" ), 1 );
87 NETINFO_ITEM* n2 = new NETINFO_ITEM( board.get(), wxS( "Net2" ), 2 );
88 NETINFO_ITEM* n3 = new NETINFO_ITEM( board.get(), wxS( "Net3" ), 3 );
89 board->Add( n1 );
90 board->Add( n2 );
91 board->Add( n3 );
92
93 n1->SetNetChain( wxS( "BUS_A" ) );
94 n2->SetNetChain( wxS( "BUS_A" ) );
95 n3->SetNetChain( wxS( "BUS_A" ) );
96
97 FOOTPRINT* src = new FOOTPRINT( board.get() );
98 src->SetReference( wxS( "U1" ) );
99 board->Add( src );
100
101 FOOTPRINT* mid = new FOOTPRINT( board.get() );
102 mid->SetReference( wxS( "R1" ) );
103 board->Add( mid );
104
105 FOOTPRINT* sink = new FOOTPRINT( board.get() );
106 sink->SetReference( wxS( "U2" ) );
107 board->Add( sink );
108
109 PAD* pSrc = MakePad( src, n1, wxS( "1" ), VECTOR2I( 0, 0 ) );
110 PAD* pMidA = MakePad( mid, n1, wxS( "1" ), VECTOR2I( 5000000, 0 ) );
111 PAD* pMidB = MakePad( mid, n2, wxS( "2" ), VECTOR2I( 6000000, 0 ) );
112 PAD* pSink = MakePad( sink, n3, wxS( "1" ), VECTOR2I( 15000000, 0 ) );
113
114 (void) pMidA;
115 (void) pMidB;
116
117 PAD* pads[2] = { pSrc, pSink };
118 AssignChainTerminalPads( board.get(), wxS( "BUS_A" ), pads );
119
120 BOOST_CHECK_EQUAL( n1->GetTerminalPad( 0 ), pSrc );
121 BOOST_CHECK( n1->GetTerminalPad( 1 ) == nullptr );
122
123 BOOST_CHECK( n2->GetTerminalPad( 0 ) == nullptr );
124 BOOST_CHECK( n2->GetTerminalPad( 1 ) == nullptr );
125
126 BOOST_CHECK( n3->GetTerminalPad( 0 ) == nullptr );
127 BOOST_CHECK_EQUAL( n3->GetTerminalPad( 1 ), pSink );
128}
129
130
131// A null pad in slot 1 must not clobber an existing assignment from a previous resolver pass
132// (the H-3 null-overwrite case). Only the slot we are providing is touched.
133BOOST_AUTO_TEST_CASE( NullPadDoesNotClobberExisting )
134{
135 std::unique_ptr<BOARD> board = std::make_unique<BOARD>();
136
137 NETINFO_ITEM* n1 = new NETINFO_ITEM( board.get(), wxS( "Net1" ), 1 );
138 NETINFO_ITEM* n2 = new NETINFO_ITEM( board.get(), wxS( "Net2" ), 2 );
139 board->Add( n1 );
140 board->Add( n2 );
141
142 n1->SetNetChain( wxS( "BUS_B" ) );
143 n2->SetNetChain( wxS( "BUS_B" ) );
144
145 FOOTPRINT* fp1 = new FOOTPRINT( board.get() );
146 fp1->SetReference( wxS( "U1" ) );
147 board->Add( fp1 );
148
149 FOOTPRINT* fp2 = new FOOTPRINT( board.get() );
150 fp2->SetReference( wxS( "U2" ) );
151 board->Add( fp2 );
152
153 PAD* pA = MakePad( fp1, n1, wxS( "1" ), VECTOR2I( 0, 0 ) );
154 PAD* pB = MakePad( fp2, n2, wxS( "1" ), VECTOR2I( 10000000, 0 ) );
155
156 n2->SetTerminalPad( 1, pB );
157
158 PAD* pads[2] = { pA, nullptr };
159 AssignChainTerminalPads( board.get(), wxS( "BUS_B" ), pads );
160
161 BOOST_CHECK_EQUAL( n1->GetTerminalPad( 0 ), pA );
162 BOOST_CHECK_EQUAL( n2->GetTerminalPad( 1 ), pB );
163 BOOST_CHECK( n1->GetTerminalPad( 1 ) == nullptr );
164 BOOST_CHECK( n2->GetTerminalPad( 0 ) == nullptr );
165}
166
167
168// Boards saved with the legacy broadcast assignment have the same pad pointer attached to every
169// member net. Re-running the resolver must clear the foreign claims so the middle net stops
170// reporting itself as on-trunk.
171BOOST_AUTO_TEST_CASE( StaleBroadcastSamePadIsCleared )
172{
173 std::unique_ptr<BOARD> board = std::make_unique<BOARD>();
174
175 NETINFO_ITEM* n1 = new NETINFO_ITEM( board.get(), wxS( "Net1" ), 1 );
176 NETINFO_ITEM* n2 = new NETINFO_ITEM( board.get(), wxS( "Net2" ), 2 );
177 NETINFO_ITEM* n3 = new NETINFO_ITEM( board.get(), wxS( "Net3" ), 3 );
178 board->Add( n1 );
179 board->Add( n2 );
180 board->Add( n3 );
181
182 n1->SetNetChain( wxS( "BUS_C" ) );
183 n2->SetNetChain( wxS( "BUS_C" ) );
184 n3->SetNetChain( wxS( "BUS_C" ) );
185
186 FOOTPRINT* src = new FOOTPRINT( board.get() );
187 src->SetReference( wxS( "U1" ) );
188 board->Add( src );
189
190 FOOTPRINT* sink = new FOOTPRINT( board.get() );
191 sink->SetReference( wxS( "U2" ) );
192 board->Add( sink );
193
194 PAD* pSrc = MakePad( src, n1, wxS( "1" ), VECTOR2I( 0, 0 ) );
195 PAD* pSnk = MakePad( sink, n3, wxS( "1" ), VECTOR2I( 10000000, 0 ) );
196
197 n1->SetTerminalPad( 0, pSrc );
198 n2->SetTerminalPad( 0, pSrc );
199 n3->SetTerminalPad( 0, pSrc );
200 n1->SetTerminalPad( 1, pSnk );
201 n2->SetTerminalPad( 1, pSnk );
202 n3->SetTerminalPad( 1, pSnk );
203
204 PAD* pads[2] = { pSrc, pSnk };
205 AssignChainTerminalPads( board.get(), wxS( "BUS_C" ), pads );
206
207 BOOST_CHECK_EQUAL( n1->GetTerminalPad( 0 ), pSrc );
208 BOOST_CHECK( n1->GetTerminalPad( 1 ) == nullptr );
209
210 BOOST_CHECK( n2->GetTerminalPad( 0 ) == nullptr );
211 BOOST_CHECK( n2->GetTerminalPad( 1 ) == nullptr );
212
213 BOOST_CHECK( n3->GetTerminalPad( 0 ) == nullptr );
214 BOOST_CHECK_EQUAL( n3->GetTerminalPad( 1 ), pSnk );
215}
216
217
218// Mirrors the matched-length predicate. With pads owned by Net1/Net3, Net2 must report
219// onTrunk=false even though all three nets share a chain.
220BOOST_AUTO_TEST_CASE( OnTrunkPredicateRequiresNetcodeMatch )
221{
222 std::unique_ptr<BOARD> board = std::make_unique<BOARD>();
223
224 NETINFO_ITEM* n1 = new NETINFO_ITEM( board.get(), wxS( "Net1" ), 1 );
225 NETINFO_ITEM* n2 = new NETINFO_ITEM( board.get(), wxS( "Net2" ), 2 );
226 NETINFO_ITEM* n3 = new NETINFO_ITEM( board.get(), wxS( "Net3" ), 3 );
227 board->Add( n1 );
228 board->Add( n2 );
229 board->Add( n3 );
230
231 FOOTPRINT* fp = new FOOTPRINT( board.get() );
232 fp->SetReference( wxS( "U1" ) );
233 board->Add( fp );
234
235 PAD* pA = MakePad( fp, n1, wxS( "1" ), VECTOR2I( 0, 0 ) );
236 PAD* pB = MakePad( fp, n3, wxS( "2" ), VECTOR2I( 1000000, 0 ) );
237
238 n1->SetTerminalPad( 0, pA );
239 n3->SetTerminalPad( 1, pB );
240
241 auto isOnTrunk = []( NETINFO_ITEM* aNet, int aNetCode )
242 {
243 return ( aNet->GetTerminalPad( 0 )
244 && aNet->GetTerminalPad( 0 )->GetNetCode() == aNetCode )
245 || ( aNet->GetTerminalPad( 1 )
246 && aNet->GetTerminalPad( 1 )->GetNetCode() == aNetCode );
247 };
248
249 BOOST_CHECK( isOnTrunk( n1, 1 ) );
250 BOOST_CHECK( isOnTrunk( n3, 3 ) );
251 BOOST_CHECK( !isOnTrunk( n2, 2 ) );
252
253 // Defense-in-depth: even if a stale broadcast slipped a foreign-net pad onto n2, the
254 // predicate refuses to be fooled because the netcodes mismatch.
255 n2->SetTerminalPad( 0, pA );
256 BOOST_CHECK( !isOnTrunk( n2, 2 ) );
257}
258
NETINFO_ITEM * GetNet() const
Return #NET_INFO object for a given item.
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:323
const NETINFO_LIST & GetNetInfo() const
Definition board.h:1004
void SetReference(const wxString &aReference)
Definition footprint.h:835
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Removes an item from the container.
Handle the data for a net.
Definition netinfo.h:50
const wxString & GetNetChain() const
Definition netinfo.h:115
PAD * GetTerminalPad(int aIndex) const
Definition netinfo.h:118
void SetNetChain(const wxString &aNetChain)
Definition netinfo.h:116
void SetTerminalPad(int aIndex, PAD *aPad)
Definition netinfo.h:119
Definition pad.h:55
@ F_Cu
Definition layer_ids.h:64
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_AUTO_TEST_SUITE(CadstarPartParser)
BOOST_AUTO_TEST_SUITE_END()
BOOST_AUTO_TEST_CASE(TerminalsOnlyAttachToOwningNet)
BOOST_CHECK_EQUAL(result, "25.4")
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:687