KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_drc_length_with_chain.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, you may find one here:
18 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19 */
20
21#include <boost/test/unit_test.hpp>
22
23#include <filesystem>
24#include <fstream>
25
26#include <board.h>
28#include <drc/drc_engine.h>
29#include <drc/drc_item.h>
30#include <netinfo.h>
31#include <pcb_marker.h>
33
34
35// Two-net board. CHAIN_NET is 25 mm long and tagged with chain "SIG"; PLAIN_NET is 25 mm long
36// and not in any chain. The .kicad_dru rule matches the default netclass that both nets
37// inherit.
38static const char* BOARD_TEXT = R"KICAD(
39(kicad_pcb
40 (version 20250904)
41 (generator "pcbnew")
42 (generator_version "9.99")
43 (layers
44 (0 "F.Cu" signal)
45 (2 "B.Cu" signal)
46 )
47 (net 0 "")
48 (net 1 "/CHAIN_NET")
49 (net 2 "/PLAIN_NET")
50 (segment (start 0 0) (end 25 0) (width 0.2) (layer "F.Cu") (net 1))
51 (segment (start 0 5) (end 25 5) (width 0.2) (layer "F.Cu") (net 2))
52)
53)KICAD";
54
55
56// length 0..5 mm fails for any 25 mm net. net_chain_length 0..200 mm passes for the chain.
57// The bug: pre-fix, presence of net_chain_length suppresses the per-net length check on every
58// net the rule matches, so neither CHAIN_NET nor PLAIN_NET reports a length violation.
59static const char* DRU_TEXT = R"KICAD((version 1)
60
61(rule "FastTopo"
62 (condition "A.NetClass == 'Default'")
63 (constraint length (min 0mm) (max 5mm))
64 (constraint net_chain_length (min 0mm) (max 200mm))
65)
66)KICAD";
67
68
69BOOST_AUTO_TEST_SUITE( DRCLengthWithChain )
70
71
72BOOST_AUTO_TEST_CASE( PerNetLengthFiresAlongsideChainLength )
73{
74 namespace fs = std::filesystem;
75
76 fs::path tmpDir = fs::temp_directory_path() / "kicad_drc_length_chain";
77 fs::create_directories( tmpDir );
78
79 fs::path pcbPath = tmpDir / "len_chain.kicad_pcb";
80 fs::path druPath = tmpDir / "len_chain.kicad_dru";
81
82 {
83 std::ofstream pcbOut( pcbPath );
84 pcbOut << BOARD_TEXT;
85 }
86
87 {
88 std::ofstream druOut( druPath );
89 druOut << DRU_TEXT;
90 }
91
92 PCB_IO_KICAD_SEXPR plugin;
93 std::unique_ptr<BOARD> board = std::make_unique<BOARD>();
94 plugin.LoadBoard( pcbPath.string(), board.get() );
95 board->BuildConnectivity();
96
97 // Tag CHAIN_NET into a signal chain so the chain branch fires; leave PLAIN_NET unchained
98 NETINFO_ITEM* chainNet = board->FindNet( wxS( "/CHAIN_NET" ) );
99 BOOST_REQUIRE( chainNet );
100 chainNet->SetNetChain( wxS( "SIG" ) );
101
102 NETINFO_ITEM* plainNet = board->FindNet( wxS( "/PLAIN_NET" ) );
103 BOOST_REQUIRE( plainNet );
104 BOOST_CHECK( plainNet->GetNetChain().IsEmpty() );
105
106 BOARD_DESIGN_SETTINGS& bds = board->GetDesignSettings();
107
108 auto drcEngine = std::make_shared<DRC_ENGINE>( board.get(), &bds );
109 wxFileName ruleFile( druPath.string() );
110 drcEngine->InitEngine( ruleFile );
111 bds.m_DRCEngine = drcEngine;
112
120
121 std::vector<DRC_ITEM> lengthViolations;
122
123 drcEngine->SetViolationHandler(
124 [&]( const std::shared_ptr<DRC_ITEM>& aItem, const VECTOR2I&, int,
125 const std::function<void( PCB_MARKER* )>& )
126 {
127 if( aItem->GetErrorCode() == DRCE_LENGTH_OUT_OF_RANGE )
128 lengthViolations.push_back( *aItem );
129 } );
130
131 drcEngine->RunTests( EDA_UNITS::MM, true, false );
132
133 // Pre-fix behaviour: 0 violations (the chain branch suppresses length on every matched net).
134 // Post-fix behaviour: at least one length violation per matched net (CHAIN_NET, PLAIN_NET).
135 BOOST_CHECK_MESSAGE( lengthViolations.size() >= 2,
136 "Expected per-net length violations on both chain and plain nets, got "
137 << lengthViolations.size() );
138
139 bool chainNetFlagged = false;
140 bool plainNetFlagged = false;
141
142 for( const DRC_ITEM& item : lengthViolations )
143 {
144 for( const KIID& id : item.GetIDs() )
145 {
146 BOARD_ITEM* bi = board->ResolveItem( id );
147
148 if( !bi )
149 continue;
150
151 if( BOARD_CONNECTED_ITEM* bci = dynamic_cast<BOARD_CONNECTED_ITEM*>( bi ) )
152 {
153 if( bci->GetNetCode() == chainNet->GetNetCode() )
154 chainNetFlagged = true;
155
156 if( bci->GetNetCode() == plainNet->GetNetCode() )
157 plainNetFlagged = true;
158 }
159 }
160 }
161
162 BOOST_CHECK_MESSAGE( chainNetFlagged, "Length violation missing for chain-bearing net" );
163 BOOST_CHECK_MESSAGE( plainNetFlagged, "Length violation missing for non-chain net" );
164
165 std::error_code ec;
166 fs::remove( pcbPath, ec );
167 fs::remove( druPath, ec );
168}
169
170
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
Container for design settings for a BOARD object.
std::map< int, SEVERITY > m_DRCSeverities
std::shared_ptr< DRC_ENGINE > m_DRCEngine
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:84
Definition kiid.h:48
Handle the data for a net.
Definition netinfo.h:50
const wxString & GetNetChain() const
Definition netinfo.h:115
int GetNetCode() const
Definition netinfo.h:97
void SetNetChain(const wxString &aNetChain)
Definition netinfo.h:116
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 ...
@ DRCE_UNCONNECTED_ITEMS
Definition drc_item.h:40
@ DRCE_LIB_FOOTPRINT_ISSUES
Definition drc_item.h:83
@ DRCE_INVALID_OUTLINE
Definition drc_item.h:73
@ DRCE_DRILL_OUT_OF_RANGE
Definition drc_item.h:61
@ DRCE_DANGLING_VIA
Definition drc_item.h:51
@ DRCE_LENGTH_OUT_OF_RANGE
Definition drc_item.h:104
@ DRCE_LIB_FOOTPRINT_MISMATCH
Definition drc_item.h:84
@ RPT_SEVERITY_ERROR
@ RPT_SEVERITY_IGNORE
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_AUTO_TEST_SUITE(CadstarPartParser)
static const char * DRU_TEXT
static const char * BOARD_TEXT
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")
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:687