68 std::unique_ptr<BOARD> testBoard = std::make_unique<BOARD>();
70 kicadPlugin.LoadBoard( dataPath +
"LayerWildcard.kicad_pcb", testBoard.get() );
73 BOOST_CHECK( testBoard->Zones().size() == 1 );
75 ZONE* z = testBoard->Zones()[0];
85 auto tmpBoard = std::filesystem::temp_directory_path() /
"Issue19775_RoundTrip.kicad_pcb";
89 std::unique_ptr<BOARD> testBoard = std::make_unique<BOARD>();
90 kicadPlugin.LoadBoard( dataPath +
"LayerEnumerate.kicad_pcb", testBoard.get() );
91 kicadPlugin.SaveBoard( tmpBoard.string(), testBoard.get() );
95 std::unique_ptr<BOARD> testBoard = std::make_unique<BOARD>();
96 kicadPlugin.LoadBoard( tmpBoard.string(), testBoard.get() );
99 BOOST_CHECK( testBoard->Zones().size() == 1 );
101 ZONE* z = testBoard->Zones()[0];
122 +
"plugins/kicad_sexpr/Issue23125_EmptyZone/";
124 std::unique_ptr<BOARD> testBoard = std::make_unique<BOARD>();
126 kicadPlugin.LoadBoard( dataPath +
"EmptyZone.kicad_pcb", testBoard.get() );
133 ZONE* z = testBoard->Zones()[0];
147 +
"plugins/kicad_sexpr/";
149 std::unique_ptr<BOARD> testBoard = std::make_unique<BOARD>();
151 kicadPlugin.LoadBoard( dataPath +
"ScientificNotation.kicad_pcb", testBoard.get() );
174 +
"plugins/kicad_sexpr/Issue23625_CorruptedStackup/";
176 std::unique_ptr<BOARD> testBoard = std::make_unique<BOARD>();
178 BOOST_CHECK_NO_THROW( kicadPlugin.LoadBoard( dataPath +
"corrupted_stackup.kicad_pcb",
182 testBoard->GetDesignSettings().GetStackupDescriptor();
187 BOOST_CHECK_LE( stackup.
GetCount(), 128 );
188 BOOST_CHECK_GT( stackup.
GetCount(), 0 );
202 +
"plugins/kicad_sexpr/Issue24133_DuplicatedStackup/";
204 std::unique_ptr<BOARD> testBoard = std::make_unique<BOARD>();
206 BOOST_CHECK_NO_THROW( kicadPlugin.LoadBoard( dataPath +
"duplicated_stackup.kicad_pcb",
209 const BOARD_STACKUP& stackup = testBoard->GetDesignSettings().GetStackupDescriptor();
231 std::string destinationPath = dataPath +
"issue3812.kicad_pcb";
233 std::string sourcePath = dataPath +
"issue18142.kicad_pcb";
234 std::map<std::string, UTF8> props;
248 int copperLayerCount = 0;
256 return copperLayerCount;
270 std::unique_ptr<BOARD> testBoard = std::make_unique<BOARD>();
272 kicadPlugin.LoadBoard( destinationPath, testBoard.get() );
274 const BOARD_STACKUP& initialStackup = testBoard->GetDesignSettings().GetStackupDescriptor();
275 const BOARD_STACKUP_ITEM* initialFirstDielectric = findFirstDielectric( initialStackup );
276 const int initialCopperLayerCount = testBoard->GetCopperLayerCount();
277 const LSET initialEnabledLayers = testBoard->GetEnabledLayers();
278 const wxString initialFinishType = initialStackup.
m_FinishType;
280 BOOST_REQUIRE_EQUAL( initialCopperLayerCount, 4 );
281 BOOST_REQUIRE_EQUAL( countCopperLayers( initialStackup ), 4 );
283 BOOST_REQUIRE_EQUAL( initialFinishType, wxS(
"ENIG" ) );
284 const wxString initialFirstDielectricMaterial = initialFirstDielectric->
GetMaterial();
285 const int initialFirstDielectricThickness = initialFirstDielectric->
GetThickness();
287 kicadPlugin.LoadBoard( sourcePath, testBoard.get(), &props );
289 const int appendedCopperLayerCount = testBoard->GetCopperLayerCount();
291 if( appendedCopperLayerCount > initialCopperLayerCount )
292 testBoard->SetCopperLayerCount( appendedCopperLayerCount );
294 LSET enabledLayers = testBoard->GetEnabledLayers();
295 enabledLayers |= initialEnabledLayers;
296 testBoard->SetEnabledLayers( enabledLayers );
297 testBoard->GetDesignSettings().GetStackupDescriptor().SynchronizeWithBoard( &testBoard->GetDesignSettings() );
299 const BOARD_STACKUP& finalStackup = testBoard->GetDesignSettings().GetStackupDescriptor();
323 std::string destinationPath = dataPath +
"issue3812.kicad_pcb";
325 std::string sourcePath = dataPath +
"issue18142.kicad_pcb";
327 std::map<std::string, UTF8> props;
330 std::unique_ptr<BOARD> testBoard = std::make_unique<BOARD>();
332 kicadPlugin.LoadBoard( destinationPath, testBoard.get() );
334 BOOST_REQUIRE_EQUAL( testBoard->GetLayerName(
F_Cu ), wxS(
"Top_layer" ) );
335 BOOST_REQUIRE_EQUAL( testBoard->GetLayerName(
In1_Cu ), wxS(
"GND_layer" ) );
336 BOOST_REQUIRE_EQUAL( testBoard->GetLayerName(
In2_Cu ), wxS(
"VDD_layer" ) );
337 BOOST_REQUIRE_EQUAL( testBoard->GetLayerName(
B_Cu ), wxS(
"Bottom_layer" ) );
339 kicadPlugin.LoadBoard( sourcePath, testBoard.get(), &props );
348 BOOST_CHECK( testBoard->IsLayerEnabled(
In3_Cu ) );
349 BOOST_CHECK( testBoard->IsLayerEnabled(
In4_Cu ) );
364 std::string sourcePath = dataPath +
"issue3812.kicad_pcb";
366 std::map<std::string, UTF8> props;
375 if( track->GetLayer() == aLayer )
383 const wxString fName = wxS(
"Top_layer" );
384 const wxString in1Name = wxS(
"GND_layer" );
385 const wxString in2Name = wxS(
"VDD_layer" );
386 const wxString bName = wxS(
"Bottom_layer" );
389 std::vector<wxString> seenNames;
391 kicadPlugin.RegisterCallback(
392 [&](
const std::vector<INPUT_LAYER_DESC>& aDescs ) -> std::map<wxString, PCB_LAYER_ID>
395 seenNames.push_back( desc.Name );
400 std::unique_ptr<BOARD> identityBoard = std::make_unique<BOARD>();
401 kicadPlugin.LoadBoard( sourcePath, identityBoard.get(), &props );
404 BOOST_CHECK( std::find( seenNames.begin(), seenNames.end(), in1Name ) != seenNames.end() );
405 BOOST_CHECK( std::find( seenNames.begin(), seenNames.end(), in2Name ) != seenNames.end() );
407 const int idIn1 = countTracksOn( identityBoard.get(),
In1_Cu );
408 const int idIn2 = countTracksOn( identityBoard.get(),
In2_Cu );
410 BOOST_REQUIRE_GT( idIn2, 0 );
413 kicadPlugin.RegisterCallback(
414 [&](
const std::vector<INPUT_LAYER_DESC>& ) -> std::map<wxString, PCB_LAYER_ID>
419 std::unique_ptr<BOARD> swapBoard = std::make_unique<BOARD>();
420 kicadPlugin.LoadBoard( sourcePath, swapBoard.get(), &props );
422 const int swIn1 = countTracksOn( swapBoard.get(),
In1_Cu );
423 const int swIn2 = countTracksOn( swapBoard.get(),
In2_Cu );
439 std::string standardNames = dataPath +
"issue18142.kicad_pcb";
440 std::string customNames = dataPath +
"issue3812.kicad_pcb";
442 std::map<std::string, UTF8> props;
445 bool handlerCalled =
false;
447 kicadPlugin.RegisterCallback(
448 [&](
const std::vector<INPUT_LAYER_DESC>& ) -> std::map<wxString, PCB_LAYER_ID>
450 handlerCalled =
true;
455 std::unique_ptr<BOARD> matchBoard = std::make_unique<BOARD>();
456 kicadPlugin.LoadBoard( standardNames, matchBoard.get() );
457 handlerCalled =
false;
458 kicadPlugin.LoadBoard( standardNames, matchBoard.get(), &props );
459 BOOST_CHECK( !handlerCalled );
462 std::unique_ptr<BOARD> mismatchBoard = std::make_unique<BOARD>();
463 kicadPlugin.LoadBoard( standardNames, mismatchBoard.get() );
464 handlerCalled =
false;
465 kicadPlugin.LoadBoard( customNames, mismatchBoard.get(), &props );
466 BOOST_CHECK( handlerCalled );
489 auto tmpLib = std::filesystem::temp_directory_path() /
"qa_fp_save_netinfo.pretty";
490 std::filesystem::remove_all( tmpLib );
491 std::filesystem::create_directories( tmpLib );
493 std::unique_ptr<BOARD> board = std::make_unique<BOARD>();
500 fp->
SetFPID(
LIB_ID( wxT(
"scratch" ), wxT(
"test_fp_save_netinfo" ) ) );
521 BOOST_REQUIRE_EQUAL(
pad->GetNet(), net );
522 BOOST_REQUIRE_EQUAL( shape->
GetNet(), net );
523 BOOST_REQUIRE_EQUAL( zone->
GetNet(), net );
526 BOOST_REQUIRE_NO_THROW( kicadPlugin.FootprintSave( tmpLib.string(), fp ) );
528 auto savedFile = tmpLib /
"test_fp_save_netinfo.kicad_mod";
531 std::ifstream in( savedFile );
532 BOOST_REQUIRE_MESSAGE( in.is_open(),
533 "Failed to open serialized footprint: " << savedFile.string() );
535 std::stringstream ss;
539 const std::string contents = ss.str();
543 "Saved footprint library file must not contain (net ...) tokens:\n"
551 std::unique_ptr<FOOTPRINT> detached(
static_cast<FOOTPRINT*
>( fp->
Clone() ) );
552 detached->SetParent(
nullptr );
553 detached->SetParentGroup(
nullptr );
554 detached->ClearAllNets();
560 detached->RunOnChildren(
563 switch( aItem->
Type() )
580 std::filesystem::remove_all( tmpLib );
594 std::unique_ptr<BOARD> writeBoard = std::make_unique<BOARD>();
596 ZONE* zone =
new ZONE( writeBoard.get() );
613 writeBoard->Add( zone );
615 std::filesystem::path tmpPath = std::filesystem::temp_directory_path()
616 /
"copper_thieving_roundtrip.kicad_pcb";
619 writer.
SaveBoard( tmpPath.string(), writeBoard.get() );
621 std::unique_ptr<BOARD> readBoard = std::make_unique<BOARD>();
623 reader.
LoadBoard( tmpPath.string(), readBoard.get() );
625 BOOST_REQUIRE_EQUAL( readBoard->Zones().size(), 1u );
627 ZONE* loaded = readBoard->Zones()[0];
641 std::filesystem::remove( tmpPath );
651 const std::array<THIEVING_PATTERN, 3> patterns = {
661 std::unique_ptr<BOARD> writeBoard = std::make_unique<BOARD>();
663 ZONE* zone =
new ZONE( writeBoard.get() );
675 writeBoard->Add( zone );
677 std::filesystem::path tmpPath = std::filesystem::temp_directory_path()
678 /
"copper_thieving_pattern.kicad_pcb";
680 writer.
SaveBoard( tmpPath.string(), writeBoard.get() );
682 std::unique_ptr<BOARD> readBoard = std::make_unique<BOARD>();
684 reader.
LoadBoard( tmpPath.string(), readBoard.get() );
686 BOOST_REQUIRE_EQUAL( readBoard->Zones().size(), 1u );
687 BOOST_CHECK( readBoard->Zones()[0]->GetThievingSettings().pattern == pattern );
689 std::filesystem::remove( tmpPath );
703 std::filesystem::path tmpPath = std::filesystem::temp_directory_path()
704 /
"copper_thieving_old_version.kicad_pcb";
705 std::ofstream out( tmpPath );
708 out <<
"(kicad_pcb (version 20260512) (generator \"test\") (generator_version \"test\")"
709 <<
" (general (thickness 1.6)) (paper \"A4\")"
710 <<
" (layers (0 \"F.Cu\" signal) (31 \"B.Cu\" signal))"
711 <<
" (zone (net 0) (net_name \"\") (layer \"F.Cu\") (uuid \"00000000-0000-0000-0000-000000000001\")"
712 <<
" (hatch edge 0.5)"
713 <<
" (connect_pads (clearance 0))"
714 <<
" (min_thickness 0.25) (filled_areas_thickness no)"
715 <<
" (fill yes (mode thieving) (thermal_gap 0.5) (thermal_bridge_width 0.5)"
716 <<
" (island_removal_mode 0))"
717 <<
" (polygon (pts (xy 0 0) (xy 5 0) (xy 5 5) (xy 0 5))))"
721 std::unique_ptr<BOARD> readBoard = std::make_unique<BOARD>();
723 BOOST_CHECK_THROW( reader.
LoadBoard( tmpPath.string(), readBoard.get() ),
IO_ERROR );
725 std::filesystem::remove( tmpPath );
737 std::filesystem::path tmpPath = std::filesystem::temp_directory_path()
738 /
"copper_thieving_malformed.kicad_pcb";
739 std::ofstream out( tmpPath );
740 out <<
"(kicad_pcb (version 20260513) (generator \"test\") (generator_version \"test\")"
741 <<
" (general (thickness 1.6)) (paper \"A4\")"
742 <<
" (layers (0 \"F.Cu\" signal) (31 \"B.Cu\" signal))"
743 <<
" (zone (net 0) (net_name \"\") (layer \"F.Cu\") (uuid \"00000000-0000-0000-0000-000000000002\")"
744 <<
" (hatch edge 0.5)"
745 <<
" (connect_pads (clearance 0))"
746 <<
" (min_thickness 0.25) (filled_areas_thickness no)"
747 <<
" (fill yes (mode thieving)"
748 <<
" (thermal_gap 0.5) (thermal_bridge_width 0.5)"
749 <<
" (island_removal_mode 0)"
750 <<
" (thieving (type dots) (size -1) (gap 0)"
751 <<
" (width -5) (stagger no) (orientation 0)))"
752 <<
" (polygon (pts (xy 0 0) (xy 5 0) (xy 5 5) (xy 0 5))))"
756 std::unique_ptr<BOARD> readBoard = std::make_unique<BOARD>();
758 reader.
LoadBoard( tmpPath.string(), readBoard.get() );
760 BOOST_REQUIRE_EQUAL( readBoard->Zones().size(), 1u );
764 BOOST_CHECK_GT( loaded.
gap, 0 );
767 std::filesystem::remove( tmpPath );
constexpr EDA_IU_SCALE pcbIUScale
General utilities for PCB file IO for QA programs.
@ BS_ITEM_TYPE_DIELECTRIC
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
virtual void SetNet(NETINFO_ITEM *aNetInfo)
Set a NET_INFO object for the item.
NETINFO_ITEM * GetNet() const
Return #NET_INFO object for a given item.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Manage one layer needed to make a physical board.
int GetThickness(int aDielectricSubLayer=0) const
wxString GetMaterial(int aDielectricSubLayer=0) const
Manage layers needed to make a physical board.
int BuildBoardThicknessFromStackup() const
wxString m_FinishType
The name of external copper finish.
Information pertinent to a Pcbnew printed circuit board.
const TRACKS & Tracks() const
KICAD_T Type() const
Returns the type of object.
VECTOR2I GetArcMid() const
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
A logical library item identifier and consists of various portions much like a URI.
LSET is a set of PCB_LAYER_IDs.
bool Contains(PCB_LAYER_ID aLayer) const
See if the layer set contains a PCB layer.
Handle the data for a net.
static NETINFO_ITEM * OrphanedItem()
NETINFO_ITEM meaning that there was no net assigned for an item, as there was no board storing net li...
static constexpr PCB_LAYER_ID ALL_LAYERS
! Temporary layer identifier to identify code that is not padstack-aware
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 ...
void SaveBoard(const wxString &aFileName, BOARD *aBoard, const std::map< std::string, UTF8 > *aProperties=nullptr) override
Write aBoard to a storage file in a format that this PCB_IO implementation knows about or it can be u...
void SetEnd(const VECTOR2I &aEnd) override
void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
void SetStart(const VECTOR2I &aStart) override
int TotalVertices() const
Return total number of vertices stored in the set.
Handle a list of polygons defining a copper zone.
const THIEVING_SETTINGS & GetThievingSettings() const
ZONE_LAYER_PROPERTIES & LayerProperties(PCB_LAYER_ID aLayer)
std::shared_ptr< SHAPE_POLY_SET > GetFilledPolysList(PCB_LAYER_ID aLayer) const
virtual void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
bool IsCopperThieving() const
void SetFillMode(ZONE_FILL_MODE aFillMode)
void SetThievingSettings(const THIEVING_SETTINGS &aSettings)
VECTOR2I GetPosition() const override
void SetNet(NETINFO_ITEM *aNetInfo) override
Override that drops aNetInfo when this zone is in copper-thieving fill mode.
ZONE_FILL_MODE GetFillMode() const
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
bool AppendCorner(VECTOR2I aPosition, int aHoleIdx, bool aAllowDuplication=false)
Add a new corner to the zone outline (to the main outline or a hole)
int GetNumCorners(void) const
Access to m_Poly parameters.
PCB_LAYER_ID
A quick note on layer IDs:
std::string GetPcbnewTestDataDir()
Utility which returns a path to the data directory where the test board files are stored.
constexpr char APPEND_PRESERVE_DESTINATION_STACKUP[]
PCB_IO_KICAD_SEXPR kicadPlugin
Parameters that drive copper-thieving fill generation.
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_AUTO_TEST_SUITE_END()
BOOST_TEST(netlist.find("R_G1 ARM_OUT1 DIE_B R='0.001 / ((SW_STATE)") !=std::string::npos)
BOOST_AUTO_TEST_CASE(Issue19775_ZoneLayerWildcards)
Declares the struct as the Boost test fixture.
BOOST_CHECK_MESSAGE(totalMismatches==0, std::to_string(totalMismatches)+" board(s) with strategy disagreements")
BOOST_TEST_CONTEXT("Test Clearance")
BOOST_CHECK_EQUAL(result, "25.4")
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
@ PCB_ZONE_T
class ZONE, a copper pour area
@ PCB_PAD_T
class PAD, a pad in a footprint
VECTOR2< int32_t > VECTOR2I
THIEVING_PATTERN
Shape stamped onto the grid for a copper-thieving fill.