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