27#include <boost/test/unit_test.hpp>
57 BOOST_CHECK( !variant.
GetDNP() );
61 BOOST_CHECK( variant.
GetFields().empty() );
70 BOOST_CHECK( variant.
GetDNP() );
92 BOOST_CHECK( board.
HasVariant(
"Production" ) );
101 BOOST_CHECK( board.
HasVariant(
"production" ) );
102 BOOST_CHECK( board.
HasVariant(
"PRODUCTION" ) );
103 BOOST_CHECK( board.
HasVariant(
"PrOdUcTiOn" ) );
144 prodVariant.
SetDNP(
false );
155 debugVariant.
SetDNP(
true );
176 prodVariant.
SetDNP(
true );
180 wxString token = wxS(
"DNP" );
184 token = wxS(
"DNP" );
188 token = wxS(
"EXCLUDE_FROM_SIM" );
192 token = wxS(
"EXCLUDE_FROM_SIM" );
300 prodVariant.
SetDNP(
true );
310 BOOST_CHECK( board.
HasVariant(
"production" ) );
311 BOOST_CHECK( board.
HasVariant(
"PRODUCTION" ) );
333 prodVariant.
SetDNP(
false );
356 prodVariant.
SetDNP(
false );
374 prodVariant.
SetDNP(
true );
383 BOOST_CHECK( copyVariant->
GetDNP() );
393 BOOST_CHECK( assignedVariant->
GetDNP() );
429 wxString variantToken = wxT(
"VARIANT" );
433 wxString descToken = wxT(
"VARIANT_DESC" );
438 wxString defaultToken = wxT(
"VARIANT" );
440 BOOST_CHECK( defaultToken.IsEmpty() );
447 "(export (version 1)\n"
451 " (footprint Resistor_SMD:R_0603_1608Metric)\n"
452 " (libsource (lib Device) (part R))\n"
454 " (variant (name Alt)\n"
455 " (property (name dnp) (value 1))\n"
456 " (property (name exclude_from_bom) (value 0))\n"
457 " (property (name exclude_from_sim) (value 1))\n"
459 " (field (name Value) \"22K\")\n"
460 " (field (name Footprint) \"Resistor_SMD:R_0805_2012Metric\")\n"
474 BOOST_REQUIRE_EQUAL( parsedNetlist.
GetCount(), 1 );
481 BOOST_CHECK( variant->
m_dnp );
487 auto valueIt = variant->
m_fields.find(
"Value" );
488 BOOST_CHECK( valueIt != variant->
m_fields.end() );
491 auto fpIt = variant->
m_fields.find(
"Footprint" );
492 BOOST_CHECK( fpIt != variant->
m_fields.end() );
558 wxString unicodeValue = wxT(
"1kΩ ±5% 日本語" );
568 wxString specialChars = wxT(
"R<1K>\"test\"'value'" );
577 wxString unicodeDesc = wxT(
"Variante für Produktion — 测试" );
596 BOOST_CHECK( board.
HasVariant(
"Variant1" ) );
603 BOOST_CHECK( !board.
HasVariant(
"Variant1" ) );
604 BOOST_CHECK( board.
HasVariant(
"Variant2" ) );
626 BOOST_CHECK( !board.
HasVariant(
"OldName" ) );
651 BOOST_CHECK( names.GetCount() >= 4 );
654 BOOST_CHECK( !names[0].IsEmpty() );
657 bool foundAlpha =
false;
658 bool foundBeta =
false;
659 bool foundZebra =
false;
661 for(
size_t i = 1; i < names.GetCount(); i++ )
663 if( names[i] == wxT(
"Alpha" ) )
665 else if( names[i] == wxT(
"Beta" ) )
667 else if( names[i] == wxT(
"Zebra" ) )
671 BOOST_CHECK( foundAlpha );
672 BOOST_CHECK( foundBeta );
673 BOOST_CHECK( foundZebra );
758 LIB_ID fpid( wxT(
"Resistor_SMD" ), wxT(
"R_0805_2012Metric" ) );
759 wxString reference = wxT(
"R1" );
760 wxString value = wxT(
"10K" );
762 std::vector<KIID> kiids;
769 variantA.
m_dnp =
true;
777 variantA.
m_fields[wxT(
"Datasheet" )] = wxT(
"https://example.com/datasheet.pdf" );
782 variantB.
m_dnp =
false;
790 variantB.
m_fields[wxT(
"Value" )] = wxT(
"22K" );
794 for(
const auto& [variantName, componentVariant] : component.
GetVariants() )
799 if( componentVariant.m_hasDnp )
800 fpVariant->
SetDNP( componentVariant.m_dnp );
802 if( componentVariant.m_hasExcludedFromBOM )
805 if( componentVariant.m_hasExcludedFromSim )
808 if( componentVariant.m_hasExcludedFromPosFiles )
811 for(
const auto& [fieldName, fieldValue] : componentVariant.m_fields )
818 BOOST_CHECK( fpVariantA->
GetDNP() );
822 BOOST_CHECK( fpVariantA->
HasFieldValue( wxT(
"Datasheet" ) ) );
824 wxT(
"https://example.com/datasheet.pdf" ) );
829 BOOST_CHECK( !fpVariantB->
GetDNP() );
870 initialVariant.
SetDNP(
true );
877 LIB_ID fpid( wxT(
"Resistor_SMD" ), wxT(
"R_0805_2012Metric" ) );
879 std::vector<KIID> kiids;
880 COMPONENT component( fpid, wxT(
"R1" ), wxT(
"10K" ),
path, kiids );
883 partialVariant.
m_dnp =
true;
889 for(
const auto& [variantName, componentVariant] : component.
GetVariants() )
895 bool targetDnp = componentVariant.m_hasDnp ? componentVariant.m_dnp : fp.
IsDNP();
896 fpVariant->
SetDNP( targetDnp );
898 bool targetBOM = componentVariant.m_hasExcludedFromBOM
899 ? componentVariant.m_excludedFromBOM
903 bool targetSim = componentVariant.m_hasExcludedFromSim
904 ? componentVariant.m_excludedFromSim
908 bool targetPos = componentVariant.m_hasExcludedFromPosFiles
909 ? componentVariant.m_excludedFromPosFiles
937 fp.
SetFPID(
LIB_ID( wxT(
"Resistor_SMD" ), wxT(
"R_0805" ) ) );
950 fpVariant->
SetDNP(
true );
977 fpVariant->
SetDNP( targetDnp );
984 "DNP should be reset to base value (false) when no explicit override" );
986 "ExcludedFromBOM should be reset to base value (false) when no override" );
988 "ExcludedFromSim should be reset to base value (false) when no override" );
990 "ExcludedFromPosFiles should be reset to base (false) when no override" );
1010 std::unique_ptr<BOARD> board = pcbIo.
LoadBoard( dataPath );
1019 for(
FOOTPRINT* fp : board->Footprints() )
1021 if( fp->GetReference() == wxT(
"R2" ) )
1023 wxString fpName = fp->GetFPID().GetLibItemName();
1025 if( fpName.Contains( wxT(
"C_1210" ) ) )
1027 else if( fpName.Contains( wxT(
"C_3640" ) ) )
1034 BOOST_REQUIRE_MESSAGE( r2_c1210,
"Should find R2 with C_1210 footprint (variant footprint)" );
1035 BOOST_REQUIRE_MESSAGE( r2_c3640,
"Should find R2 with C_3640 footprint (base footprint)" );
1046 if( c1210_variantA )
1054 BOOST_CHECK_MESSAGE( !c1210_variantA->
GetDNP(),
1055 "C_1210 Variant A DNP should be false (no schematic override)" );
1057 "C_1210 Variant A ExcludedFromBOM should be false (no override)" );
1059 "C_1210 Variant A ExcludedFromPosFiles should be false (no override)" );
1075 BOOST_REQUIRE_MESSAGE( c3640_variantA,
1076 "C_3640 must have Variant A data to hide it when Variant A is active" );
1084 BOOST_CHECK_MESSAGE( c3640_variantA->
GetDNP(),
1085 "C_3640 Variant A DNP should be true (it is not active for Variant A)" );
1097 std::unique_ptr<BOARD> board = pcbIo.
LoadBoard( dataPath );
1102 BOOST_CHECK( board->HasVariant(
"Variant A" ) );
1111 for(
FOOTPRINT* fp : board->Footprints() )
1113 const wxString& ref = fp->GetReference();
1115 if( ref == wxT(
"R1" ) )
1122 BOOST_CHECK( variantA->
HasFieldValue( wxT(
"Datasheet" ) ) );
1126 else if( ref == wxT(
"R2" ) )
1128 wxString fpName = fp->GetFPID().GetLibItemName();
1130 if( fpName.Contains( wxT(
"C_3640" ) ) )
1136 BOOST_CHECK( variantA->
GetDNP() );
1138 else if( fpName.Contains( wxT(
"C_1210" ) ) )
1143 BOOST_CHECK( fp->IsDNP() );
1146 BOOST_CHECK( !variantA->
GetDNP() );
1149 else if( ref == wxT(
"R3" ) )
1156 BOOST_CHECK( variantA->
GetDNP() );
1185 auto runExport = [&](
const wxString& aVariant,
bool aCsv ) -> std::string
1203 std::string defaultAscii = runExport( wxEmptyString,
false );
1204 BOOST_CHECK( defaultAscii.find(
"10K" ) != std::string::npos );
1205 BOOST_CHECK( defaultAscii.find(
"22K" ) == std::string::npos );
1207 std::string altPopAscii = runExport( wxS(
"AltPop" ),
false );
1208 BOOST_CHECK( altPopAscii.find(
"22K" ) != std::string::npos );
1209 BOOST_CHECK( altPopAscii.find(
"10K" ) == std::string::npos );
1212 std::string defaultCsv = runExport( wxEmptyString,
true );
1213 BOOST_CHECK( defaultCsv.find(
"10K" ) != std::string::npos );
1214 BOOST_CHECK( defaultCsv.find(
"22K" ) == std::string::npos );
1216 std::string altPopCsv = runExport( wxS(
"AltPop" ),
true );
1217 BOOST_CHECK( altPopCsv.find(
"22K" ) != std::string::npos );
1218 BOOST_CHECK( altPopCsv.find(
"10K" ) == std::string::npos );
1221 auto runReport = [&](
const wxString& aVariant ) -> std::string
1224 true,
true,
false,
false,
false );
1229 std::string defaultReport = runReport( wxEmptyString );
1230 BOOST_CHECK( defaultReport.find(
"10K" ) != std::string::npos );
1231 BOOST_CHECK( defaultReport.find(
"22K" ) == std::string::npos );
1233 std::string altPopReport = runReport( wxS(
"AltPop" ) );
1234 BOOST_CHECK( altPopReport.find(
"22K" ) != std::string::npos );
1235 BOOST_CHECK( altPopReport.find(
"10K" ) == std::string::npos );
1253 fp.
SetFPID(
LIB_ID( wxT(
"Capacitor_SMD" ), wxT(
"C_0805" ) ) );
1263 fpVariant->
SetDNP(
true );
1266 BOOST_CHECK( fp.
GetVariant(
"TestVariant" ) !=
nullptr );
1275 std::set<wxString> excessVariants;
1278 excessVariants.insert( variantName );
1283 BOOST_CHECK( excessVariants.count(
"TestVariant" ) == 1 );
1285 for(
const wxString& excess : excessVariants )
1288 BOOST_CHECK_MESSAGE( fp.
GetVariant(
"TestVariant" ) ==
nullptr,
1289 "Stale variant must be removed when netlist has no variant data" );
1291 "All variants should be cleaned up" );
1304 fp.
SetFPID(
LIB_ID( wxT(
"Package_SO" ), wxT(
"SOIC-8" ) ) );
1313 prodVariant->
SetDNP(
true );
1323 std::set<wxString> excessVariants;
1326 excessVariants.insert( variantName );
1329 excessVariants.erase(
"Production" );
1332 BOOST_CHECK( excessVariants.count(
"Debug" ) == 1 );
1334 for(
const wxString& excess : excessVariants )
1337 BOOST_CHECK_MESSAGE( fp.
GetVariant(
"Production" ) !=
nullptr,
1338 "Production variant should be preserved (in netlist)" );
1339 BOOST_CHECK_MESSAGE( fp.
GetVariant(
"Debug" ) ==
nullptr,
1340 "Debug variant should be removed (not in netlist)" );
1364 std::unique_ptr<BOARD> board = std::make_unique<BOARD>();
1365 board->SetProject( &settingsManager.
Prj() );
1366 board->AddVariant(
"Variant A" );
1369 BOOST_REQUIRE_EQUAL( baseFpid.
Parse( wxS(
"TestLib:C_3640" ) ), -1 );
1372 BOOST_REQUIRE_EQUAL( variantFpid.
Parse( wxS(
"TestLib:C_1210" ) ), -1 );
1379 board->Add( baseFp );
1383 variantFp->
SetFPID( variantFpid );
1384 board->Add( variantFp );
1390 netlist.AddVariant(
"Variant A" );
1393 std::vector<KIID>{
KIID() } );
1397 variantA.m_dnp =
false;
1398 variantA.m_hasDnp =
true;
1400 netlist.AddComponent( component );
1403 toolMgr.
SetEnvironment( board.get(),
nullptr,
nullptr,
nullptr,
nullptr );
1414 "Base FP must be visible in the default variant" );
1416 "Variant A FP must be hidden in the default variant (globally DNP)" );
1421 "Variant A FP must be visible when Variant A is active" );
1423 "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(RESOLUTION_CONTEXT aContext, 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.
std::unique_ptr< BOARD > LoadBoard(const wxString &aFileName, const std::map< std::string, UTF8 > *aProperties=nullptr, PROJECT *aProject=nullptr)
Load information from some input file format that this PCB_IO implementation knows about into new BOA...
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_hasExcludedFromSim
bool m_hasExcludedFromPosFiles
nlohmann::ordered_map< wxString, wxString > m_fields
wxString GetDefaultFieldName(FIELD_T aFieldId, TRANSLATION aTranslation)
Return a default symbol field name for a mandatory field type.
@ FOOTPRINT
Field Name Module PCB, i.e. "16DIP300".
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.