KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_odb_drill_tools.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
20#include <filesystem>
21#include <fstream>
22#include <map>
23#include <memory>
24#include <set>
25#include <string>
26
28#include <qa_utils/file_utils.h>
30#include <boost/test/unit_test.hpp>
31
32#include <board.h>
33#include <pad.h>
36#include <core/utf8.h>
37
38namespace fs = std::filesystem;
39
69
70
75{
76 int m_num = -1;
77 double m_finishSize = 0.0;
78 double m_drillSize = 0.0;
79};
80
81
89static std::vector<ODB_TOOL_RECORD> parseOdbTools( const fs::path& aToolsFile )
90{
91 std::vector<ODB_TOOL_RECORD> tools;
92 std::ifstream stream( aToolsFile );
93 std::string line;
94
95 auto value = []( const std::string& aLine ) -> std::string
96 {
97 return aLine.substr( aLine.find( '=' ) + 1 );
98 };
99
100 while( std::getline( stream, line ) )
101 {
102 const size_t start = line.find_first_not_of( " \t" );
103
104 if( start == std::string::npos )
105 continue;
106
107 line = line.substr( start );
108
109 if( line.rfind( "TOOLS", 0 ) == 0 )
110 tools.emplace_back();
111 else if( tools.empty() )
112 continue;
113 else if( line.rfind( "NUM=", 0 ) == 0 )
114 tools.back().m_num = std::stoi( value( line ) );
115 else if( line.rfind( "FINISH_SIZE=", 0 ) == 0 )
116 tools.back().m_finishSize = std::stod( value( line ) );
117 else if( line.rfind( "DRILL_SIZE=", 0 ) == 0 )
118 tools.back().m_drillSize = std::stod( value( line ) );
119 }
120
121 return tools;
122}
123
124
133BOOST_AUTO_TEST_CASE( OdbNonPlatedDrillTools )
134{
135 SETTINGS_MANAGER settingsManager;
136 std::unique_ptr<BOARD> board = KI_TEST::ReadBoardFromFileOrStream(
137 KI_TEST::GetPcbnewTestDataDir() + "issue14130.kicad_pcb" );
138
139 BOOST_REQUIRE( board );
140
141 std::set<double> expectedSizes;
142 int npthHoleCount = 0;
143
144 for( const PAD* pad : board->GetPads() )
145 {
146 if( pad->GetAttribute() != PAD_ATTRIB::NPTH || !pad->HasHole() )
147 continue;
148
149 expectedSizes.insert( pcbIUScale.IUTomm( std::min( pad->GetDrillSizeX(),
150 pad->GetDrillSizeY() ) ) );
151 npthHoleCount++;
152 }
153
154 // A fixture whose holes were all one size would not show a mis-numbered tool table
155 BOOST_REQUIRE_GT( npthHoleCount, (int) expectedSizes.size() );
156 BOOST_REQUIRE_GT( expectedSizes.size(), 1 );
157
158 KI_TEST::SCOPED_TEMP_DIR tempDir( wxT( "kicad_qa_odb_drill_tools" ) );
159 ODB_EXPORT_STATE_GUARD stateGuard;
160
161 PCB_IO_ODBPP odbExporter;
162 std::map<std::string, UTF8> props;
163 props["units"] = "mm";
164 props["sigfig"] = "6";
165
166 BOOST_REQUIRE_NO_THROW( odbExporter.SaveBoard( tempDir.Path().string(), *board, &props ) );
167
168 fs::path toolsFile;
169
170 for( const fs::directory_entry& entry : fs::recursive_directory_iterator( tempDir.Path() ) )
171 {
172 if( entry.is_regular_file() && entry.path().filename() == "tools"
173 && entry.path().parent_path().filename().string().find( "non-plated" )
174 != std::string::npos )
175 {
176 toolsFile = entry.path();
177 break;
178 }
179 }
180
181 BOOST_REQUIRE_MESSAGE( !toolsFile.empty(),
182 "ODB++ export produced no non-plated drill tools file" );
183
184 const std::vector<ODB_TOOL_RECORD> tools = parseOdbTools( toolsFile );
185
186 std::set<int> seenNums;
187 std::set<double> seenSizes;
188
189 for( const ODB_TOOL_RECORD& tool : tools )
190 {
191 BOOST_CHECK_MESSAGE( seenNums.insert( tool.m_num ).second,
192 "Drill tool number " << tool.m_num << " is used twice" );
193
194 seenSizes.insert( tool.m_drillSize );
195 }
196
197 // Sizes first, then the count, so a regression in either half is reported on its own
198 BOOST_CHECK_EQUAL_COLLECTIONS( seenSizes.begin(), seenSizes.end(), expectedSizes.begin(),
199 expectedSizes.end() );
200
201 BOOST_CHECK_EQUAL( tools.size(), expectedSizes.size() );
202}
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:121
General utilities for PCB file IO for QA programs.
const std::filesystem::path & Path() const
Get the path to the temporary directory as a std::filesystem::path.
Definition file_utils.h:59
Definition pad.h:61
static int m_sigfig
static double m_symbolScale
Internal units to thousandths of the output unit, the scale ODB++ symbol names use.
void SaveBoard(const wxString &aFileName, BOARD &aBoard, const std::map< std::string, UTF8 > *aProperties=nullptr) override
Write aBoard to a storage file in a format that this PCB_IO implementation knows about or it can be u...
static std::string m_unitsStr
static double m_scale
Internal units to the output units named by m_unitsStr, for values written as data.
std::string GetPcbnewTestDataDir()
Utility which returns a path to the data directory where the test board files are stored.
std::unique_ptr< BOARD > ReadBoardFromFileOrStream(const std::string &aFilename, std::istream &aFallback)
Read a board from a file, or another stream, as appropriate.
@ NPTH
like PAD_PTH, but not plated mechanical use only, no connection allowed
Definition padstack.h:102
One TOOLS record from an ODB++ drill layer "tools" file.
BOOST_CHECK_EQUAL_COLLECTIONS(mixed.begin(), mixed.end(), expMixed.begin(), expMixed.end())
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
static std::vector< ODB_TOOL_RECORD > parseOdbTools(const fs::path &aToolsFile)
Parse the TOOLS records out of an ODB++ "tools" file.
BOOST_AUTO_TEST_CASE(OdbNonPlatedDrillTools)
Test that the ODB++ drill "tools" file describes the board's non-plated holes.
BOOST_CHECK_EQUAL(result, "25.4")