KiCad PCB EDA Suite
test_libeval_compiler.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 (C) 2019-2020 KiCad Developers, see CHANGELOG.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 
24 #include <wx/wx.h>
25 
27 
30 
31 #include <pcbnew/class_board.h>
32 #include <pcbnew/class_track.h>
33 
34 BOOST_AUTO_TEST_SUITE( Libeval_Compiler )
35 
37 {
38  wxString expression;
41 };
42 
44 
45 const static std::vector<EXPR_TO_TEST> simpleExpressions = {
46  { "10mm + 20 mm", false, VAL( 30e6 ) },
47  { "3*(7+8)", false, VAL( 3 * ( 7 + 8 ) ) },
48  { "3*7+8", false, VAL( 3 * 7 + 8 ) },
49  { "(3*7)+8", false, VAL( 3 * 7 + 8 ) },
50  { "10mm + 20)", true, VAL( 0 ) },
51 
52  { "1", false, VAL(1) },
53  { "1.5", false, VAL(1.5) },
54  { "1,5", false, VAL(1.5) },
55  { "1mm", false, VAL(1e6) },
56  // Any White-space is OK
57  { " 1 + 2 ", false, VAL(3) },
58  // Decimals are OK in expressions
59  { "1.5 + 0.2 + 0.1", false, VAL(1.8) },
60  // Negatives are OK
61  { "3 - 10", false, VAL(-7) },
62  // Lots of operands
63  { "1 + 2 + 10 + 1000.05", false, VAL(1013.05) },
64  // Operator precedence
65  { "1 + 2 - 4 * 20 / 2", false, VAL(-37) },
66  // Parens
67  { "(1)", false, VAL(1) },
68  // Parens affect precedence
69  { "-(1 + (2 - 4)) * 20.8 / 2", false, VAL(10.4) },
70  // Unary addition is a sign, not a leading operator
71  { "+2 - 1", false, VAL(1) }
72 };
73 
74 
75 const static std::vector<EXPR_TO_TEST> introspectionExpressions = {
76  { "A.type == 'Pad' && B.type == 'Pad' && (A.existsOnLayer('F.Cu'))", false, VAL( 0.0 ) },
77  { "A.Width > B.Width", false, VAL( 0.0 ) },
78  { "A.Width + B.Width", false, VAL( Mils2iu(10) + Mils2iu(20) ) },
79  { "A.Netclass", false, VAL( "HV" ) },
80  { "(A.Netclass == 'HV') && (B.netclass == 'otherClass') && (B.netclass != 'F.Cu')", false, VAL( 1.0 ) },
81  { "A.Netclass + 1.0", false, VAL( 1.0 ) },
82  { "A.type == 'Track' && B.type == 'Track' && A.layer == 'F.Cu'", false, VAL( 1.0 ) },
83  { "(A.type == 'Track') && (B.type == 'Track') && (A.layer == 'F.Cu')", false, VAL( 1.0 ) },
84  { "A.type == 'Via' && A.isMicroVia()", false, VAL(0.0) }
85 };
86 
87 
88 static bool testEvalExpr( const wxString& expr, LIBEVAL::VALUE expectedResult,
89  bool expectError = false, BOARD_ITEM* itemA = nullptr, BOARD_ITEM* itemB = nullptr )
90 {
91  PCB_EXPR_COMPILER compiler;
92  PCB_EXPR_UCODE ucode;
93  PCB_EXPR_CONTEXT context, preflightContext;
94  bool ok = true;
95 
96  context.SetItems( itemA, itemB );
97 
98 
99  BOOST_TEST_MESSAGE("Expr: '" << expr.c_str() << "'");
100 
101  bool error = !compiler.Compile( expr, &ucode, &preflightContext );
102 
103  BOOST_CHECK_EQUAL( error, expectError );
104 
105  if( error != expectError )
106  {
107  BOOST_TEST_MESSAGE( "Result: FAIL: " << compiler.GetError().message.c_str() <<
108  " (code pos: " << compiler.GetError().srcPos << ")" );
109 
110  return false;
111  }
112 
113  if( error )
114  return true;
115 
116  LIBEVAL::VALUE result;
117 
118  if( ok )
119  {
120  result = *ucode.Run( &context );
121  ok = ( result.EqualTo( &expectedResult ) );
122  }
123 
124 
125  if( expectedResult.GetType() == LIBEVAL::VT_NUMERIC )
126  {
127  BOOST_CHECK_EQUAL( result.AsDouble(), expectedResult.AsDouble() );
128  }
129  else
130  {
131  BOOST_CHECK_EQUAL( result.AsString(), expectedResult.AsString() );
132  }
133 
134 
135  return ok;
136 }
137 
138 BOOST_AUTO_TEST_CASE( SimpleExpressions )
139 {
140  for( const auto& expr : simpleExpressions )
141  {
142  bool ok = testEvalExpr( expr.expression, expr.expectedResult, expr.expectError );
143  }
144 }
145 
146 BOOST_AUTO_TEST_CASE( IntrospectedProperties )
147 {
149  propMgr.Rebuild();
150 
151  BOARD brd;
152 
153  NETINFO_LIST& netInfo = brd.GetNetInfo();
154 
155  NETCLASSPTR netclass1( new NETCLASS("HV") );
156  NETCLASSPTR netclass2( new NETCLASS("otherClass" ) );
157 
158  auto net1info = new NETINFO_ITEM( &brd, "net1", 1);
159  auto net2info = new NETINFO_ITEM( &brd, "net2", 2);
160 
161  net1info->SetClass( netclass1 );
162  net2info->SetClass( netclass2 );
163 
164  TRACK trackA(&brd);
165  TRACK trackB(&brd);
166 
167  trackA.SetNet( net1info );
168  trackB.SetNet( net2info );
169 
170  trackB.SetLayer( F_Cu );
171 
172  trackA.SetWidth( Mils2iu( 10 ));
173  trackB.SetWidth( Mils2iu( 20 ));
174 
175  for( const auto& expr : introspectionExpressions )
176  {
177  bool ok = testEvalExpr( expr.expression, expr.expectedResult, expr.expectError, &trackA, &trackB );
178  }
179 }
180 
181 BOOST_AUTO_TEST_SUITE_END()
void Rebuild()
Rebuilds the list of all registered properties.
void SetItems(BOARD_ITEM *a, BOARD_ITEM *b=nullptr)
static PROPERTY_MANAGER & Instance()
Definition: property_mgr.h:64
LIBEVAL::VALUE expectedResult
LIBEVAL::VALUE VAL
virtual void SetLayer(PCB_LAYER_ID aLayer)
Function SetLayer sets the layer this item is on.
BOARD_ITEM is a base class for any item which can be embedded within the BOARD container class,...
const NETINFO_LIST & GetNetInfo() const
Definition: class_board.h:724
static bool testEvalExpr(const wxString &expr, LIBEVAL::VALUE expectedResult, bool expectError=false, BOARD_ITEM *itemA=nullptr, BOARD_ITEM *itemB=nullptr)
bool Compile(const wxString &aString, UCODE *aCode, CONTEXT *aPreflightContext)
A single base class (TRACK) represents both tracks and vias, with subclasses for curved tracks (ARC) ...
BOOST_AUTO_TEST_CASE(SimpleExpressions)
void SetWidth(int aWidth)
Definition: class_track.h:109
static const std::vector< EXPR_TO_TEST > introspectionExpressions
VAR_TYPE_T GetType() const
virtual bool EqualTo(const VALUE *b) const
NETINFO_LIST is a container class for NETINFO_ITEM elements, which are the nets.
Definition: netinfo.h:422
NETCLASS handles a collection of nets and the parameters used to route or test these nets.
Definition: netclass.h:49
Field Value of part, i.e. "3.3K".
const ERROR_STATUS & GetError() const
NETINFO_ITEM handles the data for a net.
Definition: netinfo.h:65
void SetNet(NETINFO_ITEM *aNetInfo)
Function SetNet Sets a NET_INFO object for the item.
Board layer functions and definitions.
virtual double AsDouble() const
Information pertinent to a Pcbnew printed circuit board.
Definition: class_board.h:186
virtual const wxString & AsString() const
static const std::vector< EXPR_TO_TEST > simpleExpressions
Provides class metadata.
Definition: property_mgr.h:61
VALUE * Run(CONTEXT *ctx)