KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_pads_common.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
24
25#include <boost/test/unit_test.hpp>
26#include <io/pads/pads_common.h>
27#include <kiid.h>
28#include <wx/string.h>
29
31
32
33BOOST_AUTO_TEST_SUITE( PadsCommon )
34
35
36BOOST_AUTO_TEST_CASE( GenerateDeterministicUuid_Deterministic )
37{
38 // Same input should always produce the same UUID
39 std::string identifier = "R1";
40
41 KIID uuid1 = PADS_COMMON::GenerateDeterministicUuid( identifier );
42 KIID uuid2 = PADS_COMMON::GenerateDeterministicUuid( identifier );
43
44 BOOST_CHECK( uuid1 == uuid2 );
45 BOOST_CHECK_EQUAL( uuid1.AsString(), uuid2.AsString() );
46}
47
48
49BOOST_AUTO_TEST_CASE( GenerateDeterministicUuid_DifferentInputs )
50{
51 // Different inputs should produce different UUIDs
55
56 BOOST_CHECK( uuid1 != uuid2 );
57 BOOST_CHECK( uuid1 != uuid3 );
58 BOOST_CHECK( uuid2 != uuid3 );
59}
60
61
62BOOST_AUTO_TEST_CASE( GenerateDeterministicUuid_ValidFormat )
63{
64 // UUID should be in valid format
66 wxString uuidStr = uuid.AsString();
67
68 // UUID format: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx (36 chars)
69 BOOST_CHECK_EQUAL( uuidStr.Length(), 36u );
70 BOOST_CHECK( uuidStr[8] == '-' );
71 BOOST_CHECK( uuidStr[13] == '-' );
72 BOOST_CHECK( uuidStr[18] == '-' );
73 BOOST_CHECK( uuidStr[23] == '-' );
74
75 // Check version nibble is 4 (position 14)
76 BOOST_CHECK( uuidStr[14] == '4' );
77}
78
79
80BOOST_AUTO_TEST_CASE( GenerateDeterministicUuid_EmptyString )
81{
82 // Empty string should still produce a valid UUID
84 wxString uuidStr = uuid.AsString();
85
86 BOOST_CHECK_EQUAL( uuidStr.Length(), 36u );
87}
88
89
90BOOST_AUTO_TEST_CASE( GenerateDeterministicUuid_LongString )
91{
92 // Long string should still produce a valid UUID
93 std::string longId = "VERY_LONG_COMPONENT_NAME_WITH_LOTS_OF_CHARACTERS_12345";
95 wxString uuidStr = uuid.AsString();
96
97 BOOST_CHECK_EQUAL( uuidStr.Length(), 36u );
98
99 // Same long string should produce same UUID
101 BOOST_CHECK( uuid == uuid2 );
102}
103
104
105BOOST_AUTO_TEST_CASE( GenerateDeterministicUuid_CrossProbeConsistency )
106{
107 // Simulate cross-probe linking: same identifier from both schematic and PCB
108 // should produce the same UUID
109 std::string schematicId = "PADS:IC_QUAD_NAND/U1";
110 std::string pcbId = "PADS:IC_QUAD_NAND/U1";
111
112 KIID schUuid = PADS_COMMON::GenerateDeterministicUuid( schematicId );
114
115 BOOST_CHECK( schUuid == pcbUuid );
116}
117
118
120
121
122BOOST_AUTO_TEST_SUITE( PadsSafeParsing )
123
124
125BOOST_AUTO_TEST_CASE( ParseInt_ValidInput )
126{
131}
132
133
134BOOST_AUTO_TEST_CASE( ParseInt_InvalidInput )
135{
138 BOOST_CHECK_EQUAL( PADS_COMMON::ParseInt( "abc", 99 ), 99 );
140}
141
142
143BOOST_AUTO_TEST_CASE( ParseInt_Overflow )
144{
145 BOOST_CHECK_EQUAL( PADS_COMMON::ParseInt( "99999999999999999", -1 ), -1 );
146}
147
148
149BOOST_AUTO_TEST_CASE( ParseDouble_ValidInput )
150{
151 BOOST_CHECK_CLOSE( PADS_COMMON::ParseDouble( "3.14" ), 3.14, 0.001 );
152 BOOST_CHECK_CLOSE( PADS_COMMON::ParseDouble( "-2.5" ), -2.5, 0.001 );
153 BOOST_CHECK_CLOSE( PADS_COMMON::ParseDouble( "0.0" ), 0.0, 0.001 );
154 BOOST_CHECK_CLOSE( PADS_COMMON::ParseDouble( "100" ), 100.0, 0.001 );
155}
156
157
158BOOST_AUTO_TEST_CASE( ParseDouble_InvalidInput )
159{
160 BOOST_CHECK_CLOSE( PADS_COMMON::ParseDouble( "xyz" ), 0.0, 0.001 );
161 BOOST_CHECK_CLOSE( PADS_COMMON::ParseDouble( "" ), 0.0, 0.001 );
162 BOOST_CHECK_CLOSE( PADS_COMMON::ParseDouble( "xyz", 1.5 ), 1.5, 0.001 );
163}
164
165
166BOOST_AUTO_TEST_CASE( ParseDouble_Overflow )
167{
168 BOOST_CHECK_CLOSE( PADS_COMMON::ParseDouble( "1e999", -1.0 ), -1.0, 0.001 );
169}
170
171
172BOOST_AUTO_TEST_CASE( PadsLineStyleToKiCad_KnownStyles )
173{
175 static_cast<int>( LINE_STYLE::SOLID ) );
176 BOOST_CHECK_EQUAL( static_cast<int>( PADS_COMMON::PadsLineStyleToKiCad( -1 ) ),
177 static_cast<int>( LINE_STYLE::SOLID ) );
178 BOOST_CHECK_EQUAL( static_cast<int>( PADS_COMMON::PadsLineStyleToKiCad( -2 ) ),
179 static_cast<int>( LINE_STYLE::DASH ) );
180 BOOST_CHECK_EQUAL( static_cast<int>( PADS_COMMON::PadsLineStyleToKiCad( -3 ) ),
181 static_cast<int>( LINE_STYLE::DOT ) );
182 BOOST_CHECK_EQUAL( static_cast<int>( PADS_COMMON::PadsLineStyleToKiCad( -4 ) ),
183 static_cast<int>( LINE_STYLE::DASHDOT ) );
184 BOOST_CHECK_EQUAL( static_cast<int>( PADS_COMMON::PadsLineStyleToKiCad( -5 ) ),
185 static_cast<int>( LINE_STYLE::DASHDOTDOT ) );
186}
187
188
189BOOST_AUTO_TEST_CASE( PadsLineStyleToKiCad_DefaultFallback )
190{
191 // Style 0 is the old dashed format
193 static_cast<int>( LINE_STYLE::DASH ) );
194
195 // Unknown values fall back to SOLID
196 BOOST_CHECK_EQUAL( static_cast<int>( PADS_COMMON::PadsLineStyleToKiCad( 42 ) ),
197 static_cast<int>( LINE_STYLE::SOLID ) );
198}
199
200
202
203
204BOOST_AUTO_TEST_SUITE( PadsNetNameConversion )
205
206
207BOOST_AUTO_TEST_CASE( ConvertInvertedNetName_InvertedSignal )
208{
209 // PADS "/" prefix indicates an inverted signal, converted to KiCad overbar notation
210 BOOST_CHECK_EQUAL( PADS_COMMON::ConvertInvertedNetName( "/CNTRL" ), wxS( "~{CNTRL}" ) );
211 BOOST_CHECK_EQUAL( PADS_COMMON::ConvertInvertedNetName( "/RESET" ), wxS( "~{RESET}" ) );
212 BOOST_CHECK_EQUAL( PADS_COMMON::ConvertInvertedNetName( "/CS" ), wxS( "~{CS}" ) );
213}
214
215
216BOOST_AUTO_TEST_CASE( ConvertInvertedNetName_NormalSignal )
217{
218 // Non-inverted signals pass through unchanged
221 BOOST_CHECK_EQUAL( PADS_COMMON::ConvertInvertedNetName( "NET_1" ), wxS( "NET_1" ) );
222}
223
224
225BOOST_AUTO_TEST_CASE( ConvertInvertedNetName_SpecialCharacters )
226{
227 // Net names with special characters preserved (no sanitization)
228 BOOST_CHECK_EQUAL( PADS_COMMON::ConvertInvertedNetName( "$3.3V" ), wxS( "$3.3V" ) );
230 BOOST_CHECK_EQUAL( PADS_COMMON::ConvertInvertedNetName( "NET 1" ), wxS( "NET 1" ) );
231}
232
233
234BOOST_AUTO_TEST_CASE( ConvertInvertedNetName_Empty )
235{
237}
238
239
240BOOST_AUTO_TEST_CASE( ConvertInvertedNetName_SlashOnly )
241{
242 // A bare "/" becomes an empty overbar
244}
245
246
248
249
250BOOST_AUTO_TEST_SUITE( PadsTextConversion )
251
252BOOST_AUTO_TEST_CASE( ConvertText_PlainAscii )
253{
254 BOOST_CHECK_EQUAL( PADS_COMMON::ConvertText( "6 RELAY 137D" ), wxS( "6 RELAY 137D" ) );
255}
256
257
258BOOST_AUTO_TEST_CASE( ConvertText_Empty )
259{
261}
262
263
264BOOST_AUTO_TEST_CASE( ConvertText_Latin1Copyright )
265{
266 // Issue #23856: a lone 0xA9 (copyright) byte is invalid UTF-8 and used to
267 // drop the whole string.
268 std::string latin1 = std::string( "\xA9 2015 TEXMATE INC." );
269 wxString result = PADS_COMMON::ConvertText( latin1 );
270
271 BOOST_CHECK( !result.IsEmpty() );
272 BOOST_CHECK( result.Contains( wxString::FromUTF8( "©" ) ) );
273 BOOST_CHECK( result.Contains( wxS( "2015 TEXMATE INC." ) ) );
274}
275
276
277BOOST_AUTO_TEST_CASE( ConvertText_Utf8Preferred )
278{
279 // Valid UTF-8 input must be decoded as UTF-8, not mangled as ISO-8859-1.
280 std::string utf8 = std::string( "\xC2\xA9 OK" );
282 wxString::FromUTF8( "© OK" ) );
283}
284
286
287
288BOOST_AUTO_TEST_SUITE( PadsFileDetection )
289
290
291BOOST_AUTO_TEST_CASE( DetectPadsFileType_Unknown )
292{
293 auto type = PADS_COMMON::DetectPadsFileType( wxS( "/nonexistent/file.asc" ) );
294
295 BOOST_CHECK_EQUAL( static_cast<int>( type ),
296 static_cast<int>( PADS_COMMON::PADS_FILE_TYPE::UNKNOWN ) );
297}
298
299
300BOOST_AUTO_TEST_CASE( DetectPadsFileType_SchematicWithCodePageSuffix )
301{
302 // Regression test for https://gitlab.com/kicad/code/kicad/-/issues/23420
303 // Headers with a code-page suffix such as *PADS-LOGIC-V9.0-CP1250* must
304 // be recognized as PADS schematic files.
305 wxString testFile = wxString::FromUTF8(
307 + "/plugins/pads/issue23420_codepage_schematic.txt" );
308
309 auto type = PADS_COMMON::DetectPadsFileType( testFile );
310
311 BOOST_CHECK_EQUAL( static_cast<int>( type ),
313}
314
315
316BOOST_AUTO_TEST_CASE( FindRelatedPadsFiles_NonExistent )
317{
318 auto related = PADS_COMMON::FindRelatedPadsFiles( wxS( "/nonexistent/file.asc" ) );
319
320 BOOST_CHECK( !related.HasPcb() );
321 BOOST_CHECK( !related.HasSchematic() );
322}
323
324
325BOOST_AUTO_TEST_CASE( RELATED_FILES_HasMethods )
326{
328 BOOST_CHECK( !empty.HasPcb() );
329 BOOST_CHECK( !empty.HasSchematic() );
330 BOOST_CHECK( !empty.HasBoth() );
331
333 pcbOnly.pcbFile = wxS( "test.asc" );
334 BOOST_CHECK( pcbOnly.HasPcb() );
335 BOOST_CHECK( !pcbOnly.HasSchematic() );
336 BOOST_CHECK( !pcbOnly.HasBoth() );
337
339 schOnly.schematicFile = wxS( "test.asc" );
340 BOOST_CHECK( !schOnly.HasPcb() );
341 BOOST_CHECK( schOnly.HasSchematic() );
342 BOOST_CHECK( !schOnly.HasBoth() );
343
345 both.pcbFile = wxS( "test_pcb.asc" );
346 both.schematicFile = wxS( "test_sch.asc" );
347 BOOST_CHECK( both.HasPcb() );
348 BOOST_CHECK( both.HasSchematic() );
349 BOOST_CHECK( both.HasBoth() );
350}
351
352
Definition kiid.h:44
wxString AsString() const
Definition kiid.cpp:242
static bool empty(const wxTextEntryBase *aCtrl)
std::string GetEeschemaTestDataDir()
Get the configured location of Eeschema test data.
@ SCHEMATIC_ASCII
PADS Logic ASCII (.asc or .txt)
Definition pads_common.h:66
RELATED_FILES FindRelatedPadsFiles(const wxString &aFilePath)
Find related PADS project files from a given source file.
int ParseInt(const std::string &aStr, int aDefault, const std::string &aContext)
Parse integer from string with error context.
wxString ConvertText(const std::string &aText)
Decode text from a PADS file, which uses an 8-bit codepage rather than UTF-8.
PADS_FILE_TYPE DetectPadsFileType(const wxString &aFilePath)
Detect the type of a PADS file by examining its header.
wxString ConvertInvertedNetName(const std::string &aNetName)
Convert a PADS net name to KiCad format, handling inverted signal notation.
LINE_STYLE PadsLineStyleToKiCad(int aPadsStyle)
Convert a PADS line style integer to a KiCad LINE_STYLE enum value.
KIID GenerateDeterministicUuid(const std::string &aIdentifier)
Generate a deterministic KIID from a PADS component identifier.
double ParseDouble(const std::string &aStr, double aDefault, const std::string &aContext)
Parse double from string with error context.
Common utilities and types for parsing PADS file formats.
Result of detecting related PADS project files.
Definition pads_common.h:74
wxString schematicFile
Path to schematic file if found.
Definition pads_common.h:76
wxString pcbFile
Path to PCB file if found.
Definition pads_common.h:75
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_AUTO_TEST_SUITE(CadstarPartParser)
BOOST_AUTO_TEST_SUITE_END()
BOOST_AUTO_TEST_CASE(GenerateDeterministicUuid_Deterministic)
wxString result
Test unit parsing edge cases and error handling.
BOOST_CHECK_EQUAL(result, "25.4")