KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_pads_sch_parser.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 along
17 * with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
24
25#include <boost/test/unit_test.hpp>
28
31#include <lib_symbol.h>
32#include <sch_shape.h>
33#include <sch_pin.h>
34
35
36BOOST_AUTO_TEST_SUITE( PadsSchParser )
37
38
39BOOST_AUTO_TEST_CASE( CheckFileHeader_ValidLogicFile )
40{
41 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/simple_schematic.txt";
42
43 BOOST_CHECK( PADS_SCH::PADS_SCH_PARSER::CheckFileHeader( testFile ) );
44}
45
46
47BOOST_AUTO_TEST_CASE( CheckFileHeader_ValidPowerLogicFile )
48{
49 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/powerlogic_schematic.txt";
50
51 BOOST_CHECK( PADS_SCH::PADS_SCH_PARSER::CheckFileHeader( testFile ) );
52}
53
54
55BOOST_AUTO_TEST_CASE( CheckFileHeader_InvalidFile )
56{
57 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/nonexistent.txt";
58
59 BOOST_CHECK( !PADS_SCH::PADS_SCH_PARSER::CheckFileHeader( testFile ) );
60}
61
62
63BOOST_AUTO_TEST_CASE( ParseHeader_LogicFormat )
64{
65 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/simple_schematic.txt";
66
68
69 BOOST_REQUIRE( parser.Parse( testFile ) );
70 BOOST_CHECK( parser.IsValid() );
71
72 const auto& header = parser.GetHeader();
73
74 BOOST_CHECK_EQUAL( header.product, "PADS-LOGIC" );
75 BOOST_CHECK_EQUAL( header.version, "V9.0" );
76 BOOST_CHECK( header.description.find( "DESIGN EXPORT FILE" ) != std::string::npos );
77}
78
79
80BOOST_AUTO_TEST_CASE( ParseHeader_PowerLogicFormat )
81{
82 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/powerlogic_schematic.txt";
83
85
86 BOOST_REQUIRE( parser.Parse( testFile ) );
87 BOOST_CHECK( parser.IsValid() );
88
89 const auto& header = parser.GetHeader();
90
91 BOOST_CHECK_EQUAL( header.product, "PADS-POWERLOGIC" );
92 BOOST_CHECK_EQUAL( header.version, "V9.5" );
93}
94
95
96BOOST_AUTO_TEST_CASE( ParseParameters_Units_Mils )
97{
98 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/simple_schematic.txt";
99
101
102 BOOST_REQUIRE( parser.Parse( testFile ) );
103
104 const auto& params = parser.GetParameters();
105
106 BOOST_CHECK( params.units == PADS_SCH::UNIT_TYPE::MILS );
107 BOOST_CHECK_EQUAL( params.grid_x, 100.0 );
108 BOOST_CHECK_EQUAL( params.grid_y, 100.0 );
109 BOOST_CHECK_EQUAL( params.border_template, "Default_A" );
110}
111
112
113BOOST_AUTO_TEST_CASE( ParseParameters_Units_Metric )
114{
115 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/powerlogic_schematic.txt";
116
118
119 BOOST_REQUIRE( parser.Parse( testFile ) );
120
121 const auto& params = parser.GetParameters();
122
123 BOOST_CHECK( params.units == PADS_SCH::UNIT_TYPE::METRIC );
124}
125
126
128{
129 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/simple_schematic.txt";
130
132
133 BOOST_REQUIRE( parser.Parse( testFile ) );
134 BOOST_CHECK_EQUAL( parser.GetVersion(), "V9.0" );
135}
136
137
138BOOST_AUTO_TEST_CASE( ParseParameters_JobName )
139{
140 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/simple_schematic.txt";
141
143
144 BOOST_REQUIRE( parser.Parse( testFile ) );
145
146 const auto& params = parser.GetParameters();
147
148 BOOST_CHECK_EQUAL( params.job_name, "Test Design" );
149}
150
151
152BOOST_AUTO_TEST_CASE( ParseParameters_SheetSize )
153{
154 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/simple_schematic.txt";
155
157
158 BOOST_REQUIRE( parser.Parse( testFile ) );
159
160 const auto& params = parser.GetParameters();
161
162 BOOST_CHECK_EQUAL( params.sheet_size.width, 11000.0 );
163 BOOST_CHECK_EQUAL( params.sheet_size.height, 8500.0 );
164 BOOST_CHECK_EQUAL( params.sheet_size.name, "A" );
165}
166
167
168BOOST_AUTO_TEST_CASE( ParseParameters_TextAndLineDefaults )
169{
170 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/simple_schematic.txt";
171
173
174 BOOST_REQUIRE( parser.Parse( testFile ) );
175
176 const auto& params = parser.GetParameters();
177
178 BOOST_CHECK_EQUAL( params.text_size, 60.0 );
179 BOOST_CHECK_EQUAL( params.line_width, 2.0 );
180}
181
182
183BOOST_AUTO_TEST_CASE( ParseSymbols_Count )
184{
185 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/symbols_schematic.txt";
186
188
189 BOOST_REQUIRE( parser.Parse( testFile ) );
190
191 const auto& symbols = parser.GetSymbolDefs();
192
193 BOOST_CHECK_EQUAL( symbols.size(), 3 );
194}
195
196
197BOOST_AUTO_TEST_CASE( ParseSymbols_V52_DecalWithoutFontLines )
198{
199 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/v52_decals.txt";
200
202
203 BOOST_REQUIRE( parser.Parse( testFile ) );
204 BOOST_CHECK( parser.IsValid() );
205
206 const auto& header = parser.GetHeader();
207
208 BOOST_CHECK_EQUAL( header.product, "PADS-POWERLOGIC" );
209 BOOST_CHECK_EQUAL( header.version, "V5.2" );
210
211 const auto& symbols = parser.GetSymbolDefs();
212
213 BOOST_REQUIRE_EQUAL( symbols.size(), 1 );
214
215 const PADS_SCH::SYMBOL_DEF* pinb = parser.GetSymbolDef( "PINB" );
216 BOOST_REQUIRE( pinb != nullptr );
217
218 BOOST_CHECK_EQUAL( pinb->num_attrs, 4 );
219 BOOST_CHECK_EQUAL( pinb->num_pieces, 2 );
220 BOOST_CHECK_EQUAL( pinb->num_pins, 0 );
222
223 // Verify attribute names were parsed correctly (not misaligned)
224 BOOST_REQUIRE_EQUAL( pinb->attrs.size(), 4 );
225 BOOST_CHECK_EQUAL( pinb->attrs[0].attr_name, "REF-DES" );
226 BOOST_CHECK_EQUAL( pinb->attrs[1].attr_name, "PART-TYPE" );
227 BOOST_CHECK_EQUAL( pinb->attrs[2].attr_name, "*" );
228 BOOST_CHECK_EQUAL( pinb->attrs[3].attr_name, "*" );
229
230 // Verify graphics were parsed correctly
231 BOOST_REQUIRE_EQUAL( pinb->graphics.size(), 2 );
232
233 const auto& openLine = pinb->graphics[0];
234 BOOST_CHECK( openLine.type == PADS_SCH::GRAPHIC_TYPE::POLYLINE );
235 BOOST_CHECK_EQUAL( openLine.line_width, 10.0 );
236 BOOST_REQUIRE_EQUAL( openLine.points.size(), 2 );
237 BOOST_CHECK_EQUAL( openLine.points[0].coord.x, 0.0 );
238 BOOST_CHECK_EQUAL( openLine.points[0].coord.y, 0.0 );
239 BOOST_CHECK_EQUAL( openLine.points[1].coord.x, 140.0 );
240 BOOST_CHECK_EQUAL( openLine.points[1].coord.y, 0.0 );
241
242 const auto& circle = pinb->graphics[1];
243 BOOST_CHECK( circle.type == PADS_SCH::GRAPHIC_TYPE::CIRCLE );
244 BOOST_CHECK_EQUAL( circle.line_width, 10.0 );
245 BOOST_CHECK_EQUAL( circle.center.x, 165.0 );
246 BOOST_CHECK_EQUAL( circle.center.y, 0.0 );
247 BOOST_CHECK_EQUAL( circle.radius, 25.0 );
248
249 // Font names should be empty since V5.2 doesn't have them
250 BOOST_CHECK( pinb->font1.empty() );
251 BOOST_CHECK( pinb->font2.empty() );
252}
253
254
255BOOST_AUTO_TEST_CASE( ParseSymbols_Resistor )
256{
257 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/symbols_schematic.txt";
258
260
261 BOOST_REQUIRE( parser.Parse( testFile ) );
262
263 const PADS_SCH::SYMBOL_DEF* res = parser.GetSymbolDef( "RES_0805" );
264 BOOST_REQUIRE( res != nullptr );
265
266 BOOST_CHECK_EQUAL( res->name, "RES_0805" );
267 BOOST_CHECK_EQUAL( res->gate_count, 1 );
268 BOOST_CHECK_EQUAL( res->graphics.size(), 4 );
269 BOOST_CHECK_EQUAL( res->pins.size(), 2 );
270}
271
272
273BOOST_AUTO_TEST_CASE( ParseSymbols_ResistorPins )
274{
275 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/symbols_schematic.txt";
276
278
279 BOOST_REQUIRE( parser.Parse( testFile ) );
280
281 const PADS_SCH::SYMBOL_DEF* res = parser.GetSymbolDef( "RES_0805" );
282 BOOST_REQUIRE( res != nullptr );
283 BOOST_REQUIRE( res->pins.size() >= 2 );
284
285 // CAEDECAL pins have placeholder numbers and empty names.
286 // Actual pin data comes from PARTTYPE GATE_DEF at build time.
287 const auto& pin1 = res->pins[0];
288 BOOST_CHECK_EQUAL( pin1.number, "1" );
289 BOOST_CHECK_EQUAL( pin1.position.x, -200.0 );
290 BOOST_CHECK_EQUAL( pin1.position.y, 0.0 );
291 BOOST_CHECK( pin1.type == PADS_SCH::PIN_TYPE::UNSPECIFIED );
292
293 const auto& pin2 = res->pins[1];
294 BOOST_CHECK_EQUAL( pin2.number, "2" );
295 BOOST_CHECK_EQUAL( pin2.position.x, 200.0 );
296 BOOST_CHECK_EQUAL( pin2.position.y, 0.0 );
297 BOOST_CHECK( pin2.type == PADS_SCH::PIN_TYPE::UNSPECIFIED );
298
299 // Verify PARTTYPE provides the actual pin numbers/names
300 auto ptIt = parser.GetPartTypes().find( "RES_0805" );
301 BOOST_REQUIRE( ptIt != parser.GetPartTypes().end() );
302 BOOST_REQUIRE( !ptIt->second.gates.empty() );
303
304 const auto& gate = ptIt->second.gates[0];
305 BOOST_REQUIRE_GE( gate.pins.size(), 2u );
306 BOOST_CHECK_EQUAL( gate.pins[0].pin_id, "1" );
307 BOOST_CHECK_EQUAL( gate.pins[0].pin_name, "1" );
308 BOOST_CHECK_EQUAL( gate.pins[1].pin_id, "2" );
309 BOOST_CHECK_EQUAL( gate.pins[1].pin_name, "2" );
310}
311
312
313BOOST_AUTO_TEST_CASE( ParseSymbols_Capacitor )
314{
315 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/symbols_schematic.txt";
316
318
319 BOOST_REQUIRE( parser.Parse( testFile ) );
320
321 const PADS_SCH::SYMBOL_DEF* cap = parser.GetSymbolDef( "CAP_0603" );
322 BOOST_REQUIRE( cap != nullptr );
323
324 BOOST_CHECK_EQUAL( cap->name, "CAP_0603" );
325 BOOST_CHECK_EQUAL( cap->gate_count, 1 );
326 BOOST_CHECK_EQUAL( cap->graphics.size(), 2 );
327 BOOST_CHECK_EQUAL( cap->pins.size(), 2 );
328}
329
330
331BOOST_AUTO_TEST_CASE( ParseSymbols_IC_MultiGate )
332{
333 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/symbols_schematic.txt";
334
336
337 BOOST_REQUIRE( parser.Parse( testFile ) );
338
339 const PADS_SCH::SYMBOL_DEF* ic = parser.GetSymbolDef( "IC_QUAD_NAND" );
340 BOOST_REQUIRE( ic != nullptr );
341
342 BOOST_CHECK_EQUAL( ic->name, "IC_QUAD_NAND" );
343 BOOST_CHECK_EQUAL( ic->graphics.size(), 9 );
344 BOOST_CHECK_EQUAL( ic->pins.size(), 14 );
345
346 // gate_count on SYMBOL_DEF stays at default (1). Multi-gate info lives in PARTTYPE.
347 auto ptIt = parser.GetPartTypes().find( "IC_QUAD_NAND" );
348 BOOST_REQUIRE( ptIt != parser.GetPartTypes().end() );
349 BOOST_CHECK_EQUAL( ptIt->second.num_physical, 4 );
350}
351
352
353BOOST_AUTO_TEST_CASE( ParseSymbols_IC_PinTypes )
354{
355 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/symbols_schematic.txt";
356
358
359 BOOST_REQUIRE( parser.Parse( testFile ) );
360
361 // Pin names/types on SYMBOL_DEF are raw CAEDECAL data (empty/unspecified).
362 // Actual pin data lives in PARTTYPE GATE_DEF and is applied at build time.
363 auto ptIt = parser.GetPartTypes().find( "IC_QUAD_NAND" );
364 BOOST_REQUIRE( ptIt != parser.GetPartTypes().end() );
365 BOOST_REQUIRE( !ptIt->second.gates.empty() );
366
367 const auto& pins = ptIt->second.gates[0].pins;
368 BOOST_REQUIRE_GE( pins.size(), 14u );
369
370 // Check input pins
371 BOOST_CHECK_EQUAL( pins[0].pin_name, "1A" );
372 BOOST_CHECK_EQUAL( pins[0].pin_type, 'L' );
373
374 // Check output pins
375 BOOST_CHECK_EQUAL( pins[2].pin_name, "1Y" );
376 BOOST_CHECK_EQUAL( pins[2].pin_type, 'S' );
377
378 // Check power pins
379 BOOST_CHECK_EQUAL( pins[6].pin_name, "GND" );
380 BOOST_CHECK_EQUAL( pins[6].pin_type, 'G' );
381}
382
383
384BOOST_AUTO_TEST_CASE( ParseSymbols_Graphics )
385{
386 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/symbols_schematic.txt";
387
389
390 BOOST_REQUIRE( parser.Parse( testFile ) );
391
392 const PADS_SCH::SYMBOL_DEF* res = parser.GetSymbolDef( "RES_0805" );
393 BOOST_REQUIRE( res != nullptr );
394 BOOST_REQUIRE( res->graphics.size() >= 1 );
395
396 // First graphic should be a rectangle (CLOSED)
397 const auto& rect = res->graphics[0];
398 BOOST_CHECK( rect.type == PADS_SCH::GRAPHIC_TYPE::RECTANGLE );
399 BOOST_CHECK_EQUAL( rect.line_width, 10.0 );
400 BOOST_REQUIRE( rect.points.size() >= 2 );
401 BOOST_CHECK_EQUAL( rect.points[0].coord.x, -100.0 );
402 BOOST_CHECK_EQUAL( rect.points[0].coord.y, -50.0 );
403 BOOST_CHECK_EQUAL( rect.points[1].coord.x, 100.0 );
404 BOOST_CHECK_EQUAL( rect.points[1].coord.y, 50.0 );
405}
406
407
408BOOST_AUTO_TEST_CASE( GetSymbolDef_NotFound )
409{
410 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/symbols_schematic.txt";
411
413
414 BOOST_REQUIRE( parser.Parse( testFile ) );
415
416 const PADS_SCH::SYMBOL_DEF* notFound = parser.GetSymbolDef( "NONEXISTENT_SYMBOL" );
417 BOOST_CHECK( notFound == nullptr );
418}
419
420
421BOOST_AUTO_TEST_CASE( ParseSymbols_EmptySection )
422{
423 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/simple_schematic.txt";
424
426
427 BOOST_REQUIRE( parser.Parse( testFile ) );
428
429 const auto& symbols = parser.GetSymbolDefs();
430 BOOST_CHECK( symbols.empty() );
431}
432
433
434BOOST_AUTO_TEST_CASE( ParseParts_Count )
435{
436 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/parts_schematic.txt";
437
439
440 BOOST_REQUIRE( parser.Parse( testFile ) );
441
442 const auto& parts = parser.GetPartPlacements();
443
444 BOOST_CHECK_EQUAL( parts.size(), 5 );
445}
446
447
448BOOST_AUTO_TEST_CASE( ParseParts_Resistor )
449{
450 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/parts_schematic.txt";
451
453
454 BOOST_REQUIRE( parser.Parse( testFile ) );
455
456 const PADS_SCH::PART_PLACEMENT* r1 = parser.GetPartPlacement( "R1" );
457 BOOST_REQUIRE( r1 != nullptr );
458
459 BOOST_CHECK_EQUAL( r1->reference, "R1" );
460 BOOST_CHECK_EQUAL( r1->symbol_name, "RES_0805" );
461 BOOST_CHECK_EQUAL( r1->position.x, 1000.0 );
462 BOOST_CHECK_EQUAL( r1->position.y, 2000.0 );
463 BOOST_CHECK_EQUAL( r1->rotation, 0.0 );
466}
467
468
469BOOST_AUTO_TEST_CASE( ParseParts_RotatedPart )
470{
471 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/parts_schematic.txt";
472
474
475 BOOST_REQUIRE( parser.Parse( testFile ) );
476
477 const PADS_SCH::PART_PLACEMENT* r2 = parser.GetPartPlacement( "R2" );
478 BOOST_REQUIRE( r2 != nullptr );
479
480 BOOST_CHECK_EQUAL( r2->rotation, 90.0 );
482}
483
484
485BOOST_AUTO_TEST_CASE( ParseParts_MirroredPart )
486{
487 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/parts_schematic.txt";
488
490
491 BOOST_REQUIRE( parser.Parse( testFile ) );
492
493 const PADS_SCH::PART_PLACEMENT* c1 = parser.GetPartPlacement( "C1" );
494 BOOST_REQUIRE( c1 != nullptr );
495
496 BOOST_CHECK_NE( c1->mirror_flags, 0 );
497}
498
499
500BOOST_AUTO_TEST_CASE( ParseParts_Attributes )
501{
502 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/parts_schematic.txt";
503
505
506 BOOST_REQUIRE( parser.Parse( testFile ) );
507
508 const PADS_SCH::PART_PLACEMENT* r1 = parser.GetPartPlacement( "R1" );
509 BOOST_REQUIRE( r1 != nullptr );
510 BOOST_CHECK_EQUAL( r1->attributes.size(), 2 );
511
512 // Check Ref.Des. attribute
513 bool foundRefDes = false;
514 bool foundValue = false;
515
516 for( const auto& attr : r1->attributes )
517 {
518 if( attr.name == "Ref.Des." )
519 {
520 BOOST_CHECK_EQUAL( attr.value, "R1" );
521 BOOST_CHECK( attr.visible );
522 foundRefDes = true;
523 }
524 else if( attr.name == "Value" )
525 {
526 BOOST_CHECK_EQUAL( attr.value, "10K" );
527 BOOST_CHECK( attr.visible );
528 foundValue = true;
529 }
530 }
531
532 BOOST_CHECK( foundRefDes );
533 BOOST_CHECK( foundValue );
534}
535
536
537BOOST_AUTO_TEST_CASE( ParseParts_AttributeVisibility )
538{
539 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/parts_schematic.txt";
540
542
543 BOOST_REQUIRE( parser.Parse( testFile ) );
544
545 const PADS_SCH::PART_PLACEMENT* r2 = parser.GetPartPlacement( "R2" );
546 BOOST_REQUIRE( r2 != nullptr );
547
548 // R2 has Value attribute with visibility N (hidden)
549 for( const auto& attr : r2->attributes )
550 {
551 if( attr.name == "Value" )
552 {
553 BOOST_CHECK( !attr.visible );
554 break;
555 }
556 }
557}
558
559
560BOOST_AUTO_TEST_CASE( ParseParts_IC_MultipleAttributes )
561{
562 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/parts_schematic.txt";
563
565
566 BOOST_REQUIRE( parser.Parse( testFile ) );
567
568 const PADS_SCH::PART_PLACEMENT* u1 = parser.GetPartPlacement( "U1" );
569 BOOST_REQUIRE( u1 != nullptr );
570
571 BOOST_CHECK_EQUAL( u1->symbol_name, "IC_QUAD_NAND" );
572 BOOST_CHECK_EQUAL( u1->attributes.size(), 4 );
573}
574
575
576BOOST_AUTO_TEST_CASE( ParseParts_MultiGatePart )
577{
578 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/parts_schematic.txt";
579
581
582 BOOST_REQUIRE( parser.Parse( testFile ) );
583
584 const PADS_SCH::PART_PLACEMENT* u1a = parser.GetPartPlacement( "U1.A" );
585 BOOST_REQUIRE( u1a != nullptr );
586
587 BOOST_CHECK_EQUAL( u1a->symbol_name, "IC_QUAD_NAND" );
589}
590
591
592BOOST_AUTO_TEST_CASE( GetPartPlacement_NotFound )
593{
594 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/parts_schematic.txt";
595
597
598 BOOST_REQUIRE( parser.Parse( testFile ) );
599
600 const PADS_SCH::PART_PLACEMENT* notFound = parser.GetPartPlacement( "NONEXISTENT" );
601 BOOST_CHECK( notFound == nullptr );
602}
603
604
605BOOST_AUTO_TEST_CASE( ParseParts_EmptySection )
606{
607 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/simple_schematic.txt";
608
610
611 BOOST_REQUIRE( parser.Parse( testFile ) );
612
613 const auto& parts = parser.GetPartPlacements();
614 BOOST_CHECK( parts.empty() );
615}
616
617
618BOOST_AUTO_TEST_CASE( ParseSignals_Count )
619{
620 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/signals_schematic.txt";
621
623
624 BOOST_REQUIRE( parser.Parse( testFile ) );
625
626 const auto& signals = parser.GetSignals();
627
628 BOOST_CHECK_EQUAL( signals.size(), 4 );
629}
630
631
632BOOST_AUTO_TEST_CASE( ParseSignals_VCC )
633{
634 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/signals_schematic.txt";
635
637
638 BOOST_REQUIRE( parser.Parse( testFile ) );
639
640 const PADS_SCH::SCH_SIGNAL* vcc = parser.GetSignal( "VCC" );
641 BOOST_REQUIRE( vcc != nullptr );
642
643 BOOST_CHECK_EQUAL( vcc->name, "VCC" );
644 BOOST_CHECK_EQUAL( vcc->connections.size(), 2 );
645 BOOST_CHECK_EQUAL( vcc->wires.size(), 2 );
646}
647
648
649BOOST_AUTO_TEST_CASE( ParseSignals_PinConnections )
650{
651 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/signals_schematic.txt";
652
654
655 BOOST_REQUIRE( parser.Parse( testFile ) );
656
657 const PADS_SCH::SCH_SIGNAL* vcc = parser.GetSignal( "VCC" );
658 BOOST_REQUIRE( vcc != nullptr );
659 BOOST_REQUIRE( vcc->connections.size() >= 2 );
660
661 // Check first connection: R1.1
662 BOOST_CHECK_EQUAL( vcc->connections[0].reference, "R1" );
663 BOOST_CHECK_EQUAL( vcc->connections[0].pin_number, "1" );
664
665 // Check second connection: U1.14
666 BOOST_CHECK_EQUAL( vcc->connections[1].reference, "U1" );
667 BOOST_CHECK_EQUAL( vcc->connections[1].pin_number, "14" );
668}
669
670
671BOOST_AUTO_TEST_CASE( ParseSignals_WireSegments )
672{
673 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/signals_schematic.txt";
674
676
677 BOOST_REQUIRE( parser.Parse( testFile ) );
678
679 const PADS_SCH::SCH_SIGNAL* vcc = parser.GetSignal( "VCC" );
680 BOOST_REQUIRE( vcc != nullptr );
681 BOOST_REQUIRE( vcc->wires.size() >= 2 );
682
683 // Check first wire segment
684 const auto& wire1 = vcc->wires[0];
685 BOOST_CHECK_EQUAL( wire1.start.x, 1000.0 );
686 BOOST_CHECK_EQUAL( wire1.start.y, 2000.0 );
687 BOOST_CHECK_EQUAL( wire1.end.x, 2000.0 );
688 BOOST_CHECK_EQUAL( wire1.end.y, 2000.0 );
689 BOOST_CHECK_EQUAL( wire1.sheet_number, 1 );
690
691 // Check second wire segment
692 const auto& wire2 = vcc->wires[1];
693 BOOST_CHECK_EQUAL( wire2.start.x, 2000.0 );
694 BOOST_CHECK_EQUAL( wire2.start.y, 2000.0 );
695 BOOST_CHECK_EQUAL( wire2.end.x, 2000.0 );
696 BOOST_CHECK_EQUAL( wire2.end.y, 3000.0 );
697}
698
699
700BOOST_AUTO_TEST_CASE( ParseSignals_MultipleConnections )
701{
702 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/signals_schematic.txt";
703
705
706 BOOST_REQUIRE( parser.Parse( testFile ) );
707
708 const PADS_SCH::SCH_SIGNAL* net1 = parser.GetSignal( "NET1" );
709 BOOST_REQUIRE( net1 != nullptr );
710
711 // NET1 connects R1.2, R2.1, U1.1, U1.2
712 BOOST_CHECK_EQUAL( net1->connections.size(), 4 );
713 BOOST_CHECK_EQUAL( net1->wires.size(), 4 );
714}
715
716
717BOOST_AUTO_TEST_CASE( ParseSignals_SingleConnection )
718{
719 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/signals_schematic.txt";
720
722
723 BOOST_REQUIRE( parser.Parse( testFile ) );
724
725 const PADS_SCH::SCH_SIGNAL* output = parser.GetSignal( "OUTPUT" );
726 BOOST_REQUIRE( output != nullptr );
727
728 BOOST_CHECK_EQUAL( output->connections.size(), 1 );
729 BOOST_CHECK_EQUAL( output->connections[0].reference, "U1" );
730 BOOST_CHECK_EQUAL( output->connections[0].pin_number, "3" );
731}
732
733
734BOOST_AUTO_TEST_CASE( GetSignal_NotFound )
735{
736 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/signals_schematic.txt";
737
739
740 BOOST_REQUIRE( parser.Parse( testFile ) );
741
742 const PADS_SCH::SCH_SIGNAL* notFound = parser.GetSignal( "NONEXISTENT" );
743 BOOST_CHECK( notFound == nullptr );
744}
745
746
747BOOST_AUTO_TEST_CASE( ParseSignals_EmptySection )
748{
749 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/simple_schematic.txt";
750
752
753 BOOST_REQUIRE( parser.Parse( testFile ) );
754
755 const auto& signals = parser.GetSignals();
756 BOOST_CHECK( signals.empty() );
757}
758
759
760BOOST_AUTO_TEST_CASE( SymbolBuilder_CreateSymbol )
761{
762 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/symbols_schematic.txt";
763
765 BOOST_REQUIRE( parser.Parse( testFile ) );
766
768
769 const PADS_SCH::SYMBOL_DEF* resDef = parser.GetSymbolDef( "RES_0805" );
770 BOOST_REQUIRE( resDef != nullptr );
771
772 LIB_SYMBOL* symbol = builder.BuildSymbol( *resDef );
773 BOOST_REQUIRE( symbol != nullptr );
774
775 BOOST_CHECK_EQUAL( symbol->GetName(), "RES_0805" );
776
777 delete symbol;
778}
779
780
781BOOST_AUTO_TEST_CASE( SymbolBuilder_SymbolHasGraphics )
782{
783 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/symbols_schematic.txt";
784
786 BOOST_REQUIRE( parser.Parse( testFile ) );
787
789
790 const PADS_SCH::SYMBOL_DEF* resDef = parser.GetSymbolDef( "RES_0805" );
791 BOOST_REQUIRE( resDef != nullptr );
792
793 LIB_SYMBOL* symbol = builder.BuildSymbol( *resDef );
794 BOOST_REQUIRE( symbol != nullptr );
795
796 // Count graphics (shapes) in the symbol
797 int shapeCount = 0;
798
799 for( const SCH_ITEM& item : symbol->GetDrawItems() )
800 {
801 if( item.Type() == SCH_SHAPE_T )
802 shapeCount++;
803 }
804
805 BOOST_CHECK_EQUAL( shapeCount, 4 );
806
807 delete symbol;
808}
809
810
811BOOST_AUTO_TEST_CASE( SymbolBuilder_SymbolHasPins )
812{
813 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/symbols_schematic.txt";
814
816 BOOST_REQUIRE( parser.Parse( testFile ) );
817
819
820 const PADS_SCH::SYMBOL_DEF* resDef = parser.GetSymbolDef( "RES_0805" );
821 BOOST_REQUIRE( resDef != nullptr );
822
823 LIB_SYMBOL* symbol = builder.BuildSymbol( *resDef );
824 BOOST_REQUIRE( symbol != nullptr );
825
826 // Count pins in the symbol
827 int pinCount = 0;
828
829 for( const SCH_ITEM& item : symbol->GetDrawItems() )
830 {
831 if( item.Type() == SCH_PIN_T )
832 pinCount++;
833 }
834
835 BOOST_CHECK_EQUAL( pinCount, 2 );
836
837 delete symbol;
838}
839
840
841BOOST_AUTO_TEST_CASE( SymbolBuilder_PinProperties )
842{
843 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/symbols_schematic.txt";
844
846 BOOST_REQUIRE( parser.Parse( testFile ) );
847
849
850 const PADS_SCH::SYMBOL_DEF* resDef = parser.GetSymbolDef( "RES_0805" );
851 BOOST_REQUIRE( resDef != nullptr );
852
853 LIB_SYMBOL* symbol = builder.BuildSymbol( *resDef );
854 BOOST_REQUIRE( symbol != nullptr );
855
856 // Find a pin and verify its properties
857 const SCH_PIN* pin1 = nullptr;
858
859 for( const SCH_ITEM& item : symbol->GetDrawItems() )
860 {
861 if( item.Type() == SCH_PIN_T )
862 {
863 const SCH_PIN* pin = static_cast<const SCH_PIN*>( &item );
864
865 if( pin->GetNumber() == "1" )
866 {
867 pin1 = pin;
868 break;
869 }
870 }
871 }
872
873 BOOST_REQUIRE( pin1 != nullptr );
874 BOOST_CHECK_EQUAL( pin1->GetNumber(), "1" );
875 BOOST_CHECK( pin1->GetType() == ELECTRICAL_PINTYPE::PT_UNSPECIFIED );
876
877 delete symbol;
878}
879
880
881BOOST_AUTO_TEST_CASE( SymbolBuilder_CacheSymbol )
882{
883 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/symbols_schematic.txt";
884
886 BOOST_REQUIRE( parser.Parse( testFile ) );
887
889
890 const PADS_SCH::SYMBOL_DEF* resDef = parser.GetSymbolDef( "RES_0805" );
891 BOOST_REQUIRE( resDef != nullptr );
892
893 // First call creates the symbol
894 BOOST_CHECK( !builder.HasSymbol( "RES_0805" ) );
895
896 LIB_SYMBOL* symbol1 = builder.GetOrCreateSymbol( *resDef );
897 BOOST_REQUIRE( symbol1 != nullptr );
898 BOOST_CHECK( builder.HasSymbol( "RES_0805" ) );
899
900 // Second call returns the same symbol
901 LIB_SYMBOL* symbol2 = builder.GetOrCreateSymbol( *resDef );
902 BOOST_CHECK_EQUAL( symbol1, symbol2 );
903}
904
905
906BOOST_AUTO_TEST_CASE( PowerSymbol_GroundVariants )
907{
915 BOOST_CHECK( PADS_SCH::PADS_SCH_SYMBOL_BUILDER::IsPowerSymbol( "EARTH" ) );
916 BOOST_CHECK( PADS_SCH::PADS_SCH_SYMBOL_BUILDER::IsPowerSymbol( "CHASSIS" ) );
917}
918
919
920BOOST_AUTO_TEST_CASE( PowerSymbol_SupplyVariants )
921{
931}
932
933
934BOOST_AUTO_TEST_CASE( PowerSymbol_VoltagePatterns )
935{
942}
943
944
945BOOST_AUTO_TEST_CASE( PowerSymbol_NonPower )
946{
949 BOOST_CHECK( !PADS_SCH::PADS_SCH_SYMBOL_BUILDER::IsPowerSymbol( "NET1" ) );
950 BOOST_CHECK( !PADS_SCH::PADS_SCH_SYMBOL_BUILDER::IsPowerSymbol( "DATA" ) );
952 BOOST_CHECK( !PADS_SCH::PADS_SCH_SYMBOL_BUILDER::IsPowerSymbol( "RESET" ) );
953}
954
955
956BOOST_AUTO_TEST_CASE( PowerSymbol_KiCadMapping_Ground )
957{
959 BOOST_REQUIRE( gnd.has_value() );
960 BOOST_CHECK_EQUAL( gnd->GetLibNickname().wx_str(), "power" );
961 BOOST_CHECK_EQUAL( gnd->GetLibItemName().wx_str(), "GND" );
962
964 BOOST_REQUIRE( agnd.has_value() );
965 BOOST_CHECK_EQUAL( agnd->GetLibItemName().wx_str(), "GND" );
966
968 BOOST_REQUIRE( dgnd.has_value() );
969 BOOST_CHECK_EQUAL( dgnd->GetLibItemName().wx_str(), "GNDD" );
970}
971
972
973BOOST_AUTO_TEST_CASE( PowerSymbol_KiCadMapping_Supply )
974{
976 BOOST_REQUIRE( vcc.has_value() );
977 BOOST_CHECK_EQUAL( vcc->GetLibNickname().wx_str(), "power" );
978 BOOST_CHECK_EQUAL( vcc->GetLibItemName().wx_str(), "VCC" );
979
981 BOOST_REQUIRE( vdd.has_value() );
982 BOOST_CHECK_EQUAL( vdd->GetLibItemName().wx_str(), "VDD" );
983
985 BOOST_REQUIRE( v5.has_value() );
986 BOOST_CHECK_EQUAL( v5->GetLibItemName().wx_str(), "+5V" );
987}
988
989
990BOOST_AUTO_TEST_CASE( PowerSymbol_KiCadMapping_NotFound )
991{
993 BOOST_CHECK( !notPower.has_value() );
994
996 BOOST_CHECK( !notPower2.has_value() );
997}
998
999
1000BOOST_AUTO_TEST_CASE( PowerSymbol_KiCadMapping_GenericFallback )
1001{
1002 // +V* names not in the explicit table should fall back to VCC
1004 BOOST_REQUIRE( plusV.has_value() );
1005 BOOST_CHECK_EQUAL( plusV->GetLibItemName().wx_str(), "VCC" );
1006
1008 BOOST_REQUIRE( plusV7.has_value() );
1009 BOOST_CHECK_EQUAL( plusV7->GetLibItemName().wx_str(), "VCC" );
1010
1011 // -V* names should fall back to VEE
1013 BOOST_REQUIRE( minusV.has_value() );
1014 BOOST_CHECK_EQUAL( minusV->GetLibItemName().wx_str(), "VEE" );
1015}
1016
1017
1018BOOST_AUTO_TEST_CASE( PowerSymbol_CaseInsensitive )
1019{
1021 BOOST_REQUIRE( gndLower.has_value() );
1022 BOOST_CHECK_EQUAL( gndLower->GetLibItemName().wx_str(), "GND" );
1023
1025 BOOST_REQUIRE( vccMixed.has_value() );
1026 BOOST_CHECK_EQUAL( vccMixed->GetLibItemName().wx_str(), "VCC" );
1027}
1028
1029
1030BOOST_AUTO_TEST_CASE( BuildKiCadPowerSymbol_Styles )
1031{
1032 PADS_SCH::PARAMETERS params;
1034 PADS_SCH::PADS_SCH_SYMBOL_BUILDER builder( params );
1035
1036 // GND style: chevron ground, pin facing down
1037 std::unique_ptr<LIB_SYMBOL> gnd( builder.BuildKiCadPowerSymbol( "GND" ) );
1038 BOOST_REQUIRE( gnd != nullptr );
1039 BOOST_CHECK( gnd->IsPower() );
1040 BOOST_CHECK_EQUAL( gnd->GetName(), "GND" );
1041
1042 // VCC style: arrow up, pin facing up
1043 std::unique_ptr<LIB_SYMBOL> vcc( builder.BuildKiCadPowerSymbol( "VCC" ) );
1044 BOOST_REQUIRE( vcc != nullptr );
1045 BOOST_CHECK( vcc->IsPower() );
1046 BOOST_CHECK_EQUAL( vcc->GetName(), "VCC" );
1047
1048 // VEE style: inverted arrow, pin facing down
1049 std::unique_ptr<LIB_SYMBOL> vee( builder.BuildKiCadPowerSymbol( "VEE" ) );
1050 BOOST_REQUIRE( vee != nullptr );
1051 BOOST_CHECK( vee->IsPower() );
1052
1053 // GNDD style: thick bar ground
1054 std::unique_ptr<LIB_SYMBOL> gndd( builder.BuildKiCadPowerSymbol( "GNDD" ) );
1055 BOOST_REQUIRE( gndd != nullptr );
1056 BOOST_CHECK( gndd->IsPower() );
1057
1058 // Earth style: descending bars
1059 std::unique_ptr<LIB_SYMBOL> earth( builder.BuildKiCadPowerSymbol( "Earth" ) );
1060 BOOST_REQUIRE( earth != nullptr );
1061 BOOST_CHECK( earth->IsPower() );
1062
1063 // PWR_BAR style: thick bar pointing up (for positive rail symbols like +V1)
1064 std::unique_ptr<LIB_SYMBOL> pwrBar( builder.BuildKiCadPowerSymbol( "PWR_BAR" ) );
1065 BOOST_REQUIRE( pwrBar != nullptr );
1066 BOOST_CHECK( pwrBar->IsPower() );
1067
1068 // PWR_TRIANGLE style: filled triangle pointing up (for arrow symbols like +V2)
1069 std::unique_ptr<LIB_SYMBOL> pwrTri( builder.BuildKiCadPowerSymbol( "PWR_TRIANGLE" ) );
1070 BOOST_REQUIRE( pwrTri != nullptr );
1071 BOOST_CHECK( pwrTri->IsPower() );
1072
1073 // Verify each symbol has exactly one pin
1074 BOOST_CHECK_EQUAL( gnd->GetPins().size(), 1u );
1075 BOOST_CHECK_EQUAL( vcc->GetPins().size(), 1u );
1076 BOOST_CHECK_EQUAL( vee->GetPins().size(), 1u );
1077 BOOST_CHECK_EQUAL( gndd->GetPins().size(), 1u );
1078 BOOST_CHECK_EQUAL( earth->GetPins().size(), 1u );
1079 BOOST_CHECK_EQUAL( pwrBar->GetPins().size(), 1u );
1080 BOOST_CHECK_EQUAL( pwrTri->GetPins().size(), 1u );
1081}
1082
1083
1084BOOST_AUTO_TEST_CASE( PowerStyleFromVariant )
1085{
1087
1088 // Ground variants
1089 BOOST_CHECK_EQUAL( PADS_SCH_SYMBOL_BUILDER::GetPowerStyleFromVariant( "GND", "G" ), "GND" );
1090 BOOST_CHECK_EQUAL( PADS_SCH_SYMBOL_BUILDER::GetPowerStyleFromVariant( "AGND", "G" ), "GND" );
1091 BOOST_CHECK_EQUAL( PADS_SCH_SYMBOL_BUILDER::GetPowerStyleFromVariant( "CHGND", "G" ), "Chassis" );
1092
1093 // Rail variants (thick bar)
1094 BOOST_CHECK_EQUAL( PADS_SCH_SYMBOL_BUILDER::GetPowerStyleFromVariant( "+RAIL", "P" ), "PWR_BAR" );
1095 BOOST_CHECK_EQUAL( PADS_SCH_SYMBOL_BUILDER::GetPowerStyleFromVariant( "-RAIL", "P" ), "GNDD" );
1096
1097 // Arrow variants (filled triangle)
1098 BOOST_CHECK_EQUAL( PADS_SCH_SYMBOL_BUILDER::GetPowerStyleFromVariant( "+ARROW", "P" ), "PWR_TRIANGLE" );
1099 BOOST_CHECK_EQUAL( PADS_SCH_SYMBOL_BUILDER::GetPowerStyleFromVariant( "-ARROW", "P" ), "VEE" );
1100
1101 // Bubble variants (map to VCC/VEE)
1102 BOOST_CHECK_EQUAL( PADS_SCH_SYMBOL_BUILDER::GetPowerStyleFromVariant( "+BUBBLE", "P" ), "VCC" );
1103 BOOST_CHECK_EQUAL( PADS_SCH_SYMBOL_BUILDER::GetPowerStyleFromVariant( "-BUBBLE", "P" ), "VEE" );
1104}
1105
1106
1107BOOST_AUTO_TEST_CASE( SheetCount_SingleSheet )
1108{
1109 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/simple_schematic.txt";
1110
1112 BOOST_REQUIRE( parser.Parse( testFile ) );
1113
1114 // Simple schematic with no parts defaults to 1 sheet
1115 BOOST_CHECK_EQUAL( parser.GetSheetCount(), 1 );
1116}
1117
1118
1119BOOST_AUTO_TEST_CASE( SheetNumbers_FromParts )
1120{
1121 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/parts_schematic.txt";
1122
1124 BOOST_REQUIRE( parser.Parse( testFile ) );
1125
1126 std::set<int> sheets = parser.GetSheetNumbers();
1127 BOOST_CHECK( sheets.count( 1 ) > 0 ); // At least sheet 1 should exist
1128}
1129
1130
1131BOOST_AUTO_TEST_CASE( GetPartsOnSheet )
1132{
1133 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/parts_schematic.txt";
1134
1136 BOOST_REQUIRE( parser.Parse( testFile ) );
1137
1138 std::vector<PADS_SCH::PART_PLACEMENT> partsOnSheet1 = parser.GetPartsOnSheet( 1 );
1139
1140 // All parts in test file should be on sheet 1
1141 BOOST_CHECK_EQUAL( partsOnSheet1.size(), parser.GetPartPlacements().size() );
1142}
1143
1144
1145BOOST_AUTO_TEST_CASE( GetSignalsOnSheet )
1146{
1147 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/signals_schematic.txt";
1148
1150 BOOST_REQUIRE( parser.Parse( testFile ) );
1151
1152 std::vector<PADS_SCH::SCH_SIGNAL> signalsOnSheet1 = parser.GetSignalsOnSheet( 1 );
1153
1154 // All signals in test file should have wires on sheet 1
1155 BOOST_CHECK( signalsOnSheet1.size() > 0 );
1156}
1157
1158
1159BOOST_AUTO_TEST_CASE( ParsePartTypes_V52_RegularPart_MultipleDecals )
1160{
1161 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/v52_parttypes.txt";
1162
1164
1165 BOOST_REQUIRE( parser.Parse( testFile ) );
1166 BOOST_CHECK( parser.IsValid() );
1167
1168 const auto& partTypes = parser.GetPartTypes();
1169
1170 // RES0805 should be parsed with G: gate format
1171 auto it = partTypes.find( "RES0805" );
1172 BOOST_REQUIRE( it != partTypes.end() );
1173
1174 const PADS_SCH::PARTTYPE_DEF& res = it->second;
1175 BOOST_CHECK_EQUAL( res.category, "RES" );
1176 BOOST_REQUIRE_EQUAL( res.gates.size(), 1 );
1177
1178 const PADS_SCH::GATE_DEF& resGate = res.gates[0];
1180 BOOST_CHECK_EQUAL( resGate.num_pins, 2 );
1181 BOOST_CHECK_EQUAL( resGate.swap_flag, 0 );
1182
1183 // Decal names parsed from colon-separated G: field
1184 BOOST_REQUIRE_EQUAL( resGate.decal_names.size(), 4 );
1185 BOOST_CHECK_EQUAL( resGate.decal_names[0], "RESZ-H" );
1186 BOOST_CHECK_EQUAL( resGate.decal_names[1], "RESZ-V" );
1187 BOOST_CHECK_EQUAL( resGate.decal_names[2], "RESB-H" );
1188 BOOST_CHECK_EQUAL( resGate.decal_names[3], "RESB-V" );
1189
1190 // Pin definitions from dot-separated tokens
1191 BOOST_REQUIRE_EQUAL( resGate.pins.size(), 2 );
1192 BOOST_CHECK_EQUAL( resGate.pins[0].pin_id, "1" );
1193 BOOST_CHECK_EQUAL( resGate.pins[0].swap_group, 1 );
1194 BOOST_CHECK_EQUAL( resGate.pins[0].pin_type, 'U' );
1195 BOOST_CHECK_EQUAL( resGate.pins[1].pin_id, "2" );
1196 BOOST_CHECK_EQUAL( resGate.pins[1].swap_group, 1 );
1197}
1198
1199
1200BOOST_AUTO_TEST_CASE( ParsePartTypes_V52_MultiGatePart )
1201{
1202 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/v52_parttypes.txt";
1203
1205
1206 BOOST_REQUIRE( parser.Parse( testFile ) );
1207
1208 const auto& partTypes = parser.GetPartTypes();
1209
1210 auto it = partTypes.find( "PS2802-4-A" );
1211 BOOST_REQUIRE( it != partTypes.end() );
1212
1213 const PADS_SCH::PARTTYPE_DEF& ps = it->second;
1214 BOOST_CHECK_EQUAL( ps.category, "SOP" );
1215 BOOST_REQUIRE_EQUAL( ps.gates.size(), 4 );
1216
1217 // Each gate should have 4 pins and reference the PS2802 decal
1218 for( int g = 0; g < 4; g++ )
1219 {
1220 BOOST_CHECK_EQUAL( ps.gates[g].num_pins, 4 );
1221 BOOST_REQUIRE_GE( ps.gates[g].decal_names.size(), 1 );
1222 BOOST_CHECK_EQUAL( ps.gates[g].decal_names[0], "PS2802" );
1223 }
1224
1225 // Verify specific pin names from first gate (AN, CATH, EMIT, COL)
1226 BOOST_REQUIRE_EQUAL( ps.gates[0].pins.size(), 4 );
1227 BOOST_CHECK_EQUAL( ps.gates[0].pins[0].pin_id, "1" );
1228 BOOST_CHECK_EQUAL( ps.gates[0].pins[0].pin_name, "AN" );
1229 BOOST_CHECK_EQUAL( ps.gates[0].pins[1].pin_id, "2" );
1230 BOOST_CHECK_EQUAL( ps.gates[0].pins[1].pin_name, "CATH" );
1231 BOOST_CHECK_EQUAL( ps.gates[0].pins[2].pin_id, "15" );
1232 BOOST_CHECK_EQUAL( ps.gates[0].pins[2].pin_name, "EMIT" );
1233 BOOST_CHECK_EQUAL( ps.gates[0].pins[3].pin_id, "16" );
1234 BOOST_CHECK_EQUAL( ps.gates[0].pins[3].pin_name, "COL" );
1235}
1236
1237
1238BOOST_AUTO_TEST_CASE( ParsePartTypes_V52_Connector )
1239{
1240 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/v52_parttypes.txt";
1241
1243
1244 BOOST_REQUIRE( parser.Parse( testFile ) );
1245
1246 const auto& partTypes = parser.GetPartTypes();
1247
1248 auto it = partTypes.find( "43650-0400" );
1249 BOOST_REQUIRE( it != partTypes.end() );
1250
1251 const PADS_SCH::PARTTYPE_DEF& conn = it->second;
1252 BOOST_CHECK_EQUAL( conn.category, "CON" );
1253 BOOST_CHECK( conn.is_connector );
1254 BOOST_REQUIRE_EQUAL( conn.gates.size(), 1 );
1255 BOOST_CHECK_EQUAL( conn.gates[0].num_pins, 4 );
1256 BOOST_REQUIRE_EQUAL( conn.gates[0].pins.size(), 4 );
1257
1258 // Connector pins should have S type
1259 for( int p = 0; p < 4; p++ )
1260 {
1261 BOOST_CHECK_EQUAL( conn.gates[0].pins[p].pin_type, 'S' );
1262 }
1263}
1264
1265
1266BOOST_AUTO_TEST_CASE( ParsePartTypes_V52_SpecialSymbols )
1267{
1268 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/v52_parttypes.txt";
1269
1271
1272 BOOST_REQUIRE( parser.Parse( testFile ) );
1273
1274 const auto& partTypes = parser.GetPartTypes();
1275
1276 // $GND_SYMS
1277 auto gndIt = partTypes.find( "$GND_SYMS" );
1278 BOOST_REQUIRE( gndIt != partTypes.end() );
1279
1280 const PADS_SCH::PARTTYPE_DEF& gnd = gndIt->second;
1281 BOOST_CHECK_EQUAL( gnd.special_keyword, "GND" );
1282 BOOST_CHECK_EQUAL( gnd.gates.size(), 2 );
1283 BOOST_REQUIRE_EQUAL( gnd.special_variants.size(), 2 );
1284 BOOST_CHECK_EQUAL( gnd.special_variants[0].decal_name, "DGND" );
1285 BOOST_CHECK_EQUAL( gnd.special_variants[0].pin_type, "G" );
1286 BOOST_CHECK_EQUAL( gnd.special_variants[1].decal_name, "PWRGND" );
1287
1288 // V5.2 SIGPIN entries
1289 BOOST_REQUIRE_EQUAL( gnd.sigpins.size(), 2 );
1290 BOOST_CHECK_EQUAL( gnd.sigpins[0].pin_number, "1" );
1291 BOOST_CHECK_EQUAL( gnd.sigpins[0].net_name, "DGND" );
1292 BOOST_CHECK_EQUAL( gnd.sigpins[1].pin_number, "2" );
1293 BOOST_CHECK_EQUAL( gnd.sigpins[1].net_name, "PWRGND" );
1294
1295 // $PWR_SYMS
1296 auto pwrIt = partTypes.find( "$PWR_SYMS" );
1297 BOOST_REQUIRE( pwrIt != partTypes.end() );
1298
1299 const PADS_SCH::PARTTYPE_DEF& pwr = pwrIt->second;
1300 BOOST_CHECK_EQUAL( pwr.special_keyword, "PWR" );
1301 BOOST_CHECK_EQUAL( pwr.gates.size(), 2 );
1302 BOOST_REQUIRE_EQUAL( pwr.special_variants.size(), 2 );
1303 BOOST_CHECK_EQUAL( pwr.special_variants[0].decal_name, "+5V" );
1304 BOOST_CHECK_EQUAL( pwr.special_variants[0].pin_type, "P" );
1305
1306 BOOST_REQUIRE_EQUAL( pwr.sigpins.size(), 2 );
1307 BOOST_CHECK_EQUAL( pwr.sigpins[0].net_name, "+5V" );
1308}
1309
1310
1311BOOST_AUTO_TEST_CASE( ParsePartTypes_V52_SimplePart )
1312{
1313 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/v52_parttypes.txt";
1314
1316
1317 BOOST_REQUIRE( parser.Parse( testFile ) );
1318
1319 const auto& partTypes = parser.GetPartTypes();
1320
1321 // MMSZ5260BT1 should map to ZENER decal
1322 auto it = partTypes.find( "MMSZ5260BT1" );
1323 BOOST_REQUIRE( it != partTypes.end() );
1324
1325 const PADS_SCH::PARTTYPE_DEF& diode = it->second;
1326 BOOST_CHECK_EQUAL( diode.category, "DIO" );
1327 BOOST_REQUIRE_EQUAL( diode.gates.size(), 1 );
1328 BOOST_REQUIRE_EQUAL( diode.gates[0].decal_names.size(), 1 );
1329 BOOST_CHECK_EQUAL( diode.gates[0].decal_names[0], "ZENER" );
1330 BOOST_CHECK_EQUAL( diode.gates[0].num_pins, 2 );
1331 BOOST_REQUIRE_EQUAL( diode.gates[0].pins.size(), 2 );
1332}
1333
1334
1335BOOST_AUTO_TEST_CASE( SymbolBuilder_ConnectorPinSymbol )
1336{
1337 PADS_SCH::PARAMETERS params;
1339 PADS_SCH::PADS_SCH_SYMBOL_BUILDER builder( params );
1340
1341 // Create a minimal connector PARTTYPE and symbol def
1343 connPt.name = "TEST_CONN";
1344 connPt.is_connector = true;
1345 connPt.category = "CON";
1346
1347 PADS_SCH::GATE_DEF gate;
1348 gate.num_pins = 1;
1349 gate.decal_names.push_back( "EXTIN" );
1350
1352 pin.pin_id = "1";
1353 pin.pin_type = 'S';
1354 gate.pins.push_back( pin );
1355 connPt.gates.push_back( gate );
1356
1357 PADS_SCH::SYMBOL_DEF symDef;
1358 symDef.name = "EXTIN";
1359 symDef.gate_count = 1;
1360
1361 PADS_SCH::SYMBOL_PIN symPin;
1362 symPin.number = "1";
1363 symPin.position.x = 0;
1364 symPin.position.y = 0;
1365 symPin.length = 100;
1366 symDef.pins.push_back( symPin );
1367
1368 // Pin 15 variant should have pin number "15"
1369 LIB_SYMBOL* sym15 = builder.GetOrCreateConnectorPinSymbol( connPt, symDef, "15" );
1370 BOOST_REQUIRE( sym15 != nullptr );
1371
1372 auto pins15 = sym15->GetPins();
1373 BOOST_REQUIRE_EQUAL( pins15.size(), 1u );
1374 BOOST_CHECK_EQUAL( pins15[0]->GetNumber(), "15" );
1375
1376 // Pin 1 variant should have pin number "1"
1377 LIB_SYMBOL* sym1 = builder.GetOrCreateConnectorPinSymbol( connPt, symDef, "1" );
1378 BOOST_REQUIRE( sym1 != nullptr );
1379
1380 auto pins1 = sym1->GetPins();
1381 BOOST_REQUIRE_EQUAL( pins1.size(), 1u );
1382 BOOST_CHECK_EQUAL( pins1[0]->GetNumber(), "1" );
1383
1384 // Different pin numbers should produce different cached symbols
1385 BOOST_CHECK_NE( sym15, sym1 );
1386
1387 // Same pin number should return cached symbol
1388 LIB_SYMBOL* sym15again = builder.GetOrCreateConnectorPinSymbol( connPt, symDef, "15" );
1389 BOOST_CHECK_EQUAL( sym15, sym15again );
1390}
1391
1392
1393BOOST_AUTO_TEST_CASE( SymbolBuilder_MultiUnitConnectorSymbol )
1394{
1395 PADS_SCH::PARAMETERS params;
1397 PADS_SCH::PADS_SCH_SYMBOL_BUILDER builder( params );
1398
1400 connPt.name = "TEST_MULTICONN";
1401 connPt.is_connector = true;
1402 connPt.category = "CON";
1403
1404 PADS_SCH::GATE_DEF gate;
1405 gate.num_pins = 4;
1406 gate.decal_names.push_back( "EXTIN" );
1407
1408 for( int i = 1; i <= 4; i++ )
1409 {
1411 pin.pin_id = std::to_string( i );
1412 pin.pin_type = 'S';
1413 gate.pins.push_back( pin );
1414 }
1415
1416 connPt.gates.push_back( gate );
1417
1418 PADS_SCH::SYMBOL_DEF symDef;
1419 symDef.name = "EXTIN";
1420 symDef.gate_count = 1;
1421
1422 PADS_SCH::SYMBOL_PIN symPin;
1423 symPin.number = "1";
1424 symPin.position.x = 0;
1425 symPin.position.y = 0;
1426 symPin.length = 100;
1427 symDef.pins.push_back( symPin );
1428
1429 std::vector<std::string> pinNumbers = { "1", "2", "3", "4" };
1430 std::string cacheKey = "TEST_MULTICONN:conn:J1";
1431
1432 LIB_SYMBOL* multiSym =
1433 builder.GetOrCreateMultiUnitConnectorSymbol( connPt, symDef, pinNumbers, cacheKey );
1434 BOOST_REQUIRE( multiSym != nullptr );
1435
1436 BOOST_CHECK_EQUAL( multiSym->GetUnitCount(), 4 );
1437
1438 for( int unit = 1; unit <= 4; unit++ )
1439 {
1440 std::vector<SCH_PIN*> unitPins;
1441
1442 for( SCH_PIN* pin : multiSym->GetPins() )
1443 {
1444 if( pin->GetUnit() == unit )
1445 unitPins.push_back( pin );
1446 }
1447
1448 BOOST_REQUIRE_EQUAL( unitPins.size(), 1u );
1449 BOOST_CHECK_EQUAL( unitPins[0]->GetNumber(), std::to_string( unit ) );
1450 }
1451
1452 // Same cache key should return the same symbol
1453 LIB_SYMBOL* cached =
1454 builder.GetOrCreateMultiUnitConnectorSymbol( connPt, symDef, pinNumbers, cacheKey );
1455 BOOST_CHECK_EQUAL( multiSym, cached );
1456
1457 // Different cache key should produce a new symbol
1458 LIB_SYMBOL* other =
1459 builder.GetOrCreateMultiUnitConnectorSymbol( connPt, symDef, pinNumbers, "other_key" );
1460 BOOST_CHECK_NE( multiSym, other );
1461}
1462
1463
1464BOOST_AUTO_TEST_CASE( V9_MultiGate_TL082_FromFile )
1465{
1466 std::string testFile = "/home/seth/Downloads/ATS-501 Tape Template (1).txt";
1467
1468 if( !wxFileExists( wxString::FromUTF8( testFile ) ) )
1469 {
1470 BOOST_TEST_MESSAGE( "Skipping: test file not present" );
1471 return;
1472 }
1473
1475 BOOST_REQUIRE( parser.Parse( testFile ) );
1476
1477 const auto& partTypes = parser.GetPartTypes();
1478 auto ptIt = partTypes.find( "TL082" );
1479 BOOST_REQUIRE( ptIt != partTypes.end() );
1480
1481 const auto& tl082 = ptIt->second;
1482 BOOST_REQUIRE_EQUAL( tl082.gates.size(), 2u );
1483 BOOST_CHECK_EQUAL( tl082.gates[0].num_pins, 5 );
1484 BOOST_CHECK_EQUAL( tl082.gates[1].num_pins, 3 );
1485 BOOST_CHECK_EQUAL( tl082.gates[0].decal_names[0], "TL082A" );
1486 BOOST_CHECK_EQUAL( tl082.gates[1].decal_names[0], "TL082" );
1487
1488 const auto& params = parser.GetParameters();
1489 PADS_SCH::PADS_SCH_SYMBOL_BUILDER builder( params );
1490
1491 LIB_SYMBOL* sym = builder.BuildMultiUnitSymbol( tl082, parser.GetSymbolDefs() );
1492 BOOST_REQUIRE( sym != nullptr );
1493 BOOST_CHECK_EQUAL( sym->GetUnitCount(), 2 );
1494
1495 int unit1Pins = 0, unit2Pins = 0;
1496
1497 for( auto* pin : sym->GetPins() )
1498 {
1499 if( pin->GetUnit() == 1 )
1500 unit1Pins++;
1501 else if( pin->GetUnit() == 2 )
1502 unit2Pins++;
1503 }
1504
1505 BOOST_CHECK_EQUAL( unit1Pins, 5 );
1506 BOOST_CHECK_EQUAL( unit2Pins, 3 );
1507
1508 delete sym;
1509}
1510
1511
1513
1514
1515// Schematic Builder tests
1516#include <sch_io/pads/pads_sch_schematic_builder.h>
1518#include <sch_line.h>
1519#include <sch_label.h>
1520#include <sch_junction.h>
1521#include <sch_symbol.h>
1522#include <sch_screen.h>
1523#include <schematic.h>
1524#include <template_fieldnames.h>
1525#include <title_block.h>
1526
1527BOOST_AUTO_TEST_SUITE( PadsSchSchematicBuilder )
1528
1529
1530BOOST_AUTO_TEST_CASE( CreateWire_SingleSegment )
1531{
1532 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/simple_schematic.txt";
1533
1535 BOOST_REQUIRE( parser.Parse( testFile ) );
1536
1537 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( parser.GetParameters(), nullptr );
1538
1540 wire.start.x = 1000.0;
1541 wire.start.y = 2000.0;
1542 wire.end.x = 3000.0;
1543 wire.end.y = 2000.0;
1544
1545 SCH_LINE* line = builder.CreateWire( wire );
1546 BOOST_REQUIRE( line != nullptr );
1547
1548 BOOST_CHECK( line->GetLayer() == LAYER_WIRE );
1549 BOOST_CHECK( line->GetStartPoint().x != 0 || line->GetStartPoint().y != 0 );
1550 BOOST_CHECK( line->GetEndPoint().x != 0 || line->GetEndPoint().y != 0 );
1551
1552 delete line;
1553}
1554
1555
1556BOOST_AUTO_TEST_CASE( CreateWire_FromSignals )
1557{
1558 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/signals_schematic.txt";
1559
1561 BOOST_REQUIRE( parser.Parse( testFile ) );
1562
1563 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( parser.GetParameters(), nullptr );
1564
1565 // Count total expected wires
1566 int expectedWires = 0;
1567
1568 for( const auto& signal : parser.GetSignals() )
1569 expectedWires += static_cast<int>( signal.wires.size() );
1570
1571 BOOST_CHECK( expectedWires > 0 );
1572}
1573
1574
1575BOOST_AUTO_TEST_CASE( CreateNetLabel_FromSignal )
1576{
1577 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/simple_schematic.txt";
1578
1580 BOOST_REQUIRE( parser.Parse( testFile ) );
1581
1582 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( parser.GetParameters(), nullptr );
1583
1584 PADS_SCH::SCH_SIGNAL signal;
1585 signal.name = "VCC";
1586
1588 wire.start.x = 1000.0;
1589 wire.start.y = 2000.0;
1590 wire.end.x = 3000.0;
1591 wire.end.y = 2000.0;
1592 signal.wires.push_back( wire );
1593
1594 VECTOR2I pos( 1000, 2000 );
1595 SCH_GLOBALLABEL* label = builder.CreateNetLabel( signal, pos );
1596 BOOST_REQUIRE( label != nullptr );
1597
1598 BOOST_CHECK_EQUAL( label->GetText(), "VCC" );
1599
1600 delete label;
1601}
1602
1603
1604BOOST_AUTO_TEST_CASE( CreateNetLabel_PreservesSpecialChars )
1605{
1606 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/simple_schematic.txt";
1607
1609 BOOST_REQUIRE( parser.Parse( testFile ) );
1610
1611 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( parser.GetParameters(), nullptr );
1612
1613 PADS_SCH::SCH_SIGNAL signal;
1614 signal.name = "NET 1";
1615
1616 VECTOR2I pos( 1000, 2000 );
1617 SCH_GLOBALLABEL* label = builder.CreateNetLabel( signal, pos );
1618 BOOST_REQUIRE( label != nullptr );
1619
1620 // Net names pass through unchanged; KiCad handles arbitrary UTF-8 net names
1621 BOOST_CHECK_EQUAL( label->GetText(), "NET 1" );
1622
1623 delete label;
1624}
1625
1626
1627BOOST_AUTO_TEST_CASE( IsBusSignal_BracketNotation )
1628{
1629 // Bus notation with brackets: NAME[n:m] or NAME[n..m]
1630 BOOST_CHECK( PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER::IsBusSignal( "DATA[7:0]" ) );
1631 BOOST_CHECK( PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER::IsBusSignal( "ADDR[15:0]" ) );
1632 BOOST_CHECK( PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER::IsBusSignal( "BUS[0..7]" ) );
1633 BOOST_CHECK( PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER::IsBusSignal( "D[31..0]" ) );
1634}
1635
1636
1637BOOST_AUTO_TEST_CASE( IsBusSignal_AngleNotation )
1638{
1639 // Bus notation with angle brackets: NAME<n:m>
1640 BOOST_CHECK( PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER::IsBusSignal( "DATA<7:0>" ) );
1641 BOOST_CHECK( PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER::IsBusSignal( "ADDR<15:0>" ) );
1642 BOOST_CHECK( PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER::IsBusSignal( "BUS<0..7>" ) );
1643}
1644
1645
1646BOOST_AUTO_TEST_CASE( IsBusSignal_NotABus )
1647{
1648 // Regular signal names that should not be detected as buses
1652 BOOST_CHECK( !PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER::IsBusSignal( "NET1" ) );
1653 BOOST_CHECK( !PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER::IsBusSignal( "DATA0" ) );
1655}
1656
1657
1658BOOST_AUTO_TEST_CASE( CreateBusWire_SingleSegment )
1659{
1660 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/simple_schematic.txt";
1661
1663 BOOST_REQUIRE( parser.Parse( testFile ) );
1664
1665 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( parser.GetParameters(), nullptr );
1666
1668 wire.start.x = 1000.0;
1669 wire.start.y = 2000.0;
1670 wire.end.x = 3000.0;
1671 wire.end.y = 2000.0;
1672
1673 SCH_LINE* line = builder.CreateBusWire( wire );
1674 BOOST_REQUIRE( line != nullptr );
1675
1676 BOOST_CHECK( line->GetLayer() == LAYER_BUS );
1677
1678 delete line;
1679}
1680
1681
1682BOOST_AUTO_TEST_CASE( ApplyPartAttributes_Reference )
1683{
1684 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/simple_schematic.txt";
1685
1687 BOOST_REQUIRE( parser.Parse( testFile ) );
1688
1689 // Create a test part placement
1690 PADS_SCH::PART_PLACEMENT placement;
1691 placement.reference = "R1";
1692 placement.part_type = "10K";
1693
1694 // Create a mock schematic for testing
1695 SCHEMATIC schematic( nullptr );
1696 schematic.Reset();
1697
1698 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( parser.GetParameters(), &schematic );
1699
1700 // Create a minimal symbol for testing
1701 LIB_SYMBOL* libSymbol = new LIB_SYMBOL( wxS( "TEST" ) );
1702 LIB_ID libId( wxS( "test" ), wxS( "TEST" ) );
1703
1704 SCH_SYMBOL* symbol = new SCH_SYMBOL( *libSymbol, libId, &schematic.CurrentSheet(), 0 );
1705
1706 builder.ApplyPartAttributes( symbol, placement );
1707
1708 // Verify reference was set
1709 wxString ref = symbol->GetRef( &schematic.CurrentSheet() );
1710 BOOST_CHECK_EQUAL( ref.ToStdString(), "R1" );
1711
1712 // Verify value was set from part_type
1713 BOOST_CHECK_EQUAL( symbol->GetField( FIELD_T::VALUE )->GetText().ToStdString(), "10K" );
1714
1715 delete symbol;
1716 delete libSymbol;
1717}
1718
1719
1720BOOST_AUTO_TEST_CASE( ApplyPartAttributes_Footprint )
1721{
1722 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/simple_schematic.txt";
1723
1725 BOOST_REQUIRE( parser.Parse( testFile ) );
1726
1727 PADS_SCH::PART_PLACEMENT placement;
1728 placement.reference = "C1";
1729 placement.part_type = "100nF";
1730
1731 // Add PCB DECAL attribute for footprint
1732 PADS_SCH::PART_ATTRIBUTE footprintAttr;
1733 footprintAttr.name = "PCB DECAL";
1734 footprintAttr.value = "CAP_0805";
1735 footprintAttr.visible = false;
1736 placement.attributes.push_back( footprintAttr );
1737
1738 SCHEMATIC schematic( nullptr );
1739 schematic.Reset();
1740
1741 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( parser.GetParameters(), &schematic );
1742
1743 LIB_SYMBOL* libSymbol = new LIB_SYMBOL( wxS( "CAP" ) );
1744 LIB_ID libId( wxS( "test" ), wxS( "CAP" ) );
1745
1746 SCH_SYMBOL* symbol = new SCH_SYMBOL( *libSymbol, libId, &schematic.CurrentSheet(), 0 );
1747
1748 builder.ApplyPartAttributes( symbol, placement );
1749
1750 // Verify footprint was set
1751 BOOST_CHECK_EQUAL( symbol->GetField( FIELD_T::FOOTPRINT )->GetText().ToStdString(), "CAP_0805" );
1752
1753 delete symbol;
1754 delete libSymbol;
1755}
1756
1757
1758BOOST_AUTO_TEST_CASE( ApplyFieldSettings_Visibility )
1759{
1760 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/simple_schematic.txt";
1761
1763 BOOST_REQUIRE( parser.Parse( testFile ) );
1764
1765 PADS_SCH::PART_PLACEMENT placement;
1766 placement.reference = "U1";
1767 placement.part_type = "74HC00";
1768
1769 // Add VALUE attribute with visibility=false
1770 PADS_SCH::PART_ATTRIBUTE valueAttr;
1771 valueAttr.name = "VALUE";
1772 valueAttr.value = "74HC00";
1773 valueAttr.visible = false;
1774 placement.attributes.push_back( valueAttr );
1775
1776 // Add REFDES attribute with visibility=true
1778 refAttr.name = "REFDES";
1779 refAttr.value = "U1";
1780 refAttr.visible = true;
1781 placement.attributes.push_back( refAttr );
1782
1783 SCHEMATIC schematic( nullptr );
1784 schematic.Reset();
1785
1786 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( parser.GetParameters(), &schematic );
1787
1788 LIB_SYMBOL* libSymbol = new LIB_SYMBOL( wxS( "74HC00" ) );
1789 LIB_ID libId( wxS( "test" ), wxS( "74HC00" ) );
1790
1791 SCH_SYMBOL* symbol = new SCH_SYMBOL( *libSymbol, libId, &schematic.CurrentSheet(), 0 );
1792
1793 builder.ApplyPartAttributes( symbol, placement );
1794
1795 // Verify visibility settings
1796 BOOST_CHECK( !symbol->GetField( FIELD_T::VALUE )->IsVisible() );
1797 BOOST_CHECK( symbol->GetField( FIELD_T::REFERENCE )->IsVisible() );
1798
1799 delete symbol;
1800 delete libSymbol;
1801}
1802
1803
1804BOOST_AUTO_TEST_CASE( ApplyPartAttributes_NullSymbol )
1805{
1806 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/simple_schematic.txt";
1807
1809 BOOST_REQUIRE( parser.Parse( testFile ) );
1810
1811 PADS_SCH::PART_PLACEMENT placement;
1812 placement.reference = "R1";
1813
1814 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( parser.GetParameters(), nullptr );
1815
1816 // Should not crash when called with nullptr
1817 builder.ApplyPartAttributes( nullptr, placement );
1818
1819 BOOST_CHECK( true ); // If we get here, we passed
1820}
1821
1822
1823BOOST_AUTO_TEST_CASE( CreateCustomFields_ManufacturerAndMPN )
1824{
1825 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/simple_schematic.txt";
1826
1828 BOOST_REQUIRE( parser.Parse( testFile ) );
1829
1830 PADS_SCH::PART_PLACEMENT placement;
1831 placement.reference = "U1";
1832 placement.part_type = "74HC00";
1833
1834 // Add manufacturer attribute (not a standard field)
1836 mfrAttr.name = "Manufacturer";
1837 mfrAttr.value = "Texas Instruments";
1838 mfrAttr.visible = false;
1839 placement.attributes.push_back( mfrAttr );
1840
1841 // Add MPN attribute (not a standard field)
1843 mpnAttr.name = "MPN";
1844 mpnAttr.value = "SN74HC00N";
1845 mpnAttr.visible = false;
1846 placement.attributes.push_back( mpnAttr );
1847
1848 SCHEMATIC schematic( nullptr );
1849 schematic.Reset();
1850
1851 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( parser.GetParameters(), &schematic );
1852
1853 LIB_SYMBOL* libSymbol = new LIB_SYMBOL( wxS( "74HC00" ) );
1854 LIB_ID libId( wxS( "test" ), wxS( "74HC00" ) );
1855
1856 SCH_SYMBOL* symbol = new SCH_SYMBOL( *libSymbol, libId, &schematic.CurrentSheet(), 0 );
1857
1858 int fieldsCreated = builder.CreateCustomFields( symbol, placement );
1859
1860 // Should have created 2 custom fields
1861 BOOST_CHECK_EQUAL( fieldsCreated, 2 );
1862
1863 // Find and verify the manufacturer field
1864 SCH_FIELD* mfrField = symbol->GetField( wxS( "Manufacturer" ) );
1865 BOOST_REQUIRE( mfrField != nullptr );
1866 BOOST_CHECK_EQUAL( mfrField->GetText().ToStdString(), "Texas Instruments" );
1867 BOOST_CHECK( !mfrField->IsVisible() );
1868
1869 // Find and verify the MPN field
1870 SCH_FIELD* mpnField = symbol->GetField( wxS( "MPN" ) );
1871 BOOST_REQUIRE( mpnField != nullptr );
1872 BOOST_CHECK_EQUAL( mpnField->GetText().ToStdString(), "SN74HC00N" );
1873
1874 delete symbol;
1875 delete libSymbol;
1876}
1877
1878
1879BOOST_AUTO_TEST_CASE( CreateCustomFields_SkipsStandardFields )
1880{
1881 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/simple_schematic.txt";
1882
1884 BOOST_REQUIRE( parser.Parse( testFile ) );
1885
1886 PADS_SCH::PART_PLACEMENT placement;
1887 placement.reference = "R1";
1888
1889 // Add standard field attributes (should be skipped by CreateCustomFields)
1891 refAttr.name = "Ref.Des."; // Standard field
1892 refAttr.value = "R1";
1893 placement.attributes.push_back( refAttr );
1894
1896 valAttr.name = "Part Type"; // Standard field
1897 valAttr.value = "10K";
1898 placement.attributes.push_back( valAttr );
1899
1900 // Add one non-standard field
1901 PADS_SCH::PART_ATTRIBUTE customAttr;
1902 customAttr.name = "Tolerance";
1903 customAttr.value = "5%";
1904 customAttr.visible = true;
1905 placement.attributes.push_back( customAttr );
1906
1907 SCHEMATIC schematic( nullptr );
1908 schematic.Reset();
1909
1910 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( parser.GetParameters(), &schematic );
1911
1912 LIB_SYMBOL* libSymbol = new LIB_SYMBOL( wxS( "RES" ) );
1913 LIB_ID libId( wxS( "test" ), wxS( "RES" ) );
1914
1915 SCH_SYMBOL* symbol = new SCH_SYMBOL( *libSymbol, libId, &schematic.CurrentSheet(), 0 );
1916
1917 int fieldsCreated = builder.CreateCustomFields( symbol, placement );
1918
1919 // Should have created only 1 custom field (Tolerance)
1920 BOOST_CHECK_EQUAL( fieldsCreated, 1 );
1921
1922 SCH_FIELD* tolField = symbol->GetField( wxS( "Tolerance" ) );
1923 BOOST_REQUIRE( tolField != nullptr );
1924 BOOST_CHECK_EQUAL( tolField->GetText().ToStdString(), "5%" );
1925 BOOST_CHECK( !tolField->IsVisible() );
1926
1927 delete symbol;
1928 delete libSymbol;
1929}
1930
1931
1932BOOST_AUTO_TEST_CASE( CreateCustomFields_SkipsEmptyValues )
1933{
1934 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/simple_schematic.txt";
1935
1937 BOOST_REQUIRE( parser.Parse( testFile ) );
1938
1939 PADS_SCH::PART_PLACEMENT placement;
1940 placement.reference = "U1";
1941
1942 // Add attribute with empty value
1943 PADS_SCH::PART_ATTRIBUTE emptyAttr;
1944 emptyAttr.name = "SerialNumber";
1945 emptyAttr.value = "";
1946 placement.attributes.push_back( emptyAttr );
1947
1948 // Add attribute with actual value
1949 PADS_SCH::PART_ATTRIBUTE validAttr;
1950 validAttr.name = "Revision";
1951 validAttr.value = "A";
1952 validAttr.visible = true;
1953 placement.attributes.push_back( validAttr );
1954
1955 SCHEMATIC schematic( nullptr );
1956 schematic.Reset();
1957
1958 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( parser.GetParameters(), &schematic );
1959
1960 LIB_SYMBOL* libSymbol = new LIB_SYMBOL( wxS( "IC" ) );
1961 LIB_ID libId( wxS( "test" ), wxS( "IC" ) );
1962
1963 SCH_SYMBOL* symbol = new SCH_SYMBOL( *libSymbol, libId, &schematic.CurrentSheet(), 0 );
1964
1965 int fieldsCreated = builder.CreateCustomFields( symbol, placement );
1966
1967 // Should have created only 1 field (Revision, not empty SerialNumber)
1968 BOOST_CHECK_EQUAL( fieldsCreated, 1 );
1969
1970 // Verify Revision field exists
1971 SCH_FIELD* revField = symbol->GetField( wxS( "Revision" ) );
1972 BOOST_REQUIRE( revField != nullptr );
1973 BOOST_CHECK_EQUAL( revField->GetText().ToStdString(), "A" );
1974
1975 // Verify SerialNumber field was NOT created
1976 SCH_FIELD* snField = symbol->GetField( wxS( "SerialNumber" ) );
1977 BOOST_CHECK( snField == nullptr );
1978
1979 delete symbol;
1980 delete libSymbol;
1981}
1982
1983
1984BOOST_AUTO_TEST_CASE( CreateTitleBlock_AllFields )
1985{
1986 PADS_SCH::PARAMETERS params;
1988 params.fields["Title"] = "Test Design";
1989 params.fields["DATE"] = "2025-01-12";
1990 params.fields["Revision"] = "A";
1991 params.fields["Company Name"] = "Test Company";
1992
1993 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( params, nullptr );
1994
1995 SCH_SCREEN screen;
1996
1997 builder.CreateTitleBlock( &screen );
1998
1999 const TITLE_BLOCK& tb = screen.GetTitleBlock();
2000
2001 BOOST_CHECK_EQUAL( tb.GetTitle().ToStdString(), "Test Design" );
2002 BOOST_CHECK_EQUAL( tb.GetDate().ToStdString(), "2025-01-12" );
2003 BOOST_CHECK_EQUAL( tb.GetRevision().ToStdString(), "A" );
2004 BOOST_CHECK_EQUAL( tb.GetCompany().ToStdString(), "Test Company" );
2005}
2006
2007
2008BOOST_AUTO_TEST_CASE( CreateTitleBlock_JobNameFallback )
2009{
2010 // Create parameters with job_name but no title
2011 PADS_SCH::PARAMETERS params;
2013 params.job_name = "My Project";
2014
2015 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( params, nullptr );
2016
2017 SCH_SCREEN screen;
2018
2019 builder.CreateTitleBlock( &screen );
2020
2021 const TITLE_BLOCK& tb = screen.GetTitleBlock();
2022
2023 // Title should fall back to job_name
2024 BOOST_CHECK_EQUAL( tb.GetTitle().ToStdString(), "My Project" );
2025}
2026
2027
2028BOOST_AUTO_TEST_CASE( CreateTitleBlock_EmptyFields )
2029{
2030 // Create empty parameters
2031 PADS_SCH::PARAMETERS params;
2033
2034 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( params, nullptr );
2035
2036 SCH_SCREEN screen;
2037
2038 builder.CreateTitleBlock( &screen );
2039
2040 const TITLE_BLOCK& tb = screen.GetTitleBlock();
2041
2042 // All fields should be empty
2043 BOOST_CHECK( tb.GetTitle().IsEmpty() );
2044 BOOST_CHECK( tb.GetDate().IsEmpty() );
2045 BOOST_CHECK( tb.GetRevision().IsEmpty() );
2046 BOOST_CHECK( tb.GetCompany().IsEmpty() );
2047}
2048
2049
2050BOOST_AUTO_TEST_CASE( CreateTitleBlock_NullScreen )
2051{
2052 PADS_SCH::PARAMETERS params;
2053 params.fields["Title"] = "Test";
2054
2055 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( params, nullptr );
2056
2057 // Should not crash with nullptr
2058 builder.CreateTitleBlock( nullptr );
2059
2060 BOOST_CHECK( true ); // If we get here, we passed
2061}
2062
2063
2065
2066
2067// Hierarchical sheet tests
2068#include <sch_sheet.h>
2069#include <sch_sheet_path.h>
2070#include <sch_sheet_pin.h>
2071
2072BOOST_AUTO_TEST_SUITE( PadsSchHierarchicalSheets )
2073
2074
2075BOOST_AUTO_TEST_CASE( GetDefaultSheetSize_ReturnsValidSize )
2076{
2077 PADS_SCH::PARAMETERS params;
2079
2080 SCHEMATIC schematic( nullptr );
2081 schematic.Reset();
2082
2083 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( params, &schematic );
2084
2085 VECTOR2I size = builder.GetDefaultSheetSize();
2086
2087 BOOST_CHECK( size.x > 0 );
2088 BOOST_CHECK( size.y > 0 );
2089}
2090
2091
2092BOOST_AUTO_TEST_CASE( CalculateSheetPosition_FirstSheet )
2093{
2094 PADS_SCH::PARAMETERS params;
2096
2097 SCHEMATIC schematic( nullptr );
2098 schematic.Reset();
2099
2100 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( params, &schematic );
2101
2102 VECTOR2I pos = builder.CalculateSheetPosition( 0, 4 );
2103
2104 BOOST_CHECK( pos.x > 0 );
2105 BOOST_CHECK( pos.y > 0 );
2106}
2107
2108
2109BOOST_AUTO_TEST_CASE( CalculateSheetPosition_GridLayout )
2110{
2111 PADS_SCH::PARAMETERS params;
2113
2114 SCHEMATIC schematic( nullptr );
2115 schematic.Reset();
2116
2117 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( params, &schematic );
2118
2119 VECTOR2I pos0 = builder.CalculateSheetPosition( 0, 4 );
2120 VECTOR2I pos1 = builder.CalculateSheetPosition( 1, 4 );
2121 VECTOR2I pos2 = builder.CalculateSheetPosition( 2, 4 );
2122 VECTOR2I pos3 = builder.CalculateSheetPosition( 3, 4 );
2123
2124 // For 4 sheets, should be 2x2 grid
2125 // pos0 and pos1 should be on same row (same Y)
2126 // pos0 and pos2 should be in same column (same X)
2127 BOOST_CHECK_EQUAL( pos0.y, pos1.y );
2128 BOOST_CHECK_EQUAL( pos2.y, pos3.y );
2129 BOOST_CHECK_EQUAL( pos0.x, pos2.x );
2130 BOOST_CHECK_EQUAL( pos1.x, pos3.x );
2131
2132 // Positions should increase going right and down
2133 BOOST_CHECK( pos1.x > pos0.x );
2134 BOOST_CHECK( pos2.y > pos0.y );
2135}
2136
2137
2138BOOST_AUTO_TEST_CASE( CreateHierarchicalSheet_ReturnsValidSheet )
2139{
2140 PADS_SCH::PARAMETERS params;
2142
2143 SCHEMATIC schematic( nullptr );
2144 schematic.Reset();
2145
2146 // Create root sheet
2147 SCH_SHEET* rootSheet = new SCH_SHEET( &schematic );
2148 SCH_SCREEN* rootScreen = new SCH_SCREEN( &schematic );
2149 rootSheet->SetScreen( rootScreen );
2150
2151 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( params, &schematic );
2152
2153 SCH_SHEET* sheet = builder.CreateHierarchicalSheet( 1, 3, rootSheet, wxT( "test_design.txt" ) );
2154 BOOST_REQUIRE( sheet != nullptr );
2155
2156 BOOST_CHECK( sheet->GetScreen() != nullptr );
2157
2158 // Verify sheet has valid position
2159 VECTOR2I pos = sheet->GetPosition();
2160 BOOST_CHECK( pos.x >= 0 );
2161 BOOST_CHECK( pos.y >= 0 );
2162
2163 // Verify sheet has valid size
2164 VECTOR2I size = sheet->GetSize();
2165 BOOST_CHECK( size.x > 0 );
2166 BOOST_CHECK( size.y > 0 );
2167
2168 delete rootSheet;
2169}
2170
2171
2172BOOST_AUTO_TEST_CASE( CreateHierarchicalSheet_SetsFilename )
2173{
2174 PADS_SCH::PARAMETERS params;
2176
2177 SCHEMATIC schematic( nullptr );
2178 schematic.Reset();
2179
2180 SCH_SHEET* rootSheet = new SCH_SHEET( &schematic );
2181 SCH_SCREEN* rootScreen = new SCH_SCREEN( &schematic );
2182 rootSheet->SetScreen( rootScreen );
2183
2184 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( params, &schematic );
2185
2186 SCH_SHEET* sheet = builder.CreateHierarchicalSheet( 2, 3, rootSheet, wxT( "my_design.asc" ) );
2187 BOOST_REQUIRE( sheet != nullptr );
2188
2189 // Verify sheet filename was set
2190 wxString filename = sheet->GetField( FIELD_T::SHEET_FILENAME )->GetText();
2191 BOOST_CHECK( filename.Contains( wxT( "my_design" ) ) );
2192 BOOST_CHECK( filename.Contains( wxT( "sheet2" ) ) );
2193 BOOST_CHECK( filename.EndsWith( wxT( ".kicad_sch" ) ) );
2194
2195 delete rootSheet;
2196}
2197
2198
2199BOOST_AUTO_TEST_CASE( CreateHierarchicalSheet_SetsSheetName )
2200{
2201 PADS_SCH::PARAMETERS params;
2203
2204 SCHEMATIC schematic( nullptr );
2205 schematic.Reset();
2206
2207 SCH_SHEET* rootSheet = new SCH_SHEET( &schematic );
2208 SCH_SCREEN* rootScreen = new SCH_SCREEN( &schematic );
2209 rootSheet->SetScreen( rootScreen );
2210
2211 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( params, &schematic );
2212
2213 SCH_SHEET* sheet = builder.CreateHierarchicalSheet( 3, 5, rootSheet, wxT( "design.txt" ) );
2214 BOOST_REQUIRE( sheet != nullptr );
2215
2216 // Verify sheet name was set
2217 wxString name = sheet->GetField( FIELD_T::SHEET_NAME )->GetText();
2218 BOOST_CHECK( name.Contains( wxT( "3" ) ) );
2219
2220 delete rootSheet;
2221}
2222
2223
2224BOOST_AUTO_TEST_CASE( CreateHierarchicalSheet_NullParent )
2225{
2226 PADS_SCH::PARAMETERS params;
2228
2229 SCHEMATIC schematic( nullptr );
2230 schematic.Reset();
2231
2232 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( params, &schematic );
2233
2234 // Should return nullptr when parent is null
2235 SCH_SHEET* sheet = builder.CreateHierarchicalSheet( 1, 3, nullptr, wxT( "test.txt" ) );
2236 BOOST_CHECK( sheet == nullptr );
2237}
2238
2239
2240BOOST_AUTO_TEST_CASE( CreateSheetPin_ValidPin )
2241{
2242 PADS_SCH::PARAMETERS params;
2244
2245 SCHEMATIC schematic( nullptr );
2246 schematic.Reset();
2247
2248 SCH_SHEET* sheet = new SCH_SHEET( &schematic );
2249 sheet->SetPosition( VECTOR2I( 1000, 2000 ) );
2250 sheet->SetSize( VECTOR2I( 3000, 2000 ) );
2251
2252 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( params, &schematic );
2253
2254 SCH_SHEET_PIN* pin = builder.CreateSheetPin( sheet, "NET1", 0 );
2255 BOOST_REQUIRE( pin != nullptr );
2256
2257 BOOST_CHECK_EQUAL( pin->GetText().ToStdString(), "NET1" );
2258 BOOST_CHECK( pin->GetSide() == SHEET_SIDE::LEFT );
2259
2260 delete sheet;
2261}
2262
2263
2264BOOST_AUTO_TEST_CASE( CreateSheetPin_PreservesName )
2265{
2266 PADS_SCH::PARAMETERS params;
2268
2269 SCHEMATIC schematic( nullptr );
2270 schematic.Reset();
2271
2272 SCH_SHEET* sheet = new SCH_SHEET( &schematic );
2273
2274 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( params, &schematic );
2275
2276 SCH_SHEET_PIN* pin = builder.CreateSheetPin( sheet, "NET 1", 0 );
2277 BOOST_REQUIRE( pin != nullptr );
2278
2279 // Net names pass through unchanged; KiCad handles arbitrary UTF-8 net names
2280 BOOST_CHECK_EQUAL( pin->GetText().ToStdString(), "NET 1" );
2281
2282 delete sheet;
2283}
2284
2285
2286BOOST_AUTO_TEST_CASE( CreateSheetPin_NullSheet )
2287{
2288 PADS_SCH::PARAMETERS params;
2290
2291 SCHEMATIC schematic( nullptr );
2292 schematic.Reset();
2293
2294 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( params, &schematic );
2295
2296 SCH_SHEET_PIN* pin = builder.CreateSheetPin( nullptr, "NET1", 0 );
2297 BOOST_CHECK( pin == nullptr );
2298}
2299
2300
2301BOOST_AUTO_TEST_CASE( CreateHierLabel_ValidLabel )
2302{
2303 PADS_SCH::PARAMETERS params;
2305
2306 SCHEMATIC schematic( nullptr );
2307 schematic.Reset();
2308
2309 SCH_SCREEN screen;
2310
2311 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( params, &schematic );
2312
2313 VECTOR2I pos( 1000, 2000 );
2314 SCH_HIERLABEL* label = builder.CreateHierLabel( "DATA_OUT", pos, &screen );
2315 BOOST_REQUIRE( label != nullptr );
2316
2317 BOOST_CHECK_EQUAL( label->GetText().ToStdString(), "DATA_OUT" );
2318
2319 // Label should be added to screen
2320 BOOST_CHECK( screen.Items().size() > 0 );
2321}
2322
2323
2324
2325BOOST_AUTO_TEST_CASE( IsGlobalSignal_PowerNets )
2326{
2327 std::set<int> singleSheet = { 1 };
2328
2329 BOOST_CHECK( PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER::IsGlobalSignal( "VCC", singleSheet ) );
2330 BOOST_CHECK( PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER::IsGlobalSignal( "GND", singleSheet ) );
2331 BOOST_CHECK( PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER::IsGlobalSignal( "vcc", singleSheet ) );
2332 BOOST_CHECK( PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER::IsGlobalSignal( "AGND", singleSheet ) );
2333 BOOST_CHECK( PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER::IsGlobalSignal( "+5V", singleSheet ) );
2334 BOOST_CHECK( PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER::IsGlobalSignal( "+3V3", singleSheet ) );
2335 BOOST_CHECK( PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER::IsGlobalSignal( "-12V", singleSheet ) );
2336}
2337
2338
2339BOOST_AUTO_TEST_CASE( IsGlobalSignal_MultiSheet )
2340{
2341 std::set<int> multiSheet = { 1, 2, 3 };
2342
2343 // Any signal on multiple sheets should be global
2344 BOOST_CHECK( PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER::IsGlobalSignal( "DATA_BUS", multiSheet ) );
2345 BOOST_CHECK( PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER::IsGlobalSignal( "RANDOM_NET", multiSheet ) );
2346}
2347
2348
2349BOOST_AUTO_TEST_CASE( IsGlobalSignal_NotGlobal )
2350{
2351 std::set<int> singleSheet = { 1 };
2352
2353 BOOST_CHECK( !PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER::IsGlobalSignal( "NET1", singleSheet ) );
2354 BOOST_CHECK( !PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER::IsGlobalSignal( "DATA", singleSheet ) );
2355 BOOST_CHECK( !PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER::IsGlobalSignal( "CLK", singleSheet ) );
2356 BOOST_CHECK( !PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER::IsGlobalSignal( "", singleSheet ) );
2357}
2358
2359
const char * name
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition eda_text.h:98
virtual bool IsVisible() const
Definition eda_text.h:187
size_t size() const
Return the number of items in the tree.
Definition sch_rtree.h:174
A logical library item identifier and consists of various portions much like a URI.
Definition lib_id.h:49
Define a library symbol object.
Definition lib_symbol.h:83
LIB_ITEMS_CONTAINER & GetDrawItems()
Return a reference to the draw item list.
Definition lib_symbol.h:712
wxString GetName() const override
Definition lib_symbol.h:145
std::vector< SCH_PIN * > GetPins() const override
int GetUnitCount() const override
Parser for PADS Logic schematic design export files.
bool Parse(const std::string &aFileName)
const std::vector< SCH_SIGNAL > & GetSignals() const
const FILE_HEADER & GetHeader() const
std::vector< SCH_SIGNAL > GetSignalsOnSheet(int aSheetNumber) const
std::set< int > GetSheetNumbers() const
static bool CheckFileHeader(const std::string &aFileName)
const std::vector< SYMBOL_DEF > & GetSymbolDefs() const
const std::vector< PART_PLACEMENT > & GetPartPlacements() const
const std::map< std::string, PARTTYPE_DEF > & GetPartTypes() const
std::vector< PART_PLACEMENT > GetPartsOnSheet(int aSheetNumber) const
const SCH_SIGNAL * GetSignal(const std::string &aName) const
const SYMBOL_DEF * GetSymbolDef(const std::string &aName) const
const PARAMETERS & GetParameters() const
const PART_PLACEMENT * GetPartPlacement(const std::string &aReference) const
std::string GetVersion() const
Builder class to create KiCad schematic elements from parsed PADS data.
SCH_LINE * CreateWire(const WIRE_SEGMENT &aWire)
Create a single wire segment.
SCH_SHEET_PIN * CreateSheetPin(SCH_SHEET *aSheet, const std::string &aSignalName, int aPinIndex)
Create hierarchical sheet pin on a sheet symbol.
void ApplyPartAttributes(SCH_SYMBOL *aSymbol, const PART_PLACEMENT &aPlacement)
Apply part attributes to a symbol instance.
void CreateTitleBlock(SCH_SCREEN *aScreen)
Create title block from parsed PADS parameters.
VECTOR2I CalculateSheetPosition(int aSheetIndex, int aTotalSheets) const
Calculate position for a sheet symbol on the parent sheet.
int CreateCustomFields(SCH_SYMBOL *aSymbol, const PART_PLACEMENT &aPlacement)
Create custom fields from non-standard PADS attributes.
SCH_LINE * CreateBusWire(const WIRE_SEGMENT &aWire)
Create a single bus wire segment.
SCH_HIERLABEL * CreateHierLabel(const std::string &aSignalName, const VECTOR2I &aPosition, SCH_SCREEN *aScreen)
Create hierarchical label in a sub-schematic.
SCH_GLOBALLABEL * CreateNetLabel(const SCH_SIGNAL &aSignal, const VECTOR2I &aPosition, SPIN_STYLE aOrientation=SPIN_STYLE::RIGHT)
Create a global net label for a signal.
static bool IsGlobalSignal(const std::string &aSignalName, const std::set< int > &aSheetNumbers)
Check if a signal name represents a global signal.
SCH_SHEET * CreateHierarchicalSheet(int aSheetNumber, int aTotalSheets, SCH_SHEET *aParentSheet, const wxString &aBaseFilename)
Create hierarchical sheet for a sub-schematic page.
VECTOR2I GetDefaultSheetSize() const
Get standard sheet size for a given sheet number.
static bool IsBusSignal(const std::string &aName)
Check if a signal name indicates a bus.
Builder class to convert PADS symbol definitions to KiCad LIB_SYMBOL objects.
LIB_SYMBOL * BuildMultiUnitSymbol(const PARTTYPE_DEF &aPartType, const std::vector< SYMBOL_DEF > &aSymbolDefs)
Build a composite multi-unit LIB_SYMBOL from a multi-gate PARTTYPE.
bool HasSymbol(const std::string &aName) const
Check if a symbol with the given name already exists.
static std::optional< LIB_ID > GetKiCadPowerSymbolId(const std::string &aPadsName)
Get KiCad power library symbol ID for a PADS power symbol.
LIB_SYMBOL * BuildKiCadPowerSymbol(const std::string &aKiCadName)
Build a power symbol using hard-coded KiCad-standard graphics.
static bool IsPowerSymbol(const std::string &aName)
Check if a symbol name indicates a power symbol.
LIB_SYMBOL * GetOrCreateSymbol(const SYMBOL_DEF &aSymbolDef)
Get or create a symbol for the given definition.
LIB_SYMBOL * GetOrCreateConnectorPinSymbol(const PARTTYPE_DEF &aPartType, const SYMBOL_DEF &aSymbolDef, const std::string &aPinNumber)
Get or create a single-pin connector symbol with a specific pin number.
LIB_SYMBOL * GetOrCreateMultiUnitConnectorSymbol(const PARTTYPE_DEF &aPartType, const SYMBOL_DEF &aSymbolDef, const std::vector< std::string > &aPinNumbers, const std::string &aCacheKey)
Get or create a multi-unit connector symbol, cached by base reference.
LIB_SYMBOL * BuildSymbol(const SYMBOL_DEF &aSymbolDef)
Build a KiCad LIB_SYMBOL from a PADS symbol definition.
Holds all the data relating to one schematic.
Definition schematic.h:88
void Reset()
Initialize this schematic to a blank one, unloading anything existing.
SCH_SHEET_PATH & CurrentSheet() const
Definition schematic.h:187
virtual const wxString & GetText() const override
Return the string associated with the text object.
Definition sch_field.h:116
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:168
SCH_LAYER_ID GetLayer() const
Return the layer this item is on.
Definition sch_item.h:341
Segment description base class to describe items which have 2 end points (track, wire,...
Definition sch_line.h:42
VECTOR2I GetEndPoint() const
Definition sch_line.h:148
VECTOR2I GetStartPoint() const
Definition sch_line.h:139
const wxString & GetNumber() const
Definition sch_pin.h:124
ELECTRICAL_PINTYPE GetType() const
Definition sch_pin.cpp:315
EE_RTREE & Items()
Get the full RTree, usually for iterating.
Definition sch_screen.h:119
const TITLE_BLOCK & GetTitleBlock() const
Definition sch_screen.h:165
Define a sheet pin (label) used in sheets to create hierarchical schematics.
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition sch_sheet.h:48
void SetSize(const VECTOR2I &aSize)
Definition sch_sheet.h:143
SCH_FIELD * GetField(FIELD_T aFieldType)
Return a mandatory field in this sheet.
void SetPosition(const VECTOR2I &aPosition) override
VECTOR2I GetSize() const
Definition sch_sheet.h:142
SCH_SCREEN * GetScreen() const
Definition sch_sheet.h:140
VECTOR2I GetPosition() const override
Definition sch_sheet.h:491
void SetScreen(SCH_SCREEN *aScreen)
Set the SCH_SCREEN associated with this sheet to aScreen.
Schematic symbol object.
Definition sch_symbol.h:76
const wxString GetRef(const SCH_SHEET_PATH *aSheet, bool aIncludeUnit=false) const override
SCH_FIELD * GetField(FIELD_T aFieldType)
Return a mandatory field in this symbol.
Hold the information shown in the lower right corner of a plot, printout, or editing view.
Definition title_block.h:41
const wxString & GetCompany() const
Definition title_block.h:96
const wxString & GetRevision() const
Definition title_block.h:86
const wxString & GetDate() const
Definition title_block.h:76
const wxString & GetTitle() const
Definition title_block.h:63
@ LAYER_WIRE
Definition layer_ids.h:452
@ LAYER_BUS
Definition layer_ids.h:453
std::string GetEeschemaTestDataDir()
Get the configured location of Eeschema test data.
@ PT_UNSPECIFIED
unknown electrical properties: creates always a warning when connected
Definition pin_type.h:45
Definition of the SCH_SHEET_PATH and SCH_SHEET_LIST classes for Eeschema.
Gate definition within a PARTTYPE.
std::vector< std::string > decal_names
std::vector< PARTTYPE_PIN > pins
General schematic parameters from SCH and FIELDS sections.
std::map< std::string, std::string > fields
Part type definition from PARTTYPE section.
std::vector< GATE_DEF > gates
std::vector< SPECIAL_VARIANT > special_variants
std::vector< SIGPIN > sigpins
Pin definition within a PARTTYPE GATE.
Part instance from PART section.
std::vector< PART_ATTRIBUTE > attributes
Signal (net) definition from CONNECTION and SIGNAL sections.
std::vector< PIN_CONNECTION > connections
std::vector< WIRE_SEGMENT > wires
Symbol definition from CAEDECAL section.
std::vector< SYMBOL_GRAPHIC > graphics
std::vector< SYMBOL_PIN > pins
std::vector< CAEDECAL_ATTR > attrs
Pin T/P line pair from CAEDECAL.
Wire segment connecting two endpoints through coordinate vertices.
@ FOOTPRINT
Field Name Module PCB, i.e. "16DIP300".
@ REFERENCE
Field Reference of part, i.e. "IC21".
@ VALUE
Field Value of part, i.e. "3.3K".
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_AUTO_TEST_SUITE(CadstarPartParser)
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_AUTO_TEST_SUITE_END()
KIBIS_PIN * pin
VECTOR3I res
BOOST_AUTO_TEST_CASE(CheckFileHeader_ValidLogicFile)
SHAPE_CIRCLE circle(c.m_circle_center, c.m_circle_radius)
BOOST_TEST_MESSAGE("Polyline has "<< chain.PointCount()<< " points")
BOOST_CHECK_EQUAL(result, "25.4")
VECTOR2I v5(-70, -70)
@ SCH_SHAPE_T
Definition typeinfo.h:153
@ SCH_PIN_T
Definition typeinfo.h:157
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695