49namespace fs = std::filesystem;
55 +
"variant_test/variant_test.kicad_pcb" );
59 for(
const FOOTPRINT* footprint : board->Footprints() )
61 if( footprint->GetReference() == wxS(
"R1" ) )
68 BOOST_CHECK(
normal.Field( wxS(
"Datasheet" ) ).IsEmpty() );
77 +
"connect/connect.kicad_pcb" );
90 BOOST_CHECK( !point.m_via );
94 BOOST_CHECK( !sawPad );
96 BOOST_CHECK( point.m_position == point.m_via->GetPosition() );
101 BOOST_CHECK_GT( vias, 0u );
102 BOOST_CHECK( sawPad );
109 +
"odbpp/net_name_collision.kicad_pcb" );
112 BOOST_REQUIRE_GT( names.size(), 1u );
115 for(
const auto& [code,
name] : names )
117 BOOST_CHECK_GT( code, 0 );
121 const NETINFO_ITEM* supply = board->FindNet( wxS(
"+12V" ) );
122 const NETINFO_ITEM* q2 = board->FindNet( wxS(
"Net-(Q2-C)" ) );
123 const NETINFO_ITEM* q1 = board->FindNet( wxS(
"Net-(Q1-C)" ) );
148 +
"odbpp/pad_roles.kicad_pcb" );
153 BOOST_REQUIRE_GT( globals, 0 );
154 BOOST_REQUIRE_EQUAL( locals, 1 );
158 wxS(
"features" ) ).ToStdWstring() ) );
168 +
"odbpp/pad_roles.kicad_pcb" );
172 const PAD* testPoint =
nullptr;
174 for(
const FOOTPRINT* footprint : board->Footprints() )
176 for(
const PAD*
pad : footprint->Pads() )
188 wxS(
"features" ) ).ToStdWstring() ) );
191 size_t taggedPoints = 0;
193 for(
const std::string& line :
ReadLines( root /
"steps" /
"pcb" /
"netlists" /
"cadnet" /
"netlist" ) )
195 std::istringstream stream( line );
196 std::vector<std::string> fields;
199 while( stream >> token )
200 fields.push_back( token );
202 if( fields.size() < 9 || fields[0].empty() || !std::isdigit( fields[0][0] ) )
205 double x = std::stod( fields[2] );
206 double y = std::stod( fields[3] );
225 +
"connect/connect.kicad_pcb" );
229 std::vector<FAB_TEST_POINT> points =
FabTestPoints( *board );
233 if( point.m_via && point.m_netCode > 0 && ( point.m_front || point.m_back ) && !point.m_netEnd )
240 BOOST_REQUIRE_MESSAGE( midpoint,
"connect board has no exposed midpoint via" );
244 for(
const std::string& line :
ReadLines( root /
"steps" /
"pcb" /
"netlists" /
"cadnet" /
"netlist" ) )
246 std::istringstream stream( line );
247 std::vector<std::string> fields;
250 while( stream >> token )
251 fields.push_back( token );
253 if( fields.size() < 8 || fields.back() !=
"v" || fields[0] != std::to_string( midpoint->
m_netCode ) )
259 if(
std::abs( std::stod( fields[2] ) - x ) < 0.00001
260 &&
std::abs( std::stod( fields[3] ) - y ) < 0.00001 )
267 BOOST_CHECK( found );
274 +
"odbpp/pad_roles.kicad_pcb" );
284 if( row.m_name.StartsWith( wxS(
"drill_plated_" ) ) )
285 drillLayer = row.m_name;
292 size_t pressFitTools = 0;
295 wxS(
"tools" ) ).ToStdWstring() ) ) )
297 if( line.find(
"TYPE2=PRESS_FIT" ) != std::string::npos )
301 BOOST_CHECK_GT( pressFitTools, 0 );
303 size_t pressFitPins = 0;
305 for(
const std::string& line :
ReadLines( root /
"steps" /
"pcb" /
"eda" /
"data" ) )
307 if( line.rfind(
"PIN ", 0 ) == 0 && line.size() >= 2
308 && line.compare( line.size() - 2, 2,
" P" ) == 0 )
314 size_t pressFitComponents = 0;
318 if( row.m_type != wxS(
"COMPONENT" ) )
332 +
"odbpp/pad_roles.kicad_pcb" );
340 if( row.m_name.StartsWith( wxS(
"drill_non-plated_" ) ) )
341 drillLayer = row.m_name;
347 BOOST_REQUIRE_GT( nonPlated, 0 );
355 +
"padstacks.kicad_pcb" );
357 size_t microvias = 0;
359 for(
PCB_TRACK* track : board->Tracks() )
365 BOOST_REQUIRE_GT( microvias, 0 );
367 size_t laserFeatures = 0;
368 size_t laserTools = 0;
372 if( row.m_type != wxS(
"DRILL" ) )
379 wxS(
"tools" ) ).ToStdWstring() ) ) )
381 if( line.find(
"TYPE2=LASER" ) != std::string::npos )
387 BOOST_CHECK_GT( laserTools, 0 );
393 const std::vector<std::pair<std::string, bool>> fixtures = {
394 {
"odbpp/npth_pressfit.kicad_pcb",
false }, {
"odbpp/npth_pressfit_slot.kicad_pcb",
true }
397 for(
const auto& [
name, isSlot] : fixtures )
401 size_t invalidPads = 0;
403 for(
const FOOTPRINT* footprint : board->Footprints() )
405 for(
const PAD*
pad : footprint->Pads() )
415 BOOST_REQUIRE_EQUAL( invalidPads, 1 );
417 size_t nonPlatedTools = 0;
418 size_t pressFitTools = 0;
422 if( row.m_type != wxS(
"DRILL" ) )
425 fs::path toolsPath( product.
LayerFile( row.m_name, wxS(
"tools" ) ).ToStdWstring() );
427 for(
const std::string& line :
ReadLines( toolsPath ) )
429 if( line.find(
"TYPE=NON_PLATED" ) != std::string::npos )
432 if( line.find(
"TYPE2=PRESS_FIT" ) != std::string::npos )
437 BOOST_CHECK_GT( nonPlatedTools, 0 );
446 +
"custom_pads.kicad_pcb" );
451 std::vector<std::string> lines =
ReadLines( root /
"steps" /
"pcb" /
"attrlist" );
454 BOOST_CHECK( std::find( lines.begin(), lines.end(),
".board_thickness=1600.0" ) != lines.end() );
457 std::vector<std::string> inchLines =
ReadLines( inchRoot /
"steps" /
"pcb" /
"attrlist" );
461 BOOST_CHECK_CLOSE( std::stod( inchLines[1].substr( 17 ) ), 62.992126, 0.01 );
468 +
"ipc2581/dielectric-sublayer.kicad_pcb" );
473 size_t materials = 0;
477 if( row.m_type != wxS(
"DIELECTRIC" ) )
480 fs::path attrlistPath( product.
LayerFile( row.m_name, wxS(
"attrlist" ) ).ToStdWstring() );
481 std::vector<std::string> attrlist =
ReadLines( attrlistPath );
485 for(
const std::string& line : attrlist )
487 if( line.rfind(
"material=", 0 ) == 0 )
490 BOOST_CHECK( line.rfind(
".material=", 0 ) != 0 );
494 BOOST_CHECK_GT( materials, 0 );
495 std::vector<std::string> declaration =
ReadLines( root /
"misc" /
"userattr" );
497 for(
const std::string& field : {
"UNITS=MM",
"TEXT {",
"NAME=material",
"ENTITY=LAYER",
"MAX_LEN=64" } )
498 BOOST_CHECK( std::find( declaration.begin(), declaration.end(), field ) != declaration.end() );
505 +
"issue25021/backdrill.kicad_pcb" );
509 const std::map<std::pair<wxString, wxString>, wxString> stopLayers = {
510 { { wxS(
"f.cu" ), wxS(
"in3.cu" ) }, wxS(
"in4.cu" ) },
511 { { wxS(
"in6.cu" ), wxS(
"b.cu" ) }, wxS(
"in5.cu" ) },
512 { { wxS(
"in3.cu" ), wxS(
"b.cu" ) }, wxS(
"in2.cu" ) }
518 if( row.m_addType != wxS(
"BACKDRILL" ) )
521 auto it = stopLayers.find( { row.m_startName, row.m_endName } );
524 std::string
expected =
".backdrill_penetrate_stop_layer=" + it->second.ToStdString();
525 fs::path attrlistPath( product.
LayerFile( row.m_name, wxS(
"attrlist" ) ).ToStdWstring() );
526 std::vector<std::string> lines =
ReadLines( attrlistPath );
527 BOOST_CHECK( std::find( lines.begin(), lines.end(),
expected ) != lines.end() );
constexpr EDA_IU_SCALE pcbIUScale
General utilities for PCB file IO for QA programs.
Handle the data for a net.
The matrix and layer directories of an exported ODB++ product model tree.
wxString LayerFile(const wxString &aLayer, const wxString &aFile) const
Path of a file in a layer directory, matched to the directory name without regard to case.
const std::vector< ODB_MATRIX_ROW > & Matrix() const
size_t CountRecordsWithOption(const std::string &aName, const std::string &aOption) const
VECTOR2I GetPosition() const override
VIATYPE GetViaType() const
FAB_COMPONENT_ROW MakeFabComponentRow(const FOOTPRINT &aFootprint, const wxString &aVariant)
std::map< int, wxString > FabAnonymousNetNames(const BOARD &aBoard)
Anonymous names NET_1 through NET_n keyed and numbered by net code.
std::vector< FAB_TEST_POINT > FabTestPoints(const BOARD &aBoard)
The caller must build board connectivity before enumerating net endpoints.
std::string GetPcbnewTestDataDir()
Utility which returns a path to the data directory where the test board files are stored.
std::unique_ptr< BOARD > ReadBoardFromFileOrStream(const std::string &aFilename, std::istream &aFallback)
Read a board from a file, or another stream, as appropriate.
wxString GenLegalEntityName(const wxString &aStr)
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
size_t CountPads(const BOARD &aBoard, PAD_PROP aProperty, PCB_LAYER_ID aLayer)
fs::path ExportOdb(const BOARD &aBoard, const fs::path &aDir, const std::string &aUnits, const std::string &aSigfig, REPORTER *aReporter)
std::vector< std::string > ReadLines(const fs::path &aFile)
const KI_TEST::SCOPED_TEMP_DIR & TempDir()
@ NPTH
like PAD_PTH, but not plated mechanical use only, no connection allowed
@ FIDUCIAL_LOCAL
a fiducial (usually a smd) local to the parent footprint
@ FIDUCIAL_GLBL
a fiducial (usually a smd) for the full board
@ PRESSFIT
a PTH with a hole diameter with tight tolerances for press fit pin
@ TESTPOINT
a test point pad
Footprint facts resolved for one assembly variant.
wxString Field(const wxString &aName) const
Variant-resolved shown text, empty when the field is missing.
One LAYER block of matrix/matrix.
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
KIBIS top(path, &reporter)
VECTOR3I expected(15, 30, 45)
BOOST_AUTO_TEST_CASE(FabComponentRowUsesSavedVariantFields)
BOOST_CHECK_EQUAL(result, "25.4")
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)