KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_via_validation.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
21#include <base_units.h>
22#include <pcb_track.h>
23
25
26
27BOOST_AUTO_TEST_SUITE( ViaValidation )
28
29
30// A well-formed via with drill smaller than diameter must validate clean.
31BOOST_AUTO_TEST_CASE( WellFormedViaPasses )
32{
33 auto error = PCB_VIA::ValidateViaParameters( pcbIUScale.mmToIU( 0.8 ), pcbIUScale.mmToIU( 0.4 ), F_Cu, B_Cu );
34
35 BOOST_CHECK( !error.has_value() );
36
37 // Still clean when the endpoints are checked against a real two-layer stack.
38 auto inStack = PCB_VIA::ValidateViaParameters( pcbIUScale.mmToIU( 0.8 ), pcbIUScale.mmToIU( 0.4 ), F_Cu, B_Cu,
39 std::nullopt, std::nullopt, std::nullopt, std::nullopt,
40 std::nullopt, std::nullopt, 2 );
41
42 BOOST_CHECK( !inStack.has_value() );
43}
44
45
46// Drill equal to or larger than the diameter leaves no annular ring and must be
47// flagged against the drill field.
48BOOST_AUTO_TEST_CASE( DrillNotSmallerThanDiameterFails )
49{
50 auto error = PCB_VIA::ValidateViaParameters( pcbIUScale.mmToIU( 0.4 ), pcbIUScale.mmToIU( 0.4 ), F_Cu, B_Cu );
51
52 BOOST_REQUIRE( error.has_value() );
53 BOOST_CHECK( error->m_Field == FIELD::DRILL );
54
55 auto oversized = PCB_VIA::ValidateViaParameters( pcbIUScale.mmToIU( 0.4 ), pcbIUScale.mmToIU( 0.6 ), F_Cu, B_Cu );
56
57 BOOST_REQUIRE( oversized.has_value() );
58 BOOST_CHECK( oversized->m_Field == FIELD::DRILL );
59}
60
61
62// Sub-minimum geometry is rejected on the offending field.
63BOOST_AUTO_TEST_CASE( TooSmallGeometryFails )
64{
65 auto tinyDiameter = PCB_VIA::ValidateViaParameters( GEOMETRY_MIN_SIZE - 1, std::nullopt, F_Cu, B_Cu );
66
67 BOOST_REQUIRE( tinyDiameter.has_value() );
68 BOOST_CHECK( tinyDiameter->m_Field == FIELD::DIAMETER );
69
70 auto tinyDrill = PCB_VIA::ValidateViaParameters( pcbIUScale.mmToIU( 0.8 ), GEOMETRY_MIN_SIZE - 1, F_Cu, B_Cu );
71
72 BOOST_REQUIRE( tinyDrill.has_value() );
73 BOOST_CHECK( tinyDrill->m_Field == FIELD::DRILL );
74}
75
76
77// Diameter and drill must be defined together.
78BOOST_AUTO_TEST_CASE( PartialSizeSpecificationFails )
79{
80 auto noDrill = PCB_VIA::ValidateViaParameters( pcbIUScale.mmToIU( 0.8 ), std::nullopt, F_Cu, B_Cu );
81
82 BOOST_REQUIRE( noDrill.has_value() );
83 BOOST_CHECK( noDrill->m_Field == FIELD::DRILL );
84
85 auto noDiameter = PCB_VIA::ValidateViaParameters( std::nullopt, pcbIUScale.mmToIU( 0.4 ), F_Cu, B_Cu );
86
87 BOOST_REQUIRE( noDiameter.has_value() );
88 BOOST_CHECK( noDiameter->m_Field == FIELD::DIAMETER );
89}
90
91
92// A via cannot start and end on the same layer.
93BOOST_AUTO_TEST_CASE( CoincidentLayersFail )
94{
95 auto error = PCB_VIA::ValidateViaParameters( pcbIUScale.mmToIU( 0.8 ), pcbIUScale.mmToIU( 0.4 ), F_Cu, F_Cu );
96
97 BOOST_REQUIRE( error.has_value() );
98 BOOST_CHECK( error->m_Field == FIELD::START_LAYER );
99}
100
101
102// Non-copper endpoints and endpoints outside the board stack are rejected.
103BOOST_AUTO_TEST_CASE( InvalidLayersFail )
104{
105 auto nonCopper = PCB_VIA::ValidateViaParameters( pcbIUScale.mmToIU( 0.8 ), pcbIUScale.mmToIU( 0.4 ), F_Cu,
106 F_SilkS );
107
108 BOOST_REQUIRE( nonCopper.has_value() );
109 BOOST_CHECK( nonCopper->m_Field == FIELD::END_LAYER );
110
111 // In2_Cu exists in the enum but a two-layer board does not contain it.
112 auto offStack = PCB_VIA::ValidateViaParameters( pcbIUScale.mmToIU( 0.8 ), pcbIUScale.mmToIU( 0.4 ), F_Cu, In2_Cu,
113 std::nullopt, std::nullopt, std::nullopt, std::nullopt,
114 std::nullopt, std::nullopt, 2 );
115
116 BOOST_REQUIRE( offStack.has_value() );
117 BOOST_CHECK( offStack->m_Field == FIELD::END_LAYER );
118}
119
120
121// A backdrill must be at least as large as the primary drill; a valid one passes.
122BOOST_AUTO_TEST_CASE( BackdrillSizeIsValidated )
123{
124 auto tooSmall = PCB_VIA::ValidateViaParameters( pcbIUScale.mmToIU( 0.8 ), pcbIUScale.mmToIU( 0.4 ), F_Cu, B_Cu,
125 pcbIUScale.mmToIU( 0.3 ) );
126
127 BOOST_REQUIRE( tooSmall.has_value() );
128 BOOST_CHECK( tooSmall->m_Field == FIELD::SECONDARY_DRILL );
129
130 auto tertiaryTooSmall = PCB_VIA::ValidateViaParameters( pcbIUScale.mmToIU( 0.8 ), pcbIUScale.mmToIU( 0.4 ),
131 F_Cu, B_Cu, std::nullopt, std::nullopt, std::nullopt,
132 pcbIUScale.mmToIU( 0.3 ) );
133
134 BOOST_REQUIRE( tertiaryTooSmall.has_value() );
135 BOOST_CHECK( tertiaryTooSmall->m_Field == FIELD::TERTIARY_DRILL );
136
137 auto valid = PCB_VIA::ValidateViaParameters( pcbIUScale.mmToIU( 0.8 ), pcbIUScale.mmToIU( 0.4 ), F_Cu, B_Cu,
138 pcbIUScale.mmToIU( 0.5 ) );
139
140 BOOST_CHECK( !valid.has_value() );
141}
142
143
144// Backdrill start and end layers get the same copper-layer checks as the primary span.
145BOOST_AUTO_TEST_CASE( BackdrillLayersAreValidated )
146{
147 auto secondaryStart = PCB_VIA::ValidateViaParameters( pcbIUScale.mmToIU( 0.8 ), pcbIUScale.mmToIU( 0.4 ),
148 F_Cu, B_Cu, pcbIUScale.mmToIU( 0.5 ), F_SilkS );
149
150 BOOST_REQUIRE( secondaryStart.has_value() );
151 BOOST_CHECK( secondaryStart->m_Field == FIELD::SECONDARY_START_LAYER );
152
153 auto secondaryEnd = PCB_VIA::ValidateViaParameters( pcbIUScale.mmToIU( 0.8 ), pcbIUScale.mmToIU( 0.4 ),
154 F_Cu, B_Cu, pcbIUScale.mmToIU( 0.5 ), F_Cu, F_SilkS );
155
156 BOOST_REQUIRE( secondaryEnd.has_value() );
157 BOOST_CHECK( secondaryEnd->m_Field == FIELD::SECONDARY_END_LAYER );
158
159 auto tertiaryStart = PCB_VIA::ValidateViaParameters( pcbIUScale.mmToIU( 0.8 ), pcbIUScale.mmToIU( 0.4 ),
160 F_Cu, B_Cu, std::nullopt, std::nullopt, std::nullopt,
161 pcbIUScale.mmToIU( 0.5 ), F_SilkS );
162
163 BOOST_REQUIRE( tertiaryStart.has_value() );
164 BOOST_CHECK( tertiaryStart->m_Field == FIELD::TERTIARY_START_LAYER );
165
166 auto tertiaryEnd = PCB_VIA::ValidateViaParameters( pcbIUScale.mmToIU( 0.8 ), pcbIUScale.mmToIU( 0.4 ),
167 F_Cu, B_Cu, std::nullopt, std::nullopt, std::nullopt,
168 pcbIUScale.mmToIU( 0.5 ), F_Cu, F_SilkS );
169
170 BOOST_REQUIRE( tertiaryEnd.has_value() );
171 BOOST_CHECK( tertiaryEnd->m_Field == FIELD::TERTIARY_END_LAYER );
172}
173
174
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:121
static std::optional< VIA_PARAMETER_ERROR > ValidateViaParameters(std::optional< int > aDiameter, std::optional< int > aPrimaryDrill, std::optional< PCB_LAYER_ID > aPrimaryStartLayer=std::nullopt, std::optional< PCB_LAYER_ID > aPrimaryEndLayer=std::nullopt, std::optional< int > aSecondaryDrill=std::nullopt, std::optional< PCB_LAYER_ID > aSecondaryStartLayer=std::nullopt, std::optional< PCB_LAYER_ID > aSecondaryEndLayer=std::nullopt, std::optional< int > aTertiaryDrill=std::nullopt, std::optional< PCB_LAYER_ID > aTertiaryStartLayer=std::nullopt, std::optional< PCB_LAYER_ID > aTertiaryEndLayer=std::nullopt, int aCopperLayerCount=0)
@ B_Cu
Definition layer_ids.h:61
@ In2_Cu
Definition layer_ids.h:63
@ F_SilkS
Definition layer_ids.h:96
@ F_Cu
Definition layer_ids.h:60
#define GEOMETRY_MIN_SIZE
Definition pcb_track.h:53
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_AUTO_TEST_SUITE(CadstarPartParser)
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_AUTO_TEST_SUITE_END()
PCB_VIA::VIA_PARAMETER_ERROR::FIELD FIELD
BOOST_AUTO_TEST_CASE(WellFormedViaPasses)