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