KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_fp_lib_differ.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
27
31
32#include <footprint.h>
33
34#include <nlohmann/json.hpp>
35
36#include <wx/filename.h>
37
38
39using namespace KICAD_DIFF;
40
41
42BOOST_AUTO_TEST_SUITE( FpLibDiffer )
43
44
45static wxString getFixturePath()
46{
47 // qa/data/pcbnew/.. -> qa/data/libraries/Resistor_SMD.pretty
48 wxFileName fn( KI_TEST::GetPcbnewTestDataDir(), wxEmptyString );
49 fn.RemoveLastDir();
50 fn.AppendDir( wxS( "libraries" ) );
51 fn.AppendDir( wxS( "Resistor_SMD.pretty" ) );
52 return fn.GetPath();
53}
54
55
56BOOST_AUTO_TEST_CASE( IdenticalLibrariesDiffEmpty )
57{
58 auto [ownersA, mapA] = FP_LIB_DIFFER::LoadLibrary( getFixturePath() );
59 auto [ownersB, mapB] = FP_LIB_DIFFER::LoadLibrary( getFixturePath() );
60
61 BOOST_REQUIRE( !mapA.empty() );
62
63 FP_LIB_DIFFER differ( mapA, mapB, wxS( "Resistor_SMD.pretty" ) );
64 DOCUMENT_DIFF result = differ.Diff();
65
66 BOOST_CHECK( result.Empty() );
67 BOOST_CHECK_EQUAL( result.docType.ToStdString(), "pretty" );
68}
69
70
71BOOST_AUTO_TEST_CASE( FootprintRemovedShowsAsRemoved )
72{
73 auto [ownersA, mapA] = FP_LIB_DIFFER::LoadLibrary( getFixturePath() );
74 auto [ownersB, mapB] = FP_LIB_DIFFER::LoadLibrary( getFixturePath() );
75
76 BOOST_REQUIRE( !mapB.empty() );
77 mapB.erase( mapB.begin() );
78
79 FP_LIB_DIFFER differ( mapA, mapB );
80 DOCUMENT_DIFF result = differ.Diff();
81
82 BOOST_REQUIRE_EQUAL( result.changes.size(), 1u );
83 BOOST_CHECK( result.changes[0].kind == CHANGE_KIND::REMOVED );
84}
85
86
87BOOST_AUTO_TEST_CASE( FootprintChangesCarryDrawableBBoxes )
88{
89 auto [ownersA, mapA] = FP_LIB_DIFFER::LoadLibrary( getFixturePath() );
90 auto [ownersB, mapB] = FP_LIB_DIFFER::LoadLibrary( getFixturePath() );
91
92 BOOST_REQUIRE( !ownersB.empty() );
93 FOOTPRINT* subject = ownersB.front().get();
94 subject->Move( VECTOR2I( 1000, 0 ) );
95
96 FP_LIB_DIFFER differ( mapA, mapB );
97 DOCUMENT_DIFF result = differ.Diff();
98
99 BOOST_REQUIRE_EQUAL( result.changes.size(), 1u );
100 BOOST_CHECK( result.changes[0].kind == CHANGE_KIND::MODIFIED );
101 BOOST_CHECK_GT( result.changes[0].bbox.GetWidth(), 0 );
102 BOOST_CHECK_GT( result.changes[0].bbox.GetHeight(), 0 );
103}
104
105
106BOOST_AUTO_TEST_CASE( ExtractFootprintGeometryProducesLayeredContext )
107{
108 auto [owners, map] = FP_LIB_DIFFER::LoadLibrary( getFixturePath() );
109
110 BOOST_REQUIRE( !owners.empty() );
111
112 DOCUMENT_GEOMETRY geometry = ExtractFootprintGeometry( *owners.front(), KIGFX::COLOR4D( 0.38, 0.38, 0.38, 0.55 ) );
113
114 BOOST_CHECK( !geometry.Empty() );
115 BOOST_CHECK( GeometryLayerSet( geometry ).any() );
116}
117
118
119BOOST_AUTO_TEST_CASE( DiffJsonRoundTrip )
120{
121 auto [ownersA, mapA] = FP_LIB_DIFFER::LoadLibrary( getFixturePath() );
122 auto [ownersB, mapB] = FP_LIB_DIFFER::LoadLibrary( getFixturePath() );
123
124 if( !mapB.empty() )
125 mapB.erase( mapB.begin() );
126
127 FP_LIB_DIFFER differ( mapA, mapB, wxS( "lib.pretty" ) );
128 DOCUMENT_DIFF result = differ.Diff();
129
130 nlohmann::json j = result.ToJson();
132 BOOST_CHECK_EQUAL( back.changes.size(), result.changes.size() );
133}
134
135
136// LibraryItemKiidPath must be deterministic for the same footprint name
137// across calls -- differ + applier must agree on the synthetic UUID or
138// per-item resolution lookup silently misses.
139BOOST_AUTO_TEST_CASE( LibraryItemKiidPathIsDeterministicForSameName )
140{
141 KIID_PATH a = LibraryItemKiidPath( wxS( "R_0402_1005Metric" ) );
142 KIID_PATH b = LibraryItemKiidPath( wxS( "R_0402_1005Metric" ) );
143
144 BOOST_REQUIRE_EQUAL( a.size(), 1u );
145 BOOST_REQUIRE_EQUAL( b.size(), 1u );
146 BOOST_CHECK( a == b );
147}
148
149
150BOOST_AUTO_TEST_CASE( LibraryItemKiidPathDiffersForDifferentNames )
151{
152 KIID_PATH a = LibraryItemKiidPath( wxS( "R_0402_1005Metric" ) );
153 KIID_PATH b = LibraryItemKiidPath( wxS( "R_0603_1608Metric" ) );
154
155 BOOST_CHECK( !( a == b ) );
156}
157
158
159// Multiple removals: each footprint must surface as its own change record
160// rather than being merged.
161BOOST_AUTO_TEST_CASE( MultipleFootprintRemovalsAllEmitChanges )
162{
163 auto [ownersA, mapA] = FP_LIB_DIFFER::LoadLibrary( getFixturePath() );
164 auto [ownersB, mapB] = FP_LIB_DIFFER::LoadLibrary( getFixturePath() );
165
166 BOOST_REQUIRE_GE( mapB.size(), 3u );
167
168 std::vector<wxString> victims;
169
170 for( int i = 0; i < 3 && !mapB.empty(); ++i )
171 {
172 victims.push_back( mapB.begin()->first );
173 mapB.erase( mapB.begin() );
174 }
175
176 FP_LIB_DIFFER differ( mapA, mapB );
177 DOCUMENT_DIFF result = differ.Diff();
178
179 BOOST_CHECK_EQUAL( result.changes.size(), victims.size() );
180
181 for( const ITEM_CHANGE& c : result.changes )
182 {
183 BOOST_CHECK( c.kind == CHANGE_KIND::REMOVED );
184 }
185}
186
187
188// Output ordering must be deterministic for the same input pair so JSON
189// diffs are byte-stable across runs.
190BOOST_AUTO_TEST_CASE( OutputOrderingIsDeterministicAcrossRuns )
191{
192 auto [ownersA1, mapA1] = FP_LIB_DIFFER::LoadLibrary( getFixturePath() );
193 auto [ownersB1, mapB1] = FP_LIB_DIFFER::LoadLibrary( getFixturePath() );
194 auto [ownersA2, mapA2] = FP_LIB_DIFFER::LoadLibrary( getFixturePath() );
195 auto [ownersB2, mapB2] = FP_LIB_DIFFER::LoadLibrary( getFixturePath() );
196
197 BOOST_REQUIRE_GE( mapB1.size(), 2u );
198
199 mapB1.erase( mapB1.begin() );
200 mapB2.erase( mapB2.begin() );
201
202 FP_LIB_DIFFER differ1( mapA1, mapB1 );
203 FP_LIB_DIFFER differ2( mapA2, mapB2 );
204
205 DOCUMENT_DIFF r1 = differ1.Diff();
206 DOCUMENT_DIFF r2 = differ2.Diff();
207
208 BOOST_CHECK_EQUAL( r1.ToJson().dump(), r2.ToJson().dump() );
209}
210
211
General utilities for PCB file IO for QA programs.
void Move(const VECTOR2I &aMoveVector) override
Move this object.
Diff two .pretty footprint library directories.
static std::pair< std::vector< std::unique_ptr< FOOTPRINT > >, FOOTPRINT_MAP > LoadLibrary(const wxString &aPrettyPath)
Load a .pretty directory into a FOOTPRINT_MAP.
DOCUMENT_DIFF Diff() override
Produce a DOCUMENT_DIFF of the inputs the concrete differ was constructed with.
A color representation with 4 components: red, green, blue, alpha.
Definition color4d.h:101
A type-safe container of any type.
Definition ki_any.h:92
LSET GeometryLayerSet(const DOCUMENT_GEOMETRY &aGeometry)
Return the union of every non-empty layer set carried by the geometry.
KIID_PATH LibraryItemKiidPath(const wxString &aName)
Build a deterministic synthetic KIID_PATH from a library item name (symbol name or footprint name).
DOCUMENT_GEOMETRY ExtractFootprintGeometry(const FOOTPRINT &aFootprint, const KIGFX::COLOR4D &aColor)
Extract drawable context geometry from a single FOOTPRINT.
std::string GetPcbnewTestDataDir()
Utility which returns a path to the data directory where the test board files are stored.
The full set of changes between two parsed documents of one type.
nlohmann::json ToJson() const
static DOCUMENT_DIFF FromJson(const nlohmann::json &aJson)
std::vector< ITEM_CHANGE > changes
Aggregate of background geometry extracted from one source document.
Definition diff_scene.h:163
One change record on a single item.
BOOST_AUTO_TEST_SUITE(CadstarPartParser)
static wxString getFixturePath()
BOOST_AUTO_TEST_CASE(IdenticalLibrariesDiffEmpty)
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_AUTO_TEST_SUITE_END()
static wxString getFixturePath()
wxString result
Test unit parsing edge cases and error handling.
BOOST_CHECK_EQUAL(result, "25.4")
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683