KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_drc_return_path_reference_net.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// One F.Cu chain track with two B.Cu zones underneath: one on net "/GND" and
36// one on net "/VCC". Both zones cover the trunk fully so without a net
37// filter the check passes. With `(net "GND")` the GND zone alone qualifies
38// and the trunk is still covered. With `(net "PWR_*")` no zone qualifies and
39// the trunk is reported as uncovered.
40static const char* DUAL_ZONE_PCB = R"(
41(kicad_pcb
42 (version 20250904)
43 (generator "pcbnew")
44 (generator_version "9.99")
45 (layers
46 (0 "F.Cu" signal)
47 (2 "B.Cu" signal)
48 (44 "Edge.Cuts" user)
49 )
50 (net 0 "")
51 (net 1 "/CHAIN_RN")
52 (net 2 "/GND")
53 (net 3 "/VCC")
54 (gr_line (start -5 -5) (end 35 -5) (layer "Edge.Cuts") (width 0.05))
55 (gr_line (start 35 -5) (end 35 5) (layer "Edge.Cuts") (width 0.05))
56 (gr_line (start 35 5) (end -5 5) (layer "Edge.Cuts") (width 0.05))
57 (gr_line (start -5 5) (end -5 -5) (layer "Edge.Cuts") (width 0.05))
58 (segment (start 0 0) (end 30 0) (width 0.2) (layer "F.Cu") (net 1))
59 (zone (net 2) (net_name "/GND") (layer "B.Cu") (name "gnd_full") (hatch edge 0.508)
60 (connect_pads (clearance 0))
61 (min_thickness 0.254) (filled_areas_thickness no)
62 (fill (thermal_gap 0.508) (thermal_bridge_width 0.508))
63 (polygon
64 (pts (xy -1 -1) (xy 31 -1) (xy 31 1) (xy -1 1))
65 )
66 )
67 (zone (net 3) (net_name "/VCC") (layer "B.Cu") (name "vcc_strip") (hatch edge 0.508)
68 (connect_pads (clearance 0))
69 (min_thickness 0.254) (filled_areas_thickness no)
70 (fill (thermal_gap 0.508) (thermal_bridge_width 0.508))
71 (polygon
72 (pts (xy -1 1.5) (xy 31 1.5) (xy 31 2) (xy -1 2))
73 )
74 )
75)
76)";
77
78
79namespace
80{
81size_t runDrc( const std::string& aDru, const std::string& aSubdir )
82{
83 namespace fs = std::filesystem;
84 fs::path tmpDir = fs::temp_directory_path() / aSubdir;
85 fs::create_directories( tmpDir );
86 fs::path pcbPath = tmpDir / "rn.kicad_pcb";
87 fs::path druPath = tmpDir / "rn.kicad_dru";
88
89 {
90 std::ofstream out( pcbPath );
91 out << DUAL_ZONE_PCB;
92 }
93
94 {
95 std::ofstream out( druPath );
96 out << aDru;
97 }
98
99 PCB_IO_KICAD_SEXPR plugin;
100 std::unique_ptr<BOARD> board = std::make_unique<BOARD>();
101 plugin.LoadBoard( pcbPath.string(), board.get() );
102 board->BuildConnectivity();
103
104 NETINFO_ITEM* sig = board->FindNet( wxS( "/CHAIN_RN" ) );
105 BOOST_REQUIRE( sig );
106 sig->SetNetChain( wxS( "RN" ) );
107
108 BOARD_DESIGN_SETTINGS& bds = board->GetDesignSettings();
109 auto drcEngine = std::make_shared<DRC_ENGINE>( board.get(), &bds );
110 wxFileName ruleFile( druPath.string() );
111 drcEngine->InitEngine( ruleFile );
112 bds.m_DRCEngine = drcEngine;
113
121
122 size_t markerCount = 0;
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_NET_CHAIN_RETURN_PATH_BREAK )
128 markerCount++;
129 } );
130
131 drcEngine->RunTests( EDA_UNITS::MM, true, false );
132
133 fs::remove( pcbPath );
134 fs::remove( druPath );
135 return markerCount;
136}
137}
138
139
140BOOST_AUTO_TEST_SUITE( DRCReturnPathReferenceNet )
141
142
143// Without (net …): both zones qualify, trunk fully covered → 0 markers.
144BOOST_AUTO_TEST_CASE( ReferenceNetEmptyAcceptsAnyZoneRegression )
145{
146 const std::string dru =
147 R"((version 1)
148(rule "RP"
149 (condition "A.NetClass == 'Default'")
150 (constraint length (min 0mm) (max 200mm))
151 (constraint return_path (layer "B.Cu"))
152)
153)";
154 BOOST_CHECK_EQUAL( runDrc( dru, "kicad_drc_rn_any" ), 0u );
155}
156
157
158// (net "GND") plus only-GND zone covering trunk → 0 markers.
159BOOST_AUTO_TEST_CASE( ReferenceNetGndShadowedByGndPasses )
160{
161 const std::string dru =
162 R"((version 1)
163(rule "RP"
164 (condition "A.NetClass == 'Default'")
165 (constraint length (min 0mm) (max 200mm))
166 (constraint return_path (layer "B.Cu") (net "GND"))
168)";
169 // The GND zone only covers the upper half of the track shadow (y < 0).
170 // The trunk runs at y=0 with width 0.2mm — partial coverage. The marker
171 // count depends on whether half-coverage triggers; just assert no false
172 // negative when the zone net matches at all.
173 size_t n = runDrc( dru, "kicad_drc_rn_gnd_match" );
174 BOOST_CHECK_LE( n, 1u );
175}
176
178// (net "PWR_*") matches no zone → trunk reported as uncovered.
179BOOST_AUTO_TEST_CASE( ReferenceNetWildcardNoMatch )
180{
181 const std::string dru =
182 R"((version 1)
183(rule "RP"
184 (condition "A.NetClass == 'Default'")
185 (constraint length (min 0mm) (max 200mm))
186 (constraint return_path (layer "B.Cu") (net "PWR_*"))
187)
188)";
189 size_t n = runDrc( dru, "kicad_drc_rn_wildcard_nomatch" );
190 BOOST_CHECK_GE( n, 1u );
191}
192
193
194// (net "GND*") matches the GND zone → covered (or partially covered).
195BOOST_AUTO_TEST_CASE( ReferenceNetWildcardMatch )
196{
197 const std::string dru =
198 R"((version 1)
199(rule "RP"
200 (condition "A.NetClass == 'Default'")
201 (constraint length (min 0mm) (max 200mm))
202 (constraint return_path (layer "B.Cu") (net "GND*"))
203)
204)";
205 size_t n = runDrc( dru, "kicad_drc_rn_wildcard_match" );
206 BOOST_CHECK_LE( n, 1u );
207}
208
209
Container for design settings for a BOARD object.
std::map< int, SEVERITY > m_DRCSeverities
std::shared_ptr< DRC_ENGINE > m_DRCEngine
Handle the data for a net.
Definition netinfo.h:50
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_NET_CHAIN_RETURN_PATH_BREAK
Definition drc_item.h:106
@ DRCE_DANGLING_VIA
Definition drc_item.h:51
@ 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 * DUAL_ZONE_PCB
BOOST_AUTO_TEST_CASE(ReferenceNetEmptyAcceptsAnyZoneRegression)
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_AUTO_TEST_SUITE_END()
BOOST_CHECK_EQUAL(result, "25.4")
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:687