KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_pads_part_structures.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2025 KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU 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
20#include <boost/test/unit_test.hpp>
21#include <sstream>
24
25using namespace PADS_IO;
26
27
28BOOST_AUTO_TEST_SUITE( PadsPartStructures )
29
30
31BOOST_AUTO_TEST_CASE( Part_DefaultConstruction )
32{
33 PART part;
34 BOOST_CHECK( part.name.empty() );
35 BOOST_CHECK( part.decal.empty() );
36 BOOST_CHECK( part.alternate_decals.empty() );
37 BOOST_CHECK( part.value.empty() );
38 BOOST_CHECK_EQUAL( part.rotation, 0.0 );
39 BOOST_CHECK_EQUAL( part.bottom_layer, false );
40 BOOST_CHECK_EQUAL( part.glued, false );
41}
42
43
44BOOST_AUTO_TEST_CASE( Part_SingleDecal )
45{
46 PART part;
47 part.decal = "DIP8";
48
49 BOOST_CHECK_EQUAL( part.decal, "DIP8" );
50 BOOST_CHECK( part.alternate_decals.empty() );
51}
52
53
54BOOST_AUTO_TEST_CASE( Part_AlternateDecals )
55{
56 PART part;
57 part.decal = "DIP8";
58 part.alternate_decals.push_back( "SOIC8" );
59 part.alternate_decals.push_back( "QFN8" );
60
61 BOOST_CHECK_EQUAL( part.decal, "DIP8" );
62 BOOST_REQUIRE_EQUAL( part.alternate_decals.size(), 2 );
63 BOOST_CHECK_EQUAL( part.alternate_decals[0], "SOIC8" );
64 BOOST_CHECK_EQUAL( part.alternate_decals[1], "QFN8" );
65}
66
67
68BOOST_AUTO_TEST_CASE( DecalStringSplit_SingleDecal )
69{
70 // Simulate what the parser does with a single decal
71 std::string decal_string = "RESISTOR_0603";
72
73 std::string primary;
74 std::vector<std::string> alternates;
75
76 size_t pos = 0;
77 size_t colon_pos = 0;
78 bool first = true;
79
80 while( ( colon_pos = decal_string.find( ':', pos ) ) != std::string::npos )
81 {
82 std::string decal_name = decal_string.substr( pos, colon_pos - pos );
83
84 if( first )
85 {
86 primary = decal_name;
87 first = false;
88 }
89 else
90 {
91 alternates.push_back( decal_name );
92 }
93
94 pos = colon_pos + 1;
95 }
96
97 std::string last_decal = decal_string.substr( pos );
98
99 if( first )
100 primary = last_decal;
101 else
102 alternates.push_back( last_decal );
103
104 BOOST_CHECK_EQUAL( primary, "RESISTOR_0603" );
105 BOOST_CHECK( alternates.empty() );
106}
107
108
109BOOST_AUTO_TEST_CASE( DecalStringSplit_TwoDecals )
110{
111 std::string decal_string = "DIP8:SOIC8";
112
113 std::string primary;
114 std::vector<std::string> alternates;
115
116 size_t pos = 0;
117 size_t colon_pos = 0;
118 bool first = true;
119
120 while( ( colon_pos = decal_string.find( ':', pos ) ) != std::string::npos )
121 {
122 std::string decal_name = decal_string.substr( pos, colon_pos - pos );
123
124 if( first )
125 {
126 primary = decal_name;
127 first = false;
128 }
129 else
130 {
131 alternates.push_back( decal_name );
132 }
133
134 pos = colon_pos + 1;
135 }
136
137 std::string last_decal = decal_string.substr( pos );
138
139 if( first )
140 primary = last_decal;
141 else
142 alternates.push_back( last_decal );
143
144 BOOST_CHECK_EQUAL( primary, "DIP8" );
145 BOOST_REQUIRE_EQUAL( alternates.size(), 1 );
146 BOOST_CHECK_EQUAL( alternates[0], "SOIC8" );
147}
148
149
150BOOST_AUTO_TEST_CASE( DecalStringSplit_ThreeDecals )
151{
152 std::string decal_string = "DIP8:SOIC8:QFN8";
153
154 std::string primary;
155 std::vector<std::string> alternates;
156
157 size_t pos = 0;
158 size_t colon_pos = 0;
159 bool first = true;
160
161 while( ( colon_pos = decal_string.find( ':', pos ) ) != std::string::npos )
162 {
163 std::string decal_name = decal_string.substr( pos, colon_pos - pos );
164
165 if( first )
166 {
167 primary = decal_name;
168 first = false;
169 }
170 else
171 {
172 alternates.push_back( decal_name );
173 }
174
175 pos = colon_pos + 1;
176 }
177
178 std::string last_decal = decal_string.substr( pos );
179
180 if( first )
181 primary = last_decal;
182 else
183 alternates.push_back( last_decal );
184
185 BOOST_CHECK_EQUAL( primary, "DIP8" );
186 BOOST_REQUIRE_EQUAL( alternates.size(), 2 );
187 BOOST_CHECK_EQUAL( alternates[0], "SOIC8" );
188 BOOST_CHECK_EQUAL( alternates[1], "QFN8" );
189}
190
191
192BOOST_AUTO_TEST_CASE( DecalStringSplit_ManyDecals )
193{
194 std::string decal_string = "PKG1:PKG2:PKG3:PKG4:PKG5";
195
196 std::string primary;
197 std::vector<std::string> alternates;
198
199 size_t pos = 0;
200 size_t colon_pos = 0;
201 bool first = true;
202
203 while( ( colon_pos = decal_string.find( ':', pos ) ) != std::string::npos )
204 {
205 std::string decal_name = decal_string.substr( pos, colon_pos - pos );
206
207 if( first )
208 {
209 primary = decal_name;
210 first = false;
211 }
212 else
213 {
214 alternates.push_back( decal_name );
215 }
216
217 pos = colon_pos + 1;
218 }
219
220 std::string last_decal = decal_string.substr( pos );
221
222 if( first )
223 primary = last_decal;
224 else
225 alternates.push_back( last_decal );
226
227 BOOST_CHECK_EQUAL( primary, "PKG1" );
228 BOOST_REQUIRE_EQUAL( alternates.size(), 4 );
229 BOOST_CHECK_EQUAL( alternates[0], "PKG2" );
230 BOOST_CHECK_EQUAL( alternates[1], "PKG3" );
231 BOOST_CHECK_EQUAL( alternates[2], "PKG4" );
232 BOOST_CHECK_EQUAL( alternates[3], "PKG5" );
233}
234
235
236BOOST_AUTO_TEST_CASE( Parameters_DefaultThermalSettings )
237{
238 PARAMETERS params;
239 BOOST_CHECK_CLOSE( params.thermal_line_width, 30.0, 0.001 );
240 BOOST_CHECK_CLOSE( params.thermal_smd_width, 20.0, 0.001 );
241 BOOST_CHECK_EQUAL( params.thermal_flags, 0 );
242 BOOST_CHECK_CLOSE( params.thermal_min_clearance, 5.0, 0.001 );
244}
245
246
247BOOST_AUTO_TEST_CASE( Parameters_CustomThermalSettings )
248{
249 PARAMETERS params;
250 params.thermal_line_width = 40.0;
251 params.thermal_smd_width = 25.0;
252 params.thermal_flags = 1024;
253 params.thermal_min_clearance = 10.0;
254 params.thermal_min_spokes = 6;
255
256 BOOST_CHECK_CLOSE( params.thermal_line_width, 40.0, 0.001 );
257 BOOST_CHECK_CLOSE( params.thermal_smd_width, 25.0, 0.001 );
258 BOOST_CHECK_EQUAL( params.thermal_flags, 1024 );
259 BOOST_CHECK_CLOSE( params.thermal_min_clearance, 10.0, 0.001 );
261}
262
263
264BOOST_AUTO_TEST_CASE( Pour_DefaultConstruction )
265{
266 POUR pour;
267 BOOST_CHECK( pour.net_name.empty() );
268 BOOST_CHECK_EQUAL( pour.layer, 0 );
269 BOOST_CHECK_EQUAL( pour.priority, 0 );
270 BOOST_CHECK_EQUAL( pour.width, 0.0 );
271 BOOST_CHECK( pour.points.empty() );
272 BOOST_CHECK_EQUAL( pour.is_cutout, false );
273 BOOST_CHECK( pour.owner_pour.empty() );
274}
275
276
277BOOST_AUTO_TEST_CASE( Pour_CutoutFlag )
278{
279 POUR outline;
280 outline.net_name = "GND";
281 outline.layer = 1;
282 outline.is_cutout = false;
283 outline.owner_pour = "POUR1";
284
285 POUR cutout;
286 cutout.net_name = "GND";
287 cutout.layer = 1;
288 cutout.is_cutout = true;
289 cutout.owner_pour = "POUR1";
290
291 BOOST_CHECK_EQUAL( outline.is_cutout, false );
292 BOOST_CHECK_EQUAL( cutout.is_cutout, true );
293 BOOST_CHECK_EQUAL( outline.owner_pour, cutout.owner_pour );
294}
295
296
297BOOST_AUTO_TEST_CASE( ReuseInstance_DefaultConstruction )
298{
299 REUSE_INSTANCE instance;
300 BOOST_CHECK( instance.instance_name.empty() );
301 BOOST_CHECK( instance.part_naming.empty() );
302 BOOST_CHECK( instance.net_naming.empty() );
303 BOOST_CHECK_EQUAL( instance.location.x, 0.0 );
304 BOOST_CHECK_EQUAL( instance.location.y, 0.0 );
305 BOOST_CHECK_EQUAL( instance.rotation, 0.0 );
306 BOOST_CHECK_EQUAL( instance.glued, false );
307}
308
309
310BOOST_AUTO_TEST_CASE( ReuseInstance_WithValues )
311{
312 REUSE_INSTANCE instance;
313 instance.instance_name = "BLOCK1_INST1";
314 instance.part_naming = "PREFIX";
315 instance.net_naming = "APPEND";
316 instance.location.x = 1000.0;
317 instance.location.y = 2000.0;
318 instance.rotation = 90.0;
319 instance.glued = true;
320
321 BOOST_CHECK_EQUAL( instance.instance_name, "BLOCK1_INST1" );
322 BOOST_CHECK_EQUAL( instance.part_naming, "PREFIX" );
323 BOOST_CHECK_EQUAL( instance.net_naming, "APPEND" );
324 BOOST_CHECK_CLOSE( instance.location.x, 1000.0, 0.001 );
325 BOOST_CHECK_CLOSE( instance.location.y, 2000.0, 0.001 );
326 BOOST_CHECK_CLOSE( instance.rotation, 90.0, 0.001 );
327 BOOST_CHECK_EQUAL( instance.glued, true );
328}
329
330
331BOOST_AUTO_TEST_CASE( ReuseBlock_DefaultConstruction )
332{
333 REUSE_BLOCK block;
334 BOOST_CHECK( block.name.empty() );
335 BOOST_CHECK_EQUAL( block.timestamp, 0 );
336 BOOST_CHECK( block.part_naming.empty() );
337 BOOST_CHECK( block.net_naming.empty() );
338 BOOST_CHECK( block.part_names.empty() );
339 BOOST_CHECK( block.nets.empty() );
340 BOOST_CHECK( block.instances.empty() );
341}
342
343
344BOOST_AUTO_TEST_CASE( ReuseBlock_WithContents )
345{
346 REUSE_BLOCK block;
347 block.name = "MEMORY_BLOCK";
348 block.timestamp = 1234567890;
349 block.part_naming = "PREFIX";
350 block.net_naming = "APPEND";
351 block.part_names.push_back( "U1" );
352 block.part_names.push_back( "U2" );
353 block.part_names.push_back( "C1" );
354
355 REUSE_NET net1;
356 net1.merge = true;
357 net1.name = "DATA0";
358 block.nets.push_back( net1 );
359
360 REUSE_NET net2;
361 net2.merge = false;
362 net2.name = "DATA1";
363 block.nets.push_back( net2 );
364
365 REUSE_INSTANCE inst;
366 inst.instance_name = "MEM1";
367 inst.location.x = 5000.0;
368 inst.location.y = 3000.0;
369 block.instances.push_back( inst );
370
371 BOOST_CHECK_EQUAL( block.name, "MEMORY_BLOCK" );
372 BOOST_CHECK_EQUAL( block.timestamp, 1234567890 );
373 BOOST_CHECK_EQUAL( block.part_naming, "PREFIX" );
374 BOOST_CHECK_EQUAL( block.net_naming, "APPEND" );
375 BOOST_REQUIRE_EQUAL( block.part_names.size(), 3 );
376 BOOST_CHECK_EQUAL( block.part_names[0], "U1" );
377 BOOST_CHECK_EQUAL( block.part_names[1], "U2" );
378 BOOST_CHECK_EQUAL( block.part_names[2], "C1" );
379 BOOST_REQUIRE_EQUAL( block.nets.size(), 2 );
380 BOOST_CHECK_EQUAL( block.nets[0].name, "DATA0" );
381 BOOST_CHECK_EQUAL( block.nets[0].merge, true );
382 BOOST_CHECK_EQUAL( block.nets[1].name, "DATA1" );
383 BOOST_CHECK_EQUAL( block.nets[1].merge, false );
384 BOOST_REQUIRE_EQUAL( block.instances.size(), 1 );
385 BOOST_CHECK_EQUAL( block.instances[0].instance_name, "MEM1" );
386}
387
388
389BOOST_AUTO_TEST_CASE( ReuseBlock_PartMembershipMapping )
390{
391 // Test building the part-to-block membership map used during expansion
392 std::map<std::string, REUSE_BLOCK> blocks;
393
394 REUSE_BLOCK memBlock;
395 memBlock.name = "MEMORY";
396 memBlock.part_names.push_back( "U1" );
397 memBlock.part_names.push_back( "U2" );
398 blocks["MEMORY"] = memBlock;
399
400 REUSE_BLOCK pwrBlock;
401 pwrBlock.name = "POWER";
402 pwrBlock.part_names.push_back( "C1" );
403 pwrBlock.part_names.push_back( "C2" );
404 pwrBlock.part_names.push_back( "L1" );
405 blocks["POWER"] = pwrBlock;
406
407 // Build membership map as done in pcb_io_pads.cpp
408 std::map<std::string, std::string> partToBlockMap;
409
410 for( const auto& [blockName, block] : blocks )
411 {
412 for( const std::string& partName : block.part_names )
413 {
414 partToBlockMap[partName] = blockName;
415 }
416 }
417
418 BOOST_REQUIRE_EQUAL( partToBlockMap.size(), 5 );
419 BOOST_CHECK_EQUAL( partToBlockMap["U1"], "MEMORY" );
420 BOOST_CHECK_EQUAL( partToBlockMap["U2"], "MEMORY" );
421 BOOST_CHECK_EQUAL( partToBlockMap["C1"], "POWER" );
422 BOOST_CHECK_EQUAL( partToBlockMap["C2"], "POWER" );
423 BOOST_CHECK_EQUAL( partToBlockMap["L1"], "POWER" );
424}
425
426
427BOOST_AUTO_TEST_CASE( ReuseBlock_EmptyBlocksMap )
428{
429 // Test that empty reuse blocks result in empty membership map
430 std::map<std::string, REUSE_BLOCK> blocks;
431 std::map<std::string, std::string> partToBlockMap;
432
433 for( const auto& [blockName, block] : blocks )
434 {
435 for( const std::string& partName : block.part_names )
436 {
437 partToBlockMap[partName] = blockName;
438 }
439 }
440
441 BOOST_CHECK( partToBlockMap.empty() );
442}
443
444
445BOOST_AUTO_TEST_CASE( ReuseBlock_GroupCreationCondition )
446{
447 // Test conditions for when groups should be created
448 REUSE_BLOCK emptyBlock;
449 emptyBlock.name = "EMPTY";
450
451 REUSE_BLOCK blockWithParts;
452 blockWithParts.name = "WITH_PARTS";
453 blockWithParts.part_names.push_back( "U1" );
454
455 REUSE_BLOCK blockWithInstances;
456 blockWithInstances.name = "WITH_INSTANCES";
457 REUSE_INSTANCE inst;
458 inst.instance_name = "INST1";
459 blockWithInstances.instances.push_back( inst );
460
461 // Groups should be created when block has parts OR instances
462 bool createEmptyGroup = !emptyBlock.instances.empty() || !emptyBlock.part_names.empty();
463 bool createPartsGroup = !blockWithParts.instances.empty() || !blockWithParts.part_names.empty();
464 bool createInstanceGroup = !blockWithInstances.instances.empty() || !blockWithInstances.part_names.empty();
465
466 BOOST_CHECK_EQUAL( createEmptyGroup, false );
467 BOOST_CHECK_EQUAL( createPartsGroup, true );
468 BOOST_CHECK_EQUAL( createInstanceGroup, true );
469}
470
471
472BOOST_AUTO_TEST_CASE( Cluster_DefaultConstruction )
473{
474 CLUSTER cluster;
475 BOOST_CHECK( cluster.name.empty() );
476 BOOST_CHECK_EQUAL( cluster.id, 0 );
477 BOOST_CHECK( cluster.net_names.empty() );
478 BOOST_CHECK( cluster.segment_refs.empty() );
479}
480
481
482BOOST_AUTO_TEST_CASE( Cluster_WithContents )
483{
484 CLUSTER cluster;
485 cluster.name = "MEMORY_BUS";
486 cluster.id = 42;
487 cluster.net_names.push_back( "DATA0" );
488 cluster.net_names.push_back( "DATA1" );
489 cluster.net_names.push_back( "ADDR0" );
490 cluster.segment_refs.push_back( "DATA0.1" );
491 cluster.segment_refs.push_back( "DATA0.2" );
492 cluster.segment_refs.push_back( "DATA1.1" );
493
494 BOOST_CHECK_EQUAL( cluster.name, "MEMORY_BUS" );
495 BOOST_CHECK_EQUAL( cluster.id, 42 );
496 BOOST_REQUIRE_EQUAL( cluster.net_names.size(), 3 );
497 BOOST_CHECK_EQUAL( cluster.net_names[0], "DATA0" );
498 BOOST_CHECK_EQUAL( cluster.net_names[1], "DATA1" );
499 BOOST_CHECK_EQUAL( cluster.net_names[2], "ADDR0" );
500 BOOST_REQUIRE_EQUAL( cluster.segment_refs.size(), 3 );
501 BOOST_CHECK_EQUAL( cluster.segment_refs[0], "DATA0.1" );
502 BOOST_CHECK_EQUAL( cluster.segment_refs[1], "DATA0.2" );
503 BOOST_CHECK_EQUAL( cluster.segment_refs[2], "DATA1.1" );
504}
505
506
507BOOST_AUTO_TEST_CASE( Cluster_SegmentRefDetection )
508{
509 // Test the segment reference detection logic used in parser
510 std::string netName = "DATA0";
511 std::string segRef = "DATA0.1";
512 std::string segRefComplex = "NET_123.45";
513
514 bool netNameHasDot = netName.find( '.' ) != std::string::npos;
515 bool segRefHasDot = segRef.find( '.' ) != std::string::npos;
516 bool segRefComplexHasDot = segRefComplex.find( '.' ) != std::string::npos;
517
518 BOOST_CHECK_EQUAL( netNameHasDot, false );
519 BOOST_CHECK_EQUAL( segRefHasDot, true );
520 BOOST_CHECK_EQUAL( segRefComplexHasDot, true );
521}
522
523
524BOOST_AUTO_TEST_CASE( TestPoint_DefaultConstruction )
525{
527 BOOST_CHECK( tp.type.empty() );
528 BOOST_CHECK_EQUAL( tp.x, 0.0 );
529 BOOST_CHECK_EQUAL( tp.y, 0.0 );
530 BOOST_CHECK_EQUAL( tp.side, 0 );
531 BOOST_CHECK( tp.net_name.empty() );
532 BOOST_CHECK( tp.symbol_name.empty() );
533}
534
535
536BOOST_AUTO_TEST_CASE( TestPoint_ViaType )
537{
539 tp.type = "VIA";
540 tp.x = 7000.0;
541 tp.y = 3450.0;
542 tp.side = 0; // Through
543 tp.net_name = "+5V";
544 tp.symbol_name = "TESTVIATHRU";
545
546 BOOST_CHECK_EQUAL( tp.type, "VIA" );
547 BOOST_CHECK_CLOSE( tp.x, 7000.0, 0.001 );
548 BOOST_CHECK_CLOSE( tp.y, 3450.0, 0.001 );
549 BOOST_CHECK_EQUAL( tp.side, 0 );
550 BOOST_CHECK_EQUAL( tp.net_name, "+5V" );
551 BOOST_CHECK_EQUAL( tp.symbol_name, "TESTVIATHRU" );
552}
553
554
555BOOST_AUTO_TEST_CASE( TestPoint_PinType )
556{
558 tp.type = "PIN";
559 tp.x = 1000.0;
560 tp.y = 2000.0;
561 tp.side = 1; // Top
562 tp.net_name = "GND";
563 tp.symbol_name = "U1.3";
564
565 BOOST_CHECK_EQUAL( tp.type, "PIN" );
566 BOOST_CHECK_EQUAL( tp.side, 1 );
567 BOOST_CHECK_EQUAL( tp.net_name, "GND" );
568 BOOST_CHECK_EQUAL( tp.symbol_name, "U1.3" );
569}
570
571
572BOOST_AUTO_TEST_CASE( TestPoint_SideValues )
573{
574 // Test side value meaning: 0=through, 1=top, 2=bottom
575 TEST_POINT tpThrough, tpTop, tpBottom;
576 tpThrough.side = 0;
577 tpTop.side = 1;
578 tpBottom.side = 2;
579
580 BOOST_CHECK_EQUAL( tpThrough.side, 0 );
581 BOOST_CHECK_EQUAL( tpTop.side, 1 );
582 BOOST_CHECK_EQUAL( tpBottom.side, 2 );
583}
584
585
586BOOST_AUTO_TEST_CASE( Dimension_DefaultConstruction )
587{
588 DIMENSION dim;
589 BOOST_CHECK( dim.name.empty() );
590 BOOST_CHECK_EQUAL( dim.x, 0.0 );
591 BOOST_CHECK_EQUAL( dim.y, 0.0 );
592 BOOST_CHECK_EQUAL( dim.layer, 0 );
593 BOOST_CHECK( dim.points.empty() );
594 BOOST_CHECK( dim.text.empty() );
595 BOOST_CHECK_EQUAL( dim.text_height, 0.0 );
596 BOOST_CHECK_EQUAL( dim.text_width, 0.0 );
597 BOOST_CHECK_EQUAL( dim.rotation, 0.0 );
598}
599
600
601BOOST_AUTO_TEST_CASE( Dimension_WithValues )
602{
603 DIMENSION dim;
604 dim.name = "DIM001";
605 dim.x = 1000.0;
606 dim.y = 2000.0;
607 dim.layer = 26; // Typical doc layer
608 dim.text = "10.5mm";
609 dim.text_height = 50.0;
610 dim.text_width = 8.0;
611 dim.rotation = 90.0;
612
613 dim.points.push_back( { 0.0, 0.0 } );
614 dim.points.push_back( { 1050.0, 0.0 } );
615 dim.points.push_back( { 1050.0, 100.0 } );
616
617 BOOST_CHECK_EQUAL( dim.name, "DIM001" );
618 BOOST_CHECK_CLOSE( dim.x, 1000.0, 0.001 );
619 BOOST_CHECK_CLOSE( dim.y, 2000.0, 0.001 );
620 BOOST_CHECK_EQUAL( dim.layer, 26 );
621 BOOST_CHECK_EQUAL( dim.text, "10.5mm" );
622 BOOST_CHECK_CLOSE( dim.text_height, 50.0, 0.001 );
623 BOOST_CHECK_CLOSE( dim.text_width, 8.0, 0.001 );
624 BOOST_CHECK_CLOSE( dim.rotation, 90.0, 0.001 );
625 BOOST_CHECK_EQUAL( dim.points.size(), 3 );
626}
627
628
629BOOST_AUTO_TEST_CASE( Dimension_NamePrefix )
630{
631 // Test the dimension detection pattern (names starting with "DIM")
632 std::string dimName1 = "DIM001";
633 std::string dimName2 = "DIM_BOARD_WIDTH";
634 std::string nonDimName = "OUTLINE";
635
636 BOOST_CHECK( dimName1.rfind( "DIM", 0 ) == 0 );
637 BOOST_CHECK( dimName2.rfind( "DIM", 0 ) == 0 );
638 BOOST_CHECK( nonDimName.rfind( "DIM", 0 ) != 0 );
639}
640
641
642BOOST_AUTO_TEST_CASE( DesignRules_DefaultConstruction )
643{
644 DESIGN_RULES rules;
645
646 BOOST_CHECK_CLOSE( rules.min_clearance, 8.0, 0.001 );
647 BOOST_CHECK_CLOSE( rules.default_clearance, 10.0, 0.001 );
648 BOOST_CHECK_CLOSE( rules.min_track_width, 6.0, 0.001 );
649 BOOST_CHECK_CLOSE( rules.default_track_width, 10.0, 0.001 );
650 BOOST_CHECK_CLOSE( rules.min_via_size, 20.0, 0.001 );
651 BOOST_CHECK_CLOSE( rules.default_via_size, 40.0, 0.001 );
652 BOOST_CHECK_CLOSE( rules.min_via_drill, 10.0, 0.001 );
653 BOOST_CHECK_CLOSE( rules.default_via_drill, 20.0, 0.001 );
654 BOOST_CHECK_CLOSE( rules.hole_to_hole, 10.0, 0.001 );
655 BOOST_CHECK_CLOSE( rules.silk_clearance, 5.0, 0.001 );
656 BOOST_CHECK_CLOSE( rules.mask_clearance, 3.0, 0.001 );
657}
658
659
660BOOST_AUTO_TEST_CASE( DesignRules_WithValues )
661{
662 DESIGN_RULES rules;
663 rules.min_clearance = 12.0;
664 rules.default_clearance = 15.0;
665 rules.min_track_width = 8.0;
666 rules.default_track_width = 12.0;
667 rules.min_via_size = 25.0;
668 rules.default_via_size = 50.0;
669 rules.min_via_drill = 15.0;
670 rules.default_via_drill = 25.0;
671 rules.hole_to_hole = 12.0;
672 rules.silk_clearance = 6.0;
673 rules.mask_clearance = 4.0;
674
675 BOOST_CHECK_CLOSE( rules.min_clearance, 12.0, 0.001 );
676 BOOST_CHECK_CLOSE( rules.default_clearance, 15.0, 0.001 );
677 BOOST_CHECK_CLOSE( rules.min_track_width, 8.0, 0.001 );
678 BOOST_CHECK_CLOSE( rules.default_track_width, 12.0, 0.001 );
679 BOOST_CHECK_CLOSE( rules.min_via_size, 25.0, 0.001 );
680 BOOST_CHECK_CLOSE( rules.default_via_size, 50.0, 0.001 );
681 BOOST_CHECK_CLOSE( rules.min_via_drill, 15.0, 0.001 );
682 BOOST_CHECK_CLOSE( rules.default_via_drill, 25.0, 0.001 );
683 BOOST_CHECK_CLOSE( rules.hole_to_hole, 12.0, 0.001 );
684 BOOST_CHECK_CLOSE( rules.silk_clearance, 6.0, 0.001 );
685 BOOST_CHECK_CLOSE( rules.mask_clearance, 4.0, 0.001 );
686}
687
688
689BOOST_AUTO_TEST_CASE( NetClassDef_DefaultConstruction )
690{
691 NET_CLASS_DEF nc;
692 BOOST_CHECK( nc.name.empty() );
693 BOOST_CHECK_EQUAL( nc.clearance, 0.0 );
695 BOOST_CHECK_EQUAL( nc.via_size, 0.0 );
696 BOOST_CHECK_EQUAL( nc.via_drill, 0.0 );
699 BOOST_CHECK( nc.net_names.empty() );
700}
701
702
703BOOST_AUTO_TEST_CASE( NetClassDef_WithValues )
704{
705 NET_CLASS_DEF nc;
706 nc.name = "HighSpeed";
707 nc.clearance = 12.0;
708 nc.track_width = 8.0;
709 nc.via_size = 30.0;
710 nc.via_drill = 15.0;
711 nc.diff_pair_gap = 6.0;
712 nc.diff_pair_width = 8.0;
713 nc.net_names.push_back( "CLK" );
714 nc.net_names.push_back( "DATA0" );
715 nc.net_names.push_back( "DATA1" );
716
717 BOOST_CHECK_EQUAL( nc.name, "HighSpeed" );
718 BOOST_CHECK_CLOSE( nc.clearance, 12.0, 0.001 );
719 BOOST_CHECK_CLOSE( nc.track_width, 8.0, 0.001 );
720 BOOST_CHECK_CLOSE( nc.via_size, 30.0, 0.001 );
721 BOOST_CHECK_CLOSE( nc.via_drill, 15.0, 0.001 );
722 BOOST_CHECK_CLOSE( nc.diff_pair_gap, 6.0, 0.001 );
723 BOOST_CHECK_CLOSE( nc.diff_pair_width, 8.0, 0.001 );
724 BOOST_CHECK_EQUAL( nc.net_names.size(), 3 );
725 BOOST_CHECK_EQUAL( nc.net_names[0], "CLK" );
726 BOOST_CHECK_EQUAL( nc.net_names[1], "DATA0" );
727 BOOST_CHECK_EQUAL( nc.net_names[2], "DATA1" );
728}
729
730
731BOOST_AUTO_TEST_CASE( DiffPairDef_DefaultConstruction )
732{
733 DIFF_PAIR_DEF dp;
734 BOOST_CHECK( dp.name.empty() );
735 BOOST_CHECK( dp.positive_net.empty() );
736 BOOST_CHECK( dp.negative_net.empty() );
737 BOOST_CHECK_EQUAL( dp.gap, 0.0 );
738 BOOST_CHECK_EQUAL( dp.width, 0.0 );
739}
740
741
742BOOST_AUTO_TEST_CASE( DiffPairDef_WithValues )
743{
744 DIFF_PAIR_DEF dp;
745 dp.name = "USB_DATA";
746 dp.positive_net = "USB_D+";
747 dp.negative_net = "USB_D-";
748 dp.gap = 8.0;
749 dp.width = 10.0;
750
751 BOOST_CHECK_EQUAL( dp.name, "USB_DATA" );
752 BOOST_CHECK_EQUAL( dp.positive_net, "USB_D+" );
753 BOOST_CHECK_EQUAL( dp.negative_net, "USB_D-" );
754 BOOST_CHECK_CLOSE( dp.gap, 8.0, 0.001 );
755 BOOST_CHECK_CLOSE( dp.width, 10.0, 0.001 );
756}
757
758
General utilities for PCB file IO for QA programs.
A cluster of related route segments that should be grouped together.
std::vector< std::string > segment_refs
References to route segments in cluster.
std::string name
Cluster name/identifier.
int id
Cluster ID number.
std::vector< std::string > net_names
Nets belonging to this cluster.
Design rule definitions from PCB section.
double silk_clearance
Minimum silkscreen clearance (SILKCLEAR)
double default_track_width
Default track width (DEFAULTTRACKWID)
double default_via_drill
Default via drill diameter (DEFAULTVIADRILL)
double min_track_width
Minimum track width (MINTRACKWID)
double min_via_size
Minimum via outer diameter (MINVIASIZE)
double min_via_drill
Minimum via drill diameter (MINVIADRILL)
double min_clearance
Minimum copper clearance (MINCLEAR)
double default_via_size
Default via outer diameter (DEFAULTVIASIZE)
double default_clearance
Default copper clearance (DEFAULTCLEAR)
double hole_to_hole
Minimum hole-to-hole spacing (HOLEHOLE)
double mask_clearance
Solder mask clearance (MASKCLEAR)
Differential pair definition.
double width
Trace width.
std::string positive_net
Positive net name.
std::string negative_net
Negative net name.
double gap
Spacing between traces.
std::string name
Pair name.
A dimension annotation for measurement display.
std::string name
Dimension identifier.
double text_width
Text width.
double y
Origin Y coordinate.
double rotation
Text rotation angle.
double x
Origin X coordinate.
std::string text
Dimension text/value.
int layer
Layer for dimension graphics.
double text_height
Text height.
std::vector< POINT > points
Dimension geometry points (measurement endpoints)
Net class definition with routing constraints.
double via_drill
Via drill diameter (VIADRILL)
double clearance
Copper clearance (CLEARANCE)
std::vector< std::string > net_names
Nets assigned to this class.
double track_width
Track width (TRACKWIDTH)
std::string name
Net class name.
double diff_pair_width
Differential pair width (DIFFPAIRWIDTH)
double diff_pair_gap
Differential pair gap (DIFFPAIRGAP)
double via_size
Via diameter (VIASIZE)
double thermal_line_width
Thermal line width for THT (THERLINEWID)
double thermal_smd_width
Thermal line width for SMD (THERSMDWID)
double thermal_min_clearance
Starved thermal minimum clearance (STMINCLEAR)
int thermal_flags
Thermal relief flags (THERFLAGS)
int thermal_min_spokes
Starved thermal minimum spokes (STMINSPOKES)
std::string value
std::string decal
Primary decal (first in colon-separated list)
std::string name
std::vector< std::string > alternate_decals
Alternate decals (remaining after ':' splits)
bool is_cutout
True if this is a cutout (POCUT) piece.
std::string net_name
std::string owner_pour
Name of parent pour (7th field in header)
std::vector< ARC_POINT > points
Pour outline, may include arc segments.
A reuse block definition containing parts and routes that can be instantiated.
std::vector< REUSE_NET > nets
Nets contained in this block with merge flags.
std::string net_naming
Default net naming scheme.
long timestamp
Creation/modification timestamp.
std::string part_naming
Default part naming scheme.
std::vector< std::string > part_names
Parts contained in this block.
std::vector< REUSE_INSTANCE > instances
Placements of this block.
std::string name
Block type name.
std::string instance_name
Instance name.
std::string part_naming
Part naming scheme (may be multi-word like "PREFIX pref")
std::string net_naming
Net naming scheme (may be multi-word like "SUFFIX suf")
bool glued
True if glued in place.
POINT location
Placement location.
double rotation
Rotation angle in degrees.
A reuse block instance placement.
std::string name
Original net name from reuse definition.
bool merge
True to merge nets, false to rename.
A test point definition for manufacturing/testing access.
int side
Probe side (0=through, 1=top, 2=bottom)
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_AUTO_TEST_SUITE(CadstarPartParser)
BOOST_AUTO_TEST_SUITE_END()
BOOST_AUTO_TEST_CASE(Part_DefaultConstruction)
BOOST_CHECK_EQUAL(result, "25.4")
static thread_pool * tp