49namespace fs = std::filesystem;
81 for(
const FOOTPRINT* footprint : board->Footprints() )
83 if( footprint->GetReference() == wxS(
"R1" ) )
90 BOOST_CHECK(
normal.Field( wxS(
"Datasheet" ) ).IsEmpty() );
101 std::vector<FAB_TEST_POINT> points =
FabTestPoints( *board );
111 BOOST_CHECK( !point.m_via );
115 BOOST_CHECK( !sawPad );
117 BOOST_CHECK( point.m_position == point.m_via->GetPosition() );
122 BOOST_CHECK_GT( vias, 0u );
123 BOOST_CHECK( sawPad );
132 BOOST_REQUIRE_GT( names.size(), 1u );
135 for(
const auto& [code,
name] : names )
137 BOOST_CHECK_GT( code, 0 );
141 const NETINFO_ITEM* supply = board->FindNet( wxS(
"+12V" ) );
142 const NETINFO_ITEM* q2 = board->FindNet( wxS(
"Net-(Q2-C)" ) );
143 const NETINFO_ITEM* q1 = board->FindNet( wxS(
"Net-(Q1-C)" ) );
171 BOOST_REQUIRE_GT( globals, 0 );
172 BOOST_REQUIRE_EQUAL( locals, 1 );
176 wxS(
"features" ) ).ToStdWstring() ) );
189 const PAD* testPoint =
nullptr;
191 for(
const FOOTPRINT* footprint : board->Footprints() )
193 for(
const PAD*
pad : footprint->Pads() )
205 wxS(
"features" ) ).ToStdWstring() ) );
208 size_t taggedPoints = 0;
210 for(
const std::string& line :
ReadLines( root /
"steps" /
"pcb" /
"netlists" /
"cadnet" /
"netlist" ) )
212 std::istringstream stream( line );
213 std::vector<std::string> fields;
216 while( stream >> token )
217 fields.push_back( token );
224 if( netNum.empty() || !std::isdigit(
static_cast<unsigned char>( netNum[0] ) ) )
235 BOOST_TEST_MESSAGE(
"Cadnet net number " << netNum <<
" found at coordinates (" << x <<
", " << y <<
")" );
237 const bool isTestPoint = std::find( fields.begin(), fields.end(),
"t" ) != fields.end();
246 BOOST_CHECK( isTestPoint );
261 std::vector<FAB_TEST_POINT> points =
FabTestPoints( *board );
265 if( point.m_via && point.m_netCode > 0 && ( point.m_front || point.m_back ) && !point.m_netEnd )
272 BOOST_REQUIRE_MESSAGE( midpoint,
"connect board has no exposed midpoint via" );
276 for(
const std::string& line :
ReadLines( root /
"steps" /
"pcb" /
"netlists" /
"cadnet" /
"netlist" ) )
278 std::istringstream stream( line );
279 std::vector<std::string> fields;
282 while( stream >> token )
283 fields.push_back( token );
285 const bool isVia = std::find( fields.begin(), fields.end(),
"v" ) != fields.end();
299 BOOST_CHECK(
radius > 0 );
306 BOOST_CHECK( found );
322 if( row.m_name.StartsWith( wxS(
"drill_plated_" ) ) )
323 drillLayer = row.m_name;
330 size_t pressFitTools = 0;
333 wxS(
"tools" ) ).ToStdWstring() ) ) )
335 if( line.find(
"TYPE2=PRESS_FIT" ) != std::string::npos )
339 BOOST_CHECK_GT( pressFitTools, 0 );
341 size_t pressFitPins = 0;
343 for(
const std::string& line :
ReadLines( root /
"steps" /
"pcb" /
"eda" /
"data" ) )
345 if( line.rfind(
"PIN ", 0 ) == 0 && line.size() >= 2
346 && line.compare( line.size() - 2, 2,
" P" ) == 0 )
352 size_t pressFitComponents = 0;
356 if( row.m_type != wxS(
"COMPONENT" ) )
376 if( row.m_name.StartsWith( wxS(
"drill_non-plated_" ) ) )
377 drillLayer = row.m_name;
383 BOOST_REQUIRE_GT( nonPlated, 0 );
392 size_t microvias = 0;
394 for(
PCB_TRACK* track : board->Tracks() )
400 BOOST_REQUIRE_GT( microvias, 0 );
402 size_t laserFeatures = 0;
403 size_t laserTools = 0;
407 if( row.m_type != wxS(
"DRILL" ) )
414 wxS(
"tools" ) ).ToStdWstring() ) ) )
416 if( line.find(
"TYPE2=LASER" ) != std::string::npos )
422 BOOST_CHECK_GT( laserTools, 0 );
428 const std::vector<std::pair<std::string, bool>> fixtures = {
429 {
"odbpp/npth_pressfit.kicad_pcb",
false }, {
"odbpp/npth_pressfit_slot.kicad_pcb",
true }
432 for(
const auto& [
name, isSlot] : fixtures )
436 size_t invalidPads = 0;
438 for(
const FOOTPRINT* footprint : board->Footprints() )
440 for(
const PAD*
pad : footprint->Pads() )
450 BOOST_REQUIRE_EQUAL( invalidPads, 1 );
452 size_t nonPlatedTools = 0;
453 size_t pressFitTools = 0;
457 if( row.m_type != wxS(
"DRILL" ) )
460 fs::path toolsPath( product.
LayerFile( row.m_name, wxS(
"tools" ) ).ToStdWstring() );
462 for(
const std::string& line :
ReadLines( toolsPath ) )
464 if( line.find(
"TYPE=NON_PLATED" ) != std::string::npos )
467 if( line.find(
"TYPE2=PRESS_FIT" ) != std::string::npos )
472 BOOST_CHECK_GT( nonPlatedTools, 0 );
485 std::vector<std::string> lines =
ReadLines( root /
"steps" /
"pcb" /
"attrlist" );
488 BOOST_CHECK( std::find( lines.begin(), lines.end(),
".board_thickness=1600.0" ) != lines.end() );
491 std::vector<std::string> inchLines =
ReadLines( inchRoot /
"steps" /
"pcb" /
"attrlist" );
495 BOOST_CHECK_CLOSE( std::stod( inchLines[1].substr( 17 ) ), 62.992126, 0.01 );
504 const auto checkCopperWeight =
505 [&](
const fs::path& aRootDir,
const std::string& aLayer,
const std::string& aExpectedUnits,
506 const std::string& aExpectedValue )
510 const fs::path attrlistPath( product.
LayerFile( aLayer, wxS(
"attrlist" ) ).ToStdWstring() );
511 const std::vector<std::string> attrlist =
ReadLines( attrlistPath );
513 const std::string expectedUnitsLine =
"UNITS=" + aExpectedUnits;
514 const std::string expectedValueLine =
".copper_weight=" + aExpectedValue;
518 BOOST_CHECK( std::find( attrlist.begin(), attrlist.end(), expectedValueLine ) != attrlist.end() );
522 checkCopperWeight( metricRoot,
"f.cu",
"MM",
"35.0" );
525 checkCopperWeight( inchRoot,
"f.cu",
"INCH",
"1.0" );
535 size_t materials = 0;
539 if( row.m_type != wxS(
"DIELECTRIC" ) )
542 fs::path attrlistPath( product.
LayerFile( row.m_name, wxS(
"attrlist" ) ).ToStdWstring() );
543 std::vector<std::string> attrlist =
ReadLines( attrlistPath );
547 for(
const std::string& line : attrlist )
549 if( line.rfind(
"material=", 0 ) == 0 )
552 BOOST_CHECK( line.rfind(
".material=", 0 ) != 0 );
556 BOOST_CHECK_GT( materials, 0 );
557 std::vector<std::string> declaration =
ReadLines( root /
"misc" /
"userattr" );
559 for(
const std::string& field : {
"UNITS=MM",
"TEXT {",
"NAME=material",
"ENTITY=LAYER",
"MAX_LEN=64" } )
560 BOOST_CHECK( std::find( declaration.begin(), declaration.end(), field ) != declaration.end() );
569 const std::map<std::pair<wxString, wxString>, wxString> stopLayers = {
570 { { wxS(
"f.cu" ), wxS(
"in3.cu" ) }, wxS(
"in4.cu" ) },
571 { { wxS(
"in6.cu" ), wxS(
"b.cu" ) }, wxS(
"in5.cu" ) },
572 { { wxS(
"in3.cu" ), wxS(
"b.cu" ) }, wxS(
"in2.cu" ) }
578 if( row.m_addType != wxS(
"BACKDRILL" ) )
581 auto it = stopLayers.find( { row.m_startName, row.m_endName } );
584 std::string
expected =
".backdrill_penetrate_stop_layer=" + it->second.ToStdString();
585 fs::path attrlistPath( product.
LayerFile( row.m_name, wxS(
"attrlist" ) ).ToStdWstring() );
586 std::vector<std::string> lines =
ReadLines( attrlistPath );
587 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::unique_ptr< BOARD > RequireBoardFromPcbnewQAData(const std::filesystem::path &aFilename)
Require a board from the path relative to the pcbnew QA data directory.
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_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_AUTO_TEST_SUITE(CadstarPartParser)
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_AUTO_TEST_SUITE_END()
KIBIS top(path, &reporter)
VECTOR3I expected(15, 30, 45)
BOOST_AUTO_TEST_CASE(FabComponentRowUsesSavedVariantFields)
BOOST_TEST_MESSAGE("Polyline has "<< chain.PointCount()<< " points")
BOOST_CHECK_EQUAL(result, "25.4")
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)