KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_altium_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
28
32
35
36#include <board.h>
38#include <netinfo.h>
39#include <netclass.h>
41#include <zone.h>
42
43
50
51
52BOOST_FIXTURE_TEST_SUITE( AltiumPcbImport, ALTIUM_PCB_IMPORT_FIXTURE )
53
54
55
59BOOST_AUTO_TEST_CASE( BoardLoadNoAssertions )
60{
61 std::string dataPath = KI_TEST::GetPcbnewTestDataDir()
62 + "plugins/altium/eDP_adapter_dvt1_source/eDP_adapter_dvt1.PcbDoc";
63
64 std::unique_ptr<BOARD> board = std::make_unique<BOARD>();
65
66 // Load the board - should not trigger any assertions
67 m_altiumPlugin.LoadBoard( dataPath, board.get(), nullptr );
68
69 BOOST_REQUIRE( board );
70
71 // Basic sanity checks
72 BOOST_CHECK( board->GetNetCount() > 0 );
73 BOOST_CHECK( board->Footprints().size() > 0 );
74}
75
76
84BOOST_AUTO_TEST_CASE( NetclassAssignment )
85{
86 // HiFive1.B01.PcbDoc has Altium netclass definitions
87 std::string dataPath = KI_TEST::GetPcbnewTestDataDir() + "plugins/altium/HiFive/HiFive1.B01.PcbDoc";
88
89 std::unique_ptr<BOARD> board = std::make_unique<BOARD>();
90
91 m_altiumPlugin.LoadBoard( dataPath, board.get(), nullptr );
92
93 BOOST_REQUIRE( board );
94
95 // Get the net settings which contains pattern assignments
96 std::shared_ptr<NET_SETTINGS> netSettings = board->GetDesignSettings().m_NetSettings;
97
98 BOOST_REQUIRE( netSettings );
99
100 // Check if there are any pattern assignments in the board
101 auto& patternAssignments = netSettings->GetNetclassPatternAssignments();
102
103 // The HiFive board should have netclass definitions - require this for the test to be meaningful
104 BOOST_REQUIRE_MESSAGE( patternAssignments.size() > 0,
105 "Test file must have netclass pattern assignments" );
106
107 // For each net that has a pattern assignment, verify that the NETINFO_ITEM
108 // has a netclass directly assigned (not just through pattern resolution)
109 bool foundAssignedNet = false;
110
111 for( NETINFO_ITEM* net : board->GetNetInfo() )
112 {
113 if( net->GetNetCode() <= 0 )
114 continue;
115
116 // Get the netclass directly from the NETINFO_ITEM
117 NETCLASS* directNetclass = net->GetNetClass();
118
119 // Get the effective netclass from pattern resolution
120 std::shared_ptr<NETCLASS> effectiveNetclass =
121 netSettings->GetEffectiveNetClass( net->GetNetname() );
122
123 // If this net has a non-default effective netclass, the direct assignment
124 // should also be non-default (this is what the fix ensures)
125 if( effectiveNetclass && effectiveNetclass->GetName() != NETCLASS::Default )
126 {
128 directNetclass != nullptr,
129 wxString::Format( "Net '%s' should have a direct netclass assignment",
130 net->GetNetname() ) );
131
132 if( directNetclass )
133 {
134 foundAssignedNet = true;
135
136 // The direct netclass should match what effective resolution returns
137 // (or be part of the effective class for multi-netclass scenarios)
139 directNetclass->GetName() != NETCLASS::Default,
140 wxString::Format( "Net '%s' should not have default netclass, "
141 "expected effective class or component",
142 net->GetNetname() ) );
143 }
144 }
145 }
146
147 // If there were pattern assignments, we should have found at least one assigned net
148 BOOST_CHECK_MESSAGE( foundAssignedNet,
149 "At least one net should have a non-default netclass assigned" );
150}
151
152
159 const std::string& aRelativePath )
160{
161 std::string dataPath = KI_TEST::GetPcbnewTestDataDir() + aRelativePath;
162
163 std::unique_ptr<BOARD> board = std::make_unique<BOARD>();
164 aPlugin.LoadBoard( dataPath, board.get(), nullptr );
165
166 BOOST_REQUIRE( board );
167
168 int fillZoneCount = 0;
169 int fillZonesWithClearance = 0;
170
171 for( ZONE* zone : board->Zones() )
172 {
173 if( !zone->IsOnCopperLayer() || zone->GetIsRuleArea() || zone->IsTeardropArea() )
174 continue;
175
176 fillZoneCount++;
177
178 if( zone->GetLocalClearance().has_value() && zone->GetLocalClearance().value() > 0 )
179 fillZonesWithClearance++;
180 }
181
182 BOOST_CHECK_GT( fillZoneCount, 0 );
183
184 BOOST_CHECK_MESSAGE( fillZonesWithClearance == fillZoneCount,
185 wxString::Format( "%s: %d/%d copper fill zones have clearance set",
186 aRelativePath, fillZonesWithClearance,
187 fillZoneCount ) );
188}
189
190
191BOOST_AUTO_TEST_CASE( ZoneClearances_eDP )
192{
194 m_altiumPlugin, "plugins/altium/eDP_adapter_dvt1_source/eDP_adapter_dvt1.PcbDoc" );
195}
196
197
198BOOST_AUTO_TEST_CASE( ZoneClearances_HiFive )
199{
201 "plugins/altium/HiFive/HiFive1.B01.PcbDoc" );
202}
203
204
212BOOST_AUTO_TEST_CASE( ScopeExprMatchesPolygon )
213{
214 // Positive matches: expressions that reference polygons
215 BOOST_CHECK( altiumScopeExprMatchesPolygon( wxT( "InPolygon" ) ) );
216 BOOST_CHECK( altiumScopeExprMatchesPolygon( wxT( "InPoly" ) ) );
217 BOOST_CHECK( altiumScopeExprMatchesPolygon( wxT( "IsPolygon" ) ) );
218 BOOST_CHECK( altiumScopeExprMatchesPolygon( wxT( "IsPoly" ) ) );
219
220 // Case insensitivity
221 BOOST_CHECK( altiumScopeExprMatchesPolygon( wxT( "inpolygon" ) ) );
222 BOOST_CHECK( altiumScopeExprMatchesPolygon( wxT( "INPOLYGON" ) ) );
223 BOOST_CHECK( altiumScopeExprMatchesPolygon( wxT( "inPOLY" ) ) );
224
225 // Contained within longer expressions
226 BOOST_CHECK( altiumScopeExprMatchesPolygon( wxT( "InPolygon And InNet('GND')" ) ) );
227 BOOST_CHECK( altiumScopeExprMatchesPolygon( wxT( "(InPoly) Or IsVia" ) ) );
228
229 // Negative matches: expressions that don't reference polygons
230 BOOST_CHECK( !altiumScopeExprMatchesPolygon( wxT( "All" ) ) );
231 BOOST_CHECK( !altiumScopeExprMatchesPolygon( wxT( "IsVia" ) ) );
232 BOOST_CHECK( !altiumScopeExprMatchesPolygon( wxT( "IsTrack" ) ) );
233 BOOST_CHECK( !altiumScopeExprMatchesPolygon( wxT( "InNet('GND')" ) ) );
234 BOOST_CHECK( !altiumScopeExprMatchesPolygon( wxT( "InComponent('U1')" ) ) );
235 BOOST_CHECK( !altiumScopeExprMatchesPolygon( wxT( "" ) ) );
236}
237
238
244BOOST_AUTO_TEST_CASE( SelectAltiumPolygonRule_PriorityOrder )
245{
246 auto makeRule = []( int aPriority, const wxString& aScope1, const wxString& aScope2,
247 int aClearance )
248 {
249 ARULE6 rule;
250 rule.priority = aPriority;
251 rule.scope1expr = aScope1;
252 rule.scope2expr = aScope2;
253 rule.clearanceGap = aClearance;
254 return rule;
255 };
256
257 // Sorted by priority ascending, matching the order produced by ParseRules6Data.
258 std::vector<ARULE6> rules = {
259 makeRule( 1, wxT( "InPolygon And InNet('GND')" ), wxT( "All" ), 100 ),
260 makeRule( 2, wxT( "InPolygon" ), wxT( "All" ), 200 ),
261 makeRule( 3, wxT( "All" ), wxT( "All" ), 300 ),
262 makeRule( 4, wxT( "All" ), wxT( "All" ), 400 ),
263 };
264
265 const ARULE6* selected = selectAltiumPolygonRule( rules );
266 BOOST_REQUIRE( selected != nullptr );
267 BOOST_CHECK_EQUAL( selected->priority, 1 );
268 BOOST_CHECK_EQUAL( selected->clearanceGap, 100 );
269
270 rules.erase( rules.begin() );
271 selected = selectAltiumPolygonRule( rules );
272 BOOST_REQUIRE( selected != nullptr );
273 BOOST_CHECK_EQUAL( selected->priority, 2 );
274 BOOST_CHECK_EQUAL( selected->clearanceGap, 200 );
275
276 rules.erase( rules.begin() );
277 BOOST_CHECK( selectAltiumPolygonRule( rules ) == nullptr );
278
279 BOOST_CHECK( selectAltiumPolygonRule( {} ) == nullptr );
280}
281
282
bool altiumScopeExprMatchesPolygon(const wxString &aExpr)
Return true if an Altium rule scope expression targets polygon pour primitives (matches InPolygon,...
const ARULE6 * selectAltiumPolygonRule(const std::vector< ARULE6 > &aRulesByPriorityAsc)
Select the highest Altium-priority rule whose scope references polygons.
General utilities for PCB file IO for QA programs.
A collection of nets and the parameters used to route or test these nets.
Definition netclass.h:42
static const char Default[]
the name of the default NETCLASS
Definition netclass.h:44
const wxString GetName() const
Gets the name of this (maybe aggregate) netclass in a format for internal usage or for export to exte...
Definition netclass.cpp:328
Handle the data for a net.
Definition netinfo.h:50
BOARD * LoadBoard(const wxString &aFileName, BOARD *aAppendToMe, const std::map< std::string, UTF8 > *aProperties, PROJECT *aProject=nullptr) override
Load information from some input file format that this PCB_IO implementation knows about into either ...
Handle a list of polygons defining a copper zone.
Definition zone.h:74
std::string GetPcbnewTestDataDir()
Utility which returns a path to the data directory where the test board files are stored.
PCB_IO_ALTIUM_DESIGNER m_altiumPlugin
wxString scope1expr
wxString scope2expr
BOOST_AUTO_TEST_CASE(BoardLoadNoAssertions)
Test basic board loading - verifies that the Altium import doesn't trigger any assertions during the ...
static void checkAllCopperFillZonesHaveClearance(PCB_IO_ALTIUM_DESIGNER &aPlugin, const std::string &aRelativePath)
Verify that copper zones in imported Altium boards have non-zero local clearance values derived from ...
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_AUTO_TEST_SUITE_END()
BOOST_CHECK_MESSAGE(totalMismatches==0, std::to_string(totalMismatches)+" board(s) with strategy disagreements")
BOOST_CHECK_EQUAL(result, "25.4")