KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_diff_types_helpers.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
27
28#include <map>
29#include <set>
30
31
32using namespace KICAD_DIFF;
33
34
35BOOST_AUTO_TEST_SUITE( DiffTypesHelpers )
36
37
38// ---------------------------------------------------------------------------
39// LibraryItemKiidPath
40// ---------------------------------------------------------------------------
41
42BOOST_AUTO_TEST_CASE( LibraryItemKiidPath_Deterministic )
43{
44 // Same input must produce the same output. The whole point of this helper
45 // is to replace KIID(string)'s random-UUID fallback, so determinism is
46 // load-bearing.
47 const KIID_PATH a = LibraryItemKiidPath( wxS( "R_0402" ) );
48 const KIID_PATH b = LibraryItemKiidPath( wxS( "R_0402" ) );
49 BOOST_CHECK( a == b );
50}
51
52
53BOOST_AUTO_TEST_CASE( LibraryItemKiidPath_PinnedOutput )
54{
55 // The produced UUID is embedded in persisted diff/merge artifacts and used
56 // to match library items across a round-trip. Pin the exact bytes for a
57 // known name so a refactor of the underlying hashing can't silently shift
58 // them and break matching against existing data.
59 const KIID_PATH path = LibraryItemKiidPath( wxS( "R_0402" ) );
60 BOOST_REQUIRE_EQUAL( path.size(), 1u );
61 BOOST_CHECK_EQUAL( path.front().AsStdString(), "b75bc79b-7a70-e264-53e6-d29f96c4fad4" );
62}
63
64
65BOOST_AUTO_TEST_CASE( LibraryItemKiidPath_DistinctNames )
66{
67 // Different names must produce different paths. Collision probability
68 // is 2^-128, but at least check the common short-string cases.
69 BOOST_CHECK( LibraryItemKiidPath( wxS( "R_0402" ) )
70 != LibraryItemKiidPath( wxS( "R_0603" ) ) );
71 BOOST_CHECK( LibraryItemKiidPath( wxS( "C_0402" ) )
72 != LibraryItemKiidPath( wxS( "R_0402" ) ) );
73 BOOST_CHECK( LibraryItemKiidPath( wxS( "A" ) )
74 != LibraryItemKiidPath( wxS( "B" ) ) );
75}
76
77
78BOOST_AUTO_TEST_CASE( LibraryItemKiidPath_EmptyName )
79{
80 // Empty name must still produce a valid one-segment path with a non-nil
81 // segment. operator== alone would pass for a default-constructed (empty)
82 // KIID_PATH, so check size + non-niluuid explicitly.
83 const KIID_PATH a = LibraryItemKiidPath( wxS( "" ) );
84 const KIID_PATH b = LibraryItemKiidPath( wxS( "" ) );
85 BOOST_REQUIRE_EQUAL( a.size(), 1u );
86 BOOST_CHECK( a == b );
87 BOOST_CHECK( a.front() != NilUuid() );
88}
89
90
91BOOST_AUTO_TEST_CASE( LibraryItemKiidPath_UnicodeName )
92{
93 // Names with non-ASCII characters should still hash deterministically.
94 const KIID_PATH a = LibraryItemKiidPath( wxString::FromUTF8( "电阻_0402" ) );
95 const KIID_PATH b = LibraryItemKiidPath( wxString::FromUTF8( "电阻_0402" ) );
96 BOOST_CHECK( a == b );
97
98 BOOST_CHECK( a != LibraryItemKiidPath( wxString::FromUTF8( "电阻_0603" ) ) );
99}
100
101
102// ---------------------------------------------------------------------------
103// SchScreenSentinelKiid
104// ---------------------------------------------------------------------------
105
106BOOST_AUTO_TEST_CASE( SchScreenSentinelKiid_Stable )
107{
108 // The sentinel is used to distinguish a SCH_SCREEN-property resolution
109 // from a SCH_SHEET symbol that lives at the same sheet path. Two calls
110 // must return the SAME value (it's a static-local const).
111 const KIID& a = SchScreenSentinelKiid();
112 const KIID& b = SchScreenSentinelKiid();
113 BOOST_CHECK( a == b );
114 BOOST_CHECK( &a == &b ); // returned by const ref to the same static
115}
116
117
118BOOST_AUTO_TEST_CASE( SchScreenSentinelKiid_DistinctFromNiluuid )
119{
120 // The sentinel was deliberately chosen to be a non-nil v4 UUID so
121 // consumers that check niluuid for "no item" still treat it as a real ID.
122 BOOST_CHECK( SchScreenSentinelKiid() != NilUuid() );
123}
124
125
126BOOST_AUTO_TEST_CASE( SchScreenSentinelKiid_PinnedLiteral )
127{
128 // The sentinel is a hard-coded constant in the header — pin its exact
129 // value so an accidental change is loud. Any consumer that has stored
130 // this UUID in a marker file or test fixture would break silently
131 // otherwise.
133 "5c50ee00-0000-4000-8000-000000000000" );
134}
135
136
137BOOST_AUTO_TEST_CASE( SchScreenSentinelKiid_DoesntCollideWithGeneratedKiids )
138{
139 // Defense in depth: the sentinel is v4-shaped, so the generator
140 // could in principle return the same UUID. Probability is 2^-128
141 // but 1024 samples cheaply guards against the sentinel accidentally
142 // sitting in a deterministic output range during testing.
143 for( int i = 0; i < 1024; ++i )
144 {
145 KIID generated;
146 BOOST_REQUIRE( generated != SchScreenSentinelKiid() );
147 }
148}
149
150
151// ---------------------------------------------------------------------------
152// SummarizeSeverities
153// ---------------------------------------------------------------------------
154
155BOOST_AUTO_TEST_CASE( SummarizeSeverities_EmptyMap )
156{
157 std::map<int, int> empty;
158 const std::string s = SummarizeSeverities( empty );
159
160 // Empty map's hash is 0 (no XOR contributions). Pin both the count and
161 // the literal hash term — `s.find("hash ")` alone would match the format
162 // string even if hashing was broken.
163 BOOST_CHECK( s.find( "0 override(s)" ) != std::string::npos );
164 BOOST_CHECK( s.find( "hash 0)" ) != std::string::npos );
165}
166
167
168BOOST_AUTO_TEST_CASE( SummarizeSeverities_NonEmpty )
169{
170 std::map<int, int> m{ { 1, 2 }, { 3, 4 } };
171 const std::string s = SummarizeSeverities( m );
172
173 // Tighter pin: the count is correct AND the hash field is non-zero (it
174 // would be "hash 0)" if every entry contributed an empty bucket).
175 BOOST_CHECK( s.find( "2 override(s)" ) != std::string::npos );
176 BOOST_CHECK( s.find( "hash " ) != std::string::npos );
177 BOOST_CHECK( s.find( "hash 0)" ) == std::string::npos );
178}
179
180
181BOOST_AUTO_TEST_CASE( SummarizeSeverities_SameContentSameHash )
182{
183 // The hash component must be deterministic — distinct callers must
184 // produce identical strings for identical content (this is what makes
185 // the diff value comparable across runs).
186 std::map<int, int> a{ { 1, 2 }, { 3, 4 } };
187 std::map<int, int> b{ { 1, 2 }, { 3, 4 } };
189}
190
191
192BOOST_AUTO_TEST_CASE( SummarizeSeverities_DifferentContentDifferentHash )
193{
194 // Same size, different values must produce different hashes. This is the
195 // bug the hash was added to catch — "5 override(s)" vs "5 override(s)"
196 // with different severities would otherwise render as identical.
197 std::map<int, int> a{ { 1, 2 } };
198 std::map<int, int> b{ { 1, 3 } };
199 BOOST_CHECK( SummarizeSeverities( a ) != SummarizeSeverities( b ) );
200}
201
202
203BOOST_AUTO_TEST_CASE( SummarizeSeverities_OrderInvariant )
204{
205 // std::map iterates in key order, so insertion order shouldn't matter.
206 std::map<int, int> a;
207 a[3] = 30;
208 a[1] = 10;
209
210 std::map<int, int> b;
211 b[1] = 10;
212 b[3] = 30;
213
215}
216
217
218// ---------------------------------------------------------------------------
219// DOC_PROP constants are unique
220// ---------------------------------------------------------------------------
221
222BOOST_AUTO_TEST_CASE( DocPropConstants_AllDistinct )
223{
224 // A typo on one side that accidentally equals another constant would
225 // silently desync PCB and SCH. Verify all DOC_PROP_* strings are
226 // distinct.
227 const std::set<wxString> all = {
235 };
236
237 BOOST_CHECK_EQUAL( all.size(), 7 );
238}
239
240
241BOOST_AUTO_TEST_CASE( DocPropConstants_PinnedValues )
242{
243 // These names are the document-level delta keys written into .kicad_merge
244 // markers; changing a value silently breaks marker compatibility. Pin the
245 // exact strings (also catches a single empty/typo that _AllDistinct misses).
246 BOOST_CHECK( DOC_PROP_PAGE_FORMAT == wxString( "Page Format" ) );
247 BOOST_CHECK( DOC_PROP_PAGE_ORIENTATION == wxString( "Page Orientation" ) );
248 BOOST_CHECK( DOC_PROP_BOARD_THICKNESS == wxString( "Board Thickness" ) );
249 BOOST_CHECK( DOC_PROP_LAYER_STACKUP == wxString( "Layer Stackup" ) );
250 BOOST_CHECK( DOC_PROP_DRC_SEVERITIES == wxString( "DRC Severity Overrides" ) );
251 BOOST_CHECK( DOC_PROP_ERC_SEVERITIES == wxString( "ERC Severity Overrides" ) );
252 BOOST_CHECK( DOC_PROP_DRAWING_SHEET == wxString( "Drawing Sheet File" ) );
253}
254
255
256// ---------------------------------------------------------------------------
257// Side-effect predicates (ChangeInvalidatesZone / ChangeRequiresConnectivityRebuild)
258// ---------------------------------------------------------------------------
259
260namespace
261{
262
263ITEM_CHANGE MakeChange( const wxString& aTypeName )
264{
265 ITEM_CHANGE c;
266 c.typeName = aTypeName;
268 return c;
269}
270
271} // namespace
272
273
274BOOST_AUTO_TEST_CASE( ChangeInvalidatesZone_CopperConductors )
275{
276 BOOST_CHECK( ChangeInvalidatesZone( MakeChange( wxS( "ZONE" ) ) ) );
277 BOOST_CHECK( ChangeInvalidatesZone( MakeChange( wxS( "PCB_TRACK" ) ) ) );
278 BOOST_CHECK( ChangeInvalidatesZone( MakeChange( wxS( "PCB_ARC" ) ) ) );
279 BOOST_CHECK( ChangeInvalidatesZone( MakeChange( wxS( "PCB_VIA" ) ) ) );
280 BOOST_CHECK( ChangeInvalidatesZone( MakeChange( wxS( "FOOTPRINT" ) ) ) );
281 BOOST_CHECK( ChangeInvalidatesZone( MakeChange( wxS( "PAD" ) ) ) );
282}
283
284
285BOOST_AUTO_TEST_CASE( ChangeInvalidatesZone_NonCopperRejected )
286{
287 // Items the predicate deliberately leaves out — see the header doc for
288 // why PCB_TEXT/PCB_SHAPE are excluded (their zone-affecting status
289 // depends on layer, which this type-only predicate can't see).
290 BOOST_CHECK( !ChangeInvalidatesZone( MakeChange( wxS( "PCB_TEXT" ) ) ) );
291 BOOST_CHECK( !ChangeInvalidatesZone( MakeChange( wxS( "PCB_DIMENSION" ) ) ) );
292 BOOST_CHECK( !ChangeInvalidatesZone( MakeChange( wxS( "SCH_LABEL" ) ) ) );
293 BOOST_CHECK( !ChangeInvalidatesZone( MakeChange( wxS( "" ) ) ) );
294 // Case-sensitive — a typo on the type name must not silently slip in.
295 BOOST_CHECK( !ChangeInvalidatesZone( MakeChange( wxS( "pcb_track" ) ) ) );
296}
297
298
299BOOST_AUTO_TEST_CASE( ChangeRequiresConnectivityRebuild_NetCarriers )
300{
301 // The full set of GetClass() names the differ emits that carry nets or
302 // act as connection markers. Missing any of these means the merge engine
303 // saves a board / schematic with a stale netlist — pin them all here so
304 // the predicate can't silently drop one in a future refactor.
305 BOOST_CHECK( ChangeRequiresConnectivityRebuild( MakeChange( wxS( "PCB_TRACK" ) ) ) );
306 BOOST_CHECK( ChangeRequiresConnectivityRebuild( MakeChange( wxS( "PCB_ARC" ) ) ) );
307 BOOST_CHECK( ChangeRequiresConnectivityRebuild( MakeChange( wxS( "PCB_VIA" ) ) ) );
308 BOOST_CHECK( ChangeRequiresConnectivityRebuild( MakeChange( wxS( "PCB_SHAPE" ) ) ) );
309 BOOST_CHECK( ChangeRequiresConnectivityRebuild( MakeChange( wxS( "PAD" ) ) ) );
310 BOOST_CHECK( ChangeRequiresConnectivityRebuild( MakeChange( wxS( "SCH_LINE" ) ) ) );
311 BOOST_CHECK( ChangeRequiresConnectivityRebuild( MakeChange( wxS( "SCH_PIN" ) ) ) );
312 BOOST_CHECK( ChangeRequiresConnectivityRebuild( MakeChange( wxS( "SCH_SYMBOL" ) ) ) );
313 BOOST_CHECK( ChangeRequiresConnectivityRebuild( MakeChange( wxS( "SCH_LABEL" ) ) ) );
314 BOOST_CHECK( ChangeRequiresConnectivityRebuild( MakeChange( wxS( "SCH_GLOBALLABEL" ) ) ) );
315 BOOST_CHECK( ChangeRequiresConnectivityRebuild( MakeChange( wxS( "SCH_HIERLABEL" ) ) ) );
316 BOOST_CHECK( ChangeRequiresConnectivityRebuild( MakeChange( wxS( "SCH_DIRECTIVE_LABEL" ) ) ) );
317 BOOST_CHECK( ChangeRequiresConnectivityRebuild( MakeChange( wxS( "SCH_JUNCTION" ) ) ) );
318 BOOST_CHECK( ChangeRequiresConnectivityRebuild( MakeChange( wxS( "SCH_NO_CONNECT" ) ) ) );
319 BOOST_CHECK( ChangeRequiresConnectivityRebuild( MakeChange( wxS( "SCH_SHEET_PIN" ) ) ) );
320 BOOST_CHECK( ChangeRequiresConnectivityRebuild( MakeChange( wxS( "SCH_BUS_WIRE_ENTRY" ) ) ) );
321 BOOST_CHECK( ChangeRequiresConnectivityRebuild( MakeChange( wxS( "SCH_BUS_BUS_ENTRY" ) ) ) );
322 BOOST_CHECK( ChangeRequiresConnectivityRebuild( MakeChange( wxS( "SCH_SHEET" ) ) ) );
323 BOOST_CHECK( ChangeRequiresConnectivityRebuild( MakeChange( wxS( "SCH_RULE_AREA" ) ) ) );
324}
325
326
327BOOST_AUTO_TEST_CASE( ChangeRequiresConnectivityRebuild_NonNetItemsRejected )
328{
329 // ZONE membership flips connectivity at fill-time but not via this
330 // predicate — the engine uses ChangeInvalidatesZone for that path.
331 // FOOTPRINT changes that move pads are handled by the PAD entry above.
332 // PCB_TEXT changes do not carry nets even on copper.
333 BOOST_CHECK( !ChangeRequiresConnectivityRebuild( MakeChange( wxS( "ZONE" ) ) ) );
334 BOOST_CHECK( !ChangeRequiresConnectivityRebuild( MakeChange( wxS( "FOOTPRINT" ) ) ) );
335 BOOST_CHECK( !ChangeRequiresConnectivityRebuild( MakeChange( wxS( "PCB_TEXT" ) ) ) );
336 BOOST_CHECK( !ChangeRequiresConnectivityRebuild( MakeChange( wxS( "SCH_BITMAP" ) ) ) );
337 BOOST_CHECK( !ChangeRequiresConnectivityRebuild( MakeChange( wxS( "" ) ) ) );
338}
339
340
341BOOST_AUTO_TEST_CASE( SideEffectPredicates_IndependentOfChangeKind )
342{
343 // The predicates dispatch on typeName only — kind (ADDED/MODIFIED/REMOVED)
344 // must not influence the result. A removed track still invalidates zones.
345 ITEM_CHANGE removed;
346 removed.typeName = wxS( "PCB_TRACK" );
347 removed.kind = CHANGE_KIND::REMOVED;
348 BOOST_CHECK( ChangeInvalidatesZone( removed ) );
349 BOOST_CHECK( ChangeRequiresConnectivityRebuild( removed ) );
350
351 ITEM_CHANGE added;
352 added.typeName = wxS( "PCB_TRACK" );
353 added.kind = CHANGE_KIND::ADDED;
354 BOOST_CHECK( ChangeInvalidatesZone( added ) );
355 BOOST_CHECK( ChangeRequiresConnectivityRebuild( added ) );
356}
357
358
359// ---------------------------------------------------------------------------
360// IndexChangesByKiid / IndexPropertiesByName
361// ---------------------------------------------------------------------------
362
363namespace
364{
365
366ITEM_CHANGE MakeChangeWithId( const wxString& aTypeName, const wxString& aIdSegment )
367{
368 ITEM_CHANGE c;
369 c.typeName = aTypeName;
371 c.id = KIID_PATH( wxS( "/" ) + KIID().AsString() );
372 // Stash the id segment in refdes so tests can identify which change came
373 // back from the index without depending on KIID equality across copies.
374 c.refdes = aIdSegment;
375 return c;
376}
377
378} // namespace
379
380
381BOOST_AUTO_TEST_CASE( IndexChangesByKiid_FlatList )
382{
383 DOCUMENT_DIFF diff;
384 diff.changes.push_back( MakeChangeWithId( wxS( "FOOTPRINT" ), wxS( "F1" ) ) );
385 diff.changes.push_back( MakeChangeWithId( wxS( "ZONE" ), wxS( "Z1" ) ) );
386
387 const auto index = IndexChangesByKiid( diff );
388
389 BOOST_REQUIRE_EQUAL( index.size(), 2u );
390 BOOST_CHECK( index.count( diff.changes[0].id ) == 1 );
391 BOOST_CHECK( index.count( diff.changes[1].id ) == 1 );
392 BOOST_CHECK( index.at( diff.changes[0].id ) == &diff.changes[0] );
393}
394
395
396BOOST_AUTO_TEST_CASE( IndexChangesByKiid_RecursesIntoChildren )
397{
398 // A footprint with a pad-level child change. Without recursive walking,
399 // the pad's id never appears in the index and conflict detection on
400 // intra-footprint edits would silently auto-merge — exactly the bug the
401 // recursion was added to prevent.
402 DOCUMENT_DIFF diff;
403 ITEM_CHANGE fp = MakeChangeWithId( wxS( "FOOTPRINT" ), wxS( "FP" ) );
404 fp.children.push_back( MakeChangeWithId( wxS( "PAD" ), wxS( "P1" ) ) );
405 fp.children.push_back( MakeChangeWithId( wxS( "PAD" ), wxS( "P2" ) ) );
406 diff.changes.push_back( std::move( fp ) );
407
408 const auto index = IndexChangesByKiid( diff );
409
410 BOOST_REQUIRE_EQUAL( index.size(), 3u );
411 BOOST_CHECK( index.at( diff.changes[0].id )->typeName == wxS( "FOOTPRINT" ) );
412 BOOST_CHECK( index.at( diff.changes[0].children[0].id )->typeName == wxS( "PAD" ) );
413 BOOST_CHECK( index.at( diff.changes[0].children[1].id )->typeName == wxS( "PAD" ) );
414}
415
416
417BOOST_AUTO_TEST_CASE( IndexChangesByKiid_DeepNesting )
418{
419 // Three levels deep. Tests recursion depth handling.
420 DOCUMENT_DIFF diff;
421 ITEM_CHANGE level1 = MakeChangeWithId( wxS( "SHEET" ), wxS( "L1" ) );
422 ITEM_CHANGE level2 = MakeChangeWithId( wxS( "SYMBOL" ), wxS( "L2" ) );
423 ITEM_CHANGE level3 = MakeChangeWithId( wxS( "FIELD" ), wxS( "L3" ) );
424 level2.children.push_back( std::move( level3 ) );
425 level1.children.push_back( std::move( level2 ) );
426 diff.changes.push_back( std::move( level1 ) );
427
428 const auto index = IndexChangesByKiid( diff );
429 BOOST_CHECK_EQUAL( index.size(), 3u );
430}
431
432
433BOOST_AUTO_TEST_CASE( IndexChangesByKiid_DuplicateKiidLastWins )
434{
435 // KIID_PATHs are unique by construction in real diffs, but a corrupt or
436 // hand-crafted diff with collisions falls through the recursive walk:
437 // operator[] last-write-wins is the documented contract. Pin it so a
438 // future refactor that flips to first-wins (or asserts) is loud.
439 const KIID_PATH sharedId = KIID_PATH( wxS( "/" ) + KIID().AsString() );
440
441 DOCUMENT_DIFF diff;
442
443 ITEM_CHANGE first;
444 first.id = sharedId;
445 first.typeName = wxS( "FIRST" );
447 diff.changes.push_back( first );
448
449 ITEM_CHANGE second;
450 second.id = sharedId;
451 second.typeName = wxS( "SECOND" );
453 diff.changes.push_back( second );
454
455 const auto index = IndexChangesByKiid( diff );
456 BOOST_REQUIRE_EQUAL( index.size(), 1u );
457 BOOST_CHECK( index.at( sharedId )->typeName == wxS( "SECOND" ) );
458}
459
460
461BOOST_AUTO_TEST_CASE( IndexChangesByKiid_EmptyDiff )
462{
463 DOCUMENT_DIFF diff;
464 BOOST_CHECK( IndexChangesByKiid( diff ).empty() );
465}
466
467
468BOOST_AUTO_TEST_CASE( IndexPropertiesByName_FlatList )
469{
470 ITEM_CHANGE c;
472 p1.name = wxS( "Width" );
473 p1.before = DIFF_VALUE::FromInt( 10 );
474 p1.after = DIFF_VALUE::FromInt( 20 );
475 c.properties.push_back( p1 );
476
478 p2.name = wxS( "Layer" );
479 p2.before = DIFF_VALUE::FromInt( 1 );
480 p2.after = DIFF_VALUE::FromInt( 2 );
481 c.properties.push_back( p2 );
482
483 const auto index = IndexPropertiesByName( c );
484
485 BOOST_REQUIRE_EQUAL( index.size(), 2u );
486 BOOST_CHECK( index.count( wxS( "Width" ) ) == 1 );
487 BOOST_CHECK( index.count( wxS( "Layer" ) ) == 1 );
488 BOOST_CHECK( index.at( wxS( "Width" ) ) == &c.properties[0] );
489}
490
491
492BOOST_AUTO_TEST_CASE( IndexPropertiesByName_EmptyChange )
493{
494 ITEM_CHANGE c;
495 BOOST_CHECK( IndexPropertiesByName( c ).empty() );
496}
497
498
int index
static DIFF_VALUE FromInt(int aValue)
Definition kiid.h:44
static bool empty(const wxTextEntryBase *aCtrl)
KIID & NilUuid()
Definition kiid.cpp:66
const wxString DOC_PROP_ERC_SEVERITIES
const KIID & SchScreenSentinelKiid()
Sentinel KIID appended to a sheet's KIID_PATH to mark a per-sheet SCH_SCREEN resolution (page format ...
bool ChangeInvalidatesZone(const ITEM_CHANGE &aChange)
Whether a change to an item of the given type invalidates any overlapping filled zones.
const wxString DOC_PROP_BOARD_THICKNESS
const wxString DOC_PROP_PAGE_FORMAT
Property-name keys for the synthetic document-level ITEM_CHANGE (empty KIID_PATH).
std::string SummarizeSeverities(const SeverityMap &aMap)
Format a severity-override map (DRC or ERC, keyed by error code, value is a SEVERITY enum) as a short...
const wxString DOC_PROP_PAGE_ORIENTATION
KIID_PATH LibraryItemKiidPath(const wxString &aName)
Build a deterministic synthetic KIID_PATH from a library item name (symbol name or footprint name).
const wxString DOC_PROP_LAYER_STACKUP
const wxString DOC_PROP_DRAWING_SHEET
bool ChangeRequiresConnectivityRebuild(const ITEM_CHANGE &aChange)
Whether a change to an item of the given type requires the connectivity graph to be rebuilt.
const wxString DOC_PROP_DRC_SEVERITIES
std::map< KIID_PATH, const ITEM_CHANGE * > IndexChangesByKiid(const DOCUMENT_DIFF &aDiff)
Flatten a DOCUMENT_DIFF's ITEM_CHANGE tree into a KIID_PATH -> ITEM_CHANGE* map, recursing into child...
std::map< wxString, const PROPERTY_DELTA * > IndexPropertiesByName(const ITEM_CHANGE &aChange)
Index property deltas inside one ITEM_CHANGE by property name.
_OUT_STRING AsString(const std::string &aString)
Definition sexpr.h:131
The full set of changes between two parsed documents of one type.
std::vector< ITEM_CHANGE > changes
One change record on a single item.
std::vector< PROPERTY_DELTA > properties
std::optional< wxString > refdes
std::vector< ITEM_CHANGE > children
Single (name, before, after) triple for one mutated property on an item.
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_AUTO_TEST_SUITE(CadstarPartParser)
BOOST_AUTO_TEST_CASE(LibraryItemKiidPath_Deterministic)
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_AUTO_TEST_SUITE_END()
std::string path
BOOST_CHECK_EQUAL(result, "25.4")