KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_fabmaster_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
24
28
30
31#include <board.h>
32#include <footprint.h>
33#include <pad.h>
34#include <padstack.h>
35#include <zone.h>
36
37
44
45
46BOOST_FIXTURE_TEST_SUITE( FabmasterImport, FABMASTER_IMPORT_FIXTURE )
47
48
49
58BOOST_AUTO_TEST_CASE( EmptyRefdesInPins )
59{
60 std::string dataPath =
61 KI_TEST::GetPcbnewTestDataDir() + "plugins/fabmaster/cds2f_only_2_comp.txt";
62
63 std::unique_ptr<BOARD> board = m_fabmasterPlugin.LoadBoard( dataPath );
64
65 BOOST_REQUIRE( board );
66
67 // The board should have footprints
68 BOOST_REQUIRE_GT( board->Footprints().size(), 0 );
69
70 // Each footprint should have pads (before the fix, pads were missing because
71 // the lookup by empty REFDES failed)
72 int totalPads = 0;
73
74 for( const FOOTPRINT* fp : board->Footprints() )
75 {
76 totalPads += fp->Pads().size();
77 }
78
79 BOOST_CHECK_MESSAGE( totalPads > 0,
80 "Footprints should have pads when REFDES is empty in PIN section" );
81}
82
83
95BOOST_AUTO_TEST_CASE( StaticShapesPreserved )
96{
97 std::string dataPath =
98 KI_TEST::GetPcbnewTestDataDir() + "plugins/fabmaster/cds2f_14066-20316FBRD.txt";
99
100 std::unique_ptr<BOARD> board = m_fabmasterPlugin.LoadBoard( dataPath );
101
102 BOOST_REQUIRE( board );
103
104 // Count zones - static shapes should be preserved as zones with net codes
105 int zonesWithNets = 0;
106
107 for( ZONE* zone : board->Zones() )
108 {
109 if( zone->GetNetCode() > 0 )
110 zonesWithNets++;
111 }
112
113 // The board should have some zones with nets assigned (static shapes).
114 // Before the fix, all netted zones were deleted because they were considered
115 // redundant fills. With the fix, unmatched static shapes are preserved.
116 BOOST_CHECK_MESSAGE( zonesWithNets > 0,
117 "Static shape zones with nets should be preserved" );
118}
119
120
124static const PAD* findPadByNumber( const FOOTPRINT* aFp, const wxString& aNumber )
125{
126 for( const PAD* pad : aFp->Pads() )
127 {
128 if( pad->GetNumber() == aNumber )
129 return pad;
130 }
131
132 return nullptr;
133}
134
135
145BOOST_AUTO_TEST_CASE( PadStackDifferentLayers )
146{
147 std::string dataPath =
148 KI_TEST::GetPcbnewTestDataDir() + "plugins/fabmaster/cds2f_padstack_test.txt";
149
150 std::unique_ptr<BOARD> board = m_fabmasterPlugin.LoadBoard( dataPath );
151
152 BOOST_REQUIRE( board );
153 BOOST_REQUIRE_GT( board->Footprints().size(), 0 );
154
155 const FOOTPRINT* fp = board->Footprints().front();
156 BOOST_REQUIRE_EQUAL( fp->Pads().size(), 3 );
157
158 // Pin 1 uses DIFF_PAD which has CIRCLE on TOP and RECTANGLE on BOTTOM.
159 // This should use FRONT_INNER_BACK padstack mode.
160 const PAD* pad1 = findPadByNumber( fp, wxT( "1" ) );
161 BOOST_REQUIRE( pad1 );
162 BOOST_CHECK_EQUAL( static_cast<int>( pad1->Padstack().Mode() ),
163 static_cast<int>( PADSTACK::MODE::FRONT_INNER_BACK ) );
164 BOOST_CHECK_EQUAL( static_cast<int>( pad1->GetShape( F_Cu ) ),
165 static_cast<int>( PAD_SHAPE::CIRCLE ) );
166 BOOST_CHECK_EQUAL( static_cast<int>( pad1->GetShape( B_Cu ) ),
167 static_cast<int>( PAD_SHAPE::RECTANGLE ) );
168
169 // Verify front layer size (2.0mm circle)
170 VECTOR2I pad1_front_size = pad1->GetSize( F_Cu );
171 BOOST_CHECK_GT( pad1_front_size.x, 0 );
172 BOOST_CHECK_EQUAL( pad1_front_size.x, pad1_front_size.y );
173
174 // Verify back layer size (1.5x3.0mm rectangle, height > width)
175 VECTOR2I pad1_back_size = pad1->GetSize( B_Cu );
176 BOOST_CHECK_GT( pad1_back_size.x, 0 );
177 BOOST_CHECK_GT( pad1_back_size.y, pad1_back_size.x );
178
179 // Verify drill is present
180 BOOST_CHECK_EQUAL( static_cast<int>( pad1->GetAttribute() ),
181 static_cast<int>( PAD_ATTRIB::PTH ) );
182 BOOST_CHECK_GT( pad1->GetDrillSizeX(), 0 );
183}
184
185
189BOOST_AUTO_TEST_CASE( PadStackSameLayers )
190{
191 std::string dataPath =
192 KI_TEST::GetPcbnewTestDataDir() + "plugins/fabmaster/cds2f_padstack_test.txt";
193
194 std::unique_ptr<BOARD> board = m_fabmasterPlugin.LoadBoard( dataPath );
195
196 BOOST_REQUIRE( board );
197 BOOST_REQUIRE_GT( board->Footprints().size(), 0 );
198
199 const FOOTPRINT* fp = board->Footprints().front();
200
201 // Pin 2 uses SAME_PAD which has RECTANGLE 1.0x2.0 on both TOP and BOTTOM.
202 // This should stay in NORMAL mode since shapes are identical.
203 const PAD* pad2 = findPadByNumber( fp, wxT( "2" ) );
204 BOOST_REQUIRE( pad2 );
205 BOOST_CHECK_EQUAL( static_cast<int>( pad2->Padstack().Mode() ),
206 static_cast<int>( PADSTACK::MODE::NORMAL ) );
207 BOOST_CHECK_EQUAL( static_cast<int>( pad2->GetShape( F_Cu ) ),
208 static_cast<int>( PAD_SHAPE::RECTANGLE ) );
209}
210
211
215BOOST_AUTO_TEST_CASE( PadStackSmdPad )
216{
217 std::string dataPath =
218 KI_TEST::GetPcbnewTestDataDir() + "plugins/fabmaster/cds2f_padstack_test.txt";
219
220 std::unique_ptr<BOARD> board = m_fabmasterPlugin.LoadBoard( dataPath );
221
222 BOOST_REQUIRE( board );
223 BOOST_REQUIRE_GT( board->Footprints().size(), 0 );
224
225 const FOOTPRINT* fp = board->Footprints().front();
226
227 // Pin 3 uses SMD_DIFF which is an OVAL on TOP only (no BOTTOM pad, no drill).
228 const PAD* pad3 = findPadByNumber( fp, wxT( "3" ) );
229 BOOST_REQUIRE( pad3 );
230 BOOST_CHECK_EQUAL( static_cast<int>( pad3->GetAttribute() ),
231 static_cast<int>( PAD_ATTRIB::SMD ) );
232 BOOST_CHECK_EQUAL( static_cast<int>( pad3->GetShape( F_Cu ) ),
233 static_cast<int>( PAD_SHAPE::OVAL ) );
234}
235
236
253BOOST_AUTO_TEST_CASE( AreaClassesImportedAsRuleAreas )
254{
255 std::string dataPath =
256 KI_TEST::GetPcbnewTestDataDir() + "plugins/fabmaster/cds2f_issue7732_shape_pads2.txt";
257
258 std::unique_ptr<BOARD> board = m_fabmasterPlugin.LoadBoard( dataPath );
259
260 BOOST_REQUIRE( board );
261
262 int routeKeepouts = 0;
263 int viaKeepouts = 0;
264 int footprintKeepouts = 0;
265 int markerAreas = 0;
266
267 for( ZONE* zone : board->Zones() )
268 {
269 if( !zone->GetIsRuleArea() )
270 continue;
271
272 if( zone->GetDoNotAllowFootprints() && !zone->GetDoNotAllowTracks()
273 && !zone->GetDoNotAllowVias() )
274 {
275 footprintKeepouts++;
276 }
277 else if( zone->GetDoNotAllowTracks() && zone->GetDoNotAllowVias()
278 && zone->GetDoNotAllowPads() && zone->GetDoNotAllowZoneFills() )
279 {
280 routeKeepouts++;
281 }
282 else if( zone->GetDoNotAllowVias() && !zone->GetDoNotAllowTracks()
283 && !zone->GetDoNotAllowFootprints() )
284 {
285 viaKeepouts++;
286 }
287 else if( !zone->GetDoNotAllowTracks() && !zone->GetDoNotAllowVias()
288 && !zone->GetDoNotAllowPads() && !zone->GetDoNotAllowFootprints()
289 && !zone->GetDoNotAllowZoneFills() )
290 {
291 markerAreas++;
292 }
293 }
294
295 BOOST_CHECK_EQUAL( routeKeepouts, 5 );
296 BOOST_CHECK_EQUAL( viaKeepouts, 5 );
297 BOOST_CHECK_EQUAL( footprintKeepouts, 3 );
298
299 // 1 route keepin + 1 package keepin + 8 constraint regions
300 BOOST_CHECK_EQUAL( markerAreas, 10 );
301}
302
303
General utilities for PCB file IO for QA programs.
std::deque< PAD * > & Pads()
Definition footprint.h:404
@ NORMAL
Shape is the same on all layers.
Definition padstack.h:170
@ FRONT_INNER_BACK
Up to three shapes can be defined (F_Cu, inner copper layers, B_Cu)
Definition padstack.h:171
MODE Mode() const
Definition padstack.h:344
Definition pad.h:61
PAD_ATTRIB GetAttribute() const
Definition pad.h:558
int GetDrillSizeX() const
Definition pad.h:320
PAD_SHAPE GetShape(PCB_LAYER_ID aLayer) const
Definition pad.h:205
VECTOR2I GetSize(PCB_LAYER_ID aLayer) const
Definition pad.cpp:288
const PADSTACK & Padstack() const
Definition pad.h:329
Handle a list of polygons defining a copper zone.
Definition zone.h:70
@ B_Cu
Definition layer_ids.h:61
@ F_Cu
Definition layer_ids.h:60
std::string GetPcbnewTestDataDir()
Utility which returns a path to the data directory where the test board files are stored.
@ SMD
Smd pad, appears on the solder paste layer (default)
Definition padstack.h:98
@ PTH
Plated through hole pad.
Definition padstack.h:97
@ RECTANGLE
Definition padstack.h:53
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
static const PAD * findPadByNumber(const FOOTPRINT *aFp, const wxString &aNumber)
Helper to find a pad by its number within a footprint.
BOOST_AUTO_TEST_CASE(EmptyRefdesInPins)
Test that footprints with pads are properly imported when the REFDES column is empty in the PIN secti...
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_AUTO_TEST_SUITE_END()
BOOST_CHECK_EQUAL(result, "25.4")
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683