KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_d356_export.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 <boost/test/unit_test.hpp>
21
22#include <filesystem>
23#include <fstream>
24#include <memory>
25#include <string>
26
27#include <board.h>
29#include <pcb_track.h>
31
32#include <wx/string.h>
33
34
35namespace
36{
37std::string trim( const std::string& aStr )
38{
39 const size_t begin = aStr.find_first_not_of( ' ' );
40
41 if( begin == std::string::npos )
42 return std::string();
43
44 const size_t end = aStr.find_last_not_of( ' ' );
45
46 return aStr.substr( begin, end - begin + 1 );
47}
48} // namespace
49
50
51/*
52 * IPC-D-356A column 32 carries the midpoint flag ('M' = a mid-net access point,
53 * blank = an end-net point / component terminal). Vias and unnamed copper features
54 * are mid-net; named component pins are end-net. The fixture exercises all three.
55 */
56BOOST_AUTO_TEST_CASE( ExportD356MidpointFlag )
57{
58 const std::filesystem::path boardPath =
59 std::filesystem::path( KI_TEST::GetPcbnewTestDataDir() ) / "issue3812.kicad_pcb";
60
61 BOOST_REQUIRE( std::filesystem::exists( boardPath ) );
62
63 std::unique_ptr<BOARD> board = KI_TEST::ReadBoardFromFileOrStream( boardPath.string() );
64 BOOST_REQUIRE( board );
65
66 const std::filesystem::path outputPath =
67 std::filesystem::temp_directory_path() / "kicad_d356_midpoint_test.d356";
68
69 IPC356D_WRITER writer( board.get() );
70 BOOST_REQUIRE( writer.Write( wxString::FromUTF8( outputPath.string().c_str() ) ) );
71
72 std::ifstream in( outputPath );
73 BOOST_REQUIRE( in.is_open() );
74
75 // The soldermask field encodes which sides are tented; derive the expectation from the
76 // board's vias (the fixture tents them uniformly) rather than hardcoding a value.
77 int expectedViaMask = -1;
78
79 for( PCB_TRACK* track : board->Tracks() )
80 {
81 if( track->Type() != PCB_VIA_T )
82 continue;
83
84 PCB_VIA* via = static_cast<PCB_VIA*>( track );
85 const int mask = ( via->IsTented( F_Mask ) ? 1 : 0 ) | ( via->IsTented( B_Mask ) ? 2 : 0 );
86
87 if( expectedViaMask < 0 )
88 expectedViaMask = mask;
89 else
90 BOOST_REQUIRE_EQUAL( mask, expectedViaMask );
91 }
92
93 std::string line;
94 int namedPads = 0;
95 int unnamedPads = 0;
96 int vias = 0;
97
98 while( std::getline( in, line ) )
99 {
100 // Only 3xx test-point records carry the midpoint flag in column 32
101 if( line.size() < 32 || line[0] != '3' )
102 continue;
103
104 const std::string refdes = trim( line.substr( 20, 6 ) );
105 const std::string pin = trim( line.substr( 27, 4 ) );
106 const char midpoint = line[31];
107
108 if( refdes == "VIA" )
109 {
110 ++vias;
111 BOOST_CHECK_EQUAL( midpoint, 'M' );
112
113 // 'S' cannot occur in the fixed-format fields after column 32, so the last one
114 // starts the soldermask field
115 const size_t sPos = line.rfind( 'S' );
116 BOOST_REQUIRE( sPos != std::string::npos && sPos > 31 );
117 BOOST_CHECK_EQUAL( std::stoi( line.substr( sPos + 1 ) ), expectedViaMask );
118 }
119 else if( pin.empty() )
120 {
121 ++unnamedPads;
122 BOOST_CHECK_EQUAL( midpoint, 'M' );
123 }
124 else
125 {
126 ++namedPads;
127 BOOST_CHECK_EQUAL( midpoint, ' ' );
128 }
129 }
130
131 // Guard against a silently trivial pass by requiring each record class
132 BOOST_CHECK_GT( namedPads, 0 );
133 BOOST_CHECK_GT( unnamedPads, 0 );
134 BOOST_CHECK_GT( vias, 0 );
135
136 std::filesystem::remove( outputPath );
137}
General utilities for PCB file IO for QA programs.
Wrapper to expose an API for writing IPC-D356 files.
Definition export_d356.h:54
bool Write(const wxString &aFilename)
Generates and writes the netlist to a given path.
@ B_Mask
Definition layer_ids.h:94
@ F_Mask
Definition layer_ids.h:93
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.
BOOST_AUTO_TEST_CASE(ExportD356MidpointFlag)
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
KIBIS_PIN * pin
VECTOR2I end
BOOST_CHECK_EQUAL(result, "25.4")
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition typeinfo.h:90