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 along
17 * with this program. If not, see <http://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 );
74 pad->SetSize( PADSTACK::ALL_LAYERS, VECTOR2I( pcbIUScale.mmToIU( 1 ), pcbIUScale.mmToIU( 1 ) ) );
75 fp->Add( pad );
76
77 PCB_SHAPE* shape = new PCB_SHAPE( fp, SHAPE_T::SEGMENT );
78 shape->SetLayer( F_Cu );
79 shape->SetStart( VECTOR2I( 0, 0 ) );
80 shape->SetEnd( VECTOR2I( pcbIUScale.mmToIU( 5 ), 0 ) );
81 fp->Add( shape );
82
83 auto items = m_board->AllConnectedItems();
84
85 bool foundPad = false;
86 bool foundShape = false;
87
88 for( BOARD_CONNECTED_ITEM* item : items )
89 {
90 if( item == pad )
91 foundPad = true;
92
93 if( item == shape )
94 foundShape = true;
95 }
96
97 BOOST_CHECK_MESSAGE( foundPad, "AllConnectedItems should include footprint pads" );
98 BOOST_CHECK_MESSAGE( foundShape, "AllConnectedItems should include footprint copper shapes" );
99}
100
101
105BOOST_AUTO_TEST_CASE( AllConnectedItems_IncludesFootprintZones )
106{
107 FOOTPRINT* fp = new FOOTPRINT( m_board.get() );
108 m_board->Add( fp );
109
110 ZONE* zone = new ZONE( fp );
111 zone->SetLayer( F_Cu );
112 zone->AppendCorner( VECTOR2I( 0, 0 ), -1 );
113 zone->AppendCorner( VECTOR2I( pcbIUScale.mmToIU( 5 ), 0 ), -1 );
114 zone->AppendCorner( VECTOR2I( pcbIUScale.mmToIU( 5 ), pcbIUScale.mmToIU( 5 ) ), -1 );
115 zone->AppendCorner( VECTOR2I( 0, pcbIUScale.mmToIU( 5 ) ), -1 );
116 fp->Add( zone );
117
118 auto items = m_board->AllConnectedItems();
119
120 bool foundZone = false;
121
122 for( BOARD_CONNECTED_ITEM* item : items )
123 {
124 if( item == zone )
125 foundZone = true;
126 }
127
128 BOOST_CHECK_MESSAGE( foundZone, "AllConnectedItems should include footprint zones" );
129}
130
131
137BOOST_AUTO_TEST_CASE( MapNets_RemapsFootprintShapes )
138{
139 // Source board simulates the clipboard board
140 std::unique_ptr<BOARD> srcBoard = std::make_unique<BOARD>();
141
142 NETINFO_ITEM* srcNet = new NETINFO_ITEM( srcBoard.get(), wxT( "TestNet" ), 1 );
143 srcBoard->Add( srcNet );
144
145 FOOTPRINT* fp = new FOOTPRINT( srcBoard.get() );
146 srcBoard->Add( fp );
147
148 PAD* pad = new PAD( fp );
150 pad->SetSize( PADSTACK::ALL_LAYERS, VECTOR2I( pcbIUScale.mmToIU( 1 ), pcbIUScale.mmToIU( 1 ) ) );
151 pad->SetNet( srcNet );
152 fp->Add( pad );
153
154 PCB_SHAPE* shape = new PCB_SHAPE( fp, SHAPE_T::SEGMENT );
155 shape->SetLayer( F_Cu );
156 shape->SetStart( VECTOR2I( 0, 0 ) );
157 shape->SetEnd( VECTOR2I( pcbIUScale.mmToIU( 5 ), 0 ) );
158 shape->SetNet( srcNet );
159 fp->Add( shape );
160
161 // Destination board
162 NETINFO_ITEM* destNet = new NETINFO_ITEM( m_board.get(), wxT( "TestNet" ), 1 );
163 m_board->Add( destNet );
164
165 // Remap nets from source to destination
166 srcBoard->MapNets( m_board.get() );
167
168 // After MapNets, all connected items should point to destination board nets
169 BOOST_CHECK_MESSAGE( pad->GetNet() != srcNet,
170 "Pad net should be remapped away from source net" );
171 BOOST_CHECK_MESSAGE( shape->GetNet() != srcNet,
172 "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 );
198 pad->SetSize( PADSTACK::ALL_LAYERS,
199 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 BOOST_CHECK_EQUAL( zone->GetLayer(), F_Cu );
316}
317
318
320BOOST_AUTO_TEST_CASE( ThievingZone_SetLayerSetClampsToOneLayer )
321{
322 ZONE* zone = MakeRectZone();
323 m_board->Add( zone );
325 BOOST_REQUIRE_EQUAL( zone->GetLayerSet().count(), 1u );
326
327 zone->SetLayerSet( LSET( { F_Cu, B_Cu, In1_Cu } ) );
328
329 BOOST_CHECK_EQUAL( zone->GetLayerSet().count(), 1u );
330}
331
332
337BOOST_AUTO_TEST_CASE( SolidCopperZone_AcceptsNetCodeViaBasePointer )
338{
339 NETINFO_ITEM* net = new NETINFO_ITEM( m_board.get(), wxT( "TestNet" ), 1 );
340 m_board->Add( net );
341
342 ZONE* zone = MakeRectZone();
344 m_board->Add( zone );
345
346 BOARD_CONNECTED_ITEM* base = zone;
347 base->SetNetCode( 1 );
348
349 BOOST_CHECK_EQUAL( zone->GetNetCode(), 1 );
350}
351
352
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:125
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:93
void SetStart(const VECTOR2I &aStart)
Definition eda_shape.h:198
void SetEnd(const VECTOR2I &aEnd)
Definition eda_shape.h:240
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
static constexpr PCB_LAYER_ID ALL_LAYERS
! Temporary layer identifier to identify code that is not padstack-aware
Definition padstack.h:177
Definition pad.h:55
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 SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
Implement an OUTPUTFORMATTER to a memory buffer.
Definition richio.h:422
const std::string & GetString()
Definition richio.h:445
Handle a list of polygons defining a copper zone.
Definition zone.h:74
virtual PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
Definition zone.cpp:536
virtual void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
Definition zone.cpp:603
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:585
void SetFillMode(ZONE_FILL_MODE aFillMode)
Definition zone.cpp:609
void SetLayerSet(const LSET &aLayerSet) override
Definition zone.cpp:628
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition zone.h:137
bool AppendCorner(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:1280
@ SEGMENT
Definition eda_shape.h:50
@ B_Cu
Definition layer_ids.h:65
@ In1_Cu
Definition layer_ids.h:66
@ F_Cu
Definition layer_ids.h:64
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()
nlohmann::json output
BOOST_CHECK_MESSAGE(totalMismatches==0, std::to_string(totalMismatches)+" board(s) with strategy disagreements")
BOOST_CHECK_EQUAL(result, "25.4")
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:687