KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_erc_label_names.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, see <https://www.gnu.org/licenses/>.
18 */
19
22
23#include <advanced_config.h>
24#include <sch_sheet.h>
25#include <sch_sheet_pin.h>
26#include <algorithm>
27#include <set>
28#include <connection_graph.h>
29#include <sch_label.h>
30#include <sch_marker.h>
31#include <schematic.h>
32#include <erc/erc_settings.h>
33#include <erc/erc.h>
34#include <erc/erc_exclusion.h>
35#include <erc/erc_report.h>
37#include <locale_io.h>
38#include <scoped_set_reset.h>
39
40namespace
41{
42struct ERC_REGRESSION_TEST_FIXTURE
43{
44 ERC_REGRESSION_TEST_FIXTURE() {}
45
46 SETTINGS_MANAGER m_settingsManager;
47 std::unique_ptr<SCHEMATIC> m_schematic;
48};
49} // namespace
50
51
52static int CountErrorCode( SHEETLIST_ERC_ITEMS_PROVIDER& aErrors, int aErrorCode )
53{
54 int count = 0;
55
56 for( int i = 0; i < aErrors.GetCount(); ++i )
57 {
58 std::shared_ptr<ERC_ITEM> ercItem = std::static_pointer_cast<ERC_ITEM>( aErrors.GetItem( i ) );
59
60 if( ercItem && ercItem->GetErrorCode() == aErrorCode )
61 ++count;
62 }
63
64 return count;
65}
66
67
68BOOST_FIXTURE_TEST_CASE( ERCLabelCapitalization, ERC_REGRESSION_TEST_FIXTURE )
69{
71
72 // Check for Errors when using rule area netclass directives
73 std::vector<std::pair<wxString, int>> tests = { { "issue16897", 3 } };
74
75 for( const std::pair<wxString, int>& test : tests )
76 {
77 KI_TEST::LoadSchematic( m_settingsManager, test.first, m_schematic );
78
79 ERC_SETTINGS& settings = m_schematic->ErcSettings();
80 SHEETLIST_ERC_ITEMS_PROVIDER errors( m_schematic.get() );
81
82 // Skip the "Modified symbol" warning
85
86 // Configure the rules under test
90
91 m_schematic->ConnectionGraph()->RunERC();
92
93 ERC_TESTER tester( m_schematic.get() );
94 tester.TestSimilarLabels();
95
97
98 ERC_REPORT reportWriter( m_schematic.get(), EDA_UNITS::MM );
99
100 BOOST_CHECK_MESSAGE( errors.GetCount() == test.second,
101 "Expected " << test.second << " errors in " << test.first.ToStdString()
102 << " but got " << errors.GetCount() << "\n"
103 << reportWriter.GetTextReport() );
104 }
105}
106
107
108BOOST_FIXTURE_TEST_CASE( ERCSimilarLabels, ERC_REGRESSION_TEST_FIXTURE )
109{
111
112 // Check for Errors when using rule area netclass directives
113 std::vector<std::pair<wxString, int>> tests = { { "similar_labels", 3 } };
114
115 for( const std::pair<wxString, int>& test : tests )
116 {
117 KI_TEST::LoadSchematic( m_settingsManager, test.first, m_schematic );
118
119 ERC_SETTINGS& settings = m_schematic->ErcSettings();
120 SHEETLIST_ERC_ITEMS_PROVIDER errors( m_schematic.get() );
121
122 // Skip the "Modified symbol" warning
126
127 // Configure the rules under test
129
130 m_schematic->ConnectionGraph()->RunERC();
131
132 ERC_TESTER tester( m_schematic.get() );
133 tester.TestSimilarLabels();
134
136
137 ERC_REPORT reportWriter( m_schematic.get(), EDA_UNITS::MM );
138
139 BOOST_CHECK_MESSAGE( errors.GetCount() == test.second,
140 "Expected " << test.second << " errors in " << test.first.ToStdString()
141 << " but got " << errors.GetCount() << "\n"
142 << reportWriter.GetTextReport() );
143 }
144}
145
146
147BOOST_FIXTURE_TEST_CASE( ERCSameLocalGlobalLabel, ERC_REGRESSION_TEST_FIXTURE )
148{
150
151 // Check for Errors when using rule area netclass directives
152 std::vector<std::pair<wxString, int>> tests = { { "same_local_global_label", 1 } };
153
154 for( const std::pair<wxString, int>& test : tests )
155 {
156 KI_TEST::LoadSchematic( m_settingsManager, test.first, m_schematic );
157
158 ERC_SETTINGS& settings = m_schematic->ErcSettings();
159 SHEETLIST_ERC_ITEMS_PROVIDER errors( m_schematic.get() );
160
161 // Skip the "Modified symbol" warning
164
165 // Configure the rules under test
167
168 m_schematic->ConnectionGraph()->RunERC();
169
170 ERC_TESTER tester( m_schematic.get() );
172
174
175 ERC_REPORT reportWriter( m_schematic.get(), EDA_UNITS::MM );
176
177 BOOST_CHECK_MESSAGE( errors.GetCount() == test.second,
178 "Expected " << test.second << " errors in " << test.first.ToStdString()
179 << " but got " << errors.GetCount() << "\n"
180 << reportWriter.GetTextReport() );
181 }
182}
183
184
185BOOST_FIXTURE_TEST_CASE( ERCSameLocalGlobalPower, ERC_REGRESSION_TEST_FIXTURE )
186{
188
189 KI_TEST::LoadSchematic( m_settingsManager, "same_local_global_power", m_schematic );
190
191 ERC_SETTINGS& settings = m_schematic->ErcSettings();
192 SHEETLIST_ERC_ITEMS_PROVIDER errors( m_schematic.get() );
193
196
199
200 m_schematic->ConnectionGraph()->RunERC();
201
202 ERC_TESTER tester( m_schematic.get() );
204
206
207 ERC_REPORT reportWriter( m_schematic.get(), EDA_UNITS::MM );
208
209 BOOST_CHECK_MESSAGE( CountErrorCode( errors, ERCE_SAME_LOCAL_GLOBAL_POWER ) == 2,
210 "Expected 2 ERCE_SAME_LOCAL_GLOBAL_POWER violations\n"
211 << reportWriter.GetTextReport() );
212
213 BOOST_CHECK_MESSAGE( CountErrorCode( errors, ERCE_SAME_LOCAL_GLOBAL_LABEL ) == 0,
214 "Expected 0 ERCE_SAME_LOCAL_GLOBAL_LABEL violations\n"
215 << reportWriter.GetTextReport() );
216}
217
218
219BOOST_AUTO_TEST_CASE( ERCLabelNameChecksMatchLegacy )
220{
221 LOCALE_IO locale;
222 auto& enabled = const_cast<ADVANCED_CFG&>( ADVANCED_CFG::GetCfg() ).m_ConnectivityEngine;
223 SCOPED_SET_RESET restore( enabled, enabled );
224 struct CASE
225 {
226 const char* fixture;
227 bool similar;
228 size_t count;
229 };
230
231 for( const CASE& test : { CASE{ "similar_labels", true, 3 },
232 CASE{ "same_local_global_label", false, 1 },
233 CASE{ "same_local_global_power", false, 2 } } )
234 {
235 BOOST_TEST_CONTEXT( test.fixture )
236 {
237 SETTINGS_MANAGER settings;
238 std::unique_ptr<SCHEMATIC> schematic;
239 enabled = false;
240 KI_TEST::LoadSchematic( settings, test.fixture, schematic );
241 schematic->RebuildConnectivity();
242 ERC_TESTER tester( schematic.get() );
243 const auto run = [&]()
244 {
245 if( test.similar )
246 tester.TestSimilarLabels();
247 else
249
250 std::vector<std::string> markers;
251
252 for( const SCH_SHEET_PATH& path : schematic->Hierarchy() )
253 {
254 std::vector<SCH_ITEM*> remove;
255
256 for( SCH_ITEM* item : path.LastScreen()->Items().OfType( SCH_MARKER_T ) )
257 {
258 markers.push_back(
259 ERC_EXCLUSION::FromMarker( *static_cast<SCH_MARKER*>( item ) ).GetSortKey() );
260 remove.push_back( item );
261 }
262
263 for( SCH_ITEM* item : remove )
264 path.LastScreen()->DeleteItem( item );
265 }
266
267 std::sort( markers.begin(), markers.end() );
268 return markers;
269 };
270 const auto legacy = run();
271 BOOST_REQUIRE_EQUAL( legacy.size(), test.count );
272 enabled = true;
273 schematic->RebuildConnectivity();
274 schematic->ConnectionGraph()->Reset();
275 const auto engine = run();
276 BOOST_TEST( engine == legacy, boost::test_tools::per_element() );
277 }
278 }
279}
280
281
282BOOST_AUTO_TEST_CASE( ERCLabelNamesPreferShortestSharedInstance )
283{
284 LOCALE_IO locale;
285 auto& enabled = const_cast<ADVANCED_CFG&>( ADVANCED_CFG::GetCfg() ).m_ConnectivityEngine;
286 SCOPED_SET_RESET restore( enabled, enabled );
287 SETTINGS_MANAGER settings;
288 std::unique_ptr<SCHEMATIC> schematic;
289 KI_TEST::LoadSchematic( settings, "issue9673/issue9673", schematic );
290 std::vector<SCH_SHEET*> sheets;
291
292 for( SCH_ITEM* item : schematic->RootScreen()->Items().OfType( SCH_SHEET_T ) )
293 sheets.push_back( static_cast<SCH_SHEET*>( item ) );
294
295 BOOST_REQUIRE_EQUAL( sheets.size(), 2u );
296 std::ranges::sort( sheets,
297 []( const SCH_SHEET* a, const SCH_SHEET* b )
298 {
299 return a->m_Uuid < b->m_Uuid;
300 } );
301 SCH_SHEET* parent = sheets.front();
302 SCH_SHEET* target = sheets.back();
303 auto* nested = static_cast<SCH_SHEET*>( target->Duplicate( false ) );
304
305 for( SCH_SHEET_PIN* pin : nested->GetPins() )
306 const_cast<KIID&>( pin->m_Uuid ) = KIID();
307
308 parent->GetScreen()->Append( nested );
309 schematic->RefreshHierarchy();
310 std::set<KIID_PATH> paths;
311
312 for( const SCH_SHEET_PATH& path : schematic->Hierarchy() )
313 {
314 if( path.LastScreen() == target->GetScreen() )
315 paths.insert( path.Path() );
316 }
317
318 BOOST_REQUIRE_EQUAL( paths.size(), 2u );
319 const KIID_PATH shallow = *paths.begin();
320 const KIID_PATH deep = *paths.rbegin();
321 BOOST_REQUIRE( shallow.size() < deep.size() );
322 BOOST_REQUIRE( deep.AsString() < shallow.AsString() );
323 SETTINGS_MANAGER sourceSettings;
324 std::unique_ptr<SCHEMATIC> source;
325 KI_TEST::LoadSchematic( sourceSettings, "similar_labels", source );
326 SCH_LABEL_BASE* localSource = nullptr;
327 SCH_LABEL_BASE* globalSource = nullptr;
328
329 for( SCH_ITEM* item : source->RootScreen()->Items() )
330 {
331 if( item->Type() == SCH_LABEL_T && ( !localSource || item->m_Uuid < localSource->m_Uuid ) )
332 localSource = static_cast<SCH_LABEL_BASE*>( item );
333 else if( item->Type() == SCH_GLOBAL_LABEL_T && ( !globalSource || item->m_Uuid < globalSource->m_Uuid ) )
334 globalSource = static_cast<SCH_LABEL_BASE*>( item );
335 }
336
337 BOOST_REQUIRE( localSource );
338 BOOST_REQUIRE( globalSource );
339 auto* local = static_cast<SCH_LABEL_BASE*>( localSource->Duplicate( false ) );
340 auto* global = static_cast<SCH_LABEL_BASE*>( globalSource->Duplicate( false ) );
341 auto* lower = static_cast<SCH_LABEL_BASE*>( globalSource->Duplicate( false ) );
342 local->SetText( wxS( "ERC_DEPTH_ORDER" ) );
343 global->SetText( wxS( "ERC_DEPTH_ORDER" ) );
344 lower->SetText( wxS( "erc_depth_order" ) );
345 lower->Move( globalSource->GetPosition() );
346 BOOST_REQUIRE( lower->GetPosition() != global->GetPosition() );
347 target->GetScreen()->Append( local );
348 target->GetScreen()->Append( global );
349 target->GetScreen()->Append( lower );
350 const std::set<KIID> labels{ local->m_Uuid, global->m_Uuid, lower->m_Uuid };
351
352 for( bool backend : { false, true } )
353 {
354 BOOST_TEST_CONTEXT( "new engine " << backend )
355 {
356 enabled = backend;
357 schematic->RebuildConnectivity();
358 SCH_SCREENS screens( schematic->Root() );
360 ERC_TESTER tester( schematic.get() );
362 size_t same = 0;
363
364 for( SCH_ITEM* item : target->GetScreen()->Items().OfType( SCH_MARKER_T ) )
365 {
366 const auto error = std::static_pointer_cast<ERC_ITEM>( static_cast<SCH_MARKER*>( item )->GetRCItem() );
367
368 if( error->GetMainItemID() == global->m_Uuid && error->GetAuxItemID() == local->m_Uuid )
369 {
370 BOOST_CHECK( error->GetMainItemSheetPath().PathRef() == shallow );
371 BOOST_CHECK( error->GetAuxItemSheetPath().PathRef() == shallow );
372 ++same;
373 }
374 }
375
376 BOOST_CHECK_EQUAL( same, 1u );
378 tester.TestSimilarLabels();
379 size_t crossSheet = 0;
380 size_t sameSheet = 0;
381
382 for( SCH_ITEM* item : target->GetScreen()->Items().OfType( SCH_MARKER_T ) )
383 {
384 const auto error = std::static_pointer_cast<ERC_ITEM>( static_cast<SCH_MARKER*>( item )->GetRCItem() );
385
386 if( !labels.contains( error->GetMainItemID() ) || !labels.contains( error->GetAuxItemID() ) )
387 continue;
388
389 BOOST_CHECK_EQUAL( error->GetErrorCode(), ERCE_SIMILAR_LABELS );
390 const auto& main = error->GetMainItemSheetPath().PathRef();
391 const auto& aux = error->GetAuxItemSheetPath().PathRef();
392
393 // Saved exclusions depend on the main item following path text order
394 if( main != aux )
395 {
396 BOOST_CHECK( main == deep );
397 BOOST_CHECK( aux == shallow );
398 ++crossSheet;
399 }
400 else
401 {
402 ++sameSheet;
403 }
404 }
405
406 BOOST_CHECK_EQUAL( crossSheet, 4u );
407 BOOST_CHECK_EQUAL( sameSheet, 4u );
409 }
410 }
411}
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
const KIID m_Uuid
Definition eda_item.h:599
virtual void SetText(const wxString &aText)
Definition eda_text.cpp:236
EE_TYPE OfType(KICAD_T aType) const
Definition sch_rtree.h:248
static ERC_EXCLUSION FromMarker(const SCH_MARKER &aMarker)
wxString GetTextReport()
Returns the ERC report in "text" (human readable) format in the C-locale.
Container for ERC settings.
std::map< int, SEVERITY > m_ERCSeverities
Runs the electrical rules checks and adds a SCH_MARKER for each violation.
Definition erc.h:60
int TestSimilarLabels()
Checks for labels that differ only in capitalization.
Definition erc.cpp:2753
int TestSameLocalGlobalLabel()
Checks for global and local labels with the same name.
Definition erc.cpp:2712
wxString AsString() const
Definition kiid.cpp:423
Definition kiid.h:46
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
Definition locale_io.h:37
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:170
SCH_ITEM * Duplicate(bool addToParentGroup, SCH_COMMIT *aCommit=nullptr, bool aDoClone=false) const
Routine to create a new copy of given item.
Definition sch_item.cpp:191
Container class that holds multiple SCH_SCREEN objects in a hierarchy.
Definition sch_screen.h:826
void DeleteAllMarkers(enum MARKER_BASE::MARKER_T aMarkerType, bool aIncludeExclusions)
Delete all electronic rules check markers of aMarkerType from all the screens in the list.
void Append(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
EE_RTREE & Items()
Get the full RTree, usually for iterating.
Definition sch_screen.h:122
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
Define a sheet pin (label) used in sheets to create hierarchical schematics.
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition sch_sheet.h:48
SCH_SCREEN * GetScreen() const
Definition sch_sheet.h:151
VECTOR2I GetPosition() const override
Definition sch_text.h:143
RAII class that sets an value at construction and resets it to the original value at destruction.
An implementation of the RC_ITEM_LIST interface which uses the global SHEETLIST to fulfill the contra...
int GetCount(int aSeverity=-1) const override
void SetSeverities(int aSeverities) override
std::shared_ptr< RC_ITEM > GetItem(int aIndex) const override
Retrieve a RC_ITEM by index.
@ ERCE_SIMILAR_POWER
2 power pins are equal for case insensitive comparisons.
@ ERCE_SIMILAR_LABELS
2 labels are equal for case insensitive comparisons.
@ ERCE_SAME_LOCAL_GLOBAL_LABEL
2 labels are equal for case insensitive comparisons.
@ ERCE_SIMILAR_LABEL_AND_POWER
label and pin are equal for case insensitive comparisons.
@ ERCE_SAME_LOCAL_GLOBAL_POWER
Local power port and global power port have the same name.
@ ERCE_LABEL_SINGLE_PIN
A label is connected only to a single pin.
@ ERCE_LIB_SYMBOL_MISMATCH
Symbol doesn't match copy in library.
@ ERCE_LIB_SYMBOL_ISSUES
Symbol not found in active libraries.
std::string source
void LoadSchematic(SETTINGS_MANAGER &aSettingsManager, const wxString &aRelPath, std::unique_ptr< SCHEMATIC > &aSchematic)
@ RPT_SEVERITY_WARNING
@ RPT_SEVERITY_ERROR
@ RPT_SEVERITY_IGNORE
std::vector< FAB_LAYER_COLOR > dummy
static int CountErrorCode(SHEETLIST_ERC_ITEMS_PROVIDER &aErrors, int aErrorCode)
BOOST_AUTO_TEST_CASE(ERCLabelNameChecksMatchLegacy)
BOOST_FIXTURE_TEST_CASE(ERCLabelCapitalization, ERC_REGRESSION_TEST_FIXTURE)
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_TEST(netlist.find("R_G1 ARM_OUT1 DIE_B R='0.001 / ((SW_STATE)") !=std::string::npos)
std::string path
KIBIS_PIN * pin
BOOST_TEST_CONTEXT("Test Clearance")
BOOST_CHECK_EQUAL(result, "25.4")
@ SCH_LABEL_T
Definition typeinfo.h:163
@ SCH_SHEET_T
Definition typeinfo.h:171
@ SCH_MARKER_T
Definition typeinfo.h:154
@ SCH_GLOBAL_LABEL_T
Definition typeinfo.h:164