2020-08-10 14:55:16 +00:00
|
|
|
/*
|
|
|
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
|
|
*
|
2021-10-06 02:46:53 +00:00
|
|
|
* Copyright (C) 2019-2021 KiCad Developers, see AUTHORS.TXT for contributors.
|
2020-08-10 14:55:16 +00:00
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, you may find one here:
|
|
|
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
|
|
|
* or you may search the http://www.gnu.org website for the version 2 license,
|
|
|
|
* or you may write to the Free Software Foundation, Inc.,
|
|
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
|
|
|
*/
|
|
|
|
|
2020-10-01 13:39:34 +00:00
|
|
|
#include <wx/wx.h>
|
|
|
|
|
2021-02-06 22:20:31 +00:00
|
|
|
#include <qa_utils/wx_utils/unit_test_utils.h>
|
2020-08-10 14:55:16 +00:00
|
|
|
|
2021-07-29 09:47:43 +00:00
|
|
|
#include <layer_ids.h>
|
2020-08-10 14:55:16 +00:00
|
|
|
#include <pcbnew/pcb_expr_evaluator.h>
|
2022-04-02 14:08:32 +00:00
|
|
|
#include <drc/drc_rule.h>
|
2020-11-12 20:19:22 +00:00
|
|
|
#include <pcbnew/board.h>
|
2021-06-11 21:07:02 +00:00
|
|
|
#include <pcbnew/pcb_track.h>
|
2020-08-10 15:14:14 +00:00
|
|
|
|
2020-08-10 14:55:16 +00:00
|
|
|
BOOST_AUTO_TEST_SUITE( Libeval_Compiler )
|
|
|
|
|
|
|
|
struct EXPR_TO_TEST
|
|
|
|
{
|
|
|
|
wxString expression;
|
|
|
|
bool expectError;
|
|
|
|
LIBEVAL::VALUE expectedResult;
|
|
|
|
};
|
|
|
|
|
|
|
|
using VAL = LIBEVAL::VALUE;
|
|
|
|
|
2020-10-01 13:39:34 +00:00
|
|
|
const static std::vector<EXPR_TO_TEST> simpleExpressions = {
|
2020-08-10 14:55:16 +00:00
|
|
|
{ "10mm + 20 mm", false, VAL( 30e6 ) },
|
2020-10-01 13:39:34 +00:00
|
|
|
{ "3*(7+8)", false, VAL( 3 * ( 7 + 8 ) ) },
|
2020-08-10 14:55:16 +00:00
|
|
|
{ "3*7+8", false, VAL( 3 * 7 + 8 ) },
|
2020-10-01 13:39:34 +00:00
|
|
|
{ "(3*7)+8", false, VAL( 3 * 7 + 8 ) },
|
2020-08-10 14:55:16 +00:00
|
|
|
{ "10mm + 20)", true, VAL( 0 ) },
|
|
|
|
|
|
|
|
{ "1", false, VAL(1) },
|
|
|
|
{ "1.5", false, VAL(1.5) },
|
|
|
|
{ "1,5", false, VAL(1.5) },
|
|
|
|
{ "1mm", false, VAL(1e6) },
|
|
|
|
// Any White-space is OK
|
|
|
|
{ " 1 + 2 ", false, VAL(3) },
|
|
|
|
// Decimals are OK in expressions
|
|
|
|
{ "1.5 + 0.2 + 0.1", false, VAL(1.8) },
|
|
|
|
// Negatives are OK
|
|
|
|
{ "3 - 10", false, VAL(-7) },
|
|
|
|
// Lots of operands
|
|
|
|
{ "1 + 2 + 10 + 1000.05", false, VAL(1013.05) },
|
|
|
|
// Operator precedence
|
|
|
|
{ "1 + 2 - 4 * 20 / 2", false, VAL(-37) },
|
|
|
|
// Parens
|
|
|
|
{ "(1)", false, VAL(1) },
|
|
|
|
// Parens affect precedence
|
|
|
|
{ "-(1 + (2 - 4)) * 20.8 / 2", false, VAL(10.4) },
|
|
|
|
// Unary addition is a sign, not a leading operator
|
|
|
|
{ "+2 - 1", false, VAL(1) }
|
2020-08-10 15:14:14 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const static std::vector<EXPR_TO_TEST> introspectionExpressions = {
|
2020-09-27 17:05:16 +00:00
|
|
|
{ "A.type == 'Pad' && B.type == 'Pad' && (A.existsOnLayer('F.Cu'))", false, VAL( 0.0 ) },
|
2020-08-10 15:14:14 +00:00
|
|
|
{ "A.Width > B.Width", false, VAL( 0.0 ) },
|
|
|
|
{ "A.Width + B.Width", false, VAL( Mils2iu(10) + Mils2iu(20) ) },
|
|
|
|
{ "A.Netclass", false, VAL( "HV" ) },
|
|
|
|
{ "(A.Netclass == 'HV') && (B.netclass == 'otherClass') && (B.netclass != 'F.Cu')", false, VAL( 1.0 ) },
|
|
|
|
{ "A.Netclass + 1.0", false, VAL( 1.0 ) },
|
|
|
|
{ "A.type == 'Track' && B.type == 'Track' && A.layer == 'F.Cu'", false, VAL( 1.0 ) },
|
2020-08-26 22:00:42 +00:00
|
|
|
{ "(A.type == 'Track') && (B.type == 'Track') && (A.layer == 'F.Cu')", false, VAL( 1.0 ) },
|
|
|
|
{ "A.type == 'Via' && A.isMicroVia()", false, VAL(0.0) }
|
2020-08-10 15:14:14 +00:00
|
|
|
};
|
|
|
|
|
2020-08-10 14:55:16 +00:00
|
|
|
|
|
|
|
static bool testEvalExpr( const wxString& expr, LIBEVAL::VALUE expectedResult,
|
2021-01-12 12:52:15 +00:00
|
|
|
bool expectError = false, BOARD_ITEM* itemA = nullptr,
|
|
|
|
BOARD_ITEM* itemB = nullptr )
|
2020-08-10 14:55:16 +00:00
|
|
|
{
|
|
|
|
PCB_EXPR_COMPILER compiler;
|
|
|
|
PCB_EXPR_UCODE ucode;
|
2022-04-02 14:08:32 +00:00
|
|
|
PCB_EXPR_CONTEXT context( NULL_CONSTRAINT, UNDEFINED_LAYER );
|
|
|
|
PCB_EXPR_CONTEXT preflightContext( NULL_CONSTRAINT, UNDEFINED_LAYER );
|
2020-08-10 14:55:16 +00:00
|
|
|
bool ok = true;
|
|
|
|
|
|
|
|
context.SetItems( itemA, itemB );
|
|
|
|
|
2020-08-26 22:00:42 +00:00
|
|
|
|
2021-01-12 12:52:15 +00:00
|
|
|
BOOST_TEST_MESSAGE( "Expr: '" << expr.c_str() << "'" );
|
2020-08-26 22:00:42 +00:00
|
|
|
|
2020-08-10 14:55:16 +00:00
|
|
|
bool error = !compiler.Compile( expr, &ucode, &preflightContext );
|
|
|
|
|
|
|
|
BOOST_CHECK_EQUAL( error, expectError );
|
|
|
|
|
|
|
|
if( error != expectError )
|
|
|
|
{
|
2020-08-26 22:00:42 +00:00
|
|
|
BOOST_TEST_MESSAGE( "Result: FAIL: " << compiler.GetError().message.c_str() <<
|
|
|
|
" (code pos: " << compiler.GetError().srcPos << ")" );
|
|
|
|
|
2020-08-10 14:55:16 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( error )
|
|
|
|
return true;
|
|
|
|
|
|
|
|
LIBEVAL::VALUE result;
|
|
|
|
|
|
|
|
if( ok )
|
|
|
|
{
|
|
|
|
result = *ucode.Run( &context );
|
2021-08-16 09:53:27 +00:00
|
|
|
ok = ( result.EqualTo( &context, &expectedResult ) );
|
2020-08-10 14:55:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if( expectedResult.GetType() == LIBEVAL::VT_NUMERIC )
|
|
|
|
{
|
|
|
|
BOOST_CHECK_EQUAL( result.AsDouble(), expectedResult.AsDouble() );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
BOOST_CHECK_EQUAL( result.AsString(), expectedResult.AsString() );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOST_AUTO_TEST_CASE( SimpleExpressions )
|
|
|
|
{
|
|
|
|
for( const auto& expr : simpleExpressions )
|
|
|
|
{
|
2021-01-12 12:52:15 +00:00
|
|
|
testEvalExpr( expr.expression, expr.expectedResult, expr.expectError );
|
2020-08-10 14:55:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-10 15:14:14 +00:00
|
|
|
BOOST_AUTO_TEST_CASE( IntrospectedProperties )
|
|
|
|
{
|
|
|
|
PROPERTY_MANAGER& propMgr = PROPERTY_MANAGER::Instance();
|
|
|
|
propMgr.Rebuild();
|
|
|
|
|
|
|
|
BOARD brd;
|
|
|
|
|
|
|
|
NETINFO_LIST& netInfo = brd.GetNetInfo();
|
|
|
|
|
2021-01-12 12:52:15 +00:00
|
|
|
NETCLASSPTR netclass1( new NETCLASS( "HV" ) );
|
|
|
|
NETCLASSPTR netclass2( new NETCLASS( "otherClass" ) );
|
2020-08-10 15:14:14 +00:00
|
|
|
|
2021-01-12 12:52:15 +00:00
|
|
|
auto net1info = new NETINFO_ITEM( &brd, "net1", 1 );
|
|
|
|
auto net2info = new NETINFO_ITEM( &brd, "net2", 2 );
|
2020-08-10 15:14:14 +00:00
|
|
|
|
2020-12-08 13:02:08 +00:00
|
|
|
net1info->SetNetClass( netclass1 );
|
|
|
|
net2info->SetNetClass( netclass2 );
|
2020-08-10 15:14:14 +00:00
|
|
|
|
2021-06-11 21:07:02 +00:00
|
|
|
PCB_TRACK trackA( &brd );
|
|
|
|
PCB_TRACK trackB( &brd );
|
2020-08-10 15:14:14 +00:00
|
|
|
|
|
|
|
trackA.SetNet( net1info );
|
|
|
|
trackB.SetNet( net2info );
|
|
|
|
|
|
|
|
trackB.SetLayer( F_Cu );
|
|
|
|
|
2021-01-12 12:52:15 +00:00
|
|
|
trackA.SetWidth( Mils2iu( 10 ) );
|
|
|
|
trackB.SetWidth( Mils2iu( 20 ) );
|
2020-08-10 15:14:14 +00:00
|
|
|
|
|
|
|
for( const auto& expr : introspectionExpressions )
|
|
|
|
{
|
2021-01-12 12:52:15 +00:00
|
|
|
testEvalExpr( expr.expression, expr.expectedResult, expr.expectError, &trackA, &trackB );
|
2020-08-10 15:14:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-18 14:17:16 +00:00
|
|
|
BOOST_AUTO_TEST_SUITE_END()
|