20#include <boost/test/unit_test.hpp>
31#include <wx/imagpng.h>
32#include <wx/mstream.h>
61#include <nlohmann/json.hpp>
93 BOOST_CHECK( !report.
IsLossy() );
95 BOOST_CHECK( report.
Entries().empty() );
107 BOOST_CHECK( report.
IsLossy() );
118 DOWNGRADE_TARGET future = { wxT(
"future" ), wxT(
"future" ), 20260623, 20260629, 20260629 };
121 BOOST_CHECK( !report.
IsLossy() );
131 board.
Add( ellipse );
149 board.
Add( ellipse );
160 BOOST_CHECK_CLOSE( areaMM,
M_PI * 5.0 * 3.0, 2.0 );
184 BOOST_CHECK_GT( areaMM, 1.5 );
185 BOOST_CHECK_LT( areaMM, 2.6 );
195 board.
Add( textbox );
211 table->SetColCount( 1 );
215 table->AddCell( cell );
243 table->SetColCount( 1 );
247 table->AddCell( cell );
281 BOOST_CHECK_CLOSE( areaMM, 60.0 - ( 4.0 -
M_PI ), 2.0 );
332 const std::string src = ( tmp.
GetPath() /
"source.kicad_pcb" ).string();
336 std::unique_ptr<BOARD> current( io.
LoadBoard( src,
nullptr ) );
338 const auto& loadedDefaults = current->GetDesignSettings().m_ZoneLayerProperties;
339 BOOST_REQUIRE_EQUAL( loadedDefaults.size(), 2 );
340 BOOST_CHECK( loadedDefaults.at(
F_Cu ).hatching_offset ==
VECTOR2I( 100000, 200000 ) );
341 BOOST_CHECK( loadedDefaults.at(
B_Cu ).hatching_offset ==
VECTOR2I( 300000, 400000 ) );
342 BOOST_CHECK( current->GetDesignSettings().GetDefaultZoneSettings().m_LayerProperties.empty() );
347 const std::string dest = ( tmp.
GetPath() / ( target.m_id.ToStdString() +
".kicad_pcb" ) ).string();
349 std::unique_ptr<BOARD> reloaded( io.
LoadBoard( dest,
nullptr ) );
351 const auto& defaults = reloaded->GetDesignSettings().m_ZoneLayerProperties;
353 if( target.m_id == wxT(
"9.0" ) )
356 BOOST_CHECK( defaults.empty() );
361 BOOST_CHECK( !report.
IsLossy() );
362 BOOST_REQUIRE_EQUAL( defaults.size(), 2 );
363 BOOST_CHECK( defaults.at(
F_Cu ).hatching_offset == loadedDefaults.at(
F_Cu ).hatching_offset );
364 BOOST_CHECK( defaults.at(
B_Cu ).hatching_offset == loadedDefaults.at(
B_Cu ).hatching_offset );
392 via->Padstack().Drill().is_capped =
true;
399 BOOST_CHECK( !
via->Padstack().Drill().is_capped.has_value() );
424 group->SetDesignBlockLibId(
LIB_ID( wxT(
"Lib" ), wxT(
"Block" ) ) );
431 BOOST_CHECK( !
group->HasDesignBlockLink() );
490 const wxString dest = ( tmp.
GetPath() /
"out.kicad_pcb" ).wstring();
491 const wxString victim = ( tmp.
GetPath() /
"victim.txt" ).wstring();
494 wxFFile file( victim, wxT(
"wb" ) );
496 file.Write( wxT(
"untouched" ) );
499 const wxString decoy =
500 dest + wxString::Format( wxT(
".downgrade_tmp.%lu" ), (
unsigned long) wxGetProcessId() );
502 std::filesystem::create_symlink( victim.ToStdString(), decoy.ToStdString(), ec );
510 wxFFile file( victim, wxT(
"rb" ) );
514 BOOST_CHECK( after == wxT(
"untouched" ) );
517 const wxString reference = ( tmp.
GetPath() /
"reference.kicad_pcb" ).wstring();
519 std::unique_ptr<BOARD> board( io.
LoadBoard( dest,
nullptr ) );
523 BOOST_CHECK( std::filesystem::status( dest.ToStdString() ).permissions()
524 == std::filesystem::status( reference.ToStdString() ).permissions() );
542 const wxString src = ( tmp.
GetPath() /
"src.kicad_pcb" ).wstring();
543 const wxString dest = ( tmp.
GetPath() /
"out.kicad_pcb" ).wstring();
551 BOOST_CHECK( !wxFileExists( dest ) );
587 BOOST_CHECK( !
pad->Padstack().FrontPostMachining().mode.has_value() );
634 const std::string dest = ( tmp.
GetPath() /
"out.kicad_pcb" ).string();
641 std::unique_ptr<BOARD> exported( io.
LoadBoard( dest,
nullptr ) );
644 BOOST_REQUIRE_EQUAL(
source->Footprints().size(), exported->Footprints().size() );
646 for(
size_t i = 0; i <
source->Footprints().size(); i++ )
649 FOOTPRINT* b = exported->Footprints()[i];
655 BOOST_REQUIRE_EQUAL( a->
Pads().size(), b->
Pads().size() );
657 for(
size_t p = 0; p < a->
Pads().size(); p++ )
658 BOOST_CHECK( a->
Pads()[p]->GetPosition() == b->
Pads()[p]->GetPosition() );
671 const std::string dest = ( tmp.
GetPath() /
"out.kicad_pcb" ).string();
678 std::unique_ptr<BOARD> exported( io.
LoadBoard( dest,
nullptr ) );
681 BOOST_REQUIRE_EQUAL(
source->Footprints().size(), exported->Footprints().size() );
683 for(
size_t i = 0; i <
source->Footprints().size(); i++ )
686 FOOTPRINT* b = exported->Footprints()[i];
690 BOOST_REQUIRE_EQUAL( a->
Pads().size(), b->
Pads().size() );
692 for(
size_t pd = 0; pd < a->
Pads().size(); pd++ )
693 BOOST_CHECK( a->
Pads()[pd]->GetPosition() == b->
Pads()[pd]->GetPosition() );
737 board.
Add( barcode );
769 BOOST_CHECK_GT( polyCount, 1 );
770 BOOST_CHECK_GT( areaMM, 5.0 );
771 BOOST_CHECK_CLOSE( areaMM, expectedMM, 0.1 );
778 wxString projectPath = ( tmp.
GetPath() /
"source.kicad_pro" ).string();
779 wxString boardPath = ( tmp.
GetPath() /
"source.kicad_pcb" ).string();
780 wxString outputPath = ( tmp.
GetPath() /
"output.kicad_pcb" ).string();
783 std::ofstream
project( projectPath.ToStdString() );
784 project << R
"({"meta":{"version":3},"text_variables":{"SERIAL":"SERIAL123"}})";
798 board.
Add( barcode );
805 double expectedArea =
expected.Area();
813 int polygonCount = 0;
814 double resultArea = 0;
830 BOOST_CHECK_CLOSE( resultArea, expectedArea, 0.01 );
861 BOOST_CHECK_GT( polyCount, 1 );
873 std::unique_ptr<FOOTPRINT> fp( loader.
ImportFootprint( src, nameOut ) );
879 const wxString dest = ( tmp.
GetPath() /
"out.kicad_mod" ).wstring();
884 std::ifstream out( dest.ToStdString() );
885 std::string content( ( std::istreambuf_iterator<char>( out ) ), std::istreambuf_iterator<char>() );
886 BOOST_CHECK( content.find(
"(version " + std::to_string(
kicad9.m_boardVersion ) +
")" ) != std::string::npos );
890 std::unique_ptr<FOOTPRINT> reloaded( reader.
ImportFootprint( dest, reloadName ) );
891 BOOST_CHECK( reloaded !=
nullptr );
904 std::unique_ptr<FOOTPRINT> fp( loader.
ImportFootprint( src, nameOut ) );
910 const wxString dest = ( tmp.
GetPath() /
"out.kicad_mod" ).wstring();
914 std::ifstream out( dest.ToStdString() );
915 std::string content( ( std::istreambuf_iterator<char>( out ) ), std::istreambuf_iterator<char>() );
916 BOOST_CHECK( content.find(
"(version " + std::to_string(
kicad10.m_boardVersion ) +
")" ) != std::string::npos );
920 std::unique_ptr<FOOTPRINT> reloaded( reader.
ImportFootprint( dest, reloadName ) );
921 BOOST_CHECK( reloaded !=
nullptr );
950 std::string dest = ( tmp.
GetPath() /
"out.kicad_pcb" ).string();
955 std::unique_ptr<BOARD> reloaded( reader.
LoadBoard( dest,
nullptr ) );
967 std::unique_ptr<FOOTPRINT> fp = std::make_unique<FOOTPRINT>(
nullptr );
968 fp->GetFields().push_back(
nullptr );
971 const wxString dest = ( tmp.
GetPath() /
"out.kicad_mod" ).wstring();
975 BOOST_CHECK( std::filesystem::exists( dest.ToStdString() ) );
987 board.
Add( onBoard );
992 group->AddItem( onBoard );
993 group->AddItem( stale );
997 const std::string dest = ( tmp.
GetPath() /
"out.kicad_pcb" ).string();
1001 std::ifstream out( dest );
1002 std::string content( ( std::istreambuf_iterator<char>( out ) ), std::istreambuf_iterator<char>() );
1004 BOOST_CHECK( content.find( onBoard->
m_Uuid.
AsString().ToStdString() ) != std::string::npos );
1005 BOOST_CHECK( content.find( stale->
m_Uuid.
AsString().ToStdString() ) == std::string::npos );
1024 const std::string dest = ( tmp.
GetPath() /
"out.kicad_pcb" ).string();
1028 std::ifstream out( dest );
1029 std::string content( ( std::istreambuf_iterator<char>( out ) ), std::istreambuf_iterator<char>() );
1031 BOOST_CHECK( content.find(
"(remove_unused_layers yes)" ) != std::string::npos );
1032 BOOST_CHECK( content.find(
"(keep_end_layers yes)" ) != std::string::npos );
1035 std::unique_ptr<BOARD> reloaded( reader.
LoadBoard( dest,
nullptr ) );
1037 BOOST_REQUIRE_EQUAL( reloaded->Tracks().size(), 1 );
1039 const PCB_VIA* reloadedVia =
static_cast<const PCB_VIA*
>( reloaded->Tracks().front() );
1056 board.
Add( otherImage );
1072 const std::string dest = ( tmp.
GetPath() /
"out.kicad_pcb" ).string();
1077 std::ifstream out( dest );
1078 std::string content( ( std::istreambuf_iterator<char>( out ) ), std::istreambuf_iterator<char>() );
1081 BOOST_CHECK_CLOSE( written, originalScale * legacyPPI / ppi, 0.1 );
1083 0.5 * legacyPPI / ppi, 0.1 );
1092 == wxT(
"transform" ) );
1109 const wxString rules = wxT(
"(version 2)\n"
1111 "(rule \"clearance_ok\"\n"
1112 " # chamfer runs at 45deg here\n"
1113 " (constraint clearance (min 0.2mm))\n"
1114 " (condition \"A.NetClass == 'HV'\"))\n"
1115 "(rule \"mask_check\"\n"
1116 " (constraint bridged_mask))\n"
1117 "(rule \"chain_check\"\n"
1118 " (condition \"inNetChain('x')\")\n"
1119 " (constraint clearance (min 0.1mm)))\n"
1120 "(rule \"delay_check\"\n"
1121 " (constraint skew (max 5ps)))\n" );
1125 BOOST_REQUIRE_EQUAL(
result.m_dropped.size(), 3 );
1126 BOOST_CHECK(
result.m_dropped[0] == wxT(
"mask_check" ) );
1127 BOOST_CHECK(
result.m_dropped[1] == wxT(
"chain_check" ) );
1128 BOOST_CHECK(
result.m_dropped[2] == wxT(
"delay_check" ) );
1130 BOOST_CHECK(
result.m_text.Contains( wxT(
"(version 1)" ) ) );
1131 BOOST_CHECK(
result.m_text.Contains( wxT(
"# keep me" ) ) );
1132 BOOST_CHECK(
result.m_text.Contains( wxT(
"(rule \"clearance_ok\"" ) ) );
1133 BOOST_CHECK(
result.m_text.Contains( wxT(
"A.NetClass == 'HV'" ) ) );
1134 BOOST_CHECK( !
result.m_text.Contains( wxT(
"bridged_mask" ) ) );
1135 BOOST_CHECK( !
result.m_text.Contains( wxT(
"inNetChain" ) ) );
1136 BOOST_CHECK( !
result.m_text.Contains( wxT(
"5ps" ) ) );
1142 const wxString rules = wxT(
"(version 1)\n"
1143 "(rule \"return_path\" (constraint clearance (min 0.2mm)))\n"
1144 "(rule inNetChain (constraint clearance (min 0.2mm)))\n"
1145 "(rule \"literal\" (condition \"A.NetName == 'hasNetChain() 100 ps .Parent.'\")\n"
1146 " (constraint clearance (min 0.2mm)))\n" );
1151 BOOST_CHECK(
result.m_error.IsEmpty() );
1152 BOOST_CHECK(
result.m_dropped.empty() );
1160 const wxString rules = wxT(
"(version 1)\n"
1161 "(rule \"time\" (constraint length (min \"100 ps\")))\n"
1162 "(rule \"femtoseconds\" (constraint length (max \"2 * 100 fs\")))\n"
1163 "(rule \"angle\" (constraint track_angle (max \"90 deg\")))\n"
1164 "(rule \"ordinary\" (constraint clearance (min \"0.2 mm\")))\n" );
1167 BOOST_CHECK( result9.
m_error.IsEmpty() );
1169 BOOST_CHECK( result9.
m_text.Contains(
"ordinary" ) );
1172 BOOST_CHECK( result10.
m_error.IsEmpty() );
1173 BOOST_CHECK( result10.
m_dropped.empty() );
1181 const wxString rules = wxT(
"(version 2)\n"
1182 "(rule \"mask_check\" (constraint bridged_mask))\n"
1183 "(rule \"delay_check\" (constraint skew (max 5ps)))\n"
1184 "(rule \"chain_check\" (constraint net_chain_length (max 10mm)))\n" );
1188 BOOST_REQUIRE_EQUAL(
result.m_dropped.size(), 1 );
1189 BOOST_CHECK(
result.m_dropped[0] == wxT(
"chain_check" ) );
1190 BOOST_CHECK(
result.m_text.Contains( wxT(
"bridged_mask" ) ) );
1191 BOOST_CHECK(
result.m_text.Contains( wxT(
"5ps" ) ) );
1199 const wxString kept = wxT(
"(rule \"clearance # literal\"\n"
1200 " # unmatched: ) (( \" \\\n"
1201 " (condition \"A.NetName == 'SIGNAL#1'\")\n"
1202 " # inNetChain('x')\n"
1203 " (constraint clearance (min 0.2mm))\n"
1206 "(rule \"second\" (constraint track_width (min 0.25mm)))" );
1207 const wxString input = wxT(
"(version 2)\n" ) + kept
1208 + wxT(
"\n(rule \"unsupported\"\n # ) \" (\n"
1209 " (constraint net_chain_length (max 10mm)))\n" );
1215 BOOST_REQUIRE_EQUAL(
result.m_dropped.size(), 1 );
1216 BOOST_CHECK(
result.m_dropped.front() == wxT(
"unsupported" ) );
1217 BOOST_CHECK(
result.m_text.Contains( kept ) );
1221 std::vector<std::shared_ptr<DRC_RULE>> rules;
1224 BOOST_REQUIRE_EQUAL( rules.size(), 2 );
1235 for(
const wxString& input : { wxT(
"(version 1)\n(rule \"inline\" # )\n (constraint clearance (min 0.2mm)))" ),
1236 wxT(
"(version 1)\n(rule \"missing_close\" (constraint clearance (min 0.2mm))" ),
1237 wxT(
"(version 1)\n(rule \"missing_quote" ) } )
1254 const std::string release = target.m_id == wxT(
"9.0" ) ?
"v9" :
"v10";
1259 std::vector<std::shared_ptr<DRC_RULE>> rules;
1282 BOOST_CHECK( fp->
IsDNP() );
1284 BOOST_CHECK( fp->
GetField( wxT(
"Value" ) )->GetText() == wxT(
"10k" ) );
1292 nlohmann::json doc = {
1293 {
"meta", { {
"filename",
"p.kicad_pro" }, {
"version", 3 } } },
1294 {
"board", { {
"layer_presets", { { {
"name",
"P" }, {
"renderLayers", {
"tracks",
"vias" } } } } } } },
1296 { {
"meta", { {
"version", 5 } } },
1297 {
"classes", { { {
"name",
"Default" }, {
"priority", 0 }, {
"tuning_profile",
"tp" } } } },
1298 {
"net_chain_classes", { { {
"name",
"chainA" } } } } } },
1299 {
"tuning_profiles",
1300 { {
"meta", { {
"version", 1 } } },
1301 {
"tuning_profiles_impedance_geometric",
1302 { { {
"name",
"tp" }, {
"frequency", 1e9 }, {
"model_solder_mask",
false } } } } } },
1303 {
"component_class_settings", { {
"meta", { {
"version", 0 } } } } },
1305 { {
"top_level_sheets", {
"aaaa" } },
1306 {
"bus_aliases", nlohmann::json::array() },
1307 {
"variants", nlohmann::json::array() } } },
1317 const nlohmann::json& preset = doc[
"board"][
"layer_presets"][0];
1319 BOOST_REQUIRE_EQUAL( preset[
"renderLayers"].size(), 2 );
1324 BOOST_CHECK( !doc[
"net_settings"][
"classes"][0].contains(
"tuning_profile" ) );
1325 BOOST_CHECK( doc[
"net_settings"][
"classes"][0].contains(
"name" ) );
1326 BOOST_CHECK( !doc[
"net_settings"].contains(
"net_chain_classes" ) );
1327 BOOST_CHECK( !doc.contains(
"tuning_profiles" ) );
1328 BOOST_CHECK( !doc.contains(
"component_class_settings" ) );
1329 BOOST_CHECK( !doc[
"schematic"].contains(
"top_level_sheets" ) );
1330 BOOST_CHECK( !doc[
"schematic"].contains(
"bus_aliases" ) );
1331 BOOST_CHECK( !doc[
"schematic"].contains(
"variants" ) );
1334 BOOST_CHECK( report.
IsLossy() );
1341 const nlohmann::json
empty = nlohmann::json::array();
1342 const std::vector<nlohmann::json> tuningDefaults = {
1344 nlohmann::json::object(),
1345 { {
"meta", { {
"version", 2 } } } },
1346 { {
"meta", { {
"version", 2 } } }, {
"tuning_profiles_impedance_geometric",
empty } },
1348 const std::vector<nlohmann::json> componentDefaults = {
1350 nlohmann::json::object(),
1351 { {
"meta", { {
"version", 0 } } } },
1352 { {
"assignments",
empty }, {
"sheet_component_classes", nlohmann::json::object() } },
1353 { {
"meta", { {
"version", 0 } } },
1354 {
"assignments",
empty },
1355 {
"sheet_component_classes", { {
"enabled",
false } } } },
1360 for(
const auto& tuning : tuningDefaults )
1362 for(
const auto& components : componentDefaults )
1364 nlohmann::json doc = {
1365 {
"meta", { {
"version", 4 } } },
1366 {
"board", { {
"design_settings", { {
"meta", { {
"version", 3 } } } } } } },
1367 {
"erc", { {
"meta", { {
"version", 1 } } }, {
"erc_exclusions",
empty } } },
1369 { {
"meta", { {
"version", 5 } } },
1370 {
"classes", { { {
"name",
"Default" }, {
"tuning_profile",
"" } } } } } },
1371 {
"tuning_profiles", tuning },
1372 {
"component_class_settings", components },
1379 BOOST_CHECK( !report.
IsLossy() );
1382 BOOST_CHECK_EQUAL( doc[
"board"][
"design_settings"][
"meta"][
"version"].get<int>(), 2 );
1384 BOOST_CHECK_EQUAL( doc.contains(
"tuning_profiles" ), target.m_id == wxT(
"10.0" ) );
1385 BOOST_CHECK_EQUAL( doc.contains(
"component_class_settings" ), target.m_id == wxT(
"10.0" ) );
1387 const nlohmann::json once = doc;
1390 BOOST_CHECK( doc == once );
1391 BOOST_CHECK( !repeated.
IsLossy() );
1400 const nlohmann::json
empty = nlohmann::json::array();
1401 const nlohmann::json profile = {
1402 {
"profile_name",
"Default" },
1403 {
"frequency", 1e9 },
1404 {
"model_solder_mask",
false },
1405 {
"net_chain_bridge_prop_delay", 0 },
1407 const std::vector<nlohmann::json> meaningful = {
1408 { {
"tuning_profiles", { {
"tuning_profiles_impedance_geometric", { profile } } } } },
1409 { {
"net_settings", { {
"classes", { { {
"tuning_profile",
"Saved" } } } } } } },
1410 { {
"tuning_profiles", { {
"tuning_profiles_impedance_geometric",
empty } } },
1411 {
"net_settings", { {
"classes", { { {
"tuning_profile",
"Saved" } } } } } } },
1412 { {
"tuning_profiles", { {
"tuning_profiles_impedance_geometric", { profile } } } },
1414 { {
"classes", { { {
"tuning_profile",
"Default" } }, { {
"tuning_profile",
"Default" } } } } } } },
1415 { {
"component_class_settings",
1417 { { {
"component_class",
"Fast" }, {
"conditions_operator",
"ALL" }, {
"conditions",
empty } } } },
1418 {
"sheet_component_classes", { {
"enabled",
false } } } } } },
1419 { {
"component_class_settings",
1420 { {
"assignments",
empty }, {
"sheet_component_classes", { {
"enabled",
true } } } } } },
1423 for(
const auto&
source : meaningful )
1427 nlohmann::json doc =
source;
1434 const nlohmann::json once = doc;
1437 BOOST_CHECK( doc == once );
1438 BOOST_CHECK( !repeated.
IsLossy() );
1446 const nlohmann::json
source = {
1447 {
"meta", { {
"version", 4 } } },
1448 {
"component_class_settings", { {
"meta", { {
"version", 1 } } } } },
1453 nlohmann::json doc =
source;
1457 BOOST_CHECK( doc ==
source );
1466 nlohmann::json metaIsString = {
1467 {
"meta",
"not an object" },
1468 {
"net_settings", { {
"meta",
"also a string" }, {
"classes",
"not an array" } } },
1469 {
"schematic",
"a string" },
1472 nlohmann::json profilesWrong = {
1473 {
"tuning_profiles",
1474 { {
"meta", 7 }, {
"tuning_profiles_impedance_geometric", {
"just",
"strings" } } } },
1486 nlohmann::json doc = {
1487 {
"net_settings", { {
"net_chain_classes", nlohmann::json::array() } } },
1493 BOOST_CHECK( !doc[
"net_settings"].contains(
"net_chain_classes" ) );
1500 nlohmann::json doc = {
1501 {
"tuning_profiles",
1502 { {
"meta", { {
"version", 1 } } },
1503 {
"tuning_profiles_impedance_geometric",
1504 { { {
"profile_name",
"5 GHz" }, {
"frequency", 5e9 }, {
"model_solder_mask",
true } },
1505 { {
"profile_name",
"Default" }, {
"frequency", 1e9 }, {
"model_solder_mask",
false } } } } } }
1510 BOOST_CHECK( report.
IsLossy() );
1513 for(
const auto& profile : doc[
"tuning_profiles"][
"tuning_profiles_impedance_geometric"] )
1515 BOOST_CHECK( !profile.contains(
"frequency" ) );
1516 BOOST_CHECK( !profile.contains(
"model_solder_mask" ) );
1521 BOOST_CHECK( !secondReport.
IsLossy() );
1527 nlohmann::json doc = {
1528 {
"meta", { {
"version", 3 } } },
1530 { {
"meta", { {
"version", 5 } } },
1531 {
"classes", { { {
"name",
"Default" }, {
"priority", 0 }, {
"tuning_profile",
"tp" } } } },
1532 {
"net_chain_classes", { { {
"name",
"chainA" } } } } } },
1533 {
"tuning_profiles",
1534 { {
"meta", { {
"version", 1 } } },
1535 {
"tuning_profiles_impedance_geometric",
1536 { { {
"name",
"tp" }, {
"frequency", 1e9 }, {
"model_solder_mask",
false } } } } } },
1545 BOOST_CHECK( doc[
"net_settings"][
"classes"][0].contains(
"tuning_profile" ) );
1546 BOOST_CHECK( !doc[
"net_settings"].contains(
"net_chain_classes" ) );
1549 BOOST_CHECK( !doc[
"tuning_profiles"][
"tuning_profiles_impedance_geometric"][0].contains(
"frequency" ) );
1550 BOOST_CHECK( !doc[
"tuning_profiles"][
"tuning_profiles_impedance_geometric"][0].contains(
"model_solder_mask" ) );
1582 BOOST_CHECK_GT( areaMM, 4.0 );
1583 BOOST_CHECK_LT( areaMM, 15.0 );
1607 BOOST_CHECK_CLOSE( ref.
GetImageScale(), 2.0 * legacyPPI / ppi, 0.1 );
1614 std::unique_ptr<FOOTPRINT> fp = std::make_unique<FOOTPRINT>(
nullptr );
1629 BOOST_CHECK_CLOSE( ref.
GetImageScale(), 2.0 * legacyPPI / ppi, 0.1 );
1656 const wxString src = ( tmp.
GetPath() /
"src.kicad_mod" ).wstring();
1657 const wxString dest = ( tmp.
GetPath() /
"out.kicad_mod" ).wstring();
1660 std::unique_ptr<FOOTPRINT> fp = std::make_unique<FOOTPRINT>(
nullptr );
1678 std::unique_ptr<FOOTPRINT> srcAgain( reader.
ImportFootprint( src, nameOut ) );
1679 std::unique_ptr<FOOTPRINT> converted( reader.
ImportFootprint( dest, nameOut ) );
1682 BOOST_REQUIRE_EQUAL( srcAgain->Zones().size(), 1 );
1683 BOOST_REQUIRE_EQUAL( converted->Zones().size(), 1 );
1685 BOOST_CHECK_EQUAL( converted->Zones()[0]->GetLayerSet().count(), srcAgain->Zones()[0]->GetLayerSet().count() );
1694 const wxString dir = tmp.
GetPath().wstring();
1696 auto writeFile = [&](
const wxString& aName,
const wxString& aContent )
1698 wxFFile file( dir + wxFileName::GetPathSeparator() + aName, wxT(
"wb" ) );
1700 file.Write( aContent );
1703 writeFile( wxT(
"a.fake_mod" ), wxT(
"old a" ) );
1704 writeFile( wxT(
"b.fake_mod" ), wxT(
"old b" ) );
1706 auto noForbidden = [](
const wxString& )
1713 wxFFile out( aTmp, wxT(
"wb" ) );
1714 out.Write( wxT(
"(version 123) converted" ) );
1720 wxFFile check( dir + wxFileName::GetPathSeparator() + wxT(
"a.fake_mod" ), wxT(
"rb" ) );
1722 BOOST_REQUIRE( check.IsOpened() && check.ReadAll( &content ) );
1723 BOOST_CHECK( content.Contains( wxT(
"converted" ) ) );
1728 if( aFile.Contains( wxT(
"b.fake_mod" ) ) )
1731 wxFFile out( aTmp, wxT(
"wb" ) );
1732 out.Write( wxT(
"(version 123) second pass" ) );
1737 BOOST_CHECK( bad.Contains( wxT(
"b.fake_mod" ) ) );
1739 wxArrayString leftovers;
1740 wxDir::GetAllFiles( dir, &leftovers );
1743 wxFFile recheck( dir + wxFileName::GetPathSeparator() + wxT(
"a.fake_mod" ), wxT(
"rb" ) );
1745 BOOST_REQUIRE( recheck.IsOpened() && recheck.ReadAll( &unchanged ) );
1746 BOOST_CHECK( !unchanged.Contains( wxT(
"second pass" ) ) );
1782 for(
bool footprintOnly : {
false,
true } )
1799 parent->
Add( shape );
1800 group->AddItem( shape );
1804 parent->
Add( barcode );
1805 group->AddItem( barcode );
1808 textbox->
SetText( wxT(
"Do not retain as plain text" ) );
1809 parent->
Add( textbox );
1810 group->AddItem( textbox );
1813 parent->
Add( supported );
1814 group->AddItem( supported );
1815 const KIID supportedUuid = supported->
m_Uuid;
1822 BOOST_REQUIRE_EQUAL(
normal.Entries().size(), omit.Entries().size() );
1823 for(
size_t i = 0; i <
normal.Entries().size(); ++i )
1825 BOOST_CHECK(
normal.Entries()[i].m_feature == omit.Entries()[i].m_feature );
1827 BOOST_CHECK(
normal.Entries()[i].m_detail != omit.Entries()[i].m_detail );
1828 BOOST_CHECK( !omit.Entries()[i].m_detail.IsEmpty() );
1837 BOOST_REQUIRE_EQUAL(
group->GetItems().size(), 1 );
1838 BOOST_CHECK( *
group->GetItems().begin() == supported );
1839 BOOST_CHECK( supported->
m_Uuid == supportedUuid );
1856 parent->Add( hatch );
1858 table->SetColCount( 2 );
1861 knockout->
SetText( wxT(
"knockout" ) );
1862 table->AddCell( knockout );
1864 plain->
SetText( wxT(
"supported" ) );
1865 table->AddCell( plain );
1866 parent->Add(
table );
1874 BOOST_REQUIRE_EQUAL(
table->GetCells().size(), 2 );
1875 BOOST_CHECK( knockout->
GetText().IsEmpty() );
1877 BOOST_CHECK( plain->
GetText() == wxT(
"supported" ) );
1892 for(
int ii = 0; ii < 3; ++ii )
1903 board.
Add( copper );
1905 for(
bool drop : {
false,
true } )
1921 for(
bool drop : {
false,
true } )
1929 std::vector<PCB_SHAPE*> copper;
1930 std::vector<PCB_SHAPE*> silk;
1938 parent->Add( onCopper );
1939 copper.push_back( onCopper );
1944 parent->Add( onSilk );
1945 silk.push_back( onSilk );
1962 for(
bool footprintOnly : {
false,
true } )
1973 pad->AddPrimitive(
F_Cu, rounded );
1975 pad->AddPrimitive(
F_Cu, supported );
1982 BOOST_REQUIRE_EQUAL(
pad->GetPrimitives(
F_Cu ).size(), 1 );
1992 for(
bool drop : {
false,
true } )
2002 board.
Add( buried );
2004 board.
Add( supported );
2013 BOOST_REQUIRE_EQUAL( board.
Tracks().size(), 3 );
2033 board.
Add( textbox );
2037 board.
Add( buried );
2069 const wxString board =
directory + wxT(
"/board.kicad_pcb" );
2071 auto write = [](
const wxString& aPath,
const wxString& aContent )
2073 wxFFile file( aPath, wxT(
"wb" ) );
2074 BOOST_REQUIRE( file.IsOpened() && file.Write( aContent ) && file.Close() );
2077 auto read = [](
const wxString& aPath )
2079 wxFFile file( aPath, wxT(
"rb" ) );
2081 BOOST_REQUIRE( file.IsOpened() && file.ReadAll( &content ) );
2085 auto noForbidden = [](
const wxString& )
2089 auto convert = [&](
const wxString&,
const wxString& aTemporary )
2091 write( aTemporary, wxT(
"(version 123) converted" ) );
2095 write(
library, wxT(
"original library" ) );
2096 write( board, wxT(
"original board" ) );
2104 BOOST_CHECK( transaction.
Stage(
directory + wxT(
"/missing/board.kicad_pcb" ) ).IsEmpty() );
2115 wxString stagedBoard = transaction.
Stage( board );
2117 write( stagedBoard, wxT(
"converted board" ) );
2123 wxArrayString files;
2124 wxDir::GetAllFiles(
directory, &files );
2133 const wxString first =
directory + wxT(
"/first.kicad_pcb" );
2134 const wxString second =
directory + wxT(
"/second.kicad_pcb" );
2137 wxFFile file( first, wxT(
"wb" ) );
2138 BOOST_REQUIRE( file.IsOpened() && file.Write( wxT(
"original" ) ) && file.Close() );
2143 wxString stagedFirst = transaction.
Stage( first );
2144 wxString stagedSecond = transaction.
Stage( second );
2145 BOOST_REQUIRE( !stagedFirst.IsEmpty() && !stagedSecond.IsEmpty() );
2147 for(
const wxString& file : { stagedFirst, stagedSecond } )
2149 wxFFile output( file, wxT(
"wb" ) );
2150 BOOST_REQUIRE( output.IsOpened() && output.Write( wxT(
"converted" ) ) && output.Close() );
2158 wxFFile input( first, wxT(
"rb" ) );
2160 BOOST_REQUIRE( input.IsOpened() && input.ReadAll( &content ) );
2162 BOOST_CHECK( wxDirExists( second ) );
2163 wxArrayString files;
2164 wxDir::GetAllFiles(
directory, &files );
2172 const wxString destination = temporary.
GetPath().wstring() + wxT(
"/board.kicad_pcb" );
2177 wxString firstTemporary = first.
Stage( destination );
2178 wxString secondTemporary = second.
Stage( destination );
2179 BOOST_REQUIRE( !firstTemporary.IsEmpty() && !secondTemporary.IsEmpty() );
2180 BOOST_CHECK( firstTemporary != secondTemporary );
2181 BOOST_CHECK( wxFileExists( firstTemporary ) );
2182 BOOST_CHECK( wxFileExists( secondTemporary ) );
2183 first.
Discard( firstTemporary );
2184 BOOST_CHECK( !wxFileExists( firstTemporary ) );
2185 BOOST_CHECK( wxFileExists( secondTemporary ) );
2186 BOOST_CHECK( !wxFileExists( destination ) );
2189 BOOST_CHECK( std::filesystem::is_empty( temporary.
GetPath() ) );
2196 const auto original = temporary.
GetPath() / u8
"original-μ.kicad_mod";
2197 const auto alias = temporary.
GetPath() /
"alias.kicad_mod";
2198 const auto danglingAlias = temporary.
GetPath() /
"dangling.kicad_mod";
2201 wxFFile file( original.wstring(), wxT(
"wb" ) );
2202 BOOST_REQUIRE( file.IsOpened() && file.Write( wxT(
"original source" ) ) && file.Close() );
2205 std::error_code error;
2206 std::filesystem::create_symlink( original.filename(), alias, error );
2214 std::filesystem::create_symlink(
"missing.kicad_mod", danglingAlias, error );
2220 for(
const auto& destination : { alias, danglingAlias } )
2222 wxString staged = transaction.
Stage( destination.wstring() );
2224 wxFFile file( staged, wxT(
"wb" ) );
2225 BOOST_REQUIRE( file.IsOpened() && file.Write( wxT(
"converted output" ) ) && file.Close() );
2231 wxFFile file( original.wstring(), wxT(
"rb" ) );
2233 BOOST_REQUIRE( file.IsOpened() && file.ReadAll( &content ) );
2235 BOOST_CHECK( !std::filesystem::is_symlink( alias ) );
2236 BOOST_CHECK( !std::filesystem::is_symlink( danglingAlias ) );
2238 std::filesystem::directory_iterator() ),
2248 if( entry.m_feature == aName )
2250 BOOST_CHECK( entry.m_bucket == aBucket );
2252 BOOST_CHECK( !entry.m_detail.IsEmpty() );
2257 BOOST_ERROR(
"Missing compatibility feature: " + aName.ToStdString() );
2265 for(
bool drop : {
false,
true } )
2271 std::vector<PCB_SHAPE*> shapes;
2279 parent->Add( shape );
2280 shapes.push_back( shape );
2283 parent->Add( constraint );
2287 BOOST_CHECK( !report.IsBlocked() );
2297 BOOST_CHECK( shape->GetStart() ==
VECTOR2I( 1000000, 2000000 ) );
2298 BOOST_CHECK( shape->GetEnd() ==
VECTOR2I( 7000000, 2000000 ) );
2307 for(
bool drop : {
false,
true } )
2324 BOOST_CHECK( board.
Drawings().empty() );
2325 BOOST_REQUIRE_EQUAL( board.
Tracks().size(), 1 );
2326 BOOST_CHECK(
via->GetPosition() ==
VECTOR2I( 1000000, 2000000 ) );
2334 for(
bool drop : {
false,
true } )
2341 board.
Add( stitch );
2345 std::vector<PCB_VIA*> vias;
2351 via->SetPosition(
VECTOR2I( 1000000 * ( vias.size() + 1 ), 2000000 ) );
2352 via->SetWidth(
F_Cu, 600000 );
2353 via->SetDrill( 300000 );
2355 generator->AddItem(
via );
2356 vias.push_back(
via );
2364 BOOST_REQUIRE_EQUAL( board.
Tracks().size(), 2 );
2365 BOOST_REQUIRE_EQUAL( outer->
GetItems().size(), 2 );
2367 for(
size_t ii = 0; ii < vias.size(); ++ii )
2369 BOOST_CHECK( vias[ii]->GetPosition() ==
VECTOR2I( 1000000 * ( ii + 1 ), 2000000 ) );
2372 BOOST_CHECK( vias[ii]->GetParentGroup() == outer );
2381 const std::string src =
2387 BOOST_REQUIRE_EQUAL(
source->GetCopperLayerCount(), 6 );
2388 BOOST_REQUIRE_EQUAL(
source->Zones().size(), 3u );
2389 BOOST_REQUIRE_EQUAL(
source->Generators().size(), 3u );
2390 BOOST_REQUIRE_EQUAL(
source->Groups().size(), 1u );
2393 const auto copperById = [](
const BOARD& aBoard )
2395 std::map<KIID, const PCB_TRACK*> items;
2397 for(
const PCB_TRACK* item : aBoard.Tracks() )
2398 BOOST_REQUIRE( items.emplace( item->m_Uuid, item ).second );
2402 const auto memberIds = [](
const PCB_GROUP& aGroup )
2406 for(
const EDA_ITEM* member : aGroup.GetItems() )
2411 const auto serializeNative = [](
BOARD* aBoard )
2419 const auto sourceCopper = copperById( *
source );
2420 BOOST_REQUIRE_EQUAL( sourceCopper.size(), 83u );
2421 std::set<KIID> plainVias;
2422 std::set<KIID> generatedVias;
2423 size_t sourceVias = 0;
2424 size_t sourceSegments = 0;
2425 size_t sourceMicrovias = 0;
2427 for(
const auto& [
id, item] : sourceCopper )
2439 if( !
via->GetParentGroup() )
2440 plainVias.insert(
id );
2449 BOOST_REQUIRE_EQUAL( sourceVias, 80u );
2450 BOOST_REQUIRE_EQUAL( sourceSegments, 3u );
2451 BOOST_REQUIRE_EQUAL( sourceMicrovias, 2u );
2452 BOOST_REQUIRE_EQUAL( plainVias.size(), 3u );
2463 BOOST_REQUIRE(
source->FindNet( viaStitch->GetNetCode() )->GetNetname() == wxT(
"GND" ) );
2489 for(
BOARD_ITEM* member : generator->GetBoardItems() )
2493 BOOST_REQUIRE( sourceCopper.count( member->m_Uuid ) == 1u );
2494 BOOST_REQUIRE( generatedVias.insert( member->m_Uuid ).second );
2499 BOOST_REQUIRE_EQUAL( stitch->
GetItems().size(), 49u );
2500 BOOST_REQUIRE_EQUAL( guard->
GetItems().size(), 26u );
2501 BOOST_REQUIRE_EQUAL( stack->
GetItems().size(), 2u );
2502 BOOST_REQUIRE_EQUAL( generatedVias.size(), 77u );
2503 const auto stitchMembers = memberIds( *stitch );
2506 const wxString outerName = outer->
GetName();
2511 const std::string sourceModel = serializeNative(
source.get() );
2516 const bool preTen = target.m_boardVersion ==
kicad9.m_boardVersion;
2518 for(
bool drop : {
false,
true } )
2527 const std::string dest =
2529 / ( target.m_id.ToStdString() + ( drop ?
"-drop.kicad_pcb" :
"-lower.kicad_pcb" ) ) )
2532 wxString unsupportedToken;
2535 BOOST_CHECK( unsupportedToken.IsEmpty() );
2539 BOOST_REQUIRE_EQUAL( report.
Entries().size(), preTen ? 3u : 2u );
2546 BOOST_REQUIRE_EQUAL( report.
Entries().size(), preview.
Entries().size() );
2548 for(
size_t ii = 0; ii < preview.
Entries().size(); ++ii )
2550 BOOST_CHECK( report.
Entries()[ii].m_bucket == preview.
Entries()[ii].m_bucket );
2551 BOOST_CHECK( report.
Entries()[ii].m_feature == preview.
Entries()[ii].m_feature );
2557 BOOST_CHECK( outputBytes.find(
"(generated" ) == std::string::npos );
2561 for(
const char* token : {
"(filling",
"(capping",
"(covering",
"(plugging" } )
2562 BOOST_CHECK( outputBytes.find( token ) == std::string::npos );
2565 std::unique_ptr<BOARD> exported( io.
LoadBoard( dest,
nullptr ) );
2567 BOOST_CHECK_EQUAL( exported->GetFileFormatVersionAtLoad(), target.m_boardVersion );
2570 BOOST_CHECK( exported->Generators().empty() );
2571 BOOST_REQUIRE_EQUAL( exported->Groups().size(), 1u );
2572 BOOST_CHECK( exported->GroupsSanityCheck().IsEmpty() );
2574 const auto exportedCopper = copperById( *exported );
2575 BOOST_REQUIRE_EQUAL( exportedCopper.size(), sourceCopper.size() );
2576 PCB_GROUP* exportedOuter = *exported->Groups().begin();
2577 BOOST_CHECK( exportedOuter->
m_Uuid == outerId );
2578 BOOST_CHECK( exportedOuter->
GetName() == outerName );
2579 BOOST_CHECK( memberIds( *exportedOuter ) == stitchMembers );
2581 for(
const auto& [
id, original] : sourceCopper )
2583 const auto found = exportedCopper.find(
id );
2586 BOOST_CHECK( item->
Type() == original->Type() );
2587 BOOST_CHECK( item->
GetStart() == original->GetStart() );
2588 BOOST_CHECK( item->
GetEnd() == original->GetEnd() );
2589 BOOST_CHECK( item->
GetLayerSet() == original->GetLayerSet() );
2592 if(
const PCB_VIA* originalVia =
dynamic_cast<const PCB_VIA*
>( original ) )
2596 BOOST_CHECK(
via->GetPosition() == originalVia->GetPosition() );
2597 BOOST_CHECK(
via->GetViaType() == originalVia->GetViaType() );
2598 BOOST_CHECK(
via->TopLayer() == originalVia->TopLayer() );
2599 BOOST_CHECK(
via->BottomLayer() == originalVia->BottomLayer() );
2619 const PADSTACK& originalStack = originalVia->Padstack();
2632 if( plainVias.count(
id ) )
2633 BOOST_CHECK( !
via->GetParentGroup() );
2637 BOOST_CHECK( item->
GetLayer() == original->GetLayer() );
2641 if( stitchMembers.count(
id ) )
2651 const auto found = std::find_if( exported->Drawings().begin(), exported->Drawings().end(),
2654 return aItem->m_Uuid == drawing->m_Uuid;
2659 BOOST_CHECK( exportedText->
GetText() ==
text->GetText() );
2679 std::unique_ptr<BOARD> lengthFixture( io.
LoadBoard( lengthPath,
nullptr ) );
2680 std::unique_ptr<BOARD> timeFixture( io.
LoadBoard( timePath,
nullptr ) );
2682 BOOST_REQUIRE_EQUAL( lengthFixture->Generators().size(), 1u );
2683 BOOST_REQUIRE_EQUAL( timeFixture->Generators().size(), 16u );
2688 if( generator->m_Uuid ==
KIID(
"2acf841f-25ce-450c-b8df-dbbc34cc96ac" ) )
2694 BOOST_REQUIRE_EQUAL( originalTime->
GetItems().size(), 1u );
2698 auto length =
dynamic_cast<PCB_TUNING_PATTERN*
>( ( *lengthFixture->Generators().begin() )->DeepClone() );
2702 BOOST_REQUIRE_GT( length->GetItems().size(), 1u );
2704 const auto addCopper = [&](
PCB_TRACK* aTrack )
2710 net =
new NETINFO_ITEM( &board, aTrack->GetNetname() );
2716 board.
Add( aTrack );
2721 for(
BOARD_ITEM* member : pattern->GetBoardItems() )
2728 board.
Add( pattern );
2733 for(
PCB_TRACK* track : timeFixture->Tracks() )
2737 originalControl = track;
2743 auto control =
static_cast<PCB_TRACK*
>( originalControl->
Clone() );
2744 control->SetParentGroup(
nullptr );
2745 addCopper( control );
2747 outer->
SetName( wxT(
"Native tuning ownership" ) );
2753 double patternLength = 0;
2755 for(
BOARD_ITEM* member : length->GetBoardItems() )
2756 patternLength +=
static_cast<PCB_TRACK*
>( member )->GetLength();
2761 for(
const char* key : {
"tuning_mode",
"initial_side",
"last_status" } )
2765 lengthProperties[key] = wxAny( wxString::FromUTF8( value ) );
2768 lengthProperties[
"last_tuning_length"] = wxAny( patternLength /
pcbIUScale.IU_PER_MM );
2769 length->SetProperties( lengthProperties );
2770 const wxString tuningInfo = length->GetRowData().back().second.GetString();
2772 const auto memberIds = [](
const PCB_GROUP& aGroup )
2776 for(
const EDA_ITEM* member : aGroup.GetItems() )
2781 const auto serializeNative = [](
BOARD* aBoard )
2788 std::map<KIID, const PCB_TRACK*> copper;
2791 BOOST_REQUIRE( copper.emplace( track->m_Uuid, track ).second );
2793 const auto lengthMembers = memberIds( *length );
2794 const auto timeMembers = memberIds( *time );
2795 BOOST_REQUIRE_EQUAL( copper.size(), lengthMembers.size() + timeMembers.size() + 1u );
2798 const std::string src = ( tmp.
GetPath() /
"native-source.kicad_pcb" ).string();
2801 const std::string sourceModel = serializeNative( &board );
2805 const bool preTen = target.m_boardVersion ==
kicad9.m_boardVersion;
2807 for(
bool drop : {
false,
true } )
2812 BOOST_CHECK( !preview.IsBlocked() );
2816 const std::string dest =
2818 / ( target.m_id.ToStdString() + ( drop ?
"-drop.kicad_pcb" :
"-lower.kicad_pcb" ) ) )
2821 wxString unsupported;
2824 BOOST_CHECK( unsupported.IsEmpty() );
2828 BOOST_REQUIRE_EQUAL( report.
Entries().size(), preTen ? 1u : 0u );
2838 for(
const char* token : {
"(is_time_domain",
"(target_delay",
"(last_tuning_length" } )
2839 BOOST_CHECK( outputBytes.find( token ) == std::string::npos );
2842 BOOST_CHECK( outputBytes.find(
"(last_tuning " + quoting.
Quotew( tuningInfo ) +
")" )
2843 != std::string::npos );
2847 BOOST_CHECK( outputBytes.find(
"(is_time_domain yes)" ) != std::string::npos );
2848 BOOST_CHECK( outputBytes.find(
"(last_tuning_length " ) != std::string::npos );
2849 BOOST_CHECK( outputBytes.find(
"(last_tuning " ) == std::string::npos );
2852 std::unique_ptr<BOARD> exported( io.
LoadBoard( dest,
nullptr ) );
2854 BOOST_CHECK_EQUAL( exported->GetFileFormatVersionAtLoad(), target.m_boardVersion );
2855 BOOST_REQUIRE_EQUAL( exported->Generators().size(), preTen ? 1u : 2u );
2856 BOOST_REQUIRE_EQUAL( exported->Groups().size(), 1u );
2857 BOOST_CHECK( exported->GroupsSanityCheck().IsEmpty() );
2858 PCB_GROUP* exportedOuter = *exported->Groups().begin();
2860 std::set<KIID> expectedOuter{ length->m_Uuid };
2863 expectedOuter.insert( timeMembers.begin(), timeMembers.end() );
2865 expectedOuter.insert( time->m_Uuid );
2867 BOOST_CHECK( memberIds( *exportedOuter ) == expectedOuter );
2868 BOOST_REQUIRE_EQUAL( exported->Tracks().size(), copper.size() );
2870 for(
const PCB_TRACK* track : exported->Tracks() )
2872 const auto found = copper.find( track->m_Uuid );
2874 const PCB_TRACK* original = found->second;
2875 BOOST_CHECK( track->Type() == original->
Type() );
2876 BOOST_CHECK( track->GetStart() == original->
GetStart() );
2877 BOOST_CHECK( track->GetEnd() == original->
GetEnd() );
2878 BOOST_CHECK( track->GetLayerSet() == original->
GetLayerSet() );
2882 if(
const PCB_ARC* arc =
dynamic_cast<const PCB_ARC*
>( original ) )
2884 const PCB_ARC* exportedArc =
dynamic_cast<const PCB_ARC*
>( track );
2886 BOOST_CHECK( exportedArc->
GetMid() == arc->GetMid() );
2889 if( timeMembers.count( track->m_Uuid ) && preTen )
2890 BOOST_CHECK( track->GetParentGroup() ==
static_cast<EDA_GROUP*
>( exportedOuter ) );
2891 else if( track->m_Uuid == control->m_Uuid )
2892 BOOST_CHECK( !track->GetParentGroup() );
2899 BOOST_CHECK( pattern->GetParentGroup() ==
static_cast<EDA_GROUP*
>( exportedOuter ) );
2900 BOOST_CHECK( pattern->m_Uuid == length->m_Uuid || ( !preTen && pattern->m_Uuid == time->m_Uuid ) );
2901 const bool isTime = pattern->m_Uuid == time->m_Uuid;
2902 BOOST_CHECK( pattern->GetSettings().m_isTimeDomain == isTime );
2903 BOOST_CHECK( memberIds( *pattern ) == ( isTime ? timeMembers : lengthMembers ) );
2908 for(
const char* key :
2909 {
"target_length",
"target_length_min",
"target_length_max",
"target_skew",
"target_skew_min",
2910 "target_skew_max",
"min_spacing",
"max_amplitude",
"min_amplitude" } )
2913 double originalValue = 0;
2915 BOOST_REQUIRE( originalProperties.get_to( key, originalValue ) );
2921 for(
const char* key :
2922 {
"target_delay",
"target_delay_min",
"target_delay_max",
"last_tuning_length" } )
2925 double originalValue = 0;
2927 BOOST_REQUIRE( originalProperties.get_to( key, originalValue ) );
2953 properties.
set(
"future_tuning_setting",
true );
2959 auto pattern =
new UNREVIEWED_TUNING_PATTERN( &board );
2961 track->SetStart(
VECTOR2I( 1000000, 2000000 ) );
2962 track->SetEnd(
VECTOR2I( 3000000, 2000000 ) );
2964 board.
Add( pattern );
2965 pattern->AddItem( track );
2969 for(
bool drop : {
false,
true } )
2973 BOOST_REQUIRE_EQUAL( board.
Generators().size(), 1u );
2974 BOOST_CHECK( track->GetParentGroup() ==
static_cast<EDA_GROUP*
>( pattern ) );
2982 const wxString
path = ( tmp.
GetPath() / ( target.m_id.ToStdString() +
".kicad_pcb" ) ).wstring();
2992 pattern->SetTargetDelay( 100000 );
2994 track->SetStart(
VECTOR2I( 1000000, 2000000 ) );
2995 track->SetEnd(
VECTOR2I( 3000000, 2000000 ) );
2997 board.
Add( pattern );
2998 pattern->AddItem( track );
3003 for(
const char* token :
3004 {
"is_time_domain",
"target_delay",
"target_delay_min",
"target_delay_max",
"last_tuning_length" } )
3006 const wxString value = wxString::FromUTF8(
"(kicad_pcb (generated (" + std::string( token ) +
" 0)))" );
3017 for(
bool stack : {
false,
true } )
3026 const std::string kind = stack ?
"via-stack" :
"via-stitch";
3032 const auto absent = tmp.
GetPath() / ( kind +
"-" + target.m_id.ToStdString() +
"-absent.kicad_pcb" );
3034 BOOST_CHECK( !wxFileExists( absent.wstring() ) );
3036 const auto existing =
3037 tmp.
GetPath() / ( kind +
"-" + target.m_id.ToStdString() +
"-existing.kicad_pcb" );
3040 std::ofstream sentinel( existing, std::ios::binary );
3041 sentinel <<
"existing destination";
3056 const std::string src =
3058 wxFileName projectFile( wxString::FromUTF8( src ) );
3059 projectFile.SetExt( wxT(
"kicad_pro" ) );
3066 BOOST_REQUIRE_EQUAL(
source->Zones().size(), 7u );
3067 BOOST_REQUIRE_EQUAL(
source->Groups().size(), 4u );
3068 BOOST_REQUIRE_EQUAL(
source->Footprints().size(), 4u );
3070 std::map<KIID, const PCB_TEXT*> sourceNotes;
3075 BOOST_REQUIRE( sourceNotes.emplace( note->m_Uuid, note ).second );
3078 BOOST_REQUIRE_EQUAL( sourceNotes.size(), 1u );
3079 std::map<KIID, const ZONE*> sourceZones;
3080 int placementAreas = 0;
3081 int filledOutlines = 0;
3085 BOOST_REQUIRE( sourceZones.emplace( zone->m_Uuid, zone ).second );
3095 filledOutlines += zone->GetFilledPolysList( layer )->OutlineCount();
3098 BOOST_REQUIRE_EQUAL( placementAreas, 4 );
3099 BOOST_REQUIRE_GT( filledOutlines, 0 );
3100 const auto memberIds = [](
const PCB_GROUP& aGroup )
3104 for(
const EDA_ITEM* member : aGroup.GetItems() )
3111 BOOST_REQUIRE_EQUAL( aExported.OutlineCount(), aOriginal.
OutlineCount() );
3113 for(
int outline = 0; outline < aOriginal.
OutlineCount(); ++outline )
3115 BOOST_CHECK( aExported.COutline( outline ).CompareGeometry( aOriginal.
COutline( outline ) ) );
3116 BOOST_REQUIRE_EQUAL( aExported.HoleCount( outline ), aOriginal.
HoleCount( outline ) );
3118 for(
int hole = 0; hole < aOriginal.
HoleCount( outline ); ++hole )
3119 BOOST_CHECK( aExported.CHole( outline, hole ).CompareGeometry( aOriginal.
CHole( outline, hole ) ) );
3122 const auto serializeNative = [](
BOARD* aBoard )
3129 const std::string sourceModel = serializeNative(
source.get() );
3137 const bool preTen = target.m_boardVersion ==
kicad9.m_boardVersion;
3139 for(
bool drop : {
false,
true } )
3144 BOOST_CHECK( !preview.IsBlocked() );
3148 const std::string dest =
3150 / ( target.m_id.ToStdString() + ( drop ?
"-drop.kicad_pcb" :
"-lower.kicad_pcb" ) ) )
3153 wxString unsupported;
3156 BOOST_CHECK( unsupported.IsEmpty() );
3160 BOOST_REQUIRE_EQUAL( report.
Entries().size(), preTen ? 1u : 0u );
3167 std::unique_ptr<BOARD> exported( io.
LoadBoard( dest,
nullptr ) );
3169 BOOST_CHECK_EQUAL( exported->GetFileFormatVersionAtLoad(), target.m_boardVersion );
3170 BOOST_REQUIRE_EQUAL( exported->Zones().size(),
source->Zones().size() );
3171 BOOST_REQUIRE_EQUAL( exported->Groups().size(),
source->Groups().size() );
3172 BOOST_REQUIRE_EQUAL( exported->Footprints().size(),
source->Footprints().size() );
3173 BOOST_CHECK( exported->GroupsSanityCheck().IsEmpty() );
3175 for(
const auto& [
id, original] : sourceNotes )
3177 const auto found = std::find_if( exported->Drawings().begin(), exported->Drawings().end(),
3180 return aItem->m_Uuid == id;
3185 BOOST_CHECK( note->
GetText() == original->GetText() );
3186 BOOST_CHECK( note->
GetPosition() == original->GetPosition() );
3187 BOOST_CHECK( note->
GetLayer() == original->GetLayer() );
3190 for(
const ZONE* zone : exported->Zones() )
3192 const auto found = sourceZones.find( zone->m_Uuid );
3194 const ZONE* original = found->second;
3195 BOOST_CHECK( zone->GetZoneName() == original->
GetZoneName() );
3196 BOOST_CHECK( zone->GetLayerSet() == original->
GetLayerSet() );
3197 BOOST_CHECK( zone->GetIsRuleArea() == original->
GetIsRuleArea() );
3203 BOOST_CHECK( zone->GetNetname() == original->
GetNetname() );
3204 BOOST_CHECK( zone->IsFilled() == original->
IsFilled() );
3205 checkPolygons( original->
GetBoardOutline(), zone->GetBoardOutline() );
3210 const auto exportedFill = zone->GetFilledPolysList( layer );
3211 checkPolygons( *originalFill, *exportedFill );
3213 for(
int outline = 0; outline < originalFill->OutlineCount(); ++outline )
3214 BOOST_CHECK( zone->IsIsland( layer, outline ) == original->
IsIsland( layer, outline ) );
3219 BOOST_CHECK( !zone->GetPlacementAreaEnabled() );
3220 BOOST_CHECK( zone->GetPlacementAreaSource().IsEmpty() );
3233 const auto original = std::find_if(
source->Groups().begin(),
source->Groups().end(),
3236 return aGroup->m_Uuid == group->m_Uuid;
3239 BOOST_CHECK(
group->GetName() == ( *original )->GetName() );
3240 BOOST_CHECK( memberIds( *
group ) == memberIds( **original ) );
3243 std::map<KIID, const PAD*> sourcePads;
3248 BOOST_REQUIRE_EQUAL( sourcePads.size(), 8u );
3249 BOOST_REQUIRE_EQUAL( exported->GetPads().size(), sourcePads.size() );
3251 for(
const PAD*
pad : exported->GetPads() )
3253 const auto found = sourcePads.find(
pad->m_Uuid );
3255 const PAD* original = found->second;
3278 for(
bool drop : {
false,
true } )
3281 auto footprint =
new FOOTPRINT( &board );
3282 auto zone =
new ZONE( footprint );
3283 zone->SetIsRuleArea(
true );
3284 zone->SetPlacementAreaEnabled(
true );
3286 zone->SetPlacementAreaSource( wxT(
"Repeated group" ) );
3287 zone->SetDoNotAllowTracks(
true );
3288 footprint->Add( zone );
3289 board.
Add( footprint );
3292 BOOST_CHECK( zone->GetPlacementAreaEnabled() );
3294 BOOST_CHECK( zone->GetIsRuleArea() );
3295 BOOST_CHECK( zone->GetDoNotAllowTracks() );
3296 BOOST_CHECK( zone->GetPlacementAreaEnabled() == ( target.m_id ==
kicad10.m_id ) );
3297 BOOST_CHECK( zone->GetPlacementAreaSource()
3298 == ( target.m_id ==
kicad10.m_id ? wxT(
"Repeated group" ) : wxEmptyString ) );
3307 == wxT(
"placement/group" ) );
3316 for(
bool drop : {
false,
true } )
3319 auto emptyRuleArea =
new ZONE( &board );
3320 emptyRuleArea->SetIsRuleArea(
true );
3322 board.
Add( emptyRuleArea );
3323 auto ordinaryZone =
new ZONE( &board );
3325 ordinaryZone->SetPlacementAreaEnabled(
true );
3326 ordinaryZone->SetPlacementAreaSource( wxT(
"Unused by ordinary copper zones" ) );
3327 board.
Add( ordinaryZone );
3330 BOOST_CHECK( emptyRuleArea->GetIsRuleArea() );
3331 BOOST_CHECK( !ordinaryZone->GetIsRuleArea() );
3343 explicit FUTURE_GENERATOR(
BOARD* aBoard ) :
3347 wxString
GetGeneratorType()
const override {
return wxT(
"future_generator" ); }
3351 board.
Add(
new FUTURE_GENERATOR( &board ) );
3353 for(
bool drop : {
false,
true } )
3360 for(
bool drop : {
false,
true } )
3365 std::vector<PCB_SHAPE*> shapes;
3366 double expectedArea = 0;
3377 parent->Add( shape );
3378 shapes.push_back( shape );
3382 expectedArea += ink.
Area();
3395 BOOST_CHECK( shape->GetEnd() ==
VECTOR2I( 10000000, 0 ) );
3404 area +=
static_cast<PCB_SHAPE*
>( item )->GetPolyShape().Area();
3407 area +=
static_cast<PCB_SHAPE*
>( item )->GetPolyShape().Area();
3409 BOOST_CHECK_CLOSE( area, expectedArea, 0.05 );
3435 for(
bool footprintOnly : {
false,
true } )
3441 fp->
Value().
SetText( wxT(
"${PROPERTY.Reference}/${REFERENCE}" ) );
3444 escaped->
SetText( wxT(
"\\${PROPERTY.Serial}" ) );
3447 expression->
SetText( wxT(
"@{${PROPERTY.Reference}+1}/${REFERENCE}" ) );
3448 fp->
Add( expression );
3452 BOOST_CHECK( !report.IsBlocked() );
3475 for(
bool drop : {
false,
true } )
3483 const wxString projectPath = ( tmp.
GetPath() /
"source.kicad_pro" ).string();
3486 std::ofstream
project( projectPath.ToStdString() );
3487 project << R
"({"meta":{"version":4},"text_variables":{"SERIAL":"${PROPERTY.Reference}","ALIAS":"${SERIAL}","UNUSED":"${PROPERTY.Missing}"}})";
3495 std::vector<FOOTPRINT*> footprints;
3497 for(
const wxString& serial : { wxT(
"42" ), wxT(
"73" ) } )
3504 footprints.push_back( fp );
3509 BOOST_CHECK_EQUAL( footprints[0]->Value().GetText(), wxString(
"42/${REFERENCE}" ) );
3510 BOOST_CHECK_EQUAL( footprints[1]->Value().GetText(), wxString(
"73/${REFERENCE}" ) );
3512 footprints[0]->Value().SetText( wxT(
"${UNUSED}" ) );
3521 board.
SetProperties( { { wxT(
"SERIAL" ), wxT(
"${PROPERTY.Reference}" ) },
3522 { wxT(
"UNUSED" ), wxT(
"${PROPERTY.Missing}" ) } } );
3525 fp->
Value().
SetText( wxT(
"${SERIAL}/${REFERENCE}" ) );
3539 fp->
SetKeywords( wxT(
"\\${REFERENCE}/\\@{1+2}" ) );
3540 fp->
Value().
SetText( wxT(
"${PROPERTY.Reference}/\\${U1:PROPERTY.Missing}/${REFERENCE}" ) );
3542 text->SetText( wxT(
"${PROPERTY.Keywords}/${REFERENCE}" ) );
3549 BOOST_CHECK( !
text->GetText().Contains( wxT(
"PROPERTY." ) ) );
3559 fp->
Value().
SetText( wxT(
"@{1000mils}/${REFERENCE}" ) );
3569 for(
const wxString& raw :
3570 { wxT(
"@{${PROPERTY.Reference}+${MISSING}}" ), wxT(
"@{unknown_function(${PROPERTY.Reference})}" ) } )
3579 for(
bool drop : {
false,
true } )
3587 for(
bool inProperty : {
false,
true } )
3592 const wxString literal = wxT(
"\\${REFERENCE}/\\@{1+2}" );
3594 fp->
Value().
SetText( inProperty ? wxString( wxT(
"${PROPERTY.Keywords}" ) ) : literal );
3598 for(
bool drop : {
false,
true } )
3612 for(
bool drop : {
false,
true } )
3621 BOOST_CHECK( !report.IsBlocked() );
3635 for(
bool drop : {
false,
true } )
3643 const wxString projectPath = ( temporary.
GetPath() /
"source.kicad_pro" ).string();
3646 std::ofstream
project( projectPath.ToStdString() );
3647 project << R
"({"meta":{"version":4},"text_variables":{"TITLE":"${PROPERTY.Reference}"}})";
3661 for(
bool drop : {
false,
true } )
3666 BOOST_CHECK( !report.IsBlocked() );
3667 BOOST_CHECK( !report.IsLossy() );
3678 table->SetColCount( 1 );
3679 table->SetColWidth( 0, 10000000 );
3680 table->SetRowHeight( 0, 6000000 );
3682 cell->
SetText( wxT(
"@{${PROPERTY.Reference}+${ROW}}/${COL}/${REFERENCE}" ) );
3683 table->AddCell( cell );
3695 const wxString
source = ( temporary.
GetPath() /
"source.kicad_mod" ).string();
3698 footprint.
Value().
SetText( wxT(
"${PROPERTY.Reference}/${REFERENCE}" ) );
3707 footprint.
Add( line );
3710 footprint.
Add( constraint );
3716 for(
bool drop : {
false,
true } )
3718 const wxString destination = ( temporary.
GetPath() /
"out.kicad_mod" ).string();
3724 BOOST_CHECK( converted->Constraints().empty() );
3725 BOOST_CHECK( !converted->HasCustomProperties() );
3726 BOOST_CHECK( !converted->IsExcludedFromSim() );
3727 BOOST_CHECK_EQUAL( converted->Value().GetText(), wxString(
"42/${REFERENCE}" ) );
3730 for(
BOARD_ITEM* item : converted->GraphicalItems() )
3744 for(
bool drop : {
false,
true } )
3758 BOOST_CHECK( !variant.GetExcludedFromSim() );
3769 std::vector<EDA_TEXT*> bold;
3771 text->SetText( wxT(
"board bold" ) );
3773 bold.push_back(
text );
3775 bold.push_back( &fp->
Value() );
3777 fpText->
SetText( wxT(
"graphic bold" ) );
3779 bold.push_back( fpText );
3781 table->SetColCount( 1 );
3782 table->SetColWidth( 0, 10000000 );
3783 table->SetRowHeight( 0, 5000000 );
3785 cell->
SetText( wxT(
"cell bold" ) );
3786 table->AddCell( cell );
3788 bold.push_back( cell );
3794 board.
Add( dimension );
3795 bold.push_back( dimension );
3799 item->SetBold(
true );
3800 item->SetTextThickness( 100000 );
3804 automatic->
SetText( wxT(
"auto bold" ) );
3807 board.
Add( automatic );
3809 outline->
SetText( wxT(
"outline bold" ) );
3813 board.
Add( outline );
3819 const std::string first = ( temporary.
GetPath() / ( target.m_id.ToStdString() +
"-first.kicad_pcb" ) ).string();
3820 const std::string second =
3821 ( temporary.
GetPath() / ( target.m_id.ToStdString() +
"-second.kicad_pcb" ) ).string();
3825 BOOST_CHECK( content.find(
"(thickness 0.16)" ) != std::string::npos );
3837 reloaded->RunOnChildren(
3842 if( !reloadedText || !reloadedText->
IsBold() )
3845 if( reloadedText->
GetText() == wxT(
"auto bold" ) )
3847 else if( reloadedText->
GetText() != wxT(
"outline bold" ) || outlineAvailable )
3882 const std::string
path = ( temporary.
GetPath() /
"out.kicad_pcb" ).string();
3886 BOOST_REQUIRE( reloaded && reloaded->Footprints().size() == 1 );
3887 BOOST_REQUIRE_EQUAL( reloaded->Footprints()[0]->Pads().size(), 1 );
3888 const PAD*
result = reloaded->Footprints()[0]->Pads()[0];
3892 BOOST_REQUIRE_EQUAL(
result->GetPrimitives(
In1_Cu ).size(), 1 );
3899 const nlohmann::json exclusion = { {
"marker",
3900 { {
"error_type",
"DRCET_CLEARANCE" },
3901 {
"position", { {
"x_nm",
"123" }, {
"y_nm",
"-456" } } },
3903 { { {
"value",
"11111111-1111-1111-1111-111111111111" } },
3904 { {
"value",
"22222222-2222-2222-2222-222222222222" } } } } } },
3905 {
"comment",
"accepted" } };
3909 nlohmann::json doc = {
3910 {
"meta", { {
"version", 4 } } },
3912 { {
"design_settings", { {
"meta", { {
"version", 3 } } }, {
"drc_exclusions", { exclusion } } } } } }
3917 const auto& settings = doc[
"board"][
"design_settings"];
3919 BOOST_REQUIRE_EQUAL( settings[
"drc_exclusions"].size(), 1 );
3921 settings[
"drc_exclusions"][0][0].get<std::string>(),
3922 "clearance|123|-456|11111111-1111-1111-1111-111111111111|22222222-2222-2222-2222-222222222222" );
3923 BOOST_CHECK_EQUAL( settings[
"drc_exclusions"][0][1].get<std::string>(),
"accepted" );
3924 BOOST_CHECK( !report.
IsLossy() );
3925 const auto migrated = doc;
3928 BOOST_CHECK( doc == migrated );
3929 BOOST_CHECK( !second.
IsLossy() );
3936 nlohmann::json multiple = { {
"marker",
3937 { {
"error_type",
"DRCET_CLEARANCE" },
3938 {
"position", { {
"x_nm",
"123" }, {
"y_nm",
"-456" } } },
3940 { { {
"value",
"11111111-1111-1111-1111-111111111111" } },
3941 { {
"value",
"22222222-2222-2222-2222-222222222222" } },
3942 { {
"value",
"33333333-3333-3333-3333-333333333333" } } } } } },
3943 {
"comment",
"three items" } };
3944 nlohmann::json
unknown = multiple;
3945 unknown[
"marker"][
"error_type"] =
"DRCET_MICROVIA_STACK_DEPTH";
3946 unknown[
"marker"][
"items"].erase( 2 );
3950 nlohmann::json doc = {
3952 { {
"design_settings",
3953 { {
"meta", { {
"version", 3 } } }, {
"drc_exclusions", { multiple,
unknown,
"malformed" } } } } } }
3957 BOOST_CHECK( doc[
"board"][
"design_settings"][
"drc_exclusions"].
empty() );
3968 doc[
"net_settings"][
"net_chain_netclasses"] = { { {
"name",
"fast" } } };
3969 doc[
"board"][
"design_settings"][
"via_stack_presets"] = { { {
"name",
"fanout" } } };
3970 doc[
"board"][
"design_settings"][
"teardrop_parameters"] = {
3971 { {
"td_target_name",
"td_track_end" }, {
"td_enabled",
true }, {
"td_max_len", 1.0 } },
3972 { {
"td_enabled",
false } }
3976 BOOST_CHECK( !doc[
"net_settings"].contains(
"net_chain_netclasses" ) );
3977 const auto& settings = doc[
"board"][
"design_settings"];
3978 BOOST_CHECK( !settings.contains(
"via_stack_presets" ) );
3979 BOOST_CHECK( !settings[
"teardrop_parameters"][0].contains(
"td_enabled" ) );
3980 BOOST_CHECK( !settings[
"teardrop_parameters"][1].contains(
"td_enabled" ) );
3981 BOOST_CHECK_EQUAL( settings[
"teardrop_parameters"][0][
"td_max_len"].get<double>(), 1.0 );
3985 BOOST_CHECK( !second.
IsLossy() );
3987 nlohmann::json defaults;
3988 defaults[
"net_settings"][
"net_chain_netclasses"] = nlohmann::json::array();
3989 defaults[
"board"][
"design_settings"][
"via_stack_presets"] = nlohmann::json::array();
3990 defaults[
"board"][
"design_settings"][
"teardrop_parameters"] = { { {
"td_enabled",
false } } };
3993 BOOST_CHECK( !silent.
IsLossy() );
4000 nlohmann::json doc = {
4001 {
"tuning_profiles",
4002 { {
"meta", { {
"version", 2 } } },
4003 {
"tuning_profiles_impedance_geometric",
4004 { { {
"net_chain_bridge_prop_delay", 25 } }, { {
"net_chain_bridge_prop_delay", 0 } } } } } }
4011 for(
const auto& profile : doc[
"tuning_profiles"][
"tuning_profiles_impedance_geometric"] )
4012 BOOST_CHECK( !profile.contains(
"net_chain_bridge_prop_delay" ) );
4021 doc[
"net_settings"][
"net_chain_classes"] = { {
"clock",
"Fast" } };
4024 BOOST_CHECK( !doc[
"net_settings"].contains(
"net_chain_classes" ) );
4028 BOOST_CHECK( !second.
IsLossy() );
4029 doc[
"net_settings"][
"net_chain_classes"] = nlohmann::json::object();
4032 BOOST_CHECK( !
empty.IsLossy() );
4041 for(
const wxString& keyword : { wxT(
"microvia_aspect_ratio" ), wxT(
"microvia_stack_depth" ) } )
4043 const wxString rule =
"(version 1)(rule \"new\" (constraint " + keyword +
" (max 2)))";
4045 BOOST_CHECK(
result.m_error.IsEmpty() );
4049 for(
const wxString& call :
4050 { wxT(
"A.intersectsKeepout('x')" ), wxT(
"A.intersectsArea('x')" ), wxT(
"A.isStackedVia()" ),
4051 wxT(
"A.ISSTACKEDVIA()" ), wxT(
"A.customProperty('Owner') == 'Team'" ),
4052 wxT(
"A.hasCustomProperty('Owner')" ) } )
4054 for(
const wxString& expression : { wxT(
"condition" ), wxT(
"assertion" ) } )
4056 const wxString rule =
4057 expression == wxT(
"condition" )
4058 ?
"(rule \"new\" (condition \"" + call +
"\") (constraint clearance (min 0.2mm)))"
4059 :
"(rule \"new\" (constraint assertion \"" + call +
"\"))";
4061 BOOST_CHECK(
result.m_error.IsEmpty() );
4066 const wxString kept = wxT(
"(rule \"customProperty\" (condition \"A.NetName == 'isStackedVia()'\") "
4067 "(constraint clearance (min 0.2mm)))\n"
4068 "(rule \"literal\" (condition \"A.NetName == 'intersectsArea()'\") "
4069 "(constraint clearance (min 0.2mm)))\n"
4070 "(rule \"uppercase literal\" (condition \"A.NetName == 'ISSTACKEDVIA()'\") "
4071 "(constraint clearance (min 0.2mm)))\n"
4072 "(rule \"legacy\" (condition \"A.insideArea('x')\") "
4073 "(constraint clearance (min 0.2mm)))\n"
4074 "(rule \"position\" (condition \"A.Start_X > 1mm && A.Start_Y > 1mm\") "
4075 "(constraint clearance (min 0.2mm)))" );
4077 BOOST_CHECK(
result.m_error.IsEmpty() );
4078 BOOST_CHECK(
result.m_dropped.empty() );
4079 BOOST_CHECK(
result.m_text.Contains( kept ) );
4088 for(
const wxString& kind : { wxT(
"condition" ), wxT(
"assertion" ) } )
4090 const wxString expression = wxT(
"A.Parent == A.Parent && A.NetName != 'A.parent.Reference'" );
4091 const wxString body =
4092 kind == wxT(
"condition" )
4093 ? wxT(
"(condition \"" ) + expression + wxT(
"\") (constraint clearance (min 0.2mm))" )
4094 : wxT(
"(constraint assertion \"" ) + expression + wxT(
"\")" );
4097 BOOST_CHECK( parent.m_error.IsEmpty() );
4098 BOOST_CHECK( parent.m_dropped.empty() );
4101 for(
const wxString& property :
4102 { wxT(
"A.Start_Shape" ), wxT(
"A.start_shape" ), wxT(
"B.End_Width" ), wxT(
"AB.Scale_X" ),
4103 wxT(
"A.parent.Reference" ), wxT(
"A . PARENT . Reference" ), wxT(
"A.Major_Radius" ),
4104 wxT(
"A.Exclude_From_Simulation" ), wxT(
"A.Automatically_Update_Net" ), wxT(
"A.Grid_Type" ) } )
4106 for(
const wxString& kind : { wxT(
"condition" ), wxT(
"assertion" ) } )
4108 const wxString expression =
4109 property + (
property.Contains( wxT(
"Reference" ) ) ? wxT(
" == 'U1'" ) : wxT(
" == 1" ) );
4110 const wxString body =
4111 kind == wxT(
"condition" )
4112 ? wxT(
"(condition \"" ) + expression + wxT(
"\") (constraint clearance (min 0.2mm))" )
4113 : wxT(
"(constraint assertion \"" ) + expression + wxT(
"\")" );
4116 BOOST_CHECK(
result.m_error.IsEmpty() );
4121 for(
const wxString& property :
4122 { wxT(
"A.Corner_Radius" ), wxT(
"A.Auto_Thickness" ), wxT(
"A.Target_Delay" ) } )
4124 for(
const wxString& kind : { wxT(
"condition" ), wxT(
"assertion" ) } )
4126 const wxString expression =
property + wxT(
" == 1" );
4127 const wxString body =
4128 kind == wxT(
"condition" )
4129 ? wxT(
"(condition \"" ) + expression + wxT(
"\") (constraint clearance (min 0.2mm))" )
4130 : wxT(
"(constraint assertion \"" ) + expression + wxT(
"\")" );
4133 BOOST_CHECK(
result.m_error.IsEmpty() );
4138 const wxString kept = wxT(
"(rule \"literal\" (condition \"A.NetName == 'A.Start_Shape' && A.Start_X > 1mm "
4139 "&& A.End_Y > 1mm && A.Radius > 1mm\") (constraint clearance (min 0.2mm)))" );
4141 BOOST_CHECK(
result.m_error.IsEmpty() );
4142 BOOST_CHECK(
result.m_dropped.empty() );
4143 BOOST_CHECK(
result.m_text.Contains( kept ) );
constexpr EDA_IU_SCALE pcbIUScale
COMPATIBILITY_REPORT ClassifyBoardForDowngrade(const BOARD *aBoard, const DOWNGRADE_TARGET &aTarget, bool aDropInsteadOfApproximate)
Report what a board would lose if exported to an older KiCad.
void SaveFootprintForTarget(FOOTPRINT *aFootprint, const wxString &aPath, const DOWNGRADE_TARGET &aTarget)
Save a single .kicad_mod footprint file for the target.
int BoardDowngradeCoveredVersion()
The format the denylist was generated against. A format bump forces a review.
void SaveBoardForTarget(BOARD *aBoard, const wxString &aPath, const DOWNGRADE_TARGET &aTarget)
Save a board stamped for the target, using the writer for that version.
void FlattenBoardVariant(BOARD *aBoard, const wxString &aVariantName)
Bake a variant's overrides into the base footprint attributes.
bool ExportBoardToOlderVersion(const wxString &aSrcFile, const wxString &aDestFile, const DOWNGRADE_TARGET &aTarget, COMPATIBILITY_REPORT &aReport, wxString *aUnsupportedToken, const wxString &aVariant, bool aDropInsteadOfApproximate)
Load a board, downgrade the copy, and write it stamped for the target.
DOWNGRADE_FILE_RESULT DowngradeFootprintFileToTemp(const wxString &aSrcFile, const wxString &aTmpFile, const DOWNGRADE_TARGET &aTarget, bool aDropInsteadOfApproximate)
Load one .kicad_mod, classify it against the rule table, and write the downgraded copy to aTmpFile.
void DowngradeBoardInPlace(BOARD *aBoard, const DOWNGRADE_TARGET &aTarget, bool aDropInsteadOfApproximate)
Approximate or remove, in place, what the target cannot represent.
void DowngradeFootprintInPlace(FOOTPRINT *aFootprint, const DOWNGRADE_TARGET &aTarget, bool aDropInsteadOfApproximate)
Footprint-scoped downgrade for standalone .kicad_mod files the board pass never sees.
wxString FindUnsupportedBoardToken(const wxString &aSerialized, const DOWNGRADE_TARGET &aTarget)
Scan serialized board text for tokens the target cannot parse.
@ BS_ITEM_TYPE_DIELECTRIC
int GetLegacyPPI() const
Recompute the PPI the way it was computed before the pixels/cm truncation fix.
wxString GetNetname() const
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
std::map< PCB_LAYER_ID, ZONE_LAYER_PROPERTIES > m_ZoneLayerProperties
DRILL_SYMBOL_PROFILE & GetDrillSymbolProfile()
BOARD_STACKUP & GetStackupDescriptor()
Abstract interface for BOARD_ITEMs capable of storing other items inside.
virtual void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false)=0
Adds an item to the container.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
virtual bool IsKnockout() const
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
virtual void SetIsKnockout(bool aKnockout)
Manage one layer needed to make a physical board.
DIELECTRIC_MODEL GetDielectricModel(int aDielectricSubLayer=0) const
void SetDielectricModel(DIELECTRIC_MODEL aModel, int aDielectricSubLayer=0)
void Add(BOARD_STACKUP_ITEM *aItem)
Add a new item in stackup layer.
Information pertinent to a Pcbnew printed circuit board.
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Removes an item from the container.
const GENERATORS & Generators() const
void SetProperties(const std::map< wxString, wxString > &aProps)
NETINFO_ITEM * FindNet(int aNetcode) const
Search for a net with the given netcode.
TITLE_BLOCK & GetTitleBlock()
const TRACKS & Tracks() const
const CONSTRAINTS & Constraints() const
Geometric constraints (#2329) owned by this board.
void SetCopperLayerCount(int aCount)
void SetProject(PROJECT *aProject, bool aReferenceOnly=false)
Link a board to a given project.
wxString GroupsSanityCheck(bool repair=false)
Consistency check of internal m_groups structure.
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
void SetEnabledLayers(const LSET &aLayerMask)
A proxy function that calls the correspondent function in m_BoardSettings.
const DRAWINGS & Drawings() const
What an export to a given target will keep, approximate, drop, or block.
bool IsLossy() const
True if anything is approximated or dropped. This is what triggers the lossy warning.
bool IsBlocked() const
True if some feature makes the target impossible. The user cannot export anyway.
int Count(DOWNGRADE_BUCKET aBucket) const
const std::vector< COMPAT_ENTRY > & Entries() const
Stage related design and library files together, retaining originals until every write is ready.
const wxString & GetRecoveryError() const
Recovery details are nonempty only if restoring an original or removing a new output failed.
wxString Commit()
Replace all destinations, rolling back earlier replacements if a rename fails.
wxString Stage(const wxString &aDestination)
Return an exclusively-created sibling staging file, or empty if it cannot be created.
void Discard(const wxString &aTemporary)
Forget a skipped conversion without exposing its empty staging file as an output.
void Parse(std::vector< std::shared_ptr< DRC_RULE > > &aRules, REPORTER *aReporter)
Grouping rules and symbol assignments, shared by reference so a chart and its map can never disagree ...
void SetName(const wxString &aName)
A set of EDA_ITEMs (i.e., without duplicates).
std::unordered_set< EDA_ITEM * > & GetItems()
void AddItem(EDA_ITEM *aItem)
Add item to group.
void SetName(const wxString &aName)
A base class for most all the KiCad significant classes used in schematics and boards.
virtual EDA_GROUP * GetParentGroup() const
KICAD_T Type() const
Returns the type of object.
bool HasCustomProperties() const
void SetCustomProperty(const wxString &aKey, const wxString &aValue)
void SetEndEnding(const LINE_ENDING &aEnding)
FILL_T GetFillMode() const
void TransformWithLineEndingsToPolygon(SHAPE_POLY_SET &aBuffer, int aClearance, int aError, ERROR_LOC aErrorLoc, bool ignoreLineWidth=false) const
Convert the shape body shortened for line endings plus line-ending geometry to polygons.
void SetLineStyle(const LINE_STYLE aStyle)
SHAPE_POLY_SET & GetPolyShape()
void SetEndEndingStyle(LINE_ENDING_STYLE aStyle)
LINE_STYLE GetLineStyle() const
LINE_ENDING_STYLE GetEndEndingStyle() const
int GetCornerRadius() const
void SetFillMode(FILL_T aFill)
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
virtual const wxString & GetText() const
Return the string associated with the text object.
KIFONT::FONT * GetFont() const
void SetBold(bool aBold)
Set the text to be bold - this will also update the font if needed.
virtual int GetTextThickness() const
virtual void SetText(const wxString &aText)
void SetFont(KIFONT::FONT *aFont)
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
static FONT * GetFont(const wxString &aFontName=wxEmptyString, bool aBold=false, bool aItalic=false, const std::vector< wxString > *aEmbeddedFiles=nullptr, bool aForDrawingSheet=false)
virtual bool IsOutline() const
wxString AsString() const
std::string AsStdString() const
A temporary directory deleted when it goes out of scope.
const std::filesystem::path & GetPath() const
A logical library item identifier and consists of various portions much like a URI.
Decorative shape (arrowhead, circle, square) at the start or end of a graphic line,...
LSEQ Seq(const LSEQ &aSequence) const
Return an LSEQ from the union of this LSET and a desired sequence.
static LSET AllCuMask(int aCuLayerCount)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Handle the data for a net.
void SetParent(BOARD *aParent)
A PADSTACK defines the characteristics of a single or multi-layer pad, in the IPC sense of the word.
MASK_LAYER_PROPS & FrontOuterLayers()
void SetUnconnectedLayerMode(UNCONNECTED_LAYER_MODE aMode)
UNCONNECTED_LAYER_MODE UnconnectedLayerMode() const
@ CUSTOM
Shapes can be defined on arbitrary layers.
MASK_LAYER_PROPS & BackOuterLayers()
LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
VECTOR2I GetPosition() const override
double GetRoundRectRadiusRatio(PCB_LAYER_ID aLayer) const
PAD_SHAPE GetShape(PCB_LAYER_ID aLayer) const
VECTOR2I GetSize(PCB_LAYER_ID aLayer) const
EDA_ANGLE GetOrientation() const
Return the rotation angle of the pad.
const VECTOR2I & GetMid() const
wxString GetShownText(RESOLUTION_CONTEXT aContext) const
void SetShowText(bool aShow)
void SetBarcodeText(const wxString &aText)
void SetWidth(int aWidth)
void SetBarcodeKind(BARCODE_T aKind)
void SetHeight(int aHeight)
void SetLayer(PCB_LAYER_ID aLayer) override
Set the drawing layer for the barcode and its text.
void TransformShapeToPolygon(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aMaxError, ERROR_LOC aErrorLoc=ERROR_INSIDE, bool ignoreLineWidth=false) const override
Convert the barcode (text + symbol shapes) to polygonal geometry suitable for filling/collision tests...
A geometric constraint between board items (issue #2329).
void AddMember(const KIID &aItem, CONSTRAINT_ANCHOR aAnchor=CONSTRAINT_ANCHOR::WHOLE, int aIndex=-1)
virtual void SetEnd(const VECTOR2I &aPoint)
virtual void SetStart(const VECTOR2I &aPoint)
void ChangeOverrideText(const wxString &aValue)
For better understanding of the points that make a dimension:
void SetHeight(int aHeight)
Set the distance from the feature points to the crossbar line.
A drill chart placed on the board, kept in step with the holes.
Turns on drill symbols at the holes, for one layer.
wxString GetShownText(RESOLUTION_CONTEXT aContext, int aDepth=0) const override
Return the string actually shown after processing of the base text.
PCB_GENERATOR * DeepClone() const
A set of BOARD_ITEMs (i.e., without duplicates).
A PCB_IO derivation for saving and loading Pcbnew s-expression formatted files.
std::unique_ptr< FOOTPRINT > ImportFootprint(const wxString &aFootprintPath, wxString &aFootprintNameOut, const std::map< std::string, UTF8 > *aProperties=nullptr) override
Load a single footprint from aFootprintPath and put its name in aFootprintNameOut.
void FootprintSave(const wxString &aLibraryPath, const FOOTPRINT *aFootprint, const std::map< std::string, UTF8 > *aProperties=nullptr) override
Write aFootprint to an existing library located at aLibraryPath.
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 FormatBoardToFormatter(OUTPUTFORMATTER *aOut, BOARD *aBoard, const std::map< std::string, UTF8 > *aProperties=nullptr)
Serialize a BOARD to an OUTPUTFORMATTER without file I/O or Prettify.
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...
Object to handle a bitmap image that can be inserted in a PCB.
REFERENCE_IMAGE & GetReferenceImage()
void SetEllipseCenter(const VECTOR2I &aPt) override
void SetCornerRadius(int aCornerRadius) override
void SetWidth(int aWidth) override
void SetEllipseStartAngle(const EDA_ANGLE &aA) override
void SetEllipseEndAngle(const EDA_ANGLE &aA) override
void SetEnd(const VECTOR2I &aEnd) override
void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
void SetEllipseMinorRadius(int aR) override
void SetStart(const VECTOR2I &aStart) override
void SetEllipseMajorRadius(int aR) override
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
void AddCell(PCB_TABLECELL *aCell)
void SetColCount(int aCount)
void SetTextThickness(int aWidth) override
The TextThickness is that set by the user.
VECTOR2I GetPosition() const override
int GetTextThickness() const override
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
virtual EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
const VECTOR2I & GetStart() const
const VECTOR2I & GetEnd() const
virtual int GetWidth() const
const STRING_ANY_MAP GetProperties() const override
PCB_TUNING_PATTERN(BOARD_ITEM *aParent=nullptr, PCB_LAYER_ID aLayer=F_Cu, LENGTH_TUNING_MODE aMode=LENGTH_TUNING_MODE::SINGLE)
PNS::MEANDER_SETTINGS & GetSettings()
A microvia stack: several single hop microvias, plus connecting traces for staggered stacks,...
VIA_STACK_STYLE GetStyle() const
PCB_LAYER_ID GetStartLayer() const
PCB_LAYER_ID GetEndLayer() const
wxString GetGeneratorType() const override
PCB_VIA_STITCH(BOARD_ITEM *aParent=nullptr)
int GetGuardedNetCode() const
Net being guarded in GUARD mode.
const PADSTACK & Padstack() const
void SetViaType(VIATYPE aViaType)
VIATYPE GetViaType() const
bool m_isTimeDomain
Calculate tuning in the time domain.
A REFERENCE_IMAGE is a wrapper around a BITMAP_IMAGE that is displayed in an editor as a reference fo...
bool ReadImageFile(const wxString &aFullFilename)
Read and store an image file.
const BITMAP_BASE & GetImage() const
Get the underlying image.
double GetImageScale() const
void SetImageScale(double aScale)
Set the image "zoom" value.
bool LoadProject(const wxString &aFullPath, bool aSetActive=true)
Load a project or sets up a new project with a specified path.
PROJECT * GetProject(const wxString &aFullPath) const
Retrieve a loaded project by name.
double Area(bool aAbsolute=true) const
Return the area of this chain.
Represent a set of closed polygons.
double Area()
Return the area of this poly set.
int HoleCount(int aOutline) const
Returns the number of holes in a given outline.
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Appends a vertex at the end of the given outline/hole (default: the last outline)
void Simplify()
Simplify the polyset (merges overlapping polys, eliminates degeneracy/self-intersections)
SHAPE_LINE_CHAIN & Outline(int aIndex)
Return the reference to aIndex-th outline in the set.
int NewOutline()
Creates a new empty polygon in the set and returns its index.
const SHAPE_LINE_CHAIN & CHole(int aOutline, int aHole) const
int OutlineCount() const
Return the number of outlines in the set.
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
A name/value tuple with unique names and wxAny values.
bool get_to(const std::string &aKey, T &aVar) const
void set(const std::string &aKey, const T &aVar)
void SetComment(int aIdx, const wxString &aComment)
void SetTitle(const wxString &aTitle)
const wxString & GetTitle() const
A wrapper for reporting to a wxString object.
Handle a list of polygons defining a copper zone.
bool GetIsRuleArea() const
Accessors to parameters used in Rule Area zones:
bool GetDoNotAllowVias() const
bool AppendCorner(const VECTOR2I &aPosition, int aHoleIdx, bool aAllowDuplication=false)
Add a new corner to the zone outline (to the main outline or a hole)
ZONE_LAYER_PROPERTIES & LayerProperties(PCB_LAYER_ID aLayer)
wxString GetPlacementAreaSource() const
std::shared_ptr< SHAPE_POLY_SET > GetFilledPolysList(PCB_LAYER_ID aLayer) const
bool GetDoNotAllowPads() const
PLACEMENT_SOURCE_T GetPlacementAreaSourceType() const
bool GetDoNotAllowTracks() const
virtual void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
SHAPE_POLY_SET * Outline()
bool IsIsland(PCB_LAYER_ID aLayer, int aPolyIdx) const
Check if a given filled polygon is an insulated island.
bool IsCopperThieving() const
const wxString & GetZoneName() const
SHAPE_POLY_SET GetBoardOutline() const
void SetFillMode(ZONE_FILL_MODE aFillMode)
void SetLayerSet(const LSET &aLayerSet) override
bool GetPlacementAreaEnabled() const
bool GetDoNotAllowFootprints() const
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
bool GetDoNotAllowZoneFills() const
DOWNGRADE_BUCKET
What happens to a feature when we export to an older KiCad.
@ BLOCK
Cannot be represented at all, export to this target is not possible.
@ LOWER
Approximated down to a simpler equivalent.
@ DROP
No equivalent, left out.
static bool empty(const wxTextEntryBase *aCtrl)
wxString DowngradeLibraryFilesInPlace(const wxString &aDir, const wxString &aGlob, int aStampVersion, const std::function< wxString(const wxString &)> &aFindForbidden, const std::function< DOWNGRADE_FILE_RESULT(const wxString &, const wxString &)> &aConvert, DOWNGRADE_FILE_TRANSACTION *aTransaction=nullptr, wxString *aRecoveryError=nullptr)
Downgrade every library file matching aGlob under aDir in place.
bool IsDowngradeDesignFile(const wxString &aPath)
Files the project export carries over.
DOWNGRADE_FILE_RESULT
What a per-file converter did with one library file.
@ REFUSED
The target cannot represent this file.
@ CONVERTED
The temp file holds the downgraded copy.
DRC_RULES_FILTER_RESULT FilterDrcRulesForTarget(const wxString &aRulesText, const DOWNGRADE_TARGET &aTarget)
Filter a .kicad_dru file for the target.
static constexpr EDA_ANGLE ANGLE_0
static constexpr EDA_ANGLE ANGLE_90
static constexpr EDA_ANGLE ANGLE_360
@ FILLED_SHAPE
Fill with object color.
@ RECTANGLE
Use RECTANGLE instead of RECT to avoid collision in a Windows header.
PCB_LAYER_ID
A quick note on layer IDs:
Test utilities for timestamps.
std::string GetPcbnewTestDataDir()
Utility which returns a path to the data directory where the test board files are stored.
std::string ReadGoldenText(const std::string &aPath)
wxMemoryBuffer MakePngWithFractionalPixelsPerCm()
A tiny PNG whose embedded resolution gives a fractional pixels/cm, so the legacy truncating PPI diffe...
double SerializedImageScale(const std::string &aContent, const std::string &aUuid)
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
@ PTH
Plated through hole pad.
@ PRESSFIT
a PTH with a hole diameter with tight tolerances for press fit pin
@ NONE
no special fabrication property
@ REMOVE_EXCEPT_START_AND_END
BARCODE class definition.
@ HORIZONTAL
A segment (or two points) is horizontal.
Class to handle a set of BOARD_ITEMs.
#define SEXPR_BOARD_FILE_VERSION
Current s-expression file format version. 2 was the last legacy format version.
@ STITCH
Fill the outline with vias with a pattern.
@ GUARD
Place vias to guard a net contained within.
void DowngradeProjectFileJson(nlohmann::json &aDoc, const DOWNGRADE_TARGET &aTarget, COMPATIBILITY_REPORT &aReport)
Migrate a .kicad_pro document down to what the target release expects.
One line in the compatibility report.
An older KiCad release we can export a project back to.
wxString m_text
The filtered rules file text.
wxString m_error
Invalid source syntax; do not write m_text.
std::vector< wxString > m_dropped
Names of the rules the target cannot parse.
std::optional< bool > is_capped
True if the drill hole should be capped.
std::optional< bool > is_filled
True if the drill hole should be filled completely.
std::optional< bool > has_covering
True if the pad on this side should have covering.
std::optional< bool > has_plugging
True if the drill hole should be plugged on this side.
std::optional< VECTOR2I > hatching_offset
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_AUTO_TEST_CASE(EmptyBoardIsClean)
static void checkFeature(const COMPATIBILITY_REPORT &aReport, const wxString &aName, DOWNGRADE_BUCKET aBucket, int aCount)
BOOST_AUTO_TEST_SUITE(CadstarPartParser)
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_AUTO_TEST_SUITE_END()
IbisParser parser & reporter
VECTOR3I expected(15, 30, 45)
static const DOWNGRADE_TARGET & kicad10
static const DOWNGRADE_TARGET & kicad9
BOOST_TEST_CONTEXT("Test Clearance")
BOOST_TEST_MESSAGE("Polyline has "<< chain.PointCount()<< " points")
wxString result
Test unit parsing edge cases and error handling.
BOOST_CHECK_EQUAL(result, "25.4")
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
@ PCB_BARCODE_T
class PCB_BARCODE, a barcode (graphic item)
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
VECTOR2< int32_t > VECTOR2I
Class ZONE_SETTINGS used to handle zones parameters in dialogs.