KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_cadstar_archive_parser.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
24
26
28
29#include <qa_utils/geometry/geometry.h> // For KI_TEST::IsVecWithinTol
31#include <geometry/shape_arc.h> // For SHAPE_ARC::DefaultAccuracyForPCB()
32#include <wx/log.h>
33
34#include <ki_exception.h>
35#include <xnode.h>
36
37
38BOOST_AUTO_TEST_SUITE( CadstartArchiveParser )
39
40
48
49 std::function<wxPoint( const wxPoint& )> m_CadstarToKicadPointCallback;
50
52
53
54static const std::vector<VERTEX_APPEND_CASE> appendToChainCases
55{
56 {
57 "Append a point on x",
58 { vt::VT_POINT, { 500000, 0 } },
59 { /* BBOX Position: */ { 0, 0 }, /* Size:*/ { 500000, 0 } },
60 0
61 },
62 {
63 "Append a point on y",
64 { vt::VT_POINT, { 0, 500000 } },
65 { /* BBOX Position: */ { 0, 0 }, /* Size:*/ { 0, 500000 } },
66 0
67 },
68 {
69 "Append a Semicircle (clockwise)",
70 { vt::CLOCKWISE_SEMICIRCLE, { 500000, 0 } },
71 { /* BBOX Position: */ { 0, 0 }, /* Size: */ { 500000, 250000 } },
72 int( SHAPE_ARC::DefaultAccuracyForPCB() ) // acceptable error when converting to line segments
73 },
74 {
75 "Append a Semicircle (anticlockwise)",
76 { vt::ANTICLOCKWISE_SEMICIRCLE, { 500000, 0 } },
77 { /* BBOX Position: */ { 0, -250000 }, /* Size: */ { 500000, 250000 } },
78 int( SHAPE_ARC::DefaultAccuracyForPCB() ) // acceptable error when converting to line segments
79 },
80 {
81 "Append a 90 degree Arc (clockwise)",
82 { vt::CLOCKWISE_ARC, { 250000, 250000 }, { 250000, 0 } },
83 { /* BBOX Position: */ { 0, 0 }, /* Size: */ { 250000, 250000 } },
84 int( SHAPE_ARC::DefaultAccuracyForPCB() ) // acceptable error when converting to line segments
85 },
86 {
87 "Append a 90 degree Arc (anticlockwise)",
88 { vt::ANTICLOCKWISE_ARC, { 250000, -250000 }, { 250000, 0 } },
89 { /* BBOX Position: */ { 0, -250000 }, /* Size: */ { 250000, 250000 } },
90 int( SHAPE_ARC::DefaultAccuracyForPCB() ) // acceptable error when converting to line segments
91 },
92};
93
94
95
96BOOST_AUTO_TEST_CASE( AppendToChain )
97{
98 static const std::vector<VECTOR2D> coordinateMultipliers =
99 {
100 { 0.1, 0.1 },
101 { 0.1, -0.1 }, // y inversion
102 { 1, 1 },
103 { 1, -1 }, // y inversion
104 { 10, 10 },
105 { 10, -10 } // y inversion
106 };
107
108
109 for( const auto& c : appendToChainCases )
110 {
111 BOOST_TEST_INFO_SCOPE( c.m_CaseName );
112
113 for( const VECTOR2D& mult : coordinateMultipliers )
114 {
115 BOOST_TEST_INFO_SCOPE( "Applied scaling x=" << mult.x << " y=" << mult.y );
116
117 SHAPE_LINE_CHAIN chain( { 0, 0 } ); // starting chain contains a point at 0,0
118
119 auto transformCoord =
120 [&]( const VECTOR2I& aPt ) -> VECTOR2I
121 {
122 int x = double( aPt.x ) * mult.x;
123 int y = double( aPt.y ) * mult.y;
124 return { x, y };
125 };
126
127 c.m_VertexToAppend.AppendToChain( &chain, transformCoord, SCH_IU_PER_MM * 0.01 );
128
129 BOX2I expBoxTransformed;
130 expBoxTransformed.SetOrigin( transformCoord( c.m_ExpBBox.GetPosition() ) );
131 expBoxTransformed.SetSize( transformCoord( c.m_ExpBBox.GetSize() ) );
132 expBoxTransformed.Normalize();
133
136 ( chain.BBox().GetPosition() )( expBoxTransformed.GetPosition() ) ( c.m_ExpBBoxError ) );
137
140 ( chain.BBox().GetSize() )( expBoxTransformed.GetSize() ) ( c.m_ExpBBoxError ) );
141 }
142 }
143
144}
145
150BOOST_AUTO_TEST_CASE( ParseChildErrorContext )
151{
152 XNODE parent( wxXML_ELEMENT_NODE, wxT( "VERTICES" ) );
153
154 // A "PT" node missing its required coordinate attributes triggers a parse failure.
155 new XNODE( &parent, wxXML_ELEMENT_NODE, wxT( "PT" ) );
156
157 auto messageMentionsSection =
158 []( const IO_ERROR& aError ) -> bool
159 {
160 return aError.What().Contains( wxT( "VERTICES" ) );
161 };
162
163 BOOST_CHECK_EXCEPTION(
164 CADSTAR_ARCHIVE_PARSER::ParseAllChildPoints( &parent, nullptr, true ),
165 IO_ERROR, messageMentionsSection );
166}
167
172static void AddCadstarAttributes( XNODE* aNode, const std::vector<wxString>& aValues )
173{
174 for( size_t i = 0; i < aValues.size(); ++i )
175 {
176 wxString attrName = wxString::Format( wxT( "attr%zu" ), i );
177 aNode->AddAttribute( attrName, aValues[i] );
178 }
179
180 aNode->AddAttribute( wxT( "numAttributes" ),
181 wxString::Format( wxT( "%zu" ), aValues.size() ) );
182}
183
184
189BOOST_AUTO_TEST_CASE( UnknownNodeInHeaderDoesNotThrow )
190{
191 wxLogNull suppress; // Suppress wxLogWarning messages during this test
192
193 XNODE headerNode( wxXML_ELEMENT_NODE, wxT( "HEADER" ) );
194
195 XNODE* formatNode = new XNODE( wxXML_ELEMENT_NODE, wxT( "FORMAT" ) );
196 AddCadstarAttributes( formatNode, { wxT( "REGULAR" ), wxT( "1" ), wxT( "21" ) } );
197 headerNode.AddChild( formatNode );
198
199 XNODE* unknownNode = new XNODE( wxXML_ELEMENT_NODE, wxT( "FUTURE_FEATURE" ) );
200 headerNode.AddChild( unknownNode );
201
204
205 BOOST_CHECK_NO_THROW( header.Parse( &headerNode, &ctx ) );
206 BOOST_CHECK_EQUAL( header.Format.Type, wxT( "REGULAR" ) );
207}
208
209
214BOOST_AUTO_TEST_CASE( UnknownNodeInRouteCodeDoesNotThrow )
215{
216 wxLogNull suppress;
217
218 XNODE routeCodeNode( wxXML_ELEMENT_NODE, wxT( "ROUTECODE" ) );
219 AddCadstarAttributes( &routeCodeNode, { wxT( "RC1" ), wxT( "Default" ), wxT( "1000" ) } );
220
221 XNODE* neckNode = new XNODE( wxXML_ELEMENT_NODE, wxT( "NECKWIDTH" ) );
222 AddCadstarAttributes( neckNode, { wxT( "500" ) } );
223 routeCodeNode.AddChild( neckNode );
224
225 XNODE* unknownNode = new XNODE( wxXML_ELEMENT_NODE, wxT( "NEWFEATURE_V25" ) );
226 routeCodeNode.AddChild( unknownNode );
227
230
231 BOOST_CHECK_NO_THROW( routecode.Parse( &routeCodeNode, &ctx ) );
232 BOOST_CHECK_EQUAL( routecode.ID, wxT( "RC1" ) );
233 BOOST_CHECK_EQUAL( routecode.NeckedWidth, 500 );
234}
235
236
241BOOST_AUTO_TEST_CASE( UnknownAlignmentReturnsDefault )
242{
243 wxLogNull suppress;
244
245 XNODE alignNode( wxXML_ELEMENT_NODE, wxT( "ALIGN" ) );
246 AddCadstarAttributes( &alignNode, { wxT( "FUTURE_ALIGNMENT" ) } );
247
249
250 BOOST_CHECK_NO_THROW( result = CADSTAR_ARCHIVE_PARSER::ParseAlignment( &alignNode ) );
251 BOOST_CHECK_EQUAL( static_cast<int>( result ),
253}
254
255
259BOOST_AUTO_TEST_CASE( UnknownReadabilityReturnsDefault )
260{
261 wxLogNull suppress;
262
263 XNODE readNode( wxXML_ELEMENT_NODE, wxT( "READABILITY" ) );
264 AddCadstarAttributes( &readNode, { wxT( "LEFT_TO_RIGHT" ) } );
265
267
268 BOOST_CHECK_NO_THROW( result = CADSTAR_ARCHIVE_PARSER::ParseReadability( &readNode ) );
269 BOOST_CHECK_EQUAL( static_cast<int>( result ),
271}
272
273
278BOOST_AUTO_TEST_CASE( CheckNoChildNodesWarnsInsteadOfThrowing )
279{
280 wxLogNull suppress;
281
282 XNODE parentNode( wxXML_ELEMENT_NODE, wxT( "PARENT" ) );
283 XNODE* childNode = new XNODE( wxXML_ELEMENT_NODE, wxT( "UNEXPECTED" ) );
284 parentNode.AddChild( childNode );
285
286 BOOST_CHECK_NO_THROW( CADSTAR_ARCHIVE_PARSER::CheckNoChildNodes( &parentNode ) );
287}
288
289
290BOOST_AUTO_TEST_CASE( CheckNoNextNodesWarnsInsteadOfThrowing )
291{
292 wxLogNull suppress;
293
294 XNODE parentNode( wxXML_ELEMENT_NODE, wxT( "PARENT" ) );
295 XNODE* child1 = new XNODE( wxXML_ELEMENT_NODE, wxT( "CHILD1" ) );
296 XNODE* child2 = new XNODE( wxXML_ELEMENT_NODE, wxT( "CHILD2" ) );
297 parentNode.AddChild( child1 );
298 parentNode.AddChild( child2 );
299
300 BOOST_CHECK_NO_THROW( CADSTAR_ARCHIVE_PARSER::CheckNoNextNodes( child1 ) );
301}
302
303
307BOOST_AUTO_TEST_CASE( UnknownUnitsReturnsDefault )
308{
309 wxLogNull suppress;
310
311 XNODE unitsNode( wxXML_ELEMENT_NODE, wxT( "UNITS" ) );
312 AddCadstarAttributes( &unitsNode, { wxT( "FUTURISTIC_UNIT" ) } );
313
315
316 BOOST_CHECK_NO_THROW( result = CADSTAR_ARCHIVE_PARSER::ParseUnits( &unitsNode ) );
317 BOOST_CHECK_EQUAL( static_cast<int>( result ),
318 static_cast<int>( CADSTAR_ARCHIVE_PARSER::UNITS::DESIGN ) );
319}
320
321
325BOOST_AUTO_TEST_CASE( UnknownPinTypeReturnsDefault )
326{
327 wxLogNull suppress;
328
329 XNODE pinTypeNode( wxXML_ELEMENT_NODE, wxT( "PINTYPE" ) );
330 AddCadstarAttributes( &pinTypeNode, { wxT( "FUTURE_PIN_TYPE" ) } );
331
333
334 BOOST_CHECK_NO_THROW( result = CADSTAR_ARCHIVE_PARSER::PART::GetPinType( &pinTypeNode ) );
335 BOOST_CHECK_EQUAL( static_cast<int>( result ),
336 static_cast<int>( CADSTAR_PIN_TYPE::UNCOMMITTED ) );
337}
338
339
341
constexpr double SCH_IU_PER_MM
Schematic internal units 1=100nm.
Definition base_units.h:70
BOX2< VECTOR2I > BOX2I
Definition box2.h:918
CADSTAR_PIN_TYPE
file: cadstar_archive_objects.h Contains common object definitions
@ UNCOMMITTED
Uncommitted pin (default)
Helper functions and common defines between schematic and PCB Archive files.
constexpr const Vec & GetPosition() const
Definition box2.h:207
constexpr void SetOrigin(const Vec &pos)
Definition box2.h:233
constexpr BOX2< Vec > & Normalize()
Ensure that the height and width are positive.
Definition box2.h:142
constexpr void SetSize(const SizeVec &size)
Definition box2.h:244
constexpr const SizeVec & GetSize() const
Definition box2.h:202
READABILITY
Sets the readability direction of text.
@ BOTTOM_TO_TOP
When text is vertical, show it rotated 90 degrees anticlockwise.
static UNITS ParseUnits(XNODE *aNode)
static ALIGNMENT ParseAlignment(XNODE *aNode)
ALIGNMENT
From CADSTAR Help: "Text Alignment enables you to define the position of an alignment origin for all ...
@ NO_ALIGNMENT
NO_ALIGNMENT has different meaning depending on the object type.
static void CheckNoNextNodes(XNODE *aNode)
static READABILITY ParseReadability(XNODE *aNode)
static std::vector< POINT > ParseAllChildPoints(XNODE *aNode, PARSER_CONTEXT *aContext, bool aTestAllChildNodes=false, int aExpectedNumPoints=UNDEFINED_VALUE)
If no children are present, it just returns an empty vector (without throwing an exception).
@ DESIGN
Inherits from design units (assumed Assignments->Technology->Units)
static void CheckNoChildNodes(XNODE *aNode)
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
static int DefaultAccuracyForPCB()
Definition shape_arc.h:279
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
An extension of wxXmlNode that can format its contents as KiCad-style s-expressions.
Definition xnode.h:67
void AddAttribute(const wxString &aName, const wxString &aValue) override
Definition xnode.cpp:88
bool IsVecWithinTol(const VEC &aVec, const VEC &aExp, typename VEC::coord_type aTol)
Check that both x and y of a vector are within expected error.
Definition geometry.h:51
static void formatNode(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const std::string &aKey, const CPTREE &aTree)
Definition ptree.cpp:160
static CADSTAR_PIN_TYPE GetPinType(XNODE *aNode)
void Parse(XNODE *aNode, PARSER_CONTEXT *aContext) override
Represents a vertex in a shape.
CADSTAR_ARCHIVE_PARSER::VERTEX m_VertexToAppend
BOOST_AUTO_TEST_CASE(AppendToChain)
CADSTAR_ARCHIVE_PARSER::VERTEX_TYPE vt
static void AddCadstarAttributes(XNODE *aNode, const std::vector< wxString > &aValues)
Helper to add "attr0", "attr1", ... attributes to an XNODE, matching the format used by the CADSTAR S...
static const std::vector< VERTEX_APPEND_CASE > appendToChainCases
std::function< wxPoint(const wxPoint &)> m_CadstarToKicadPointCallback
BOOST_AUTO_TEST_SUITE(CadstarPartParser)
BOOST_AUTO_TEST_SUITE_END()
std::vector< std::string > header
const SHAPE_LINE_CHAIN chain
BOOST_CHECK_PREDICATE(ArePolylineEndPointsNearCircle,(chain)(c.m_geom.m_center_point)(radius)(accuracy+epsilon))
wxString result
Test unit parsing edge cases and error handling.
BOOST_CHECK_EQUAL(result, "25.4")
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683
VECTOR2< double > VECTOR2D
Definition vector2d.h:682