KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_erc_bus_conflicts.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 modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation, either version 3 of the License, or (at your
9 * option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * 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#include <advanced_config.h>
23#include <connection_graph.h>
24#include <erc/erc.h>
25#include <erc/erc_settings.h>
26#include <locale_io.h>
27#include <schematic.h>
28#include <sch_label.h>
29#include <sch_line.h>
30#include <sch_marker.h>
32#include <set>
33#include <tuple>
34#include <scoped_set_reset.h>
35
36BOOST_AUTO_TEST_CASE( ERCBusNetConflictsUsePublishedInstances )
37{
38 LOCALE_IO locale;
39 auto& enabled = const_cast<ADVANCED_CFG&>( ADVANCED_CFG::GetCfg() ).m_ConnectivityEngine;
40 SCOPED_SET_RESET restore( enabled, enabled );
41
42 for( int variant = 0; variant < 6; ++variant )
43 {
44 BOOST_TEST_CONTEXT( "variant=" << variant )
45 {
46 enabled = false;
47 SETTINGS_MANAGER settings;
48 std::unique_ptr<SCHEMATIC> schematic;
49 KI_TEST::LoadSchematic( settings, "issue23840/BusAndVectors", schematic );
50 SCH_SCREEN* screen = nullptr;
51 std::set<KIID_PATH> paths;
52
53 for( const SCH_SHEET_PATH& path : schematic->Hierarchy() )
54 {
55 if( path.LastScreen()->GetFileName().EndsWith( "LEDs.kicad_sch" ) )
56 {
57 BOOST_REQUIRE( !screen || screen == path.LastScreen() );
58 screen = path.LastScreen();
59 paths.insert( path.PathRef() );
60 }
61 }
62
63 BOOST_REQUIRE( screen );
64 BOOST_REQUIRE_EQUAL( paths.size(), 2 );
65 SCH_LABEL* labelSource = nullptr;
66 SCH_LINE* wireSource = nullptr;
67 BOX2I bounds;
68
69 for( SCH_ITEM* item : screen->Items() )
70 {
71 bounds.Merge( item->GetBoundingBox() );
72
73 if( item->Type() == SCH_LABEL_T && ( !labelSource || item->m_Uuid < labelSource->m_Uuid ) )
74 labelSource = static_cast<SCH_LABEL*>( item );
75
76 if( item->Type() == SCH_LINE_T && item->GetLayer() == LAYER_WIRE )
77 {
78 auto* line = static_cast<SCH_LINE*>( item );
79
80 if( line->GetStartPoint() != line->GetEndPoint()
81 && ( !wireSource || item->m_Uuid < wireSource->m_Uuid ) )
82 {
83 wireSource = line;
84 }
85 }
86 }
87
88 BOOST_REQUIRE( labelSource );
89 BOOST_REQUIRE( wireSource );
90 const VECTOR2I anchor = bounds.GetEnd() + VECTOR2I( 100000, 100000 );
91 auto* label = static_cast<SCH_LABEL*>( labelSource->Duplicate( false ) );
92 label->SetPosition( anchor );
93 label->SetText( variant == 1 || variant == 4 ? "ERC_BUS[0..1]" : "ERC_SIGNAL" );
94 screen->Append( label );
95 SCH_ITEM* other = nullptr;
96
97 if( variant == 0 )
98 {
99 auto* bus = static_cast<SCH_LABEL*>( labelSource->Duplicate( false ) );
100 bus->SetText( "ERC_BUS[0..1]" );
101 bus->SetPosition( anchor );
102 other = bus;
103 }
104 else
105 {
106 auto* line = static_cast<SCH_LINE*>( wireSource->Duplicate( false ) );
107 line->Move( anchor - ( line->GetStartPoint() + line->GetEndPoint() ) / 2 );
108 line->SetLayer( variant == 2 || variant >= 4 ? LAYER_BUS : LAYER_WIRE );
109 other = line;
110 }
111
112 screen->Append( other );
113
114 if( variant == 5 )
115 {
116 auto* extraBus = static_cast<SCH_LABEL*>( labelSource->Duplicate( false ) );
117 extraBus->SetText( "ERC_BUS[0..1]" );
118 extraBus->SetPosition( anchor );
119 screen->Append( extraBus );
120 }
121
122 for( auto& [code, severity] : schematic->ErcSettings().m_ERCSeverities )
123 severity = RPT_SEVERITY_IGNORE;
124
125 schematic->ErcSettings().m_ERCSeverities[ERCE_BUS_TO_NET_CONFLICT] = RPT_SEVERITY_ERROR;
126 using DIAGNOSTIC = std::tuple<KIID_PATH, KIID, KIID, int, int>;
127 std::set<KIID_PATH> excludedPaths;
128 const auto diagnostics = [&]( bool aRecordExclusions = false )
129 {
130 std::multiset<DIAGNOSTIC> result;
131 std::vector<SCH_MARKER*> markers;
132
133 for( SCH_ITEM* item : screen->Items().OfType( SCH_MARKER_T ) )
134 {
135 auto* marker = static_cast<SCH_MARKER*>( item );
136 const auto error = std::static_pointer_cast<ERC_ITEM>( marker->GetRCItem() );
137
138 if( error->GetMainItemID() == label->m_Uuid || error->GetMainItemID() == other->m_Uuid )
139 {
140 BOOST_CHECK_EQUAL( error->GetErrorCode(), ERCE_BUS_TO_NET_CONFLICT );
141 BOOST_CHECK( !error->MainItemHasSheetPath() );
142
143 if( aRecordExclusions )
144 {
145 marker->SetExcluded( true, "Retained bus/net conflict" );
146 excludedPaths.insert( error->GetSpecificSheetPath().PathRef() );
147 }
148
149 const bool excluded = excludedPaths.contains( error->GetSpecificSheetPath().PathRef() );
150 BOOST_CHECK_EQUAL( marker->IsExcluded(), excluded );
151
152 if( excluded )
153 BOOST_CHECK_EQUAL( marker->GetComment(), wxString( "Retained bus/net conflict" ) );
154
155 result.emplace( error->GetSpecificSheetPath().PathRef(), error->GetMainItemID(),
156 error->GetAuxItemID(), marker->GetPosition().x, marker->GetPosition().y );
157 }
158
159 markers.push_back( marker );
160 }
161
162 if( aRecordExclusions )
163 schematic->RecordERCExclusions();
164
165 for( SCH_MARKER* marker : markers )
166 screen->DeleteItem( marker );
167
168 return result;
169 };
170 schematic->RebuildConnectivity();
171 schematic->ConnectionGraph()->RunERC();
172 const auto expected = diagnostics( true );
173
174 if( variant < 3 || variant == 5 )
175 BOOST_REQUIRE_EQUAL( expected.size(), 1 );
176 else
177 BOOST_REQUIRE( expected.empty() );
178
179 for( bool backend : { false, true } )
180 {
181 enabled = backend;
182 schematic->RebuildConnectivity();
183
184 for( bool clearLegacy : { false, true } )
185 {
186 // Only the engine can report without the legacy graph
187 if( clearLegacy && !backend )
188 continue;
189
190 if( clearLegacy )
191 schematic->ConnectionGraph()->Reset();
192
193 BOOST_TEST_CONTEXT( "backend=" << backend << "; clearLegacy=" << clearLegacy )
194 {
195 schematic->ConnectionGraph()->RunERC();
196 schematic->ResolveERCExclusionsPostUpdate();
197 BOOST_CHECK( diagnostics() == expected );
198 }
199 }
200 }
201 }
202 }
203}
BOX2< VECTOR2I > BOX2I
Definition box2.h:927
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
constexpr const Vec GetEnd() const
Definition box2.h:209
constexpr BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
Definition box2.h:653
const KIID m_Uuid
Definition eda_item.h:597
virtual void SetText(const wxString &aText)
Definition eda_text.cpp:231
EE_TYPE OfType(KICAD_T aType) const
Definition sch_rtree.h:248
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 doClone=false) const
Routine to create a new copy of given item.
Definition sch_item.cpp:186
void SetPosition(const VECTOR2I &aPosition) override
Segment description base class to describe items which have 2 end points (track, wire,...
Definition sch_line.h:39
void Move(const VECTOR2I &aMoveVector) override
Move the item by aMoveVector to a new position.
Definition sch_line.cpp:247
void Append(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
EE_RTREE & Items()
Get the full RTree, usually for iterating.
Definition sch_screen.h:122
void DeleteItem(SCH_ITEM *aItem)
Remove aItem from the linked list and deletes the object.
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
RAII class that sets an value at construction and resets it to the original value at destruction.
@ ERCE_BUS_TO_NET_CONFLICT
A bus wire is graphically connected to a net port/pin (or vice versa).
@ LAYER_WIRE
Definition layer_ids.h:474
@ LAYER_BUS
Definition layer_ids.h:475
void LoadSchematic(SETTINGS_MANAGER &aSettingsManager, const wxString &aRelPath, std::unique_ptr< SCHEMATIC > &aSchematic)
@ RPT_SEVERITY_ERROR
@ RPT_SEVERITY_IGNORE
BOOST_AUTO_TEST_CASE(ERCBusNetConflictsUsePublishedInstances)
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
std::string path
VECTOR3I expected(15, 30, 45)
BOOST_TEST_CONTEXT("Test Clearance")
wxString result
Test unit parsing edge cases and error handling.
BOOST_CHECK_EQUAL(result, "25.4")
@ SCH_LINE_T
Definition typeinfo.h:159
@ SCH_LABEL_T
Definition typeinfo.h:163
@ SCH_MARKER_T
Definition typeinfo.h:154
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683