KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_board_item_index.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, see <https://www.gnu.org/licenses/>.
18 */
19
20#include <boost/test/unit_test.hpp>
21
22#include <memory>
23
24#include <board.h>
25#include <footprint.h>
26#include <pad.h>
27#include <pcb_shape.h>
28
29
30BOOST_AUTO_TEST_SUITE( BoardItemIndex )
31
32
33BOOST_AUTO_TEST_CASE( SwapItemDataReindexesFootprintChildren )
34{
35 BOARD* board = new BOARD();
36
37 auto footprint = std::make_unique<FOOTPRINT>( board );
38 auto pad = new PAD( footprint.get() );
39 pad->SetNumber( "1" );
40
41 PAD* originalPad = pad;
42 KIID originalPadId = originalPad->m_Uuid;
43
44 footprint->Add( pad );
45
46 FOOTPRINT* liveFootprint = footprint.get();
47 board->Add( footprint.release() );
48
49 auto image = std::unique_ptr<FOOTPRINT>( static_cast<FOOTPRINT*>( liveFootprint->Clone() ) );
50
51 liveFootprint->SwapItemData( image.get() );
52 image.reset();
53
54 BOARD_ITEM* resolved = board->ResolveItem( originalPadId, true );
55
56 BOOST_REQUIRE( resolved );
57 BOOST_CHECK_EQUAL( resolved->Type(), PCB_PAD_T );
58 BOOST_CHECK( resolved != originalPad );
59
60 delete board;
61}
62
63
64BOOST_AUTO_TEST_CASE( AttachedItemUuidRewriteDropsOldAlias )
65{
66 BOARD* board = new BOARD();
67
68 auto shape = std::make_unique<PCB_SHAPE>( board );
69 PCB_SHAPE* liveShape = shape.get();
70 const KIID oldId = liveShape->m_Uuid;
71 const KIID newId;
72
73 board->Add( shape.release() );
74
75 const_cast<KIID&>( liveShape->m_Uuid ) = newId;
76
77 BOOST_CHECK( board->ResolveItem( oldId, true ) == nullptr );
78 BOOST_CHECK_EQUAL( board->ResolveItem( newId, true ), liveShape );
79
80 delete board;
81}
82
83
84BOOST_AUTO_TEST_CASE( ResolvingNewUuidPurgesStaleOldAlias )
85{
86 BOARD* board = new BOARD();
87
88 auto shape = std::make_unique<PCB_SHAPE>( board );
89 PCB_SHAPE* liveShape = shape.get();
90 const KIID oldId = liveShape->m_Uuid;
91 const KIID newId;
92
93 board->Add( shape.release() );
94 const_cast<KIID&>( liveShape->m_Uuid ) = newId;
95
96 BOOST_CHECK_EQUAL( board->ResolveItem( newId, true ), liveShape );
97 BOOST_CHECK( board->GetItemByIdCache().contains( newId ) );
98 BOOST_CHECK( !board->GetItemByIdCache().contains( oldId ) );
99
100 delete board;
101}
102
103
104BOOST_AUTO_TEST_CASE( RebindItemUuidUpdatesCacheAtomically )
105{
106 BOARD* board = new BOARD();
107
108 auto shape = std::make_unique<PCB_SHAPE>( board );
109 PCB_SHAPE* liveShape = shape.get();
110 const KIID oldId = liveShape->m_Uuid;
111 const KIID newId;
112
113 board->Add( shape.release() );
114 board->RebindItemUuid( liveShape, newId );
115
116 BOOST_CHECK( liveShape->m_Uuid == newId );
117 BOOST_CHECK( !board->GetItemByIdCache().contains( oldId ) );
118 BOOST_CHECK( board->GetItemByIdCache().contains( newId ) );
119 BOOST_CHECK_EQUAL( board->ResolveItem( newId, true ), liveShape );
120
121 delete board;
122}
123
124
125BOOST_AUTO_TEST_CASE( AttachedChildSetUuidRebindsCache )
126{
127 BOARD* board = new BOARD();
128
129 auto footprint = std::make_unique<FOOTPRINT>( board );
130 auto pad = new PAD( footprint.get() );
131 PAD* livePad = pad;
132 const KIID oldId = livePad->m_Uuid;
133 const KIID newId;
134
135 footprint->Add( pad );
136 board->Add( footprint.release() );
137
138 livePad->SetUuid( newId );
139
140 BOOST_CHECK( livePad->m_Uuid == newId );
141 BOOST_CHECK( !board->GetItemByIdCache().contains( oldId ) );
142 BOOST_CHECK( board->GetItemByIdCache().contains( newId ) );
143 BOOST_CHECK_EQUAL( board->ResolveItem( newId, true ), livePad );
144
145 delete board;
146}
147
148
149BOOST_AUTO_TEST_CASE( CacheItemByIdCanonicalizesRewrittenUuid )
150{
151 BOARD* board = new BOARD();
152
153 auto shape = std::make_unique<PCB_SHAPE>( board );
154 PCB_SHAPE* liveShape = shape.get();
155 const KIID oldId = liveShape->m_Uuid;
156 const KIID newId;
157
158 board->Add( shape.release() );
159
160 const_cast<KIID&>( liveShape->m_Uuid ) = newId;
161 board->CacheItemById( liveShape );
162
163 BOOST_CHECK( !board->GetItemByIdCache().contains( oldId ) );
164 BOOST_CHECK( board->GetItemByIdCache().contains( newId ) );
165 BOOST_CHECK_EQUAL( board->ResolveItem( newId, true ), liveShape );
166
167 delete board;
168}
169
170
171BOOST_AUTO_TEST_CASE( RepairDuplicateItemUuidsKeepsEarlierTraversalWinner )
172{
173 BOARD* board = new BOARD();
174
175 auto footprint = std::make_unique<FOOTPRINT>( board );
176 FOOTPRINT* liveFootprint = footprint.get();
177 const KIID claimedId = liveFootprint->m_Uuid;
178
179 auto shape = std::make_unique<PCB_SHAPE>( board );
180 PCB_SHAPE* liveShape = shape.get();
181 const KIID originalShapeId = liveShape->m_Uuid;
182
183 board->Add( footprint.release() );
184 board->Add( shape.release() );
185
186 const_cast<KIID&>( liveShape->m_Uuid ) = claimedId;
187
189 BOOST_CHECK( liveFootprint->m_Uuid == claimedId );
190 BOOST_CHECK( liveShape->m_Uuid != claimedId );
191 BOOST_CHECK( liveShape->m_Uuid != originalShapeId );
192 BOOST_CHECK_EQUAL( board->ResolveItem( claimedId, true ), liveFootprint );
193 BOOST_CHECK( board->ResolveItem( originalShapeId, true ) == nullptr );
194 BOOST_CHECK_EQUAL( board->ResolveItem( liveShape->m_Uuid, true ), liveShape );
195
196 delete board;
197}
198
199
200BOOST_AUTO_TEST_CASE( RemovingResolvedChildEvictsCacheOnFootprintHolder )
201{
202 // Regression for the RC_TREE_MODEL::GetValue use-after-free: ResolveItem() caches a
203 // footprint child on demand, but the cache eviction in FOOTPRINT::Remove is gated on the
204 // parent footprint being indexed. A footprint-holder board never indexes anything (
205 // CacheItemById early-returns), yet ResolveItem still caches children, so removing and
206 // freeing a resolved child leaves a dangling id in the cache. A later resolve then hands
207 // back the freed pointer.
208 BOARD* board = new BOARD();
210
211 auto footprint = std::make_unique<FOOTPRINT>( board );
212 auto pad = new PAD( footprint.get() );
213 pad->SetNumber( "1" );
214
215 const KIID padId = pad->m_Uuid;
216 footprint->Add( pad );
217
218 FOOTPRINT* liveFootprint = footprint.get();
219 board->Add( footprint.release() );
220
221 // Resolve the pad the way a results-tree row does. On the buggy code this caches the pad
222 // even though the holder board never indexed its parent footprint.
223 BOOST_REQUIRE_EQUAL( board->ResolveItem( padId, true ), pad );
224
225 // Remove and destroy the pad through the footprint, as a footprint edit does.
226 liveFootprint->Remove( pad );
227 const bool staleEntrySurvived = board->GetItemByIdCache().contains( padId );
228
229 delete pad;
230 delete board;
231
232 BOOST_CHECK( !staleEntrySurvived );
233}
234
235
@ FPHOLDER
Definition board.h:364
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:81
void SwapItemData(BOARD_ITEM *aImage)
Swap data between aItem and aImage.
void SetUuid(const KIID &aUuid)
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:372
void CacheItemById(BOARD_ITEM *aItem) const
Add an item to the item-by-id cache.
Definition board.cpp:1986
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Removes an item from the container.
Definition board.cpp:1295
void SetBoardUse(BOARD_USE aUse)
Set what the board is going to be used for.
Definition board.h:384
void RebindItemUuid(BOARD_ITEM *aItem, const KIID &aNewId)
Rebind the UUID of an attached item and keep the item-by-id cache coherent.
Definition board.cpp:2088
int RepairDuplicateItemUuids()
Rebind duplicate attached-item UUIDs so each live board item has a unique ID.
Definition board.cpp:2114
const std::unordered_map< KIID, BOARD_ITEM * > & GetItemByIdCache() const
Definition board.h:1536
BOARD_ITEM * ResolveItem(const KIID &aID, bool aAllowNullptrReturn=false) const
Definition board.cpp:1846
const KIID m_Uuid
Definition eda_item.h:531
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:108
void Remove(BOARD_ITEM *aItem, REMOVE_MODE aMode=REMOVE_MODE::NORMAL) override
Removes an item from the container.
EDA_ITEM * Clone() const override
Invoke a function on all children.
Definition kiid.h:44
Definition pad.h:61
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_AUTO_TEST_CASE(SwapItemDataReindexesFootprintChildren)
BOOST_AUTO_TEST_SUITE(CadstarPartParser)
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_AUTO_TEST_SUITE_END()
BOOST_CHECK_EQUAL(result, "25.4")
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition typeinfo.h:80