43#include <wx/filename.h>
68 BOOST_CHECK( m_plugin.CanReadBoard( GetTestDataDir() +
"keyboard.dip" ) );
69 BOOST_CHECK( m_plugin.CanReadBoard( GetTestDataDir() +
"156bus_narrow.dip" ) );
70 BOOST_CHECK( m_plugin.CanReadBoard( GetTestDataDir() +
"z80_board.dip" ) );
71 BOOST_CHECK( m_plugin.CanReadBoard( GetTestDataDir() +
"logic_probe.dip" ) );
72 BOOST_CHECK( m_plugin.CanReadBoard( GetTestDataDir() +
"project4.dip" ) );
74 wxString tempBase = wxFileName::CreateTempFileName( wxS(
"kicad_diptrace_legacy_" ) );
75 wxRemoveFile( tempBase );
76 wxString legacyPath = tempBase + wxS(
".dip" );
79 const uint8_t legacyHeader[] = {
80 0x0B,
'D',
'T',
'B',
'O',
'A',
'R',
'D',
'2',
'.',
'2',
'1'
83 wxFFile file( legacyPath, wxS(
"wb" ) );
85 BOOST_REQUIRE_EQUAL( file.Write( legacyHeader,
sizeof( legacyHeader ) ),
86 sizeof( legacyHeader ) );
89 BOOST_CHECK( m_plugin.CanReadBoard( legacyPath ) );
90 wxRemoveFile( legacyPath );
96 const std::string sourcePath = GetTestDataDir() +
"z80_board.dip";
97 wxString tempBase = wxFileName::CreateTempFileName( wxS(
"kicad_diptrace_bad_pcb_comp_" ) );
98 wxRemoveFile( tempBase );
99 wxString tempPath = tempBase + wxS(
".dip" );
104 static constexpr wxFileOffset FIRST_COMPONENT_FLAGS_OFFSET = 0x491;
105 const uint8_t invalidFlags[] = { 0xFF, 0x00, 0x00, 0x00 };
107 wxFFile file( tempPath, wxS(
"r+b" ) );
110 BOOST_REQUIRE_EQUAL( file.Write( invalidFlags,
sizeof( invalidFlags ) ),
111 sizeof( invalidFlags ) );
114 std::unique_ptr<BOARD> board = std::make_unique<BOARD>();
116 BOOST_CHECK_THROW( m_plugin.LoadBoard( tempPath.ToStdString(), board.get() ),
IO_ERROR );
118 wxRemoveFile( tempPath );
124 const std::string sourcePath = GetTestDataDir() +
"z80_board.dip";
125 wxString tempBase = wxFileName::CreateTempFileName( wxS(
"kicad_diptrace_bad_route_chain_" ) );
126 wxRemoveFile( tempBase );
127 wxString tempPath = tempBase + wxS(
".dip" );
132 static constexpr wxFileOffset FIRST_ROUTE_CHAIN_NODE_COUNT_OFFSET = 0x1CEA7;
133 const uint8_t invalidNodeCount[] = { 0x0F, 0x69, 0x51 };
135 wxFFile file( tempPath, wxS(
"r+b" ) );
137 BOOST_REQUIRE( file.Seek( FIRST_ROUTE_CHAIN_NODE_COUNT_OFFSET ) );
138 BOOST_REQUIRE_EQUAL( file.Write( invalidNodeCount,
sizeof( invalidNodeCount ) ),
139 sizeof( invalidNodeCount ) );
142 std::unique_ptr<BOARD> board = std::make_unique<BOARD>();
144 BOOST_CHECK_THROW( m_plugin.LoadBoard( tempPath.ToStdString(), board.get() ),
IO_ERROR );
146 wxRemoveFile( tempPath );
152 const std::string sourcePath = GetTestDataDir() +
"z80_board.dip";
153 wxString tempBase = wxFileName::CreateTempFileName( wxS(
"kicad_diptrace_bad_net_name_" ) );
154 wxRemoveFile( tempBase );
155 wxString tempPath = tempBase + wxS(
".dip" );
160 static constexpr wxFileOffset FIRST_NET_NAME_LENGTH_OFFSET = 0x1CE2D;
161 const uint8_t invalidNameLength[] = { 0x01, 0xF5 };
163 wxFFile file( tempPath, wxS(
"r+b" ) );
166 BOOST_REQUIRE_EQUAL( file.Write( invalidNameLength,
sizeof( invalidNameLength ) ),
167 sizeof( invalidNameLength ) );
170 std::unique_ptr<BOARD> board = std::make_unique<BOARD>();
172 BOOST_CHECK_THROW( m_plugin.LoadBoard( tempPath.ToStdString(), board.get() ),
IO_ERROR );
174 wxRemoveFile( tempPath );
180 const std::string sourcePath = GetTestDataDir() +
"z80_board.dip";
181 wxString tempBase = wxFileName::CreateTempFileName( wxS(
"kicad_diptrace_bad_zone_width_" ) );
182 wxRemoveFile( tempBase );
183 wxString tempPath = tempBase + wxS(
".dip" );
188 static constexpr wxFileOffset FIRST_ZONE_MIN_WIDTH_OFFSET = 0x382CB;
189 const uint8_t zeroMinWidth[] = { 0x3B, 0x9A, 0xCA, 0x00 };
191 wxFFile file( tempPath, wxS(
"r+b" ) );
194 BOOST_REQUIRE_EQUAL( file.Write( zeroMinWidth,
sizeof( zeroMinWidth ) ),
195 sizeof( zeroMinWidth ) );
198 std::unique_ptr<BOARD> board = std::make_unique<BOARD>();
200 BOOST_CHECK_THROW( m_plugin.LoadBoard( tempPath.ToStdString(), board.get() ),
IO_ERROR );
202 wxRemoveFile( tempPath );
213 std::unique_ptr<BOARD> board = std::make_unique<BOARD>();
215 m_plugin.LoadBoard( GetTestDataDir() +
"keyboard.dip", board.get() );
220 BOOST_CHECK_GT( board->Footprints().size(), 50 );
223 BOOST_CHECK_GT( board->GetNetCount(), 20 );
242 const std::vector<std::string> files = {
243 "keyboard.dip",
"156bus_narrow.dip",
"logic_probe.dip",
"project4.dip",
"z80_board.dip"
246 for(
const std::string&
name : files )
248 const std::string
path = GetTestDataDir() +
name;
249 std::unique_ptr<BOARD> board = std::make_unique<BOARD>();
250 board->SetFileName( wxString::FromUTF8(
path ) );
262 name +
": mount hole located by scan ("
265 name +
": shape located by scan ("
268 name +
": component located by scan ("
271 name +
": section located by scan ("
276 name +
": object/section located by byte-pattern scan (total="
293 std::unique_ptr<BOARD> board = std::make_unique<BOARD>();
295 m_plugin.LoadBoard( GetTestDataDir() +
"156bus_narrow.dip", board.get() );
298 BOOST_CHECK_GT( board->Footprints().size(), 0 );
301 bool hasOutline =
false;
303 for(
BOARD_ITEM* drawing : board->Drawings() )
312 BOOST_CHECK( hasOutline );
322 std::unique_ptr<BOARD> board = std::make_unique<BOARD>();
324 m_plugin.LoadBoard( GetTestDataDir() +
"project4.dip", board.get() );
327 BOOST_CHECK_GT( board->Footprints().size(), 0 );
336 std::unique_ptr<BOARD> board = std::make_unique<BOARD>();
338 m_plugin.LoadBoard( GetTestDataDir() +
"logic_probe.dip", board.get() );
341 BOOST_CHECK_GT( board->Footprints().size(), 0 );
351 std::unique_ptr<BOARD> board = std::make_unique<BOARD>();
353 m_plugin.LoadBoard( GetTestDataDir() +
"z80_board.dip", board.get() );
358 BOOST_CHECK_GT( board->Footprints().size(), 10 );
364 for(
const FOOTPRINT* fp : board->Footprints() )
366 if( !fp->GetReference().IsEmpty() )
369 totalPads +=
static_cast<int>( fp->Pads().size() );
372 BOOST_CHECK_GT( refsFound, 10 );
373 BOOST_CHECK_GT( totalPads, 0 );
376 BOOST_CHECK_GT( board->GetNetCount(), 20 );
385 std::unique_ptr<BOARD> board = std::make_unique<BOARD>();
387 m_plugin.LoadBoard( GetTestDataDir() +
"project4.dip", board.get() );
393 for(
const FOOTPRINT* fp : board->Footprints() )
394 totalPads +=
static_cast<int>( fp->Pads().size() );
397 BOOST_CHECK_GT( totalPads, 0 );
406 std::unique_ptr<BOARD> board = std::make_unique<BOARD>();
408 m_plugin.LoadBoard( GetTestDataDir() +
"keyboard.dip", board.get() );
414 for(
const FOOTPRINT* fp : board->Footprints() )
415 totalPads +=
static_cast<int>( fp->Pads().size() );
417 BOOST_CHECK_GT( totalPads, 0 );
429 std::unique_ptr<BOARD> board = std::make_unique<BOARD>();
431 m_plugin.LoadBoard( GetTestDataDir() +
"keyboard.dip", board.get() );
435 int totalGraphics = 0;
437 for(
const FOOTPRINT* fp : board->Footprints() )
439 for(
const BOARD_ITEM* item : fp->GraphicalItems() )
448 BOOST_CHECK_GT( totalGraphics, 100 );
458 std::unique_ptr<BOARD> board = std::make_unique<BOARD>();
460 m_plugin.LoadBoard( GetTestDataDir() +
"logic_probe.dip", board.get() );
464 int totalGraphics = 0;
466 for(
const FOOTPRINT* fp : board->Footprints() )
468 for(
const BOARD_ITEM* item : fp->GraphicalItems() )
475 BOOST_CHECK_GT( totalGraphics, 50 );
485 std::unique_ptr<BOARD> board = std::make_unique<BOARD>();
487 m_plugin.LoadBoard( GetTestDataDir() +
"z80_board.dip", board.get() );
491 int totalGraphics = 0;
493 for(
const FOOTPRINT* fp : board->Footprints() )
495 for(
const BOARD_ITEM* item : fp->GraphicalItems() )
504 BOOST_CHECK_GT( totalGraphics, 10 );
515 std::unique_ptr<BOARD> board = std::make_unique<BOARD>();
517 m_plugin.LoadBoard( GetTestDataDir() +
"logic_probe.dip", board.get() );
524 for(
const FOOTPRINT* fp : board->Footprints() )
526 VECTOR2I refPos = fp->Reference().GetPosition();
527 VECTOR2I valPos = fp->Value().GetPosition();
530 if( refPos.
y != fpPos.
y )
533 if( valPos.
y != fpPos.
y )
539 BOOST_CHECK_GT( nonZeroRefY, 30 );
540 BOOST_CHECK_GT( nonZeroValY, 3 );
549 std::unique_ptr<BOARD> board = std::make_unique<BOARD>();
551 m_plugin.LoadBoard( GetTestDataDir() +
"z80_board.dip", board.get() );
558 for(
const FOOTPRINT* fp : board->Footprints() )
560 VECTOR2I refPos = fp->Reference().GetPosition();
561 VECTOR2I valPos = fp->Value().GetPosition();
564 if( refPos.
y != fpPos.
y )
567 if( valPos.
y != fpPos.
y )
571 BOOST_CHECK_GT( nonZeroRefY, 1 );
572 BOOST_CHECK_GT( nonZeroValY, 1 );
581 std::unique_ptr<BOARD> board = std::make_unique<BOARD>();
583 m_plugin.LoadBoard( GetTestDataDir() +
"keyboard.dip", board.get() );
589 for(
const FOOTPRINT* fp : board->Footprints() )
591 VECTOR2I refPos = fp->Reference().GetPosition();
594 if( refPos.
y != fpPos.
y )
598 BOOST_CHECK_GT( nonZeroRefY, 30 );
607 std::unique_ptr<BOARD> board = std::make_unique<BOARD>();
609 m_plugin.LoadBoard( GetTestDataDir() +
"project4.dip", board.get() );
615 for(
const FOOTPRINT* fp : board->Footprints() )
617 VECTOR2I valPos = fp->Value().GetPosition();
620 if( valPos.
y != fpPos.
y )
625 BOOST_CHECK_GT( nonZeroValY, 5 );
635 std::vector<std::string> files = {
"logic_probe.dip",
"keyboard.dip" };
637 int totalSegments = 0;
638 int totalCircles = 0;
641 for(
const std::string& file : files )
643 std::unique_ptr<BOARD> board = std::make_unique<BOARD>();
645 m_plugin.LoadBoard( GetTestDataDir() + file, board.get() );
653 for(
const FOOTPRINT* fp : board->Footprints() )
655 for(
const BOARD_ITEM* item : fp->GraphicalItems() )
673 <<
" CIRCLE=" << circles <<
" ARC=" << arcs );
675 BOOST_CHECK_GT( segments + circles + arcs, 0 );
677 totalSegments += segments;
678 totalCircles += circles;
683 BOOST_CHECK_GT( totalSegments, 200 );
684 BOOST_CHECK_GT( totalCircles + totalArcs, 0 );
695 std::unique_ptr<BOARD> board = std::make_unique<BOARD>();
697 m_plugin.LoadBoard( GetTestDataDir() +
"z80_board.dip", board.get() );
703 for(
const FOOTPRINT* fp : board->Footprints() )
705 for(
const PAD*
pad : fp->Pads() )
712 BOOST_CHECK_GT( customPads, 0 );
722 std::unique_ptr<BOARD> board = std::make_unique<BOARD>();
724 m_plugin.LoadBoard( GetTestDataDir() +
"z80_board.dip", board.get() );
730 for(
const FOOTPRINT* fp : board->Footprints() )
732 for(
const PAD*
pad : fp->Pads() )
740 BOOST_CHECK_GT( rectPads, 0 );
750 std::unique_ptr<BOARD> board = std::make_unique<BOARD>();
752 m_plugin.LoadBoard( GetTestDataDir() +
"keyboard.dip", board.get() );
760 for(
const FOOTPRINT* fp : board->Footprints() )
762 for(
const PAD*
pad : fp->Pads() )
775 <<
" OVAL=" << ovalPads <<
" RECT=" << rectPads );
778 BOOST_CHECK_GT( circlePads, 0 );
788 std::unique_ptr<BOARD> board = std::make_unique<BOARD>();
790 m_plugin.LoadBoard( GetTestDataDir() +
"logic_probe.dip", board.get() );
797 BOOST_CHECK_GE( board->GetCopperLayerCount(), 2 );
801 BOOST_CHECK_GT( defNc->GetTrackWidth(), 0 );
802 BOOST_CHECK_GT( defNc->GetClearance(), 0 );
805 BOOST_CHECK_GT( defNc->GetViaDiameter(), 0 );
806 BOOST_CHECK_GT( defNc->GetViaDrill(), 0 );
815 std::unique_ptr<BOARD> board = std::make_unique<BOARD>();
817 m_plugin.LoadBoard( GetTestDataDir() +
"z80_board.dip", board.get() );
828 BOOST_CHECK_GT( defNc->GetTrackWidth(), 0 );
844 std::unique_ptr<BOARD> board = std::make_unique<BOARD>();
845 m_plugin.LoadBoard( GetTestDataDir() +
"re-arm_pub.dip", board.get() );
847 std::map<wxString, int> orient;
849 for(
FOOTPRINT* fp : board->Footprints() )
850 orient[fp->GetReference()] =
KiROUND( fp->GetOrientation().Normalize().AsDegrees() ) % 360;
852 const std::vector<std::pair<wxString, int>>
expected = {
853 { wxT(
"A1" ), 0 }, { wxT(
"C1" ), 270 }, { wxT(
"C2" ), 180 }, { wxT(
"C12" ), 180 },
854 { wxT(
"C25" ), 90 }, { wxT(
"C32" ), 270 }, { wxT(
"D2" ), 90 }, { wxT(
"J3" ), 180 },
855 { wxT(
"J5" ), 90 }, { wxT(
"J7" ), 270 }, { wxT(
"J12" ), 180 }, { wxT(
"R2" ), 270 },
856 { wxT(
"R11" ), 90 }, { wxT(
"U1" ), 270 }, { wxT(
"U2" ), 180 }, { wxT(
"X1" ), 90 },
859 for(
const auto& [ref, deg] :
expected )
861 auto it = orient.find( ref );
862 BOOST_REQUIRE_MESSAGE( it != orient.end(),
"missing footprint " << ref.ToStdString() );
864 <<
" != expected " << deg );
870 for(
const auto& [ref, deg] : orient )
876 BOOST_CHECK_GT( rotated, 50 );
General utilities for PCB file IO for QA programs.
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Container for design settings for a BOARD object.
std::shared_ptr< NET_SETTINGS > m_NetSettings
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Parses a DipTrace .dip binary board file and populates a KiCad BOARD.
int ScanLocatorUseCount() const
Number of objects or sections that were located by byte-pattern scanning rather than a deterministic ...
int ComponentLocatorScans() const
int PadLocatorScans() const
int MountHoleLocatorScans() const
int SectionLocatorScans() const
void Parse()
Parse the file and populate the board. Throws IO_ERROR on failure.
int ShapeLocatorScans() const
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
std::shared_ptr< NETCLASS > GetDefaultNetclass() const
Gets the default netclass for the project.
static constexpr PCB_LAYER_ID ALL_LAYERS
! Temporary layer identifier to identify code that is not padstack-aware
Parser for DipTrace binary .dip board files.
std::string GetPcbnewTestDataDir()
Utility which returns a path to the data directory where the test board files are stored.
Pcbnew PCB_IO for DipTrace binary .dip board files.
std::string GetTestDataDir()
DIPTRACE_PCB_IMPORT_FIXTURE()
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_AUTO_TEST_CASE(CanReadBoard)
Test that CanReadBoard correctly identifies DipTrace .dip files by their magic header bytes (0x07 "DT...
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_AUTO_TEST_SUITE_END()
VECTOR3I expected(15, 30, 45)
BOOST_CHECK_MESSAGE(totalMismatches==0, std::to_string(totalMismatches)+" board(s) with strategy disagreements")
BOOST_TEST_MESSAGE("\n=== Real-World Polygon PIP Benchmark ===\n"<< formatTable(table))
BOOST_CHECK_EQUAL(result, "25.4")
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
VECTOR2< int32_t > VECTOR2I