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