KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_api_handler_pcb.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 modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation, either version 3 of the License, or (at your
9 * option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * 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 <memory>
21#include <vector>
22
23#include <boost/test/unit_test.hpp>
24
25#include <wx/filename.h>
26
29
30#include <api/api_handler_pcb.h>
32#include <api/board/board_commands.pb.h>
33#include <api/common/envelope.pb.h>
34#include <api/common/types/base_types.pb.h>
35
36#include <board.h>
39#include <zone.h>
40
41
42namespace
43{
44
46const wxString F_CU_ZONE = wxS( "00000000-0000-0000-0000-00005c07d704" );
47const wxString B_CU_ZONE = wxS( "00000000-0000-0000-0000-00005c07d701" );
48const wxString IN1_CU_ZONE = wxS( "00000000-0000-0000-0000-00005c07d707" );
49const wxString IN2_CU_ZONE = wxS( "00000000-0000-0000-0000-00005c07d70a" );
50
51
52struct API_HANDLER_PCB_FIXTURE
53{
54 SETTINGS_MANAGER m_settingsManager;
55 std::unique_ptr<BOARD> m_board;
56 std::shared_ptr<HEADLESS_PCB_CONTEXT> m_context;
57
58 // The context takes ownership of the board; the returned raw pointer lets the test inspect
59 // zone state after the handler runs.
60 BOARD* loadBoard( const wxString& aRelPath )
61 {
62 KI_TEST::LoadBoard( m_settingsManager, aRelPath, m_board );
63
64 BOARD* board = m_board.get();
65 m_context = std::make_shared<HEADLESS_PCB_CONTEXT>( std::move( m_board ),
66 &m_settingsManager.Prj(), nullptr );
67 return board;
68 }
69
70 kiapi::common::ApiRequest makeRefillRequest( BOARD* aBoard, const std::vector<wxString>& aZoneIds ) const
71 {
72 kiapi::board::commands::RefillZones command;
73 command.mutable_board()->set_type( kiapi::common::types::DocumentType::DOCTYPE_PCB );
74 command.mutable_board()->set_board_filename(
75 wxFileName( aBoard->GetFileName() ).GetFullName().ToStdString() );
76
77 for( const wxString& id : aZoneIds )
78 command.add_zones()->set_value( id.ToStdString() );
79
80 kiapi::common::ApiRequest request;
81 request.mutable_header()->set_client_name( "kicad.qa" );
82 BOOST_REQUIRE( request.mutable_message()->PackFrom( command ) );
83
84 return request;
85 }
86
87 ZONE* zoneByUuid( BOARD* aBoard, const wxString& aUuid ) const
88 {
89 for( ZONE* zone : aBoard->Zones() )
90 {
91 if( zone->m_Uuid.AsString() == aUuid )
92 return zone;
93 }
94
95 return nullptr;
96 }
97
98 void unfillAll( BOARD* aBoard ) const
99 {
100 // Start from a clean slate so a positive IsFilled() result can only come from this fill
101 for( ZONE* zone : aBoard->Zones() )
102 {
103 zone->UnFill();
104 BOOST_REQUIRE( !zone->IsFilled() );
105 }
106 }
107};
108
109} // namespace
110
111
112BOOST_FIXTURE_TEST_SUITE( ApiHandlerPcb, API_HANDLER_PCB_FIXTURE )
113
114
115BOOST_AUTO_TEST_CASE( RefillZonesSubset )
116{
117 BOARD* board = loadBoard( wxS( "issue5830" ) );
118
119 unfillAll( board );
120
121 API_HANDLER_PCB handler( m_context );
122 kiapi::common::ApiRequest request = makeRefillRequest( board, { F_CU_ZONE, IN1_CU_ZONE } );
123 API_RESULT result = handler.Handle( request );
124
125 BOOST_REQUIRE_MESSAGE( result.has_value(),
126 "RefillZones returned status " << result.error().status() << ": "
127 << result.error().error_message() );
128 BOOST_CHECK_EQUAL( result->status().status(), kiapi::common::ApiStatusCode::AS_OK );
129
130 ZONE* fCu = zoneByUuid( board, F_CU_ZONE );
131 ZONE* bCu = zoneByUuid( board, B_CU_ZONE );
132 ZONE* in1Cu = zoneByUuid( board, IN1_CU_ZONE );
133 ZONE* in2Cu = zoneByUuid( board, IN2_CU_ZONE );
134
135 BOOST_REQUIRE( fCu && bCu && in1Cu && in2Cu );
136
137 // Exactly the requested zones must be filled; the others must be untouched.
138 BOOST_CHECK( fCu->IsFilled() );
139 BOOST_CHECK( in1Cu->IsFilled() );
140 BOOST_CHECK( !bCu->IsFilled() );
141 BOOST_CHECK( !in2Cu->IsFilled() );
142}
143
144
145BOOST_AUTO_TEST_CASE( RefillZonesSubsetRebuildsConnectivity )
146{
147 BOARD* board = loadBoard( wxS( "issue5830" ) );
148
149 unfillAll( board );
150
151 // Baseline ratsnest with every zone empty; the GND planes are unfilled so their pads still
152 // ratsnest together.
153 board->BuildConnectivity();
154 const unsigned baseline = board->GetConnectivity()->GetUnconnectedCount( false );
155 BOOST_REQUIRE_MESSAGE( baseline > 0, "expected an unconnected baseline with zones empty" );
156
157 API_HANDLER_PCB handler( m_context );
158 kiapi::common::ApiRequest request = makeRefillRequest( board, { F_CU_ZONE, IN1_CU_ZONE } );
159 API_RESULT result = handler.Handle( request );
160
161 BOOST_REQUIRE_MESSAGE( result.has_value(),
162 "RefillZones returned status " << result.error().status() << ": "
163 << result.error().error_message() );
164
165 const unsigned afterFill = board->GetConnectivity()->GetUnconnectedCount( false );
166
167 // Filling the GND planes bridges GND pads that previously ratsnested, so the unconnected
168 // count drops. Push cleared the ratsnest, so if the handler skipped the connectivity
169 // rebuild this would read zero instead of the reduced-but-nonzero count.
170 BOOST_CHECK_MESSAGE( afterFill > 0, "connectivity was cleared, not rebuilt, after the fill" );
171 BOOST_CHECK_MESSAGE( afterFill < baseline,
172 "filling the GND planes should reduce the unconnected count ("
173 << afterFill << " vs baseline " << baseline << ")" );
174}
175
176
177BOOST_AUTO_TEST_CASE( RefillZonesAllHeadless )
178{
179 BOARD* board = loadBoard( wxS( "issue5830" ) );
180
181 unfillAll( board );
182
183 API_HANDLER_PCB handler( m_context );
184 kiapi::common::ApiRequest request = makeRefillRequest( board, {} );
185 API_RESULT result = handler.Handle( request );
186
187 BOOST_REQUIRE_MESSAGE( result.has_value(),
188 "RefillZones returned status " << result.error().status() << ": "
189 << result.error().error_message() );
190 BOOST_CHECK_EQUAL( result->status().status(), kiapi::common::ApiStatusCode::AS_OK );
191
192 // With no frame the empty-zones request must fill everything synchronously
193 for( ZONE* zone : board->Zones() )
194 BOOST_CHECK_MESSAGE( zone->IsFilled(), "zone " << zone->m_Uuid.AsStdString() << " not filled" );
195}
196
197
198BOOST_AUTO_TEST_CASE( RefillZonesUnknownIdRejected )
199{
200 BOARD* board = loadBoard( wxS( "issue5830" ) );
201
202 API_HANDLER_PCB handler( m_context );
203 kiapi::common::ApiRequest request =
204 makeRefillRequest( board, { wxS( "deadbeef-0000-0000-0000-000000000000" ) } );
205 API_RESULT result = handler.Handle( request );
206
207 BOOST_REQUIRE( !result.has_value() );
208 BOOST_CHECK_EQUAL( result.error().status(), kiapi::common::ApiStatusCode::AS_BAD_REQUEST );
209}
210
211
tl::expected< ApiResponse, ApiResponseStatus > API_RESULT
Definition api_handler.h:42
API_RESULT Handle(ApiRequest &aMsg)
Attempt to handle the given API request, if a handler exists in this class for the message.
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:373
const ZONES & Zones() const
Definition board.h:425
const wxString & GetFileName() const
Definition board.h:410
Handle a list of polygons defining a copper zone.
Definition zone.h:70
bool IsFilled() const
Definition zone.h:306
void LoadBoard(SETTINGS_MANAGER &aSettingsManager, const wxString &aRelPath, std::unique_ptr< BOARD > &aBoard)
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_AUTO_TEST_CASE(RefillZonesSubset)
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")
wxString result
Test unit parsing edge cases and error handling.
BOOST_CHECK_EQUAL(result, "25.4")