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
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
24
25#include <boost/test/unit_test.hpp>
28
31#include <io/pads/pads_common.h>
32#include <ki_exception.h>
33#include <lib_symbol.h>
34#include <sch_shape.h>
35#include <sch_pin.h>
36
37
38BOOST_AUTO_TEST_SUITE( PadsSchParser )
39
40
41BOOST_AUTO_TEST_CASE( CheckFileHeader_ValidLogicFile )
42{
43 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/simple_schematic.txt";
44
45 BOOST_CHECK( PADS_SCH::PADS_SCH_PARSER::CheckFileHeader( testFile ) );
46}
47
48
49BOOST_AUTO_TEST_CASE( CheckFileHeader_ValidPowerLogicFile )
50{
51 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/powerlogic_schematic.txt";
52
53 BOOST_CHECK( PADS_SCH::PADS_SCH_PARSER::CheckFileHeader( testFile ) );
54}
55
56
57BOOST_AUTO_TEST_CASE( BussesSection )
58{
59 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/buses.txt";
61 BOOST_REQUIRE( parser.Parse( testFile ) );
62
63 const auto& buses = parser.GetBuses();
64 BOOST_REQUIRE_EQUAL( buses.size(), 1 );
65 BOOST_CHECK_EQUAL( buses[0].handle, "@@@B0" );
66 BOOST_CHECK_EQUAL( buses[0].name, "DATA[0..2]" );
67 BOOST_CHECK_EQUAL( buses[0].sheet_number, 1 );
68 BOOST_REQUIRE_EQUAL( buses[0].path.size(), 3 );
69 BOOST_CHECK_EQUAL( buses[0].path[0].x, 3000 );
70 BOOST_CHECK_EQUAL( buses[0].path[2].y, 5000 );
71 BOOST_REQUIRE_EQUAL( buses[0].entries.size(), 3 );
72 BOOST_CHECK_EQUAL( buses[0].entries[1].member_net, "DATA1" );
73 BOOST_CHECK_EQUAL( buses[0].entries[1].position.x, 5000 );
74 BOOST_CHECK_EQUAL( buses[0].aliases, std::vector<std::string>{ "DATA[0..2]" } );
75 BOOST_CHECK_EQUAL( buses[0].member_nets, ( std::vector<std::string>{ "DATA0", "DATA1", "DATA2" } ) );
76}
77
78
79BOOST_AUTO_TEST_CASE( ParseBussesClearsPriorState )
80{
81 const std::string root = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/";
83 BOOST_REQUIRE( parser.Parse( root + "buses.txt" ) );
84 BOOST_REQUIRE_EQUAL( parser.GetBuses().size(), 1 );
85 BOOST_REQUIRE( parser.Parse( root + "simple_schematic.txt" ) );
86 BOOST_CHECK( parser.GetBuses().empty() );
87}
88
89
90// A malformed bus drops that bus and the import continues. Nothing outside these tests reads
91// GetBuses(), and the grammar is inferred, so aborting a whole design over it would be worse than
92// losing a payload no consumer wants. buses_truncated.txt also proves the parser resynchronizes:
93// its first bus is short, but the well-formed bus that follows is still recovered.
94BOOST_AUTO_TEST_CASE( ParseBussesSkipsMalformedRecords )
95{
96 const std::string root = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/";
97
98 for( const std::string fixture : { "buses_bad_header.txt", "buses_bad_point.txt",
99 "buses_negative_count.txt", "buses_excessive_count.txt" } )
100 {
101 BOOST_TEST_CONTEXT( fixture )
102 {
104
105 BOOST_CHECK( parser.Parse( root + fixture ) );
106 BOOST_CHECK( parser.GetBuses().empty() );
107 }
108 }
109
111
112 BOOST_CHECK( truncated.Parse( root + "buses_truncated.txt" ) );
113 BOOST_REQUIRE_EQUAL( truncated.GetBuses().size(), 1 );
114 BOOST_CHECK_EQUAL( truncated.GetBuses()[0].name, std::string( "OTHER" ) );
115
116 // A readable point after an unreadable one must not complete the bus, or a record we could
117 // not decode would reach the design looking whole
119
120 BOOST_CHECK( recovered.Parse( root + "buses_bad_point_recovers.txt" ) );
121 BOOST_REQUIRE_EQUAL( recovered.GetBuses().size(), 1 );
122 BOOST_CHECK_EQUAL( recovered.GetBuses()[0].name, std::string( "OTHER" ) );
123}
124
125
126BOOST_AUTO_TEST_CASE( CheckFileHeader_InvalidFile )
127{
128 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/nonexistent.txt";
129
130 BOOST_CHECK( !PADS_SCH::PADS_SCH_PARSER::CheckFileHeader( testFile ) );
131}
132
133
134BOOST_AUTO_TEST_CASE( ParseHeader_LogicFormat )
135{
136 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/simple_schematic.txt";
137
139
140 BOOST_REQUIRE( parser.Parse( testFile ) );
141 BOOST_CHECK( parser.IsValid() );
142
143 const auto& header = parser.GetHeader();
144
145 BOOST_CHECK_EQUAL( header.product, "PADS-LOGIC" );
146 BOOST_CHECK_EQUAL( header.version, "V9.0" );
147 BOOST_CHECK( header.description.find( "DESIGN EXPORT FILE" ) != std::string::npos );
148}
149
150
151BOOST_AUTO_TEST_CASE( CheckFileHeader_LogicWithCodePageSuffix )
152{
153 // Regression test for https://gitlab.com/kicad/code/kicad/-/issues/23420
154 // PADS exporters may include the ANSI code page as a suffix in the header
155 // (e.g. *PADS-LOGIC-V9.0-CP1250*). Detection must still succeed.
156 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/issue23420_codepage_schematic.txt";
157
158 BOOST_CHECK( PADS_SCH::PADS_SCH_PARSER::CheckFileHeader( testFile ) );
159}
160
161
162BOOST_AUTO_TEST_CASE( ParseHeader_LogicWithCodePageSuffix )
163{
164 // Regression test for https://gitlab.com/kicad/code/kicad/-/issues/23420
165 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/issue23420_codepage_schematic.txt";
166
168
169 BOOST_REQUIRE( parser.Parse( testFile ) );
170 BOOST_CHECK( parser.IsValid() );
171
172 const auto& header = parser.GetHeader();
173
174 BOOST_CHECK_EQUAL( header.product, "PADS-LOGIC" );
175 BOOST_CHECK_EQUAL( header.version, "V9.0" );
176 BOOST_CHECK_EQUAL( header.codepage, "CP1250" );
177}
178
179
180BOOST_AUTO_TEST_CASE( ParseHeader_PowerLogicFormat )
181{
182 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/powerlogic_schematic.txt";
183
185
186 BOOST_REQUIRE( parser.Parse( testFile ) );
187 BOOST_CHECK( parser.IsValid() );
188
189 const auto& header = parser.GetHeader();
190
191 BOOST_CHECK_EQUAL( header.product, "PADS-POWERLOGIC" );
192 BOOST_CHECK_EQUAL( header.version, "V9.5" );
193}
194
195
196BOOST_AUTO_TEST_CASE( ParseParameters_Units_Mils )
197{
198 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/simple_schematic.txt";
199
201
202 BOOST_REQUIRE( parser.Parse( testFile ) );
203
204 const auto& params = parser.GetParameters();
205
206 BOOST_CHECK( params.units == PADS_SCH::UNIT_TYPE::MILS );
207 BOOST_CHECK_EQUAL( params.grid_x, 100.0 );
208 BOOST_CHECK_EQUAL( params.grid_y, 100.0 );
209 BOOST_CHECK_EQUAL( params.border_template, "Default_A" );
210}
211
212
213BOOST_AUTO_TEST_CASE( ParseParameters_Units_Metric )
214{
215 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/powerlogic_schematic.txt";
216
218
219 BOOST_REQUIRE( parser.Parse( testFile ) );
220
221 const auto& params = parser.GetParameters();
222
223 BOOST_CHECK( params.units == PADS_SCH::UNIT_TYPE::METRIC );
224}
225
226
228{
229 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/simple_schematic.txt";
230
232
233 BOOST_REQUIRE( parser.Parse( testFile ) );
234 BOOST_CHECK_EQUAL( parser.GetVersion(), "V9.0" );
235}
236
237
238BOOST_AUTO_TEST_CASE( ParseParameters_JobName )
239{
240 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/simple_schematic.txt";
241
243
244 BOOST_REQUIRE( parser.Parse( testFile ) );
245
246 const auto& params = parser.GetParameters();
247
248 BOOST_CHECK_EQUAL( params.job_name, "Test Design" );
249}
250
251
252BOOST_AUTO_TEST_CASE( ParseParameters_SheetSize )
253{
254 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/simple_schematic.txt";
255
257
258 BOOST_REQUIRE( parser.Parse( testFile ) );
259
260 const auto& params = parser.GetParameters();
261
262 BOOST_CHECK_EQUAL( params.sheet_size.width, 11000.0 );
263 BOOST_CHECK_EQUAL( params.sheet_size.height, 8500.0 );
264 BOOST_CHECK_EQUAL( params.sheet_size.name, "A" );
265}
266
267
268BOOST_AUTO_TEST_CASE( ParseParameters_TextAndLineDefaults )
269{
270 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/simple_schematic.txt";
271
273
274 BOOST_REQUIRE( parser.Parse( testFile ) );
275
276 const auto& params = parser.GetParameters();
277
278 BOOST_CHECK_EQUAL( params.text_size, 60.0 );
279 BOOST_CHECK_EQUAL( params.line_width, 2.0 );
280}
281
282
283BOOST_AUTO_TEST_CASE( ParseSymbols_Count )
284{
285 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/symbols_schematic.txt";
286
288
289 BOOST_REQUIRE( parser.Parse( testFile ) );
290
291 const auto& symbols = parser.GetSymbolDefs();
292
293 BOOST_CHECK_EQUAL( symbols.size(), 3 );
294}
295
296
297BOOST_AUTO_TEST_CASE( ParseSymbols_V52_DecalWithoutFontLines )
298{
299 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/v52_decals.txt";
300
302
303 BOOST_REQUIRE( parser.Parse( testFile ) );
304 BOOST_CHECK( parser.IsValid() );
305
306 const auto& header = parser.GetHeader();
307
308 BOOST_CHECK_EQUAL( header.product, "PADS-POWERLOGIC" );
309 BOOST_CHECK_EQUAL( header.version, "V5.2" );
310
311 const auto& symbols = parser.GetSymbolDefs();
312
313 BOOST_REQUIRE_EQUAL( symbols.size(), 1 );
314
315 const PADS_SCH::SYMBOL_DEF* pinb = parser.GetSymbolDef( "PINB" );
316 BOOST_REQUIRE( pinb != nullptr );
317
318 BOOST_CHECK_EQUAL( pinb->num_attrs, 4 );
319 BOOST_CHECK_EQUAL( pinb->num_pieces, 2 );
320 BOOST_CHECK_EQUAL( pinb->num_pins, 0 );
322
323 // Verify attribute names were parsed correctly (not misaligned)
324 BOOST_REQUIRE_EQUAL( pinb->attrs.size(), 4 );
325 BOOST_CHECK_EQUAL( pinb->attrs[0].attr_name, "REF-DES" );
326 BOOST_CHECK_EQUAL( pinb->attrs[1].attr_name, "PART-TYPE" );
327 BOOST_CHECK_EQUAL( pinb->attrs[2].attr_name, "*" );
328 BOOST_CHECK_EQUAL( pinb->attrs[3].attr_name, "*" );
329
330 // Verify graphics were parsed correctly
331 BOOST_REQUIRE_EQUAL( pinb->graphics.size(), 2 );
332
333 const auto& openLine = pinb->graphics[0];
334 BOOST_CHECK( openLine.type == PADS_SCH::GRAPHIC_TYPE::POLYLINE );
335 BOOST_CHECK_EQUAL( openLine.line_width, 10.0 );
336 BOOST_REQUIRE_EQUAL( openLine.points.size(), 2 );
337 BOOST_CHECK_EQUAL( openLine.points[0].coord.x, 0.0 );
338 BOOST_CHECK_EQUAL( openLine.points[0].coord.y, 0.0 );
339 BOOST_CHECK_EQUAL( openLine.points[1].coord.x, 140.0 );
340 BOOST_CHECK_EQUAL( openLine.points[1].coord.y, 0.0 );
341
342 const auto& circle = pinb->graphics[1];
343 BOOST_CHECK( circle.type == PADS_SCH::GRAPHIC_TYPE::CIRCLE );
344 BOOST_CHECK_EQUAL( circle.line_width, 10.0 );
345 BOOST_CHECK_EQUAL( circle.center.x, 165.0 );
346 BOOST_CHECK_EQUAL( circle.center.y, 0.0 );
347 BOOST_CHECK_EQUAL( circle.radius, 25.0 );
348
349 // Font names should be empty since V5.2 doesn't have them
350 BOOST_CHECK( pinb->font1.empty() );
351 BOOST_CHECK( pinb->font2.empty() );
352}
353
354
355BOOST_AUTO_TEST_CASE( ParseSymbols_Resistor )
356{
357 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/symbols_schematic.txt";
358
360
361 BOOST_REQUIRE( parser.Parse( testFile ) );
362
363 const PADS_SCH::SYMBOL_DEF* res = parser.GetSymbolDef( "RES_0805" );
364 BOOST_REQUIRE( res != nullptr );
365
366 BOOST_CHECK_EQUAL( res->name, "RES_0805" );
367 BOOST_CHECK_EQUAL( res->gate_count, 1 );
368 BOOST_CHECK_EQUAL( res->graphics.size(), 4 );
369 BOOST_CHECK_EQUAL( res->pins.size(), 2 );
370}
371
372
373BOOST_AUTO_TEST_CASE( ParseSymbols_ResistorPins )
374{
375 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/symbols_schematic.txt";
376
378
379 BOOST_REQUIRE( parser.Parse( testFile ) );
380
381 const PADS_SCH::SYMBOL_DEF* res = parser.GetSymbolDef( "RES_0805" );
382 BOOST_REQUIRE( res != nullptr );
383 BOOST_REQUIRE( res->pins.size() >= 2 );
384
385 // CAEDECAL pins have placeholder numbers and empty names.
386 // Actual pin data comes from PARTTYPE GATE_DEF at build time.
387 const auto& pin1 = res->pins[0];
388 BOOST_CHECK_EQUAL( pin1.number, "1" );
389 BOOST_CHECK_EQUAL( pin1.position.x, -200.0 );
390 BOOST_CHECK_EQUAL( pin1.position.y, 0.0 );
391 BOOST_CHECK( pin1.type == PADS_SCH::PIN_TYPE::UNSPECIFIED );
392
393 const auto& pin2 = res->pins[1];
394 BOOST_CHECK_EQUAL( pin2.number, "2" );
395 BOOST_CHECK_EQUAL( pin2.position.x, 200.0 );
396 BOOST_CHECK_EQUAL( pin2.position.y, 0.0 );
397 BOOST_CHECK( pin2.type == PADS_SCH::PIN_TYPE::UNSPECIFIED );
398
399 // Verify PARTTYPE provides the actual pin numbers/names
400 auto ptIt = parser.GetPartTypes().find( "RES_0805" );
401 BOOST_REQUIRE( ptIt != parser.GetPartTypes().end() );
402 BOOST_REQUIRE( !ptIt->second.gates.empty() );
403
404 const auto& gate = ptIt->second.gates[0];
405 BOOST_REQUIRE_GE( gate.pins.size(), 2u );
406 BOOST_CHECK_EQUAL( gate.pins[0].pin_id, "1" );
407 BOOST_CHECK_EQUAL( gate.pins[0].pin_name, "1" );
408 BOOST_CHECK_EQUAL( gate.pins[1].pin_id, "2" );
409 BOOST_CHECK_EQUAL( gate.pins[1].pin_name, "2" );
410}
411
412
413BOOST_AUTO_TEST_CASE( ParseSymbols_Capacitor )
414{
415 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/symbols_schematic.txt";
416
418
419 BOOST_REQUIRE( parser.Parse( testFile ) );
420
421 const PADS_SCH::SYMBOL_DEF* cap = parser.GetSymbolDef( "CAP_0603" );
422 BOOST_REQUIRE( cap != nullptr );
423
424 BOOST_CHECK_EQUAL( cap->name, "CAP_0603" );
425 BOOST_CHECK_EQUAL( cap->gate_count, 1 );
426 BOOST_CHECK_EQUAL( cap->graphics.size(), 2 );
427 BOOST_CHECK_EQUAL( cap->pins.size(), 2 );
428}
429
430
431BOOST_AUTO_TEST_CASE( ParseSymbols_IC_MultiGate )
432{
433 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/symbols_schematic.txt";
434
436
437 BOOST_REQUIRE( parser.Parse( testFile ) );
438
439 const PADS_SCH::SYMBOL_DEF* ic = parser.GetSymbolDef( "IC_QUAD_NAND" );
440 BOOST_REQUIRE( ic != nullptr );
441
442 BOOST_CHECK_EQUAL( ic->name, "IC_QUAD_NAND" );
443 BOOST_CHECK_EQUAL( ic->graphics.size(), 9 );
444 BOOST_CHECK_EQUAL( ic->pins.size(), 14 );
445
446 // gate_count on SYMBOL_DEF stays at default (1). Multi-gate info lives in PARTTYPE.
447 auto ptIt = parser.GetPartTypes().find( "IC_QUAD_NAND" );
448 BOOST_REQUIRE( ptIt != parser.GetPartTypes().end() );
449 BOOST_CHECK_EQUAL( ptIt->second.num_physical, 4 );
450}
451
452
453BOOST_AUTO_TEST_CASE( ParseSymbols_IC_PinTypes )
454{
455 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/symbols_schematic.txt";
456
458
459 BOOST_REQUIRE( parser.Parse( testFile ) );
460
461 // Pin names/types on SYMBOL_DEF are raw CAEDECAL data (empty/unspecified).
462 // Actual pin data lives in PARTTYPE GATE_DEF and is applied at build time.
463 auto ptIt = parser.GetPartTypes().find( "IC_QUAD_NAND" );
464 BOOST_REQUIRE( ptIt != parser.GetPartTypes().end() );
465 BOOST_REQUIRE( !ptIt->second.gates.empty() );
466
467 const auto& pins = ptIt->second.gates[0].pins;
468 BOOST_REQUIRE_GE( pins.size(), 14u );
469
470 // Check input pins
471 BOOST_CHECK_EQUAL( pins[0].pin_name, "1A" );
472 BOOST_CHECK_EQUAL( pins[0].pin_type, 'L' );
473
474 // Check output pins
475 BOOST_CHECK_EQUAL( pins[2].pin_name, "1Y" );
476 BOOST_CHECK_EQUAL( pins[2].pin_type, 'S' );
477
478 // Check power pins
479 BOOST_CHECK_EQUAL( pins[6].pin_name, "GND" );
480 BOOST_CHECK_EQUAL( pins[6].pin_type, 'G' );
481}
482
483
484BOOST_AUTO_TEST_CASE( ParseSymbols_Graphics )
485{
486 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/symbols_schematic.txt";
487
489
490 BOOST_REQUIRE( parser.Parse( testFile ) );
491
492 const PADS_SCH::SYMBOL_DEF* res = parser.GetSymbolDef( "RES_0805" );
493 BOOST_REQUIRE( res != nullptr );
494 BOOST_REQUIRE( res->graphics.size() >= 1 );
495
496 // First graphic should be a rectangle (CLOSED)
497 const auto& rect = res->graphics[0];
498 BOOST_CHECK( rect.type == PADS_SCH::GRAPHIC_TYPE::RECTANGLE );
499 BOOST_CHECK_EQUAL( rect.line_width, 10.0 );
500 BOOST_REQUIRE( rect.points.size() >= 2 );
501 BOOST_CHECK_EQUAL( rect.points[0].coord.x, -100.0 );
502 BOOST_CHECK_EQUAL( rect.points[0].coord.y, -50.0 );
503 BOOST_CHECK_EQUAL( rect.points[1].coord.x, 100.0 );
504 BOOST_CHECK_EQUAL( rect.points[1].coord.y, 50.0 );
505}
506
507
508BOOST_AUTO_TEST_CASE( GetSymbolDef_NotFound )
509{
510 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/symbols_schematic.txt";
511
513
514 BOOST_REQUIRE( parser.Parse( testFile ) );
515
516 const PADS_SCH::SYMBOL_DEF* notFound = parser.GetSymbolDef( "NONEXISTENT_SYMBOL" );
517 BOOST_CHECK( notFound == nullptr );
518}
519
520
521BOOST_AUTO_TEST_CASE( ParseSymbols_EmptySection )
522{
523 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/simple_schematic.txt";
524
526
527 BOOST_REQUIRE( parser.Parse( testFile ) );
528
529 const auto& symbols = parser.GetSymbolDefs();
530 BOOST_CHECK( symbols.empty() );
531}
532
533
534BOOST_AUTO_TEST_CASE( ParseParts_Count )
535{
536 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/parts_schematic.txt";
537
539
540 BOOST_REQUIRE( parser.Parse( testFile ) );
541
542 const auto& parts = parser.GetPartPlacements();
543
544 BOOST_CHECK_EQUAL( parts.size(), 5 );
545}
546
547
548BOOST_AUTO_TEST_CASE( ParseParts_Resistor )
549{
550 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/parts_schematic.txt";
551
553
554 BOOST_REQUIRE( parser.Parse( testFile ) );
555
556 const PADS_SCH::PART_PLACEMENT* r1 = parser.GetPartPlacement( "R1" );
557 BOOST_REQUIRE( r1 != nullptr );
558
559 BOOST_CHECK_EQUAL( r1->reference, "R1" );
560 BOOST_CHECK_EQUAL( r1->symbol_name, "RES_0805" );
561 BOOST_CHECK_EQUAL( r1->position.x, 1000.0 );
562 BOOST_CHECK_EQUAL( r1->position.y, 2000.0 );
563 BOOST_CHECK_EQUAL( r1->rotation, 0.0 );
566}
567
568
569BOOST_AUTO_TEST_CASE( ParseParts_RotatedPart )
570{
571 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/parts_schematic.txt";
572
574
575 BOOST_REQUIRE( parser.Parse( testFile ) );
576
577 const PADS_SCH::PART_PLACEMENT* r2 = parser.GetPartPlacement( "R2" );
578 BOOST_REQUIRE( r2 != nullptr );
579
580 BOOST_CHECK_EQUAL( r2->rotation, 90.0 );
582}
583
584
585BOOST_AUTO_TEST_CASE( ParseParts_MirroredPart )
586{
587 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/parts_schematic.txt";
588
590
591 BOOST_REQUIRE( parser.Parse( testFile ) );
592
593 const PADS_SCH::PART_PLACEMENT* c1 = parser.GetPartPlacement( "C1" );
594 BOOST_REQUIRE( c1 != nullptr );
595
596 BOOST_CHECK_NE( c1->mirror_flags, 0 );
597}
598
599
600BOOST_AUTO_TEST_CASE( ParseParts_Attributes )
601{
602 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/parts_schematic.txt";
603
605
606 BOOST_REQUIRE( parser.Parse( testFile ) );
607
608 const PADS_SCH::PART_PLACEMENT* r1 = parser.GetPartPlacement( "R1" );
609 BOOST_REQUIRE( r1 != nullptr );
610 BOOST_CHECK_EQUAL( r1->attributes.size(), 2 );
611
612 // Check Ref.Des. attribute
613 bool foundRefDes = false;
614 bool foundValue = false;
615
616 for( const auto& attr : r1->attributes )
617 {
618 if( attr.name == "Ref.Des." )
619 {
620 BOOST_CHECK_EQUAL( attr.value, "R1" );
621 BOOST_CHECK( attr.visible );
622 foundRefDes = true;
623 }
624 else if( attr.name == "Value" )
625 {
626 BOOST_CHECK_EQUAL( attr.value, "10K" );
627 BOOST_CHECK( attr.visible );
628 foundValue = true;
629 }
630 }
631
632 BOOST_CHECK( foundRefDes );
633 BOOST_CHECK( foundValue );
634}
635
636
637BOOST_AUTO_TEST_CASE( ParseParts_AttributeVisibility )
638{
639 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/parts_schematic.txt";
640
642
643 BOOST_REQUIRE( parser.Parse( testFile ) );
644
645 const PADS_SCH::PART_PLACEMENT* r2 = parser.GetPartPlacement( "R2" );
646 BOOST_REQUIRE( r2 != nullptr );
647
648 // R2 has Value attribute with visibility N (hidden)
649 for( const auto& attr : r2->attributes )
650 {
651 if( attr.name == "Value" )
652 {
653 BOOST_CHECK( !attr.visible );
654 break;
655 }
656 }
657}
658
659
660BOOST_AUTO_TEST_CASE( ParseParts_IC_MultipleAttributes )
661{
662 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/parts_schematic.txt";
663
665
666 BOOST_REQUIRE( parser.Parse( testFile ) );
667
668 const PADS_SCH::PART_PLACEMENT* u1 = parser.GetPartPlacement( "U1" );
669 BOOST_REQUIRE( u1 != nullptr );
670
671 BOOST_CHECK_EQUAL( u1->symbol_name, "IC_QUAD_NAND" );
672 BOOST_CHECK_EQUAL( u1->attributes.size(), 4 );
673}
674
675
676BOOST_AUTO_TEST_CASE( ParseParts_MultiGatePart )
677{
678 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/parts_schematic.txt";
679
681
682 BOOST_REQUIRE( parser.Parse( testFile ) );
683
684 const PADS_SCH::PART_PLACEMENT* u1a = parser.GetPartPlacement( "U1.A" );
685 BOOST_REQUIRE( u1a != nullptr );
686
687 BOOST_CHECK_EQUAL( u1a->symbol_name, "IC_QUAD_NAND" );
689}
690
691
692BOOST_AUTO_TEST_CASE( GetPartPlacement_NotFound )
693{
694 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/parts_schematic.txt";
695
697
698 BOOST_REQUIRE( parser.Parse( testFile ) );
699
700 const PADS_SCH::PART_PLACEMENT* notFound = parser.GetPartPlacement( "NONEXISTENT" );
701 BOOST_CHECK( notFound == nullptr );
702}
703
704
705BOOST_AUTO_TEST_CASE( ParseParts_EmptySection )
706{
707 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/simple_schematic.txt";
708
710
711 BOOST_REQUIRE( parser.Parse( testFile ) );
712
713 const auto& parts = parser.GetPartPlacements();
714 BOOST_CHECK( parts.empty() );
715}
716
717
718BOOST_AUTO_TEST_CASE( ParseSignals_Count )
719{
720 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/signals_schematic.txt";
721
723
724 BOOST_REQUIRE( parser.Parse( testFile ) );
725
726 const auto& signals = parser.GetSignals();
727
728 BOOST_CHECK_EQUAL( signals.size(), 4 );
729}
730
731
732BOOST_AUTO_TEST_CASE( ParseSignals_VCC )
733{
734 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/signals_schematic.txt";
735
737
738 BOOST_REQUIRE( parser.Parse( testFile ) );
739
740 const PADS_SCH::SCH_SIGNAL* vcc = parser.GetSignal( "VCC" );
741 BOOST_REQUIRE( vcc != nullptr );
742
743 BOOST_CHECK_EQUAL( vcc->name, "VCC" );
744 BOOST_CHECK_EQUAL( vcc->connections.size(), 2 );
745 BOOST_CHECK_EQUAL( vcc->wires.size(), 2 );
746}
747
748
749BOOST_AUTO_TEST_CASE( ParseSignals_PinConnections )
750{
751 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/signals_schematic.txt";
752
754
755 BOOST_REQUIRE( parser.Parse( testFile ) );
756
757 const PADS_SCH::SCH_SIGNAL* vcc = parser.GetSignal( "VCC" );
758 BOOST_REQUIRE( vcc != nullptr );
759 BOOST_REQUIRE( vcc->connections.size() >= 2 );
760
761 // Check first connection: R1.1
762 BOOST_CHECK_EQUAL( vcc->connections[0].reference, "R1" );
763 BOOST_CHECK_EQUAL( vcc->connections[0].pin_number, "1" );
764
765 // Check second connection: U1.14
766 BOOST_CHECK_EQUAL( vcc->connections[1].reference, "U1" );
767 BOOST_CHECK_EQUAL( vcc->connections[1].pin_number, "14" );
768}
769
770
771BOOST_AUTO_TEST_CASE( ParseSignals_WireSegments )
772{
773 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/signals_schematic.txt";
774
776
777 BOOST_REQUIRE( parser.Parse( testFile ) );
778
779 const PADS_SCH::SCH_SIGNAL* vcc = parser.GetSignal( "VCC" );
780 BOOST_REQUIRE( vcc != nullptr );
781 BOOST_REQUIRE( vcc->wires.size() >= 2 );
782
783 // Check first wire segment
784 const auto& wire1 = vcc->wires[0];
785 BOOST_CHECK_EQUAL( wire1.start.x, 1000.0 );
786 BOOST_CHECK_EQUAL( wire1.start.y, 2000.0 );
787 BOOST_CHECK_EQUAL( wire1.end.x, 2000.0 );
788 BOOST_CHECK_EQUAL( wire1.end.y, 2000.0 );
789 BOOST_CHECK_EQUAL( wire1.sheet_number, 1 );
790
791 // Check second wire segment
792 const auto& wire2 = vcc->wires[1];
793 BOOST_CHECK_EQUAL( wire2.start.x, 2000.0 );
794 BOOST_CHECK_EQUAL( wire2.start.y, 2000.0 );
795 BOOST_CHECK_EQUAL( wire2.end.x, 2000.0 );
796 BOOST_CHECK_EQUAL( wire2.end.y, 3000.0 );
797}
798
799
800BOOST_AUTO_TEST_CASE( ParseSignals_MultipleConnections )
801{
802 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/signals_schematic.txt";
803
805
806 BOOST_REQUIRE( parser.Parse( testFile ) );
807
808 const PADS_SCH::SCH_SIGNAL* net1 = parser.GetSignal( "NET1" );
809 BOOST_REQUIRE( net1 != nullptr );
810
811 // NET1 connects R1.2, R2.1, U1.1, U1.2
812 BOOST_CHECK_EQUAL( net1->connections.size(), 4 );
813 BOOST_CHECK_EQUAL( net1->wires.size(), 4 );
814}
815
816
817BOOST_AUTO_TEST_CASE( ParseSignals_SingleConnection )
818{
819 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/signals_schematic.txt";
820
822
823 BOOST_REQUIRE( parser.Parse( testFile ) );
824
825 const PADS_SCH::SCH_SIGNAL* output = parser.GetSignal( "OUTPUT" );
826 BOOST_REQUIRE( output != nullptr );
827
828 BOOST_CHECK_EQUAL( output->connections.size(), 1 );
829 BOOST_CHECK_EQUAL( output->connections[0].reference, "U1" );
830 BOOST_CHECK_EQUAL( output->connections[0].pin_number, "3" );
831}
832
833
834BOOST_AUTO_TEST_CASE( GetSignal_NotFound )
835{
836 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/signals_schematic.txt";
837
839
840 BOOST_REQUIRE( parser.Parse( testFile ) );
841
842 const PADS_SCH::SCH_SIGNAL* notFound = parser.GetSignal( "NONEXISTENT" );
843 BOOST_CHECK( notFound == nullptr );
844}
845
846
847BOOST_AUTO_TEST_CASE( ParseSignals_EmptySection )
848{
849 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/simple_schematic.txt";
850
852
853 BOOST_REQUIRE( parser.Parse( testFile ) );
854
855 const auto& signals = parser.GetSignals();
856 BOOST_CHECK( signals.empty() );
857}
858
859
860BOOST_AUTO_TEST_CASE( SymbolBuilder_CreateSymbol )
861{
862 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/symbols_schematic.txt";
863
865 BOOST_REQUIRE( parser.Parse( testFile ) );
866
868
869 const PADS_SCH::SYMBOL_DEF* resDef = parser.GetSymbolDef( "RES_0805" );
870 BOOST_REQUIRE( resDef != nullptr );
871
872 LIB_SYMBOL* symbol = builder.BuildSymbol( *resDef );
873 BOOST_REQUIRE( symbol != nullptr );
874
875 BOOST_CHECK_EQUAL( symbol->GetName(), "RES_0805" );
876
877 delete symbol;
878}
879
880
881BOOST_AUTO_TEST_CASE( SymbolBuilder_SymbolHasGraphics )
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 LIB_SYMBOL* symbol = builder.BuildSymbol( *resDef );
894 BOOST_REQUIRE( symbol != nullptr );
895
896 // Count graphics (shapes) in the symbol
897 int shapeCount = 0;
898
899 for( const SCH_ITEM& item : symbol->GetDrawItems() )
900 {
901 if( item.Type() == SCH_SHAPE_T )
902 shapeCount++;
903 }
904
905 BOOST_CHECK_EQUAL( shapeCount, 4 );
906
907 delete symbol;
908}
909
910
911BOOST_AUTO_TEST_CASE( SymbolBuilder_SymbolHasPins )
912{
913 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/symbols_schematic.txt";
914
916 BOOST_REQUIRE( parser.Parse( testFile ) );
917
919
920 const PADS_SCH::SYMBOL_DEF* resDef = parser.GetSymbolDef( "RES_0805" );
921 BOOST_REQUIRE( resDef != nullptr );
922
923 LIB_SYMBOL* symbol = builder.BuildSymbol( *resDef );
924 BOOST_REQUIRE( symbol != nullptr );
925
926 // Count pins in the symbol
927 int pinCount = 0;
928
929 for( const SCH_ITEM& item : symbol->GetDrawItems() )
930 {
931 if( item.Type() == SCH_PIN_T )
932 pinCount++;
933 }
934
935 BOOST_CHECK_EQUAL( pinCount, 2 );
936
937 delete symbol;
938}
939
940
941BOOST_AUTO_TEST_CASE( SymbolBuilder_PinProperties )
942{
943 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/symbols_schematic.txt";
944
946 BOOST_REQUIRE( parser.Parse( testFile ) );
947
949
950 const PADS_SCH::SYMBOL_DEF* resDef = parser.GetSymbolDef( "RES_0805" );
951 BOOST_REQUIRE( resDef != nullptr );
952
953 LIB_SYMBOL* symbol = builder.BuildSymbol( *resDef );
954 BOOST_REQUIRE( symbol != nullptr );
955
956 // Find a pin and verify its properties
957 const SCH_PIN* pin1 = nullptr;
958
959 for( const SCH_ITEM& item : symbol->GetDrawItems() )
960 {
961 if( item.Type() == SCH_PIN_T )
962 {
963 const SCH_PIN* pin = static_cast<const SCH_PIN*>( &item );
964
965 if( pin->GetNumber() == "1" )
966 {
967 pin1 = pin;
968 break;
969 }
970 }
971 }
972
973 BOOST_REQUIRE( pin1 != nullptr );
974 BOOST_CHECK_EQUAL( pin1->GetNumber(), "1" );
975 BOOST_CHECK( pin1->GetType() == ELECTRICAL_PINTYPE::PT_UNSPECIFIED );
976
977 delete symbol;
978}
979
980
981BOOST_AUTO_TEST_CASE( SymbolBuilder_CacheSymbol )
982{
983 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/symbols_schematic.txt";
984
986 BOOST_REQUIRE( parser.Parse( testFile ) );
987
989
990 const PADS_SCH::SYMBOL_DEF* resDef = parser.GetSymbolDef( "RES_0805" );
991 BOOST_REQUIRE( resDef != nullptr );
992
993 // First call creates the symbol
994 BOOST_CHECK( !builder.HasSymbol( "RES_0805" ) );
995
996 LIB_SYMBOL* symbol1 = builder.GetOrCreateSymbol( *resDef );
997 BOOST_REQUIRE( symbol1 != nullptr );
998 BOOST_CHECK( builder.HasSymbol( "RES_0805" ) );
999
1000 // Second call returns the same symbol
1001 LIB_SYMBOL* symbol2 = builder.GetOrCreateSymbol( *resDef );
1002 BOOST_CHECK_EQUAL( symbol1, symbol2 );
1003}
1004
1005
1006BOOST_AUTO_TEST_CASE( PowerSymbol_GroundVariants )
1007{
1010 BOOST_CHECK( PADS_SCH::PADS_SCH_SYMBOL_BUILDER::IsPowerSymbol( "AGND" ) );
1011 BOOST_CHECK( PADS_SCH::PADS_SCH_SYMBOL_BUILDER::IsPowerSymbol( "DGND" ) );
1012 BOOST_CHECK( PADS_SCH::PADS_SCH_SYMBOL_BUILDER::IsPowerSymbol( "PGND" ) );
1015 BOOST_CHECK( PADS_SCH::PADS_SCH_SYMBOL_BUILDER::IsPowerSymbol( "EARTH" ) );
1016 BOOST_CHECK( PADS_SCH::PADS_SCH_SYMBOL_BUILDER::IsPowerSymbol( "CHASSIS" ) );
1017}
1018
1019
1020BOOST_AUTO_TEST_CASE( PowerSymbol_SupplyVariants )
1021{
1027 BOOST_CHECK( PADS_SCH::PADS_SCH_SYMBOL_BUILDER::IsPowerSymbol( "VBAT" ) );
1028 BOOST_CHECK( PADS_SCH::PADS_SCH_SYMBOL_BUILDER::IsPowerSymbol( "VBUS" ) );
1031}
1032
1033
1034BOOST_AUTO_TEST_CASE( PowerSymbol_VoltagePatterns )
1035{
1037 BOOST_CHECK( PADS_SCH::PADS_SCH_SYMBOL_BUILDER::IsPowerSymbol( "+3V3" ) );
1038 BOOST_CHECK( PADS_SCH::PADS_SCH_SYMBOL_BUILDER::IsPowerSymbol( "+12V" ) );
1039 BOOST_CHECK( PADS_SCH::PADS_SCH_SYMBOL_BUILDER::IsPowerSymbol( "-12V" ) );
1040 BOOST_CHECK( PADS_SCH::PADS_SCH_SYMBOL_BUILDER::IsPowerSymbol( "+1V8" ) );
1041 BOOST_CHECK( PADS_SCH::PADS_SCH_SYMBOL_BUILDER::IsPowerSymbol( "+24V" ) );
1042}
1043
1044
1045BOOST_AUTO_TEST_CASE( PowerSymbol_NonPower )
1046{
1049 BOOST_CHECK( !PADS_SCH::PADS_SCH_SYMBOL_BUILDER::IsPowerSymbol( "NET1" ) );
1050 BOOST_CHECK( !PADS_SCH::PADS_SCH_SYMBOL_BUILDER::IsPowerSymbol( "DATA" ) );
1051 BOOST_CHECK( !PADS_SCH::PADS_SCH_SYMBOL_BUILDER::IsPowerSymbol( "CLK" ) );
1052 BOOST_CHECK( !PADS_SCH::PADS_SCH_SYMBOL_BUILDER::IsPowerSymbol( "RESET" ) );
1053}
1054
1055
1056BOOST_AUTO_TEST_CASE( PowerSymbol_KiCadMapping_Ground )
1057{
1059 BOOST_REQUIRE( gnd.has_value() );
1060 BOOST_CHECK_EQUAL( gnd->GetLibNickname().wx_str(), "power" );
1061 BOOST_CHECK_EQUAL( gnd->GetLibItemName().wx_str(), "GND" );
1062
1064 BOOST_REQUIRE( agnd.has_value() );
1065 BOOST_CHECK_EQUAL( agnd->GetLibItemName().wx_str(), "GND" );
1066
1068 BOOST_REQUIRE( dgnd.has_value() );
1069 BOOST_CHECK_EQUAL( dgnd->GetLibItemName().wx_str(), "GNDD" );
1070}
1071
1072
1073BOOST_AUTO_TEST_CASE( PowerSymbol_KiCadMapping_Supply )
1074{
1076 BOOST_REQUIRE( vcc.has_value() );
1077 BOOST_CHECK_EQUAL( vcc->GetLibNickname().wx_str(), "power" );
1078 BOOST_CHECK_EQUAL( vcc->GetLibItemName().wx_str(), "VCC" );
1079
1081 BOOST_REQUIRE( vdd.has_value() );
1082 BOOST_CHECK_EQUAL( vdd->GetLibItemName().wx_str(), "VDD" );
1083
1085 BOOST_REQUIRE( v5.has_value() );
1086 BOOST_CHECK_EQUAL( v5->GetLibItemName().wx_str(), "+5V" );
1087}
1088
1089
1090BOOST_AUTO_TEST_CASE( PowerSymbol_KiCadMapping_NotFound )
1091{
1093 BOOST_CHECK( !notPower.has_value() );
1094
1096 BOOST_CHECK( !notPower2.has_value() );
1097}
1098
1099
1100BOOST_AUTO_TEST_CASE( PowerSymbol_KiCadMapping_GenericFallback )
1101{
1102 // +V* names not in the explicit table should fall back to VCC
1104 BOOST_REQUIRE( plusV.has_value() );
1105 BOOST_CHECK_EQUAL( plusV->GetLibItemName().wx_str(), "VCC" );
1106
1108 BOOST_REQUIRE( plusV7.has_value() );
1109 BOOST_CHECK_EQUAL( plusV7->GetLibItemName().wx_str(), "VCC" );
1110
1111 // -V* names should fall back to VEE
1113 BOOST_REQUIRE( minusV.has_value() );
1114 BOOST_CHECK_EQUAL( minusV->GetLibItemName().wx_str(), "VEE" );
1115}
1116
1117
1118BOOST_AUTO_TEST_CASE( PowerSymbol_CaseInsensitive )
1119{
1121 BOOST_REQUIRE( gndLower.has_value() );
1122 BOOST_CHECK_EQUAL( gndLower->GetLibItemName().wx_str(), "GND" );
1123
1125 BOOST_REQUIRE( vccMixed.has_value() );
1126 BOOST_CHECK_EQUAL( vccMixed->GetLibItemName().wx_str(), "VCC" );
1127}
1128
1129
1130BOOST_AUTO_TEST_CASE( BuildKiCadPowerSymbol_Styles )
1131{
1132 PADS_SCH::PARAMETERS params;
1134 PADS_SCH::PADS_SCH_SYMBOL_BUILDER builder( params );
1135
1136 std::unique_ptr<LIB_SYMBOL> gnd( builder.BuildKiCadPowerSymbol( "GND" ) );
1137 BOOST_REQUIRE( gnd != nullptr );
1138 BOOST_CHECK( gnd->IsPower() );
1139 BOOST_CHECK_EQUAL( gnd->GetName(), "GND" );
1140
1141 std::unique_ptr<LIB_SYMBOL> vcc( builder.BuildKiCadPowerSymbol( "VCC" ) );
1142 BOOST_REQUIRE( vcc != nullptr );
1143 BOOST_CHECK( vcc->IsPower() );
1144 BOOST_CHECK_EQUAL( vcc->GetName(), "VCC" );
1145
1146 // VEE style: inverted arrow, pin facing down
1147 std::unique_ptr<LIB_SYMBOL> vee( builder.BuildKiCadPowerSymbol( "VEE" ) );
1148 BOOST_REQUIRE( vee != nullptr );
1149 BOOST_CHECK( vee->IsPower() );
1150
1151 // GNDD style: thick bar ground
1152 std::unique_ptr<LIB_SYMBOL> gndd( builder.BuildKiCadPowerSymbol( "GNDD" ) );
1153 BOOST_REQUIRE( gndd != nullptr );
1154 BOOST_CHECK( gndd->IsPower() );
1155
1156 // Earth style: descending bars
1157 std::unique_ptr<LIB_SYMBOL> earth( builder.BuildKiCadPowerSymbol( "Earth" ) );
1158 BOOST_REQUIRE( earth != nullptr );
1159 BOOST_CHECK( earth->IsPower() );
1160
1161 // PWR_BAR style: thick bar pointing up (for positive rail symbols like +V1)
1162 std::unique_ptr<LIB_SYMBOL> pwrBar( builder.BuildKiCadPowerSymbol( "PWR_BAR" ) );
1163 BOOST_REQUIRE( pwrBar != nullptr );
1164 BOOST_CHECK( pwrBar->IsPower() );
1165
1166 // PWR_TRIANGLE style: filled triangle pointing up (for arrow symbols like +V2)
1167 std::unique_ptr<LIB_SYMBOL> pwrTri( builder.BuildKiCadPowerSymbol( "PWR_TRIANGLE" ) );
1168 BOOST_REQUIRE( pwrTri != nullptr );
1169 BOOST_CHECK( pwrTri->IsPower() );
1170
1171 // Verify each symbol has exactly one pin
1172 BOOST_CHECK_EQUAL( gnd->GetPins().size(), 1u );
1173 BOOST_CHECK_EQUAL( vcc->GetPins().size(), 1u );
1174 BOOST_CHECK_EQUAL( vee->GetPins().size(), 1u );
1175 BOOST_CHECK_EQUAL( gndd->GetPins().size(), 1u );
1176 BOOST_CHECK_EQUAL( earth->GetPins().size(), 1u );
1177 BOOST_CHECK_EQUAL( pwrBar->GetPins().size(), 1u );
1178 BOOST_CHECK_EQUAL( pwrTri->GetPins().size(), 1u );
1179 BOOST_CHECK( !gnd->GetReferenceField().IsVisible() );
1180 BOOST_CHECK( !vcc->GetReferenceField().IsVisible() );
1181
1182 size_t gndShapes = 0;
1183 size_t vccCircles = 0;
1184
1185 for( const SCH_ITEM& item : gnd->GetDrawItems() )
1186 gndShapes += item.Type() == SCH_SHAPE_T;
1187
1188 for( const SCH_ITEM& item : vcc->GetDrawItems() )
1189 {
1190 vccCircles += item.Type() == SCH_SHAPE_T && static_cast<const SCH_SHAPE&>( item ).GetShape() == SHAPE_T::CIRCLE;
1191 }
1192
1193 BOOST_CHECK_EQUAL( gndShapes, 4u );
1194 BOOST_CHECK_EQUAL( vccCircles, 1u );
1195}
1196
1197
1198BOOST_AUTO_TEST_CASE( PowerStyleFromVariant )
1199{
1201
1202 // Ground variants
1203 BOOST_CHECK_EQUAL( PADS_SCH_SYMBOL_BUILDER::GetPowerStyleFromVariant( "GND", "G" ), "GND" );
1204 BOOST_CHECK_EQUAL( PADS_SCH_SYMBOL_BUILDER::GetPowerStyleFromVariant( "AGND", "G" ), "GND" );
1205 BOOST_CHECK_EQUAL( PADS_SCH_SYMBOL_BUILDER::GetPowerStyleFromVariant( "CHGND", "G" ), "Chassis" );
1206
1207 // Rail variants (thick bar)
1208 BOOST_CHECK_EQUAL( PADS_SCH_SYMBOL_BUILDER::GetPowerStyleFromVariant( "+RAIL", "P" ), "PWR_BAR" );
1209 BOOST_CHECK_EQUAL( PADS_SCH_SYMBOL_BUILDER::GetPowerStyleFromVariant( "-RAIL", "P" ), "GNDD" );
1210
1211 // Arrow variants (filled triangle)
1212 BOOST_CHECK_EQUAL( PADS_SCH_SYMBOL_BUILDER::GetPowerStyleFromVariant( "+ARROW", "P" ), "PWR_TRIANGLE" );
1213 BOOST_CHECK_EQUAL( PADS_SCH_SYMBOL_BUILDER::GetPowerStyleFromVariant( "-ARROW", "P" ), "VEE" );
1214
1215 // Bubble variants (map to VCC/VEE)
1216 BOOST_CHECK_EQUAL( PADS_SCH_SYMBOL_BUILDER::GetPowerStyleFromVariant( "+BUBBLE", "P" ), "VCC" );
1217 BOOST_CHECK_EQUAL( PADS_SCH_SYMBOL_BUILDER::GetPowerStyleFromVariant( "-BUBBLE", "P" ), "VEE" );
1218}
1219
1220
1221BOOST_AUTO_TEST_CASE( SheetCount_SingleSheet )
1222{
1223 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/simple_schematic.txt";
1224
1226 BOOST_REQUIRE( parser.Parse( testFile ) );
1227
1228 // Simple schematic with no parts defaults to 1 sheet
1229 BOOST_CHECK_EQUAL( parser.GetSheetCount(), 1 );
1230}
1231
1232
1233BOOST_AUTO_TEST_CASE( SheetNumbers_FromParts )
1234{
1235 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/parts_schematic.txt";
1236
1238 BOOST_REQUIRE( parser.Parse( testFile ) );
1239
1240 std::set<int> sheets = parser.GetSheetNumbers();
1241 BOOST_CHECK( sheets.count( 1 ) > 0 ); // At least sheet 1 should exist
1242}
1243
1244
1245BOOST_AUTO_TEST_CASE( GetPartsOnSheet )
1246{
1247 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/parts_schematic.txt";
1248
1250 BOOST_REQUIRE( parser.Parse( testFile ) );
1251
1252 std::vector<PADS_SCH::PART_PLACEMENT> partsOnSheet1 = parser.GetPartsOnSheet( 1 );
1253
1254 // All parts in test file should be on sheet 1
1255 BOOST_CHECK_EQUAL( partsOnSheet1.size(), parser.GetPartPlacements().size() );
1256}
1257
1258
1259BOOST_AUTO_TEST_CASE( GetSignalsOnSheet )
1260{
1261 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/signals_schematic.txt";
1262
1264 BOOST_REQUIRE( parser.Parse( testFile ) );
1265
1266 std::vector<PADS_SCH::SCH_SIGNAL> signalsOnSheet1 = parser.GetSignalsOnSheet( 1 );
1267
1268 // All signals in test file should have wires on sheet 1
1269 BOOST_CHECK( signalsOnSheet1.size() > 0 );
1270}
1271
1272
1273BOOST_AUTO_TEST_CASE( ParsePartTypes_V52_RegularPart_MultipleDecals )
1274{
1275 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/v52_parttypes.txt";
1276
1278
1279 BOOST_REQUIRE( parser.Parse( testFile ) );
1280 BOOST_CHECK( parser.IsValid() );
1281
1282 const auto& partTypes = parser.GetPartTypes();
1283
1284 // RES0805 should be parsed with G: gate format
1285 auto it = partTypes.find( "RES0805" );
1286 BOOST_REQUIRE( it != partTypes.end() );
1287
1288 const PADS_SCH::PARTTYPE_DEF& res = it->second;
1289 BOOST_CHECK_EQUAL( res.category, "RES" );
1290 BOOST_REQUIRE_EQUAL( res.gates.size(), 1 );
1291
1292 const PADS_SCH::GATE_DEF& resGate = res.gates[0];
1294 BOOST_CHECK_EQUAL( resGate.num_pins, 2 );
1295 BOOST_CHECK_EQUAL( resGate.swap_flag, 0 );
1296
1297 // Decal names parsed from colon-separated G: field
1298 BOOST_REQUIRE_EQUAL( resGate.decal_names.size(), 4 );
1299 BOOST_CHECK_EQUAL( resGate.decal_names[0], "RESZ-H" );
1300 BOOST_CHECK_EQUAL( resGate.decal_names[1], "RESZ-V" );
1301 BOOST_CHECK_EQUAL( resGate.decal_names[2], "RESB-H" );
1302 BOOST_CHECK_EQUAL( resGate.decal_names[3], "RESB-V" );
1303
1304 // Pin definitions from dot-separated tokens
1305 BOOST_REQUIRE_EQUAL( resGate.pins.size(), 2 );
1306 BOOST_CHECK_EQUAL( resGate.pins[0].pin_id, "1" );
1307 BOOST_CHECK_EQUAL( resGate.pins[0].swap_group, 1 );
1308 BOOST_CHECK_EQUAL( resGate.pins[0].pin_type, 'U' );
1309 BOOST_CHECK_EQUAL( resGate.pins[1].pin_id, "2" );
1310 BOOST_CHECK_EQUAL( resGate.pins[1].swap_group, 1 );
1311}
1312
1313
1314BOOST_AUTO_TEST_CASE( ParsePartTypes_V52_MultiGatePart )
1315{
1316 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/v52_parttypes.txt";
1317
1319
1320 BOOST_REQUIRE( parser.Parse( testFile ) );
1321
1322 const auto& partTypes = parser.GetPartTypes();
1323
1324 auto it = partTypes.find( "PS2802-4-A" );
1325 BOOST_REQUIRE( it != partTypes.end() );
1326
1327 const PADS_SCH::PARTTYPE_DEF& ps = it->second;
1328 BOOST_CHECK_EQUAL( ps.category, "SOP" );
1329 BOOST_REQUIRE_EQUAL( ps.gates.size(), 4 );
1330
1331 // Each gate should have 4 pins and reference the PS2802 decal
1332 for( int g = 0; g < 4; g++ )
1333 {
1334 BOOST_CHECK_EQUAL( ps.gates[g].num_pins, 4 );
1335 BOOST_REQUIRE_GE( ps.gates[g].decal_names.size(), 1 );
1336 BOOST_CHECK_EQUAL( ps.gates[g].decal_names[0], "PS2802" );
1337 }
1338
1339 // Verify specific pin names from first gate (AN, CATH, EMIT, COL)
1340 BOOST_REQUIRE_EQUAL( ps.gates[0].pins.size(), 4 );
1341 BOOST_CHECK_EQUAL( ps.gates[0].pins[0].pin_id, "1" );
1342 BOOST_CHECK_EQUAL( ps.gates[0].pins[0].pin_name, "AN" );
1343 BOOST_CHECK_EQUAL( ps.gates[0].pins[1].pin_id, "2" );
1344 BOOST_CHECK_EQUAL( ps.gates[0].pins[1].pin_name, "CATH" );
1345 BOOST_CHECK_EQUAL( ps.gates[0].pins[2].pin_id, "15" );
1346 BOOST_CHECK_EQUAL( ps.gates[0].pins[2].pin_name, "EMIT" );
1347 BOOST_CHECK_EQUAL( ps.gates[0].pins[3].pin_id, "16" );
1348 BOOST_CHECK_EQUAL( ps.gates[0].pins[3].pin_name, "COL" );
1349}
1350
1351
1352BOOST_AUTO_TEST_CASE( ParsePartTypes_V52_Connector )
1353{
1354 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/v52_parttypes.txt";
1355
1357
1358 BOOST_REQUIRE( parser.Parse( testFile ) );
1359
1360 const auto& partTypes = parser.GetPartTypes();
1361
1362 auto it = partTypes.find( "43650-0400" );
1363 BOOST_REQUIRE( it != partTypes.end() );
1364
1365 const PADS_SCH::PARTTYPE_DEF& conn = it->second;
1366 BOOST_CHECK_EQUAL( conn.category, "CON" );
1367 BOOST_CHECK( conn.is_connector );
1368 BOOST_REQUIRE_EQUAL( conn.gates.size(), 1 );
1369 BOOST_CHECK_EQUAL( conn.gates[0].num_pins, 4 );
1370 BOOST_REQUIRE_EQUAL( conn.gates[0].pins.size(), 4 );
1371
1372 // Connector pins should have S type
1373 for( int p = 0; p < 4; p++ )
1374 {
1375 BOOST_CHECK_EQUAL( conn.gates[0].pins[p].pin_type, 'S' );
1376 }
1377}
1378
1379
1380BOOST_AUTO_TEST_CASE( ParsePartTypes_V52_SpecialSymbols )
1381{
1382 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/v52_parttypes.txt";
1383
1385
1386 BOOST_REQUIRE( parser.Parse( testFile ) );
1387
1388 const auto& partTypes = parser.GetPartTypes();
1389
1390 // $GND_SYMS
1391 auto gndIt = partTypes.find( "$GND_SYMS" );
1392 BOOST_REQUIRE( gndIt != partTypes.end() );
1393
1394 const PADS_SCH::PARTTYPE_DEF& gnd = gndIt->second;
1395 BOOST_CHECK_EQUAL( gnd.special_keyword, "GND" );
1396 BOOST_CHECK_EQUAL( gnd.gates.size(), 2 );
1397 BOOST_REQUIRE_EQUAL( gnd.special_variants.size(), 2 );
1398 BOOST_CHECK_EQUAL( gnd.special_variants[0].decal_name, "DGND" );
1399 BOOST_CHECK_EQUAL( gnd.special_variants[0].pin_type, "G" );
1400 BOOST_CHECK_EQUAL( gnd.special_variants[1].decal_name, "PWRGND" );
1401
1402 // V5.2 SIGPIN entries
1403 BOOST_REQUIRE_EQUAL( gnd.sigpins.size(), 2 );
1404 BOOST_CHECK_EQUAL( gnd.sigpins[0].pin_number, "1" );
1405 BOOST_CHECK_EQUAL( gnd.sigpins[0].net_name, "DGND" );
1406 BOOST_CHECK_EQUAL( gnd.sigpins[1].pin_number, "2" );
1407 BOOST_CHECK_EQUAL( gnd.sigpins[1].net_name, "PWRGND" );
1408
1409 // $PWR_SYMS
1410 auto pwrIt = partTypes.find( "$PWR_SYMS" );
1411 BOOST_REQUIRE( pwrIt != partTypes.end() );
1412
1413 const PADS_SCH::PARTTYPE_DEF& pwr = pwrIt->second;
1414 BOOST_CHECK_EQUAL( pwr.special_keyword, "PWR" );
1415 BOOST_CHECK_EQUAL( pwr.gates.size(), 2 );
1416 BOOST_REQUIRE_EQUAL( pwr.special_variants.size(), 2 );
1417 BOOST_CHECK_EQUAL( pwr.special_variants[0].decal_name, "+5V" );
1418 BOOST_CHECK_EQUAL( pwr.special_variants[0].pin_type, "P" );
1419
1420 BOOST_REQUIRE_EQUAL( pwr.sigpins.size(), 2 );
1421 BOOST_CHECK_EQUAL( pwr.sigpins[0].net_name, "+5V" );
1422}
1423
1424
1425BOOST_AUTO_TEST_CASE( ParsePartTypes_V52_SimplePart )
1426{
1427 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/v52_parttypes.txt";
1428
1430
1431 BOOST_REQUIRE( parser.Parse( testFile ) );
1432
1433 const auto& partTypes = parser.GetPartTypes();
1434
1435 // MMSZ5260BT1 should map to ZENER decal
1436 auto it = partTypes.find( "MMSZ5260BT1" );
1437 BOOST_REQUIRE( it != partTypes.end() );
1438
1439 const PADS_SCH::PARTTYPE_DEF& diode = it->second;
1440 BOOST_CHECK_EQUAL( diode.category, "DIO" );
1441 BOOST_REQUIRE_EQUAL( diode.gates.size(), 1 );
1442 BOOST_REQUIRE_EQUAL( diode.gates[0].decal_names.size(), 1 );
1443 BOOST_CHECK_EQUAL( diode.gates[0].decal_names[0], "ZENER" );
1444 BOOST_CHECK_EQUAL( diode.gates[0].num_pins, 2 );
1445 BOOST_REQUIRE_EQUAL( diode.gates[0].pins.size(), 2 );
1446}
1447
1448
1449BOOST_AUTO_TEST_CASE( SymbolBuilder_ConnectorPinSymbol )
1450{
1451 PADS_SCH::PARAMETERS params;
1453 PADS_SCH::PADS_SCH_SYMBOL_BUILDER builder( params );
1454
1455 // Create a minimal connector PARTTYPE and symbol def
1457 connPt.name = "TEST_CONN";
1458 connPt.is_connector = true;
1459 connPt.category = "CON";
1460
1461 PADS_SCH::GATE_DEF gate;
1462 gate.num_pins = 1;
1463 gate.decal_names.push_back( "EXTIN" );
1464
1466 pin.pin_id = "1";
1467 pin.pin_type = 'S';
1468 gate.pins.push_back( pin );
1469 connPt.gates.push_back( gate );
1470
1471 PADS_SCH::SYMBOL_DEF symDef;
1472 symDef.name = "EXTIN";
1473 symDef.gate_count = 1;
1474
1475 PADS_SCH::SYMBOL_PIN symPin;
1476 symPin.number = "1";
1477 symPin.position.x = 0;
1478 symPin.position.y = 0;
1479 symPin.length = 100;
1480 symDef.pins.push_back( symPin );
1481
1482 // Pin 15 variant should have pin number "15"
1483 LIB_SYMBOL* sym15 = builder.GetOrCreateConnectorPinSymbol( connPt, symDef, "15" );
1484 BOOST_REQUIRE( sym15 != nullptr );
1485
1486 auto pins15 = sym15->GetPins();
1487 BOOST_REQUIRE_EQUAL( pins15.size(), 1u );
1488 BOOST_CHECK_EQUAL( pins15[0]->GetNumber(), "15" );
1489
1490 // Pin 1 variant should have pin number "1"
1491 LIB_SYMBOL* sym1 = builder.GetOrCreateConnectorPinSymbol( connPt, symDef, "1" );
1492 BOOST_REQUIRE( sym1 != nullptr );
1493
1494 auto pins1 = sym1->GetPins();
1495 BOOST_REQUIRE_EQUAL( pins1.size(), 1u );
1496 BOOST_CHECK_EQUAL( pins1[0]->GetNumber(), "1" );
1497
1498 // Different pin numbers should produce different cached symbols
1499 BOOST_CHECK_NE( sym15, sym1 );
1500
1501 // Same pin number should return cached symbol
1502 LIB_SYMBOL* sym15again = builder.GetOrCreateConnectorPinSymbol( connPt, symDef, "15" );
1503 BOOST_CHECK_EQUAL( sym15, sym15again );
1504}
1505
1506
1507BOOST_AUTO_TEST_CASE( SymbolBuilder_MultiUnitConnectorSymbol )
1508{
1509 PADS_SCH::PARAMETERS params;
1511 PADS_SCH::PADS_SCH_SYMBOL_BUILDER builder( params );
1512
1514 connPt.name = "TEST_MULTICONN";
1515 connPt.is_connector = true;
1516 connPt.category = "CON";
1517
1518 PADS_SCH::GATE_DEF gate;
1519 gate.num_pins = 4;
1520 gate.decal_names.push_back( "EXTIN" );
1521
1522 for( int i = 1; i <= 4; i++ )
1523 {
1525 pin.pin_id = std::to_string( i );
1526 pin.pin_type = 'S';
1527 gate.pins.push_back( pin );
1528 }
1529
1530 connPt.gates.push_back( gate );
1531
1532 PADS_SCH::SYMBOL_DEF symDef;
1533 symDef.name = "EXTIN";
1534 symDef.gate_count = 1;
1535
1536 PADS_SCH::SYMBOL_PIN symPin;
1537 symPin.number = "1";
1538 symPin.position.x = 0;
1539 symPin.position.y = 0;
1540 symPin.length = 100;
1541 symDef.pins.push_back( symPin );
1542
1543 std::vector<std::string> pinNumbers = { "1", "2", "3", "4" };
1544 std::string cacheKey = "TEST_MULTICONN:conn:J1";
1545
1546 LIB_SYMBOL* multiSym = builder.GetOrCreateMultiUnitConnectorSymbol( connPt, symDef, pinNumbers, cacheKey );
1547 BOOST_REQUIRE( multiSym != nullptr );
1548
1549 BOOST_CHECK_EQUAL( multiSym->GetUnitCount(), 4 );
1550
1551 for( int unit = 1; unit <= 4; unit++ )
1552 {
1553 std::vector<SCH_PIN*> unitPins;
1554
1555 for( SCH_PIN* pin : multiSym->GetPins() )
1556 {
1557 if( pin->GetUnit() == unit )
1558 unitPins.push_back( pin );
1559 }
1560
1561 BOOST_REQUIRE_EQUAL( unitPins.size(), 1u );
1562 BOOST_CHECK_EQUAL( unitPins[0]->GetNumber(), std::to_string( unit ) );
1563 }
1564
1565 // Same cache key should return the same symbol
1566 LIB_SYMBOL* cached = builder.GetOrCreateMultiUnitConnectorSymbol( connPt, symDef, pinNumbers, cacheKey );
1567 BOOST_CHECK_EQUAL( multiSym, cached );
1568
1569 // Different cache key should produce a new symbol
1570 LIB_SYMBOL* other = builder.GetOrCreateMultiUnitConnectorSymbol( connPt, symDef, pinNumbers, "other_key" );
1571 BOOST_CHECK_NE( multiSym, other );
1572}
1573
1574
1576
1577
1578// Schematic Builder tests
1579#include <sch_io/pads/pads_sch_schematic_builder.h>
1581#include <sch_line.h>
1582#include <sch_label.h>
1583#include <sch_junction.h>
1584#include <sch_symbol.h>
1585#include <sch_screen.h>
1586#include <schematic.h>
1587#include <template_fieldnames.h>
1588#include <title_block.h>
1589
1590BOOST_AUTO_TEST_SUITE( PadsSchSchematicBuilder )
1591
1592
1593BOOST_AUTO_TEST_CASE( CreateWire_SingleSegment )
1594{
1595 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/simple_schematic.txt";
1596
1598 BOOST_REQUIRE( parser.Parse( testFile ) );
1599
1600 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( parser.GetParameters(), nullptr );
1601
1603 wire.start.x = 1000.0;
1604 wire.start.y = 2000.0;
1605 wire.end.x = 3000.0;
1606 wire.end.y = 2000.0;
1607
1608 SCH_LINE* line = builder.CreateWire( wire );
1609 BOOST_REQUIRE( line != nullptr );
1610
1611 BOOST_CHECK( line->GetLayer() == LAYER_WIRE );
1612 BOOST_CHECK( line->GetStartPoint().x != 0 || line->GetStartPoint().y != 0 );
1613 BOOST_CHECK( line->GetEndPoint().x != 0 || line->GetEndPoint().y != 0 );
1614
1615 delete line;
1616}
1617
1618
1619BOOST_AUTO_TEST_CASE( CreateWire_FromSignals )
1620{
1621 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/signals_schematic.txt";
1622
1624 BOOST_REQUIRE( parser.Parse( testFile ) );
1625
1626 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( parser.GetParameters(), nullptr );
1627
1628 // Count total expected wires
1629 int expectedWires = 0;
1630
1631 for( const auto& signal : parser.GetSignals() )
1632 expectedWires += static_cast<int>( signal.wires.size() );
1633
1634 BOOST_CHECK( expectedWires > 0 );
1635}
1636
1637
1638BOOST_AUTO_TEST_CASE( CreateNetLabel_FromSignal )
1639{
1640 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/simple_schematic.txt";
1641
1643 BOOST_REQUIRE( parser.Parse( testFile ) );
1644
1645 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( parser.GetParameters(), nullptr );
1646
1647 PADS_SCH::SCH_SIGNAL signal;
1648 signal.name = "VCC";
1649
1651 wire.start.x = 1000.0;
1652 wire.start.y = 2000.0;
1653 wire.end.x = 3000.0;
1654 wire.end.y = 2000.0;
1655 signal.wires.push_back( wire );
1656
1657 VECTOR2I pos( 1000, 2000 );
1658 SCH_GLOBALLABEL* label = builder.CreateNetLabel( signal, pos );
1659 BOOST_REQUIRE( label != nullptr );
1660
1661 BOOST_CHECK_EQUAL( label->GetText(), "VCC" );
1662
1663 delete label;
1664}
1665
1666
1667BOOST_AUTO_TEST_CASE( CreateNetLabel_PreservesSpecialChars )
1668{
1669 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/simple_schematic.txt";
1670
1672 BOOST_REQUIRE( parser.Parse( testFile ) );
1673
1674 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( parser.GetParameters(), nullptr );
1675
1676 PADS_SCH::SCH_SIGNAL signal;
1677 signal.name = "NET 1";
1678
1679 VECTOR2I pos( 1000, 2000 );
1680 SCH_GLOBALLABEL* label = builder.CreateNetLabel( signal, pos );
1681 BOOST_REQUIRE( label != nullptr );
1682
1683 // Net names pass through unchanged; KiCad handles arbitrary UTF-8 net names
1684 BOOST_CHECK_EQUAL( label->GetText(), "NET 1" );
1685
1686 delete label;
1687}
1688
1689
1690BOOST_AUTO_TEST_CASE( IsBusSignal_BracketNotation )
1691{
1692 // Bus notation with brackets: NAME[n:m] or NAME[n..m]
1693 BOOST_CHECK( PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER::IsBusSignal( "DATA[7:0]" ) );
1694 BOOST_CHECK( PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER::IsBusSignal( "ADDR[15:0]" ) );
1695 BOOST_CHECK( PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER::IsBusSignal( "BUS[0..7]" ) );
1696 BOOST_CHECK( PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER::IsBusSignal( "D[31..0]" ) );
1697}
1698
1699
1700BOOST_AUTO_TEST_CASE( IsBusSignal_AngleNotation )
1701{
1702 // Bus notation with angle brackets: NAME<n:m>
1703 BOOST_CHECK( PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER::IsBusSignal( "DATA<7:0>" ) );
1704 BOOST_CHECK( PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER::IsBusSignal( "ADDR<15:0>" ) );
1705 BOOST_CHECK( PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER::IsBusSignal( "BUS<0..7>" ) );
1706}
1707
1708
1709BOOST_AUTO_TEST_CASE( IsBusSignal_NotABus )
1710{
1711 // Regular signal names that should not be detected as buses
1715 BOOST_CHECK( !PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER::IsBusSignal( "NET1" ) );
1716 BOOST_CHECK( !PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER::IsBusSignal( "DATA0" ) );
1718}
1719
1720
1721BOOST_AUTO_TEST_CASE( CreateBusWire_SingleSegment )
1722{
1723 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/simple_schematic.txt";
1724
1726 BOOST_REQUIRE( parser.Parse( testFile ) );
1727
1728 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( parser.GetParameters(), nullptr );
1729
1731 wire.start.x = 1000.0;
1732 wire.start.y = 2000.0;
1733 wire.end.x = 3000.0;
1734 wire.end.y = 2000.0;
1735
1736 SCH_LINE* line = builder.CreateBusWire( wire );
1737 BOOST_REQUIRE( line != nullptr );
1738
1739 BOOST_CHECK( line->GetLayer() == LAYER_BUS );
1740
1741 delete line;
1742}
1743
1744
1745BOOST_AUTO_TEST_CASE( ApplyPartAttributes_Reference )
1746{
1747 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/simple_schematic.txt";
1748
1750 BOOST_REQUIRE( parser.Parse( testFile ) );
1751
1752 // Create a test part placement
1753 PADS_SCH::PART_PLACEMENT placement;
1754 placement.reference = "R1";
1755 placement.part_type = "10K";
1756
1757 // Create a mock schematic for testing
1758 SCHEMATIC schematic( nullptr );
1759 schematic.Reset();
1760
1761 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( parser.GetParameters(), &schematic );
1762
1763 // Create a minimal symbol for testing
1764 LIB_SYMBOL* libSymbol = new LIB_SYMBOL( wxS( "TEST" ) );
1765 LIB_ID libId( wxS( "test" ), wxS( "TEST" ) );
1766
1767 SCH_SYMBOL* symbol = new SCH_SYMBOL( *libSymbol, libId, &schematic.CurrentSheet(), 0 );
1768
1769 builder.ApplyPartAttributes( symbol, placement );
1770
1771 // Verify reference was set
1772 wxString ref = symbol->GetRef( &schematic.CurrentSheet() );
1773 BOOST_CHECK_EQUAL( ref.ToStdString(), "R1" );
1774
1775 // Verify value was set from part_type
1776 BOOST_CHECK_EQUAL( symbol->GetField( FIELD_T::VALUE )->GetText().ToStdString(), "10K" );
1777
1778 delete symbol;
1779 delete libSymbol;
1780}
1781
1782
1783BOOST_AUTO_TEST_CASE( ApplyPartAttributes_Footprint )
1784{
1785 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/simple_schematic.txt";
1786
1788 BOOST_REQUIRE( parser.Parse( testFile ) );
1789
1790 PADS_SCH::PART_PLACEMENT placement;
1791 placement.reference = "C1";
1792 placement.part_type = "100nF";
1793
1794 // Add PCB DECAL attribute for footprint
1795 PADS_SCH::PART_ATTRIBUTE footprintAttr;
1796 footprintAttr.name = "PCB DECAL";
1797 footprintAttr.value = "CAP_0805";
1798 footprintAttr.visible = false;
1799 placement.attributes.push_back( footprintAttr );
1800
1801 SCHEMATIC schematic( nullptr );
1802 schematic.Reset();
1803
1804 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( parser.GetParameters(), &schematic );
1805
1806 LIB_SYMBOL* libSymbol = new LIB_SYMBOL( wxS( "CAP" ) );
1807 LIB_ID libId( wxS( "test" ), wxS( "CAP" ) );
1808
1809 SCH_SYMBOL* symbol = new SCH_SYMBOL( *libSymbol, libId, &schematic.CurrentSheet(), 0 );
1810
1811 builder.ApplyPartAttributes( symbol, placement );
1812
1813 // Verify footprint was set
1814 BOOST_CHECK_EQUAL( symbol->GetField( FIELD_T::FOOTPRINT )->GetText().ToStdString(), "CAP_0805" );
1815
1816 delete symbol;
1817 delete libSymbol;
1818}
1819
1820
1821BOOST_AUTO_TEST_CASE( ApplyFieldSettings_Visibility )
1822{
1823 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/simple_schematic.txt";
1824
1826 BOOST_REQUIRE( parser.Parse( testFile ) );
1827
1828 PADS_SCH::PART_PLACEMENT placement;
1829 placement.reference = "U1";
1830 placement.part_type = "74HC00";
1831
1832 // Add VALUE attribute with visibility=false
1833 PADS_SCH::PART_ATTRIBUTE valueAttr;
1834 valueAttr.name = "VALUE";
1835 valueAttr.value = "74HC00";
1836 valueAttr.visible = false;
1837 placement.attributes.push_back( valueAttr );
1838
1839 // Add REFDES attribute with visibility=true
1841 refAttr.name = "REFDES";
1842 refAttr.value = "U1";
1843 refAttr.visible = true;
1844 placement.attributes.push_back( refAttr );
1845
1846 SCHEMATIC schematic( nullptr );
1847 schematic.Reset();
1848
1849 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( parser.GetParameters(), &schematic );
1850
1851 LIB_SYMBOL* libSymbol = new LIB_SYMBOL( wxS( "74HC00" ) );
1852 LIB_ID libId( wxS( "test" ), wxS( "74HC00" ) );
1853
1854 SCH_SYMBOL* symbol = new SCH_SYMBOL( *libSymbol, libId, &schematic.CurrentSheet(), 0 );
1855
1856 builder.ApplyPartAttributes( symbol, placement );
1857
1858 // Verify visibility settings
1859 BOOST_CHECK( !symbol->GetField( FIELD_T::VALUE )->IsVisible() );
1860 BOOST_CHECK( symbol->GetField( FIELD_T::REFERENCE )->IsVisible() );
1861
1862 delete symbol;
1863 delete libSymbol;
1864}
1865
1866
1867BOOST_AUTO_TEST_CASE( ApplyPartAttributes_NullSymbol )
1868{
1869 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/simple_schematic.txt";
1870
1872 BOOST_REQUIRE( parser.Parse( testFile ) );
1873
1874 PADS_SCH::PART_PLACEMENT placement;
1875 placement.reference = "R1";
1876
1877 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( parser.GetParameters(), nullptr );
1878
1879 // Should not crash when called with nullptr
1880 builder.ApplyPartAttributes( nullptr, placement );
1881
1882 BOOST_CHECK( true ); // If we get here, we passed
1883}
1884
1885
1886BOOST_AUTO_TEST_CASE( CreateCustomFields_ManufacturerAndMPN )
1887{
1888 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/simple_schematic.txt";
1889
1891 BOOST_REQUIRE( parser.Parse( testFile ) );
1892
1893 PADS_SCH::PART_PLACEMENT placement;
1894 placement.reference = "U1";
1895 placement.part_type = "74HC00";
1896
1897 // Add manufacturer attribute (not a standard field)
1899 mfrAttr.name = "Manufacturer";
1900 mfrAttr.value = "Texas Instruments";
1901 mfrAttr.visible = false;
1902 placement.attributes.push_back( mfrAttr );
1903
1904 // Add MPN attribute (not a standard field)
1906 mpnAttr.name = "MPN";
1907 mpnAttr.value = "SN74HC00N";
1908 mpnAttr.visible = false;
1909 placement.attributes.push_back( mpnAttr );
1910
1911 SCHEMATIC schematic( nullptr );
1912 schematic.Reset();
1913
1914 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( parser.GetParameters(), &schematic );
1915
1916 LIB_SYMBOL* libSymbol = new LIB_SYMBOL( wxS( "74HC00" ) );
1917 LIB_ID libId( wxS( "test" ), wxS( "74HC00" ) );
1918
1919 SCH_SYMBOL* symbol = new SCH_SYMBOL( *libSymbol, libId, &schematic.CurrentSheet(), 0 );
1920
1921 int fieldsCreated = builder.CreateCustomFields( symbol, placement );
1922
1923 // Should have created 2 custom fields
1924 BOOST_CHECK_EQUAL( fieldsCreated, 2 );
1925
1926 // Find and verify the manufacturer field
1927 SCH_FIELD* mfrField = symbol->GetField( wxS( "Manufacturer" ) );
1928 BOOST_REQUIRE( mfrField != nullptr );
1929 BOOST_CHECK_EQUAL( mfrField->GetText().ToStdString(), "Texas Instruments" );
1930 BOOST_CHECK( !mfrField->IsVisible() );
1931
1932 // Find and verify the MPN field
1933 SCH_FIELD* mpnField = symbol->GetField( wxS( "MPN" ) );
1934 BOOST_REQUIRE( mpnField != nullptr );
1935 BOOST_CHECK_EQUAL( mpnField->GetText().ToStdString(), "SN74HC00N" );
1936
1937 delete symbol;
1938 delete libSymbol;
1939}
1940
1941
1942BOOST_AUTO_TEST_CASE( CreateCustomFields_SkipsStandardFields )
1943{
1944 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/simple_schematic.txt";
1945
1947 BOOST_REQUIRE( parser.Parse( testFile ) );
1948
1949 PADS_SCH::PART_PLACEMENT placement;
1950 placement.reference = "R1";
1951
1952 // Add standard field attributes (should be skipped by CreateCustomFields)
1954 refAttr.name = "Ref.Des."; // Standard field
1955 refAttr.value = "R1";
1956 placement.attributes.push_back( refAttr );
1957
1959 valAttr.name = "Part Type"; // Standard field
1960 valAttr.value = "10K";
1961 placement.attributes.push_back( valAttr );
1962
1963 // Add one non-standard field
1964 PADS_SCH::PART_ATTRIBUTE customAttr;
1965 customAttr.name = "Tolerance";
1966 customAttr.value = "5%";
1967 customAttr.visible = true;
1968 placement.attributes.push_back( customAttr );
1969
1970 SCHEMATIC schematic( nullptr );
1971 schematic.Reset();
1972
1973 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( parser.GetParameters(), &schematic );
1974
1975 LIB_SYMBOL* libSymbol = new LIB_SYMBOL( wxS( "RES" ) );
1976 LIB_ID libId( wxS( "test" ), wxS( "RES" ) );
1977
1978 SCH_SYMBOL* symbol = new SCH_SYMBOL( *libSymbol, libId, &schematic.CurrentSheet(), 0 );
1979
1980 int fieldsCreated = builder.CreateCustomFields( symbol, placement );
1981
1982 // Should have created only 1 custom field (Tolerance)
1983 BOOST_CHECK_EQUAL( fieldsCreated, 1 );
1984
1985 SCH_FIELD* tolField = symbol->GetField( wxS( "Tolerance" ) );
1986 BOOST_REQUIRE( tolField != nullptr );
1987 BOOST_CHECK_EQUAL( tolField->GetText().ToStdString(), "5%" );
1988 BOOST_CHECK( !tolField->IsVisible() );
1989
1990 delete symbol;
1991 delete libSymbol;
1992}
1993
1994
1995BOOST_AUTO_TEST_CASE( CreateCustomFields_SkipsEmptyValues )
1996{
1997 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/simple_schematic.txt";
1998
2000 BOOST_REQUIRE( parser.Parse( testFile ) );
2001
2002 PADS_SCH::PART_PLACEMENT placement;
2003 placement.reference = "U1";
2004
2005 // Add attribute with empty value
2006 PADS_SCH::PART_ATTRIBUTE emptyAttr;
2007 emptyAttr.name = "SerialNumber";
2008 emptyAttr.value = "";
2009 placement.attributes.push_back( emptyAttr );
2010
2011 // Add attribute with actual value
2012 PADS_SCH::PART_ATTRIBUTE validAttr;
2013 validAttr.name = "Revision";
2014 validAttr.value = "A";
2015 validAttr.visible = true;
2016 placement.attributes.push_back( validAttr );
2017
2018 SCHEMATIC schematic( nullptr );
2019 schematic.Reset();
2020
2021 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( parser.GetParameters(), &schematic );
2022
2023 LIB_SYMBOL* libSymbol = new LIB_SYMBOL( wxS( "IC" ) );
2024 LIB_ID libId( wxS( "test" ), wxS( "IC" ) );
2025
2026 SCH_SYMBOL* symbol = new SCH_SYMBOL( *libSymbol, libId, &schematic.CurrentSheet(), 0 );
2027
2028 int fieldsCreated = builder.CreateCustomFields( symbol, placement );
2029
2030 // Should have created only 1 field (Revision, not empty SerialNumber)
2031 BOOST_CHECK_EQUAL( fieldsCreated, 1 );
2032
2033 // Verify Revision field exists
2034 SCH_FIELD* revField = symbol->GetField( wxS( "Revision" ) );
2035 BOOST_REQUIRE( revField != nullptr );
2036 BOOST_CHECK_EQUAL( revField->GetText().ToStdString(), "A" );
2037
2038 // Verify SerialNumber field was NOT created
2039 SCH_FIELD* snField = symbol->GetField( wxS( "SerialNumber" ) );
2040 BOOST_CHECK( snField == nullptr );
2041
2042 delete symbol;
2043 delete libSymbol;
2044}
2045
2046
2047BOOST_AUTO_TEST_CASE( CreateTitleBlock_AllFields )
2048{
2049 PADS_SCH::PARAMETERS params;
2051 params.fields["Title"] = "Test Design";
2052 params.fields["DATE"] = "2025-01-12";
2053 params.fields["Revision"] = "A";
2054 params.fields["Company Name"] = "Test Company";
2055
2056 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( params, nullptr );
2057
2058 SCH_SCREEN screen;
2059
2060 builder.CreateTitleBlock( &screen );
2061
2062 const TITLE_BLOCK& tb = screen.GetTitleBlock();
2063
2064 BOOST_CHECK_EQUAL( tb.GetTitle().ToStdString(), "Test Design" );
2065 BOOST_CHECK_EQUAL( tb.GetDate().ToStdString(), "2025-01-12" );
2066 BOOST_CHECK_EQUAL( tb.GetRevision().ToStdString(), "A" );
2067 BOOST_CHECK_EQUAL( tb.GetCompany().ToStdString(), "Test Company" );
2068}
2069
2070
2071BOOST_AUTO_TEST_CASE( CreateTitleBlock_JobNameFallback )
2072{
2073 // Create parameters with job_name but no title
2074 PADS_SCH::PARAMETERS params;
2076 params.job_name = "My Project";
2077
2078 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( params, nullptr );
2079
2080 SCH_SCREEN screen;
2081
2082 builder.CreateTitleBlock( &screen );
2083
2084 const TITLE_BLOCK& tb = screen.GetTitleBlock();
2085
2086 // Title should fall back to job_name
2087 BOOST_CHECK_EQUAL( tb.GetTitle().ToStdString(), "My Project" );
2088}
2089
2090
2091BOOST_AUTO_TEST_CASE( CreateTitleBlock_EmptyFields )
2092{
2093 // Create empty parameters
2094 PADS_SCH::PARAMETERS params;
2096
2097 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( params, nullptr );
2098
2099 SCH_SCREEN screen;
2100
2101 builder.CreateTitleBlock( &screen );
2102
2103 const TITLE_BLOCK& tb = screen.GetTitleBlock();
2104
2105 // All fields should be empty
2106 BOOST_CHECK( tb.GetTitle().IsEmpty() );
2107 BOOST_CHECK( tb.GetDate().IsEmpty() );
2108 BOOST_CHECK( tb.GetRevision().IsEmpty() );
2109 BOOST_CHECK( tb.GetCompany().IsEmpty() );
2110}
2111
2112
2113BOOST_AUTO_TEST_CASE( CreateTitleBlock_NullScreen )
2114{
2115 PADS_SCH::PARAMETERS params;
2116 params.fields["Title"] = "Test";
2117
2118 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( params, nullptr );
2119
2120 // Should not crash with nullptr
2121 builder.CreateTitleBlock( nullptr );
2122
2123 BOOST_CHECK( true ); // If we get here, we passed
2124}
2125
2126
2128
2129
2130// Hierarchical sheet tests
2131#include <sch_sheet.h>
2132#include <sch_sheet_path.h>
2133#include <sch_sheet_pin.h>
2134
2135BOOST_AUTO_TEST_SUITE( PadsSchHierarchicalSheets )
2136
2137
2138BOOST_AUTO_TEST_CASE( GetDefaultSheetSize_ReturnsValidSize )
2139{
2140 PADS_SCH::PARAMETERS params;
2142
2143 SCHEMATIC schematic( nullptr );
2144 schematic.Reset();
2145
2146 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( params, &schematic );
2147
2148 VECTOR2I size = builder.GetDefaultSheetSize();
2149
2150 BOOST_CHECK( size.x > 0 );
2151 BOOST_CHECK( size.y > 0 );
2152}
2153
2154
2155BOOST_AUTO_TEST_CASE( CalculateSheetPosition_FirstSheet )
2156{
2157 PADS_SCH::PARAMETERS params;
2159
2160 SCHEMATIC schematic( nullptr );
2161 schematic.Reset();
2162
2163 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( params, &schematic );
2164
2165 VECTOR2I pos = builder.CalculateSheetPosition( 0, 4 );
2166
2167 BOOST_CHECK( pos.x > 0 );
2168 BOOST_CHECK( pos.y > 0 );
2169}
2170
2171
2172BOOST_AUTO_TEST_CASE( CalculateSheetPosition_GridLayout )
2173{
2174 PADS_SCH::PARAMETERS params;
2176
2177 SCHEMATIC schematic( nullptr );
2178 schematic.Reset();
2179
2180 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( params, &schematic );
2181
2182 VECTOR2I pos0 = builder.CalculateSheetPosition( 0, 4 );
2183 VECTOR2I pos1 = builder.CalculateSheetPosition( 1, 4 );
2184 VECTOR2I pos2 = builder.CalculateSheetPosition( 2, 4 );
2185 VECTOR2I pos3 = builder.CalculateSheetPosition( 3, 4 );
2186
2187 // For 4 sheets, should be 2x2 grid
2188 // pos0 and pos1 should be on same row (same Y)
2189 // pos0 and pos2 should be in same column (same X)
2190 BOOST_CHECK_EQUAL( pos0.y, pos1.y );
2191 BOOST_CHECK_EQUAL( pos2.y, pos3.y );
2192 BOOST_CHECK_EQUAL( pos0.x, pos2.x );
2193 BOOST_CHECK_EQUAL( pos1.x, pos3.x );
2194
2195 // Positions should increase going right and down
2196 BOOST_CHECK( pos1.x > pos0.x );
2197 BOOST_CHECK( pos2.y > pos0.y );
2198}
2199
2200
2201BOOST_AUTO_TEST_CASE( CreateHierarchicalSheet_ReturnsValidSheet )
2202{
2203 PADS_SCH::PARAMETERS params;
2205
2206 SCHEMATIC schematic( nullptr );
2207 schematic.Reset();
2208
2209 // Create root sheet
2210 SCH_SHEET* rootSheet = new SCH_SHEET( &schematic );
2211 SCH_SCREEN* rootScreen = new SCH_SCREEN( &schematic );
2212 rootSheet->SetScreen( rootScreen );
2213
2214 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( params, &schematic );
2215
2216 SCH_SHEET* sheet = builder.CreateHierarchicalSheet( 1, 3, rootSheet, wxT( "test_design.txt" ) );
2217 BOOST_REQUIRE( sheet != nullptr );
2218
2219 BOOST_CHECK( sheet->GetScreen() != nullptr );
2220
2221 // Verify sheet has valid position
2222 VECTOR2I pos = sheet->GetPosition();
2223 BOOST_CHECK( pos.x >= 0 );
2224 BOOST_CHECK( pos.y >= 0 );
2225
2226 // Verify sheet has valid size
2227 VECTOR2I size = sheet->GetSize();
2228 BOOST_CHECK( size.x > 0 );
2229 BOOST_CHECK( size.y > 0 );
2230
2231 delete rootSheet;
2232}
2233
2234
2235BOOST_AUTO_TEST_CASE( CreateHierarchicalSheet_SetsFilename )
2236{
2237 PADS_SCH::PARAMETERS params;
2239
2240 SCHEMATIC schematic( nullptr );
2241 schematic.Reset();
2242
2243 SCH_SHEET* rootSheet = new SCH_SHEET( &schematic );
2244 SCH_SCREEN* rootScreen = new SCH_SCREEN( &schematic );
2245 rootSheet->SetScreen( rootScreen );
2246
2247 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( params, &schematic );
2248
2249 SCH_SHEET* sheet = builder.CreateHierarchicalSheet( 2, 3, rootSheet, wxT( "my_design.asc" ) );
2250 BOOST_REQUIRE( sheet != nullptr );
2251
2252 // Verify sheet filename was set
2253 wxString filename = sheet->GetField( FIELD_T::SHEET_FILENAME )->GetText();
2254 BOOST_CHECK( filename.Contains( wxT( "my_design" ) ) );
2255 BOOST_CHECK( filename.Contains( wxT( "sheet2" ) ) );
2256 BOOST_CHECK( filename.EndsWith( wxT( ".kicad_sch" ) ) );
2257
2258 delete rootSheet;
2259}
2260
2261
2262BOOST_AUTO_TEST_CASE( CreateHierarchicalSheet_SetsSheetName )
2263{
2264 PADS_SCH::PARAMETERS params;
2266
2267 SCHEMATIC schematic( nullptr );
2268 schematic.Reset();
2269
2270 SCH_SHEET* rootSheet = new SCH_SHEET( &schematic );
2271 SCH_SCREEN* rootScreen = new SCH_SCREEN( &schematic );
2272 rootSheet->SetScreen( rootScreen );
2273
2274 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( params, &schematic );
2275
2276 SCH_SHEET* sheet = builder.CreateHierarchicalSheet( 3, 5, rootSheet, wxT( "design.txt" ) );
2277 BOOST_REQUIRE( sheet != nullptr );
2278
2279 // Verify sheet name was set
2280 wxString name = sheet->GetField( FIELD_T::SHEET_NAME )->GetText();
2281 BOOST_CHECK( name.Contains( wxT( "3" ) ) );
2282
2283 delete rootSheet;
2284}
2285
2286
2287BOOST_AUTO_TEST_CASE( CreateHierarchicalSheet_NullParent )
2288{
2289 PADS_SCH::PARAMETERS params;
2291
2292 SCHEMATIC schematic( nullptr );
2293 schematic.Reset();
2294
2295 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( params, &schematic );
2296
2297 // Should return nullptr when parent is null
2298 SCH_SHEET* sheet = builder.CreateHierarchicalSheet( 1, 3, nullptr, wxT( "test.txt" ) );
2299 BOOST_CHECK( sheet == nullptr );
2300}
2301
2302
2303BOOST_AUTO_TEST_CASE( CreateSheetPin_ValidPin )
2304{
2305 PADS_SCH::PARAMETERS params;
2307
2308 SCHEMATIC schematic( nullptr );
2309 schematic.Reset();
2310
2311 SCH_SHEET* sheet = new SCH_SHEET( &schematic );
2312 sheet->SetPosition( VECTOR2I( 1000, 2000 ) );
2313 sheet->SetSize( VECTOR2I( 3000, 2000 ) );
2314
2315 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( params, &schematic );
2316
2317 SCH_SHEET_PIN* pin = builder.CreateSheetPin( sheet, "NET1", 0 );
2318 BOOST_REQUIRE( pin != nullptr );
2319
2320 BOOST_CHECK_EQUAL( pin->GetText().ToStdString(), "NET1" );
2321 BOOST_CHECK( pin->GetSide() == SHEET_SIDE::LEFT );
2322
2323 delete sheet;
2324}
2325
2326
2327BOOST_AUTO_TEST_CASE( CreateSheetPin_PreservesName )
2328{
2329 PADS_SCH::PARAMETERS params;
2331
2332 SCHEMATIC schematic( nullptr );
2333 schematic.Reset();
2334
2335 SCH_SHEET* sheet = new SCH_SHEET( &schematic );
2336
2337 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( params, &schematic );
2338
2339 SCH_SHEET_PIN* pin = builder.CreateSheetPin( sheet, "NET 1", 0 );
2340 BOOST_REQUIRE( pin != nullptr );
2341
2342 // Net names pass through unchanged; KiCad handles arbitrary UTF-8 net names
2343 BOOST_CHECK_EQUAL( pin->GetText().ToStdString(), "NET 1" );
2344
2345 delete sheet;
2346}
2347
2348
2349BOOST_AUTO_TEST_CASE( CreateSheetPin_NullSheet )
2350{
2351 PADS_SCH::PARAMETERS params;
2353
2354 SCHEMATIC schematic( nullptr );
2355 schematic.Reset();
2356
2357 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( params, &schematic );
2358
2359 SCH_SHEET_PIN* pin = builder.CreateSheetPin( nullptr, "NET1", 0 );
2360 BOOST_CHECK( pin == nullptr );
2361}
2362
2363
2364BOOST_AUTO_TEST_CASE( CreateHierLabel_ValidLabel )
2365{
2366 PADS_SCH::PARAMETERS params;
2368
2369 SCHEMATIC schematic( nullptr );
2370 schematic.Reset();
2371
2372 SCH_SCREEN screen;
2373
2374 PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER builder( params, &schematic );
2375
2376 VECTOR2I pos( 1000, 2000 );
2377 SCH_HIERLABEL* label = builder.CreateHierLabel( "DATA_OUT", pos, &screen );
2378 BOOST_REQUIRE( label != nullptr );
2379
2380 BOOST_CHECK_EQUAL( label->GetText().ToStdString(), "DATA_OUT" );
2381
2382 // Label should be added to screen
2383 BOOST_CHECK( screen.Items().size() > 0 );
2384}
2385
2386
2387BOOST_AUTO_TEST_CASE( IsGlobalSignal_PowerNets )
2388{
2389 std::set<int> singleSheet = { 1 };
2390
2391 BOOST_CHECK( PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER::IsGlobalSignal( "VCC", singleSheet ) );
2392 BOOST_CHECK( PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER::IsGlobalSignal( "GND", singleSheet ) );
2393 BOOST_CHECK( PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER::IsGlobalSignal( "vcc", singleSheet ) );
2394 BOOST_CHECK( PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER::IsGlobalSignal( "AGND", singleSheet ) );
2395 BOOST_CHECK( PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER::IsGlobalSignal( "+5V", singleSheet ) );
2396 BOOST_CHECK( PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER::IsGlobalSignal( "+3V3", singleSheet ) );
2397 BOOST_CHECK( PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER::IsGlobalSignal( "-12V", singleSheet ) );
2398}
2399
2400
2401BOOST_AUTO_TEST_CASE( IsGlobalSignal_MultiSheet )
2402{
2403 std::set<int> multiSheet = { 1, 2, 3 };
2404
2405 // Any signal on multiple sheets should be global
2406 BOOST_CHECK( PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER::IsGlobalSignal( "DATA_BUS", multiSheet ) );
2407 BOOST_CHECK( PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER::IsGlobalSignal( "RANDOM_NET", multiSheet ) );
2408}
2409
2410
2411BOOST_AUTO_TEST_CASE( IsGlobalSignal_NotGlobal )
2412{
2413 std::set<int> singleSheet = { 1 };
2414
2415 BOOST_CHECK( !PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER::IsGlobalSignal( "NET1", singleSheet ) );
2416 BOOST_CHECK( !PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER::IsGlobalSignal( "DATA", singleSheet ) );
2417 BOOST_CHECK( !PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER::IsGlobalSignal( "CLK", singleSheet ) );
2418 BOOST_CHECK( !PADS_SCH::PADS_SCH_SCHEMATIC_BUILDER::IsGlobalSignal( "", singleSheet ) );
2419}
2420
2421
2422// Issue 23855: a resistor Value attribute uses display flag 3 (name+value). The low
2423// bits select what is shown, so it must remain visible. Only the hidden bit (8) hides.
2424BOOST_AUTO_TEST_CASE( Issue23855_ValueVisibleWithDisplayFlag )
2425{
2426 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/issue23855_schematic.txt";
2427
2429 BOOST_REQUIRE( parser.Parse( testFile ) );
2430
2431 const PADS_SCH::PART_PLACEMENT* r1 = parser.GetPartPlacement( "R1" );
2432 BOOST_REQUIRE( r1 != nullptr );
2433
2434 bool foundValue = false;
2435
2436 for( const auto& attr : r1->attributes )
2437 {
2438 if( attr.name == "Value" )
2439 {
2440 // Display flag 3 (name+value) must stay visible.
2441 BOOST_CHECK( attr.visible );
2442 BOOST_CHECK_EQUAL( attr.justification, 6 );
2443 foundValue = true;
2444 }
2445 }
2446
2447 BOOST_CHECK( foundValue );
2448}
2449
2450
2451// Issue 23855: a "CN" category part type must be flagged as a connector so its pin
2452// numbers are shown, even when the gate is written in the V9 "GATE" format.
2453BOOST_AUTO_TEST_CASE( Issue23855_ConnectorCategoryFlagged )
2454{
2455 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/issue23855_schematic.txt";
2456
2458 BOOST_REQUIRE( parser.Parse( testFile ) );
2459
2460 auto ptIt = parser.GetPartTypes().find( "91-HDSKT10DH" );
2461 BOOST_REQUIRE( ptIt != parser.GetPartTypes().end() );
2462 BOOST_CHECK( ptIt->second.is_connector );
2463
2464 // A non-connector resistor must not be flagged.
2465 auto resIt = parser.GetPartTypes().find( "71=B2002.2" );
2466 BOOST_REQUIRE( resIt != parser.GetPartTypes().end() );
2467 BOOST_CHECK( !resIt->second.is_connector );
2468}
2469
2470
2471// Issue 23855: a connector part type symbol must show pin numbers even though its pins
2472// carry no pin names.
2473BOOST_AUTO_TEST_CASE( Issue23855_ConnectorShowsPinNumbers )
2474{
2475 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/issue23855_schematic.txt";
2476
2478 BOOST_REQUIRE( parser.Parse( testFile ) );
2479
2480 auto ptIt = parser.GetPartTypes().find( "91-HDSKT10DH" );
2481 BOOST_REQUIRE( ptIt != parser.GetPartTypes().end() );
2482
2483 const PADS_SCH::SYMBOL_DEF* symDef = parser.GetSymbolDef( "CONNECTOR-10P" );
2484 BOOST_REQUIRE( symDef != nullptr );
2485
2487 LIB_SYMBOL* connSym = builder.GetOrCreatePartTypeSymbol( ptIt->second, *symDef );
2488 BOOST_REQUIRE( connSym != nullptr );
2489 BOOST_CHECK( connSym->GetShowPinNumbers() );
2490
2491 // A resistor (non-connector, no pin names) keeps pin numbers off.
2492 auto resIt = parser.GetPartTypes().find( "71=B2002.2" );
2493 BOOST_REQUIRE( resIt != parser.GetPartTypes().end() );
2494
2495 const PADS_SCH::SYMBOL_DEF* resDef = parser.GetSymbolDef( "RESZ-H" );
2496 BOOST_REQUIRE( resDef != nullptr );
2497
2498 LIB_SYMBOL* resSym = builder.GetOrCreatePartTypeSymbol( resIt->second, *resDef );
2499 BOOST_REQUIRE( resSym != nullptr );
2500 BOOST_CHECK( !resSym->GetShowPinNumbers() );
2501}
2502
2503
2504// Issue 23855: the shared justification decoder maps PADS codes to KiCad alignment so
2505// reference and value fields keep their authored alignment instead of forcing center.
2506BOOST_AUTO_TEST_CASE( Issue23855_DecodeJustification )
2507{
2510
2511 // 0 = bottom-left
2515
2516 // 6 = top-center (band 2..7 -> top, code 6-2=4 -> center)
2520
2521 // 1 = bottom-right
2525
2526 // 12 = middle-center (band 8.. -> middle, code 12-8=4 -> center)
2530}
2531
2532
2533// Issue 23855: the parser must capture the *NETNAMES* offset/justification for each
2534// off-page anchor so the importer can orient global labels correctly, and must read the
2535// placed-frame attribute offsets of a 90 degree rotated part.
2536BOOST_AUTO_TEST_CASE( Issue23855_NetNamesAndRotatedAttributes )
2537{
2538 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/issue23855_schematic.txt";
2539
2541 BOOST_REQUIRE( parser.Parse( testFile ) );
2542
2543 // The SP1 net carries two off-page anchors with opposite X offsets, so its global
2544 // labels must take opposite orientations from the *NETNAMES* offsets. @@@O14 sits on
2545 // the CN1 side (positive offset) and @@@O22 on the R1 side (negative offset).
2546 const PADS_SCH::NETNAME_LABEL* o0 = nullptr;
2547 const PADS_SCH::NETNAME_LABEL* o1 = nullptr;
2548
2549 for( const auto& nn : parser.GetNetNameLabels() )
2550 {
2551 if( nn.anchor_ref == "@@@O14" )
2552 o0 = &nn;
2553 else if( nn.anchor_ref == "@@@O22" )
2554 o1 = &nn;
2555 }
2556
2557 BOOST_REQUIRE( o0 != nullptr );
2558 BOOST_REQUIRE( o1 != nullptr );
2559 BOOST_CHECK_GT( o0->x_offset, 0 );
2560 BOOST_CHECK_LT( o1->x_offset, 0 );
2561
2562 // The 90 degree rotated diode keeps its placed-frame attribute offsets and text angle.
2563 // PADS writes the named REF-DES and PART-TYPE labels rotated with the part, followed by
2564 // unnamed free-attribute slots ("*") that stay axis-aligned; only the named labels matter.
2565 const PADS_SCH::PART_PLACEMENT* d5 = parser.GetPartPlacement( "D5" );
2566 BOOST_REQUIRE( d5 != nullptr );
2567 BOOST_CHECK_EQUAL( d5->rotation, 90.0 );
2568
2569 bool foundRef = false;
2570 bool foundPartType = false;
2571
2572 for( const auto& attr : d5->attributes )
2573 {
2574 if( attr.name == "REF-DES" )
2575 {
2576 foundRef = true;
2577 BOOST_CHECK_EQUAL( attr.rotation, 90.0 );
2578 BOOST_CHECK_EQUAL( attr.position.x, 210 );
2579 BOOST_CHECK_EQUAL( attr.position.y, 230 );
2580 BOOST_CHECK_EQUAL( attr.justification, 4 );
2581 }
2582 else if( attr.name == "PART-TYPE" )
2583 {
2584 foundPartType = true;
2585 BOOST_CHECK_EQUAL( attr.rotation, 90.0 );
2586 BOOST_CHECK_EQUAL( attr.position.x, -70 );
2587 BOOST_CHECK_EQUAL( attr.position.y, 520 );
2588 BOOST_CHECK_EQUAL( attr.justification, 5 );
2589 }
2590 }
2591
2592 BOOST_CHECK( foundRef );
2593 BOOST_CHECK( foundPartType );
2594}
2595
2596// The gate decal is a lookup key. symbol_name is what the power-symbol and CAEDECAL-fallback
2597// consumers read as the part's identity, so it has to stay the part type.
2598BOOST_AUTO_TEST_CASE( PartPlacementKeepsPartTypeAndDecalApart )
2599{
2600 std::string testFile = KI_TEST::GetEeschemaTestDataDir() + "/plugins/pads/power_gate_decal.txt";
2601
2603
2604 BOOST_REQUIRE( parser.Parse( testFile ) );
2605
2606 const PADS_SCH::PART_PLACEMENT* vcc = parser.GetPartPlacement( "VCC1" );
2607 BOOST_REQUIRE( vcc != nullptr );
2608
2609 BOOST_CHECK_EQUAL( vcc->part_type, "+5V" );
2610 BOOST_CHECK_EQUAL( vcc->symbol_name, "+5V" );
2611 BOOST_CHECK_EQUAL( vcc->decal_name, "RES_0805" );
2612}
2613
2614
const char * name
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition eda_text.h:118
virtual bool IsVisible() const
Definition eda_text.h:226
size_t size() const
Return the number of items in the tree.
Definition sch_rtree.h:177
A logical library item identifier and consists of various portions much like a URI.
Definition lib_id.h:45
Define a library symbol object.
Definition lib_symbol.h:119
LIB_ITEMS_CONTAINER & GetDrawItems()
Return a reference to the draw item list.
Definition lib_symbol.h:832
wxString GetName() const override
Definition lib_symbol.h:181
std::vector< SCH_PIN * > GetPins() const override
int GetUnitCount() const override
Parser for PADS Logic ASCII schematic export files.
bool Parse(const std::string &aFileName)
const std::vector< NETNAME_LABEL > & GetNetNameLabels() const
const std::vector< BUS_DEF > & GetBuses() const
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
Builds KiCad schematic elements (wires, junctions, labels, fields, sheets) from parsed PADS data.
SCH_LINE * CreateWire(const WIRE_SEGMENT &aWire)
SCH_SHEET_PIN * CreateSheetPin(SCH_SHEET *aSheet, const std::string &aSignalName, int aPinIndex)
Create a sheet pin that connects to a hierarchical label in the sub-schematic.
void ApplyPartAttributes(SCH_SYMBOL *aSymbol, const PART_PLACEMENT &aPlacement)
Set reference, value, footprint and other fields on a symbol from a part placement.
void CreateTitleBlock(SCH_SCREEN *aScreen)
Set the title block from PADS fields, checking custom names too because PADS designs often leave the ...
VECTOR2I CalculateSheetPosition(int aSheetIndex, int aTotalSheets) const
Position a sheet symbol in a roughly square grid on the parent.
int CreateCustomFields(SCH_SYMBOL *aSymbol, const PART_PLACEMENT &aPlacement)
Create KiCad user fields for PADS attributes that have no standard-field mapping.
SCH_LINE * CreateBusWire(const WIRE_SEGMENT &aWire)
SCH_HIERLABEL * CreateHierLabel(const std::string &aSignalName, const VECTOR2I &aPosition, SCH_SCREEN *aScreen)
Create a hierarchical label that connects to a sheet pin on the parent.
SCH_GLOBALLABEL * CreateNetLabel(const SCH_SIGNAL &aSignal, const VECTOR2I &aPosition, SPIN_STYLE aOrientation=SPIN_STYLE::RIGHT)
Create a net label.
static bool IsGlobalSignal(const std::string &aSignalName, const std::set< int > &aSheetNumbers)
A signal is global when it spans multiple sheets or is a common power net.
SCH_SHEET * CreateHierarchicalSheet(int aSheetNumber, int aTotalSheets, SCH_SHEET *aParentSheet, const wxString &aBaseFilename)
Create a sub-sheet positioned on its parent and backed by its own screen.
static bool IsBusSignal(const std::string &aName)
Builds KiCad LIB_SYMBOL objects from parsed PADS symbol definitions.
bool HasSymbol(const std::string &aName) const
static std::optional< LIB_ID > GetKiCadPowerSymbolId(const std::string &aPadsName)
Map a PADS power symbol name to a KiCad power library LIB_ID, or nullopt if unmapped.
LIB_SYMBOL * BuildKiCadPowerSymbol(const std::string &aKiCadName)
Build a power symbol using hard-coded KiCad-standard graphics, or nullptr if the name is unrecognized...
static bool IsPowerSymbol(const std::string &aName)
LIB_SYMBOL * GetOrCreateSymbol(const SYMBOL_DEF &aSymbolDef)
Return the cached symbol for the given definition, building and caching it if needed.
LIB_SYMBOL * GetOrCreateConnectorPinSymbol(const PARTTYPE_DEF &aPartType, const SYMBOL_DEF &aSymbolDef, const std::string &aPinNumber)
Return a connector symbol variant carrying a specific pin number, since PADS connectors reuse one dec...
LIB_SYMBOL * GetOrCreateMultiUnitConnectorSymbol(const PARTTYPE_DEF &aPartType, const SYMBOL_DEF &aSymbolDef, const std::vector< std::string > &aPinNumbers, const std::string &aCacheKey)
Return the cached multi-unit connector symbol, building it if needed.
LIB_SYMBOL * BuildSymbol(const SYMBOL_DEF &aSymbolDef)
Build a KiCad LIB_SYMBOL from a PADS symbol definition.
LIB_SYMBOL * GetOrCreatePartTypeSymbol(const PARTTYPE_DEF &aPartType, const SYMBOL_DEF &aSymbolDef)
Return a single-gate symbol with PARTTYPE pin overrides applied at build time.
Holds all the data relating to one schematic.
Definition schematic.h:148
void Reset()
Initialize this schematic to a blank one, unloading anything existing.
SCH_SHEET_PATH & CurrentSheet() const
Definition schematic.h:303
virtual const wxString & GetText() const override
Return the string associated with the text object.
Definition sch_field.h:138
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:165
SCH_LAYER_ID GetLayer() const
Return the layer this item is on.
Definition sch_item.h:345
Segment description base class to describe items which have 2 end points (track, wire,...
Definition sch_line.h:39
VECTOR2I GetEndPoint() const
Definition sch_line.h:145
VECTOR2I GetStartPoint() const
Definition sch_line.h:136
EE_RTREE & Items()
Get the full RTree, usually for iterating.
Definition sch_screen.h:118
TITLE_BLOCK & GetTitleBlock()
Definition sch_screen.h:164
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:504
void SetScreen(SCH_SCREEN *aScreen)
Set the SCH_SCREEN associated with this sheet to aScreen.
Schematic symbol object.
Definition sch_symbol.h:75
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.
virtual bool GetShowPinNumbers() const
Definition symbol.h:171
Hold the information shown in the lower right corner of a plot, printout, or editing view.
Definition title_block.h:38
const wxString & GetCompany() const
Definition title_block.h:93
const wxString & GetRevision() const
Definition title_block.h:83
const wxString & GetDate() const
Definition title_block.h:73
const wxString & GetTitle() const
Definition title_block.h:60
@ LAYER_WIRE
Definition layer_ids.h:474
@ LAYER_BUS
Definition layer_ids.h:475
std::string GetEeschemaTestDataDir()
Get the configured location of Eeschema test data.
void DecodeJustification(int aJustification, GR_TEXT_H_ALIGN_T &aHJustify, GR_TEXT_V_ALIGN_T &aVJustify)
Decode a PADS text justification code into KiCad horizontal and vertical alignment.
@ PT_UNSPECIFIED
unknown electrical properties: creates always a warning when connected
Definition pin_type.h:41
Definition of the SCH_SHEET_PATH and SCH_SHEET_LIST classes for Eeschema.
std::vector< std::string > decal_names
std::vector< PARTTYPE_PIN > pins
std::map< std::string, std::string > fields
std::vector< GATE_DEF > gates
std::vector< SPECIAL_VARIANT > special_variants
std::vector< SIGPIN > sigpins
std::string symbol_name
The part type, which is also the power symbol's net name.
std::string decal_name
CAEDECAL the placed gate draws, empty when unresolved.
std::vector< PART_ATTRIBUTE > attributes
std::vector< PIN_CONNECTION > connections
std::vector< WIRE_SEGMENT > wires
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()
std::string path
KIBIS_PIN * pin1
KIBIS_PIN * pin
VECTOR3I res
BOOST_AUTO_TEST_CASE(CheckFileHeader_ValidLogicFile)
BOOST_TEST_CONTEXT("Test Clearance")
SHAPE_CIRCLE circle(c.m_circle_center, c.m_circle_radius)
BOOST_CHECK_EQUAL(result, "25.4")
VECTOR2I v5(-70, -70)
GR_TEXT_H_ALIGN_T
This is API surface mapped to common.types.HorizontalAlignment.
@ GR_TEXT_H_ALIGN_CENTER
@ GR_TEXT_H_ALIGN_RIGHT
@ GR_TEXT_H_ALIGN_LEFT
GR_TEXT_V_ALIGN_T
This is API surface mapped to common.types.VertialAlignment.
@ GR_TEXT_V_ALIGN_BOTTOM
@ GR_TEXT_V_ALIGN_CENTER
@ GR_TEXT_V_ALIGN_TOP
@ SCH_SHAPE_T
Definition typeinfo.h:145
@ SCH_PIN_T
Definition typeinfo.h:149
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683