KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_drc_return_path_per_segment.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, see <https://www.gnu.org/licenses/>.
18 */
19
20#include <boost/test/unit_test.hpp>
21
22#include <filesystem>
23#include <fstream>
24
25#include <board.h>
27#include <drc/drc_engine.h>
28#include <drc/drc_item.h>
29#include <netinfo.h>
30#include <pcb_marker.h>
32
33
34// Trunk on F.Cu from x=0..30 at y=0. B.Cu zone covers only x=0..15. Per-segment
35// check should report exactly one return-path break, anchored at the
36// uncovered run (around x=22.5).
37static const char* PARTIAL_PCB = R"(
38(kicad_pcb
39 (version 20250904)
40 (generator "pcbnew")
41 (generator_version "9.99")
42 (layers
43 (0 "F.Cu" signal)
44 (2 "B.Cu" signal)
45 (44 "Edge.Cuts" user)
46 )
47 (net 0 "")
48 (net 1 "/CHAIN_PARTIAL")
49 (net 2 "/GND")
50 (gr_line (start -5 -5) (end 35 -5) (layer "Edge.Cuts") (width 0.05))
51 (gr_line (start 35 -5) (end 35 5) (layer "Edge.Cuts") (width 0.05))
52 (gr_line (start 35 5) (end -5 5) (layer "Edge.Cuts") (width 0.05))
53 (gr_line (start -5 5) (end -5 -5) (layer "Edge.Cuts") (width 0.05))
54 (segment (start 0 0) (end 15 0) (width 0.2) (layer "F.Cu") (net 1))
55 (segment (start 15 0) (end 30 0) (width 0.2) (layer "F.Cu") (net 1))
56 (zone (net 2) (net_name "/GND") (layer "B.Cu") (name "gnd_left") (hatch edge 0.508)
57 (connect_pads (clearance 0))
58 (min_thickness 0.254) (filled_areas_thickness no)
59 (fill (thermal_gap 0.508) (thermal_bridge_width 0.508))
60 (polygon
61 (pts (xy -1 -1) (xy 15 -1) (xy 15 1) (xy -1 1))
62 )
63 )
64)
65)";
66
67
68// Trunk fully off-zone: a single track from (0,0) to (30,0) with a B.Cu
69// zone only at x=40..50 — no overlap. Expect exactly one marker (covering
70// the whole track with no zone overlap).
71static const char* FULLY_UNSHADOWED_PCB = R"(
72(kicad_pcb
73 (version 20250904)
74 (generator "pcbnew")
75 (generator_version "9.99")
76 (layers
77 (0 "F.Cu" signal)
78 (2 "B.Cu" signal)
79 (44 "Edge.Cuts" user)
80 )
81 (net 0 "")
82 (net 1 "/CHAIN_FULL")
83 (net 2 "/GND")
84 (gr_line (start -5 -5) (end 55 -5) (layer "Edge.Cuts") (width 0.05))
85 (gr_line (start 55 -5) (end 55 5) (layer "Edge.Cuts") (width 0.05))
86 (gr_line (start 55 5) (end -5 5) (layer "Edge.Cuts") (width 0.05))
87 (gr_line (start -5 5) (end -5 -5) (layer "Edge.Cuts") (width 0.05))
88 (segment (start 0 0) (end 30 0) (width 0.2) (layer "F.Cu") (net 1))
89 (zone (net 2) (net_name "/GND") (layer "B.Cu") (name "gnd_far") (hatch edge 0.508)
90 (connect_pads (clearance 0))
91 (min_thickness 0.254) (filled_areas_thickness no)
92 (fill (thermal_gap 0.508) (thermal_bridge_width 0.508))
93 (polygon
94 (pts (xy 40 -1) (xy 50 -1) (xy 50 1) (xy 40 1))
95 )
96 )
97)
98)";
99
100
101static const char* DRU_TEXT = R"((version 1)
102(rule "ReturnPath"
103 (condition "A.NetClass == 'Default'")
104 (constraint length (min 0mm) (max 200mm))
105 (constraint return_path (layer "B.Cu"))
106)
107)";
108
109
110namespace
111{
112size_t runReturnPathDrc( const char* aPcb, const wxString& aChainName,
113 const wxString& aChainTag,
114 const std::string& aSubdir )
115{
116 namespace fs = std::filesystem;
117 fs::path tmpDir = fs::temp_directory_path() / aSubdir;
118 fs::create_directories( tmpDir );
119 fs::path pcbPath = tmpDir / "ret.kicad_pcb";
120 fs::path druPath = tmpDir / "ret.kicad_dru";
121
122 {
123 std::ofstream out( pcbPath );
124 out << aPcb;
125 }
126
127 {
128 std::ofstream out( druPath );
129 out << DRU_TEXT;
130 }
131
132 PCB_IO_KICAD_SEXPR plugin;
133 std::unique_ptr<BOARD> board = std::make_unique<BOARD>();
134 plugin.LoadBoard( pcbPath.string(), board.get() );
135 board->BuildConnectivity();
136
137 NETINFO_ITEM* sig = board->FindNet( aChainName );
138 BOOST_REQUIRE( sig );
139 sig->SetNetChain( aChainTag );
140
141 BOARD_DESIGN_SETTINGS& bds = board->GetDesignSettings();
142
143 auto drcEngine = std::make_shared<DRC_ENGINE>( board.get(), &bds );
144 wxFileName ruleFile( druPath.string() );
145 drcEngine->InitEngine( ruleFile );
146 bds.m_DRCEngine = drcEngine;
147
155
156 size_t markerCount = 0;
157
158 drcEngine->SetViolationHandler(
159 [&]( const std::shared_ptr<DRC_ITEM>& aItem, const VECTOR2I&, int,
160 const std::function<void( PCB_MARKER* )>& )
161 {
162 if( aItem->GetErrorCode() == DRCE_NET_CHAIN_RETURN_PATH_BREAK )
163 markerCount++;
164 } );
165
166 drcEngine->RunTests( EDA_UNITS::MM, true, false );
167
168 fs::remove( pcbPath );
169 fs::remove( druPath );
170
171 return markerCount;
172}
173}
174
175
176BOOST_AUTO_TEST_SUITE( DRCReturnPathPerSegment )
177
178
179BOOST_AUTO_TEST_CASE( PartiallyShadowedTrunkReportsOneMarker )
180{
181 size_t n = runReturnPathDrc( PARTIAL_PCB, wxS( "/CHAIN_PARTIAL" ),
182 wxS( "PARTIAL" ),
183 "kicad_drc_ret_partial" );
184 BOOST_CHECK_EQUAL( n, 1u );
185}
186
187
188BOOST_AUTO_TEST_CASE( FullyUnshadowedTrunkReportsOneMarker )
189{
190 size_t n = runReturnPathDrc( FULLY_UNSHADOWED_PCB, wxS( "/CHAIN_FULL" ),
191 wxS( "FULL" ),
192 "kicad_drc_ret_full" );
193 BOOST_CHECK_EQUAL( n, 1u );
194}
195
196
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:46
void SetNetChain(const wxString &aNetChain)
Definition netinfo.h:113
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:36
@ DRCE_LIB_FOOTPRINT_ISSUES
Definition drc_item.h:79
@ DRCE_INVALID_OUTLINE
Definition drc_item.h:69
@ DRCE_DRILL_OUT_OF_RANGE
Definition drc_item.h:57
@ DRCE_NET_CHAIN_RETURN_PATH_BREAK
Definition drc_item.h:103
@ DRCE_DANGLING_VIA
Definition drc_item.h:47
@ DRCE_LIB_FOOTPRINT_MISMATCH
Definition drc_item.h:80
@ RPT_SEVERITY_ERROR
@ RPT_SEVERITY_IGNORE
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_AUTO_TEST_SUITE(CadstarPartParser)
static const char * DRU_TEXT
static const char * FULLY_UNSHADOWED_PCB
static const char * PARTIAL_PCB
BOOST_AUTO_TEST_CASE(PartiallyShadowedTrunkReportsOneMarker)
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:683