KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_erc_shared_pin_multiunit.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 at
18 * http://www.gnu.org/licenses/
19 */
20
33
36
37#include <connection_graph.h>
38#include <schematic.h>
39#include <erc/erc_settings.h>
40#include <erc/erc.h>
41#include <erc/erc_report.h>
44#include <locale_io.h>
45
46
54
55
56BOOST_FIXTURE_TEST_CASE( Issue1768_SharedPinDifferentNets, ERC_SHARED_PIN_TEST_FIXTURE )
57{
59
60 // Load the issue 1768 test schematic
61 // This schematic has a 4-unit diode symbol (ESDAxx-SC5-V) where pin 2 is the
62 // common anode shared across all units. In the test case, only unit 2 has
63 // pin 2 connected to GND, while the other units have pin 2 unconnected
64 // (which results in auto-generated net names).
65 KI_TEST::LoadSchematic( m_settingsManager, "issue1768/issue1768", m_schematic );
66
67 ERC_SETTINGS& settings = m_schematic->ErcSettings();
68 SHEETLIST_ERC_ITEMS_PROVIDER errors( m_schematic.get() );
69
70 // Ignore library symbol warnings since we're using old/rescue symbols
73
74 // Build connectivity and run ERC
75 m_schematic->ConnectionGraph()->RunERC();
76
77 ERC_TESTER tester( m_schematic.get() );
78
79 // This is the key test - TestMultUnitPinConflicts should detect that the shared
80 // pin 2 is connected to different nets across different unit instances
81 int multiUnitErrors = tester.TestMultUnitPinConflicts();
82
84
85 ERC_REPORT reportWriter( m_schematic.get(), EDA_UNITS::MM );
86
87 // We expect at least one ERCE_DIFFERENT_UNIT_NET error because pin 2
88 // is connected to GND in one unit but has auto-generated nets in others
89 BOOST_CHECK_MESSAGE( multiUnitErrors > 0,
90 "Expected ERC to detect shared pin on different nets.\n"
91 << reportWriter.GetTextReport() );
92
93 // Verify the specific error type is present
94 bool foundDifferentUnitNetError = false;
95
96 for( int i = 0; i < errors.GetCount(); ++i )
97 {
98 std::shared_ptr<RC_ITEM> item = errors.GetItem( i );
99
100 if( item && item->GetErrorCode() == ERCE_DIFFERENT_UNIT_NET )
101 {
102 foundDifferentUnitNetError = true;
103 break;
104 }
105 }
106
107 BOOST_CHECK_MESSAGE( foundDifferentUnitNetError,
108 "Expected ERCE_DIFFERENT_UNIT_NET error for shared pin 2.\n"
109 << reportWriter.GetTextReport() );
110}
111
112
113BOOST_AUTO_TEST_CASE( Issue1768_NetlistPreferUserNet )
114{
115 // Test that the netlist exporter's eraseDuplicatePins() prefers user-assigned nets
116 // over auto-generated "unconnected-(" or "Net-(" nets.
117
118 std::vector<PIN_INFO> pins;
119
120 // Simulate duplicate pin 2 entries: one with auto-generated net, one with user net
121 // The auto-generated net appears first (simulating the problematic ordering)
122 pins.emplace_back( wxT( "2" ), wxT( "unconnected-(VD1A-A-Pad2)" ), wxT( "A" ) );
123 pins.emplace_back( wxT( "2" ), wxT( "GND" ), wxT( "A" ) );
124 pins.emplace_back( wxT( "3" ), wxT( "Net-(VD1-K)" ), wxT( "K" ) );
125
126 // Helper lambda matching the one in eraseDuplicatePins
127 auto isAutoGeneratedNet = []( const wxString& aNetName ) -> bool
128 {
129 return aNetName.StartsWith( wxT( "unconnected-(" ) )
130 || aNetName.StartsWith( wxT( "Net-(" ) );
131 };
132
133 // Simulate eraseDuplicatePins logic
134 for( unsigned ii = 0; ii < pins.size(); ii++ )
135 {
136 if( pins[ii].num.empty() )
137 continue;
138
139 unsigned idxBest = ii;
140
141 for( unsigned jj = ii + 1; jj < pins.size(); jj++ )
142 {
143 if( pins[jj].num.empty() )
144 continue;
145
146 if( pins[idxBest].num != pins[jj].num )
147 break;
148
149 bool bestIsAuto = isAutoGeneratedNet( pins[idxBest].netName );
150 bool jjIsAuto = isAutoGeneratedNet( pins[jj].netName );
151
152 if( bestIsAuto && !jjIsAuto )
153 {
154 pins[idxBest].num.clear();
155 idxBest = jj;
156 }
157 else
158 {
159 pins[jj].num.clear();
160 }
161 }
162 }
163
164 // Collect non-deleted pins
165 std::vector<PIN_INFO> result;
166
167 for( const PIN_INFO& pin : pins )
168 {
169 if( !pin.num.empty() )
170 result.push_back( pin );
171 }
172
173 // Should have 2 pins remaining (pin 2 and pin 3)
174 BOOST_REQUIRE_EQUAL( result.size(), 2 );
175
176 // Pin 2 should have the user-assigned net "GND", not the auto-generated one
177 BOOST_CHECK_EQUAL( result[0].num, wxT( "2" ) );
178 BOOST_CHECK_EQUAL( result[0].netName, wxT( "GND" ) );
179
180 // Pin 3 keeps its net (even though it's auto-generated, there's no duplicate)
181 BOOST_CHECK_EQUAL( result[1].num, wxT( "3" ) );
182 BOOST_CHECK_EQUAL( result[1].netName, wxT( "Net-(VD1-K)" ) );
183}
184
185
186BOOST_AUTO_TEST_CASE( Issue1768_NetlistPreferUserNet_ReverseOrder )
187{
188 // Same test but with user net appearing first - should still work correctly
189
190 std::vector<PIN_INFO> pins;
191
192 // User net appears first this time
193 pins.emplace_back( wxT( "2" ), wxT( "GND" ), wxT( "A" ) );
194 pins.emplace_back( wxT( "2" ), wxT( "unconnected-(VD1A-A-Pad2)" ), wxT( "A" ) );
195
196 auto isAutoGeneratedNet = []( const wxString& aNetName ) -> bool
197 {
198 return aNetName.StartsWith( wxT( "unconnected-(" ) )
199 || aNetName.StartsWith( wxT( "Net-(" ) );
200 };
201
202 for( unsigned ii = 0; ii < pins.size(); ii++ )
203 {
204 if( pins[ii].num.empty() )
205 continue;
206
207 unsigned idxBest = ii;
208
209 for( unsigned jj = ii + 1; jj < pins.size(); jj++ )
210 {
211 if( pins[jj].num.empty() )
212 continue;
213
214 if( pins[idxBest].num != pins[jj].num )
215 break;
216
217 bool bestIsAuto = isAutoGeneratedNet( pins[idxBest].netName );
218 bool jjIsAuto = isAutoGeneratedNet( pins[jj].netName );
219
220 if( bestIsAuto && !jjIsAuto )
221 {
222 pins[idxBest].num.clear();
223 idxBest = jj;
224 }
225 else
226 {
227 pins[jj].num.clear();
228 }
229 }
230 }
231
232 std::vector<PIN_INFO> result;
233
234 for( const PIN_INFO& pin : pins )
235 {
236 if( !pin.num.empty() )
237 result.push_back( pin );
238 }
239
240 BOOST_REQUIRE_EQUAL( result.size(), 1 );
241 BOOST_CHECK_EQUAL( result[0].num, wxT( "2" ) );
242 BOOST_CHECK_EQUAL( result[0].netName, wxT( "GND" ) );
243}
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
int TestMultUnitPinConflicts()
Checks if shared pins on multi-unit symbols have been connected to different nets.
Definition erc.cpp:1174
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
Definition locale_io.h:41
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_DIFFERENT_UNIT_NET
Shared pin in a multi-unit symbol is connected to more than one net.
@ ERCE_LIB_SYMBOL_MISMATCH
Symbol doesn't match copy in library.
@ ERCE_LIB_SYMBOL_ISSUES
Symbol not found in active libraries.
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
std::unique_ptr< SCHEMATIC > m_schematic
BOOST_AUTO_TEST_CASE(Issue1768_NetlistPreferUserNet)
BOOST_FIXTURE_TEST_CASE(Issue1768_SharedPinDifferentNets, ERC_SHARED_PIN_TEST_FIXTURE)
KIBIS_PIN * pin
wxString result
Test unit parsing edge cases and error handling.
BOOST_CHECK_EQUAL(result, "25.4")