KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_pads_unit_converter.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 2
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
24
26
28
29#include <ostream>
30
31std::ostream& operator<<( std::ostream& os, PADS_UNIT_TYPE aType )
32{
33 switch( aType )
34 {
35 case PADS_UNIT_TYPE::MILS: os << "MILS"; break;
36 case PADS_UNIT_TYPE::METRIC: os << "METRIC"; break;
37 case PADS_UNIT_TYPE::INCHES: os << "INCHES"; break;
38 }
39
40 return os;
41}
42
47
48BOOST_FIXTURE_TEST_SUITE( PadsUnitConverter, PADS_UNIT_CONVERTER_FIXTURE )
49
50
51BOOST_AUTO_TEST_CASE( DefaultsToMils )
52{
53 PADS_UNIT_CONVERTER converter;
55}
56
57
58BOOST_AUTO_TEST_CASE( MilsConversion )
59{
60 PADS_UNIT_CONVERTER converter;
62
63 // 1000 mils = 1 inch = 25.4 mm = 25,400,000 nm
64 BOOST_CHECK_EQUAL( converter.ToNanometers( 1000.0 ), 25400000 );
65
66 // 1 mil = 25,400 nm
67 BOOST_CHECK_EQUAL( converter.ToNanometers( 1.0 ), 25400 );
68
69 // 100 mils = 2,540,000 nm
70 BOOST_CHECK_EQUAL( converter.ToNanometers( 100.0 ), 2540000 );
71
72 // Test size conversion (same as coordinate for now)
73 BOOST_CHECK_EQUAL( converter.ToNanometersSize( 1000.0 ), 25400000 );
74}
75
76
77BOOST_AUTO_TEST_CASE( MetricConversion )
78{
79 PADS_UNIT_CONVERTER converter;
81
82 // 1 mm = 1,000,000 nm
83 BOOST_CHECK_EQUAL( converter.ToNanometers( 1.0 ), 1000000 );
84
85 // 25.4 mm = 25,400,000 nm (1 inch)
86 BOOST_CHECK_EQUAL( converter.ToNanometers( 25.4 ), 25400000 );
87
88 // 0.1 mm = 100,000 nm
89 BOOST_CHECK_EQUAL( converter.ToNanometers( 0.1 ), 100000 );
90
91 // Test size conversion
92 BOOST_CHECK_EQUAL( converter.ToNanometersSize( 1.0 ), 1000000 );
93}
94
95
96BOOST_AUTO_TEST_CASE( InchesConversion )
97{
98 PADS_UNIT_CONVERTER converter;
100
101 // 1 inch = 25,400,000 nm
102 BOOST_CHECK_EQUAL( converter.ToNanometers( 1.0 ), 25400000 );
103
104 // 0.001 inch (1 mil) = 25,400 nm
105 BOOST_CHECK_EQUAL( converter.ToNanometers( 0.001 ), 25400 );
106
107 // 0.1 inch = 2,540,000 nm
108 BOOST_CHECK_EQUAL( converter.ToNanometers( 0.1 ), 2540000 );
109
110 // Test size conversion
111 BOOST_CHECK_EQUAL( converter.ToNanometersSize( 1.0 ), 25400000 );
112}
113
114
128
129
130BOOST_AUTO_TEST_CASE( ZeroConversion )
131{
132 PADS_UNIT_CONVERTER converter;
133
135 BOOST_CHECK_EQUAL( converter.ToNanometers( 0.0 ), 0 );
136
138 BOOST_CHECK_EQUAL( converter.ToNanometers( 0.0 ), 0 );
139
141 BOOST_CHECK_EQUAL( converter.ToNanometers( 0.0 ), 0 );
142}
143
144
145BOOST_AUTO_TEST_CASE( NegativeConversion )
146{
147 PADS_UNIT_CONVERTER converter;
149
150 // Negative values should convert correctly
151 BOOST_CHECK_EQUAL( converter.ToNanometers( -1000.0 ), -25400000 );
152 BOOST_CHECK_EQUAL( converter.ToNanometersSize( -100.0 ), -2540000 );
153}
154
155
156BOOST_AUTO_TEST_CASE( ConstantsAreCorrect )
157{
158 // Verify the conversion constants are accurate
162 BOOST_CHECK_CLOSE( PADS_UNIT_CONVERTER::BASIC_TO_NM,
163 PADS_UNIT_CONVERTER::MILS_TO_NM / 38100.0, 1e-10 );
164
165 // Cross-check: 1000 mils should equal 1 inch
168
169 // Cross-check: 25.4 mm should equal 1 inch
172
173 // Cross-check: 38100 BASIC units should equal 1 mil
174 BOOST_CHECK_CLOSE( 38100.0 * PADS_UNIT_CONVERTER::BASIC_TO_NM,
176}
177
178
179BOOST_AUTO_TEST_CASE( BasicUnitsMode )
180{
181 PADS_UNIT_CONVERTER converter;
182
183 // Default should not be in BASIC mode
184 BOOST_CHECK( !converter.IsBasicUnitsMode() );
185
186 // Enable BASIC mode
187 converter.SetBasicUnitsMode( true );
188 BOOST_CHECK( converter.IsBasicUnitsMode() );
189
190 // 38100 BASIC units = 1 mil = 25,400 nm
191 BOOST_CHECK_EQUAL( converter.ToNanometers( 38100.0 ), 25400 );
192
193 // 1 BASIC unit rounds to 1 nm
194 BOOST_CHECK_EQUAL( converter.ToNanometers( 1.0 ), 1 );
195
196 // 3 BASIC units = 2 nm (3 * 2/3 = 2)
197 BOOST_CHECK_EQUAL( converter.ToNanometers( 3.0 ), 2 );
198
199 // Disable BASIC mode should revert to base units
200 converter.SetBasicUnitsMode( false );
201 BOOST_CHECK( !converter.IsBasicUnitsMode() );
202 BOOST_CHECK_EQUAL( converter.ToNanometers( 1.0 ), 25400 ); // Back to MILS
203}
204
205
206BOOST_AUTO_TEST_CASE( BasicUnitsCustomScale )
207{
208 PADS_UNIT_CONVERTER converter;
209 converter.SetBasicUnitsMode( true );
210
211 // Default scale
213
214 // Set custom scale (e.g., 5.0 nm per unit)
215 converter.SetBasicUnitsScale( 5.0 );
216 BOOST_CHECK_EQUAL( converter.GetBasicUnitsScale(), 5.0 );
217
218 // 1000 units at 5.0 nm/unit = 5000 nm
219 BOOST_CHECK_EQUAL( converter.ToNanometers( 1000.0 ), 5000 );
220}
221
222
223BOOST_AUTO_TEST_CASE( ParseFileHeaderBasic )
224{
225 PADS_UNIT_CONVERTER converter;
226
227 // Test BASIC header detection
228 BOOST_CHECK( converter.ParseFileHeader( "!PADS-POWERPCB-V9.0-BASIC!" ) );
229 BOOST_CHECK( converter.IsBasicUnitsMode() );
230
231 // Reset
232 converter.SetBasicUnitsMode( false );
233
234 // Test lowercase basic
235 BOOST_CHECK( converter.ParseFileHeader( "!PADS-POWERPCB-V9.0-basic!" ) );
236 BOOST_CHECK( converter.IsBasicUnitsMode() );
237}
238
239
240BOOST_AUTO_TEST_CASE( ParseFileHeaderMils )
241{
242 PADS_UNIT_CONVERTER converter;
243
244 // Test MILS header detection
245 BOOST_CHECK( converter.ParseFileHeader( "!PADS-POWERPCB-V9.5-MILS!" ) );
246 BOOST_CHECK( !converter.IsBasicUnitsMode() );
248}
249
250
251BOOST_AUTO_TEST_CASE( ParseFileHeaderMetric )
252{
253 PADS_UNIT_CONVERTER converter;
254
255 // Test METRIC header detection
256 BOOST_CHECK( converter.ParseFileHeader( "!PADS-POWERPCB-V9.5-METRIC!" ) );
257 BOOST_CHECK( !converter.IsBasicUnitsMode() );
259}
260
261
262BOOST_AUTO_TEST_CASE( ParseFileHeaderInches )
263{
264 PADS_UNIT_CONVERTER converter;
265
266 // Test INCHES header detection
267 BOOST_CHECK( converter.ParseFileHeader( "!PADS-POWERPCB-V9.5-INCHES!" ) );
268 BOOST_CHECK( !converter.IsBasicUnitsMode() );
270}
271
272
273BOOST_AUTO_TEST_CASE( ParseFileHeaderUnknown )
274{
275 PADS_UNIT_CONVERTER converter;
276
277 // Unknown header should return false
278 BOOST_CHECK( !converter.ParseFileHeader( "!UNKNOWN-FORMAT!" ) );
279}
280
281
282BOOST_AUTO_TEST_CASE( BasicModeOverridesBaseUnits )
283{
284 PADS_UNIT_CONVERTER converter;
285
286 // Set to METRIC
288 BOOST_CHECK_EQUAL( converter.ToNanometers( 1.0 ), 1000000 ); // 1 mm
289
290 // Enable BASIC - should override METRIC
291 converter.SetBasicUnitsMode( true );
292 BOOST_CHECK_EQUAL( converter.ToNanometers( 1.0 ), 1 );
293
294 // Disable BASIC - should revert to METRIC
295 converter.SetBasicUnitsMode( false );
296 BOOST_CHECK_EQUAL( converter.ToNanometers( 1.0 ), 1000000 ); // Back to mm
297}
298
299
300BOOST_AUTO_TEST_CASE( ParseUnitCodeMils )
301{
302 // Test "M" -> MILS
304 BOOST_CHECK( result.has_value() );
306
307 // Test lowercase
309 BOOST_CHECK( result.has_value() );
311
312 // Test "D" (default) -> MILS
314 BOOST_CHECK( result.has_value() );
316
317 // Test long form
319 BOOST_CHECK( result.has_value() );
321}
322
323
324BOOST_AUTO_TEST_CASE( ParseUnitCodeMetric )
325{
326 // Test "MM" -> METRIC
328 BOOST_CHECK( result.has_value() );
330
331 // Test lowercase
333 BOOST_CHECK( result.has_value() );
335
336 // Test long form
338 BOOST_CHECK( result.has_value() );
340}
341
342
343BOOST_AUTO_TEST_CASE( ParseUnitCodeInches )
344{
345 // Test "I" -> INCHES
347 BOOST_CHECK( result.has_value() );
349
350 // Test lowercase
352 BOOST_CHECK( result.has_value() );
354
355 // Test long form
357 BOOST_CHECK( result.has_value() );
359}
360
361
362BOOST_AUTO_TEST_CASE( ParseUnitCodeNoOverride )
363{
364 // Test "N" -> no override (empty optional)
366 BOOST_CHECK( !result.has_value() );
367
368 // Test empty string
370 BOOST_CHECK( !result.has_value() );
371
372 // Test invalid code
374 BOOST_CHECK( !result.has_value() );
375
377 BOOST_CHECK( !result.has_value() );
378}
379
380
381BOOST_AUTO_TEST_CASE( PushPopUnitOverride )
382{
383 PADS_UNIT_CONVERTER converter;
384
385 // Start with MILS
387 BOOST_CHECK( !converter.HasUnitOverride() );
388 BOOST_CHECK_EQUAL( converter.GetOverrideDepth(), 0 );
389 BOOST_CHECK_EQUAL( converter.ToNanometers( 1.0 ), 25400 ); // 1 mil
390
391 // Push METRIC override
392 BOOST_CHECK( converter.PushUnitOverride( "MM" ) );
393 BOOST_CHECK( converter.HasUnitOverride() );
394 BOOST_CHECK_EQUAL( converter.GetOverrideDepth(), 1 );
395 BOOST_CHECK_EQUAL( converter.ToNanometers( 1.0 ), 1000000 ); // 1 mm
396
397 // Push INCHES override (nested)
398 BOOST_CHECK( converter.PushUnitOverride( "I" ) );
399 BOOST_CHECK_EQUAL( converter.GetOverrideDepth(), 2 );
400 BOOST_CHECK_EQUAL( converter.ToNanometers( 1.0 ), 25400000 ); // 1 inch
401
402 // Pop back to METRIC
403 converter.PopUnitOverride();
404 BOOST_CHECK_EQUAL( converter.GetOverrideDepth(), 1 );
405 BOOST_CHECK_EQUAL( converter.ToNanometers( 1.0 ), 1000000 ); // 1 mm
406
407 // Pop back to base MILS
408 converter.PopUnitOverride();
409 BOOST_CHECK( !converter.HasUnitOverride() );
410 BOOST_CHECK_EQUAL( converter.GetOverrideDepth(), 0 );
411 BOOST_CHECK_EQUAL( converter.ToNanometers( 1.0 ), 25400 ); // 1 mil
412}
413
414
415BOOST_AUTO_TEST_CASE( PushInvalidUnitCode )
416{
417 PADS_UNIT_CONVERTER converter;
418
419 // Invalid code should return false and not push
420 BOOST_CHECK( !converter.PushUnitOverride( "X" ) );
421 BOOST_CHECK( !converter.HasUnitOverride() );
422
423 // "N" (no override) should return false and not push
424 BOOST_CHECK( !converter.PushUnitOverride( "N" ) );
425 BOOST_CHECK( !converter.HasUnitOverride() );
426
427 // Empty string should return false and not push
428 BOOST_CHECK( !converter.PushUnitOverride( "" ) );
429 BOOST_CHECK( !converter.HasUnitOverride() );
430}
431
432
433BOOST_AUTO_TEST_CASE( PopEmptyStack )
434{
435 PADS_UNIT_CONVERTER converter;
436
437 // Popping empty stack should be safe (no-op)
438 BOOST_CHECK( !converter.HasUnitOverride() );
439 converter.PopUnitOverride();
440 BOOST_CHECK( !converter.HasUnitOverride() );
441
442 // Conversion should still work
443 BOOST_CHECK_EQUAL( converter.ToNanometers( 1.0 ), 25400 ); // Default MILS
444}
445
446
447BOOST_AUTO_TEST_CASE( OverrideDoesNotAffectBasicMode )
448{
449 PADS_UNIT_CONVERTER converter;
450
451 // Enable BASIC mode
452 converter.SetBasicUnitsMode( true );
453 BOOST_CHECK_EQUAL( converter.ToNanometers( 38100.0 ), 25400 ); // BASIC
454
455 // Push override - should have no effect in BASIC mode
456 BOOST_CHECK( converter.PushUnitOverride( "MM" ) );
457 BOOST_CHECK( converter.HasUnitOverride() );
458 BOOST_CHECK_EQUAL( converter.ToNanometers( 38100.0 ), 25400 ); // Still BASIC
459
460 // Disable BASIC - now override should take effect
461 converter.SetBasicUnitsMode( false );
462 BOOST_CHECK_EQUAL( converter.ToNanometers( 1.0 ), 1000000 ); // METRIC override
463
464 // Pop override
465 converter.PopUnitOverride();
466 BOOST_CHECK_EQUAL( converter.ToNanometers( 1.0 ), 25400 ); // Back to MILS
467}
468
469
Converts PADS file format units to KiCad internal units (nanometers).
static constexpr double MILS_TO_NM
double GetBasicUnitsScale() const
Get the current BASIC units scale.
static constexpr double INCHES_TO_NM
bool IsBasicUnitsMode() const
Check if BASIC units mode is enabled.
size_t GetOverrideDepth() const
Get the current override depth.
void SetBaseUnits(PADS_UNIT_TYPE aUnitType)
Set the base units for conversion.
bool PushUnitOverride(const std::string &aUnitCode)
Push a unit override onto the stack.
static constexpr double BASIC_TO_NM
void SetBasicUnitsMode(bool aEnabled)
Enable or disable BASIC units mode.
int64_t ToNanometersSize(double aValue) const
Convert a size value to nanometers.
bool ParseFileHeader(const std::string &aHeader)
Parse a PADS file header string and configure units accordingly.
static std::optional< PADS_UNIT_TYPE > ParseUnitCode(const std::string &aUnitCode)
Parse a PADS unit code and return the corresponding unit type.
PADS_UNIT_TYPE GetUnitType() const
Get the current unit type.
static constexpr double MM_TO_NM
void SetBasicUnitsScale(double aScale)
Set a custom scale for BASIC units.
void PopUnitOverride()
Pop the most recent unit override from the stack.
int64_t ToNanometers(double aValue) const
Convert a coordinate value to nanometers.
bool HasUnitOverride() const
Check if any unit overrides are currently active.
PADS_UNIT_TYPE
Unit types supported by PADS file formats.
@ MILS
Thousandths of an inch (1 mil = 0.001 inch)
@ METRIC
Millimeters.
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_AUTO_TEST_SUITE_END()
std::ostream & operator<<(std::ostream &os, PADS_UNIT_TYPE aType)
BOOST_AUTO_TEST_CASE(DefaultsToMils)
wxString result
Test unit parsing edge cases and error handling.
BOOST_CHECK_EQUAL(result, "25.4")