KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_backdrill_properties.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
25
26#include <padstack.h>
27#include <layer_ids.h>
28#include <base_units.h>
29
30// Regression tests for GitLab #23901. A backdrill's side is identified by its start layer
31// (F_Cu = top, B_Cu = bottom), not by which drill slot it occupies. The accessors must read both
32// the current layout and the one written by KiCad 10.0 (top backdrill in the tertiary slot), and
33// must write start layers that older KiCad reads back correctly.
34BOOST_AUTO_TEST_SUITE( BackdrillProperties )
35
36
37// Top backdrill -> secondary drill, start F_Cu.
38BOOST_AUTO_TEST_CASE( TopBackdrillUsesSecondaryDrill )
39{
40 PADSTACK stack( nullptr );
41 stack.Drill().size = { pcbIUScale.mmToIU( 0.4 ), pcbIUScale.mmToIU( 0.4 ) };
42
44 stack.SetBackdrillSize( true, pcbIUScale.mmToIU( 0.7 ) );
45 stack.SetBackdrillEndLayer( true, In1_Cu );
46
47 BOOST_CHECK( stack.SecondaryDrill().size.x > 0 );
51
52 BOOST_CHECK( stack.GetBackdrillMode() == BACKDRILL_MODE::BACKDRILL_TOP );
53 BOOST_CHECK_EQUAL( stack.GetBackdrillSize( true ).value_or( 0 ), pcbIUScale.mmToIU( 0.7 ) );
55}
56
57
58// Bottom backdrill -> tertiary drill, start B_Cu.
59BOOST_AUTO_TEST_CASE( BottomBackdrillUsesTertiaryDrill )
60{
61 PADSTACK stack( nullptr );
62 stack.Drill().size = { pcbIUScale.mmToIU( 0.4 ), pcbIUScale.mmToIU( 0.4 ) };
63
65 stack.SetBackdrillSize( false, pcbIUScale.mmToIU( 0.7 ) );
66 stack.SetBackdrillEndLayer( false, In2_Cu );
67
68 BOOST_CHECK( stack.TertiaryDrill().size.x > 0 );
72
73 BOOST_CHECK( stack.GetBackdrillMode() == BACKDRILL_MODE::BACKDRILL_BOTTOM );
74 BOOST_CHECK_EQUAL( stack.GetBackdrillSize( false ).value_or( 0 ), pcbIUScale.mmToIU( 0.7 ) );
76}
77
78
79// Getters must read dialog-written slots back unchanged (no swap).
80BOOST_AUTO_TEST_CASE( DialogToPanelRoundTrip )
81{
82 PADSTACK stack( nullptr );
83
84 // What the dialog writes for a top + bottom backdrill.
85 PADSTACK::DRILL_PROPS& secondary = stack.SecondaryDrill();
86 secondary.size = { pcbIUScale.mmToIU( 0.9 ), pcbIUScale.mmToIU( 0.9 ) };
87 secondary.start = F_Cu;
88 secondary.end = In1_Cu;
90
91 PADSTACK::DRILL_PROPS& tertiary = stack.TertiaryDrill();
92 tertiary.size = { pcbIUScale.mmToIU( 0.7 ), pcbIUScale.mmToIU( 0.7 ) };
93 tertiary.start = B_Cu;
94 tertiary.end = In2_Cu;
96
97 BOOST_CHECK( stack.GetBackdrillMode() == BACKDRILL_MODE::BACKDRILL_BOTH );
98
99 BOOST_CHECK_EQUAL( stack.GetBackdrillSize( true ).value_or( 0 ), pcbIUScale.mmToIU( 0.9 ) );
101
102 BOOST_CHECK_EQUAL( stack.GetBackdrillSize( false ).value_or( 0 ), pcbIUScale.mmToIU( 0.7 ) );
104}
105
106
107// Re-editing a size must not jump slots or zero out.
108BOOST_AUTO_TEST_CASE( EditingSizePreservesSlotAndValue )
109{
110 PADSTACK stack( nullptr );
111 stack.Drill().size = { pcbIUScale.mmToIU( 0.4 ), pcbIUScale.mmToIU( 0.4 ) };
112
114 stack.SetBackdrillSize( false, pcbIUScale.mmToIU( 0.7 ) );
115 stack.SetBackdrillEndLayer( false, In2_Cu );
116
117 stack.SetBackdrillSize( false, pcbIUScale.mmToIU( 0.8 ) );
118
119 BOOST_CHECK( stack.GetBackdrillMode() == BACKDRILL_MODE::BACKDRILL_BOTTOM );
120 BOOST_CHECK_EQUAL( stack.GetBackdrillSize( false ).value_or( 0 ), pcbIUScale.mmToIU( 0.8 ) );
123}
124
125
126// NO_BACKDRILL clears both slots.
127BOOST_AUTO_TEST_CASE( ClearingModeRemovesBackdrill )
128{
129 PADSTACK stack( nullptr );
130 stack.Drill().size = { pcbIUScale.mmToIU( 0.4 ), pcbIUScale.mmToIU( 0.4 ) };
131
133 stack.SetBackdrillSize( true, pcbIUScale.mmToIU( 0.7 ) );
134
136
137 BOOST_CHECK( stack.GetBackdrillMode() == BACKDRILL_MODE::NO_BACKDRILL );
140}
141
142
143// Seed a padstack the way KiCad 10.0 wrote it: top backdrill in the tertiary slot (start F_Cu),
144// bottom backdrill in the secondary slot (start B_Cu). The accessors must read each side from the
145// slot carrying the matching start layer, not from a fixed slot position.
146BOOST_AUTO_TEST_CASE( ReadsLegacyV10SlotLayout )
147{
148 PADSTACK stack( nullptr );
149
150 PADSTACK::DRILL_PROPS& secondary = stack.SecondaryDrill();
151 secondary.size = { pcbIUScale.mmToIU( 0.8 ), pcbIUScale.mmToIU( 0.8 ) };
152 secondary.start = B_Cu;
153 secondary.end = In2_Cu;
154 secondary.shape = PAD_DRILL_SHAPE::CIRCLE;
155
156 PADSTACK::DRILL_PROPS& tertiary = stack.TertiaryDrill();
157 tertiary.size = { pcbIUScale.mmToIU( 0.6 ), pcbIUScale.mmToIU( 0.6 ) };
158 tertiary.start = F_Cu;
159 tertiary.end = In1_Cu;
161
162 BOOST_CHECK( stack.GetBackdrillMode() == BACKDRILL_MODE::BACKDRILL_BOTH );
163
164 BOOST_CHECK_EQUAL( stack.GetBackdrillSize( true ).value_or( 0 ), pcbIUScale.mmToIU( 0.6 ) );
166
167 BOOST_CHECK_EQUAL( stack.GetBackdrillSize( false ).value_or( 0 ), pcbIUScale.mmToIU( 0.8 ) );
169}
170
171
172// A 10.0 top-only backdrill lives in the tertiary slot; it must read as a top backdrill, not a
173// bottom one (the slot-position reading regressed exactly this case).
174BOOST_AUTO_TEST_CASE( ReadsLegacyV10TopOnly )
175{
176 PADSTACK stack( nullptr );
177
178 PADSTACK::DRILL_PROPS& tertiary = stack.TertiaryDrill();
179 tertiary.size = { pcbIUScale.mmToIU( 0.6 ), pcbIUScale.mmToIU( 0.6 ) };
180 tertiary.start = F_Cu;
181 tertiary.end = In1_Cu;
183
184 BOOST_CHECK( stack.GetBackdrillMode() == BACKDRILL_MODE::BACKDRILL_TOP );
185 BOOST_CHECK_EQUAL( stack.GetBackdrillSize( true ).value_or( 0 ), pcbIUScale.mmToIU( 0.6 ) );
187 BOOST_CHECK( !stack.GetBackdrillSize( false ).has_value() );
188}
189
190
191// Editing a 10.0 top-only backdrill must update it in place (in the tertiary slot it already
192// occupies) and keep the F_Cu start layer, so the result stays readable by older KiCad and no
193// duplicate top backdrill appears in the secondary slot.
194BOOST_AUTO_TEST_CASE( EditingLegacyBackdrillStaysInPlaceAndReadable )
195{
196 PADSTACK stack( nullptr );
197
198 PADSTACK::DRILL_PROPS& tertiary = stack.TertiaryDrill();
199 tertiary.size = { pcbIUScale.mmToIU( 0.6 ), pcbIUScale.mmToIU( 0.6 ) };
200 tertiary.start = F_Cu;
201 tertiary.end = In1_Cu;
203
204 stack.SetBackdrillSize( true, pcbIUScale.mmToIU( 0.75 ) );
205
206 BOOST_CHECK_EQUAL( stack.TertiaryDrill().size.x, pcbIUScale.mmToIU( 0.75 ) );
209
210 BOOST_CHECK( stack.GetBackdrillMode() == BACKDRILL_MODE::BACKDRILL_TOP );
211 BOOST_CHECK_EQUAL( stack.GetBackdrillSize( true ).value_or( 0 ), pcbIUScale.mmToIU( 0.75 ) );
212}
213
214
215// Clearing the must-cut layer removes the backdrill: a sized drill with no must-cut does not
216// exist (the via layer sanitizer enforces the same rule).
217BOOST_AUTO_TEST_CASE( ClearingMustCutRemovesBackdrill )
218{
219 PADSTACK stack( nullptr );
220 stack.Drill().size = { pcbIUScale.mmToIU( 0.4 ), pcbIUScale.mmToIU( 0.4 ) };
221
223 stack.SetBackdrillSize( true, pcbIUScale.mmToIU( 0.7 ) );
224 stack.SetBackdrillEndLayer( true, In1_Cu );
225
227
228 BOOST_CHECK( stack.GetBackdrillMode() == BACKDRILL_MODE::NO_BACKDRILL );
229 BOOST_CHECK( !stack.GetBackdrillSize( true ).has_value() );
231}
232
233
234// A malformed padstack with the same side duplicated across both slots must be fully cleared, not
235// left with a surviving duplicate that re-asserts the backdrill.
236BOOST_AUTO_TEST_CASE( ClearingCollapsesDuplicateSideSlots )
237{
238 PADSTACK stack( nullptr );
239
240 PADSTACK::DRILL_PROPS& secondary = stack.SecondaryDrill();
241 secondary.size = { pcbIUScale.mmToIU( 0.7 ), pcbIUScale.mmToIU( 0.7 ) };
242 secondary.start = F_Cu;
243 secondary.end = In1_Cu;
244 secondary.shape = PAD_DRILL_SHAPE::CIRCLE;
245
246 PADSTACK::DRILL_PROPS& tertiary = stack.TertiaryDrill();
247 tertiary.size = { pcbIUScale.mmToIU( 0.6 ), pcbIUScale.mmToIU( 0.6 ) };
248 tertiary.start = F_Cu;
249 tertiary.end = In1_Cu;
251
252 stack.SetBackdrillSize( true, std::nullopt );
253
256 BOOST_CHECK( stack.GetBackdrillMode() == BACKDRILL_MODE::NO_BACKDRILL );
257}
258
259
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:121
A PADSTACK defines the characteristics of a single or multi-layer pad, in the IPC sense of the word.
Definition padstack.h:157
void SetBackdrillMode(BACKDRILL_MODE aMode)
Definition padstack.cpp:539
void SetBackdrillSize(bool aTop, std::optional< int > aSize)
Definition padstack.cpp:572
DRILL_PROPS & TertiaryDrill()
Definition padstack.h:357
DRILL_PROPS & Drill()
Definition padstack.h:351
void SetBackdrillEndLayer(bool aTop, PCB_LAYER_ID aLayer)
Definition padstack.cpp:597
std::optional< int > GetBackdrillSize(bool aTop) const
Definition padstack.cpp:563
BACKDRILL_MODE GetBackdrillMode() const
Definition padstack.cpp:521
DRILL_PROPS & SecondaryDrill()
Definition padstack.h:354
PCB_LAYER_ID GetBackdrillEndLayer(bool aTop) const
Definition padstack.cpp:588
@ B_Cu
Definition layer_ids.h:61
@ In2_Cu
Definition layer_ids.h:63
@ UNDEFINED_LAYER
Definition layer_ids.h:57
@ In1_Cu
Definition layer_ids.h:62
@ F_Cu
Definition layer_ids.h:60
! The properties of a padstack drill. Drill position is always the pad position (origin).
Definition padstack.h:266
PCB_LAYER_ID start
Definition padstack.h:269
PCB_LAYER_ID end
Definition padstack.h:270
VECTOR2I size
Drill diameter (x == y) or slot dimensions (x != y)
Definition padstack.h:267
PAD_DRILL_SHAPE shape
Definition padstack.h:268
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_AUTO_TEST_CASE(TopBackdrillUsesSecondaryDrill)
BOOST_AUTO_TEST_SUITE(CadstarPartParser)
BOOST_AUTO_TEST_SUITE_END()
BOOST_CHECK_EQUAL(result, "25.4")