20#include <boost/test/unit_test.hpp>
50#include <wx/filename.h>
51#include <wx/tokenzr.h>
57wxFileName MakeTempDir()
59 wxFileName tempDir( wxFileName::GetTempDir(), wxEmptyString );
60 tempDir.AppendDir( wxString::Format(
"kicad-backdrill-%llu",
static_cast<unsigned long long>( wxGetUTCTime() ) ) );
61 BOOST_REQUIRE( tempDir.Mkdir( wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL ) );
70 gerber.SetOptions(
VECTOR2I( 0, 0 ) );
71 gerber.SetFormat( 6 );
73 return gerber.GetCreatedFiles();
77size_t CountContaining(
const std::vector<wxString>& aFiles,
const wxString& aPart )
79 return std::count_if( aFiles.begin(), aFiles.end(), [&](
const wxString& aName )
81 return aName.Contains( aPart );
91 +
"drc_via_stack/FillFromBoardHonoursTheBoardDefault.kicad_pcb" );
97 std::vector<wxString> created = ExportGerberDrill( *board, dir );
98 auto front = std::find_if( created.begin(), created.end(), [](
const wxString& aName )
100 return aName.EndsWith( wxT(
"-tenting-front.gbr" ) );
103 std::ifstream stream( std::filesystem::path( front->ToStdString() ), std::ios::binary );
104 std::string frontTenting( std::istreambuf_iterator<char>{ stream }, std::istreambuf_iterator<char>{} );
109 BOOST_CHECK( frontTenting.find(
"TF,FileFunction,Other,Tenting-Front" ) != std::string::npos );
123 if( !span.m_IsBackdrill )
131 BOOST_CHECK( !op.m_TopTented );
132 BOOST_CHECK( !op.m_BottomTented );
133 BOOST_CHECK( !op.m_TopCovered );
134 BOOST_CHECK( !op.m_BottomCovered );
135 BOOST_CHECK( !op.m_TopPlugged );
136 BOOST_CHECK( !op.m_BottomPlugged );
141 std::vector<wxString> created = ExportGerberDrill( *board, dir );
149 wxFileName tempDir = MakeTempDir();
150 wxFileName boardFile( tempDir.GetFullPath(), wxT(
"backdrill_board.kicad_pcb" ) );
163 via->SetSecondaryDrillStartLayer(
F_Cu );
164 via->SetSecondaryDrillEndLayer(
In3_Cu );
167 via->SetFrontPostMachiningDepth(
pcbIUScale.mmToIU( 0.15 ) );
168 via->SetFrontPostMachiningAngle( 900 );
176 wxFileName excellonFile( tempDir.GetFullPath(), wxT(
"backdrill_board_Backdrills_Drill_1_4.drl" ) );
179 wxFFile excellonStream( excellonFile.GetFullPath(), wxT(
"rb" ) );
180 wxString excellonContents;
181 BOOST_REQUIRE( excellonStream.ReadAll( &excellonContents ) );
182 BOOST_CHECK( excellonContents.Contains( wxT(
"TF.FileFunction,NonPlated,1,4,Blind" ) ) );
183 BOOST_CHECK( excellonContents.Contains( wxT(
"; Backdrill" ) ) );
184 BOOST_CHECK( excellonContents.Contains( wxT(
"post-machining" ) ) );
186 wxFileName layerPairFile( tempDir.GetFullPath(), wxT(
"backdrill_board-front-in3-backdrill.drl" ) );
189 wxFFile layerPairStream( layerPairFile.GetFullPath(), wxT(
"rb" ) );
190 wxString layerPairContents;
191 BOOST_REQUIRE( layerPairStream.ReadAll( &layerPairContents ) );
192 BOOST_CHECK( layerPairContents.Contains( wxT(
"; backdrill" ) ) );
194 wxFileName pthFile( tempDir.GetFullPath(), wxT(
"backdrill_board-PTH.drl" ) );
197 wxFFile pthStream( pthFile.GetFullPath(), wxT(
"rb" ) );
198 wxString pthContents;
200 BOOST_CHECK( pthContents.Contains( wxT(
"; Post-machining front countersink dia 0.600mm depth 0.150mm angle 90deg" ) ) );
207 wxFileName gerberFile( tempDir.GetFullPath(), wxT(
"backdrill_board_Backdrills_Drill_1_4-drl.gbr" ) );
210 wxFFile gerberStream( gerberFile.GetFullPath(), wxT(
"rb" ) );
211 wxString gerberContents;
213 BOOST_CHECK( gerberContents.Contains( wxT(
"%TA.AperFunction,BackDrill*%" ) ) );
214 BOOST_CHECK( gerberContents.Contains( wxT(
"%TF.FileFunction,NonPlated,1,4,Blind,Drill*%" ) ) );
216 wxFileName gerberLayerPairFile( tempDir.GetFullPath(),
217 wxT(
"backdrill_board-front-in3-backdrill-drl.gbr" ) );
220 wxFFile gerberLayerPairStream( gerberLayerPairFile.GetFullPath(), wxT(
"rb" ) );
221 wxString gerberLayerPairContents;
222 BOOST_REQUIRE( gerberLayerPairStream.ReadAll( &gerberLayerPairContents ) );
223 BOOST_CHECK( gerberLayerPairContents.Contains( wxT(
"%TF.FileFunction,NonPlated,1,4,Blind,Drill*%" ) ) );
224 BOOST_CHECK( gerberLayerPairContents.Contains( wxT(
"%TA.AperFunction,BackDrill*%" ) ) );
226 wxFileName odbRoot( tempDir.GetFullPath(), wxEmptyString );
227 odbRoot.AppendDir( wxT(
"odb_out" ) );
228 BOOST_REQUIRE( odbRoot.Mkdir( wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL ) );
231 std::map<std::string, UTF8> props;
232 props[
"units"] =
"mm";
233 props[
"sigfig"] =
"4";
234 BOOST_REQUIRE_NO_THROW( odbExporter.
SaveBoard( odbRoot.GetFullPath(), board, &props ) );
236 wxFileName drill1Dir( odbRoot.GetFullPath(), wxEmptyString );
237 drill1Dir.AppendDir( wxT(
"steps" ) );
238 drill1Dir.AppendDir( wxT(
"pcb" ) );
239 drill1Dir.AppendDir( wxT(
"layers" ) );
240 drill1Dir.AppendDir( wxT(
"drill1" ) );
243 wxFileName toolsFile( drill1Dir.GetFullPath(), wxT(
"tools" ) );
246 wxFFile toolsStream( toolsFile.GetFullPath(), wxT(
"rb" ) );
247 wxString toolsContents;
249 BOOST_CHECK( toolsContents.Contains( wxT(
"TYPE=NON_PLATED" ) ) );
250 BOOST_CHECK( toolsContents.Contains( wxT(
"TYPE2=BLIND" ) ) );
252 wxFileName matrixFile( odbRoot.GetFullPath(), wxEmptyString );
253 matrixFile.AppendDir( wxT(
"matrix" ) );
254 matrixFile.SetFullName( wxT(
"matrix" ) );
257 wxFFile matrixStream( matrixFile.GetFullPath(), wxT(
"rb" ) );
258 wxString matrixContents;
260 BOOST_CHECK( matrixContents.Contains( wxT(
"ADD_TYPE=BACKDRILL" ) ) );
262 matrixStream.Close();
264 gerberStream.Close();
265 gerberLayerPairStream.Close();
266 excellonStream.Close();
267 layerPairStream.Close();
270 wxFileName::Rmdir( odbRoot.GetFullPath(), wxPATH_RMDIR_RECURSIVE );
271 wxFileName::Rmdir( tempDir.GetFullPath(), wxPATH_RMDIR_RECURSIVE );
280 wxFileName tempDir = MakeTempDir();
281 wxFileName boardFile( tempDir.GetFullPath(), wxT(
"backdrill_pair_board.kicad_pcb" ) );
307 board.
Add( bottomVia );
314 wxFileName topBackdrillFile( tempDir.GetFullPath(),
315 wxT(
"backdrill_pair_board_Backdrills_Drill_1_2.drl" ) );
316 BOOST_CHECK_MESSAGE( topBackdrillFile.FileExists(),
317 "Front-side backdrill drill file should be produced" );
320 wxFileName bottomBackdrillFile( tempDir.GetFullPath(),
321 wxT(
"backdrill_pair_board_Backdrills_Drill_6_4.drl" ) );
322 BOOST_CHECK_MESSAGE( bottomBackdrillFile.FileExists(),
323 "Back-side (tertiary) backdrill drill file should be produced" );
325 if( bottomBackdrillFile.FileExists() )
327 wxFFile stream( bottomBackdrillFile.GetFullPath(), wxT(
"rb" ) );
330 BOOST_CHECK( contents.Contains( wxT(
"; Backdrill" ) ) );
334 wxFileName::Rmdir( tempDir.GetFullPath(), wxPATH_RMDIR_RECURSIVE );
343 wxFileName tempDir = MakeTempDir();
344 wxFileName boardFile( tempDir.GetFullPath(), wxT(
"dual_backdrill_board.kicad_pcb" ) );
357 via->SetSecondaryDrillStartLayer(
F_Cu );
358 via->SetSecondaryDrillEndLayer(
In1_Cu );
360 via->SetTertiaryDrillStartLayer(
B_Cu );
370 wxFileName topBackdrillFile( tempDir.GetFullPath(),
371 wxT(
"dual_backdrill_board_Backdrills_Drill_1_2.drl" ) );
372 BOOST_CHECK( topBackdrillFile.FileExists() );
374 wxFileName bottomBackdrillFile( tempDir.GetFullPath(),
375 wxT(
"dual_backdrill_board_Backdrills_Drill_6_4.drl" ) );
376 BOOST_CHECK( bottomBackdrillFile.FileExists() );
378 wxFileName::Rmdir( tempDir.GetFullPath(), wxPATH_RMDIR_RECURSIVE );
386 wxFileName tempDir = MakeTempDir();
387 wxFileName boardFile( tempDir.GetFullPath(), wxT(
"precision_board.kicad_pcb" ) );
407 wxFileName gerberFile5( tempDir.GetFullPath(), wxT(
"precision_board-PTH-drl.gbr" ) );
410 wxFFile gerberStream5( gerberFile5.GetFullPath(), wxT(
"rb" ) );
411 wxString gerberContents5;
413 BOOST_CHECK_MESSAGE( gerberContents5.Contains( wxT(
"Fmt 4.5" ) ),
414 "Expected 'Fmt 4.5' in gerber header with precision=5" );
415 BOOST_CHECK( !gerberContents5.Contains( wxT(
"Fmt 4.6" ) ) );
416 gerberStream5.Close();
424 wxFFile gerberStream6( gerberFile5.GetFullPath(), wxT(
"rb" ) );
425 wxString gerberContents6;
427 BOOST_CHECK_MESSAGE( gerberContents6.Contains( wxT(
"Fmt 4.6" ) ),
428 "Expected 'Fmt 4.6' in gerber header with precision=6" );
429 BOOST_CHECK( !gerberContents6.Contains( wxT(
"Fmt 4.5" ) ) );
430 gerberStream6.Close();
432 wxFileName::Rmdir( tempDir.GetFullPath(), wxPATH_RMDIR_RECURSIVE );
441 wxFileName tempDir = MakeTempDir();
442 wxFileName boardFile( tempDir.GetFullPath(), wxT(
"layer_order_board.kicad_pcb" ) );
464 wxFileName correctFile( tempDir.GetFullPath(), wxT(
"layer_order_board-in2-back.drl" ) );
465 wxFileName reversedFile( tempDir.GetFullPath(), wxT(
"layer_order_board-back-in2.drl" ) );
466 BOOST_CHECK_MESSAGE( correctFile.FileExists(),
"Expected drill file 'in2-back' not found" );
467 BOOST_CHECK_MESSAGE( !reversedFile.FileExists(),
"Incorrectly named drill file 'back-in2' found" );
469 wxFileName::Rmdir( tempDir.GetFullPath(), wxPATH_RMDIR_RECURSIVE );
477 wxFileName tempDir = MakeTempDir();
478 wxFileName boardFile( tempDir.GetFullPath(), wxT(
"test_board.kicad_pcb" ) );
484 wxFileName reportFile( tempDir.GetFullPath(), wxT(
"test_board-drl.rpt" ) );
489 BOOST_CHECK( reportFile.FileExists() );
496 BOOST_CHECK( !excellon2.
GenDrillReportFile( wxT(
"/nonexistent/path/report.rpt" ) ) );
501 wxFileName::Rmdir( tempDir.GetFullPath(), wxPATH_RMDIR_RECURSIVE );
510 wxFileName tempDir = MakeTempDir();
511 wxFileName boardFile( tempDir.GetFullPath(), wxT(
"test_board_with_drills.kicad_pcb" ) );
525 wxFileName reportFile( tempDir.GetFullPath(), wxT(
"test_board_with_drills-drl.rpt" ) );
531 BOOST_CHECK( reportFile.FileExists() );
533 wxFFile reportStream( reportFile.GetFullPath(), wxT(
"rb" ) );
534 wxString reportContents;
536 BOOST_CHECK( reportContents.Contains( wxT(
"T1" ) ) );
537 BOOST_CHECK( reportContents.Contains( wxT(
"0.300mm" ) ) );
538 reportStream.Close();
540 wxFileName::Rmdir( tempDir.GetFullPath(), wxPATH_RMDIR_RECURSIVE );
552 wxFileName tempDir = MakeTempDir();
553 wxFileName boardFile( tempDir.GetFullPath(), wxT(
"silk_rect_board.kicad_pcb" ) );
568 wxFileName odbRoot( tempDir.GetFullPath(), wxEmptyString );
569 odbRoot.AppendDir( wxT(
"odb_out" ) );
570 BOOST_REQUIRE( odbRoot.Mkdir( wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL ) );
573 std::map<std::string, UTF8> props;
574 props[
"units"] =
"mm";
575 props[
"sigfig"] =
"4";
576 BOOST_REQUIRE_NO_THROW( odbExporter.
SaveBoard( odbRoot.GetFullPath(), board, &props ) );
578 wxFileName silkFeatures( odbRoot.GetFullPath(), wxT(
"features" ) );
579 silkFeatures.AppendDir( wxT(
"steps" ) );
580 silkFeatures.AppendDir( wxT(
"pcb" ) );
581 silkFeatures.AppendDir( wxT(
"layers" ) );
582 silkFeatures.AppendDir( wxT(
"f.silkscreen" ) );
585 wxFFile silkStream( silkFeatures.GetFullPath(), wxT(
"rb" ) );
586 wxString silkContents;
592 wxStringTokenizer lines( silkContents, wxT(
"\n" ) );
594 while( lines.HasMoreTokens() )
596 if( lines.GetNextToken().StartsWith( wxT(
"L " ) ) )
603 BOOST_CHECK( !silkContents.Contains( wxT(
"donut_rc" ) ) );
605 wxFileName::Rmdir( odbRoot.GetFullPath(), wxPATH_RMDIR_RECURSIVE );
606 wxFileName::Rmdir( tempDir.GetFullPath(), wxPATH_RMDIR_RECURSIVE );
612 wxFileName tempDir = MakeTempDir();
630 wxFileName odbRoot( tempDir.GetFullPath(), wxEmptyString );
631 odbRoot.AppendDir( wxT(
"odb_out" ) );
632 BOOST_REQUIRE( odbRoot.Mkdir( wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL ) );
635 std::map<std::string, UTF8> props;
636 props[
"units"] =
"mm";
637 props[
"sigfig"] =
"4";
638 BOOST_REQUIRE_NO_THROW( odbExporter.
SaveBoard( odbRoot.GetFullPath(), board, &props ) );
640 wxFileName copperFeatures( odbRoot.GetFullPath(), wxT(
"features" ) );
641 copperFeatures.AppendDir( wxT(
"steps" ) );
642 copperFeatures.AppendDir( wxT(
"pcb" ) );
643 copperFeatures.AppendDir( wxT(
"layers" ) );
644 copperFeatures.AppendDir( wxT(
"f.cu" ) );
647 wxFFile copperStream( copperFeatures.GetFullPath(), wxT(
"rb" ) );
648 wxString copperContents;
650 copperStream.Close();
654 wxStringTokenizer lines( copperContents, wxT(
"\n" ) );
656 while( lines.HasMoreTokens() )
658 wxString line = lines.GetNextToken();
660 if( line.StartsWith( wxT(
"L " ) ) )
662 else if( line.StartsWith( wxT(
"A " ) ) )
669 wxFileName::Rmdir( odbRoot.GetFullPath(), wxPATH_RMDIR_RECURSIVE );
670 wxFileName::Rmdir( tempDir.GetFullPath(), wxPATH_RMDIR_RECURSIVE );
678 wxFileName odbRoot( aTempDir.GetFullPath(), wxEmptyString );
679 odbRoot.AppendDir( wxT(
"odb_out" ) );
680 BOOST_REQUIRE( odbRoot.Mkdir( wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL ) );
683 std::map<std::string, UTF8> props;
684 props[
"units"] =
"mm";
685 props[
"sigfig"] =
"4";
686 BOOST_REQUIRE_NO_THROW( odbExporter.
SaveBoard( odbRoot.GetFullPath(), *aBoard, &props ) );
694 wxFileName features( aOdbRoot.GetFullPath(), wxT(
"features" ) );
695 features.AppendDir( wxT(
"steps" ) );
696 features.AppendDir( wxT(
"pcb" ) );
697 features.AppendDir( wxT(
"layers" ) );
698 features.AppendDir( aLayerDir );
701 wxFFile stream( features.GetFullPath(), wxT(
"rb" ) );
717 std::unique_ptr<BOARD> board;
722 wxFileName tempDir = MakeTempDir();
728 BOOST_CHECK_MESSAGE( contents.Contains( wxT(
"donut_r2100.0x1900.0" ) ),
729 "Wrong copper annulus, features file holds:\n" + contents );
731 wxFileName::Rmdir( odbRoot.GetFullPath(), wxPATH_RMDIR_RECURSIVE );
732 wxFileName::Rmdir( tempDir.GetFullPath(), wxPATH_RMDIR_RECURSIVE );
743 std::unique_ptr<BOARD> board;
745 KI_TEST::LoadBoard( settingsManager, wxT(
"issue25089/odb_circle_edge_cases" ), board );
748 wxFileName tempDir = MakeTempDir();
753 BOOST_CHECK_MESSAGE( frontContents.Contains( wxT(
"r400.0" ) )
754 && !frontContents.Contains( wxT(
"donut" ) ),
755 "Circle with a hole-closing stroke should export as a solid pad, "
756 "features file holds:\n"
761 wxStringTokenizer backLines( backContents, wxT(
"\n" ) );
763 while( backLines.HasMoreTokens() )
765 wxString line = backLines.GetNextToken();
767 if( line.StartsWith( wxT(
"$" ) ) )
769 BOOST_CHECK_MESSAGE( !line.Contains( wxT(
"-" ) ),
770 "Oversized circle overflowed to a negative symbol dimension: "
775 wxFileName::Rmdir( odbRoot.GetFullPath(), wxPATH_RMDIR_RECURSIVE );
776 wxFileName::Rmdir( tempDir.GetFullPath(), wxPATH_RMDIR_RECURSIVE );
786 pad->SetAttribute( aAttribute );
789 pad->SetPosition( aPos );
808 wxFileName tempDir = MakeTempDir();
809 wxFileName boardFile( tempDir.GetFullPath(), wxT(
"plated_slot_board.kicad_pcb" ) );
825 wxFileName odbRoot( tempDir.GetFullPath(), wxEmptyString );
826 odbRoot.AppendDir( wxT(
"odb_out" ) );
827 BOOST_REQUIRE( odbRoot.Mkdir( wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL ) );
830 std::map<std::string, UTF8> props;
831 props[
"units"] =
"mm";
832 props[
"sigfig"] =
"4";
833 BOOST_REQUIRE_NO_THROW( odbExporter.
SaveBoard( odbRoot.GetFullPath(), board, &props ) );
835 auto layerDir = [&](
const wxString& aLayer )
837 wxFileName dir( odbRoot.GetFullPath(), wxEmptyString );
838 dir.AppendDir( wxT(
"steps" ) );
839 dir.AppendDir( wxT(
"pcb" ) );
840 dir.AppendDir( wxT(
"layers" ) );
841 dir.AppendDir( aLayer );
846 auto readFile = [](
const wxFileName& aFile )
848 wxFFile stream( aFile.GetFullPath(), wxT(
"rb" ) );
857 auto countLinesStartingWith = [](
const wxString& aContents,
const wxString& aPrefix )
860 wxStringTokenizer lines( aContents, wxT(
"\n" ) );
862 while( lines.HasMoreTokens() )
864 wxString line = lines.GetNextToken();
867 if( line.StartsWith( aPrefix ) )
874 auto containsOvalSymbol = [](
const wxString& aContents )
876 wxStringTokenizer lines( aContents, wxT(
"\n" ) );
878 while( lines.HasMoreTokens() )
880 wxString line = lines.GetNextToken();
883 if( line.StartsWith( wxT(
"$" ) ) && line.Contains( wxT(
"oval" ) ) )
893 wxFileName platedDir = layerDir( wxT(
"drill_plated_f.cu-b.cu" ) );
894 BOOST_REQUIRE_MESSAGE( platedDir.DirExists(),
"Plated drill layer should exist" );
896 wxFileName platedFeatures( platedDir.GetFullPath(), wxT(
"features" ) );
898 wxString platedContents =
readFile( platedFeatures );
901 BOOST_CHECK_MESSAGE( !containsOvalSymbol( platedContents ),
902 "Plated slot should be a line, not an oval pad" );
904 wxFileName platedTools( platedDir.GetFullPath(), wxT(
"tools" ) );
906 wxString platedToolsContents =
readFile( platedTools );
907 BOOST_CHECK_EQUAL( countLinesStartingWith( platedToolsContents, wxT(
"TYPE=PLATED" ) ), 1 );
908 BOOST_CHECK_EQUAL( countLinesStartingWith( platedToolsContents, wxT(
"TYPE=NON_PLATED" ) ), 0 );
912 wxFileName nonPlatedDir = layerDir( wxT(
"drill_non-plated_f.cu-b.cu" ) );
913 BOOST_REQUIRE_MESSAGE( nonPlatedDir.DirExists(),
"Non-plated drill layer should exist" );
915 wxFileName nonPlatedFeatures( nonPlatedDir.GetFullPath(), wxT(
"features" ) );
917 wxString nonPlatedContents =
readFile( nonPlatedFeatures );
919 BOOST_CHECK_EQUAL( countLinesStartingWith( nonPlatedContents, wxT(
"L " ) ), 1 );
920 BOOST_CHECK_MESSAGE( !containsOvalSymbol( nonPlatedContents ),
921 "Non-plated slot should be a line, not an oval pad" );
923 wxFileName nonPlatedTools( nonPlatedDir.GetFullPath(), wxT(
"tools" ) );
925 wxString nonPlatedToolsContents =
readFile( nonPlatedTools );
926 BOOST_CHECK_EQUAL( countLinesStartingWith( nonPlatedToolsContents, wxT(
"TYPE=NON_PLATED" ) ),
928 BOOST_CHECK_EQUAL( countLinesStartingWith( nonPlatedToolsContents, wxT(
"TYPE=PLATED" ) ), 0 );
930 wxFileName::Rmdir( odbRoot.GetFullPath(), wxPATH_RMDIR_RECURSIVE );
931 wxFileName::Rmdir( tempDir.GetFullPath(), wxPATH_RMDIR_RECURSIVE );
942 std::unique_ptr<BOARD> board;
947 wxFileName tempDir = MakeTempDir();
948 wxFileName boardFile( tempDir.GetFullPath(), wxT(
"backdrill.kicad_pcb" ) );
951 board->SetFileName( boardFile.GetFullPath() );
953 wxFileName reportFile( tempDir.GetFullPath(), wxT(
"backdrill-drl.rpt" ) );
960 wxFFile reportStream( reportFile.GetFullPath(), wxT(
"rb" ) );
961 wxString reportContents;
963 reportStream.Close();
965 struct BACKDRILL_SECTION
971 std::map<wxString, BACKDRILL_SECTION> sections;
972 wxString currentFile;
973 wxStringTokenizer lines( reportContents, wxT(
"\n" ) );
975 while( lines.HasMoreTokens() )
977 wxString line = lines.GetNextToken();
978 line.Trim(
true ).Trim(
false );
980 if( line.StartsWith( wxT(
"Drill file '" ) ) )
981 currentFile = line.AfterFirst(
'\'' ).BeforeFirst(
'\'' );
983 if( line.StartsWith( wxT(
"T" ) ) && line.Contains( wxT(
"0.330mm" ) ) )
984 sections[currentFile].toolLines++;
988 if( line.StartsWith( wxT(
"Total backdrilled holes count " ), &count ) )
992 sections[currentFile].holes = value;
998 const std::map<wxString, long>
expected = {
999 { wxT(
"backdrill_Backdrills_Drill_1_4.drl" ), 2 },
1000 { wxT(
"backdrill_Backdrills_Drill_10_4.drl" ), 1 },
1001 { wxT(
"backdrill_Backdrills_Drill_10_7.drl" ), 1 }
1007 for(
const auto& [file, holes] :
expected )
1009 auto section = sections.find( file );
1011 if( section == sections.end() )
1013 BOOST_ERROR(
"No backdrill section for " << file );
1024 BOOST_CHECK( reportContents.Contains( wxT(
"Total plated holes count 4" ) ) );
1025 BOOST_CHECK( reportContents.Contains( wxT(
"Total unplated holes count 0" ) ) );
1027 wxFileName::Rmdir( tempDir.GetFullPath(), wxPATH_RMDIR_RECURSIVE );
constexpr EDA_IU_SCALE pcbIUScale
General utilities for PCB file IO for QA programs.
virtual void SetNet(NETINFO_ITEM *aNetInfo)
Set a NET_INFO object for the item.
void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
Information pertinent to a Pcbnew printed circuit board.
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Removes an item from the container.
void SetFileName(const wxString &aFileName)
void SetCopperLayerCount(int aCount)
virtual void SetFilled(bool aFlag)
Create Excellon drill, drill map, and drill report files.
void SetFormat(bool aMetric, ZEROS_FMT aZerosFmt=DECIMAL_FORMAT, int aLeftDigits=0, int aRightDigits=0)
Initialize internal parameters to match the given format.
bool CreateDrillandMapFilesSet(const wxString &aPlotDirectory, bool aGenDrill, bool aGenMap, REPORTER *aReporter=nullptr)
Create the full set of Excellon drill file for the board.
void SetOptions(bool aMirror, bool aMinimalHeader, const VECTOR2I &aOffset, bool aMerge_PTH_NPTH)
Initialize internal parameters to match drill options.
bool GenDrillReportFile(const wxString &aFullFileName, REPORTER *aReporter=nullptr)
Create a plain text report file giving a list of drill values and drill count for through holes,...
Used to create Gerber drill files.
bool CreateDrillandMapFilesSet(const wxString &aPlotDirectory, bool aGenDrill, bool aGenMap, bool aGenTenting, REPORTER *aReporter=nullptr)
Create the full set of Excellon drill file for the board filenames are computed from the board name,...
void SetOptions(const VECTOR2I &aOffset)
Initialize internal parameters to match drill options.
void SetFormat(int aRightDigits=6)
Initialize internal parameters to match the given format.
wxString PathStr() const
Get the path to the temporary directory as a wxString.
Handle the data for a net.
@ NORMAL
Shape is the same on all layers.
static constexpr PCB_LAYER_ID ALL_LAYERS
! The layer identifier to use for the single defintion on normal padstacks
static LSET PTHMask()
layer set for a through hole pad
static LSET UnplatedHoleMask()
layer set for a mechanical unplated through hole pad
void SetMid(const VECTOR2I &aMid)
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...
void SetWidth(int aWidth) override
void SetEnd(const VECTOR2I &aEnd) override
void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
void SetStart(const VECTOR2I &aStart) override
void SetEnd(const VECTOR2I &aEnd)
void SetStart(const VECTOR2I &aStart)
virtual void SetWidth(int aWidth)
void SetSecondaryDrillStartLayer(PCB_LAYER_ID aLayer)
void SetTertiaryDrillEndLayer(PCB_LAYER_ID aLayer)
void SetDrill(int aDrill)
void SetPadstackMode(PADSTACK::MODE aMode)
void SetSecondaryDrillEndLayer(PCB_LAYER_ID aLayer)
void SetPosition(const VECTOR2I &aPoint) override
void SetLayerPair(PCB_LAYER_ID aTopLayer, PCB_LAYER_ID aBottomLayer)
For a via m_layer contains the top layer, the other layer is in m_bottomLayer/.
void SetTertiaryDrillStartLayer(PCB_LAYER_ID aLayer)
void SetTertiaryDrillSize(const VECTOR2I &aSize)
void SetSecondaryDrillSize(const VECTOR2I &aSize)
void SetWidth(int aWidth) override
std::vector< DRILL_SPAN > EnumerateDrillSpans(const BOARD &aBoard, bool aPadBackdrills)
Every drill span present on the board, through-holes first.
std::vector< DRILL_OPERATION > EnumerateDrillOperations(const BOARD &aBoard, const DRILL_QUERY &aQuery)
The one place that decides what the board's holes are.
@ RECTANGLE
Use RECTANGLE instead of RECT to avoid collision in a Windows header.
Classes used in drill files, map files and report files generation.
Classes used in drill files, map files and report files generation.
std::string GetPcbnewTestDataDir()
Utility which returns a path to the data directory where the test board files are stored.
void LoadBoard(SETTINGS_MANAGER &aSettingsManager, const wxString &aRelPath, std::unique_ptr< BOARD > &aBoard)
std::unique_ptr< BOARD > ReadBoardFromFileOrStream(const std::string &aFilename, std::istream &aFallback)
Read a board from a file, or another stream, as appropriate.
PAD_ATTRIB
The set of pad shapes, used with PAD::{Set,Get}Attribute().
@ NPTH
like PAD_PTH, but not plated mechanical use only, no connection allowed
@ PTH
Plated through hole pad.
static bool readFile(const wxString &aFileName, wxString &aOut, size_t aLimit=0)
Read a file into aOut.
One machining action, which is also one NC hit and one tool assignment.
Selects which operations EnumerateDrillOperations() returns.
static wxString ReadOdbLayerFeatures(const wxFileName &aOdbRoot, const wxString &aLayerDir)
static wxFileName ExportOdbTree(BOARD *aBoard, const wxFileName &aTempDir)
BOOST_AUTO_TEST_CASE(GerberDrillBoardDefaultsCreateProtectionFiles)
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
VECTOR3I expected(15, 30, 45)
BOOST_CHECK_EQUAL(result, "25.4")
VECTOR2< int32_t > VECTOR2I