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