21#include <boost/test/unit_test.hpp>
52 (generator_version "9.99")
63 (uuid "11111111-1111-1111-1111-111111111111")
69 (uuid "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaa01")
75 (uuid "33333333-3333-3333-3333-333333333333")
81 (uuid "cccccccc-cccc-cccc-cccc-cccccccccc01")
85 (segment (start 0 0) (end 2 0) (width 0.2) (layer "F.Cu") (net 1))
86 (segment (start 5 0) (end 35 0) (width 0.2) (layer "F.Cu") (net 2))
87 (segment (start 38 0) (end 40 0) (width 0.2) (layer "F.Cu") (net 3))
94static const char*
DRU_TEXT = R
"KICAD((version 1)
97 (condition "A.NetClass == 'Default'")
98 (constraint stub_length (min 0mm) (max 5mm))
108 namespace fs = std::filesystem;
110 fs::path tmpDir = fs::temp_directory_path() /
"kicad_drc_stub_length";
111 fs::create_directories( tmpDir );
113 fs::path pcbPath = tmpDir /
"stub_length.kicad_pcb";
114 fs::path druPath = tmpDir /
"stub_length.kicad_dru";
117 std::ofstream pcbOut( pcbPath );
122 std::ofstream druOut( druPath );
127 std::unique_ptr<BOARD> board = std::make_unique<BOARD>();
128 plugin.
LoadBoard( pcbPath.string(), board.get() );
129 board->BuildConnectivity();
131 NETINFO_ITEM* netA = board->FindNet( wxS(
"/TRUNK_A" ) );
133 NETINFO_ITEM* netC = board->FindNet( wxS(
"/TRUNK_C" ) );
146 for(
FOOTPRINT* fp : board->Footprints() )
148 for(
PAD*
pad : fp->Pads() )
166 auto drcEngine = std::make_shared<DRC_ENGINE>( board.get(), &bds );
167 wxFileName ruleFile( druPath.string() );
168 drcEngine->InitEngine( ruleFile );
179 std::vector<wxString> stubMessages;
181 drcEngine->SetViolationHandler(
182 [&](
const std::shared_ptr<DRC_ITEM>& aItem,
const VECTOR2I&,
int,
186 stubMessages.push_back( aItem->GetErrorMessage(
false ) );
191 auto matchesNet = [&](
const wxString& netName )
193 for(
const wxString& msg : stubMessages )
195 if( msg.Contains( wxString::Format( wxS(
"'%s'" ), netName ) ) )
202 bool aFlagged = matchesNet( netA->
GetNetname() );
203 bool bFlagged = matchesNet( netB->
GetNetname() );
204 bool cFlagged = matchesNet( netC->
GetNetname() );
207 "Intermediate stub net MID_B should fire stub_length violation" );
209 "Trunk endpoint net TRUNK_A (owns terminal_pad_0) must not fire" );
211 "Trunk endpoint net TRUNK_C (owns terminal_pad_1) must not fire" );
214 fs::remove( pcbPath, ec );
215 fs::remove( druPath, ec );
221 namespace fs = std::filesystem;
223 fs::path tmpDir = fs::temp_directory_path() /
"kicad_drc_stub_length";
224 fs::create_directories( tmpDir );
226 fs::path pcbPath = tmpDir /
"stub_length_2net.kicad_pcb";
227 fs::path druPath = tmpDir /
"stub_length_2net.kicad_dru";
232 static const char* TWO_NET_BOARD = R
"KICAD(
236 (generator_version "9.99")
246 (uuid "44444444-4444-4444-4444-444444444444")
252 (uuid "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaa02")
258 (uuid "55555555-5555-5555-5555-555555555555")
264 (uuid "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbb02")
268 (segment (start 0 0) (end 30 0) (width 0.2) (layer "F.Cu") (net 1))
269 (segment (start 30 0) (end 60 0) (width 0.2) (layer "F.Cu") (net 2))
273 static const char* TWO_NET_DRU = R
"KICAD((version 1)
276 (condition "A.NetClass == 'Default'")
277 (constraint stub_length (min 0mm) (max 5mm))
282 std::ofstream pcbOut( pcbPath );
283 pcbOut << TWO_NET_BOARD;
287 std::ofstream druOut( druPath );
288 druOut << TWO_NET_DRU;
292 std::unique_ptr<BOARD> board = std::make_unique<BOARD>();
293 plugin.LoadBoard( pcbPath.string(), board.get() );
294 board->BuildConnectivity();
308 for(
FOOTPRINT* fp : board->Footprints() )
310 for(
PAD*
pad : fp->Pads() )
328 auto drcEngine = std::make_shared<DRC_ENGINE>( board.get(), &bds );
329 wxFileName ruleFile( druPath.string() );
330 drcEngine->InitEngine( ruleFile );
343 drcEngine->SetViolationHandler(
344 [&](
const std::shared_ptr<DRC_ITEM>& aItem,
const VECTOR2I&,
int,
354 "Two-net chain with both ends owning terminal pads must not "
355 "fire any stub_length violation, got "
359 fs::remove( pcbPath, ec );
360 fs::remove( druPath, ec );
366 namespace fs = std::filesystem;
368 fs::path tmpDir = fs::temp_directory_path() /
"kicad_drc_stub_length";
369 fs::create_directories( tmpDir );
371 fs::path pcbPath = tmpDir /
"stub_length_pad_to_die.kicad_pcb";
372 fs::path druPath = tmpDir /
"stub_length_pad_to_die.kicad_dru";
378 static const char* PAD_TO_DIE_BOARD = R
"KICAD(
382 (generator_version "9.99")
393 (uuid "66666666-6666-6666-6666-666666666666")
399 (uuid "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaa03")
405 (uuid "77777777-7777-7777-7777-777777777777")
411 (uuid "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbb03")
417 (uuid "88888888-8888-8888-8888-888888888888")
423 (uuid "cccccccc-cccc-cccc-cccc-cccccccccc03")
427 (segment (start 0 0) (end 2 0) (width 0.2) (layer "F.Cu") (net 1))
428 (segment (start 3 0) (end 5 0) (width 0.2) (layer "F.Cu") (net 2))
429 (segment (start 8 0) (end 10 0) (width 0.2) (layer "F.Cu") (net 3))
433 static const char* PAD_TO_DIE_DRU = R
"KICAD((version 1)
436 (condition "A.NetClass == 'Default'")
437 (constraint stub_length (min 0mm) (max 5mm))
442 std::ofstream pcbOut( pcbPath );
443 pcbOut << PAD_TO_DIE_BOARD;
447 std::ofstream druOut( druPath );
448 druOut << PAD_TO_DIE_DRU;
452 std::unique_ptr<BOARD> board = std::make_unique<BOARD>();
453 plugin.LoadBoard( pcbPath.string(), board.get() );
455 NETINFO_ITEM* netA = board->FindNet( wxS( "/TRUNK_A" ) );
457 NETINFO_ITEM* netC = board->FindNet( wxS(
"/TRUNK_C" ) );
471 for(
FOOTPRINT* fp : board->Footprints() )
473 for(
PAD*
pad : fp->Pads() )
497 board->BuildConnectivity();
501 auto drcEngine = std::make_shared<DRC_ENGINE>( board.get(), &bds );
502 wxFileName ruleFile( druPath.string() );
503 drcEngine->InitEngine( ruleFile );
514 std::vector<wxString> stubMessages;
516 drcEngine->SetViolationHandler(
517 [&](
const std::shared_ptr<DRC_ITEM>& aItem,
const VECTOR2I&,
int,
521 stubMessages.push_back( aItem->GetErrorMessage(
false ) );
526 auto matchesNet = [&](
const wxString& netName )
528 for(
const wxString& msg : stubMessages )
530 if( msg.Contains( wxString::Format( wxS(
"'%s'" ), netName ) ) )
538 "Stub net MID_B with 2 mm route + 10 mm pad-to-die must violate "
539 "the 5 mm stub_length budget" );
542 fs::remove( pcbPath, ec );
543 fs::remove( druPath, ec );
554 const wxString DRU_TIME = wxS(
556 "(rule \"StubBudgetTime\"\n"
557 " (condition \"A.NetClass == 'Default'\")\n"
558 " (constraint stub_length (max 100ps))\n"
564 std::vector<std::shared_ptr<DRC_RULE>> rules;
566 parser.
Parse( rules, &reporter );
569 "stub_length with ps units must parse without error, got: "
572 BOOST_REQUIRE_EQUAL( rules.size(), 1u );
574 std::optional<DRC_CONSTRAINT> stubConstraint =
593 const wxString DRU_LAYER = wxS(
595 "(rule \"GoodReturnPath\"\n"
596 " (condition \"A.NetClass == 'Default'\")\n"
597 " (constraint return_path (layer \"B.Cu\"))\n"
603 std::vector<std::shared_ptr<DRC_RULE>> rules;
605 parser.
Parse( rules, &reporter );
608 "return_path with a layer must parse without error, got: "
611 BOOST_REQUIRE_EQUAL( rules.size(), 1u );
613 std::optional<DRC_CONSTRAINT> rpConstraint =
constexpr EDA_IU_SCALE pcbIUScale
Container for design settings for a BOARD object.
std::map< int, SEVERITY > m_DRCSeverities
std::shared_ptr< DRC_ENGINE > m_DRCEngine
void Parse(std::vector< std::shared_ptr< DRC_RULE > > &aRules, REPORTER *aReporter)
Handle the data for a net.
const wxString & GetNetname() const
void SetNetChain(const wxString &aNetChain)
void SetTerminalPad(int aIndex, PAD *aPad)
void SetPadToDieLength(int aLength)
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 ...
virtual bool HasMessageOfSeverity(int aSeverityMask) const
Returns true if the reporter has one or more messages matching the specified severity mask.
A wrapper for reporting to a wxString object.
const wxString & GetMessages() const
@ DRCE_LIB_FOOTPRINT_ISSUES
@ DRCE_NET_CHAIN_STUB_TOO_LONG
@ DRCE_DRILL_OUT_OF_RANGE
@ DRCE_LIB_FOOTPRINT_MISMATCH
@ NET_CHAIN_STUB_LENGTH_CONSTRAINT
@ NET_CHAIN_RETURN_PATH_CONSTRAINT
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_AUTO_TEST_SUITE(CadstarPartParser)
static const char * DRU_TEXT
static const char * BOARD_TEXT
BOOST_AUTO_TEST_CASE(StubLengthFiresOnIntermediateNetOnly)
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_AUTO_TEST_SUITE_END()
BOOST_CHECK_MESSAGE(totalMismatches==0, std::to_string(totalMismatches)+" board(s) with strategy disagreements")
BOOST_CHECK_EQUAL(result, "25.4")
VECTOR2< int32_t > VECTOR2I