KiCad PCB EDA Suite
Loading...
Searching...
No Matches
board_test_utils.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
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, you may find one here:
18 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19 * or you may search the http://www.gnu.org website for the version 2 license,
20 * or you may write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23
25
26#include <iostream>
27#include <filesystem>
28
29#include <wx/filename.h>
30
31#include <boost/test/unit_test.hpp>
32
33#include <board.h>
34#include <board_commit.h>
36#include <footprint.h>
37#include <kiid.h>
38#include <pad.h>
39#include <pcb_shape.h>
40#include <zone.h>
41#include <zone_filler.h>
46#include <tool/tool_manager.h>
47
48#define CHECK_ENUM_CLASS_EQUAL( L, R ) \
49 BOOST_CHECK_EQUAL( static_cast<int>( L ), static_cast<int>( R ) )
50
51
52namespace KI_TEST
53{
54
59
60
61void BOARD_DUMPER::DumpBoardToFile( BOARD& aBoard, const std::string& aName ) const
62{
63 if( !m_dump_boards )
64 return;
65
66 auto path = std::filesystem::temp_directory_path() / aName;
67 path += ".kicad_pcb";
68
69 BOOST_TEST_MESSAGE( "Dumping board file: " << path.string() );
70 ::KI_TEST::DumpBoardToFile( aBoard, path.string() );
71}
72
73
74void LoadBoard( SETTINGS_MANAGER& aSettingsManager, const wxString& aRelPath,
75 std::unique_ptr<BOARD>& aBoard )
76{
77 if( aBoard )
78 {
79 aBoard->SetProject( nullptr );
80 aBoard = nullptr;
81 }
82
83 std::string absPath = GetPcbnewTestDataDir() + aRelPath.ToStdString();
84 wxFileName projectFile( absPath + ".kicad_pro" );
85 wxFileName legacyProject( absPath + ".pro" );
86 std::string boardPath = absPath + ".kicad_pcb";
87 wxFileName rulesFile( absPath + ".kicad_dru" );
88
89 if( projectFile.Exists() )
90 {
91 aSettingsManager.LoadProject( projectFile.GetFullPath() );
92 BOOST_TEST_MESSAGE( "Loading project file: " << projectFile.GetFullPath() );
93 }
94 else if( legacyProject.Exists() )
95 {
96 aSettingsManager.LoadProject( legacyProject.GetFullPath() );
97 BOOST_TEST_MESSAGE( "Loading project file: " << projectFile.GetFullPath() );
98 }
99 else
100 BOOST_TEST_MESSAGE( "Could not load project: " << projectFile.GetFullPath() );
101
102 BOOST_TEST_MESSAGE( "Loading board file: " << boardPath );
103
104 try {
105 aBoard = ReadBoardFromFileOrStream( boardPath );
106 }
107 catch( const IO_ERROR& ioe )
108 {
109 BOOST_TEST_ERROR( ioe.What() );
110 }
111
112 BOOST_REQUIRE_MESSAGE( aBoard, "aBoard is null or invalid" );
113
114 if( projectFile.Exists() || legacyProject.Exists() )
115 aBoard->SetProject( &aSettingsManager.Prj() );
116
117 auto m_DRCEngine = std::make_shared<DRC_ENGINE>( aBoard.get(), &aBoard->GetDesignSettings() );
118
119 BOOST_TEST_CHECKPOINT( "Init drc engine" );
120
121 if( rulesFile.Exists() )
122 m_DRCEngine->InitEngine( rulesFile );
123 else
124 m_DRCEngine->InitEngine( wxFileName() );
125
126 aBoard->GetDesignSettings().m_DRCEngine = m_DRCEngine;
127
128 BOOST_TEST_CHECKPOINT( "Build list of nets" );
129 try
130 {
131 aBoard->BuildListOfNets();
132 }
133 catch( const std::exception& e )
134 {
135 BOOST_TEST_ERROR( "Exception in BuildListOfNets: " << e.what() );
136 return;
137 }
138
139 BOOST_TEST_CHECKPOINT( "Build connectivity" );
140 try
141 {
142 aBoard->BuildConnectivity();
143 }
144 catch( const std::exception& e )
145 {
146 BOOST_TEST_ERROR( "Exception in BuildConnectivity: " << e.what() );
147 return;
148 }
149
150 BOOST_TEST_CHECKPOINT( "Synchronize Time Domain Properties" );
151 try
152 {
153 aBoard->GetLengthCalculation()->SynchronizeTimeDomainProperties();
154 }
155 catch( const std::exception& e )
156 {
157 BOOST_TEST_ERROR( "Exception in SynchronizeTimeDomainProperties: " << e.what() );
158 return;
159 }
160
161 if( aBoard->GetProject() )
162 {
163 std::unordered_set<wxString> dummy;
164 BOOST_TEST_CHECKPOINT( "Synchronize Component Classes" );
165 try
166 {
167 aBoard->SynchronizeComponentClasses( dummy );
168 }
169 catch( const std::exception& e )
170 {
171 BOOST_TEST_ERROR( "Exception in SynchronizeComponentClasses: " << e.what() );
172 return;
173 }
174
175 BOOST_TEST_CHECKPOINT( "Run DRC cache generator" );
176 try
177 {
178 DRC_CACHE_GENERATOR cacheGenerator;
179 cacheGenerator.SetDRCEngine( m_DRCEngine.get() );
180 cacheGenerator.Run();
181 }
182 catch( const std::exception& e )
183 {
184 BOOST_TEST_ERROR( "Exception in DRC cache generator: " << e.what() );
185 return;
186 }
187 }
188}
189
190
191BOARD_ITEM& RequireBoardItemWithTypeAndId( const BOARD& aBoard, KICAD_T aItemType, const KIID& aID )
192{
193 BOARD_ITEM* item = aBoard.ResolveItem( aID, true );
194
195 BOOST_REQUIRE( item );
196 BOOST_REQUIRE_EQUAL( item->Type(), aItemType );
197
198 return *item;
199}
200
201
206{
207public:
212 TEMPORARY_DIRECTORY( const std::string& aNamePrefix, const std::string aSuffix )
213 {
214 int i = 0;
215
216 // Find a unique directory name
217 while( true )
218 {
219 m_path = std::filesystem::temp_directory_path()
220 / ( aNamePrefix + std::to_string( i ) + aSuffix );
221
222 if( !std::filesystem::exists( m_path ) )
223 break;
224
225 i++;
226 }
227
228 wxASSERT( !std::filesystem::exists( m_path ) );
229 std::filesystem::create_directories( m_path );
230 }
231
232 ~TEMPORARY_DIRECTORY() { std::filesystem::remove_all( m_path ); }
233
234 const std::filesystem::path& GetPath() const { return m_path; }
235
236private:
237 std::filesystem::path m_path;
238};
239
240
241void LoadAndTestBoardFile( const wxString aRelativePath, bool aRoundtrip,
242 std::function<void( BOARD& )> aBoardTestFunction,
243 std::optional<int> aExpectedBoardVersion )
244{
245 const std::string absBoardPath =
246 KI_TEST::GetPcbnewTestDataDir() + aRelativePath.ToStdString() + ".kicad_pcb";
247
248 BOOST_TEST_MESSAGE( "Loading board to test: " << absBoardPath );
249 std::unique_ptr<BOARD> board1 = KI_TEST::ReadBoardFromFileOrStream( absBoardPath );
250
251 // Should load - if it doesn't we're done for
252 BOOST_REQUIRE( board1 );
253
254 BOOST_TEST_MESSAGE( "Testing loaded board" );
255 aBoardTestFunction( *board1 );
256
257 // If we care about the board version, check it now - but not after a roundtrip
258 // (as the version will be updated to the current version)
259 if( aExpectedBoardVersion )
260 {
261 BOOST_CHECK_EQUAL( board1->GetFileFormatVersionAtLoad(), *aExpectedBoardVersion );
262 }
263
264 if( aRoundtrip )
265 {
266 TEMPORARY_DIRECTORY tempLib( "kicad_qa_brd_roundtrip", "" );
267
268 const auto savePath = tempLib.GetPath() / ( aRelativePath.ToStdString() + ".kicad_pcb" );
269 KI_TEST::DumpBoardToFile( *board1, savePath.string() );
270
271 std::unique_ptr<BOARD> board2 = KI_TEST::ReadBoardFromFileOrStream( savePath.string() );
272
273 // Should load again
274 BOOST_REQUIRE( board2 );
275
276 BOOST_TEST_MESSAGE( "Testing roundtripped (saved/reloaded) file" );
277 aBoardTestFunction( *board2 );
278 }
279}
280
281
282void LoadAndTestFootprintFile( const wxString& aLibRelativePath, const wxString& aFpName,
283 bool aRoundtrip,
284 std::function<void( FOOTPRINT& )> aFootprintTestFunction,
285 std::optional<int> aExpectedFootprintVersion )
286{
287 const std::string absFootprintPath = KI_TEST::GetPcbnewTestDataDir()
288 + aLibRelativePath.ToStdString() + "/"
289 + aFpName.ToStdString() + ".kicad_mod";
290
291 BOOST_TEST_MESSAGE( "Loading footprint to test: " << absFootprintPath );
292 std::unique_ptr<FOOTPRINT> fp1 = KI_TEST::ReadFootprintFromFileOrStream( absFootprintPath );
293
294 // Should load - if it doesn't we're done for
295 BOOST_REQUIRE( fp1 );
296
297 BOOST_TEST_MESSAGE( "Testing loaded footprint (value: " << fp1->GetValue() << ")" );
298 aFootprintTestFunction( *fp1 );
299
300 // If we care about the board version, check it now - but not after a roundtrip
301 // (as the version will be updated to the current version)
302 if( aExpectedFootprintVersion )
303 {
304 BOOST_CHECK_EQUAL( fp1->GetFileFormatVersionAtLoad(), *aExpectedFootprintVersion );
305 }
306
307 if( aRoundtrip )
308 {
314 TEMPORARY_DIRECTORY tempLib( "kicad_qa_fp_roundtrip", ".pretty" );
315 const wxString fpFilename = fp1->GetFPID().GetLibItemName() + wxString( ".kicad_mod" );
316
317 BOOST_TEST_MESSAGE( "Resaving footprint: " << fpFilename << " in " << tempLib.GetPath() );
318
319 KI_TEST::DumpFootprintToFile( *fp1, tempLib.GetPath().string() );
320
321 const auto fp2Path = tempLib.GetPath() / fpFilename.ToStdString();
322
323 BOOST_TEST_MESSAGE( "Re-reading footprint: " << fpFilename << " in " << tempLib.GetPath() );
324
325 std::unique_ptr<FOOTPRINT> fp2 = KI_TEST::ReadFootprintFromFileOrStream( fp2Path.string() );
326
327 // Should load again
328 BOOST_REQUIRE( fp2 );
329
330 BOOST_TEST_MESSAGE( "Testing roundtripped (saved/reloaded) file" );
331 aFootprintTestFunction( *fp2 );
332 }
333}
334
335
336void FillZones( BOARD* m_board )
337{
338 BOOST_TEST_CHECKPOINT( "Filling zones" );
339
340 TOOL_MANAGER toolMgr;
341 toolMgr.SetEnvironment( m_board, nullptr, nullptr, nullptr, nullptr );
342
343 KI_TEST::DUMMY_TOOL* dummyTool = new KI_TEST::DUMMY_TOOL();
344 toolMgr.RegisterTool( dummyTool );
345
346 BOARD_COMMIT commit( dummyTool );
347 ZONE_FILLER filler( m_board, &commit );
348 std::vector<ZONE*> toFill;
349
350 for( ZONE* zone : m_board->Zones() )
351 toFill.push_back( zone );
352
353 if( filler.Fill( toFill, false, nullptr ) )
354 commit.Push( _( "Fill Zone(s)" ), SKIP_UNDO | SKIP_SET_DIRTY | ZONE_FILL_OP | SKIP_CONNECTIVITY );
355
356 BOOST_TEST_CHECKPOINT( "Building connectivity (after zone fill)" );
357 m_board->BuildConnectivity();
358}
359
360
361#define TEST( a, b ) \
362 { \
363 if( a != b ) \
364 return a < b; \
365 }
366#define TEST_PT( a, b ) \
367 { \
368 if( a.x != b.x ) \
369 return a.x < b.x; \
370 if( a.y != b.y ) \
371 return a.y < b.y; \
372 }
373
374
376{
378
379 bool operator()( const BOARD_ITEM* itemA, const BOARD_ITEM* itemB ) const
380 {
381 TEST( itemA->Type(), itemB->Type() );
382
383 if( itemA->GetLayerSet() != itemB->GetLayerSet() )
384 return itemA->GetLayerSet().Seq() < itemB->GetLayerSet().Seq();
385
386 if( itemA->Type() == PCB_TEXT_T )
387 {
388 const PCB_TEXT* textA = static_cast<const PCB_TEXT*>( itemA );
389 const PCB_TEXT* textB = static_cast<const PCB_TEXT*>( itemB );
390
391 TEST_PT( textA->GetPosition(), textB->GetPosition() );
392 TEST( textA->GetTextAngle(), textB->GetTextAngle() );
393 }
394
395 return fp_comp( itemA, itemB );
396 }
397};
398
399
401{
402 CHECK_ENUM_CLASS_EQUAL( expected->Type(), fp->Type() );
403
404 // TODO: validate those informations match the importer
405 BOOST_CHECK_EQUAL( expected->GetPosition(), fp->GetPosition() );
406 BOOST_CHECK_EQUAL( expected->GetOrientation(), fp->GetOrientation() );
407
408 BOOST_CHECK_EQUAL( expected->GetReference(), fp->GetReference() );
409 BOOST_CHECK_EQUAL( expected->GetValue(), fp->GetValue() );
410 BOOST_CHECK_EQUAL( expected->GetLibDescription(), fp->GetLibDescription() );
411 BOOST_CHECK_EQUAL( expected->GetKeywords(), fp->GetKeywords() );
412 BOOST_CHECK_EQUAL( expected->GetAttributes(), fp->GetAttributes() );
413 BOOST_CHECK_EQUAL( expected->GetFlag(), fp->GetFlag() );
414 //BOOST_CHECK_EQUAL( expected->GetProperties(), fp->GetProperties() );
415 BOOST_CHECK_EQUAL( expected->GetTypeName(), fp->GetTypeName() );
416
417 // simple test if count matches
418 BOOST_CHECK_EQUAL( expected->GetFields().size(), fp->GetFields().size() );
419 BOOST_CHECK_EQUAL( expected->Pads().size(), fp->Pads().size() );
420 BOOST_CHECK_EQUAL( expected->GraphicalItems().size(), fp->GraphicalItems().size() );
421 BOOST_CHECK_EQUAL( expected->Zones().size(), fp->Zones().size() );
422 BOOST_CHECK_EQUAL( expected->Groups().size(), fp->Groups().size() );
423 BOOST_CHECK_EQUAL( expected->Models().size(), fp->Models().size() );
424
425 std::set<PAD*, FOOTPRINT::cmp_pads> expectedPads( expected->Pads().begin(),
426 expected->Pads().end() );
427 std::set<PAD*, FOOTPRINT::cmp_pads> fpPads( fp->Pads().begin(), fp->Pads().end() );
428
429 for( auto itExpected = expectedPads.begin(), itFp = fpPads.begin();
430 itExpected != expectedPads.end() && itFp != fpPads.end(); itExpected++, itFp++ )
431 {
432 CheckFpPad( *itExpected, *itFp );
433 }
434
435 std::set<BOARD_ITEM*, kitest_cmp_drawings> expectedGraphicalItems( expected->GraphicalItems().begin(),
436 expected->GraphicalItems().end() );
437 std::set<BOARD_ITEM*, kitest_cmp_drawings> fpGraphicalItems( fp->GraphicalItems().begin(),
438 fp->GraphicalItems().end() );
439
440 for( auto itExpected = expectedGraphicalItems.begin(), itFp = fpGraphicalItems.begin();
441 itExpected != expectedGraphicalItems.end() && itFp != fpGraphicalItems.end();
442 itExpected++, itFp++ )
443 {
444 BOOST_CHECK_EQUAL( ( *itExpected )->Type(), ( *itFp )->Type() );
445
446 switch( ( *itExpected )->Type() )
447 {
448 case PCB_TEXT_T:
449 {
450 const PCB_TEXT* expectedText = static_cast<const PCB_TEXT*>( *itExpected );
451 const PCB_TEXT* text = static_cast<const PCB_TEXT*>( *itFp );
452
453 CheckFpText( expectedText, text );
454 break;
455 }
456
457 case PCB_SHAPE_T:
458 {
459 const PCB_SHAPE* expectedShape = static_cast<const PCB_SHAPE*>( *itExpected );
460 const PCB_SHAPE* shape = static_cast<const PCB_SHAPE*>( *itFp );
461
462 CheckFpShape( expectedShape, shape );
463 break;
464 }
465
467 case PCB_DIM_LEADER_T:
468 case PCB_DIM_CENTER_T:
469 case PCB_DIM_RADIAL_T:
471 // TODO
472 break;
473
474 default:
475 BOOST_ERROR( "KICAD_T not known" );
476 break;
477 }
478 }
479
480 std::set<ZONE*, FOOTPRINT::cmp_zones> expectedZones( expected->Zones().begin(),
481 expected->Zones().end() );
482 std::set<ZONE*, FOOTPRINT::cmp_zones> fpZones( fp->Zones().begin(), fp->Zones().end() );
483
484 for( auto itExpected = expectedZones.begin(), itFp = fpZones.begin();
485 itExpected != expectedZones.end() && itFp != fpZones.end(); itExpected++, itFp++ )
486 {
487 CheckFpZone( *itExpected, *itFp );
488 }
489
490 // TODO: Groups
491
492 // Use FootprintNeedsUpdate as sanity check (which should do many of the same checks as above,
493 // but neither is guaranteed to be complete).
494 WX_STRING_REPORTER reporter;
495
496 if( const_cast<FOOTPRINT*>(expected)->FootprintNeedsUpdate(fp, BOARD_ITEM::COMPARE_FLAGS::DRC, &reporter) )
497 BOOST_REQUIRE_MESSAGE( false, reporter.GetMessages() );
498}
499
500
501void CheckFpPad( const PAD* expected, const PAD* pad )
502{
503 // TODO(JE) padstacks
504 BOOST_TEST_CONTEXT( "Assert PAD with KIID=" << expected->m_Uuid.AsString() )
505 {
506 CHECK_ENUM_CLASS_EQUAL( expected->Type(), pad->Type() );
507
508 BOOST_CHECK_EQUAL( expected->GetNumber(), pad->GetNumber() );
509 CHECK_ENUM_CLASS_EQUAL( expected->GetAttribute(), pad->GetAttribute() );
510 CHECK_ENUM_CLASS_EQUAL( expected->GetProperty(), pad->GetProperty() );
512 pad->GetShape( PADSTACK::ALL_LAYERS ) );
513
514 BOOST_CHECK_EQUAL( expected->IsLocked(), pad->IsLocked() );
515
516 BOOST_CHECK_EQUAL( expected->GetPosition(), pad->GetPosition() );
518 pad->GetSize( PADSTACK::ALL_LAYERS ) );
519 BOOST_CHECK_EQUAL( expected->GetOrientation(), pad->GetOrientation() );
521 pad->GetDelta( PADSTACK::ALL_LAYERS ) );
523 pad->GetOffset( PADSTACK::ALL_LAYERS ) );
524 BOOST_CHECK_EQUAL( expected->GetDrillSize(), pad->GetDrillSize() );
525 CHECK_ENUM_CLASS_EQUAL( expected->GetDrillShape(), pad->GetDrillShape() );
526
527 BOOST_CHECK_EQUAL( expected->GetLayerSet(), pad->GetLayerSet() );
528
529 BOOST_CHECK_EQUAL( expected->GetNetCode(), pad->GetNetCode() );
530 BOOST_CHECK_EQUAL( expected->GetPinFunction(), pad->GetPinFunction() );
531 BOOST_CHECK_EQUAL( expected->GetPinType(), pad->GetPinType() );
532 BOOST_CHECK_EQUAL( expected->GetPadToDieLength(), pad->GetPadToDieLength() );
533 BOOST_CHECK_EQUAL( expected->GetPadToDieDelay(), pad->GetPadToDieDelay() );
534 BOOST_CHECK_EQUAL( expected->GetLocalSolderMaskMargin().value_or( 0 ),
535 pad->GetLocalSolderMaskMargin().value_or( 0 ) );
536 BOOST_CHECK_EQUAL( expected->GetLocalSolderPasteMargin().value_or( 0 ),
537 pad->GetLocalSolderPasteMargin().value_or( 0 ) );
538 BOOST_CHECK_EQUAL( expected->GetLocalSolderPasteMarginRatio().value_or( 0 ),
539 pad->GetLocalSolderPasteMarginRatio().value_or( 0 ) );
540 BOOST_CHECK_EQUAL( expected->GetLocalClearance().value_or( 0 ),
541 pad->GetLocalClearance().value_or( 0 ) );
542 CHECK_ENUM_CLASS_EQUAL( expected->GetLocalZoneConnection(), pad->GetLocalZoneConnection() );
543 BOOST_CHECK_EQUAL( expected->GetLocalThermalSpokeWidthOverride().value_or( 0 ),
544 pad->GetLocalThermalSpokeWidthOverride().value_or( 0 ) );
545 BOOST_CHECK_EQUAL( expected->GetThermalSpokeAngle(), pad->GetThermalSpokeAngle() );
546 BOOST_CHECK_EQUAL( expected->GetThermalGap(), pad->GetThermalGap() );
547 BOOST_CHECK_EQUAL( expected->GetRoundRectRadiusRatio( PADSTACK::ALL_LAYERS ),
548 pad->GetRoundRectRadiusRatio( PADSTACK::ALL_LAYERS ) );
549 BOOST_CHECK_EQUAL( expected->GetChamferRectRatio( PADSTACK::ALL_LAYERS ),
550 pad->GetChamferRectRatio( PADSTACK::ALL_LAYERS ) );
551 BOOST_CHECK_EQUAL( expected->GetChamferPositions( PADSTACK::ALL_LAYERS ),
552 pad->GetChamferPositions( PADSTACK::ALL_LAYERS ) );
553 BOOST_CHECK_EQUAL( expected->GetRemoveUnconnected(), pad->GetRemoveUnconnected() );
554 BOOST_CHECK_EQUAL( expected->GetKeepTopBottom(), pad->GetKeepTopBottom() );
555
556 // TODO: did we check everything for complex pad shapes?
558 pad->GetAnchorPadShape( PADSTACK::ALL_LAYERS ) );
559 CHECK_ENUM_CLASS_EQUAL( expected->GetCustomShapeInZoneOpt(),
560 pad->GetCustomShapeInZoneOpt() );
561
562 BOOST_CHECK_EQUAL( expected->GetPrimitives( PADSTACK::ALL_LAYERS ).size(),
563 pad->GetPrimitives( PADSTACK::ALL_LAYERS ).size() );
564
565 if( expected->GetPrimitives( PADSTACK::ALL_LAYERS ).size()
566 == pad->GetPrimitives( PADSTACK::ALL_LAYERS ).size() )
567 {
568 for( size_t i = 0; i < expected->GetPrimitives( PADSTACK::ALL_LAYERS ).size(); ++i )
569 {
570 CheckFpShape( expected->GetPrimitives( PADSTACK::ALL_LAYERS ).at( i ).get(),
571 pad->GetPrimitives( PADSTACK::ALL_LAYERS ).at( i ).get() );
572 }
573 }
574 }
575}
576
577
579{
580 BOOST_TEST_CONTEXT( "Assert PCB_TEXT with KIID=" << expected->m_Uuid.AsString() )
581 {
582 CHECK_ENUM_CLASS_EQUAL( expected->Type(), text->Type() );
583
584 BOOST_CHECK_EQUAL( expected->IsLocked(), text->IsLocked() );
585
586 BOOST_CHECK_EQUAL( expected->GetText(), text->GetText() );
587 BOOST_CHECK_EQUAL( expected->GetPosition(), text->GetPosition() );
588 BOOST_CHECK_EQUAL( expected->GetTextAngle(), text->GetTextAngle() );
589 BOOST_CHECK_EQUAL( expected->IsKeepUpright(), text->IsKeepUpright() );
590
591 BOOST_CHECK_EQUAL( expected->GetLayerSet(), text->GetLayerSet() );
592 BOOST_CHECK_EQUAL( expected->IsVisible(), text->IsVisible() );
593
594 BOOST_CHECK_EQUAL( expected->GetTextSize(), text->GetTextSize() );
595 BOOST_CHECK_EQUAL( expected->GetLineSpacing(), text->GetLineSpacing() );
596 BOOST_CHECK_EQUAL( expected->GetTextThickness(), text->GetTextThickness() );
597 BOOST_CHECK_EQUAL( expected->IsBold(), text->IsBold() );
598 BOOST_CHECK_EQUAL( expected->IsItalic(), text->IsItalic() );
599 BOOST_CHECK_EQUAL( expected->GetHorizJustify(), text->GetHorizJustify() );
600 BOOST_CHECK_EQUAL( expected->GetVertJustify(), text->GetVertJustify() );
601 BOOST_CHECK_EQUAL( expected->IsMirrored(), text->IsMirrored() );
602 BOOST_CHECK_EQUAL( expected->GetFontName(), text->GetFontName() );
603
604 // TODO: render cache?
605 }
606}
607
608
609void CheckFpShape( const PCB_SHAPE* expected, const PCB_SHAPE* shape )
610{
611 BOOST_TEST_CONTEXT( "Assert PCB_SHAPE with KIID=" << expected->m_Uuid.AsString() )
612 {
613 CHECK_ENUM_CLASS_EQUAL( expected->Type(), shape->Type() );
614
615 CHECK_ENUM_CLASS_EQUAL( expected->GetShape(), shape->GetShape() );
616
617 BOOST_CHECK_EQUAL( expected->IsLocked(), shape->IsLocked() );
618
619 BOOST_CHECK_EQUAL( expected->GetStart(), shape->GetStart() );
620 BOOST_CHECK_EQUAL( expected->GetEnd(), shape->GetEnd() );
621
622 if( expected->GetShape() == SHAPE_T::ARC )
623 {
624 // center and position might differ as they are calculated from start/mid/end -> compare mid instead
625 BOOST_CHECK_EQUAL( expected->GetArcMid(), shape->GetArcMid() );
626 }
627 else
628 {
629 BOOST_CHECK_EQUAL( expected->GetCenter(), shape->GetCenter() );
630 BOOST_CHECK_EQUAL( expected->GetPosition(), shape->GetPosition() );
631 }
632
633 BOOST_CHECK_EQUAL( expected->GetBezierC1(), shape->GetBezierC1() );
634 BOOST_CHECK_EQUAL( expected->GetBezierC2(), shape->GetBezierC2() );
635
636 CheckShapePolySet( &expected->GetPolyShape(), &shape->GetPolyShape() );
637
638 BOOST_CHECK_EQUAL( expected->GetLayerSet(), shape->GetLayerSet() );
639
640 BOOST_CHECK_EQUAL( expected->GetStroke().GetWidth(), shape->GetStroke().GetWidth() );
641 CHECK_ENUM_CLASS_EQUAL( expected->GetStroke().GetLineStyle(),
642 shape->GetStroke().GetLineStyle() );
643 CHECK_ENUM_CLASS_EQUAL( expected->GetFillMode(), shape->GetFillMode() );
644 }
645}
646
647
648void CheckFpZone( const ZONE* expected, const ZONE* zone )
649{
650 BOOST_TEST_CONTEXT( "Assert ZONE with KIID=" << expected->m_Uuid.AsString() )
651 {
652 CHECK_ENUM_CLASS_EQUAL( expected->Type(), zone->Type() );
653
654 BOOST_CHECK_EQUAL( expected->IsLocked(), zone->IsLocked() );
655
656 BOOST_CHECK_EQUAL( expected->GetNetCode(), zone->GetNetCode() );
657 BOOST_CHECK_EQUAL( expected->GetAssignedPriority(), zone->GetAssignedPriority() );
658 CHECK_ENUM_CLASS_EQUAL( expected->GetPadConnection(), zone->GetPadConnection() );
659 BOOST_CHECK_EQUAL( expected->GetLocalClearance().value_or( 0 ),
660 zone->GetLocalClearance().value_or( 0 ) );
661 BOOST_CHECK_EQUAL( expected->GetMinThickness(), zone->GetMinThickness() );
662
663 BOOST_CHECK_EQUAL( expected->GetLayerSet(), zone->GetLayerSet() );
664
665 BOOST_CHECK_EQUAL( expected->IsFilled(), zone->IsFilled() );
666 CHECK_ENUM_CLASS_EQUAL( expected->GetFillMode(), zone->GetFillMode() );
667 BOOST_CHECK_EQUAL( expected->GetHatchThickness(), zone->GetHatchThickness() );
668 BOOST_CHECK_EQUAL( expected->GetHatchGap(), zone->GetHatchGap() );
669 BOOST_CHECK_EQUAL( expected->GetHatchOrientation(), zone->GetHatchOrientation() );
670 BOOST_CHECK_EQUAL( expected->GetHatchSmoothingLevel(), zone->GetHatchSmoothingLevel() );
671 BOOST_CHECK_EQUAL( expected->GetHatchSmoothingValue(), zone->GetHatchSmoothingValue() );
672 BOOST_CHECK_EQUAL( expected->GetHatchBorderAlgorithm(), zone->GetHatchBorderAlgorithm() );
673 BOOST_CHECK_EQUAL( expected->GetHatchHoleMinArea(), zone->GetHatchHoleMinArea() );
674 BOOST_CHECK_EQUAL( expected->GetThermalReliefGap(), zone->GetThermalReliefGap() );
675 BOOST_CHECK_EQUAL( expected->GetThermalReliefSpokeWidth(),
677 BOOST_CHECK_EQUAL( expected->GetCornerSmoothingType(), zone->GetCornerSmoothingType() );
678 BOOST_CHECK_EQUAL( expected->GetCornerRadius(), zone->GetCornerRadius() );
679 CHECK_ENUM_CLASS_EQUAL( expected->GetIslandRemovalMode(), zone->GetIslandRemovalMode() );
680 BOOST_CHECK_EQUAL( expected->GetMinIslandArea(), zone->GetMinIslandArea() );
681
682 BOOST_CHECK_EQUAL( expected->GetIsRuleArea(), zone->GetIsRuleArea() );
683 BOOST_CHECK_EQUAL( expected->GetDoNotAllowZoneFills(), zone->GetDoNotAllowZoneFills() );
684 BOOST_CHECK_EQUAL( expected->GetDoNotAllowVias(), zone->GetDoNotAllowVias() );
685 BOOST_CHECK_EQUAL( expected->GetDoNotAllowTracks(), zone->GetDoNotAllowTracks() );
686 BOOST_CHECK_EQUAL( expected->GetDoNotAllowPads(), zone->GetDoNotAllowPads() );
687 BOOST_CHECK_EQUAL( expected->GetDoNotAllowFootprints(), zone->GetDoNotAllowFootprints() );
688
689 BOOST_CHECK_EQUAL( expected->GetZoneName(), zone->GetZoneName() );
690 CHECK_ENUM_CLASS_EQUAL( expected->GetTeardropAreaType(), zone->GetTeardropAreaType() );
691 BOOST_CHECK_EQUAL( expected->GetZoneName(), zone->GetZoneName() );
692
693 CheckShapePolySet( expected->Outline(), zone->Outline() );
694 // TODO: filled zones
695 }
696}
697
698
700{
701 BOOST_TEST_CONTEXT( "Assert SHAPE_POLY_SET" )
702 {
703 BOOST_CHECK_EQUAL( expected->OutlineCount(), polyset->OutlineCount() );
704 BOOST_CHECK_EQUAL( expected->TotalVertices(), polyset->TotalVertices() );
705
706 if( expected->OutlineCount() != polyset->OutlineCount() )
707 return; // don't check the rest
708
709 if( expected->TotalVertices() != polyset->TotalVertices() )
710 return; // don't check the rest
711
712 // TODO: check all outlines and holes (just checking outlines for now)
713 for( int i = 0; i < expected->OutlineCount(); ++i )
714 {
715 BOOST_TEST_CONTEXT( "Outline " << i )
716 {
717 BOOST_CHECK_EQUAL( expected->Outline( i ).ArcCount(),
718 polyset->Outline( i ).ArcCount() );
719 BOOST_CHECK_EQUAL( expected->Outline( i ).PointCount(),
720 polyset->Outline( i ).PointCount() );
721
722
723 if( expected->Outline( i ).PointCount() != polyset->Outline( i ).PointCount() )
724 return; // don't check the rest
725
726 for( int j = 0; j < expected->Outline( i ).PointCount(); ++j )
727 {
728 BOOST_CHECK_EQUAL( expected->Outline( i ).GetPoint( j ),
729 polyset->Outline( i ).GetPoint( j ) );
730 }
731 }
732 }
733 }
734}
735
736} // namespace KI_TEST
#define SKIP_CONNECTIVITY
#define ZONE_FILL_OP
General utilities for PCB file IO for QA programs.
#define CHECK_ENUM_CLASS_EQUAL(L, R)
virtual void Push(const wxString &aMessage=wxEmptyString, int aCommitFlags=0) override
Execute the changes.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:79
bool IsLocked() const override
virtual LSET GetLayerSet() const
Return a std::bitset of all layers on which the item physically resides.
Definition board_item.h:252
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:317
const ZONES & Zones() const
Definition board.h:362
bool BuildConnectivity(PROGRESS_REPORTER *aReporter=nullptr)
Build or rebuild the board connectivity database for the board, especially the list of connected item...
Definition board.cpp:188
BOARD_ITEM * ResolveItem(const KIID &aID, bool aAllowNullptrReturn=false) const
Definition board.cpp:1613
virtual bool Run() override
Run this provider against the given PCB with configured options (if any).
void SetDRCEngine(DRC_ENGINE *engine)
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:110
const VECTOR2I & GetBezierC2() const
Definition eda_shape.h:258
FILL_T GetFillMode() const
Definition eda_shape.h:142
SHAPE_POLY_SET & GetPolyShape()
Definition eda_shape.h:337
SHAPE_T GetShape() const
Definition eda_shape.h:168
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
Definition eda_shape.h:215
const VECTOR2I & GetStart() const
Return the starting point of the graphic.
Definition eda_shape.h:173
const VECTOR2I & GetBezierC1() const
Definition eda_shape.h:255
VECTOR2I GetArcMid() const
const EDA_ANGLE & GetTextAngle() const
Definition eda_text.h:146
wxString GetLibDescription() const
Definition footprint.h:278
EDA_ANGLE GetOrientation() const
Definition footprint.h:248
ZONES & Zones()
Definition footprint.h:230
std::deque< PAD * > & Pads()
Definition footprint.h:224
int GetAttributes() const
Definition footprint.h:327
wxString GetTypeName() const
Get the type of footprint.
GROUPS & Groups()
Definition footprint.h:233
void GetFields(std::vector< PCB_FIELD * > &aVector, bool aVisibleOnly) const
Populate a std::vector with PCB_TEXTs.
std::vector< FP_3DMODEL > & Models()
Definition footprint.h:241
const wxString & GetValue() const
Definition footprint.h:683
const wxString & GetReference() const
Definition footprint.h:661
int GetFlag() const
Definition footprint.h:338
wxString GetKeywords() const
Definition footprint.h:281
VECTOR2I GetPosition() const override
Definition footprint.h:245
DRAWINGS & GraphicalItems()
Definition footprint.h:227
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
virtual const wxString What() const
A composite of Problem() and Where()
Definition kiid.h:49
void DumpBoardToFile(BOARD &aBoard, const std::string &aName) const
A temporary directory that will be deleted when it goes out of scope.
const std::filesystem::path & GetPath() const
TEMPORARY_DIRECTORY(const std::string &aNamePrefix, const std::string aSuffix)
Create a temporary directory with a given prefix and suffix.
LSEQ Seq(const LSEQ &aSequence) const
Return an LSEQ from the union of this LSET and a desired sequence.
Definition lset.cpp:296
static constexpr PCB_LAYER_ID ALL_LAYERS
! Temporary layer identifier to identify code that is not padstack-aware
Definition padstack.h:145
Definition pad.h:54
VECTOR2I GetCenter() const override
This defaults to the center of the bounding box if not overridden.
Definition pcb_shape.h:81
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
STROKE_PARAMS GetStroke() const override
Definition pcb_shape.h:91
VECTOR2I GetPosition() const override
Definition pcb_shape.h:79
virtual VECTOR2I GetPosition() const override
Definition pcb_text.h:84
bool LoadProject(const wxString &aFullPath, bool aSetActive=true)
Load a project or sets up a new project with a specified path.
PROJECT & Prj() const
A helper while we are not MDI-capable – return the one and only project.
virtual const VECTOR2I GetPoint(int aIndex) const override
int PointCount() const
Return the number of points (vertices) in this line chain.
size_t ArcCount() const
Represent a set of closed polygons.
int TotalVertices() const
Return total number of vertices stored in the set.
SHAPE_LINE_CHAIN & Outline(int aIndex)
Return the reference to aIndex-th outline in the set.
int OutlineCount() const
Return the number of outlines in the set.
int GetWidth() const
LINE_STYLE GetLineStyle() const
Master controller class:
void RegisterTool(TOOL_BASE *aTool)
Add a tool to the manager set and sets it up.
void SetEnvironment(EDA_ITEM *aModel, KIGFX::VIEW *aView, KIGFX::VIEW_CONTROLS *aViewControls, APP_SETTINGS_BASE *aSettings, TOOLS_HOLDER *aFrame)
Set the work environment (model, view, view controls and the parent window).
A wrapper for reporting to a wxString object.
Definition reporter.h:191
const wxString & GetMessages() const
Definition reporter.cpp:77
bool Fill(const std::vector< ZONE * > &aZones, bool aCheck=false, wxWindow *aParent=nullptr)
Fills the given list of zones.
Handle a list of polygons defining a copper zone.
Definition zone.h:74
int GetHatchBorderAlgorithm() const
Definition zone.h:328
bool GetIsRuleArea() const
Accessors to parameters used in Rule Area zones:
Definition zone.h:704
std::optional< int > GetLocalClearance() const override
Definition zone.cpp:814
bool GetDoNotAllowVias() const
Definition zone.h:720
bool GetDoNotAllowPads() const
Definition zone.h:722
bool GetDoNotAllowTracks() const
Definition zone.h:721
bool IsFilled() const
Definition zone.h:292
ISLAND_REMOVAL_MODE GetIslandRemovalMode() const
Definition zone.h:731
SHAPE_POLY_SET * Outline()
Definition zone.h:335
long long int GetMinIslandArea() const
Definition zone.h:734
const wxString & GetZoneName() const
Definition zone.h:163
int GetMinThickness() const
Definition zone.h:301
ZONE_CONNECTION GetPadConnection() const
Definition zone.h:298
int GetHatchThickness() const
Definition zone.h:310
double GetHatchHoleMinArea() const
Definition zone.h:325
int GetThermalReliefSpokeWidth() const
Definition zone.h:245
EDA_ANGLE GetHatchOrientation() const
Definition zone.h:316
bool GetDoNotAllowFootprints() const
Definition zone.h:723
ZONE_FILL_MODE GetFillMode() const
Definition zone.h:224
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition zone.h:136
int GetHatchGap() const
Definition zone.h:313
TEARDROP_TYPE GetTeardropAreaType() const
Definition zone.h:690
double GetHatchSmoothingValue() const
Definition zone.h:322
bool GetDoNotAllowZoneFills() const
Definition zone.h:719
int GetHatchSmoothingLevel() const
Definition zone.h:319
unsigned int GetCornerRadius() const
Definition zone.h:650
int GetCornerSmoothingType() const
Definition zone.h:646
int GetThermalReliefGap() const
Definition zone.h:234
unsigned GetAssignedPriority() const
Definition zone.h:126
#define _(s)
#define TEST_PT(a, b)
#define TEST(a, b)
std::string GetPcbnewTestDataDir()
Utility which returns a path to the data directory where the test board files are stored.
void LoadBoard(SETTINGS_MANAGER &aSettingsManager, const wxString &aRelPath, std::unique_ptr< BOARD > &aBoard)
void CheckFootprint(const FOOTPRINT *expected, const FOOTPRINT *fp)
Helper method to check if two footprints are semantically the same.
void FillZones(BOARD *m_board)
std::unique_ptr< BOARD > ReadBoardFromFileOrStream(const std::string &aFilename, std::istream &aFallback)
Read a board from a file, or another stream, as appropriate.
void CheckFpShape(const PCB_SHAPE *expected, const PCB_SHAPE *shape)
std::unique_ptr< FOOTPRINT > ReadFootprintFromFileOrStream(const std::string &aFilename, std::istream &aFallback)
void LoadAndTestFootprintFile(const wxString &aLibRelativePath, const wxString &aFpName, bool aRoundtrip, std::function< void(FOOTPRINT &)> aFootprintTestFunction, std::optional< int > aExpectedFootprintVersion)
Same as LoadAndTestBoardFile, but for footprints.
void DumpBoardToFile(BOARD &board, const std::string &aFilename)
Utility function to simply write a Board out to a file.
void CheckFpPad(const PAD *expected, const PAD *pad)
void CheckFpZone(const ZONE *expected, const ZONE *zone)
void CheckFpText(const PCB_TEXT *expected, const PCB_TEXT *text)
void DumpFootprintToFile(const FOOTPRINT &aFootprint, const std::string &aLibraryPath)
Same as DumpBoardToFile, but for footprints.
void LoadAndTestBoardFile(const wxString aRelativePath, bool aRoundtrip, std::function< void(BOARD &)> aBoardTestFunction, std::optional< int > aExpectedBoardVersion)
Perform "some test" on a board file loaded from the path, then optionally save and reload and run the...
void CheckShapePolySet(const SHAPE_POLY_SET *expected, const SHAPE_POLY_SET *polyset)
BOARD_ITEM & RequireBoardItemWithTypeAndId(const BOARD &aBoard, KICAD_T aItemType, const KIID &aID)
Get an item from the given board with a certain type and UUID.
#define SKIP_SET_DIRTY
Definition sch_commit.h:42
#define SKIP_UNDO
Definition sch_commit.h:40
std::vector< FAB_LAYER_COLOR > dummy
FOOTPRINT::cmp_drawings fp_comp
bool operator()(const BOARD_ITEM *itemA, const BOARD_ITEM *itemB) const
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
VECTOR3I expected(15, 30, 45)
BOOST_TEST_CONTEXT("Test Clearance")
BOOST_TEST_MESSAGE("Polyline has "<< chain.PointCount()<< " points")
BOOST_CHECK_EQUAL(result, "25.4")
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition typeinfo.h:78
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
Definition typeinfo.h:88
@ PCB_DIM_ORTHOGONAL_T
class PCB_DIM_ORTHOGONAL, a linear dimension constrained to x/y
Definition typeinfo.h:105
@ PCB_DIM_LEADER_T
class PCB_DIM_LEADER, a leader dimension (graphic item)
Definition typeinfo.h:102
@ PCB_DIM_CENTER_T
class PCB_DIM_CENTER, a center point marking (graphic item)
Definition typeinfo.h:103
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
Definition typeinfo.h:92
@ PCB_DIM_ALIGNED_T
class PCB_DIM_ALIGNED, a linear dimension (graphic item)
Definition typeinfo.h:101
@ PCB_DIM_RADIAL_T
class PCB_DIM_RADIAL, a radius or diameter dimension
Definition typeinfo.h:104