KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_autotrax_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 (C) 2026 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
30
34
36
37#include <board.h>
38#include <footprint.h>
39#include <pad.h>
40#include <pcb_track.h>
41#include <pcb_shape.h>
42#include <pcb_text.h>
43
44#include <reporter.h>
45
46#include <wx/filename.h>
47
48
50{
52
54
55 std::string path( const std::string& aName )
56 {
57 return KI_TEST::GetPcbnewTestDataDir() + "plugins/autotrax/" + aName;
58 }
59
60 bool haveSample( const std::string& aName ) { return wxFileName::FileExists( path( aName ) ); }
61};
62
63
64BOOST_FIXTURE_TEST_SUITE( AutotraxImport, AUTOTRAX_IMPORT_FIXTURE )
65
66
67
69BOOST_AUTO_TEST_CASE( SniffRecognizesPcb )
70{
71 if( !haveSample( "PRJ.PCB" ) )
72 {
73 BOOST_TEST_MESSAGE( "no real autotrax sample available; load test skipped" );
74 return;
75 }
76
77 BOOST_CHECK( m_plugin.CanReadBoard( path( "PRJ.PCB" ) ) );
78}
79
80
83BOOST_AUTO_TEST_CASE( SimpleBoardStructure )
84{
85 if( !haveSample( "PRJ.PCB" ) )
86 {
87 BOOST_TEST_MESSAGE( "no real autotrax sample available; load test skipped" );
88 return;
89 }
90
91 std::unique_ptr<BOARD> board = std::make_unique<BOARD>();
92
93 BOOST_REQUIRE_NO_THROW( board = m_plugin.LoadBoard( path( "PRJ.PCB" ) ) );
94 BOOST_REQUIRE( board );
95
96 BOOST_CHECK_GT( board->Footprints().size(), 0 );
97
98 int pads = 0;
99
100 for( FOOTPRINT* fp : board->Footprints() )
101 pads += fp->Pads().size();
102
103 BOOST_CHECK_GT( pads, 0 );
104 BOOST_CHECK_GT( board->Tracks().size(), 0 );
105}
106
107
111BOOST_AUTO_TEST_CASE( RichBoardStructure )
112{
113 if( !haveSample( "PRJ12.PCB" ) )
114 {
115 BOOST_TEST_MESSAGE( "no real autotrax sample available; load test skipped" );
116 return;
117 }
118
119 std::unique_ptr<BOARD> board;
120
121 BOOST_REQUIRE_NO_THROW( board = m_plugin.LoadBoard( path( "PRJ12.PCB" ) ) );
122 BOOST_REQUIRE( board );
123
124 int tracks = 0;
125 int vias = 0;
126
127 for( PCB_TRACK* t : board->Tracks() )
128 {
129 if( t->Type() == PCB_VIA_T )
130 vias++;
131 else if( t->Type() == PCB_TRACE_T )
132 tracks++;
133 }
134
135 BOOST_CHECK_GT( tracks, 0 );
136 BOOST_CHECK_GT( vias, 0 );
137 BOOST_CHECK_GT( board->Footprints().size(), 0 );
138
139 int pads = 0;
140
141 for( FOOTPRINT* fp : board->Footprints() )
142 pads += fp->Pads().size();
143
144 BOOST_CHECK_GT( pads, 0 );
145}
146
147
150BOOST_AUTO_TEST_CASE( AllSamplesLoad )
151{
152 const std::vector<std::string> samples = { "PRJ.PCB", "PRJ2.PCB", "PRJ10.PCB", "PRJ12.PCB" };
153
154 bool any = false;
155
156 for( const std::string& name : samples )
157 {
158 if( !haveSample( name ) )
159 continue;
160
161 any = true;
162
163 std::unique_ptr<BOARD> board;
164 BOOST_REQUIRE_NO_THROW( board = m_plugin.LoadBoard( path( name ) ) );
165 BOOST_REQUIRE( board );
166
167 size_t items = board->Tracks().size() + board->Footprints().size() + board->Drawings().size();
168 BOOST_CHECK_GT( items, 0 );
169 }
170
171 if( !any )
172 BOOST_TEST_MESSAGE( "no real autotrax sample available; load test skipped" );
173}
174
175
177BOOST_AUTO_TEST_CASE( NetdefAssignsPadNets )
178{
179 std::unique_ptr<BOARD> board;
180
181 BOOST_REQUIRE_NO_THROW( board = m_plugin.LoadBoard( path( "DEMOSMD.PCB" ) ) );
182 BOOST_REQUIRE( board );
183
184 FOOTPRINT* u5 = board->FindFootprintByReference( wxS( "U5" ) );
185 BOOST_REQUIRE( u5 );
186
187 auto netOf = [&]( const wxString& aNumber ) -> wxString
188 {
189 PAD* pad = u5->FindPadByNumber( aNumber );
191 return pad->GetNetname();
192 };
193
194 BOOST_CHECK_EQUAL( netOf( wxS( "29" ) ), wxS( "GND" ) );
195 BOOST_CHECK_EQUAL( netOf( wxS( "11" ) ), wxS( "VCC" ) );
196 BOOST_CHECK_EQUAL( netOf( wxS( "13" ) ), wxS( "D7" ) );
197}
198
199
201BOOST_AUTO_TEST_CASE( CompHeaderPlacesFields )
202{
203 std::unique_ptr<BOARD> board;
204
205 BOOST_REQUIRE_NO_THROW( board = m_plugin.LoadBoard( path( "DEMOSMD.PCB" ) ) );
206 BOOST_REQUIRE( board );
207
208 FOOTPRINT* r6 = board->FindFootprintByReference( wxS( "R6" ) );
209 BOOST_REQUIRE( r6 );
210
211 BOOST_CHECK_EQUAL( r6->Reference().GetPosition().x, pcbIUScale.MilsToIU( 559 ) );
212 BOOST_CHECK_EQUAL( r6->Value().GetPosition().x, pcbIUScale.MilsToIU( 584 ) );
213 BOOST_CHECK( r6->Reference().IsVisible() );
214 BOOST_CHECK( !r6->Value().IsVisible() );
215}
216
217
219BOOST_AUTO_TEST_CASE( TextRotationAndMirror )
220{
221 auto angleOf = []( const PCB_TEXT& aText )
222 {
223 EDA_ANGLE angle = aText.GetTextAngle();
224 return angle.Normalize().AsDegrees();
225 };
226
227 std::unique_ptr<BOARD> smd;
228 BOOST_REQUIRE_NO_THROW( smd = m_plugin.LoadBoard( path( "DEMOSMD.PCB" ) ) );
229 FOOTPRINT* r6 = smd->FindFootprintByReference( wxS( "R6" ) );
230 BOOST_REQUIRE( r6 );
231
232 BOOST_CHECK_EQUAL( angleOf( r6->Reference() ), 90.0 );
233 BOOST_CHECK( !r6->Reference().IsMirrored() );
234
235 std::unique_ptr<BOARD> prj;
236 BOOST_REQUIRE_NO_THROW( prj = m_plugin.LoadBoard( path( "PRJ12.PCB" ) ) );
237 FOOTPRINT* a32 = prj->FindFootprintByReference( wxS( "A32" ) );
238 BOOST_REQUIRE( a32 );
239
240 BOOST_CHECK_EQUAL( angleOf( a32->Reference() ), 90.0 );
241 BOOST_CHECK( a32->Reference().IsMirrored() );
242 BOOST_CHECK( a32->Reference().GetLayer() == F_SilkS );
243}
244
245
247BOOST_AUTO_TEST_CASE( ArcQuadrantsBulgeIntoPart )
248{
249 std::unique_ptr<BOARD> board;
250
251 BOOST_REQUIRE_NO_THROW( board = m_plugin.LoadBoard( path( "PRJ.PCB" ) ) );
252 FOOTPRINT* u7 = board->FindFootprintByReference( wxS( "U7" ) );
253 BOOST_REQUIRE( u7 );
254
255 PCB_SHAPE* notch = nullptr;
256
257 for( BOARD_ITEM* item : u7->GraphicalItems() )
258 {
259 if( item->Type() == PCB_SHAPE_T && static_cast<PCB_SHAPE*>( item )->GetShape() == SHAPE_T::ARC )
260 notch = static_cast<PCB_SHAPE*>( item );
261 }
262
263 BOOST_REQUIRE( notch );
264 BOOST_CHECK_GT( notch->GetArcMid().x, notch->GetCenter().x );
265}
266
267
269BOOST_AUTO_TEST_CASE( KeepoutBecomesBoardOutline )
270{
271 std::unique_ptr<BOARD> board;
272
273 BOOST_REQUIRE_NO_THROW( board = m_plugin.LoadBoard( path( "DEMOSMD.PCB" ) ) );
274
275 int edges = 0;
276
277 for( BOARD_ITEM* item : board->Drawings() )
278 {
279 if( item->GetLayer() == Edge_Cuts )
280 edges++;
281 }
282
283 BOOST_CHECK_EQUAL( edges, 7 );
284}
285
286
288BOOST_AUTO_TEST_CASE( PlaneConnectionsAreReported )
289{
291 std::unique_ptr<BOARD> board;
292
293 m_plugin.SetReporter( &reporter );
294 BOOST_REQUIRE_NO_THROW( board = m_plugin.LoadBoard( path( "DEMO.PCB" ) ) );
295
296 BOOST_CHECK( reporter.GetMessages().Contains( wxS( "87 pad(s) ask for a ground or power plane" ) ) );
297}
298
299
const char * name
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:128
General utilities for PCB file IO for QA programs.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:84
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
EDA_ANGLE Normalize()
Definition eda_angle.h:228
double AsDegrees() const
Definition eda_angle.h:115
SHAPE_T GetShape() const
Definition eda_shape.h:175
VECTOR2I GetArcMid() const
virtual bool IsVisible() const
Definition eda_text.h:226
bool IsMirrored() const
Definition eda_text.h:229
PCB_FIELD & Value()
read/write accessors:
Definition footprint.h:947
PCB_FIELD & Reference()
Definition footprint.h:948
DRAWINGS & GraphicalItems()
Definition footprint.h:408
PAD * FindPadByNumber(const wxString &aPadNumber, PAD *aSearchAfterMe=nullptr) const
Return a PAD with a matching number.
Definition pad.h:61
Read-only importer for Protel Autotrax (.PCB, "PCB FILE 4") and Easytrax (.PCB, "PCB FILE 5") layout ...
VECTOR2I GetCenter() const override
This defaults to the center of the bounding box if not overridden.
Definition pcb_shape.h:78
VECTOR2I GetPosition() const override
Definition pcb_text.h:100
A wrapper for reporting to a wxString object.
Definition reporter.h:242
A type-safe container of any type.
Definition ki_any.h:92
@ Edge_Cuts
Definition layer_ids.h:108
@ F_SilkS
Definition layer_ids.h:96
std::string GetPcbnewTestDataDir()
Utility which returns a path to the data directory where the test board files are stored.
std::string path(const std::string &aName)
bool haveSample(const std::string &aName)
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_AUTO_TEST_CASE(SniffRecognizesPcb)
CanReadBoard must accept a real Autotrax file by sniffing the magic header, not just the (gEDA-shared...
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_AUTO_TEST_SUITE_END()
std::string path
IbisParser parser & reporter
BOOST_TEST_MESSAGE("Polyline has "<< chain.PointCount()<< " points")
BOOST_CHECK_EQUAL(result, "25.4")
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
Definition typeinfo.h:80
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition typeinfo.h:89
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
Definition typeinfo.h:88