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
1160
1161
1162// Schematic Builder tests
1163#include <sch_io/pads/pads_sch_schematic_builder.h>
1165#include <sch_line.h>
1166#include <sch_label.h>
1167#include <sch_junction.h>
1168#include <sch_symbol.h>
1169#include <sch_screen.h>
1170#include <schematic.h>
1171#include <template_fieldnames.h>
1172#include <title_block.h>
1173
1174BOOST_AUTO_TEST_SUITE( PadsSchSchematicBuilder )
1175
1176
1177BOOST_AUTO_TEST_CASE( CreateWire_SingleSegment )
1178{
1179 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/simple_schematic.txt";
1180
1182 BOOST_REQUIRE( parser.Parse( testFile ) );
1183
1184 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( parser.GetParameters(), nullptr );
1185
1187 wire.start.x = 1000.0;
1188 wire.start.y = 2000.0;
1189 wire.end.x = 3000.0;
1190 wire.end.y = 2000.0;
1191
1192 SCH_LINE* line = builder.CreateWire( wire );
1193 BOOST_REQUIRE( line != nullptr );
1194
1195 BOOST_CHECK( line->GetLayer() == LAYER_WIRE );
1196 BOOST_CHECK( line->GetStartPoint().x != 0 || line->GetStartPoint().y != 0 );
1197 BOOST_CHECK( line->GetEndPoint().x != 0 || line->GetEndPoint().y != 0 );
1198
1199 delete line;
1200}
1201
1202
1203BOOST_AUTO_TEST_CASE( CreateWire_FromSignals )
1204{
1205 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/signals_schematic.txt";
1206
1208 BOOST_REQUIRE( parser.Parse( testFile ) );
1209
1210 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( parser.GetParameters(), nullptr );
1211
1212 // Count total expected wires
1213 int expectedWires = 0;
1214
1215 for( const auto& signal : parser.GetSignals() )
1216 expectedWires += static_cast<int>( signal.wires.size() );
1217
1218 BOOST_CHECK( expectedWires > 0 );
1219}
1220
1221
1222BOOST_AUTO_TEST_CASE( CreateNetLabel_FromSignal )
1223{
1224 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/simple_schematic.txt";
1225
1227 BOOST_REQUIRE( parser.Parse( testFile ) );
1228
1229 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( parser.GetParameters(), nullptr );
1230
1231 PADS_SCH::SCH_SIGNAL signal;
1232 signal.name = "VCC";
1233
1235 wire.start.x = 1000.0;
1236 wire.start.y = 2000.0;
1237 wire.end.x = 3000.0;
1238 wire.end.y = 2000.0;
1239 signal.wires.push_back( wire );
1240
1241 VECTOR2I pos( 1000, 2000 );
1242 SCH_GLOBALLABEL* label = builder.CreateNetLabel( signal, pos );
1243 BOOST_REQUIRE( label != nullptr );
1244
1245 BOOST_CHECK_EQUAL( label->GetText(), "VCC" );
1246
1247 delete label;
1248}
1249
1250
1251BOOST_AUTO_TEST_CASE( CreateNetLabel_PreservesSpecialChars )
1252{
1253 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/simple_schematic.txt";
1254
1256 BOOST_REQUIRE( parser.Parse( testFile ) );
1257
1258 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( parser.GetParameters(), nullptr );
1259
1260 PADS_SCH::SCH_SIGNAL signal;
1261 signal.name = "NET 1";
1262
1263 VECTOR2I pos( 1000, 2000 );
1264 SCH_GLOBALLABEL* label = builder.CreateNetLabel( signal, pos );
1265 BOOST_REQUIRE( label != nullptr );
1266
1267 // Net names pass through unchanged; KiCad handles arbitrary UTF-8 net names
1268 BOOST_CHECK_EQUAL( label->GetText(), "NET 1" );
1269
1270 delete label;
1271}
1272
1273
1274BOOST_AUTO_TEST_CASE( IsBusSignal_BracketNotation )
1275{
1276 // Bus notation with brackets: NAME[n:m] or NAME[n..m]
1277 BOOST_CHECK( PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER::IsBusSignal( "DATA[7:0]" ) );
1278 BOOST_CHECK( PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER::IsBusSignal( "ADDR[15:0]" ) );
1279 BOOST_CHECK( PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER::IsBusSignal( "BUS[0..7]" ) );
1280 BOOST_CHECK( PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER::IsBusSignal( "D[31..0]" ) );
1281}
1282
1283
1284BOOST_AUTO_TEST_CASE( IsBusSignal_AngleNotation )
1285{
1286 // Bus notation with angle brackets: NAME<n:m>
1287 BOOST_CHECK( PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER::IsBusSignal( "DATA<7:0>" ) );
1288 BOOST_CHECK( PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER::IsBusSignal( "ADDR<15:0>" ) );
1289 BOOST_CHECK( PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER::IsBusSignal( "BUS<0..7>" ) );
1290}
1291
1292
1293BOOST_AUTO_TEST_CASE( IsBusSignal_NotABus )
1294{
1295 // Regular signal names that should not be detected as buses
1299 BOOST_CHECK( !PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER::IsBusSignal( "NET1" ) );
1300 BOOST_CHECK( !PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER::IsBusSignal( "DATA0" ) );
1302}
1303
1304
1305BOOST_AUTO_TEST_CASE( CreateBusWire_SingleSegment )
1306{
1307 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/simple_schematic.txt";
1308
1310 BOOST_REQUIRE( parser.Parse( testFile ) );
1311
1312 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( parser.GetParameters(), nullptr );
1313
1315 wire.start.x = 1000.0;
1316 wire.start.y = 2000.0;
1317 wire.end.x = 3000.0;
1318 wire.end.y = 2000.0;
1319
1320 SCH_LINE* line = builder.CreateBusWire( wire );
1321 BOOST_REQUIRE( line != nullptr );
1322
1323 BOOST_CHECK( line->GetLayer() == LAYER_BUS );
1324
1325 delete line;
1326}
1327
1328
1329BOOST_AUTO_TEST_CASE( ApplyPartAttributes_Reference )
1330{
1331 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/simple_schematic.txt";
1332
1334 BOOST_REQUIRE( parser.Parse( testFile ) );
1335
1336 // Create a test part placement
1337 PADS_SCH::PART_PLACEMENT placement;
1338 placement.reference = "R1";
1339 placement.part_type = "10K";
1340
1341 // Create a mock schematic for testing
1342 SCHEMATIC schematic( nullptr );
1343 schematic.Reset();
1344
1345 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( parser.GetParameters(), &schematic );
1346
1347 // Create a minimal symbol for testing
1348 LIB_SYMBOL* libSymbol = new LIB_SYMBOL( wxS( "TEST" ) );
1349 LIB_ID libId( wxS( "test" ), wxS( "TEST" ) );
1350
1351 SCH_SYMBOL* symbol = new SCH_SYMBOL( *libSymbol, libId, &schematic.CurrentSheet(), 0 );
1352
1353 builder.ApplyPartAttributes( symbol, placement );
1354
1355 // Verify reference was set
1356 wxString ref = symbol->GetRef( &schematic.CurrentSheet() );
1357 BOOST_CHECK_EQUAL( ref.ToStdString(), "R1" );
1358
1359 // Verify value was set from part_type
1360 BOOST_CHECK_EQUAL( symbol->GetField( FIELD_T::VALUE )->GetText().ToStdString(), "10K" );
1361
1362 delete symbol;
1363 delete libSymbol;
1364}
1365
1366
1367BOOST_AUTO_TEST_CASE( ApplyPartAttributes_Footprint )
1368{
1369 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/simple_schematic.txt";
1370
1372 BOOST_REQUIRE( parser.Parse( testFile ) );
1373
1374 PADS_SCH::PART_PLACEMENT placement;
1375 placement.reference = "C1";
1376 placement.part_type = "100nF";
1377
1378 // Add PCB DECAL attribute for footprint
1379 PADS_SCH::PART_ATTRIBUTE footprintAttr;
1380 footprintAttr.name = "PCB DECAL";
1381 footprintAttr.value = "CAP_0805";
1382 footprintAttr.visible = false;
1383 placement.attributes.push_back( footprintAttr );
1384
1385 SCHEMATIC schematic( nullptr );
1386 schematic.Reset();
1387
1388 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( parser.GetParameters(), &schematic );
1389
1390 LIB_SYMBOL* libSymbol = new LIB_SYMBOL( wxS( "CAP" ) );
1391 LIB_ID libId( wxS( "test" ), wxS( "CAP" ) );
1392
1393 SCH_SYMBOL* symbol = new SCH_SYMBOL( *libSymbol, libId, &schematic.CurrentSheet(), 0 );
1394
1395 builder.ApplyPartAttributes( symbol, placement );
1396
1397 // Verify footprint was set
1398 BOOST_CHECK_EQUAL( symbol->GetField( FIELD_T::FOOTPRINT )->GetText().ToStdString(), "CAP_0805" );
1399
1400 delete symbol;
1401 delete libSymbol;
1402}
1403
1404
1405BOOST_AUTO_TEST_CASE( ApplyFieldSettings_Visibility )
1406{
1407 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/simple_schematic.txt";
1408
1410 BOOST_REQUIRE( parser.Parse( testFile ) );
1411
1412 PADS_SCH::PART_PLACEMENT placement;
1413 placement.reference = "U1";
1414 placement.part_type = "74HC00";
1415
1416 // Add VALUE attribute with visibility=false
1417 PADS_SCH::PART_ATTRIBUTE valueAttr;
1418 valueAttr.name = "VALUE";
1419 valueAttr.value = "74HC00";
1420 valueAttr.visible = false;
1421 placement.attributes.push_back( valueAttr );
1422
1423 // Add REFDES attribute with visibility=true
1425 refAttr.name = "REFDES";
1426 refAttr.value = "U1";
1427 refAttr.visible = true;
1428 placement.attributes.push_back( refAttr );
1429
1430 SCHEMATIC schematic( nullptr );
1431 schematic.Reset();
1432
1433 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( parser.GetParameters(), &schematic );
1434
1435 LIB_SYMBOL* libSymbol = new LIB_SYMBOL( wxS( "74HC00" ) );
1436 LIB_ID libId( wxS( "test" ), wxS( "74HC00" ) );
1437
1438 SCH_SYMBOL* symbol = new SCH_SYMBOL( *libSymbol, libId, &schematic.CurrentSheet(), 0 );
1439
1440 builder.ApplyPartAttributes( symbol, placement );
1441
1442 // Verify visibility settings
1443 BOOST_CHECK( !symbol->GetField( FIELD_T::VALUE )->IsVisible() );
1444 BOOST_CHECK( symbol->GetField( FIELD_T::REFERENCE )->IsVisible() );
1445
1446 delete symbol;
1447 delete libSymbol;
1448}
1449
1450
1451BOOST_AUTO_TEST_CASE( ApplyPartAttributes_NullSymbol )
1452{
1453 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/simple_schematic.txt";
1454
1456 BOOST_REQUIRE( parser.Parse( testFile ) );
1457
1458 PADS_SCH::PART_PLACEMENT placement;
1459 placement.reference = "R1";
1460
1461 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( parser.GetParameters(), nullptr );
1462
1463 // Should not crash when called with nullptr
1464 builder.ApplyPartAttributes( nullptr, placement );
1465
1466 BOOST_CHECK( true ); // If we get here, we passed
1467}
1468
1469
1470BOOST_AUTO_TEST_CASE( CreateCustomFields_ManufacturerAndMPN )
1471{
1472 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/simple_schematic.txt";
1473
1475 BOOST_REQUIRE( parser.Parse( testFile ) );
1476
1477 PADS_SCH::PART_PLACEMENT placement;
1478 placement.reference = "U1";
1479 placement.part_type = "74HC00";
1480
1481 // Add manufacturer attribute (not a standard field)
1483 mfrAttr.name = "Manufacturer";
1484 mfrAttr.value = "Texas Instruments";
1485 mfrAttr.visible = false;
1486 placement.attributes.push_back( mfrAttr );
1487
1488 // Add MPN attribute (not a standard field)
1490 mpnAttr.name = "MPN";
1491 mpnAttr.value = "SN74HC00N";
1492 mpnAttr.visible = false;
1493 placement.attributes.push_back( mpnAttr );
1494
1495 SCHEMATIC schematic( nullptr );
1496 schematic.Reset();
1497
1498 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( parser.GetParameters(), &schematic );
1499
1500 LIB_SYMBOL* libSymbol = new LIB_SYMBOL( wxS( "74HC00" ) );
1501 LIB_ID libId( wxS( "test" ), wxS( "74HC00" ) );
1502
1503 SCH_SYMBOL* symbol = new SCH_SYMBOL( *libSymbol, libId, &schematic.CurrentSheet(), 0 );
1504
1505 int fieldsCreated = builder.CreateCustomFields( symbol, placement );
1506
1507 // Should have created 2 custom fields
1508 BOOST_CHECK_EQUAL( fieldsCreated, 2 );
1509
1510 // Find and verify the manufacturer field
1511 SCH_FIELD* mfrField = symbol->GetField( wxS( "Manufacturer" ) );
1512 BOOST_REQUIRE( mfrField != nullptr );
1513 BOOST_CHECK_EQUAL( mfrField->GetText().ToStdString(), "Texas Instruments" );
1514 BOOST_CHECK( !mfrField->IsVisible() );
1515
1516 // Find and verify the MPN field
1517 SCH_FIELD* mpnField = symbol->GetField( wxS( "MPN" ) );
1518 BOOST_REQUIRE( mpnField != nullptr );
1519 BOOST_CHECK_EQUAL( mpnField->GetText().ToStdString(), "SN74HC00N" );
1520
1521 delete symbol;
1522 delete libSymbol;
1523}
1524
1525
1526BOOST_AUTO_TEST_CASE( CreateCustomFields_SkipsStandardFields )
1527{
1528 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/simple_schematic.txt";
1529
1531 BOOST_REQUIRE( parser.Parse( testFile ) );
1532
1533 PADS_SCH::PART_PLACEMENT placement;
1534 placement.reference = "R1";
1535
1536 // Add standard field attributes (should be skipped by CreateCustomFields)
1538 refAttr.name = "Ref.Des."; // Standard field
1539 refAttr.value = "R1";
1540 placement.attributes.push_back( refAttr );
1541
1543 valAttr.name = "Part Type"; // Standard field
1544 valAttr.value = "10K";
1545 placement.attributes.push_back( valAttr );
1546
1547 // Add one non-standard field
1548 PADS_SCH::PART_ATTRIBUTE customAttr;
1549 customAttr.name = "Tolerance";
1550 customAttr.value = "5%";
1551 customAttr.visible = true;
1552 placement.attributes.push_back( customAttr );
1553
1554 SCHEMATIC schematic( nullptr );
1555 schematic.Reset();
1556
1557 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( parser.GetParameters(), &schematic );
1558
1559 LIB_SYMBOL* libSymbol = new LIB_SYMBOL( wxS( "RES" ) );
1560 LIB_ID libId( wxS( "test" ), wxS( "RES" ) );
1561
1562 SCH_SYMBOL* symbol = new SCH_SYMBOL( *libSymbol, libId, &schematic.CurrentSheet(), 0 );
1563
1564 int fieldsCreated = builder.CreateCustomFields( symbol, placement );
1565
1566 // Should have created only 1 custom field (Tolerance)
1567 BOOST_CHECK_EQUAL( fieldsCreated, 1 );
1568
1569 SCH_FIELD* tolField = symbol->GetField( wxS( "Tolerance" ) );
1570 BOOST_REQUIRE( tolField != nullptr );
1571 BOOST_CHECK_EQUAL( tolField->GetText().ToStdString(), "5%" );
1572 BOOST_CHECK( !tolField->IsVisible() );
1573
1574 delete symbol;
1575 delete libSymbol;
1576}
1577
1578
1579BOOST_AUTO_TEST_CASE( CreateCustomFields_SkipsEmptyValues )
1580{
1581 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/simple_schematic.txt";
1582
1584 BOOST_REQUIRE( parser.Parse( testFile ) );
1585
1586 PADS_SCH::PART_PLACEMENT placement;
1587 placement.reference = "U1";
1588
1589 // Add attribute with empty value
1590 PADS_SCH::PART_ATTRIBUTE emptyAttr;
1591 emptyAttr.name = "SerialNumber";
1592 emptyAttr.value = "";
1593 placement.attributes.push_back( emptyAttr );
1594
1595 // Add attribute with actual value
1596 PADS_SCH::PART_ATTRIBUTE validAttr;
1597 validAttr.name = "Revision";
1598 validAttr.value = "A";
1599 validAttr.visible = true;
1600 placement.attributes.push_back( validAttr );
1601
1602 SCHEMATIC schematic( nullptr );
1603 schematic.Reset();
1604
1605 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( parser.GetParameters(), &schematic );
1606
1607 LIB_SYMBOL* libSymbol = new LIB_SYMBOL( wxS( "IC" ) );
1608 LIB_ID libId( wxS( "test" ), wxS( "IC" ) );
1609
1610 SCH_SYMBOL* symbol = new SCH_SYMBOL( *libSymbol, libId, &schematic.CurrentSheet(), 0 );
1611
1612 int fieldsCreated = builder.CreateCustomFields( symbol, placement );
1613
1614 // Should have created only 1 field (Revision, not empty SerialNumber)
1615 BOOST_CHECK_EQUAL( fieldsCreated, 1 );
1616
1617 // Verify Revision field exists
1618 SCH_FIELD* revField = symbol->GetField( wxS( "Revision" ) );
1619 BOOST_REQUIRE( revField != nullptr );
1620 BOOST_CHECK_EQUAL( revField->GetText().ToStdString(), "A" );
1621
1622 // Verify SerialNumber field was NOT created
1623 SCH_FIELD* snField = symbol->GetField( wxS( "SerialNumber" ) );
1624 BOOST_CHECK( snField == nullptr );
1625
1626 delete symbol;
1627 delete libSymbol;
1628}
1629
1630
1631BOOST_AUTO_TEST_CASE( CreateTitleBlock_AllFields )
1632{
1633 PADS_SCH::PARAMETERS params;
1635 params.fields["Title"] = "Test Design";
1636 params.fields["DATE"] = "2025-01-12";
1637 params.fields["Revision"] = "A";
1638 params.fields["Company Name"] = "Test Company";
1639
1640 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( params, nullptr );
1641
1642 SCH_SCREEN screen;
1643
1644 builder.CreateTitleBlock( &screen );
1645
1646 const TITLE_BLOCK& tb = screen.GetTitleBlock();
1647
1648 BOOST_CHECK_EQUAL( tb.GetTitle().ToStdString(), "Test Design" );
1649 BOOST_CHECK_EQUAL( tb.GetDate().ToStdString(), "2025-01-12" );
1650 BOOST_CHECK_EQUAL( tb.GetRevision().ToStdString(), "A" );
1651 BOOST_CHECK_EQUAL( tb.GetCompany().ToStdString(), "Test Company" );
1652}
1653
1654
1655BOOST_AUTO_TEST_CASE( CreateTitleBlock_JobNameFallback )
1656{
1657 // Create parameters with job_name but no title
1658 PADS_SCH::PARAMETERS params;
1660 params.job_name = "My Project";
1661
1662 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( params, nullptr );
1663
1664 SCH_SCREEN screen;
1665
1666 builder.CreateTitleBlock( &screen );
1667
1668 const TITLE_BLOCK& tb = screen.GetTitleBlock();
1669
1670 // Title should fall back to job_name
1671 BOOST_CHECK_EQUAL( tb.GetTitle().ToStdString(), "My Project" );
1672}
1673
1674
1675BOOST_AUTO_TEST_CASE( CreateTitleBlock_EmptyFields )
1676{
1677 // Create empty parameters
1678 PADS_SCH::PARAMETERS params;
1680
1681 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( params, nullptr );
1682
1683 SCH_SCREEN screen;
1684
1685 builder.CreateTitleBlock( &screen );
1686
1687 const TITLE_BLOCK& tb = screen.GetTitleBlock();
1688
1689 // All fields should be empty
1690 BOOST_CHECK( tb.GetTitle().IsEmpty() );
1691 BOOST_CHECK( tb.GetDate().IsEmpty() );
1692 BOOST_CHECK( tb.GetRevision().IsEmpty() );
1693 BOOST_CHECK( tb.GetCompany().IsEmpty() );
1694}
1695
1696
1697BOOST_AUTO_TEST_CASE( CreateTitleBlock_NullScreen )
1698{
1699 PADS_SCH::PARAMETERS params;
1700 params.fields["Title"] = "Test";
1701
1702 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( params, nullptr );
1703
1704 // Should not crash with nullptr
1705 builder.CreateTitleBlock( nullptr );
1706
1707 BOOST_CHECK( true ); // If we get here, we passed
1708}
1709
1710
1712
1713
1714// Hierarchical sheet tests
1715#include <sch_sheet.h>
1716#include <sch_sheet_path.h>
1717#include <sch_sheet_pin.h>
1718
1719BOOST_AUTO_TEST_SUITE( PadsSchHierarchicalSheets )
1720
1721
1722BOOST_AUTO_TEST_CASE( GetDefaultSheetSize_ReturnsValidSize )
1723{
1724 PADS_SCH::PARAMETERS params;
1726
1727 SCHEMATIC schematic( nullptr );
1728 schematic.Reset();
1729
1730 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( params, &schematic );
1731
1732 VECTOR2I size = builder.GetDefaultSheetSize();
1733
1734 BOOST_CHECK( size.x > 0 );
1735 BOOST_CHECK( size.y > 0 );
1736}
1737
1738
1739BOOST_AUTO_TEST_CASE( CalculateSheetPosition_FirstSheet )
1740{
1741 PADS_SCH::PARAMETERS params;
1743
1744 SCHEMATIC schematic( nullptr );
1745 schematic.Reset();
1746
1747 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( params, &schematic );
1748
1749 VECTOR2I pos = builder.CalculateSheetPosition( 0, 4 );
1750
1751 BOOST_CHECK( pos.x > 0 );
1752 BOOST_CHECK( pos.y > 0 );
1753}
1754
1755
1756BOOST_AUTO_TEST_CASE( CalculateSheetPosition_GridLayout )
1757{
1758 PADS_SCH::PARAMETERS params;
1760
1761 SCHEMATIC schematic( nullptr );
1762 schematic.Reset();
1763
1764 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( params, &schematic );
1765
1766 VECTOR2I pos0 = builder.CalculateSheetPosition( 0, 4 );
1767 VECTOR2I pos1 = builder.CalculateSheetPosition( 1, 4 );
1768 VECTOR2I pos2 = builder.CalculateSheetPosition( 2, 4 );
1769 VECTOR2I pos3 = builder.CalculateSheetPosition( 3, 4 );
1770
1771 // For 4 sheets, should be 2x2 grid
1772 // pos0 and pos1 should be on same row (same Y)
1773 // pos0 and pos2 should be in same column (same X)
1774 BOOST_CHECK_EQUAL( pos0.y, pos1.y );
1775 BOOST_CHECK_EQUAL( pos2.y, pos3.y );
1776 BOOST_CHECK_EQUAL( pos0.x, pos2.x );
1777 BOOST_CHECK_EQUAL( pos1.x, pos3.x );
1778
1779 // Positions should increase going right and down
1780 BOOST_CHECK( pos1.x > pos0.x );
1781 BOOST_CHECK( pos2.y > pos0.y );
1782}
1783
1784
1785BOOST_AUTO_TEST_CASE( CreateHierarchicalSheet_ReturnsValidSheet )
1786{
1787 PADS_SCH::PARAMETERS params;
1789
1790 SCHEMATIC schematic( nullptr );
1791 schematic.Reset();
1792
1793 // Create root sheet
1794 SCH_SHEET* rootSheet = new SCH_SHEET( &schematic );
1795 SCH_SCREEN* rootScreen = new SCH_SCREEN( &schematic );
1796 rootSheet->SetScreen( rootScreen );
1797
1798 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( params, &schematic );
1799
1800 SCH_SHEET* sheet = builder.CreateHierarchicalSheet( 1, 3, rootSheet, wxT( "test_design.txt" ) );
1801 BOOST_REQUIRE( sheet != nullptr );
1802
1803 BOOST_CHECK( sheet->GetScreen() != nullptr );
1804
1805 // Verify sheet has valid position
1806 VECTOR2I pos = sheet->GetPosition();
1807 BOOST_CHECK( pos.x >= 0 );
1808 BOOST_CHECK( pos.y >= 0 );
1809
1810 // Verify sheet has valid size
1811 VECTOR2I size = sheet->GetSize();
1812 BOOST_CHECK( size.x > 0 );
1813 BOOST_CHECK( size.y > 0 );
1814
1815 delete rootSheet;
1816}
1817
1818
1819BOOST_AUTO_TEST_CASE( CreateHierarchicalSheet_SetsFilename )
1820{
1821 PADS_SCH::PARAMETERS params;
1823
1824 SCHEMATIC schematic( nullptr );
1825 schematic.Reset();
1826
1827 SCH_SHEET* rootSheet = new SCH_SHEET( &schematic );
1828 SCH_SCREEN* rootScreen = new SCH_SCREEN( &schematic );
1829 rootSheet->SetScreen( rootScreen );
1830
1831 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( params, &schematic );
1832
1833 SCH_SHEET* sheet = builder.CreateHierarchicalSheet( 2, 3, rootSheet, wxT( "my_design.asc" ) );
1834 BOOST_REQUIRE( sheet != nullptr );
1835
1836 // Verify sheet filename was set
1837 wxString filename = sheet->GetField( FIELD_T::SHEET_FILENAME )->GetText();
1838 BOOST_CHECK( filename.Contains( wxT( "my_design" ) ) );
1839 BOOST_CHECK( filename.Contains( wxT( "sheet2" ) ) );
1840 BOOST_CHECK( filename.EndsWith( wxT( ".kicad_sch" ) ) );
1841
1842 delete rootSheet;
1843}
1844
1845
1846BOOST_AUTO_TEST_CASE( CreateHierarchicalSheet_SetsSheetName )
1847{
1848 PADS_SCH::PARAMETERS params;
1850
1851 SCHEMATIC schematic( nullptr );
1852 schematic.Reset();
1853
1854 SCH_SHEET* rootSheet = new SCH_SHEET( &schematic );
1855 SCH_SCREEN* rootScreen = new SCH_SCREEN( &schematic );
1856 rootSheet->SetScreen( rootScreen );
1857
1858 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( params, &schematic );
1859
1860 SCH_SHEET* sheet = builder.CreateHierarchicalSheet( 3, 5, rootSheet, wxT( "design.txt" ) );
1861 BOOST_REQUIRE( sheet != nullptr );
1862
1863 // Verify sheet name was set
1864 wxString name = sheet->GetField( FIELD_T::SHEET_NAME )->GetText();
1865 BOOST_CHECK( name.Contains( wxT( "3" ) ) );
1866
1867 delete rootSheet;
1868}
1869
1870
1871BOOST_AUTO_TEST_CASE( CreateHierarchicalSheet_NullParent )
1872{
1873 PADS_SCH::PARAMETERS params;
1875
1876 SCHEMATIC schematic( nullptr );
1877 schematic.Reset();
1878
1879 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( params, &schematic );
1880
1881 // Should return nullptr when parent is null
1882 SCH_SHEET* sheet = builder.CreateHierarchicalSheet( 1, 3, nullptr, wxT( "test.txt" ) );
1883 BOOST_CHECK( sheet == nullptr );
1884}
1885
1886
1887BOOST_AUTO_TEST_CASE( CreateSheetPin_ValidPin )
1888{
1889 PADS_SCH::PARAMETERS params;
1891
1892 SCHEMATIC schematic( nullptr );
1893 schematic.Reset();
1894
1895 SCH_SHEET* sheet = new SCH_SHEET( &schematic );
1896 sheet->SetPosition( VECTOR2I( 1000, 2000 ) );
1897 sheet->SetSize( VECTOR2I( 3000, 2000 ) );
1898
1899 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( params, &schematic );
1900
1901 SCH_SHEET_PIN* pin = builder.CreateSheetPin( sheet, "NET1", 0 );
1902 BOOST_REQUIRE( pin != nullptr );
1903
1904 BOOST_CHECK_EQUAL( pin->GetText().ToStdString(), "NET1" );
1905 BOOST_CHECK( pin->GetSide() == SHEET_SIDE::LEFT );
1906
1907 delete sheet;
1908}
1909
1910
1911BOOST_AUTO_TEST_CASE( CreateSheetPin_PreservesName )
1912{
1913 PADS_SCH::PARAMETERS params;
1915
1916 SCHEMATIC schematic( nullptr );
1917 schematic.Reset();
1918
1919 SCH_SHEET* sheet = new SCH_SHEET( &schematic );
1920
1921 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( params, &schematic );
1922
1923 SCH_SHEET_PIN* pin = builder.CreateSheetPin( sheet, "NET 1", 0 );
1924 BOOST_REQUIRE( pin != nullptr );
1925
1926 // Net names pass through unchanged; KiCad handles arbitrary UTF-8 net names
1927 BOOST_CHECK_EQUAL( pin->GetText().ToStdString(), "NET 1" );
1928
1929 delete sheet;
1930}
1931
1932
1933BOOST_AUTO_TEST_CASE( CreateSheetPin_NullSheet )
1934{
1935 PADS_SCH::PARAMETERS params;
1937
1938 SCHEMATIC schematic( nullptr );
1939 schematic.Reset();
1940
1941 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( params, &schematic );
1942
1943 SCH_SHEET_PIN* pin = builder.CreateSheetPin( nullptr, "NET1", 0 );
1944 BOOST_CHECK( pin == nullptr );
1945}
1946
1947
1948BOOST_AUTO_TEST_CASE( CreateHierLabel_ValidLabel )
1949{
1950 PADS_SCH::PARAMETERS params;
1952
1953 SCHEMATIC schematic( nullptr );
1954 schematic.Reset();
1955
1956 SCH_SCREEN screen;
1957
1958 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( params, &schematic );
1959
1960 VECTOR2I pos( 1000, 2000 );
1961 SCH_HIERLABEL* label = builder.CreateHierLabel( "DATA_OUT", pos, &screen );
1962 BOOST_REQUIRE( label != nullptr );
1963
1964 BOOST_CHECK_EQUAL( label->GetText().ToStdString(), "DATA_OUT" );
1965
1966 // Label should be added to screen
1967 BOOST_CHECK( screen.Items().size() > 0 );
1968}
1969
1970
1971
1972BOOST_AUTO_TEST_CASE( IsGlobalSignal_PowerNets )
1973{
1974 std::set<int> singleSheet = { 1 };
1975
1976 BOOST_CHECK( PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER::IsGlobalSignal( "VCC", singleSheet ) );
1977 BOOST_CHECK( PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER::IsGlobalSignal( "GND", singleSheet ) );
1978 BOOST_CHECK( PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER::IsGlobalSignal( "vcc", singleSheet ) );
1979 BOOST_CHECK( PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER::IsGlobalSignal( "AGND", singleSheet ) );
1980 BOOST_CHECK( PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER::IsGlobalSignal( "+5V", singleSheet ) );
1981 BOOST_CHECK( PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER::IsGlobalSignal( "+3V3", singleSheet ) );
1982 BOOST_CHECK( PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER::IsGlobalSignal( "-12V", singleSheet ) );
1983}
1984
1985
1986BOOST_AUTO_TEST_CASE( IsGlobalSignal_MultiSheet )
1987{
1988 std::set<int> multiSheet = { 1, 2, 3 };
1989
1990 // Any signal on multiple sheets should be global
1991 BOOST_CHECK( PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER::IsGlobalSignal( "DATA_BUS", multiSheet ) );
1992 BOOST_CHECK( PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER::IsGlobalSignal( "RANDOM_NET", multiSheet ) );
1993}
1994
1995
1996BOOST_AUTO_TEST_CASE( IsGlobalSignal_NotGlobal )
1997{
1998 std::set<int> singleSheet = { 1 };
1999
2000 BOOST_CHECK( !PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER::IsGlobalSignal( "NET1", singleSheet ) );
2001 BOOST_CHECK( !PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER::IsGlobalSignal( "DATA", singleSheet ) );
2002 BOOST_CHECK( !PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER::IsGlobalSignal( "CLK", singleSheet ) );
2003 BOOST_CHECK( !PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER::IsGlobalSignal( "", singleSheet ) );
2004}
2005
2006
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
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.
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 * 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:148
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:147
SCH_SCREEN * GetScreen() const
Definition sch_sheet.h:145
VECTOR2I GetPosition() const override
Definition sch_sheet.h:496
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.
General schematic parameters from SCH and FIELDS sections.
std::map< std::string, std::string > fields
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
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_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