KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_geda_pcb_import.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
23
25
26#include <board.h>
27#include <footprint.h>
28#include <pad.h>
29#include <pcb_track.h>
30#include <netinfo.h>
31#include <zone.h>
32
33
40
41
42BOOST_FIXTURE_TEST_SUITE( GedaPcbImport, GEDA_PCB_IMPORT_FIXTURE )
43
44
45BOOST_AUTO_TEST_CASE( CanReadBoard )
46{
47 std::string goodPath = KI_TEST::GetPcbnewTestDataDir() + "/io/geda/minimal_test.pcb";
48 BOOST_CHECK( m_plugin.CanReadBoard( goodPath ) );
49}
50
51
52BOOST_AUTO_TEST_CASE( MinimalBoardLoad )
53{
54 std::string dataPath = KI_TEST::GetPcbnewTestDataDir() + "/io/geda/minimal_test.pcb";
55
56 std::unique_ptr<BOARD> board( m_plugin.LoadBoard( dataPath, nullptr ) );
57
58 BOOST_REQUIRE( board );
59
60 // The minimal test board has 2 elements (R1, C1)
61 BOOST_CHECK_EQUAL( board->Footprints().size(), 2 );
62
63 // Check that reference designators were imported
64 bool foundR1 = false;
65 bool foundC1 = false;
66
67 for( FOOTPRINT* fp : board->Footprints() )
68 {
69 if( fp->GetReference() == wxT( "R1" ) )
70 foundR1 = true;
71
72 if( fp->GetReference() == wxT( "C1" ) )
73 foundC1 = true;
74 }
75
76 BOOST_CHECK_MESSAGE( foundR1, "R1 footprint not found" );
77 BOOST_CHECK_MESSAGE( foundC1, "C1 footprint not found" );
78}
79
80
81BOOST_AUTO_TEST_CASE( MinimalBoardPads )
82{
83 std::string dataPath = KI_TEST::GetPcbnewTestDataDir() + "/io/geda/minimal_test.pcb";
84
85 std::unique_ptr<BOARD> board( m_plugin.LoadBoard( dataPath, nullptr ) );
86
87 BOOST_REQUIRE( board );
88
89 // Both R1 and C1 should have 2 pads each
90 for( FOOTPRINT* fp : board->Footprints() )
91 {
92 BOOST_CHECK_MESSAGE( fp->Pads().size() == 2,
93 wxString::Format( "%s should have 2 pads, has %zu",
94 fp->GetReference(),
95 fp->Pads().size() ) );
96 }
97}
98
99
100BOOST_AUTO_TEST_CASE( MinimalBoardNetlist )
101{
102 std::string dataPath = KI_TEST::GetPcbnewTestDataDir() + "/io/geda/minimal_test.pcb";
103
104 std::unique_ptr<BOARD> board( m_plugin.LoadBoard( dataPath, nullptr ) );
105
106 BOOST_REQUIRE( board );
107
108 // The minimal test board defines nets in a NetList section.
109 // Verify that at least some nets were imported.
110 BOOST_CHECK( board->GetNetCount() > 1 );
111}
112
113
114BOOST_AUTO_TEST_CASE( MinimalBoardTracks )
115{
116 std::string dataPath = KI_TEST::GetPcbnewTestDataDir() + "/io/geda/minimal_test.pcb";
117
118 std::unique_ptr<BOARD> board( m_plugin.LoadBoard( dataPath, nullptr ) );
119
120 BOOST_REQUIRE( board );
121
122 // The minimal test has traces on the copper layer
123 BOOST_CHECK( board->Tracks().size() > 0 );
124}
125
126
127BOOST_AUTO_TEST_CASE( MinimalBoardVias )
128{
129 std::string dataPath = KI_TEST::GetPcbnewTestDataDir() + "/io/geda/minimal_test.pcb";
130
131 std::unique_ptr<BOARD> board( m_plugin.LoadBoard( dataPath, nullptr ) );
132
133 BOOST_REQUIRE( board );
134
135 // Count vias among the tracks
136 int viaCount = 0;
137
138 for( PCB_TRACK* track : board->Tracks() )
139 {
140 if( track->Type() == PCB_VIA_T )
141 viaCount++;
142 }
143
144 BOOST_CHECK( viaCount > 0 );
145}
146
147
148BOOST_AUTO_TEST_CASE( MinimalBoardCopperLayers )
149{
150 std::string dataPath = KI_TEST::GetPcbnewTestDataDir() + "/io/geda/minimal_test.pcb";
151
152 std::unique_ptr<BOARD> board( m_plugin.LoadBoard( dataPath, nullptr ) );
153
154 BOOST_REQUIRE( board );
155
156 // Should have at least 2 copper layers
157 BOOST_CHECK( board->GetCopperLayerCount() >= 2 );
158}
159
160
161BOOST_AUTO_TEST_CASE( CachedLibraryFootprints )
162{
163 std::string dataPath = KI_TEST::GetPcbnewTestDataDir() + "/io/geda/minimal_test.pcb";
164
165 std::unique_ptr<BOARD> board( m_plugin.LoadBoard( dataPath, nullptr ) );
166
167 BOOST_REQUIRE( board );
168
169 std::vector<FOOTPRINT*> cached = m_plugin.GetImportedCachedLibraryFootprints();
170 BOOST_CHECK_EQUAL( cached.size(), board->Footprints().size() );
171
172 for( FOOTPRINT* fp : cached )
173 delete fp;
174}
175
176
177BOOST_AUTO_TEST_CASE( RealWorldBoardLoad )
178{
179 // Test with a real-world gEDA board file
180 std::string dataPath = KI_TEST::GetPcbnewTestDataDir() + "/io/geda/powermeter.pcb";
181
182 std::unique_ptr<BOARD> board( m_plugin.LoadBoard( dataPath, nullptr ) );
183
184 BOOST_REQUIRE( board );
185 BOOST_CHECK( board->Footprints().size() > 0 );
186 BOOST_CHECK( board->Tracks().size() > 0 );
187}
188
189
190// ============================================================================
191// File discrimination tests
192// ============================================================================
193
194BOOST_AUTO_TEST_CASE( RejectsNonGedaPcbFile )
195{
196 std::string badPath = KI_TEST::GetPcbnewTestDataDir() + "/io/geda/non_geda.pcb";
197 BOOST_CHECK( !m_plugin.CanReadBoard( badPath ) );
198}
199
200
201BOOST_AUTO_TEST_CASE( RejectsNonPcbExtension )
202{
203 std::string txtPath = KI_TEST::GetPcbnewTestDataDir() + "/io/geda/minimal_test.pcb";
204 wxFileName fn( txtPath );
205 fn.SetExt( wxT( "txt" ) );
206 BOOST_CHECK( !m_plugin.CanReadBoard( fn.GetFullPath() ) );
207}
208
209
210// ============================================================================
211// Element onsolder flag (bottom-side components)
212// ============================================================================
213
214BOOST_AUTO_TEST_CASE( OnsolderElementFlippedToBack )
215{
216 std::string dataPath = KI_TEST::GetPcbnewTestDataDir() + "/io/geda/onsolder_test.pcb";
217
218 std::unique_ptr<BOARD> board( m_plugin.LoadBoard( dataPath, nullptr ) );
219
220 BOOST_REQUIRE( board );
221 BOOST_CHECK_EQUAL( board->Footprints().size(), 2 );
222
223 FOOTPRINT* r1 = nullptr;
224 FOOTPRINT* c1 = nullptr;
225
226 for( FOOTPRINT* fp : board->Footprints() )
227 {
228 if( fp->GetReference() == wxT( "R1" ) )
229 r1 = fp;
230 else if( fp->GetReference() == wxT( "C1" ) )
231 c1 = fp;
232 }
233
234 BOOST_REQUIRE_MESSAGE( r1, "R1 footprint not found" );
235 BOOST_REQUIRE_MESSAGE( c1, "C1 footprint not found" );
236
237 // R1 has no onsolder flag, should be on front
238 BOOST_CHECK_MESSAGE( !r1->IsFlipped(), "R1 should be on the front side" );
239
240 // C1 has onsolder flag, should be flipped to back
241 BOOST_CHECK_MESSAGE( c1->IsFlipped(), "C1 (onsolder) should be flipped to the back side" );
242}
243
244
245// ============================================================================
246// Multi-layer board with through-hole components
247// ============================================================================
248
249BOOST_AUTO_TEST_CASE( MultilayerBoardCopperCount )
250{
251 std::string dataPath = KI_TEST::GetPcbnewTestDataDir() + "/io/geda/multilayer_test.pcb";
252
253 std::unique_ptr<BOARD> board( m_plugin.LoadBoard( dataPath, nullptr ) );
254
255 BOOST_REQUIRE( board );
256
257 // Groups("1,c:2,s:3:4") defines 4 copper layers
258 BOOST_CHECK_EQUAL( board->GetCopperLayerCount(), 4 );
259}
260
261
262BOOST_AUTO_TEST_CASE( MultilayerBoardThroughHolePins )
263{
264 std::string dataPath = KI_TEST::GetPcbnewTestDataDir() + "/io/geda/multilayer_test.pcb";
265
266 std::unique_ptr<BOARD> board( m_plugin.LoadBoard( dataPath, nullptr ) );
267
268 BOOST_REQUIRE( board );
269
270 for( FOOTPRINT* fp : board->Footprints() )
271 {
272 if( fp->GetReference() != wxT( "U1" ) )
273 continue;
274
275 BOOST_CHECK_EQUAL( fp->Pads().size(), 8 );
276
277 for( PAD* pad : fp->Pads() )
278 {
279 BOOST_CHECK_MESSAGE( pad->GetAttribute() == PAD_ATTRIB::PTH,
280 "DIP8 pad " + pad->GetNumber() + " should be PTH" );
281 }
282
283 return;
284 }
285
286 BOOST_FAIL( "U1 footprint not found" );
287}
288
289
290BOOST_AUTO_TEST_CASE( MultilayerBoardNetAssignment )
291{
292 std::string dataPath = KI_TEST::GetPcbnewTestDataDir() + "/io/geda/multilayer_test.pcb";
293
294 std::unique_ptr<BOARD> board( m_plugin.LoadBoard( dataPath, nullptr ) );
295
296 BOOST_REQUIRE( board );
297
298 bool foundGND = false;
299 bool foundVCC = false;
300
301 for( int i = 0; i < board->GetNetCount(); i++ )
302 {
303 NETINFO_ITEM* net = board->GetNetInfo().GetNetItem( i );
304
305 if( !net )
306 continue;
307
308 if( net->GetNetname() == wxT( "GND" ) )
309 foundGND = true;
310
311 if( net->GetNetname() == wxT( "VCC" ) )
312 foundVCC = true;
313 }
314
315 BOOST_CHECK_MESSAGE( foundGND, "Net GND not found" );
316 BOOST_CHECK_MESSAGE( foundVCC, "Net VCC not found" );
317}
318
319
320BOOST_AUTO_TEST_CASE( MultilayerBoardVias )
321{
322 std::string dataPath = KI_TEST::GetPcbnewTestDataDir() + "/io/geda/multilayer_test.pcb";
323
324 std::unique_ptr<BOARD> board( m_plugin.LoadBoard( dataPath, nullptr ) );
325
326 BOOST_REQUIRE( board );
327
328 int viaCount = 0;
329 int trackCount = 0;
330
331 for( PCB_TRACK* track : board->Tracks() )
332 {
333 if( track->Type() == PCB_VIA_T )
334 viaCount++;
335 else
336 trackCount++;
337 }
338
339 BOOST_CHECK_EQUAL( viaCount, 1 );
340 BOOST_CHECK_EQUAL( trackCount, 4 );
341}
342
343
344// ============================================================================
345// Real-world boards
346// ============================================================================
347
348BOOST_AUTO_TEST_CASE( GoodfetBoardLoad )
349{
350 std::string dataPath = KI_TEST::GetPcbnewTestDataDir() + "/io/geda/goodfet50.pcb";
351
352 std::unique_ptr<BOARD> board( m_plugin.LoadBoard( dataPath, nullptr ) );
353
354 BOOST_REQUIRE( board );
355 BOOST_CHECK( board->Footprints().size() > 5 );
356 BOOST_CHECK( board->Tracks().size() > 10 );
357}
358
359
360BOOST_AUTO_TEST_CASE( Scsi2sdBoardLoad )
361{
362 std::string dataPath = KI_TEST::GetPcbnewTestDataDir() + "/io/geda/scsi2sd.pcb";
363
364 std::unique_ptr<BOARD> board( m_plugin.LoadBoard( dataPath, nullptr ) );
365
366 BOOST_REQUIRE( board );
367 BOOST_CHECK( board->Footprints().size() > 10 );
368 BOOST_CHECK( board->Tracks().size() > 50 );
369}
370
371
General utilities for PCB file IO for QA programs.
bool IsFlipped() const
Definition footprint.h:614
Handle the data for a net.
Definition netinfo.h:46
const wxString & GetNetname() const
Definition netinfo.h:100
Definition pad.h:61
A #PLUGIN derivation for saving and loading Geda PCB files.
Definition pcb_io_geda.h:59
std::string GetPcbnewTestDataDir()
Utility which returns a path to the data directory where the test board files are stored.
@ PTH
Plated through hole pad.
Definition padstack.h:98
Geda PCB file plugin definition file.
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_AUTO_TEST_CASE(CanReadBoard)
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")
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition typeinfo.h:90