KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_board_connected_items.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
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
20#include <boost/test/unit_test.hpp>
21
22#include <board.h>
24#include <footprint.h>
25#include <pad.h>
26#include <pcb_shape.h>
27#include <pcb_track.h>
28#include <zone.h>
29#include <netinfo.h>
31
32
34{
36 {
37 m_board = std::make_unique<BOARD>();
38 }
39
44 {
45 ZONE* zone = new ZONE( m_board.get() );
46 zone->SetLayer( F_Cu );
47 zone->AppendCorner( VECTOR2I( 0, 0 ), -1 );
48 zone->AppendCorner( VECTOR2I( pcbIUScale.mmToIU( 5 ), 0 ), -1 );
49 zone->AppendCorner( VECTOR2I( pcbIUScale.mmToIU( 5 ), pcbIUScale.mmToIU( 5 ) ), -1 );
50 zone->AppendCorner( VECTOR2I( 0, pcbIUScale.mmToIU( 5 ) ), -1 );
51 return zone;
52 }
53
54 std::unique_ptr<BOARD> m_board;
55};
56
57
58BOOST_FIXTURE_TEST_SUITE( BoardConnectedItems, BOARD_CONNECTED_ITEMS_FIXTURE )
59
60
61
67BOOST_AUTO_TEST_CASE( AllConnectedItems_IncludesFootprintShapes )
68{
69 FOOTPRINT* fp = new FOOTPRINT( m_board.get() );
70 m_board->Add( fp );
71
72 PAD* pad = new PAD( fp );
73 pad->SetPadstackMode( PADSTACK::MODE::NORMAL );
75 pad->SetSize( PADSTACK::ALL_LAYERS, VECTOR2I( pcbIUScale.mmToIU( 1 ), pcbIUScale.mmToIU( 1 ) ) );
76 fp->Add( pad );
77
78 PCB_SHAPE* shape = new PCB_SHAPE( fp, SHAPE_T::SEGMENT );
79 shape->SetLayer( F_Cu );
80 shape->SetStart( VECTOR2I( 0, 0 ) );
81 shape->SetEnd( VECTOR2I( pcbIUScale.mmToIU( 5 ), 0 ) );
82 fp->Add( shape );
83
84 auto items = m_board->AllConnectedItems();
85
86 bool foundPad = false;
87 bool foundShape = false;
88
89 for( BOARD_CONNECTED_ITEM* item : items )
90 {
91 if( item == pad )
92 foundPad = true;
93
94 if( item == shape )
95 foundShape = true;
96 }
97
98 BOOST_CHECK_MESSAGE( foundPad, "AllConnectedItems should include footprint pads" );
99 BOOST_CHECK_MESSAGE( foundShape, "AllConnectedItems should include footprint copper shapes" );
100}
101
102
106BOOST_AUTO_TEST_CASE( AllConnectedItems_IncludesFootprintZones )
107{
108 FOOTPRINT* fp = new FOOTPRINT( m_board.get() );
109 m_board->Add( fp );
110
111 ZONE* zone = new ZONE( fp );
112 zone->SetLayer( F_Cu );
113 zone->AppendCorner( VECTOR2I( 0, 0 ), -1 );
114 zone->AppendCorner( VECTOR2I( pcbIUScale.mmToIU( 5 ), 0 ), -1 );
115 zone->AppendCorner( VECTOR2I( pcbIUScale.mmToIU( 5 ), pcbIUScale.mmToIU( 5 ) ), -1 );
116 zone->AppendCorner( VECTOR2I( 0, pcbIUScale.mmToIU( 5 ) ), -1 );
117 fp->Add( zone );
118
119 auto items = m_board->AllConnectedItems();
120
121 bool foundZone = false;
122
123 for( BOARD_CONNECTED_ITEM* item : items )
124 {
125 if( item == zone )
126 foundZone = true;
127 }
128
129 BOOST_CHECK_MESSAGE( foundZone, "AllConnectedItems should include footprint zones" );
130}
131
132
138BOOST_AUTO_TEST_CASE( MapNets_RemapsFootprintShapes )
139{
140 // Source board simulates the clipboard board
141 std::unique_ptr<BOARD> srcBoard = std::make_unique<BOARD>();
142
143 NETINFO_ITEM* srcNet = new NETINFO_ITEM( srcBoard.get(), wxT( "TestNet" ), 1 );
144 srcBoard->Add( srcNet );
145
146 FOOTPRINT* fp = new FOOTPRINT( srcBoard.get() );
147 srcBoard->Add( fp );
148
149 PAD* pad = new PAD( fp );
150 pad->SetPadstackMode( PADSTACK::MODE::NORMAL );
152 pad->SetSize( PADSTACK::ALL_LAYERS, VECTOR2I( pcbIUScale.mmToIU( 1 ), pcbIUScale.mmToIU( 1 ) ) );
153 pad->SetNet( srcNet );
154 fp->Add( pad );
155
156 PCB_SHAPE* shape = new PCB_SHAPE( fp, SHAPE_T::SEGMENT );
157 shape->SetLayer( F_Cu );
158 shape->SetStart( VECTOR2I( 0, 0 ) );
159 shape->SetEnd( VECTOR2I( pcbIUScale.mmToIU( 5 ), 0 ) );
160 shape->SetNet( srcNet );
161 fp->Add( shape );
162
163 // Destination board
164 NETINFO_ITEM* destNet = new NETINFO_ITEM( m_board.get(), wxT( "TestNet" ), 1 );
165 m_board->Add( destNet );
166
167 // Remap nets from source to destination
168 srcBoard->MapNets( m_board.get() );
169
170 // After MapNets, all connected items should point to destination board nets
171 BOOST_CHECK_MESSAGE( pad->GetNet() != srcNet, "Pad net should be remapped away from source net" );
172 BOOST_CHECK_MESSAGE( shape->GetNet() != srcNet, "Footprint shape net should be remapped away from source net" );
173 BOOST_CHECK( pad->GetNetname() == wxT( "TestNet" ) );
174 BOOST_CHECK( shape->GetNetname() == wxT( "TestNet" ) );
175}
176
177
182BOOST_AUTO_TEST_CASE( MapNets_FootprintShapeSurvivesSourceBoardDeletion )
183{
184 FOOTPRINT* fp = nullptr;
185
186 {
187 // Source board (clipboard) - will be destroyed at end of this scope
188 std::unique_ptr<BOARD> srcBoard = std::make_unique<BOARD>();
189
190 NETINFO_ITEM* srcNet = new NETINFO_ITEM( srcBoard.get(), wxT( "GND" ), 1 );
191 srcBoard->Add( srcNet );
192
193 fp = new FOOTPRINT( srcBoard.get() );
194 srcBoard->Add( fp );
195
196 PAD* pad = new PAD( fp );
197 pad->SetPadstackMode( PADSTACK::MODE::NORMAL );
199 pad->SetSize( PADSTACK::ALL_LAYERS, VECTOR2I( pcbIUScale.mmToIU( 1 ), pcbIUScale.mmToIU( 1 ) ) );
200 pad->SetNet( srcNet );
201 fp->Add( pad );
202
203 PCB_SHAPE* shape = new PCB_SHAPE( fp, SHAPE_T::SEGMENT );
204 shape->SetLayer( F_Cu );
205 shape->SetStart( VECTOR2I( 0, 0 ) );
206 shape->SetEnd( VECTOR2I( pcbIUScale.mmToIU( 5 ), 0 ) );
207 shape->SetNet( srcNet );
208 fp->Add( shape );
209
210 // Remap nets to destination board before source goes away
211 srcBoard->MapNets( m_board.get() );
212
213 // Remove footprint from source board (simulates placeBoardItems calling RemoveAll)
214 srcBoard->Remove( fp );
215 }
216
217 // Source board and its NETINFO_LIST are now destroyed.
218 // Move the footprint to the destination board.
219 fp->SetParent( m_board.get() );
220 m_board->Add( fp );
221
222 // Attempt to format the board. Before the fix, GetNetname() on the footprint
223 // shape would dereference a dangling pointer and crash.
224 STRING_FORMATTER formatter;
226 io.SetOutputFormatter( &formatter );
227 BOOST_CHECK_NO_THROW( io.Format( static_cast<const BOARD_ITEM*>( fp ) ) );
228
229 // Verify the formatted output contains the net name
230 std::string output = formatter.GetString();
231 BOOST_CHECK_MESSAGE( output.find( "GND" ) != std::string::npos,
232 "Formatted footprint should contain the remapped net name" );
233}
234
235
244BOOST_AUTO_TEST_CASE( ThievingZone_RejectsNetCodeViaBasePointer )
245{
246 NETINFO_ITEM* net = new NETINFO_ITEM( m_board.get(), wxT( "TestNet" ), 1 );
247 m_board->Add( net );
248
249 ZONE* zone = MakeRectZone();
251 m_board->Add( zone );
252
253 BOARD_CONNECTED_ITEM* base = zone;
254 base->SetNetCode( 1 );
255
256 BOOST_CHECK_EQUAL( zone->GetNetCode(), 0 );
257}
258
259
265BOOST_AUTO_TEST_CASE( ThievingZone_RejectsSetNetViaBasePointer )
266{
267 NETINFO_ITEM* net = new NETINFO_ITEM( m_board.get(), wxT( "TestNet" ), 1 );
268 m_board->Add( net );
269
270 ZONE* zone = MakeRectZone();
272 m_board->Add( zone );
273
274 BOARD_CONNECTED_ITEM* base = zone;
275 base->SetNet( net );
276
277 BOOST_CHECK( zone->GetNet() == nullptr );
278}
279
280
286BOOST_AUTO_TEST_CASE( ThievingZone_DropsNetWhenFillModeBecomesThieving )
287{
288 NETINFO_ITEM* net = new NETINFO_ITEM( m_board.get(), wxT( "TestNet" ), 1 );
289 m_board->Add( net );
290
291 ZONE* zone = MakeRectZone();
292 m_board->Add( zone );
293
294 zone->SetNetCode( 1 );
295 BOOST_REQUIRE_EQUAL( zone->GetNetCode(), 1 );
296
298
299 BOOST_CHECK_EQUAL( zone->GetNetCode(), 0 );
300}
301
302
304BOOST_AUTO_TEST_CASE( ThievingZone_ReducesToSingleLayerWhenFillModeBecomesThieving )
305{
306 ZONE* zone = MakeRectZone();
307 m_board->Add( zone );
308
309 zone->SetLayerSet( LSET( { F_Cu, B_Cu, In1_Cu } ) );
310 BOOST_REQUIRE_EQUAL( zone->GetLayerSet().count(), 3u );
311
313
314 BOOST_CHECK_EQUAL( zone->GetLayerSet().count(), 1u );
315}
316
317
319BOOST_AUTO_TEST_CASE( ThievingZone_SetLayerSetClampsToOneLayer )
320{
321 ZONE* zone = MakeRectZone();
322 m_board->Add( zone );
324 BOOST_REQUIRE_EQUAL( zone->GetLayerSet().count(), 1u );
325
326 zone->SetLayerSet( LSET( { F_Cu, B_Cu, In1_Cu } ) );
327
328 BOOST_CHECK_EQUAL( zone->GetLayerSet().count(), 1u );
329}
330
331
336BOOST_AUTO_TEST_CASE( SolidCopperZone_AcceptsNetCodeViaBasePointer )
337{
338 NETINFO_ITEM* net = new NETINFO_ITEM( m_board.get(), wxT( "TestNet" ), 1 );
339 m_board->Add( net );
340
341 ZONE* zone = MakeRectZone();
343 m_board->Add( zone );
344
345 BOARD_CONNECTED_ITEM* base = zone;
346 base->SetNetCode( 1 );
347
348 BOOST_CHECK_EQUAL( zone->GetNetCode(), 1 );
349}
350
351
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:121
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
virtual bool SetNetCode(int aNetCode, bool aNoAssert)
Set net using a net code.
virtual void SetNet(NETINFO_ITEM *aNetInfo)
Set a NET_INFO object for the item.
NETINFO_ITEM * GetNet() const
Return #NET_INFO object for a given item.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:84
virtual void SetParent(EDA_ITEM *aParent)
Definition eda_item.cpp:153
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Removes an item from the container.
LSET is a set of PCB_LAYER_IDs.
Definition lset.h:37
Handle the data for a net.
Definition netinfo.h:50
@ NORMAL
Shape is the same on all layers.
Definition padstack.h:170
static constexpr PCB_LAYER_ID ALL_LAYERS
! The layer identifier to use for the single defintion on normal padstacks
Definition padstack.h:179
Definition pad.h:61
A #PLUGIN derivation for saving and loading Pcbnew s-expression formatted files.
void Format(const BOARD_ITEM *aItem) const
Output aItem to aFormatter in s-expression format.
void SetOutputFormatter(OUTPUTFORMATTER *aFormatter)
void SetEnd(const VECTOR2I &aEnd) override
void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
void SetStart(const VECTOR2I &aStart) override
Implement an OUTPUTFORMATTER to a memory buffer.
Definition richio.h:430
const std::string & GetString()
Definition richio.h:453
Handle a list of polygons defining a copper zone.
Definition zone.h:70
bool AppendCorner(const VECTOR2I &aPosition, int aHoleIdx, bool aAllowDuplication=false)
Add a new corner to the zone outline (to the main outline or a hole)
Definition zone.cpp:1441
virtual void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
Definition zone.cpp:641
bool SetNetCode(int aNetCode, bool aNoAssert) override
Override that clamps the netcode to 0 when this zone is in copper-thieving fill mode.
Definition zone.cpp:623
void SetFillMode(ZONE_FILL_MODE aFillMode)
Definition zone.cpp:647
void SetLayerSet(const LSET &aLayerSet) override
Definition zone.cpp:666
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition zone.h:133
@ SEGMENT
Definition eda_shape.h:56
@ B_Cu
Definition layer_ids.h:61
@ In1_Cu
Definition layer_ids.h:62
@ F_Cu
Definition layer_ids.h:60
ZONE * MakeRectZone()
Build a 5x5 mm rectangular zone on F_Cu owned by m_board.
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_AUTO_TEST_CASE(AllConnectedItems_IncludesFootprintShapes)
Verify that AllConnectedItems includes copper shapes inside footprints.
BOOST_AUTO_TEST_SUITE_END()
BOOST_CHECK_EQUAL(result, "25.4")
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683