KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_stacked_pin_conversion.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 (C) 2024 KiCad Developers
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 along
17 * with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
21#include <sch_pin.h>
22#include <lib_symbol.h>
23#include <eeschema_test_utils.h>
24
26{
28 {
29 m_settingsManager = std::make_unique<SETTINGS_MANAGER>( true );
30 m_symbol = std::make_unique<LIB_SYMBOL>( "TestSymbol" );
31 }
32
33 std::unique_ptr<SETTINGS_MANAGER> m_settingsManager;
34 std::unique_ptr<LIB_SYMBOL> m_symbol;
35};
36
37BOOST_FIXTURE_TEST_SUITE( StackedPinConversion, STACKED_PIN_CONVERSION_FIXTURE )
38
39
40
43BOOST_AUTO_TEST_CASE( TestStackedPinExpansion )
44{
45 // Test simple list notation
46 SCH_PIN* pin = new SCH_PIN( m_symbol.get() );
47 pin->SetNumber( wxT("[1,2,3]") );
48
49 bool isValid;
50 std::vector<wxString> expanded = pin->GetStackedPinNumbers( &isValid );
51
52 BOOST_CHECK( isValid );
53 BOOST_REQUIRE_EQUAL( expanded.size(), 3 );
54 BOOST_CHECK_EQUAL( expanded[0], "1" );
55 BOOST_CHECK_EQUAL( expanded[1], "2" );
56 BOOST_CHECK_EQUAL( expanded[2], "3" );
57
58 delete pin;
59
60 // Test range notation
61 pin = new SCH_PIN( m_symbol.get() );
62 pin->SetNumber( wxT("[5-7]") );
63
64 expanded = pin->GetStackedPinNumbers( &isValid );
65
66 BOOST_CHECK( isValid );
67 BOOST_REQUIRE_EQUAL( expanded.size(), 3 );
68 BOOST_CHECK_EQUAL( expanded[0], "5" );
69 BOOST_CHECK_EQUAL( expanded[1], "6" );
70 BOOST_CHECK_EQUAL( expanded[2], "7" );
71
72 delete pin;
73
74 // Test mixed notation
75 pin = new SCH_PIN( m_symbol.get() );
76 pin->SetNumber( wxT("[1,3,5-7]") );
77
78 expanded = pin->GetStackedPinNumbers( &isValid );
79
80 BOOST_CHECK( isValid );
81 BOOST_REQUIRE_EQUAL( expanded.size(), 5 );
82 BOOST_CHECK_EQUAL( expanded[0], "1" );
83 BOOST_CHECK_EQUAL( expanded[1], "3" );
84 BOOST_CHECK_EQUAL( expanded[2], "5" );
85 BOOST_CHECK_EQUAL( expanded[3], "6" );
86 BOOST_CHECK_EQUAL( expanded[4], "7" );
87
88 delete pin;
89}
90
91
95BOOST_AUTO_TEST_CASE( TestStackedPinValidity )
96{
97 SCH_PIN* pin = new SCH_PIN( m_symbol.get() );
98
99 // Test valid single pin (should not be considered stacked)
100 pin->SetNumber( wxT("1") );
101 bool isValid;
102 std::vector<wxString> expanded = pin->GetStackedPinNumbers( &isValid );
103 BOOST_CHECK( isValid );
104 BOOST_CHECK_EQUAL( expanded.size(), 1 );
105 BOOST_CHECK_EQUAL( expanded[0], "1" );
106
107 // Test invalid notation (malformed brackets)
108 pin->SetNumber( wxT("[1,2") );
109 expanded = pin->GetStackedPinNumbers( &isValid );
110 BOOST_CHECK( !isValid );
111
112 // Test invalid range
113 pin->SetNumber( wxT("[5-3]") ); // backwards range
114 expanded = pin->GetStackedPinNumbers( &isValid );
115 BOOST_CHECK( !isValid );
116
117 // Test empty brackets
118 pin->SetNumber( wxT("[]") );
119 expanded = pin->GetStackedPinNumbers( &isValid );
120 BOOST_CHECK( !isValid );
121
122 delete pin;
123}
124
125
129BOOST_AUTO_TEST_CASE( TestPinCreation )
130{
131 // Create multiple pins at the same location
132 VECTOR2I position( 0, 0 );
133
134 SCH_PIN* pin1 = new SCH_PIN( m_symbol.get() );
135 pin1->SetNumber( wxT("1") );
136 pin1->SetPosition( position );
138
139 SCH_PIN* pin2 = new SCH_PIN( m_symbol.get() );
140 pin2->SetNumber( wxT("2") );
141 pin2->SetPosition( position );
143
144 SCH_PIN* pin3 = new SCH_PIN( m_symbol.get() );
145 pin3->SetNumber( wxT("3") );
146 pin3->SetPosition( position );
148
149 // Verify pins are at same location
150 BOOST_CHECK_EQUAL( pin1->GetPosition(), pin2->GetPosition() );
151 BOOST_CHECK_EQUAL( pin2->GetPosition(), pin3->GetPosition() );
152
153 // Test IsStacked functionality
154 BOOST_CHECK( pin1->IsStacked( pin2 ) );
155 BOOST_CHECK( pin2->IsStacked( pin3 ) );
156
157 delete pin1;
158 delete pin2;
159 delete pin3;
160}
161
162
166BOOST_AUTO_TEST_CASE( TestStackedPinNetNaming )
167{
168 SCH_PIN* pin = new SCH_PIN( m_symbol.get() );
169 pin->SetNumber( wxT("[8,9,10]") );
170
171 // This test would require a full SCH_SYMBOL context to test GetDefaultNetName
172 // For now just verify the pin number expansion works
173 bool isValid;
174 std::vector<wxString> expanded = pin->GetStackedPinNumbers( &isValid );
175
176 BOOST_CHECK( isValid );
177 BOOST_REQUIRE_EQUAL( expanded.size(), 3 );
178 // The smallest number should be first for deterministic net naming
179 BOOST_CHECK_EQUAL( expanded[0], "8" );
180
181 delete pin;
182}
183
184
188BOOST_AUTO_TEST_CASE( TestConvertMultiplePinsToStacked )
189{
190 // Create multiple pins at the same location
191 VECTOR2I position( 0, 0 );
192
193 SCH_PIN* pin1 = new SCH_PIN( m_symbol.get() );
194 pin1->SetNumber( wxT("1") );
195 pin1->SetPosition( position );
197 pin1->SetVisible( true );
198
199 SCH_PIN* pin2 = new SCH_PIN( m_symbol.get() );
200 pin2->SetNumber( wxT("2") );
201 pin2->SetPosition( position );
203 pin2->SetVisible( true );
204
205 SCH_PIN* pin3 = new SCH_PIN( m_symbol.get() );
206 pin3->SetNumber( wxT("3") );
207 pin3->SetPosition( position );
209 pin3->SetVisible( true );
210
211 // Test basic property access before adding to symbol
212 BOOST_CHECK_EQUAL( pin1->GetNumber(), "1" );
213 BOOST_CHECK_EQUAL( pin2->GetNumber(), "2" );
214 BOOST_CHECK_EQUAL( pin3->GetNumber(), "3" );
215
216 // Just test the basic conversion logic without symbol management
217 // Build the stacked notation string
218 wxString stackedNotation = wxT("[");
219 stackedNotation += pin1->GetNumber();
220 stackedNotation += wxT(",");
221 stackedNotation += pin2->GetNumber();
222 stackedNotation += wxT(",");
223 stackedNotation += pin3->GetNumber();
224 stackedNotation += wxT("]");
225
226 // Test stacked notation creation
227 BOOST_CHECK_EQUAL( stackedNotation, "[1,2,3]" );
228
229 // Set stacked notation on one pin
230 pin1->SetNumber( stackedNotation );
231 BOOST_CHECK_EQUAL( pin1->GetNumber(), "[1,2,3]" );
232
233 // Verify the stacked pin expansion works
234 bool isValid;
235 std::vector<wxString> expanded = pin1->GetStackedPinNumbers( &isValid );
236 BOOST_CHECK( isValid );
237 BOOST_REQUIRE_EQUAL( expanded.size(), 3 );
238 BOOST_CHECK_EQUAL( expanded[0], "1" );
239 BOOST_CHECK_EQUAL( expanded[1], "2" );
240 BOOST_CHECK_EQUAL( expanded[2], "3" );
241
242 // Clean up - delete pins manually since they're not in symbol
243 delete pin1;
244 delete pin2;
245 delete pin3;
246}
247
248
252BOOST_AUTO_TEST_CASE( TestRangeCollapsingConversion )
253{
254 // Test range collapsing logic directly without symbol management
255
256 // Test consecutive pins that should collapse to a range
257 std::vector<long> numbers = { 1, 2, 3, 4 };
258
259 // Build collapsed ranges
260 wxString result;
261 size_t i = 0;
262 while( i < numbers.size() )
263 {
264 if( !result.IsEmpty() )
265 result += wxT(",");
266
267 long start = numbers[i];
268 long end = start;
269
270 // Find the end of consecutive sequence
271 while( i + 1 < numbers.size() && numbers[i + 1] == numbers[i] + 1 )
272 {
273 i++;
274 end = numbers[i];
275 }
276
277 // Add range or single number
278 if( end > start + 1 ) // Range of 3+ numbers
279 result += wxString::Format( wxT("%ld-%ld"), start, end );
280 else if( end == start + 1 ) // Two consecutive numbers
281 result += wxString::Format( wxT("%ld,%ld"), start, end );
282 else // Single number
283 result += wxString::Format( wxT("%ld"), start );
284
285 i++;
286 }
287
288 // Verify range collapsing: 1,2,3,4 should become "1-4"
289 BOOST_CHECK_EQUAL( result, "1-4" );
290
291 // Test with mixed consecutive and non-consecutive: 1,2,3,4,7,8,9
292 numbers = { 1, 2, 3, 4, 7, 8, 9 };
293 result.Clear();
294 i = 0;
295
296 while( i < numbers.size() )
297 {
298 if( !result.IsEmpty() )
299 result += wxT(",");
300
301 long start = numbers[i];
302 long end = start;
303
304 // Find the end of consecutive sequence
305 while( i + 1 < numbers.size() && numbers[i + 1] == numbers[i] + 1 )
306 {
307 i++;
308 end = numbers[i];
309 }
310
311 // Add range or single number
312 if( end > start + 1 ) // Range of 3+ numbers
313 result += wxString::Format( wxT("%ld-%ld"), start, end );
314 else if( end == start + 1 ) // Two consecutive numbers
315 result += wxString::Format( wxT("%ld,%ld"), start, end );
316 else // Single number
317 result += wxString::Format( wxT("%ld"), start );
318
319 i++;
320 }
321
322 // Verify mixed ranges: 1,2,3,4,7,8,9 should become "1-4,7-9"
323 BOOST_CHECK_EQUAL( result, "1-4,7-9" );
324
325 // Test edge cases
326 numbers = { 1, 3, 5 }; // Non-consecutive
327 result.Clear();
328 i = 0;
329
330 while( i < numbers.size() )
331 {
332 if( !result.IsEmpty() )
333 result += wxT(",");
334
335 long start = numbers[i];
336 long end = start;
337
338 // Find the end of consecutive sequence
339 while( i + 1 < numbers.size() && numbers[i + 1] == numbers[i] + 1 )
340 {
341 i++;
342 end = numbers[i];
343 }
344
345 // Add range or single number
346 if( end > start + 1 ) // Range of 3+ numbers
347 result += wxString::Format( wxT("%ld-%ld"), start, end );
348 else if( end == start + 1 ) // Two consecutive numbers
349 result += wxString::Format( wxT("%ld,%ld"), start, end );
350 else // Single number
351 result += wxString::Format( wxT("%ld"), start );
352
353 i++;
354 }
355
356 // Verify non-consecutive: 1,3,5 should remain "1,3,5"
357 BOOST_CHECK_EQUAL( result, "1,3,5" );
358
359 // Test two consecutive numbers
360 numbers = { 5, 6 };
361 result.Clear();
362 i = 0;
363
364 while( i < numbers.size() )
365 {
366 if( !result.IsEmpty() )
367 result += wxT(",");
368
369 long start = numbers[i];
370 long end = start;
371
372 // Find the end of consecutive sequence
373 while( i + 1 < numbers.size() && numbers[i + 1] == numbers[i] + 1 )
374 {
375 i++;
376 end = numbers[i];
377 }
378
379 // Add range or single number
380 if( end > start + 1 ) // Range of 3+ numbers
381 result += wxString::Format( wxT("%ld-%ld"), start, end );
382 else if( end == start + 1 ) // Two consecutive numbers
383 result += wxString::Format( wxT("%ld,%ld"), start, end );
384 else // Single number
385 result += wxString::Format( wxT("%ld"), start );
386
387 i++;
388 }
389
390 // Verify two consecutive: 5,6 should remain "5,6" (not convert to range)
391 BOOST_CHECK_EQUAL( result, "5,6" );
392
393 // Test complex mixed case: 1,2,4,5,6,8,9,10,11
394 numbers = { 1, 2, 4, 5, 6, 8, 9, 10, 11 };
395 result.Clear();
396 i = 0;
397
398 while( i < numbers.size() )
399 {
400 if( !result.IsEmpty() )
401 result += wxT(",");
402
403 long start = numbers[i];
404 long end = start;
405
406 // Find the end of consecutive sequence
407 while( i + 1 < numbers.size() && numbers[i + 1] == numbers[i] + 1 )
408 {
409 i++;
410 end = numbers[i];
411 }
412
413 // Add range or single number
414 if( end > start + 1 ) // Range of 3+ numbers
415 result += wxString::Format( wxT("%ld-%ld"), start, end );
416 else if( end == start + 1 ) // Two consecutive numbers
417 result += wxString::Format( wxT("%ld,%ld"), start, end );
418 else // Single number
419 result += wxString::Format( wxT("%ld"), start );
420
421 i++;
422 }
423
424 // Verify complex case: 1,2,4,5,6,8,9,10,11 should become "1,2,4-6,8-11"
425 BOOST_CHECK_EQUAL( result, "1,2,4-6,8-11" );
426
427 // Test that our range notation can be expanded back correctly
428 SCH_PIN* rangePin = new SCH_PIN( m_symbol.get() );
429 rangePin->SetNumber( wxT("[1-4,7-9]") );
430
431 bool isValid;
432 std::vector<wxString> expanded = rangePin->GetStackedPinNumbers( &isValid );
433 BOOST_CHECK( isValid );
434 BOOST_REQUIRE_EQUAL( expanded.size(), 7 );
435
436 // Should expand to: 1,2,3,4,7,8,9
437 BOOST_CHECK_EQUAL( expanded[0], "1" );
438 BOOST_CHECK_EQUAL( expanded[1], "2" );
439 BOOST_CHECK_EQUAL( expanded[2], "3" );
440 BOOST_CHECK_EQUAL( expanded[3], "4" );
441 BOOST_CHECK_EQUAL( expanded[4], "7" );
442 BOOST_CHECK_EQUAL( expanded[5], "8" );
443 BOOST_CHECK_EQUAL( expanded[6], "9" );
444
445 delete rangePin;
446}
447
448
452BOOST_AUTO_TEST_CASE( TestRoundTripConversion )
453{
454 // Create multiple pins at the same location
455 VECTOR2I position( 100, 200 );
456
457 SCH_PIN* pin5 = new SCH_PIN( m_symbol.get() );
458 pin5->SetNumber( wxT("5") );
459 pin5->SetPosition( position );
462 pin5->SetName( wxT("TestPin") );
463 pin5->SetVisible( true );
464
465 SCH_PIN* pin7 = new SCH_PIN( m_symbol.get() );
466 pin7->SetNumber( wxT("7") );
467 pin7->SetPosition( position );
470 pin7->SetName( wxT("TestPin") );
471 pin7->SetVisible( true );
472
473 SCH_PIN* pin9 = new SCH_PIN( m_symbol.get() );
474 pin9->SetNumber( wxT("9") );
475 pin9->SetPosition( position );
478 pin9->SetName( wxT("TestPin") );
479 pin9->SetVisible( true );
480
481 // Store original properties for comparison
482 PIN_ORIENTATION originalOrientation = pin5->GetOrientation();
483 ELECTRICAL_PINTYPE originalType = pin5->GetType();
484 wxString originalName = pin5->GetName();
485 int originalLength = pin5->GetLength();
486
487 // Step 1: Convert to stacked notation (simulating ConvertStackedPins)
488 std::vector<SCH_PIN*> pinsToConvert = { pin5, pin7, pin9 };
489
490 // Sort pins numerically
491 std::sort( pinsToConvert.begin(), pinsToConvert.end(),
492 []( SCH_PIN* a, SCH_PIN* b )
493 {
494 long numA, numB;
495 if( a->GetNumber().ToLong( &numA ) && b->GetNumber().ToLong( &numB ) )
496 return numA < numB;
497 return a->GetNumber() < b->GetNumber();
498 });
499
500 // Build stacked notation
501 wxString stackedNotation = wxT("[5,7,9]");
502 pinsToConvert[0]->SetNumber( stackedNotation );
503
504 // Remove other pins (don't delete them yet for testing)
505 SCH_PIN* stackedPin = pinsToConvert[0];
506
507 // Step 2: Verify stacked notation
508 bool isValid;
509 std::vector<wxString> expanded = stackedPin->GetStackedPinNumbers( &isValid );
510 BOOST_CHECK( isValid );
511 BOOST_REQUIRE_EQUAL( expanded.size(), 3 );
512 BOOST_CHECK_EQUAL( expanded[0], "5" );
513 BOOST_CHECK_EQUAL( expanded[1], "7" );
514 BOOST_CHECK_EQUAL( expanded[2], "9" );
515
516 // Step 3: Convert back to individual pins (simulating ExplodeStackedPin)
517 // Sort the stacked numbers (should already be sorted in our case)
518 std::sort( expanded.begin(), expanded.end(),
519 []( const wxString& a, const wxString& b )
520 {
521 long numA, numB;
522 if( a.ToLong( &numA ) && b.ToLong( &numB ) )
523 return numA < numB;
524 return a < b;
525 });
526
527 // Change the original pin to use the first (smallest) number and make it visible
528 stackedPin->SetNumber( expanded[0] );
529 stackedPin->SetVisible( true );
530
531 // Create additional pins for the remaining numbers and make them invisible
532 std::vector<SCH_PIN*> explodedPins;
533 explodedPins.push_back( stackedPin );
534
535 for( size_t i = 1; i < expanded.size(); ++i )
536 {
537 SCH_PIN* newPin = new SCH_PIN( m_symbol.get() );
538
539 // Copy all properties from the original pin
540 newPin->SetPosition( stackedPin->GetPosition() );
541 newPin->SetOrientation( stackedPin->GetOrientation() );
542 newPin->SetShape( stackedPin->GetShape() );
543 newPin->SetLength( stackedPin->GetLength() );
544 newPin->SetType( stackedPin->GetType() );
545 newPin->SetName( stackedPin->GetName() );
546 newPin->SetNumber( expanded[i] );
547 newPin->SetNameTextSize( stackedPin->GetNameTextSize() );
548 newPin->SetNumberTextSize( stackedPin->GetNumberTextSize() );
549 newPin->SetUnit( stackedPin->GetUnit() );
550 newPin->SetBodyStyle( stackedPin->GetBodyStyle() );
551 newPin->SetVisible( false ); // Make all other pins invisible
552
553 explodedPins.push_back( newPin );
554 }
555
556 // Step 4: Verify the round-trip conversion
557 BOOST_REQUIRE_EQUAL( explodedPins.size(), 3 );
558
559 // Check pin numbers
560 BOOST_CHECK_EQUAL( explodedPins[0]->GetNumber(), "5" );
561 BOOST_CHECK_EQUAL( explodedPins[1]->GetNumber(), "7" );
562 BOOST_CHECK_EQUAL( explodedPins[2]->GetNumber(), "9" );
563
564 // Check visibility (only first pin should be visible)
565 BOOST_CHECK( explodedPins[0]->IsVisible() );
566 BOOST_CHECK( !explodedPins[1]->IsVisible() );
567 BOOST_CHECK( !explodedPins[2]->IsVisible() );
568
569 // Check that properties were preserved
570 for( SCH_PIN* pin : explodedPins )
571 {
572 BOOST_CHECK_EQUAL( pin->GetPosition(), position );
573 BOOST_CHECK( pin->GetOrientation() == originalOrientation );
574 BOOST_CHECK( pin->GetType() == originalType );
575 BOOST_CHECK_EQUAL( pin->GetName(), originalName );
576 BOOST_CHECK_EQUAL( pin->GetLength(), originalLength );
577 }
578
579 // Clean up
580 for( size_t i = 1; i < explodedPins.size(); ++i )
581 delete explodedPins[i];
582 // Note: explodedPins[0] is the original stackedPin, don't delete twice
583}
584
585
589BOOST_AUTO_TEST_CASE( TestVisibilityHandling )
590{
591 // Create a single pin to test visibility handling
592 SCH_PIN* pin = new SCH_PIN( m_symbol.get() );
593 pin->SetNumber( wxT("[8,10,12]") );
594 pin->SetVisible( false ); // Start invisible
595
596 // Test expansion of stacked notation
597 bool isValid;
598 std::vector<wxString> expanded = pin->GetStackedPinNumbers( &isValid );
599 BOOST_CHECK( isValid );
600 BOOST_REQUIRE_EQUAL( expanded.size(), 3 );
601
602 // Sort expanded numbers
603 std::sort( expanded.begin(), expanded.end(),
604 []( const wxString& a, const wxString& b )
605 {
606 long numA, numB;
607 if( a.ToLong( &numA ) && b.ToLong( &numB ) )
608 return numA < numB;
609 return a < b;
610 });
611
612 // Verify sorted order is correct
613 BOOST_CHECK_EQUAL( expanded[0], "8" );
614 BOOST_CHECK_EQUAL( expanded[1], "10" );
615 BOOST_CHECK_EQUAL( expanded[2], "12" );
616
617 // Set the smallest pin number and make it visible
618 pin->SetNumber( expanded[0] ); // "8"
619 pin->SetVisible( true ); // Make visible
620
621 // Verify the smallest pin is visible and has correct number
622 BOOST_CHECK_EQUAL( pin->GetNumber(), "8" );
623 BOOST_CHECK( pin->IsVisible() );
624
625 // Clean up
626 delete pin;
627}
628
629
633BOOST_AUTO_TEST_CASE( TestAlphanumericRangeCollapsing )
634{
635 // Test the new alphanumeric prefix parsing logic
636
637 // Helper function to test prefix parsing
638 auto testPrefixParsing = []( const wxString& pinNumber ) -> std::pair<wxString, long>
639 {
640 wxString prefix;
641 long numValue = -1;
642
643 // Find where numeric part starts (scan from end)
644 size_t numStart = pinNumber.length();
645 for( int i = pinNumber.length() - 1; i >= 0; i-- )
646 {
647 if( !wxIsdigit( pinNumber[i] ) )
648 {
649 numStart = i + 1;
650 break;
651 }
652 if( i == 0 ) // All digits
653 numStart = 0;
654 }
655
656 if( numStart < pinNumber.length() ) // Has numeric suffix
657 {
658 prefix = pinNumber.Left( numStart );
659 wxString numericPart = pinNumber.Mid( numStart );
660 numericPart.ToLong( &numValue );
661 }
662
663 return std::make_pair( prefix, numValue );
664 };
665
666 // Test basic prefix parsing
667 auto [prefix1, num1] = testPrefixParsing( wxT("A1") );
668 BOOST_CHECK_EQUAL( prefix1, "A" );
669 BOOST_CHECK_EQUAL( num1, 1 );
670
671 auto [prefix2, num2] = testPrefixParsing( wxT("AB12") );
672 BOOST_CHECK_EQUAL( prefix2, "AB" );
673 BOOST_CHECK_EQUAL( num2, 12 );
674
675 auto [prefix3, num3] = testPrefixParsing( wxT("123") );
676 BOOST_CHECK_EQUAL( prefix3, "" );
677 BOOST_CHECK_EQUAL( num3, 123 );
678
679 auto [prefix4, num4] = testPrefixParsing( wxT("XYZ") );
680 BOOST_CHECK_EQUAL( prefix4, "" ); // No numeric suffix
681 BOOST_CHECK_EQUAL( num4, -1 );
682
683 // Test grouping logic with example: AA1,AA2,AA3,AB4,CD12,CD13,CD14
684 std::map<wxString, std::vector<long>> prefixGroups;
685 std::vector<wxString> testPins = { wxT("AA1"), wxT("AA2"), wxT("AA3"), wxT("AB4"), wxT("CD12"), wxT("CD13"), wxT("CD14") };
686
687 for( const wxString& pinNumber : testPins )
688 {
689 auto [prefix, numValue] = testPrefixParsing( pinNumber );
690 if( numValue != -1 )
691 prefixGroups[prefix].push_back( numValue );
692 }
693
694 // Verify grouping
695 BOOST_CHECK_EQUAL( prefixGroups.size(), 3 );
696 BOOST_CHECK_EQUAL( prefixGroups[wxT("AA")].size(), 3 );
697 BOOST_CHECK_EQUAL( prefixGroups[wxT("AB")].size(), 1 );
698 BOOST_CHECK_EQUAL( prefixGroups[wxT("CD")].size(), 3 );
699
700 // Build expected result: AA1-AA3,AB4,CD12-CD14
701 wxString expectedResult;
702 for( auto& [prefix, numbers] : prefixGroups )
703 {
704 if( !expectedResult.IsEmpty() )
705 expectedResult += wxT(",");
706
707 std::sort( numbers.begin(), numbers.end() );
708
709 size_t i = 0;
710 while( i < numbers.size() )
711 {
712 if( i > 0 )
713 expectedResult += wxT(",");
714
715 long start = numbers[i];
716 long end = start;
717
718 // Find consecutive sequence
719 while( i + 1 < numbers.size() && numbers[i + 1] == numbers[i] + 1 )
720 {
721 i++;
722 end = numbers[i];
723 }
724
725 // Format with prefix
726 if( end > start + 1 ) // Range of 3+ numbers
727 expectedResult += wxString::Format( wxT("%s%ld-%s%ld"), prefix, start, prefix, end );
728 else if( end == start + 1 ) // Two consecutive numbers
729 expectedResult += wxString::Format( wxT("%s%ld,%s%ld"), prefix, start, prefix, end );
730 else // Single number
731 expectedResult += wxString::Format( wxT("%s%ld"), prefix, start );
732
733 i++;
734 }
735 }
736
737 // Should result in: AA1-AA3,AB4,CD12-CD14
738 BOOST_CHECK_EQUAL( expectedResult, "AA1-AA3,AB4,CD12-CD14" );
739}
740
741
virtual void SetBodyStyle(int aBodyStyle)
Definition sch_item.h:243
int GetBodyStyle() const
Definition sch_item.h:244
int GetUnit() const
Definition sch_item.h:238
virtual void SetUnit(int aUnit)
Definition sch_item.h:237
int GetNumberTextSize() const
Definition sch_pin.cpp:670
int GetLength() const
Definition sch_pin.cpp:298
void SetNumber(const wxString &aNumber)
Definition sch_pin.cpp:633
void SetVisible(bool aVisible)
Definition sch_pin.h:114
void SetOrientation(PIN_ORIENTATION aOrientation)
Definition sch_pin.h:93
void SetName(const wxString &aName)
Definition sch_pin.cpp:418
void SetPosition(const VECTOR2I &aPos) override
Definition sch_pin.h:238
std::vector< wxString > GetStackedPinNumbers(bool *aValid=nullptr) const
Definition sch_pin.cpp:593
const wxString & GetName() const
Definition sch_pin.cpp:400
void SetLength(int aLength)
Definition sch_pin.h:99
PIN_ORIENTATION GetOrientation() const
Definition sch_pin.cpp:263
void SetNumberTextSize(int aSize)
Definition sch_pin.cpp:684
void SetShape(GRAPHIC_PINSHAPE aShape)
Definition sch_pin.h:96
VECTOR2I GetPosition() const override
Definition sch_pin.cpp:255
int GetNameTextSize() const
Definition sch_pin.cpp:646
void SetType(ELECTRICAL_PINTYPE aType)
Definition sch_pin.cpp:332
bool IsStacked(const SCH_PIN *aPin) const
Definition sch_pin.cpp:475
const wxString & GetNumber() const
Definition sch_pin.h:124
GRAPHIC_PINSHAPE GetShape() const
Definition sch_pin.cpp:277
ELECTRICAL_PINTYPE GetType() const
Definition sch_pin.cpp:312
void SetNameTextSize(int aSize)
Definition sch_pin.cpp:660
ELECTRICAL_PINTYPE
The symbol library pin object electrical types used in ERC tests.
Definition pin_type.h:36
@ PT_INPUT
usual pin input: must be connected
Definition pin_type.h:37
PIN_ORIENTATION
The symbol library pin object orientations.
Definition pin_type.h:105
@ PIN_RIGHT
The pin extends rightwards from the connection point.
Definition pin_type.h:111
@ PIN_LEFT
The pin extends leftwards from the connection point: Probably on the right side of the symbol.
Definition pin_type.h:118
std::unique_ptr< SETTINGS_MANAGER > m_settingsManager
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_AUTO_TEST_SUITE_END()
VECTOR2I end
BOOST_AUTO_TEST_CASE(TestStackedPinExpansion)
Test basic stacked pin number expansion functionality.
wxString result
Test unit parsing edge cases and error handling.
BOOST_CHECK_EQUAL(result, "25.4")
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695