27#include <boost/test/unit_test.hpp>
57 BOOST_CHECK( !variant.
GetDNP() );
60 BOOST_CHECK( variant.
GetFields().empty() );
68 BOOST_CHECK( variant.
GetDNP() );
89 BOOST_CHECK( board.
HasVariant(
"Production" ) );
98 BOOST_CHECK( board.
HasVariant(
"production" ) );
99 BOOST_CHECK( board.
HasVariant(
"PRODUCTION" ) );
100 BOOST_CHECK( board.
HasVariant(
"PrOdUcTiOn" ) );
141 prodVariant.
SetDNP(
false );
152 debugVariant.
SetDNP(
true );
231 prodVariant.
SetDNP(
true );
241 BOOST_CHECK( board.
HasVariant(
"production" ) );
242 BOOST_CHECK( board.
HasVariant(
"PRODUCTION" ) );
264 prodVariant.
SetDNP(
false );
287 prodVariant.
SetDNP(
false );
305 prodVariant.
SetDNP(
true );
313 BOOST_CHECK( copyVariant->
GetDNP() );
322 BOOST_CHECK( assignedVariant->
GetDNP() );
357 wxString variantToken = wxT(
"VARIANT" );
361 wxString descToken = wxT(
"VARIANT_DESC" );
366 wxString defaultToken = wxT(
"VARIANT" );
368 BOOST_CHECK( defaultToken.IsEmpty() );
375 "(export (version 1)\n"
379 " (footprint Resistor_SMD:R_0603_1608Metric)\n"
380 " (libsource (lib Device) (part R))\n"
382 " (variant (name Alt)\n"
383 " (property (name dnp) (value 1))\n"
384 " (property (name exclude_from_bom) (value 0))\n"
386 " (field (name Value) \"22K\")\n"
387 " (field (name Footprint) \"Resistor_SMD:R_0805_2012Metric\")\n"
401 BOOST_REQUIRE_EQUAL( parsedNetlist.
GetCount(), 1 );
408 BOOST_CHECK( variant->
m_dnp );
412 auto valueIt = variant->
m_fields.find(
"Value" );
413 BOOST_CHECK( valueIt != variant->
m_fields.end() );
416 auto fpIt = variant->
m_fields.find(
"Footprint" );
417 BOOST_CHECK( fpIt != variant->
m_fields.end() );
483 wxString unicodeValue = wxT(
"1kΩ ±5% 日本語" );
493 wxString specialChars = wxT(
"R<1K>\"test\"'value'" );
502 wxString unicodeDesc = wxT(
"Variante für Produktion — 测试" );
521 BOOST_CHECK( board.
HasVariant(
"Variant1" ) );
528 BOOST_CHECK( !board.
HasVariant(
"Variant1" ) );
529 BOOST_CHECK( board.
HasVariant(
"Variant2" ) );
551 BOOST_CHECK( !board.
HasVariant(
"OldName" ) );
576 BOOST_CHECK( names.GetCount() >= 4 );
579 BOOST_CHECK( !names[0].IsEmpty() );
582 bool foundAlpha =
false;
583 bool foundBeta =
false;
584 bool foundZebra =
false;
586 for(
size_t i = 1; i < names.GetCount(); i++ )
588 if( names[i] == wxT(
"Alpha" ) )
590 else if( names[i] == wxT(
"Beta" ) )
592 else if( names[i] == wxT(
"Zebra" ) )
596 BOOST_CHECK( foundAlpha );
597 BOOST_CHECK( foundBeta );
598 BOOST_CHECK( foundZebra );
675 LIB_ID fpid( wxT(
"Resistor_SMD" ), wxT(
"R_0805_2012Metric" ) );
676 wxString reference = wxT(
"R1" );
677 wxString value = wxT(
"10K" );
679 std::vector<KIID> kiids;
686 variantA.
m_dnp =
true;
692 variantA.
m_fields[wxT(
"Datasheet" )] = wxT(
"https://example.com/datasheet.pdf" );
697 variantB.
m_dnp =
false;
703 variantB.
m_fields[wxT(
"Value" )] = wxT(
"22K" );
707 for(
const auto& [variantName, componentVariant] : component.
GetVariants() )
712 if( componentVariant.m_hasDnp )
713 fpVariant->
SetDNP( componentVariant.m_dnp );
715 if( componentVariant.m_hasExcludedFromBOM )
718 if( componentVariant.m_hasExcludedFromPosFiles )
721 for(
const auto& [fieldName, fieldValue] : componentVariant.m_fields )
728 BOOST_CHECK( fpVariantA->
GetDNP() );
731 BOOST_CHECK( fpVariantA->
HasFieldValue( wxT(
"Datasheet" ) ) );
733 wxT(
"https://example.com/datasheet.pdf" ) );
738 BOOST_CHECK( !fpVariantB->
GetDNP() );
775 initialVariant.
SetDNP(
true );
781 LIB_ID fpid( wxT(
"Resistor_SMD" ), wxT(
"R_0805_2012Metric" ) );
783 std::vector<KIID> kiids;
784 COMPONENT component( fpid, wxT(
"R1" ), wxT(
"10K" ),
path, kiids );
787 partialVariant.
m_dnp =
true;
793 for(
const auto& [variantName, componentVariant] : component.
GetVariants() )
799 bool targetDnp = componentVariant.m_hasDnp ? componentVariant.m_dnp : fp.
IsDNP();
800 fpVariant->
SetDNP( targetDnp );
802 bool targetBOM = componentVariant.m_hasExcludedFromBOM
803 ? componentVariant.m_excludedFromBOM
807 bool targetPos = componentVariant.m_hasExcludedFromPosFiles
808 ? componentVariant.m_excludedFromPosFiles
833 fp.
SetFPID(
LIB_ID( wxT(
"Resistor_SMD" ), wxT(
"R_0805" ) ) );
845 fpVariant->
SetDNP(
true );
868 fpVariant->
SetDNP( targetDnp );
874 "DNP should be reset to base value (false) when no explicit override" );
876 "ExcludedFromBOM should be reset to base value (false) when no override" );
878 "ExcludedFromPosFiles should be reset to base (false) when no override" );
898 std::unique_ptr<BOARD> board( pcbIo.
LoadBoard( dataPath,
nullptr ) );
907 for(
FOOTPRINT* fp : board->Footprints() )
909 if( fp->GetReference() == wxT(
"R2" ) )
911 wxString fpName = fp->GetFPID().GetLibItemName();
913 if( fpName.Contains( wxT(
"C_1210" ) ) )
915 else if( fpName.Contains( wxT(
"C_3640" ) ) )
922 BOOST_REQUIRE_MESSAGE( r2_c1210,
"Should find R2 with C_1210 footprint (variant footprint)" );
923 BOOST_REQUIRE_MESSAGE( r2_c3640,
"Should find R2 with C_3640 footprint (base footprint)" );
942 BOOST_CHECK_MESSAGE( !c1210_variantA->
GetDNP(),
943 "C_1210 Variant A DNP should be false (no schematic override)" );
945 "C_1210 Variant A ExcludedFromBOM should be false (no override)" );
947 "C_1210 Variant A ExcludedFromPosFiles should be false (no override)" );
963 BOOST_REQUIRE_MESSAGE( c3640_variantA,
964 "C_3640 must have Variant A data to hide it when Variant A is active" );
972 BOOST_CHECK_MESSAGE( c3640_variantA->
GetDNP(),
973 "C_3640 Variant A DNP should be true (it is not active for Variant A)" );
985 std::unique_ptr<BOARD> board( pcbIo.
LoadBoard( dataPath,
nullptr ) );
990 BOOST_CHECK( board->HasVariant(
"Variant A" ) );
999 for(
FOOTPRINT* fp : board->Footprints() )
1001 const wxString& ref = fp->GetReference();
1003 if( ref == wxT(
"R1" ) )
1010 BOOST_CHECK( variantA->
HasFieldValue( wxT(
"Datasheet" ) ) );
1014 else if( ref == wxT(
"R2" ) )
1016 wxString fpName = fp->GetFPID().GetLibItemName();
1018 if( fpName.Contains( wxT(
"C_3640" ) ) )
1024 BOOST_CHECK( variantA->
GetDNP() );
1026 else if( fpName.Contains( wxT(
"C_1210" ) ) )
1031 BOOST_CHECK( fp->IsDNP() );
1034 BOOST_CHECK( !variantA->
GetDNP() );
1037 else if( ref == wxT(
"R3" ) )
1044 BOOST_CHECK( variantA->
GetDNP() );
1073 auto runExport = [&](
const wxString& aVariant,
bool aCsv ) -> std::string
1091 std::string defaultAscii = runExport( wxEmptyString,
false );
1092 BOOST_CHECK( defaultAscii.find(
"10K" ) != std::string::npos );
1093 BOOST_CHECK( defaultAscii.find(
"22K" ) == std::string::npos );
1095 std::string altPopAscii = runExport( wxS(
"AltPop" ),
false );
1096 BOOST_CHECK( altPopAscii.find(
"22K" ) != std::string::npos );
1097 BOOST_CHECK( altPopAscii.find(
"10K" ) == std::string::npos );
1100 std::string defaultCsv = runExport( wxEmptyString,
true );
1101 BOOST_CHECK( defaultCsv.find(
"10K" ) != std::string::npos );
1102 BOOST_CHECK( defaultCsv.find(
"22K" ) == std::string::npos );
1104 std::string altPopCsv = runExport( wxS(
"AltPop" ),
true );
1105 BOOST_CHECK( altPopCsv.find(
"22K" ) != std::string::npos );
1106 BOOST_CHECK( altPopCsv.find(
"10K" ) == std::string::npos );
1109 auto runReport = [&](
const wxString& aVariant ) -> std::string
1112 true,
true,
false,
false,
false );
1117 std::string defaultReport = runReport( wxEmptyString );
1118 BOOST_CHECK( defaultReport.find(
"10K" ) != std::string::npos );
1119 BOOST_CHECK( defaultReport.find(
"22K" ) == std::string::npos );
1121 std::string altPopReport = runReport( wxS(
"AltPop" ) );
1122 BOOST_CHECK( altPopReport.find(
"22K" ) != std::string::npos );
1123 BOOST_CHECK( altPopReport.find(
"10K" ) == std::string::npos );
1141 fp.
SetFPID(
LIB_ID( wxT(
"Capacitor_SMD" ), wxT(
"C_0805" ) ) );
1151 fpVariant->
SetDNP(
true );
1154 BOOST_CHECK( fp.
GetVariant(
"TestVariant" ) !=
nullptr );
1163 std::set<wxString> excessVariants;
1166 excessVariants.insert( variantName );
1171 BOOST_CHECK( excessVariants.count(
"TestVariant" ) == 1 );
1173 for(
const wxString& excess : excessVariants )
1176 BOOST_CHECK_MESSAGE( fp.
GetVariant(
"TestVariant" ) ==
nullptr,
1177 "Stale variant must be removed when netlist has no variant data" );
1179 "All variants should be cleaned up" );
1192 fp.
SetFPID(
LIB_ID( wxT(
"Package_SO" ), wxT(
"SOIC-8" ) ) );
1201 prodVariant->
SetDNP(
true );
1211 std::set<wxString> excessVariants;
1214 excessVariants.insert( variantName );
1217 excessVariants.erase(
"Production" );
1220 BOOST_CHECK( excessVariants.count(
"Debug" ) == 1 );
1222 for(
const wxString& excess : excessVariants )
1225 BOOST_CHECK_MESSAGE( fp.
GetVariant(
"Production" ) !=
nullptr,
1226 "Production variant should be preserved (in netlist)" );
1227 BOOST_CHECK_MESSAGE( fp.
GetVariant(
"Debug" ) ==
nullptr,
1228 "Debug variant should be removed (not in netlist)" );
1252 std::unique_ptr<BOARD> board = std::make_unique<BOARD>();
1253 board->SetProject( &settingsManager.
Prj() );
1254 board->AddVariant(
"Variant A" );
1257 BOOST_REQUIRE_EQUAL( baseFpid.
Parse( wxS(
"TestLib:C_3640" ) ), -1 );
1260 BOOST_REQUIRE_EQUAL( variantFpid.
Parse( wxS(
"TestLib:C_1210" ) ), -1 );
1267 board->Add( baseFp );
1271 variantFp->
SetFPID( variantFpid );
1272 board->Add( variantFp );
1278 netlist.AddVariant(
"Variant A" );
1281 std::vector<KIID>{
KIID() } );
1285 variantA.m_dnp =
false;
1286 variantA.m_hasDnp =
true;
1288 netlist.AddComponent( component );
1291 toolMgr.
SetEnvironment( board.get(),
nullptr,
nullptr,
nullptr,
nullptr );
1302 "Base FP must be visible in the default variant" );
1304 "Variant A FP must be hidden in the default variant (globally DNP)" );
1309 "Variant A FP must be visible when Variant A is active" );
1311 "Base FP must be hidden when Variant A is active (issue #23298)" );
General utilities for PCB file IO for QA programs.
Update the BOARD with a new netlist.
bool UpdateNetlist(NETLIST &aNetlist)
Update the board's components according to the new netlist.
void SetDeleteUnusedFootprints(bool aEnabled)
void SetReplaceFootprints(bool aEnabled)
Information pertinent to a Pcbnew printed circuit board.
void SetCurrentVariant(const wxString &aVariant)
const std::vector< wxString > & GetVariantNames() const
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Removes an item from the container.
wxArrayString GetVariantNamesForUI() const
Return the variant names for UI display.
void DeleteVariant(const wxString &aVariantName)
bool ResolveTextVar(wxString *token, int aDepth) const
bool HasVariant(const wxString &aVariantName) const
void AddVariant(const wxString &aVariantName)
wxString GetVariantDescription(const wxString &aVariantName) const
wxString GetCurrentVariant() const
void RenameVariant(const wxString &aOldName, const wxString &aNewName)
void SetVariantDescription(const wxString &aVariantName, const wxString &aDescription)
Store all of the related component information found in a netlist.
void AddVariant(const COMPONENT_VARIANT &aVariant)
const COMPONENT_VARIANT * GetVariant(const wxString &aVariantName) const
const CASE_INSENSITIVE_MAP< COMPONENT_VARIANT > & GetVariants() const
The parser for reading the KiCad s-expression netlist format.
void Parse()
Function Parse parse the full netlist.
A logical library item identifier and consists of various portions much like a URI.
int Parse(const UTF8 &aId, bool aFix=false)
Parse LIB_ID with the information from aId.
Store information read from a netlist along with the flags used to update the NETLIST in the BOARD.
unsigned GetCount() const
COMPONENT * GetComponent(unsigned aIndex)
Return the COMPONENT at aIndex.
wxString GetShownText(bool aAllowExtraText, int aDepth=0) const override
Return the string actually shown after processing of the base text.
wxString GetName(bool aUseDefaultName=true) const
Return the field name (not translated).
A #PLUGIN derivation for saving and loading Pcbnew s-expression formatted files.
BOARD * LoadBoard(const wxString &aFileName, BOARD *aAppendToMe, const std::map< std::string, UTF8 > *aProperties=nullptr, PROJECT *aProject=nullptr) override
Load information from some input file format that this PCB_IO implementation knows about into either ...
The ASCII format of the kicad place file is:
std::string GenPositionData()
build a string filled with the position data
void SetVariant(const wxString &aVariant)
Set the variant name for variant-aware export.
std::string GenReportData()
build a string filled with the pad report data This report does not used options aForceSmdItems,...
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.
Is a LINE_READER that reads from a multiline 8 bit wide std::string.
std::string GetPcbnewTestDataDir()
Utility which returns a path to the data directory where the test board files are stored.
bool m_excludedFromPosFiles
bool m_hasExcludedFromBOM
bool m_hasExcludedFromPosFiles
nlohmann::ordered_map< wxString, wxString > m_fields
@ FOOTPRINT
Field Name Module PCB, i.e. "16DIP300".
wxString GetCanonicalFieldName(FIELD_T aFieldType)
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_AUTO_TEST_SUITE(CadstarPartParser)
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_AUTO_TEST_SUITE_END()
BOOST_TEST_MESSAGE("Polyline has "<< chain.PointCount()<< " points")
BOOST_CHECK_EQUAL(result, "25.4")
BOOST_AUTO_TEST_CASE(FootprintVariantBasics)
Test FOOTPRINT_VARIANT class basic operations.