KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_merge_validators.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
29using namespace KICAD_DIFF;
30
31
32BOOST_AUTO_TEST_SUITE( MergeValidators )
33
34
35BOOST_AUTO_TEST_CASE( RefdesUniquenessPassesOnUnique )
36{
38 KIID id1, id2, id3;
39
40 std::vector<REFDES_ENTRY> entries = {
41 { wxS( "R1" ), KIID_PATH( id1.AsString() ) },
42 { wxS( "R2" ), KIID_PATH( id2.AsString() ) },
43 { wxS( "C1" ), KIID_PATH( id3.AsString() ) },
44 };
45
47 BOOST_CHECK( r.Passed() );
48}
49
50
51BOOST_AUTO_TEST_CASE( RefdesUniquenessDetectsDuplicates )
52{
54 KIID id1, id2;
55
56 std::vector<REFDES_ENTRY> entries = {
57 { wxS( "R1" ), KIID_PATH( id1.AsString() ) },
58 { wxS( "R1" ), KIID_PATH( id2.AsString() ) },
59 };
60
62 BOOST_REQUIRE_EQUAL( r.failures.size(), 1u );
63 BOOST_CHECK( r.HasErrors() );
64 BOOST_CHECK_EQUAL( r.failures[0].validator.ToStdString(), "RefdesUniqueness" );
65 BOOST_CHECK_EQUAL( r.failures[0].relatedItems.size(), 2u );
66}
67
68
69BOOST_AUTO_TEST_CASE( RefdesUniquenessIgnoresEmptyAndPlaceholder )
70{
72 KIID id1, id2, id3;
73
74 std::vector<REFDES_ENTRY> entries = {
75 { wxS( "" ), KIID_PATH( id1.AsString() ) },
76 { wxS( "" ), KIID_PATH( id2.AsString() ) }, // both empty — OK
77 { wxS( "R?" ), KIID_PATH( id3.AsString() ) }, // placeholder — OK
78 };
79
81 BOOST_CHECK( r.Passed() );
82}
83
84
85BOOST_AUTO_TEST_CASE( ConnectivityFlagDetectsMissedRebuild )
86{
87 BOOST_CHECK( CheckConnectivityRebuildFlag( true, true ).Passed() );
88 BOOST_CHECK( CheckConnectivityRebuildFlag( false, false ).Passed() );
89 BOOST_CHECK( CheckConnectivityRebuildFlag( false, true ).Passed() ); // OK to over-rebuild
90
92 BOOST_REQUIRE_EQUAL( r.failures.size(), 1u );
93 BOOST_CHECK( r.HasErrors() );
94}
95
96
97BOOST_AUTO_TEST_CASE( SchemaVersionEqualPasses )
98{
99 VALIDATION_REPORT r = CheckSchemaVersions( 20240108, 20240108, 20240108 );
100 BOOST_CHECK( r.Passed() );
101}
102
103
104BOOST_AUTO_TEST_CASE( SchemaVersionMinorMismatchWarns )
105{
106 VALIDATION_REPORT r = CheckSchemaVersions( 20240108, 20240115, 20240108 );
107 BOOST_REQUIRE_EQUAL( r.failures.size(), 1u );
108 BOOST_CHECK( !r.HasErrors() ); // WARNING only
109}
110
111
112BOOST_AUTO_TEST_CASE( SchemaVersionMajorMismatchErrors )
113{
114 VALIDATION_REPORT r = CheckSchemaVersions( 20180101, 20240115, 20240108 );
115 BOOST_CHECK( r.HasErrors() );
116}
117
118
119BOOST_AUTO_TEST_CASE( ReportMergePreservesFailures )
120{
121 KIID::SeedGenerator( 303 );
122 KIID id1, id2;
123
125 { wxS( "R1" ), KIID_PATH( id1.AsString() ) },
126 { wxS( "R1" ), KIID_PATH( id2.AsString() ) },
127 } );
128
130
131 std::size_t expectedSize = a.failures.size() + b.failures.size();
132 a.Merge( std::move( b ) );
133 BOOST_CHECK_EQUAL( a.failures.size(), expectedSize );
134}
135
136
137BOOST_AUTO_TEST_CASE( ReportMergePreservesFailureContent )
138{
139 // Size alone isn't enough — verify the actual validator names from
140 // both sides land in the merged report. The move-out side must also
141 // be empty (Merge takes by rvalue and clear()s in the impl).
142 KIID::SeedGenerator( 304 );
143 KIID id1, id2;
144
146 { wxS( "R1" ), KIID_PATH( id1.AsString() ) },
147 { wxS( "R1" ), KIID_PATH( id2.AsString() ) },
148 } );
150
151 a.Merge( std::move( b ) );
152
153 BOOST_CHECK( b.failures.empty() );
154
155 bool sawRefdes = false;
156 bool sawConnectivity = false;
157
158 for( const VALIDATION_FAILURE& f : a.failures )
159 {
160 if( f.validator == wxS( "RefdesUniqueness" ) )
161 sawRefdes = true;
162 if( f.validator == wxS( "ConnectivityRebuild" ) )
163 sawConnectivity = true;
164 }
165
166 BOOST_CHECK( sawRefdes );
167 BOOST_CHECK( sawConnectivity );
168}
169
170
171BOOST_AUTO_TEST_CASE( HasErrorsMixedSeverityFindsError )
172{
173 // HasErrors must short-circuit on a single ERROR even when WARNINGs
174 // also exist. A naive "all entries are errors" implementation would
175 // miss this case.
177
180 w.validator = wxS( "WarnOnly" );
181 r.failures.push_back( w );
182
185 e.validator = wxS( "RealError" );
186 r.failures.push_back( e );
187
188 BOOST_CHECK( r.HasErrors() );
189 BOOST_CHECK( !r.Passed() );
190}
191
192
193BOOST_AUTO_TEST_CASE( HasErrorsAllWarningsIsClean )
194{
195 // Only-warning reports must read as "passed for the purposes of
196 // errors" — the caller can still surface warnings separately, but
197 // HasErrors is the gate that blocks the merge.
199
202 r.failures.push_back( w1 );
203
206 r.failures.push_back( w2 );
207
208 BOOST_CHECK( !r.HasErrors() );
209 BOOST_CHECK( !r.Passed() ); // warnings still fail Passed()
210}
211
212
213BOOST_AUTO_TEST_CASE( HasErrorsEmptyReportIsClean )
214{
216 BOOST_CHECK( !r.HasErrors() );
217 BOOST_CHECK( r.Passed() );
218}
219
220
221BOOST_AUTO_TEST_CASE( SchemaVersionBoundaryDeltaJustBelowMajor )
222{
223 // 48885 < MAJOR_EPOCH_DELTA (50000), so this should warn, not error.
224 // Without an explicit boundary test the threshold could drift silently.
225 VALIDATION_REPORT r = CheckSchemaVersions( 20240115, 20290000, 20240115 );
226 BOOST_REQUIRE_EQUAL( r.failures.size(), 1u );
227 BOOST_CHECK( !r.HasErrors() );
228}
229
230
231BOOST_AUTO_TEST_CASE( SchemaVersionBoundaryDeltaExactly50000 )
232{
233 // Delta == 50000 exactly. The implementation uses `>=` so this is the
234 // first ERROR; a future refactor to `>` would silently downgrade this
235 // case to WARNING and let a borderline-stale schema land. Pin the
236 // inclusive comparison explicitly.
237 VALIDATION_REPORT r = CheckSchemaVersions( 20200000, 20250000, 20200000 );
238 BOOST_REQUIRE( !r.failures.empty() );
239 BOOST_CHECK( r.HasErrors() );
240}
241
242
243BOOST_AUTO_TEST_CASE( RefdesUniquenessSingleEntryNeverFails )
244{
245 // A single entry can't collide with itself — the < 2 guard prevents
246 // emitting a vacuous self-collision report.
247 KIID::SeedGenerator( 305 );
248 KIID id1;
249 std::vector<REFDES_ENTRY> entries = {
250 { wxS( "R1" ), KIID_PATH( id1.AsString() ) },
251 };
252 BOOST_CHECK( CheckRefdesUniqueness( entries ).Passed() );
253}
254
255
256BOOST_AUTO_TEST_CASE( RefdesUniquenessThreeWayCollision )
257{
258 // Triple collision should surface all three ids in relatedItems, not
259 // just the first pair detected.
260 KIID::SeedGenerator( 306 );
261 KIID id1, id2, id3;
262 std::vector<REFDES_ENTRY> entries = {
263 { wxS( "U1" ), KIID_PATH( id1.AsString() ) },
264 { wxS( "U1" ), KIID_PATH( id2.AsString() ) },
265 { wxS( "U1" ), KIID_PATH( id3.AsString() ) },
266 };
267
269 BOOST_REQUIRE_EQUAL( r.failures.size(), 1u );
270 BOOST_CHECK_EQUAL( r.failures[0].relatedItems.size(), 3u );
271}
272
273
Definition kiid.h:44
static void SeedGenerator(unsigned int aSeed)
Re-initialize the UUID generator with a given seed (for testing or QA purposes)
Definition kiid.cpp:331
wxString AsString() const
Definition kiid.cpp:242
VALIDATION_REPORT CheckConnectivityRebuildFlag(bool aPlanRequiredRebuild, bool aApplierReportedRebuild)
Information needed for the connectivity-rebuild side-effect check.
VALIDATION_REPORT CheckSchemaVersions(int aAncestorVersion, int aOursVersion, int aTheirsVersion)
Schema-version compatibility check: every input to the merge must use a compatible serialization vers...
VALIDATION_REPORT CheckRefdesUniqueness(const std::vector< REFDES_ENTRY > &aEntries)
Run refdes-uniqueness checks.
@ RPT_SEVERITY_WARNING
@ RPT_SEVERITY_ERROR
Outcome of a single validator run.
void Merge(VALIDATION_REPORT &&aOther)
std::vector< VALIDATION_FAILURE > failures
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_AUTO_TEST_SUITE(CadstarPartParser)
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_AUTO_TEST_SUITE_END()
BOOST_AUTO_TEST_CASE(RefdesUniquenessPassesOnUnique)
BOOST_CHECK_EQUAL(result, "25.4")