KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_drc_return_path_zone_bbox.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 F.Cu chains, each 30 mm long. CHAIN_COVERED is shadowed by a B.Cu zone in the
36// (0,0)..(30,1) corridor; CHAIN_UNCOVERED is at y=20 with no overlying B.Cu zone.
37// Pre-fix the global zone count is 1 board-wide so the return-path check never fires.
38// Post-fix the spatial test catches CHAIN_UNCOVERED while leaving CHAIN_COVERED clean.
39static const char* BOARD_TEXT = R"KICAD(
40(kicad_pcb
41 (version 20250904)
42 (generator "pcbnew")
43 (generator_version "9.99")
44 (layers
45 (0 "F.Cu" signal)
46 (2 "B.Cu" signal)
47 (44 "Edge.Cuts" user)
48 )
49 (net 0 "")
50 (net 1 "/CHAIN_COVERED")
51 (net 2 "/CHAIN_UNCOVERED")
52 (net 3 "/GND")
53 (gr_line (start 0 -5) (end 40 -5) (layer "Edge.Cuts") (width 0.05))
54 (gr_line (start 40 -5) (end 40 30) (layer "Edge.Cuts") (width 0.05))
55 (gr_line (start 40 30) (end 0 30) (layer "Edge.Cuts") (width 0.05))
56 (gr_line (start 0 30) (end 0 -5) (layer "Edge.Cuts") (width 0.05))
57 (segment (start 0 0) (end 30 0) (width 0.2) (layer "F.Cu") (net 1))
58 (segment (start 0 20) (end 30 20) (width 0.2) (layer "F.Cu") (net 2))
59 (zone (net 3) (net_name "/GND") (layer "B.Cu") (name "gnd_corridor") (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
65 (xy -1 -1)
66 (xy 31 -1)
67 (xy 31 1)
68 (xy -1 1)
69 )
70 )
71 )
72)
73)KICAD";
74
75
76// length 0..200 mm passes; the only firing constraint is return_path which requires a
77// continuous B.Cu reference under the F.Cu chain.
78static const char* DRU_TEXT = R"KICAD((version 1)
79
80(rule "ReturnPath"
81 (condition "A.NetClass == 'Default'")
82 (constraint length (min 0mm) (max 200mm))
83 (constraint return_path (layer "B.Cu"))
84)
85)KICAD";
86
87
88BOOST_AUTO_TEST_SUITE( DRCReturnPathZoneBBox )
89
90
91BOOST_AUTO_TEST_CASE( ZoneSpatialFilterFiresForUnshadowedChain )
92{
93 namespace fs = std::filesystem;
94
95 fs::path tmpDir = fs::temp_directory_path() / "kicad_drc_return_path_bbox";
96 fs::create_directories( tmpDir );
97
98 fs::path pcbPath = tmpDir / "ret_path.kicad_pcb";
99 fs::path druPath = tmpDir / "ret_path.kicad_dru";
100
101 {
102 std::ofstream pcbOut( pcbPath );
103 pcbOut << BOARD_TEXT;
104 }
105
106 {
107 std::ofstream druOut( druPath );
108 druOut << DRU_TEXT;
109 }
110
111 PCB_IO_KICAD_SEXPR plugin;
112 std::unique_ptr<BOARD> board = std::make_unique<BOARD>();
113 plugin.LoadBoard( pcbPath.string(), board.get() );
114 board->BuildConnectivity();
115
116 NETINFO_ITEM* coveredNet = board->FindNet( wxS( "/CHAIN_COVERED" ) );
117 BOOST_REQUIRE( coveredNet );
118 coveredNet->SetNetChain( wxS( "COVERED" ) );
119
120 NETINFO_ITEM* uncoveredNet = board->FindNet( wxS( "/CHAIN_UNCOVERED" ) );
121 BOOST_REQUIRE( uncoveredNet );
122 uncoveredNet->SetNetChain( wxS( "UNCOVERED" ) );
123
124 BOARD_DESIGN_SETTINGS& bds = board->GetDesignSettings();
125
126 auto drcEngine = std::make_shared<DRC_ENGINE>( board.get(), &bds );
127 wxFileName ruleFile( druPath.string() );
128 drcEngine->InitEngine( ruleFile );
129 bds.m_DRCEngine = drcEngine;
130
138
139 std::vector<DRC_ITEM> returnPathViolations;
140
141 drcEngine->SetViolationHandler(
142 [&]( const std::shared_ptr<DRC_ITEM>& aItem, const VECTOR2I&, int,
143 const std::function<void( PCB_MARKER* )>& )
144 {
145 if( aItem->GetErrorCode() == DRCE_NET_CHAIN_RETURN_PATH_BREAK )
146 returnPathViolations.push_back( *aItem );
147 } );
148
149 drcEngine->RunTests( EDA_UNITS::MM, true, false );
150
151 // Exactly one chain (UNCOVERED) should report a return-path break. Pre-fix the
152 // board-wide zone count of 1 produced zero violations even though only COVERED is
153 // actually shadowed.
154 BOOST_CHECK_EQUAL( returnPathViolations.size(), 1u );
155
156 bool coveredFlagged = false;
157 bool uncoveredFlagged = false;
158
159 for( const DRC_ITEM& item : returnPathViolations )
160 {
161 const wxString msg = item.GetErrorMessage( false );
162
163 if( msg.Find( wxS( "COVERED" ) ) != wxNOT_FOUND
164 && msg.Find( wxS( "UNCOVERED" ) ) == wxNOT_FOUND )
165 {
166 coveredFlagged = true;
167 }
168
169 if( msg.Find( wxS( "UNCOVERED" ) ) != wxNOT_FOUND )
170 uncoveredFlagged = true;
171 }
172
173 BOOST_CHECK_MESSAGE( !coveredFlagged,
174 "Return-path break wrongly reported for chain shadowed by a zone" );
175 BOOST_CHECK_MESSAGE( uncoveredFlagged,
176 "Return-path break missing for chain with no overlying zone" );
177
178 std::error_code ec;
179 fs::remove( pcbPath, ec );
180 fs::remove( druPath, ec );
181}
182
183
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 * 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")
BOOST_CHECK_EQUAL(result, "25.4")
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:687