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 ) ),
sizeof( invalidFlags ) );
113 BOOST_CHECK_THROW( m_plugin.LoadBoard( tempPath.ToStdString() ),
IO_ERROR );
115 wxRemoveFile( tempPath );
121 const std::string sourcePath = GetTestDataDir() +
"z80_board.dip";
122 wxString tempBase = wxFileName::CreateTempFileName( wxS(
"kicad_diptrace_bad_route_chain_" ) );
123 wxRemoveFile( tempBase );
124 wxString tempPath = tempBase + wxS(
".dip" );
129 static constexpr wxFileOffset FIRST_ROUTE_CHAIN_NODE_COUNT_OFFSET = 0x1CEA7;
130 const uint8_t invalidNodeCount[] = { 0x0F, 0x69, 0x51 };
132 wxFFile file( tempPath, wxS(
"r+b" ) );
134 BOOST_REQUIRE( file.Seek( FIRST_ROUTE_CHAIN_NODE_COUNT_OFFSET ) );
135 BOOST_REQUIRE_EQUAL( file.Write( invalidNodeCount,
sizeof( invalidNodeCount ) ),
sizeof( invalidNodeCount ) );
138 BOOST_CHECK_THROW( m_plugin.LoadBoard( tempPath.ToStdString() ),
IO_ERROR );
140 wxRemoveFile( tempPath );
146 const std::string sourcePath = GetTestDataDir() +
"z80_board.dip";
147 wxString tempBase = wxFileName::CreateTempFileName( wxS(
"kicad_diptrace_bad_net_name_" ) );
148 wxRemoveFile( tempBase );
149 wxString tempPath = tempBase + wxS(
".dip" );
154 static constexpr wxFileOffset FIRST_NET_NAME_LENGTH_OFFSET = 0x1CE2D;
155 const uint8_t invalidNameLength[] = { 0x01, 0xF5 };
157 wxFFile file( tempPath, wxS(
"r+b" ) );
160 BOOST_REQUIRE_EQUAL( file.Write( invalidNameLength,
sizeof( invalidNameLength ) ),
161 sizeof( invalidNameLength ) );
164 BOOST_CHECK_THROW( m_plugin.LoadBoard( tempPath.ToStdString() ),
IO_ERROR );
166 wxRemoveFile( tempPath );
172 const std::string sourcePath = GetTestDataDir() +
"z80_board.dip";
173 wxString tempBase = wxFileName::CreateTempFileName( wxS(
"kicad_diptrace_bad_zone_width_" ) );
174 wxRemoveFile( tempBase );
175 wxString tempPath = tempBase + wxS(
".dip" );
180 static constexpr wxFileOffset FIRST_ZONE_MIN_WIDTH_OFFSET = 0x382CB;
181 const uint8_t zeroMinWidth[] = { 0x3B, 0x9A, 0xCA, 0x00 };
183 wxFFile file( tempPath, wxS(
"r+b" ) );
186 BOOST_REQUIRE_EQUAL( file.Write( zeroMinWidth,
sizeof( zeroMinWidth ) ),
sizeof( zeroMinWidth ) );
189 BOOST_CHECK_THROW( m_plugin.LoadBoard( tempPath.ToStdString() ),
IO_ERROR );
191 wxRemoveFile( tempPath );
202 std::unique_ptr<BOARD> board = m_plugin.LoadBoard( GetTestDataDir() +
"keyboard.dip" );
207 BOOST_CHECK_GT( board->Footprints().size(), 50 );
210 BOOST_CHECK_GT( board->GetNetCount(), 20 );
229 const std::vector<std::string> files = {
237 for(
const std::string&
name : files )
239 const std::string
path = GetTestDataDir() +
name;
240 std::unique_ptr<BOARD> board = std::make_unique<BOARD>();
241 board->SetFileName( wxString::FromUTF8(
path ) );
253 name +
": mount hole located by scan ("
256 name +
": shape located by scan ("
259 name +
": component located by scan ("
262 name +
": section located by scan ("
266 name +
": object/section located by byte-pattern scan (total="
283 std::unique_ptr<BOARD> board = m_plugin.LoadBoard( GetTestDataDir() +
"156bus_narrow.dip" );
286 BOOST_CHECK_GT( board->Footprints().size(), 0 );
289 bool hasOutline =
false;
291 for(
BOARD_ITEM* drawing : board->Drawings() )
300 BOOST_CHECK( hasOutline );
310 std::unique_ptr<BOARD> board = m_plugin.LoadBoard( GetTestDataDir() +
"project4.dip" );
313 BOOST_CHECK_GT( board->Footprints().size(), 0 );
322 std::unique_ptr<BOARD> board = m_plugin.LoadBoard( GetTestDataDir() +
"logic_probe.dip" );
325 BOOST_CHECK_GT( board->Footprints().size(), 0 );
335 std::unique_ptr<BOARD> board = m_plugin.LoadBoard( GetTestDataDir() +
"z80_board.dip" );
340 BOOST_CHECK_GT( board->Footprints().size(), 10 );
346 for(
const FOOTPRINT* fp : board->Footprints() )
348 if( !fp->GetReference().IsEmpty() )
351 totalPads +=
static_cast<int>( fp->Pads().size() );
354 BOOST_CHECK_GT( refsFound, 10 );
355 BOOST_CHECK_GT( totalPads, 0 );
358 BOOST_CHECK_GT( board->GetNetCount(), 20 );
367 std::unique_ptr<BOARD> board = m_plugin.LoadBoard( GetTestDataDir() +
"project4.dip" );
373 for(
const FOOTPRINT* fp : board->Footprints() )
374 totalPads +=
static_cast<int>( fp->Pads().size() );
377 BOOST_CHECK_GT( totalPads, 0 );
386 std::unique_ptr<BOARD> board = m_plugin.LoadBoard( GetTestDataDir() +
"keyboard.dip" );
392 for(
const FOOTPRINT* fp : board->Footprints() )
393 totalPads +=
static_cast<int>( fp->Pads().size() );
395 BOOST_CHECK_GT( totalPads, 0 );
407 std::unique_ptr<BOARD> board = m_plugin.LoadBoard( GetTestDataDir() +
"keyboard.dip" );
411 int totalGraphics = 0;
413 for(
const FOOTPRINT* fp : board->Footprints() )
415 for(
const BOARD_ITEM* item : fp->GraphicalItems() )
424 BOOST_CHECK_GT( totalGraphics, 100 );
434 std::unique_ptr<BOARD> board = m_plugin.LoadBoard( GetTestDataDir() +
"logic_probe.dip" );
438 int totalGraphics = 0;
440 for(
const FOOTPRINT* fp : board->Footprints() )
442 for(
const BOARD_ITEM* item : fp->GraphicalItems() )
449 BOOST_CHECK_GT( totalGraphics, 50 );
459 std::unique_ptr<BOARD> board = m_plugin.LoadBoard( GetTestDataDir() +
"z80_board.dip" );
463 int totalGraphics = 0;
465 for(
const FOOTPRINT* fp : board->Footprints() )
467 for(
const BOARD_ITEM* item : fp->GraphicalItems() )
476 BOOST_CHECK_GT( totalGraphics, 10 );
487 std::unique_ptr<BOARD> board = m_plugin.LoadBoard( GetTestDataDir() +
"logic_probe.dip" );
494 for(
const FOOTPRINT* fp : board->Footprints() )
496 VECTOR2I refPos = fp->Reference().GetPosition();
497 VECTOR2I valPos = fp->Value().GetPosition();
500 if( refPos.
y != fpPos.
y )
503 if( valPos.
y != fpPos.
y )
509 BOOST_CHECK_GT( nonZeroRefY, 30 );
510 BOOST_CHECK_GT( nonZeroValY, 3 );
519 std::unique_ptr<BOARD> board = m_plugin.LoadBoard( GetTestDataDir() +
"z80_board.dip" );
526 for(
const FOOTPRINT* fp : board->Footprints() )
528 VECTOR2I refPos = fp->Reference().GetPosition();
529 VECTOR2I valPos = fp->Value().GetPosition();
532 if( refPos.
y != fpPos.
y )
535 if( valPos.
y != fpPos.
y )
539 BOOST_CHECK_GT( nonZeroRefY, 1 );
540 BOOST_CHECK_GT( nonZeroValY, 1 );
549 std::unique_ptr<BOARD> board = m_plugin.LoadBoard( GetTestDataDir() +
"keyboard.dip" );
555 for(
const FOOTPRINT* fp : board->Footprints() )
557 VECTOR2I refPos = fp->Reference().GetPosition();
560 if( refPos.
y != fpPos.
y )
564 BOOST_CHECK_GT( nonZeroRefY, 30 );
573 std::unique_ptr<BOARD> board = m_plugin.LoadBoard( GetTestDataDir() +
"project4.dip" );
579 for(
const FOOTPRINT* fp : board->Footprints() )
581 VECTOR2I valPos = fp->Value().GetPosition();
584 if( valPos.
y != fpPos.
y )
589 BOOST_CHECK_GT( nonZeroValY, 5 );
599 std::vector<std::string> files = {
"logic_probe.dip",
602 int totalSegments = 0;
603 int totalCircles = 0;
606 for(
const std::string& file : files )
608 std::unique_ptr<BOARD> board = m_plugin.LoadBoard( GetTestDataDir() + file );
616 for(
const FOOTPRINT* fp : board->Footprints() )
618 for(
const BOARD_ITEM* item : fp->GraphicalItems() )
636 <<
" CIRCLE=" << circles <<
" ARC=" << arcs );
638 BOOST_CHECK_GT( segments + circles + arcs, 0 );
640 totalSegments += segments;
641 totalCircles += circles;
646 BOOST_CHECK_GT( totalSegments, 200 );
647 BOOST_CHECK_GT( totalCircles + totalArcs, 0 );
658 std::unique_ptr<BOARD> board = m_plugin.LoadBoard( GetTestDataDir() +
"z80_board.dip" );
664 for(
const FOOTPRINT* fp : board->Footprints() )
666 for(
const PAD*
pad : fp->Pads() )
673 BOOST_CHECK_GT( customPads, 0 );
683 std::unique_ptr<BOARD> board = m_plugin.LoadBoard( GetTestDataDir() +
"z80_board.dip" );
689 for(
const FOOTPRINT* fp : board->Footprints() )
691 for(
const PAD*
pad : fp->Pads() )
699 BOOST_CHECK_GT( rectPads, 0 );
709 std::unique_ptr<BOARD> board = m_plugin.LoadBoard( GetTestDataDir() +
"keyboard.dip" );
717 for(
const FOOTPRINT* fp : board->Footprints() )
719 for(
const PAD*
pad : fp->Pads() )
732 <<
" OVAL=" << ovalPads <<
" RECT=" << rectPads );
735 BOOST_CHECK_GT( circlePads, 0 );
745 std::unique_ptr<BOARD> board = m_plugin.LoadBoard( GetTestDataDir() +
"logic_probe.dip" );
752 BOOST_CHECK_GE( board->GetCopperLayerCount(), 2 );
756 BOOST_CHECK_GT( defNc->GetTrackWidth(), 0 );
757 BOOST_CHECK_GT( defNc->GetClearance(), 0 );
760 BOOST_CHECK_GT( defNc->GetViaDiameter(), 0 );
761 BOOST_CHECK_GT( defNc->GetViaDrill(), 0 );
770 std::unique_ptr<BOARD> board = m_plugin.LoadBoard( GetTestDataDir() +
"z80_board.dip" );
781 BOOST_CHECK_GT( defNc->GetTrackWidth(), 0 );
797 std::unique_ptr<BOARD> board = m_plugin.LoadBoard( GetTestDataDir() +
"re-arm_pub.dip" );
799 std::map<wxString, int> orient;
801 for(
FOOTPRINT* fp : board->Footprints() )
802 orient[fp->GetReference()] =
KiROUND( fp->GetOrientation().Normalize().AsDegrees() ) % 360;
804 const std::vector<std::pair<wxString, int>>
expected = {
805 { wxT(
"A1" ), 0 }, { wxT(
"C1" ), 270 }, { wxT(
"C2" ), 180 }, { wxT(
"C12" ), 180 },
806 { wxT(
"C25" ), 90 }, { wxT(
"C32" ), 270 }, { wxT(
"D2" ), 90 }, { wxT(
"J3" ), 180 },
807 { wxT(
"J5" ), 90 }, { wxT(
"J7" ), 270 }, { wxT(
"J12" ), 180 }, { wxT(
"R2" ), 270 },
808 { wxT(
"R11" ), 90 }, { wxT(
"U1" ), 270 }, { wxT(
"U2" ), 180 }, { wxT(
"X1" ), 90 },
811 for(
const auto& [ref, deg] :
expected )
813 auto it = orient.find( ref );
814 BOOST_REQUIRE_MESSAGE( it != orient.end(),
"missing footprint " << ref.ToStdString() );
815 BOOST_CHECK_MESSAGE( it->second == deg, ref.ToStdString() <<
" orientation " << it->second
816 <<
" != expected " << deg );
822 for(
const auto& [ref, deg] : orient )
828 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
! The layer identifier to use for the single defintion on normal padstacks
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_TEST_MESSAGE("Polyline has "<< chain.PointCount()<< " points")
BOOST_CHECK_EQUAL(result, "25.4")
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
VECTOR2< int32_t > VECTOR2I