OpcUaCanOpen
CANopen OPC-UA server
muParserTest.cpp
Go to the documentation of this file.
1 /*
2  __________
3  _____ __ __\______ \_____ _______ ______ ____ _______
4  / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \
5  | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/
6  |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__|
7  \/ \/ \/ \/
8  Copyright (C) 2013 Ingo Berg
9 
10  Permission is hereby granted, free of charge, to any person obtaining a copy of this
11  software and associated documentation files (the "Software"), to deal in the Software
12  without restriction, including without limitation the rights to use, copy, modify,
13  merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
14  permit persons to whom the Software is furnished to do so, subject to the following conditions:
15 
16  The above copyright notice and this permission notice shall be included in all copies or
17  substantial portions of the Software.
18 
19  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
20  NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
22  DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 */
25 
26 #include "muParserTest.h"
27 
28 #include <cstdio>
29 #include <cmath>
30 #include <iostream>
31 #include <limits>
32 
33 #define PARSER_CONST_PI 3.141592653589793238462643
34 #define PARSER_CONST_E 2.718281828459045235360287
35 
36 using namespace std;
37 
42 namespace mu
43 {
44  namespace Test
45  {
46  int ParserTester::c_iCount = 0;
47 
48  //---------------------------------------------------------------------------------------------
49  ParserTester::ParserTester()
50  :m_vTestFun()
51  {
65 
67  }
68 
69  //---------------------------------------------------------------------------------------------
71  {
72  if (a_szExpr[1]==0 || (a_szExpr[0]!='0' || a_szExpr[1]!='x') )
73  return 0;
74 
75  unsigned iVal(0);
76 
77  // New code based on streams for UNICODE compliance:
78  stringstream_type::pos_type nPos(0);
80  ss >> std::hex >> iVal;
81  nPos = ss.tellg();
82 
83  if (nPos==(stringstream_type::pos_type)0)
84  return 1;
85 
86  *a_iPos += (int)(2 + nPos);
87  *a_fVal = (value_type)iVal;
88  return 1;
89  }
90 
91  //---------------------------------------------------------------------------------------------
93  {
94  int iStat = 0;
95  mu::console() << _T("testing member functions...");
96 
97  // Test RemoveVar
98  value_type afVal[3] = {1,2,3};
99  Parser p;
100 
101  try
102  {
103  p.DefineVar( _T("a"), &afVal[0]);
104  p.DefineVar( _T("b"), &afVal[1]);
105  p.DefineVar( _T("c"), &afVal[2]);
106  p.SetExpr( _T("a+b+c") );
107  p.Eval();
108  }
109  catch(...)
110  {
111  iStat += 1; // this is not supposed to happen
112  }
113 
114  try
115  {
116  p.RemoveVar( _T("c") );
117  p.Eval();
118  iStat += 1; // not supposed to reach this, nonexisting variable "c" deleted...
119  }
120  catch(...)
121  {
122  // failure is expected...
123  }
124 
125  if (iStat==0)
126  mu::console() << _T("passed") << endl;
127  else
128  mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl;
129 
130  return iStat;
131  }
132 
133  //---------------------------------------------------------------------------------------------
135  {
136  int iStat = 0;
137  mu::console() << _T("testing string arguments...");
138 
139  iStat += EqnTest(_T("valueof(\"\")"), 123, true); // empty string arguments caused a crash
140  iStat += EqnTest(_T("valueof(\"aaa\")+valueof(\"bbb\") "), 246, true);
141  iStat += EqnTest(_T("2*(valueof(\"aaa\")-23)+valueof(\"bbb\")"), 323, true);
142  // use in expressions with variables
143  iStat += EqnTest(_T("a*(atof(\"10\")-b)"), 8, true);
144  iStat += EqnTest(_T("a-(atof(\"10\")*b)"), -19, true);
145  // string + numeric arguments
146  iStat += EqnTest(_T("strfun1(\"100\")"), 100, true);
147  iStat += EqnTest(_T("strfun2(\"100\",1)"), 101, true);
148  iStat += EqnTest(_T("strfun3(\"99\",1,2)"), 102, true);
149  // string constants
150  iStat += EqnTest(_T("atof(str1)+atof(str2)"), 3.33, true);
151 
152  if (iStat==0)
153  mu::console() << _T("passed") << endl;
154  else
155  mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl;
156 
157  return iStat;
158  }
159 
160  //---------------------------------------------------------------------------------------------
162  {
163  int iStat = 0;
164  mu::console() << _T("testing bulkmode...");
165 
166 #define EQN_TEST_BULK(EXPR, R1, R2, R3, R4, PASS) \
167  { \
168  double res[] = { R1, R2, R3, R4 }; \
169  iStat += EqnTestBulk(_T(EXPR), res, (PASS)); \
170  }
171 
172  // Bulk Variables for the test:
173  // a: 1,2,3,4
174  // b: 2,2,2,2
175  // c: 3,3,3,3
176  // d: 5,4,3,2
177  EQN_TEST_BULK("a", 1, 1, 1, 1, false)
178  EQN_TEST_BULK("a", 1, 2, 3, 4, true)
179  EQN_TEST_BULK("b=a", 1, 2, 3, 4, true)
180  EQN_TEST_BULK("b=a, b*10", 10, 20, 30, 40, true)
181  EQN_TEST_BULK("b=a, b*10, a", 1, 2, 3, 4, true)
182  EQN_TEST_BULK("a+b", 3, 4, 5, 6, true)
183  EQN_TEST_BULK("c*(a+b)", 9, 12, 15, 18, true)
184 #undef EQN_TEST_BULK
185 
186  if (iStat == 0)
187  mu::console() << _T("passed") << endl;
188  else
189  mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl;
190 
191  return iStat;
192  }
193 
194  //---------------------------------------------------------------------------------------------
196  {
197  int iStat = 0;
198  mu::console() << _T("testing binary operators...");
199 
200  // built in operators
201  // xor operator
202 
203  iStat += EqnTest(_T("a++b"), 3, true);
204  iStat += EqnTest(_T("a ++ b"), 3, true);
205  iStat += EqnTest(_T("1++2"), 3, true);
206  iStat += EqnTest(_T("1 ++ 2"), 3, true);
207  iStat += EqnTest(_T("a add b"), 3, true);
208  iStat += EqnTest(_T("1 add 2"), 3, true);
209  iStat += EqnTest(_T("a<b"), 1, true);
210  iStat += EqnTest(_T("b>a"), 1, true);
211  iStat += EqnTest(_T("a>a"), 0, true);
212  iStat += EqnTest(_T("a<a"), 0, true);
213  iStat += EqnTest(_T("a>a"), 0, true);
214  iStat += EqnTest(_T("a<=a"), 1, true);
215  iStat += EqnTest(_T("a<=b"), 1, true);
216  iStat += EqnTest(_T("b<=a"), 0, true);
217  iStat += EqnTest(_T("a>=a"), 1, true);
218  iStat += EqnTest(_T("b>=a"), 1, true);
219  iStat += EqnTest(_T("a>=b"), 0, true);
220 
221  // Test logical operators, especially if user defined "&" and the internal "&&" collide
222  iStat += EqnTest(_T("1 && 1"), 1, true);
223  iStat += EqnTest(_T("1 && 0"), 0, true);
224  iStat += EqnTest(_T("(a<b) && (b>a)"), 1, true);
225  iStat += EqnTest(_T("(a<b) && (a>b)"), 0, true);
226  //iStat += EqnTest(_T("12 and 255"), 12, true);
227  //iStat += EqnTest(_T("12 and 0"), 0, true);
228  iStat += EqnTest(_T("12 & 255"), 12, true);
229  iStat += EqnTest(_T("12 & 0"), 0, true);
230  iStat += EqnTest(_T("12&255"), 12, true);
231  iStat += EqnTest(_T("12&0"), 0, true);
232 
233  // Assignment operator
234  iStat += EqnTest(_T("a = b"), 2, true);
235  iStat += EqnTest(_T("a = sin(b)"), 0.909297, true);
236  iStat += EqnTest(_T("a = 1+sin(b)"), 1.909297, true);
237  iStat += EqnTest(_T("(a=b)*2"), 4, true);
238  iStat += EqnTest(_T("2*(a=b)"), 4, true);
239  iStat += EqnTest(_T("2*(a=b+1)"), 6, true);
240  iStat += EqnTest(_T("(a=b+1)*2"), 6, true);
241  iStat += EqnTest(_T("a=c, a*10"), 30, true);
242 
243  iStat += EqnTest(_T("2^2^3"), 256, true);
244  iStat += EqnTest(_T("1/2/3"), 1.0/6.0, true);
245 
246  // reference: http://www.wolframalpha.com/input/?i=3%2B4*2%2F%281-5%29^2^3
247  iStat += EqnTest(_T("3+4*2/(1-5)^2^3"), 3.0001220703125, true);
248 
249  // Test user defined binary operators
250  iStat += EqnTestInt(_T("1 | 2"), 3, true);
251  iStat += EqnTestInt(_T("1 || 2"), 1, true);
252  iStat += EqnTestInt(_T("123 & 456"), 72, true);
253  iStat += EqnTestInt(_T("(123 & 456) % 10"), 2, true);
254  iStat += EqnTestInt(_T("1 && 0"), 0, true);
255  iStat += EqnTestInt(_T("123 && 456"), 1, true);
256  iStat += EqnTestInt(_T("1 << 3"), 8, true);
257  iStat += EqnTestInt(_T("8 >> 3"), 1, true);
258  iStat += EqnTestInt(_T("9 / 4"), 2, true);
259  iStat += EqnTestInt(_T("9 % 4"), 1, true);
260  iStat += EqnTestInt(_T("if(5%2,1,0)"), 1, true);
261  iStat += EqnTestInt(_T("if(4%2,1,0)"), 0, true);
262  iStat += EqnTestInt(_T("-10+1"), -9, true);
263  iStat += EqnTestInt(_T("1+2*3"), 7, true);
264  iStat += EqnTestInt(_T("const1 != const2"), 1, true);
265  iStat += EqnTestInt(_T("const1 != const2"), 0, false);
266  iStat += EqnTestInt(_T("const1 == const2"), 0, true);
267  iStat += EqnTestInt(_T("const1 == 1"), 1, true);
268  iStat += EqnTestInt(_T("10*(const1 == 1)"), 10, true);
269  iStat += EqnTestInt(_T("2*(const1 | const2)"), 6, true);
270  iStat += EqnTestInt(_T("2*(const1 | const2)"), 7, false);
271  iStat += EqnTestInt(_T("const1 < const2"), 1, true);
272  iStat += EqnTestInt(_T("const2 > const1"), 1, true);
273  iStat += EqnTestInt(_T("const1 <= 1"), 1, true);
274  iStat += EqnTestInt(_T("const2 >= 2"), 1, true);
275  iStat += EqnTestInt(_T("2*(const1 + const2)"), 6, true);
276  iStat += EqnTestInt(_T("2*(const1 - const2)"), -2, true);
277  iStat += EqnTestInt(_T("a != b"), 1, true);
278  iStat += EqnTestInt(_T("a != b"), 0, false);
279  iStat += EqnTestInt(_T("a == b"), 0, true);
280  iStat += EqnTestInt(_T("a == 1"), 1, true);
281  iStat += EqnTestInt(_T("10*(a == 1)"), 10, true);
282  iStat += EqnTestInt(_T("2*(a | b)"), 6, true);
283  iStat += EqnTestInt(_T("2*(a | b)"), 7, false);
284  iStat += EqnTestInt(_T("a < b"), 1, true);
285  iStat += EqnTestInt(_T("b > a"), 1, true);
286  iStat += EqnTestInt(_T("a <= 1"), 1, true);
287  iStat += EqnTestInt(_T("b >= 2"), 1, true);
288  iStat += EqnTestInt(_T("2*(a + b)"), 6, true);
289  iStat += EqnTestInt(_T("2*(a - b)"), -2, true);
290  iStat += EqnTestInt(_T("a + (a << b)"), 5, true);
291  iStat += EqnTestInt(_T("-2^2"), -4, true);
292  iStat += EqnTestInt(_T("3--a"), 4, true);
293  iStat += EqnTestInt(_T("3+-3^2"), -6, true);
294 
295  // Test reading of hex values:
296  iStat += EqnTestInt(_T("0xff"), 255, true);
297  iStat += EqnTestInt(_T("10+0xff"), 265, true);
298  iStat += EqnTestInt(_T("0xff+10"), 265, true);
299  iStat += EqnTestInt(_T("10*0xff"), 2550, true);
300  iStat += EqnTestInt(_T("0xff*10"), 2550, true);
301  iStat += EqnTestInt(_T("10+0xff+1"), 266, true);
302  iStat += EqnTestInt(_T("1+0xff+10"), 266, true);
303 
304 // incorrect: '^' is yor here, not power
305 // iStat += EqnTestInt("-(1+2)^2", -9, true);
306 // iStat += EqnTestInt("-1^3", -1, true);
307 
308  // Test precedence
309  // a=1, b=2, c=3
310  iStat += EqnTestInt(_T("a + b * c"), 7, true);
311  iStat += EqnTestInt(_T("a * b + c"), 5, true);
312  iStat += EqnTestInt(_T("a<b && b>10"), 0, true);
313  iStat += EqnTestInt(_T("a<b && b<10"), 1, true);
314 
315  iStat += EqnTestInt(_T("a + b << c"), 17, true);
316  iStat += EqnTestInt(_T("a << b + c"), 7, true);
317  iStat += EqnTestInt(_T("c * b < a"), 0, true);
318  iStat += EqnTestInt(_T("c * b == 6 * a"), 1, true);
319  iStat += EqnTestInt(_T("2^2^3"), 256, true);
320 
321 
322  if (iStat==0)
323  mu::console() << _T("passed") << endl;
324  else
325  mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl;
326 
327  return iStat;
328  }
329 
330  //---------------------------------------------------------------------------------------------
333  {
334  int iStat= 0,
335  iErr = 0;
336 
337  mu::console() << "testing name restriction enforcement...";
338 
339  Parser p;
340 
341  #define PARSER_THROWCHECK(DOMAIN, FAIL, EXPR, ARG) \
342  iErr = 0; \
343  ParserTester::c_iCount++; \
344  try \
345  { \
346  p.Define##DOMAIN(EXPR, ARG); \
347  } \
348  catch(Parser::exception_type&) \
349  { \
350  iErr = (FAIL==false) ? 0 : 1; \
351  } \
352  iStat += iErr;
353 
354  // constant names
355  PARSER_THROWCHECK(Const, false, _T("0a"), 1)
356  PARSER_THROWCHECK(Const, false, _T("9a"), 1)
357  PARSER_THROWCHECK(Const, false, _T("+a"), 1)
358  PARSER_THROWCHECK(Const, false, _T("-a"), 1)
359  PARSER_THROWCHECK(Const, false, _T("a-"), 1)
360  PARSER_THROWCHECK(Const, false, _T("a*"), 1)
361  PARSER_THROWCHECK(Const, false, _T("a?"), 1)
362  PARSER_THROWCHECK(Const, true, _T("a"), 1)
363  PARSER_THROWCHECK(Const, true, _T("a_min"), 1)
364  PARSER_THROWCHECK(Const, true, _T("a_min0"), 1)
365  PARSER_THROWCHECK(Const, true, _T("a_min9"), 1)
366  // variable names
367  value_type a;
368  p.ClearConst();
369  PARSER_THROWCHECK(Var, false, _T("123abc"), &a)
370  PARSER_THROWCHECK(Var, false, _T("9a"), &a)
371  PARSER_THROWCHECK(Var, false, _T("0a"), &a)
372  PARSER_THROWCHECK(Var, false, _T("+a"), &a)
373  PARSER_THROWCHECK(Var, false, _T("-a"), &a)
374  PARSER_THROWCHECK(Var, false, _T("?a"), &a)
375  PARSER_THROWCHECK(Var, false, _T("!a"), &a)
376  PARSER_THROWCHECK(Var, false, _T("a+"), &a)
377  PARSER_THROWCHECK(Var, false, _T("a-"), &a)
378  PARSER_THROWCHECK(Var, false, _T("a*"), &a)
379  PARSER_THROWCHECK(Var, false, _T("a?"), &a)
380  PARSER_THROWCHECK(Var, true, _T("a"), &a)
381  PARSER_THROWCHECK(Var, true, _T("a_min"), &a)
382  PARSER_THROWCHECK(Var, true, _T("a_min0"), &a)
383  PARSER_THROWCHECK(Var, true, _T("a_min9"), &a)
384  PARSER_THROWCHECK(Var, false, _T("a_min9"), 0)
385  // Postfix operators
386  // fail
387  PARSER_THROWCHECK(PostfixOprt, false, _T("(k"), f1of1)
388  PARSER_THROWCHECK(PostfixOprt, false, _T("9+"), f1of1)
389  PARSER_THROWCHECK(PostfixOprt, false, _T("+"), 0)
390  // pass
391  PARSER_THROWCHECK(PostfixOprt, true, _T("-a"), f1of1)
392  PARSER_THROWCHECK(PostfixOprt, true, _T("?a"), f1of1)
393  PARSER_THROWCHECK(PostfixOprt, true, _T("_"), f1of1)
394  PARSER_THROWCHECK(PostfixOprt, true, _T("#"), f1of1)
395  PARSER_THROWCHECK(PostfixOprt, true, _T("&&"), f1of1)
396  PARSER_THROWCHECK(PostfixOprt, true, _T("||"), f1of1)
397  PARSER_THROWCHECK(PostfixOprt, true, _T("&"), f1of1)
398  PARSER_THROWCHECK(PostfixOprt, true, _T("|"), f1of1)
399  PARSER_THROWCHECK(PostfixOprt, true, _T("++"), f1of1)
400  PARSER_THROWCHECK(PostfixOprt, true, _T("--"), f1of1)
401  PARSER_THROWCHECK(PostfixOprt, true, _T("?>"), f1of1)
402  PARSER_THROWCHECK(PostfixOprt, true, _T("?<"), f1of1)
403  PARSER_THROWCHECK(PostfixOprt, true, _T("**"), f1of1)
404  PARSER_THROWCHECK(PostfixOprt, true, _T("xor"), f1of1)
405  PARSER_THROWCHECK(PostfixOprt, true, _T("and"), f1of1)
406  PARSER_THROWCHECK(PostfixOprt, true, _T("or"), f1of1)
407  PARSER_THROWCHECK(PostfixOprt, true, _T("not"), f1of1)
408  PARSER_THROWCHECK(PostfixOprt, true, _T("!"), f1of1)
409  // Binary operator
410  // The following must fail with builtin operators activated
411  // p.EnableBuiltInOp(true); -> this is the default
412  p.ClearPostfixOprt();
413  PARSER_THROWCHECK(Oprt, false, _T("+"), f1of2)
414  PARSER_THROWCHECK(Oprt, false, _T("-"), f1of2)
415  PARSER_THROWCHECK(Oprt, false, _T("*"), f1of2)
416  PARSER_THROWCHECK(Oprt, false, _T("/"), f1of2)
417  PARSER_THROWCHECK(Oprt, false, _T("^"), f1of2)
418  PARSER_THROWCHECK(Oprt, false, _T("&&"), f1of2)
419  PARSER_THROWCHECK(Oprt, false, _T("||"), f1of2)
420  // without activated built in operators it should work
421  p.EnableBuiltInOprt(false);
422  PARSER_THROWCHECK(Oprt, true, _T("+"), f1of2)
423  PARSER_THROWCHECK(Oprt, true, _T("-"), f1of2)
424  PARSER_THROWCHECK(Oprt, true, _T("*"), f1of2)
425  PARSER_THROWCHECK(Oprt, true, _T("/"), f1of2)
426  PARSER_THROWCHECK(Oprt, true, _T("^"), f1of2)
427  PARSER_THROWCHECK(Oprt, true, _T("&&"), f1of2)
428  PARSER_THROWCHECK(Oprt, true, _T("||"), f1of2)
429  #undef PARSER_THROWCHECK
430 
431  if (iStat==0)
432  mu::console() << _T("passed") << endl;
433  else
434  mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl;
435 
436  return iStat;
437  }
438 
439  //---------------------------------------------------------------------------
441  {
442  int iStat = 0;
443  mu::console() << _T("testing syntax engine...");
444 
445  iStat += ThrowTest(_T("1,"), ecUNEXPECTED_EOF); // incomplete hex definition
446  iStat += ThrowTest(_T("a,"), ecUNEXPECTED_EOF); // incomplete hex definition
447  iStat += ThrowTest(_T("sin(8),"), ecUNEXPECTED_EOF); // incomplete hex definition
448  iStat += ThrowTest(_T("(sin(8)),"), ecUNEXPECTED_EOF); // incomplete hex definition
449  iStat += ThrowTest(_T("a{m},"), ecUNEXPECTED_EOF); // incomplete hex definition
450 
451  iStat += EqnTest(_T("(1+ 2*a)"), 3, true); // Spaces within formula
452  iStat += EqnTest(_T("sqrt((4))"), 2, true); // Multiple brackets
453  iStat += EqnTest(_T("sqrt((2)+2)"), 2, true);// Multiple brackets
454  iStat += EqnTest(_T("sqrt(2+(2))"), 2, true);// Multiple brackets
455  iStat += EqnTest(_T("sqrt(a+(3))"), 2, true);// Multiple brackets
456  iStat += EqnTest(_T("sqrt((3)+a)"), 2, true);// Multiple brackets
457  iStat += EqnTest(_T("order(1,2)"), 1, true); // May not cause name collision with operator "or"
458  iStat += EqnTest(_T("(2+"), 0, false); // missing closing bracket
459  iStat += EqnTest(_T("2++4"), 0, false); // unexpected operator
460  iStat += EqnTest(_T("2+-4"), 0, false); // unexpected operator
461  iStat += EqnTest(_T("(2+)"), 0, false); // unexpected closing bracket
462  iStat += EqnTest(_T("--2"), 0, false); // double sign
463  iStat += EqnTest(_T("ksdfj"), 0, false); // unknown token
464  iStat += EqnTest(_T("()"), 0, false); // empty bracket without a function
465  iStat += EqnTest(_T("5+()"), 0, false); // empty bracket without a function
466  iStat += EqnTest(_T("sin(cos)"), 0, false); // unexpected function
467  iStat += EqnTest(_T("5t6"), 0, false); // unknown token
468  iStat += EqnTest(_T("5 t 6"), 0, false); // unknown token
469  iStat += EqnTest(_T("8*"), 0, false); // unexpected end of formula
470  iStat += EqnTest(_T(",3"), 0, false); // unexpected comma
471  iStat += EqnTest(_T("3,5"), 0, false); // unexpected comma
472  iStat += EqnTest(_T("sin(8,8)"), 0, false); // too many function args
473  iStat += EqnTest(_T("(7,8)"), 0, false); // too many function args
474  iStat += EqnTest(_T("sin)"), 0, false); // unexpected closing bracket
475  iStat += EqnTest(_T("a)"), 0, false); // unexpected closing bracket
476  iStat += EqnTest(_T("pi)"), 0, false); // unexpected closing bracket
477  iStat += EqnTest(_T("sin(())"), 0, false); // unexpected closing bracket
478  iStat += EqnTest(_T("sin()"), 0, false); // unexpected closing bracket
479 
480  if (iStat==0)
481  mu::console() << _T("passed") << endl;
482  else
483  mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl;
484 
485  return iStat;
486  }
487 
488  //---------------------------------------------------------------------------
490  {
491  int iStat = 0;
492  mu::console() << _T("testing variable/constant detection...");
493 
494  // Test if the result changes when a variable changes
495  iStat += EqnTestWithVarChange( _T("a"), 1, 1, 2, 2 );
496  iStat += EqnTestWithVarChange( _T("2*a"), 2, 4, 3, 6 );
497 
498  // distinguish constants with same basename
499  iStat += EqnTest( _T("const"), 1, true);
500  iStat += EqnTest( _T("const1"), 2, true);
501  iStat += EqnTest( _T("const2"), 3, true);
502  iStat += EqnTest( _T("2*const"), 2, true);
503  iStat += EqnTest( _T("2*const1"), 4, true);
504  iStat += EqnTest( _T("2*const2"), 6, true);
505  iStat += EqnTest( _T("2*const+1"), 3, true);
506  iStat += EqnTest( _T("2*const1+1"), 5, true);
507  iStat += EqnTest( _T("2*const2+1"), 7, true);
508  iStat += EqnTest( _T("const"), 0, false);
509  iStat += EqnTest( _T("const1"), 0, false);
510  iStat += EqnTest( _T("const2"), 0, false);
511 
512  // distinguish variables with same basename
513  iStat += EqnTest( _T("a"), 1, true);
514  iStat += EqnTest( _T("aa"), 2, true);
515  iStat += EqnTest( _T("2*a"), 2, true);
516  iStat += EqnTest( _T("2*aa"), 4, true);
517  iStat += EqnTest( _T("2*a-1"), 1, true);
518  iStat += EqnTest( _T("2*aa-1"), 3, true);
519 
520  // custom value recognition
521  iStat += EqnTest( _T("0xff"), 255, true);
522  iStat += EqnTest( _T("0x97 + 0xff"), 406, true);
523 
524  // Finally test querying of used variables
525  try
526  {
527  int idx;
528  mu::Parser p;
529  mu::value_type vVarVal[] = { 1, 2, 3, 4, 5};
530  p.DefineVar( _T("a"), &vVarVal[0]);
531  p.DefineVar( _T("b"), &vVarVal[1]);
532  p.DefineVar( _T("c"), &vVarVal[2]);
533  p.DefineVar( _T("d"), &vVarVal[3]);
534  p.DefineVar( _T("e"), &vVarVal[4]);
535 
536  // Test lookup of defined variables
537  // 4 used variables
538  p.SetExpr( _T("a+b+c+d") );
539  mu::varmap_type UsedVar = p.GetUsedVar();
540  int iCount = (int)UsedVar.size();
541  if (iCount!=4)
542  throw false;
543 
544  // the next check will fail if the parser
545  // erroneously creates new variables internally
546  if (p.GetVar().size()!=5)
547  throw false;
548 
549  mu::varmap_type::const_iterator item = UsedVar.begin();
550  for (idx=0; item!=UsedVar.end(); ++item)
551  {
552  if (&vVarVal[idx++]!=item->second)
553  throw false;
554  }
555 
556  // Test lookup of undefined variables
557  p.SetExpr( _T("undef1+undef2+undef3") );
558  UsedVar = p.GetUsedVar();
559  iCount = (int)UsedVar.size();
560  if (iCount!=3)
561  throw false;
562 
563  // the next check will fail if the parser
564  // erroneously creates new variables internally
565  if (p.GetVar().size()!=5)
566  throw false;
567 
568  for (item = UsedVar.begin(); item!=UsedVar.end(); ++item)
569  {
570  if (item->second!=0)
571  throw false; // all pointers to undefined variables must be null
572  }
573 
574  // 1 used variables
575  p.SetExpr( _T("a+b") );
576  UsedVar = p.GetUsedVar();
577  iCount = (int)UsedVar.size();
578  if (iCount!=2) throw false;
579  item = UsedVar.begin();
580  for (idx=0; item!=UsedVar.end(); ++item)
581  if (&vVarVal[idx++]!=item->second) throw false;
582 
583  }
584  catch(...)
585  {
586  iStat += 1;
587  }
588 
589  if (iStat==0)
590  mu::console() << _T("passed") << endl;
591  else
592  mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl;
593 
594  return iStat;
595  }
596 
597  //---------------------------------------------------------------------------
599  {
600  int iStat = 0;
601  mu::console() << _T("testing multiarg functions...");
602 
603  // Compound expressions
604  iStat += EqnTest( _T("1,2,3"), 3, true);
605  iStat += EqnTest( _T("a,b,c"), 3, true);
606  iStat += EqnTest( _T("a=10,b=20,c=a*b"), 200, true);
607  iStat += EqnTest( _T("1,\n2,\n3"), 3, true);
608  iStat += EqnTest( _T("a,\nb,\nc"), 3, true);
609  iStat += EqnTest( _T("a=10,\nb=20,\nc=a*b"), 200, true);
610  iStat += EqnTest( _T("1,\r\n2,\r\n3"), 3, true);
611  iStat += EqnTest( _T("a,\r\nb,\r\nc"), 3, true);
612  iStat += EqnTest( _T("a=10,\r\nb=20,\r\nc=a*b"), 200, true);
613 
614  // picking the right argument
615  iStat += EqnTest( _T("f1of1(1)"), 1, true);
616  iStat += EqnTest( _T("f1of2(1, 2)"), 1, true);
617  iStat += EqnTest( _T("f2of2(1, 2)"), 2, true);
618  iStat += EqnTest( _T("f1of3(1, 2, 3)"), 1, true);
619  iStat += EqnTest( _T("f2of3(1, 2, 3)"), 2, true);
620  iStat += EqnTest( _T("f3of3(1, 2, 3)"), 3, true);
621  iStat += EqnTest( _T("f1of4(1, 2, 3, 4)"), 1, true);
622  iStat += EqnTest( _T("f2of4(1, 2, 3, 4)"), 2, true);
623  iStat += EqnTest( _T("f3of4(1, 2, 3, 4)"), 3, true);
624  iStat += EqnTest( _T("f4of4(1, 2, 3, 4)"), 4, true);
625  iStat += EqnTest( _T("f1of5(1, 2, 3, 4, 5)"), 1, true);
626  iStat += EqnTest( _T("f2of5(1, 2, 3, 4, 5)"), 2, true);
627  iStat += EqnTest( _T("f3of5(1, 2, 3, 4, 5)"), 3, true);
628  iStat += EqnTest( _T("f4of5(1, 2, 3, 4, 5)"), 4, true);
629  iStat += EqnTest( _T("f5of5(1, 2, 3, 4, 5)"), 5, true);
630  // Too few arguments / Too many arguments
631  iStat += EqnTest( _T("1+ping()"), 11, true);
632  iStat += EqnTest( _T("ping()+1"), 11, true);
633  iStat += EqnTest( _T("2*ping()"), 20, true);
634  iStat += EqnTest( _T("ping()*2"), 20, true);
635  iStat += EqnTest( _T("ping(1,2)"), 0, false);
636  iStat += EqnTest( _T("1+ping(1,2)"), 0, false);
637  iStat += EqnTest( _T("f1of1(1,2)"), 0, false);
638  iStat += EqnTest( _T("f1of1()"), 0, false);
639  iStat += EqnTest( _T("f1of2(1, 2, 3)"), 0, false);
640  iStat += EqnTest( _T("f1of2(1)"), 0, false);
641  iStat += EqnTest( _T("f1of3(1, 2, 3, 4)"), 0, false);
642  iStat += EqnTest( _T("f1of3(1)"), 0, false);
643  iStat += EqnTest( _T("f1of4(1, 2, 3, 4, 5)"), 0, false);
644  iStat += EqnTest( _T("f1of4(1)"), 0, false);
645  iStat += EqnTest( _T("(1,2,3)"), 0, false);
646  iStat += EqnTest( _T("1,2,3"), 0, false);
647  iStat += EqnTest( _T("(1*a,2,3)"), 0, false);
648  iStat += EqnTest( _T("1,2*a,3"), 0, false);
649 
650  // correct calculation of arguments
651  iStat += EqnTest( _T("min(a, 1)"), 1, true);
652  iStat += EqnTest( _T("min(3*2, 1)"), 1, true);
653  iStat += EqnTest( _T("min(3*2, 1)"), 6, false);
654  iStat += EqnTest( _T("firstArg(2,3,4)"), 2, true);
655  iStat += EqnTest( _T("lastArg(2,3,4)"), 4, true);
656  iStat += EqnTest( _T("min(3*a+1, 1)"), 1, true);
657  iStat += EqnTest( _T("max(3*a+1, 1)"), 4, true);
658  iStat += EqnTest( _T("max(3*a+1, 1)*2"), 8, true);
659  iStat += EqnTest( _T("2*max(3*a+1, 1)+2"), 10, true);
660 
661  // functions with Variable argument count
662  iStat += EqnTest( _T("sum(a)"), 1, true);
663  iStat += EqnTest( _T("sum(1,2,3)"), 6, true);
664  iStat += EqnTest( _T("sum(a,b,c)"), 6, true);
665  iStat += EqnTest( _T("sum(1,-max(1,2),3)*2"), 4, true);
666  iStat += EqnTest( _T("2*sum(1,2,3)"), 12, true);
667  iStat += EqnTest( _T("2*sum(1,2,3)+2"), 14, true);
668  iStat += EqnTest( _T("2*sum(-1,2,3)+2"), 10, true);
669  iStat += EqnTest( _T("2*sum(-1,2,-(-a))+2"), 6, true);
670  iStat += EqnTest( _T("2*sum(-1,10,-a)+2"), 18, true);
671  iStat += EqnTest( _T("2*sum(1,2,3)*2"), 24, true);
672  iStat += EqnTest( _T("sum(1,-max(1,2),3)*2"), 4, true);
673  iStat += EqnTest( _T("sum(1*3, 4, a+2)"), 10, true);
674  iStat += EqnTest( _T("sum(1*3, 2*sum(1,2,2), a+2)"), 16, true);
675  iStat += EqnTest( _T("sum(1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2)"), 24, true);
676 
677  // some failures
678  iStat += EqnTest( _T("sum()"), 0, false);
679  iStat += EqnTest( _T("sum(,)"), 0, false);
680  iStat += EqnTest( _T("sum(1,2,)"), 0, false);
681  iStat += EqnTest( _T("sum(,1,2)"), 0, false);
682 
683  if (iStat==0)
684  mu::console() << _T("passed") << endl;
685  else
686  mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl;
687 
688  return iStat;
689  }
690 
691 
692  //---------------------------------------------------------------------------
694  {
695  int iStat(0);
696  mu::console() << "testing infix operators...";
697 
698  iStat += EqnTest( _T("+1"), +1, true);
699  iStat += EqnTest( _T("-(+1)"), -1, true);
700  iStat += EqnTest( _T("-(+1)*2"), -2, true);
701  iStat += EqnTest( _T("-(+2)*sqrt(4)"), -4, true);
702  iStat += EqnTest( _T("3-+a"), 2, true);
703  iStat += EqnTest( _T("+1*3"), 3, true);
704 
705  iStat += EqnTest( _T("-1"), -1, true);
706  iStat += EqnTest( _T("-(-1)"), 1, true);
707  iStat += EqnTest( _T("-(-1)*2"), 2, true);
708  iStat += EqnTest( _T("-(-2)*sqrt(4)"), 4, true);
709  iStat += EqnTest( _T("-_pi"), -PARSER_CONST_PI, true);
710  iStat += EqnTest( _T("-a"), -1, true);
711  iStat += EqnTest( _T("-(a)"), -1, true);
712  iStat += EqnTest( _T("-(-a)"), 1, true);
713  iStat += EqnTest( _T("-(-a)*2"), 2, true);
714  iStat += EqnTest( _T("-(8)"), -8, true);
715  iStat += EqnTest( _T("-8"), -8, true);
716  iStat += EqnTest( _T("-(2+1)"), -3, true);
717  iStat += EqnTest( _T("-(f1of1(1+2*3)+1*2)"), -9, true);
718  iStat += EqnTest( _T("-(-f1of1(1+2*3)+1*2)"), 5, true);
719  iStat += EqnTest( _T("-sin(8)"), -0.989358, true);
720  iStat += EqnTest( _T("3-(-a)"), 4, true);
721  iStat += EqnTest( _T("3--a"), 4, true);
722  iStat += EqnTest( _T("-1*3"), -3, true);
723 
724  // Postfix / infix priorities
725  iStat += EqnTest( _T("~2#"), 8, true);
726  iStat += EqnTest( _T("~f1of1(2)#"), 8, true);
727  iStat += EqnTest( _T("~(b)#"), 8, true);
728  iStat += EqnTest( _T("(~b)#"), 12, true);
729  iStat += EqnTest( _T("~(2#)"), 8, true);
730  iStat += EqnTest( _T("~(f1of1(2)#)"), 8, true);
731  //
732  iStat += EqnTest( _T("-2^2"),-4, true);
733  iStat += EqnTest( _T("-(a+b)^2"),-9, true);
734  iStat += EqnTest( _T("(-3)^2"),9, true);
735  iStat += EqnTest( _T("-(-2^2)"),4, true);
736  iStat += EqnTest( _T("3+-3^2"),-6, true);
737  // The following assumes use of sqr as postfix operator together
738  // with a sign operator of low priority:
739  iStat += EqnTest( _T("-2'"), -4, true);
740  iStat += EqnTest( _T("-(1+1)'"),-4, true);
741  iStat += EqnTest( _T("2+-(1+1)'"),-2, true);
742  iStat += EqnTest( _T("2+-2'"), -2, true);
743  // This is the classic behaviour of the infix sign operator (here: "$") which is
744  // now deprecated:
745  iStat += EqnTest( _T("$2^2"),4, true);
746  iStat += EqnTest( _T("$(a+b)^2"),9, true);
747  iStat += EqnTest( _T("($3)^2"),9, true);
748  iStat += EqnTest( _T("$($2^2)"),-4, true);
749  iStat += EqnTest( _T("3+$3^2"),12, true);
750 
751  // infix operators sharing the first few characters
752  iStat += EqnTest( _T("~ 123"), 123+2, true);
753  iStat += EqnTest( _T("~~ 123"), 123+2, true);
754 
755  if (iStat==0)
756  mu::console() << _T("passed") << endl;
757  else
758  mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl;
759 
760  return iStat;
761  }
762 
763 
764  //---------------------------------------------------------------------------
766  {
767  int iStat = 0;
768  mu::console() << _T("testing postfix operators...");
769 
770  // application
771  iStat += EqnTest( _T("3{m}+5"), 5.003, true);
772  iStat += EqnTest( _T("1000{m}"), 1, true);
773  iStat += EqnTest( _T("1000 {m}"), 1, true);
774  iStat += EqnTest( _T("(a){m}"), 1e-3, true);
775  iStat += EqnTest( _T("a{m}"), 1e-3, true);
776  iStat += EqnTest( _T("a {m}"), 1e-3, true);
777  iStat += EqnTest( _T("-(a){m}"), -1e-3, true);
778  iStat += EqnTest( _T("-2{m}"), -2e-3, true);
779  iStat += EqnTest( _T("-2 {m}"), -2e-3, true);
780  iStat += EqnTest( _T("f1of1(1000){m}"), 1, true);
781  iStat += EqnTest( _T("-f1of1(1000){m}"), -1, true);
782  iStat += EqnTest( _T("-f1of1(-1000){m}"), 1, true);
783  iStat += EqnTest( _T("f4of4(0,0,0,1000){m}"), 1, true);
784  iStat += EqnTest( _T("2+(a*1000){m}"), 3, true);
785 
786  // can postfix operators "m" und "meg" be told apart properly?
787  iStat += EqnTest( _T("2*3000meg+2"), 2*3e9+2, true);
788 
789  // some incorrect results
790  iStat += EqnTest( _T("1000{m}"), 0.1, false);
791  iStat += EqnTest( _T("(a){m}"), 2, false);
792  // failure due to syntax checking
793  iStat += ThrowTest(_T("0x"), ecUNASSIGNABLE_TOKEN); // incomplete hex definition
794  iStat += ThrowTest(_T("3+"), ecUNEXPECTED_EOF);
795  iStat += ThrowTest( _T("4 + {m}"), ecUNASSIGNABLE_TOKEN);
796  iStat += ThrowTest( _T("{m}4"), ecUNASSIGNABLE_TOKEN);
797  iStat += ThrowTest( _T("sin({m})"), ecUNASSIGNABLE_TOKEN);
798  iStat += ThrowTest( _T("{m} {m}"), ecUNASSIGNABLE_TOKEN);
799  iStat += ThrowTest( _T("{m}(8)"), ecUNASSIGNABLE_TOKEN);
800  iStat += ThrowTest( _T("4,{m}"), ecUNASSIGNABLE_TOKEN);
801  iStat += ThrowTest( _T("-{m}"), ecUNASSIGNABLE_TOKEN);
802  iStat += ThrowTest( _T("2(-{m})"), ecUNEXPECTED_PARENS);
803  iStat += ThrowTest( _T("2({m})"), ecUNEXPECTED_PARENS);
804 
805  iStat += ThrowTest( _T("multi*1.0"), ecUNASSIGNABLE_TOKEN);
806 
807  if (iStat==0)
808  mu::console() << _T("passed") << endl;
809  else
810  mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl;
811 
812  return iStat;
813  }
814 
815  //---------------------------------------------------------------------------
817  {
818  int iStat = 0;
819  mu::console() << _T("testing expression samples...");
820 
821  value_type b = 2;
822 
823  // Optimization
824  iStat += EqnTest( _T("2*b*5"), 20, true);
825  iStat += EqnTest( _T("2*b*5 + 4*b"), 28, true);
826  iStat += EqnTest( _T("2*a/3"), 2.0/3.0, true);
827 
828  // Addition auf cmVARMUL
829  iStat += EqnTest( _T("3+b"), b+3, true);
830  iStat += EqnTest( _T("b+3"), b+3, true);
831  iStat += EqnTest( _T("b*3+2"), b*3+2, true);
832  iStat += EqnTest( _T("3*b+2"), b*3+2, true);
833  iStat += EqnTest( _T("2+b*3"), b*3+2, true);
834  iStat += EqnTest( _T("2+3*b"), b*3+2, true);
835  iStat += EqnTest( _T("b+3*b"), b+3*b, true);
836  iStat += EqnTest( _T("3*b+b"), b+3*b, true);
837 
838  iStat += EqnTest( _T("2+b*3+b"), 2+b*3+b, true);
839  iStat += EqnTest( _T("b+2+b*3"), b+2+b*3, true);
840 
841  iStat += EqnTest( _T("(2*b+1)*4"), (2*b+1)*4, true);
842  iStat += EqnTest( _T("4*(2*b+1)"), (2*b+1)*4, true);
843 
844  // operator precedences
845  iStat += EqnTest( _T("1+2-3*4/5^6"), 2.99923, true);
846  iStat += EqnTest( _T("1^2/3*4-5+6"), 2.33333333, true);
847  iStat += EqnTest( _T("1+2*3"), 7, true);
848  iStat += EqnTest( _T("1+2*3"), 7, true);
849  iStat += EqnTest( _T("(1+2)*3"), 9, true);
850  iStat += EqnTest( _T("(1+2)*(-3)"), -9, true);
851  iStat += EqnTest( _T("2/4"), 0.5, true);
852 
853  iStat += EqnTest( _T("exp(ln(7))"), 7, true);
854  iStat += EqnTest( _T("e^ln(7)"), 7, true);
855  iStat += EqnTest( _T("e^(ln(7))"), 7, true);
856  iStat += EqnTest( _T("(e^(ln(7)))"), 7, true);
857  iStat += EqnTest( _T("1-(e^(ln(7)))"), -6, true);
858  iStat += EqnTest( _T("2*(e^(ln(7)))"), 14, true);
859  iStat += EqnTest( _T("10^log(5)"), pow(10.0, log(5.0)), true);
860  iStat += EqnTest( _T("10^log10(5)"), 5, true);
861  iStat += EqnTest( _T("2^log2(4)"), 4, true);
862  iStat += EqnTest( _T("-(sin(0)+1)"), -1, true);
863  iStat += EqnTest( _T("-(2^1.1)"), -2.14354692, true);
864 
865  iStat += EqnTest( _T("(cos(2.41)/b)"), -0.372056, true);
866  iStat += EqnTest( _T("(1*(2*(3*(4*(5*(6*(a+b)))))))"), 2160, true);
867  iStat += EqnTest( _T("(1*(2*(3*(4*(5*(6*(7*(a+b))))))))"), 15120, true);
868  iStat += EqnTest( _T("(a/((((b+(((e*(((((pi*((((3.45*((pi+a)+pi))+b)+b)*a))+0.68)+e)+a)/a))+a)+b))+b)*a)-pi))"), 0.00377999, true);
869 
870  // long formula (Reference: Matlab)
871  iStat += EqnTest(
872  _T("(((-9))-e/(((((((pi-(((-7)+(-3)/4/e))))/(((-5))-2)-((pi+(-0))*(sqrt((e+e))*(-8))*(((-pi)+(-pi)-(-9)*(6*5))")
873  _T("/(-e)-e))/2)/((((sqrt(2/(-e)+6)-(4-2))+((5/(-2))/(1*(-pi)+3))/8)*pi*((pi/((-2)/(-6)*1*(-1))*(-6)+(-e)))))/")
874  _T("((e+(-2)+(-e)*((((-3)*9+(-e)))+(-9)))))))-((((e-7+(((5/pi-(3/1+pi)))))/e)/(-5))/(sqrt((((((1+(-7))))+((((-")
875  _T("e)*(-e)))-8))*(-5)/((-e)))*(-6)-((((((-2)-(-9)-(-e)-1)/3))))/(sqrt((8+(e-((-6))+(9*(-9))))*(((3+2-8))*(7+6")
876  _T("+(-5))+((0/(-e)*(-pi))+7)))+(((((-e)/e/e)+((-6)*5)*e+(3+(-5)/pi))))+pi))/sqrt((((9))+((((pi))-8+2))+pi))/e")
877  _T("*4)*((-5)/(((-pi))*(sqrt(e)))))-(((((((-e)*(e)-pi))/4+(pi)*(-9)))))))+(-pi)"), -12.23016549, true);
878 
879  // long formula (Reference: Matlab)
880  iStat += EqnTest(
881  _T("(atan(sin((((((((((((((((pi/cos((a/((((0.53-b)-pi)*e)/b))))+2.51)+a)-0.54)/0.98)+b)*b)+e)/a)+b)+a)+b)+pi)/e")
882  _T(")+a)))*2.77)"), -2.16995656, true);
883 
884  // long formula (Reference: Matlab)
885  iStat += EqnTest( _T("1+2-3*4/5^6*(2*(1-5+(3*7^9)*(4+6*7-3)))+12"), -7995810.09926, true);
886 
887  if (iStat==0)
888  mu::console() << _T("passed") << endl;
889  else
890  mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl;
891 
892  return iStat;
893  }
894 
895 
896 
897  //---------------------------------------------------------------------------
899  {
900  int iStat = 0;
901  mu::console() << _T("testing if-then-else operator...");
902 
903  // Test error detection
904  iStat += ThrowTest(_T(":3"), ecUNEXPECTED_CONDITIONAL);
905  iStat += ThrowTest(_T("? 1 : 2"), ecUNEXPECTED_CONDITIONAL);
906  iStat += ThrowTest(_T("(a<b) ? (b<c) ? 1 : 2"), ecMISSING_ELSE_CLAUSE);
907  iStat += ThrowTest(_T("(a<b) ? 1"), ecMISSING_ELSE_CLAUSE);
908  iStat += ThrowTest(_T("(a<b) ? a"), ecMISSING_ELSE_CLAUSE);
909  iStat += ThrowTest(_T("(a<b) ? a+b"), ecMISSING_ELSE_CLAUSE);
910  iStat += ThrowTest(_T("a : b"), ecMISPLACED_COLON);
911  iStat += ThrowTest(_T("1 : 2"), ecMISPLACED_COLON);
912  iStat += ThrowTest(_T("(1) ? 1 : 2 : 3"), ecMISPLACED_COLON);
913  iStat += ThrowTest(_T("(true) ? 1 : 2 : 3"), ecUNASSIGNABLE_TOKEN);
914 
915  iStat += EqnTest(_T("1 ? 128 : 255"), 128, true);
916  iStat += EqnTest(_T("1<2 ? 128 : 255"), 128, true);
917  iStat += EqnTest(_T("a<b ? 128 : 255"), 128, true);
918  iStat += EqnTest(_T("(a<b) ? 128 : 255"), 128, true);
919  iStat += EqnTest(_T("(1) ? 10 : 11"), 10, true);
920  iStat += EqnTest(_T("(0) ? 10 : 11"), 11, true);
921  iStat += EqnTest(_T("(1) ? a+b : c+d"), 3, true);
922  iStat += EqnTest(_T("(0) ? a+b : c+d"), 1, true);
923  iStat += EqnTest(_T("(1) ? 0 : 1"), 0, true);
924  iStat += EqnTest(_T("(0) ? 0 : 1"), 1, true);
925  iStat += EqnTest(_T("(a<b) ? 10 : 11"), 10, true);
926  iStat += EqnTest(_T("(a>b) ? 10 : 11"), 11, true);
927  iStat += EqnTest(_T("(a<b) ? c : d"), 3, true);
928  iStat += EqnTest(_T("(a>b) ? c : d"), -2, true);
929 
930  iStat += EqnTest(_T("(a>b) ? 1 : 0"), 0, true);
931  iStat += EqnTest(_T("((a>b) ? 1 : 0) ? 1 : 2"), 2, true);
932  iStat += EqnTest(_T("((a>b) ? 1 : 0) ? 1 : sum((a>b) ? 1 : 2)"), 2, true);
933  iStat += EqnTest(_T("((a>b) ? 0 : 1) ? 1 : sum((a>b) ? 1 : 2)"), 1, true);
934 
935  iStat += EqnTest(_T("sum((a>b) ? 1 : 2)"), 2, true);
936  iStat += EqnTest(_T("sum((1) ? 1 : 2)"), 1, true);
937  iStat += EqnTest(_T("sum((a>b) ? 1 : 2, 100)"), 102, true);
938  iStat += EqnTest(_T("sum((1) ? 1 : 2, 100)"), 101, true);
939  iStat += EqnTest(_T("sum(3, (a>b) ? 3 : 10)"), 13, true);
940  iStat += EqnTest(_T("sum(3, (a<b) ? 3 : 10)"), 6, true);
941  iStat += EqnTest(_T("10*sum(3, (a>b) ? 3 : 10)"), 130, true);
942  iStat += EqnTest(_T("10*sum(3, (a<b) ? 3 : 10)"), 60, true);
943  iStat += EqnTest(_T("sum(3, (a>b) ? 3 : 10)*10"), 130, true);
944  iStat += EqnTest(_T("sum(3, (a<b) ? 3 : 10)*10"), 60, true);
945  iStat += EqnTest(_T("(a<b) ? sum(3, (a<b) ? 3 : 10)*10 : 99"), 60, true);
946  iStat += EqnTest(_T("(a>b) ? sum(3, (a<b) ? 3 : 10)*10 : 99"), 99, true);
947  iStat += EqnTest(_T("(a<b) ? sum(3, (a<b) ? 3 : 10,10,20)*10 : 99"), 360, true);
948  iStat += EqnTest(_T("(a>b) ? sum(3, (a<b) ? 3 : 10,10,20)*10 : 99"), 99, true);
949  iStat += EqnTest(_T("(a>b) ? sum(3, (a<b) ? 3 : 10,10,20)*10 : sum(3, (a<b) ? 3 : 10)*10"), 60, true);
950 
951  // todo: also add for muParserX!
952  iStat += EqnTest(_T("(a<b)&&(a<b) ? 128 : 255"), 128, true);
953  iStat += EqnTest(_T("(a>b)&&(a<b) ? 128 : 255"), 255, true);
954  iStat += EqnTest(_T("(1<2)&&(1<2) ? 128 : 255"), 128, true);
955  iStat += EqnTest(_T("(1>2)&&(1<2) ? 128 : 255"), 255, true);
956  iStat += EqnTest(_T("((1<2)&&(1<2)) ? 128 : 255"), 128, true);
957  iStat += EqnTest(_T("((1>2)&&(1<2)) ? 128 : 255"), 255, true);
958  iStat += EqnTest(_T("((a<b)&&(a<b)) ? 128 : 255"), 128, true);
959  iStat += EqnTest(_T("((a>b)&&(a<b)) ? 128 : 255"), 255, true);
960 
961  iStat += EqnTest(_T("1>0 ? 1>2 ? 128 : 255 : 1>0 ? 32 : 64"), 255, true);
962  iStat += EqnTest(_T("1>0 ? 1>2 ? 128 : 255 :(1>0 ? 32 : 64)"), 255, true);
963  iStat += EqnTest(_T("1>0 ? 1>0 ? 128 : 255 : 1>2 ? 32 : 64"), 128, true);
964  iStat += EqnTest(_T("1>0 ? 1>0 ? 128 : 255 :(1>2 ? 32 : 64)"), 128, true);
965  iStat += EqnTest(_T("1>2 ? 1>2 ? 128 : 255 : 1>0 ? 32 : 64"), 32, true);
966  iStat += EqnTest(_T("1>2 ? 1>0 ? 128 : 255 : 1>2 ? 32 : 64"), 64, true);
967  iStat += EqnTest(_T("1>0 ? 50 : 1>0 ? 128 : 255"), 50, true);
968  iStat += EqnTest(_T("1>0 ? 50 : (1>0 ? 128 : 255)"), 50, true);
969  iStat += EqnTest(_T("1>0 ? 1>0 ? 128 : 255 : 50"), 128, true);
970  iStat += EqnTest(_T("1>2 ? 1>2 ? 128 : 255 : 1>0 ? 32 : 1>2 ? 64 : 16"), 32, true);
971  iStat += EqnTest(_T("1>2 ? 1>2 ? 128 : 255 : 1>0 ? 32 :(1>2 ? 64 : 16)"), 32, true);
972  iStat += EqnTest(_T("1>0 ? 1>2 ? 128 : 255 : 1>0 ? 32 :1>2 ? 64 : 16"), 255, true);
973  iStat += EqnTest(_T("1>0 ? 1>2 ? 128 : 255 : (1>0 ? 32 :1>2 ? 64 : 16)"), 255, true);
974  iStat += EqnTest(_T("1 ? 0 ? 128 : 255 : 1 ? 32 : 64"), 255, true);
975 
976  // assignment operators
977  iStat += EqnTest(_T("a= 0 ? 128 : 255, a"), 255, true);
978  iStat += EqnTest(_T("a=((a>b)&&(a<b)) ? 128 : 255, a"), 255, true);
979  iStat += EqnTest(_T("c=(a<b)&&(a<b) ? 128 : 255, c"), 128, true);
980  iStat += EqnTest(_T("0 ? a=a+1 : 666, a"), 1, true);
981  iStat += EqnTest(_T("1?a=10:a=20, a"), 10, true);
982  iStat += EqnTest(_T("0?a=10:a=20, a"), 20, true);
983  iStat += EqnTest(_T("0?a=sum(3,4):10, a"), 1, true); // a should not change its value due to lazy calculation
984 
985  iStat += EqnTest(_T("a=1?b=1?3:4:5, a"), 3, true);
986  iStat += EqnTest(_T("a=1?b=1?3:4:5, b"), 3, true);
987  iStat += EqnTest(_T("a=0?b=1?3:4:5, a"), 5, true);
988  iStat += EqnTest(_T("a=0?b=1?3:4:5, b"), 2, true);
989 
990  iStat += EqnTest(_T("a=1?5:b=1?3:4, a"), 5, true);
991  iStat += EqnTest(_T("a=1?5:b=1?3:4, b"), 2, true);
992  iStat += EqnTest(_T("a=0?5:b=1?3:4, a"), 3, true);
993  iStat += EqnTest(_T("a=0?5:b=1?3:4, b"), 3, true);
994 
995  if (iStat==0)
996  mu::console() << _T("passed") << endl;
997  else
998  mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl;
999 
1000  return iStat;
1001  }
1002 
1003  //---------------------------------------------------------------------------
1005  {
1006  int iStat = 0;
1007  mu::console() << _T("testing error codes...");
1008 
1009  iStat += ThrowTest(_T("3+"), ecUNEXPECTED_EOF);
1010  iStat += ThrowTest(_T("3+)"), ecUNEXPECTED_PARENS);
1011  iStat += ThrowTest(_T("()"), ecUNEXPECTED_PARENS);
1012  iStat += ThrowTest(_T("3+()"), ecUNEXPECTED_PARENS);
1013  iStat += ThrowTest(_T("sin(3,4)"), ecTOO_MANY_PARAMS);
1014  iStat += ThrowTest(_T("sin()"), ecTOO_FEW_PARAMS);
1015  iStat += ThrowTest(_T("(1+2"), ecMISSING_PARENS);
1016  iStat += ThrowTest(_T("sin(3)3"), ecUNEXPECTED_VAL);
1017  iStat += ThrowTest(_T("sin(3)xyz"), ecUNASSIGNABLE_TOKEN);
1018  iStat += ThrowTest(_T("sin(3)cos(3)"), ecUNEXPECTED_FUN);
1019  iStat += ThrowTest(_T("a+b+c=10"), ecUNEXPECTED_OPERATOR);
1020  iStat += ThrowTest(_T("a=b=3"), ecUNEXPECTED_OPERATOR);
1021 
1022 #if defined(MUP_MATH_EXCEPTIONS)
1023  // divide by zero whilst constant folding
1024  iStat += ThrowTest(_T("1/0"), ecDIV_BY_ZERO);
1025  // square root of a negative number
1026  iStat += ThrowTest(_T("sqrt(-1)"), ecDOMAIN_ERROR);
1027  // logarithms of zero
1028  iStat += ThrowTest(_T("ln(0)"), ecDOMAIN_ERROR);
1029  iStat += ThrowTest(_T("log2(0)"), ecDOMAIN_ERROR);
1030  iStat += ThrowTest(_T("log10(0)"), ecDOMAIN_ERROR);
1031  iStat += ThrowTest(_T("log(0)"), ecDOMAIN_ERROR);
1032  // logarithms of negative values
1033  iStat += ThrowTest(_T("ln(-1)"), ecDOMAIN_ERROR);
1034  iStat += ThrowTest(_T("log2(-1)"), ecDOMAIN_ERROR);
1035  iStat += ThrowTest(_T("log10(-1)"), ecDOMAIN_ERROR);
1036  iStat += ThrowTest(_T("log(-1)"), ecDOMAIN_ERROR);
1037 #endif
1038 
1039  // functions without parameter
1040  iStat += ThrowTest( _T("3+ping(2)"), ecTOO_MANY_PARAMS);
1041  iStat += ThrowTest( _T("3+ping(a+2)"), ecTOO_MANY_PARAMS);
1042  iStat += ThrowTest( _T("3+ping(sin(a)+2)"), ecTOO_MANY_PARAMS);
1043  iStat += ThrowTest( _T("3+ping(1+sin(a))"), ecTOO_MANY_PARAMS);
1044 
1045  // String function related
1046  iStat += ThrowTest( _T("valueof(\"xxx\")"), 999, false);
1047  iStat += ThrowTest( _T("valueof()"), ecUNEXPECTED_PARENS);
1048  iStat += ThrowTest( _T("1+valueof(\"abc\""), ecMISSING_PARENS);
1049  iStat += ThrowTest( _T("valueof(\"abc\""), ecMISSING_PARENS);
1050  iStat += ThrowTest( _T("valueof(\"abc"), ecUNTERMINATED_STRING);
1051  iStat += ThrowTest( _T("valueof(\"abc\",3)"), ecTOO_MANY_PARAMS);
1052  iStat += ThrowTest( _T("valueof(3)"), ecSTRING_EXPECTED);
1053  iStat += ThrowTest( _T("sin(\"abc\")"), ecVAL_EXPECTED);
1054  iStat += ThrowTest( _T("valueof(\"\\\"abc\\\"\")"), 999, false);
1055  iStat += ThrowTest( _T("\"hello world\""), ecSTR_RESULT);
1056  iStat += ThrowTest( _T("(\"hello world\")"), ecSTR_RESULT);
1057  iStat += ThrowTest( _T("\"abcd\"+100"), ecOPRT_TYPE_CONFLICT);
1058  iStat += ThrowTest( _T("\"a\"+\"b\""), ecOPRT_TYPE_CONFLICT);
1059  iStat += ThrowTest( _T("strfun1(\"100\",3)"), ecTOO_MANY_PARAMS);
1060  iStat += ThrowTest( _T("strfun2(\"100\",3,5)"), ecTOO_MANY_PARAMS);
1061  iStat += ThrowTest( _T("strfun3(\"100\",3,5,6)"), ecTOO_MANY_PARAMS);
1062  iStat += ThrowTest( _T("strfun2(\"100\")"), ecTOO_FEW_PARAMS);
1063  iStat += ThrowTest( _T("strfun3(\"100\",6)"), ecTOO_FEW_PARAMS);
1064  iStat += ThrowTest( _T("strfun2(1,1)"), ecSTRING_EXPECTED);
1065  iStat += ThrowTest( _T("strfun2(a,1)"), ecSTRING_EXPECTED);
1066  iStat += ThrowTest( _T("strfun2(1,1,1)"), ecTOO_MANY_PARAMS);
1067  iStat += ThrowTest( _T("strfun2(a,1,1)"), ecTOO_MANY_PARAMS);
1068  iStat += ThrowTest( _T("strfun3(1,2,3)"), ecSTRING_EXPECTED);
1069  iStat += ThrowTest( _T("strfun3(1, \"100\",3)"), ecSTRING_EXPECTED);
1070  iStat += ThrowTest( _T("strfun3(\"1\", \"100\",3)"), ecVAL_EXPECTED);
1071  iStat += ThrowTest( _T("strfun3(\"1\", 3, \"100\")"), ecVAL_EXPECTED);
1072  iStat += ThrowTest( _T("strfun3(\"1\", \"100\", \"100\", \"100\")"), ecTOO_MANY_PARAMS);
1073 
1074  // assignment operator
1075  iStat += ThrowTest( _T("3=4"), ecUNEXPECTED_OPERATOR);
1076  iStat += ThrowTest( _T("sin(8)=4"), ecUNEXPECTED_OPERATOR);
1077  iStat += ThrowTest( _T("\"test\"=a"), ecUNEXPECTED_OPERATOR);
1078 
1079  // <ibg 20090529>
1080  // this is now legal, for reference see:
1081  // https://sourceforge.net/forum/message.php?msg_id=7411373
1082  // iStat += ThrowTest( _T("sin=9"), ecUNEXPECTED_OPERATOR);
1083  // </ibg>
1084 
1085  iStat += ThrowTest( _T("(8)=5"), ecUNEXPECTED_OPERATOR);
1086  iStat += ThrowTest( _T("(a)=5"), ecUNEXPECTED_OPERATOR);
1087  iStat += ThrowTest( _T("a=\"tttt\""), ecOPRT_TYPE_CONFLICT);
1088 
1089  if (iStat==0)
1090  mu::console() << _T("passed") << endl;
1091  else
1092  mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl;
1093 
1094  return iStat;
1095  }
1096 
1097 
1098  //---------------------------------------------------------------------------
1099  void ParserTester::AddTest(testfun_type a_pFun)
1100  {
1101  m_vTestFun.push_back(a_pFun);
1102  }
1103 
1104  //---------------------------------------------------------------------------
1106  {
1107  int iStat = 0;
1108  try
1109  {
1110  for (int i=0; i<(int)m_vTestFun.size(); ++i)
1111  iStat += (this->*m_vTestFun[i])();
1112  }
1113  catch(Parser::exception_type &e)
1114  {
1115  mu::console() << "\n" << e.GetMsg() << endl;
1116  mu::console() << e.GetToken() << endl;
1117  Abort();
1118  }
1119  catch(std::exception &e)
1120  {
1121  mu::console() << e.what() << endl;
1122  Abort();
1123  }
1124  catch(...)
1125  {
1126  mu::console() << "Internal error";
1127  Abort();
1128  }
1129 
1130  if (iStat==0)
1131  {
1132  mu::console() << "Test passed (" << ParserTester::c_iCount << " expressions)" << endl;
1133  }
1134  else
1135  {
1136  mu::console() << "Test failed with " << iStat
1137  << " errors (" << ParserTester::c_iCount
1138  << " expressions)" << endl;
1139  }
1141  }
1142 
1143 
1144  //---------------------------------------------------------------------------
1145  int ParserTester::ThrowTest(const string_type &a_str, int a_iErrc, bool a_bFail)
1146  {
1148 
1149  try
1150  {
1151  value_type fVal[] = {1,1,1};
1152  Parser p;
1153 
1154  p.DefineVar( _T("a"), &fVal[0]);
1155  p.DefineVar( _T("b"), &fVal[1]);
1156  p.DefineVar( _T("c"), &fVal[2]);
1157  p.DefinePostfixOprt( _T("{m}"), Milli);
1158  p.DefinePostfixOprt( _T("m"), Milli);
1159  p.DefineFun( _T("ping"), Ping);
1160  p.DefineFun( _T("valueof"), ValueOf);
1161  p.DefineFun( _T("strfun1"), StrFun1);
1162  p.DefineFun( _T("strfun2"), StrFun2);
1163  p.DefineFun( _T("strfun3"), StrFun3);
1164  p.SetExpr(a_str);
1165  p.Eval();
1166  }
1167  catch(ParserError &e)
1168  {
1169  // output the formula in case of an failed test
1170  if (a_bFail==false || (a_bFail==true && a_iErrc!=e.GetCode()) )
1171  {
1172  mu::console() << _T("\n ")
1173  << _T("Expression: ") << a_str
1174  << _T(" Code:") << e.GetCode() << _T("(") << e.GetMsg() << _T(")")
1175  << _T(" Expected:") << a_iErrc;
1176  }
1177 
1178  return (a_iErrc==e.GetCode()) ? 0 : 1;
1179  }
1180 
1181  // if a_bFail==false no exception is expected
1182  bool bRet((a_bFail==false) ? 0 : 1);
1183  if (bRet==1)
1184  {
1185  mu::console() << _T("\n ")
1186  << _T("Expression: ") << a_str
1187  << _T(" did evaluate; Expected error:") << a_iErrc;
1188  }
1189 
1190  return bRet;
1191  }
1192 
1193  //---------------------------------------------------------------------------
1199  double a_fVar1,
1200  double a_fRes1,
1201  double a_fVar2,
1202  double a_fRes2)
1203  {
1205 
1206  try
1207  {
1208  value_type fVal[2] = {-999, -999 }; // should be equal
1209 
1210  Parser p;
1211  value_type var = 0;
1212 
1213  // variable
1214  p.DefineVar( _T("a"), &var);
1215  p.SetExpr(a_str);
1216 
1217  var = a_fVar1;
1218  fVal[0] = p.Eval();
1219 
1220  var = a_fVar2;
1221  fVal[1] = p.Eval();
1222 
1223  if ( fabs(a_fRes1-fVal[0]) > 0.0000000001)
1224  throw std::runtime_error("incorrect result (first pass)");
1225 
1226  if ( fabs(a_fRes2-fVal[1]) > 0.0000000001)
1227  throw std::runtime_error("incorrect result (second pass)");
1228  }
1229  catch(Parser::exception_type &e)
1230  {
1231  mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (") << e.GetMsg() << _T(")");
1232  return 1;
1233  }
1234  catch(std::exception &e)
1235  {
1236  mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (") << e.what() << _T(")");
1237  return 1; // always return a failure since this exception is not expected
1238  }
1239  catch(...)
1240  {
1241  mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (unexpected exception)");
1242  return 1; // exceptions other than ParserException are not allowed
1243  }
1244 
1245  return 0;
1246  }
1247 
1248  //---------------------------------------------------------------------------
1253  int ParserTester::EqnTest(const string_type &a_str, double a_fRes, bool a_fPass)
1254  {
1256  int iRet(0);
1257  value_type fVal[5] = {-999, -998, -997, -996, -995}; // initially should be different
1258 
1259  try
1260  {
1261  std::unique_ptr<Parser> p1;
1262  Parser p2, p3; // three parser objects
1263  // they will be used for testing copy and assignment operators
1264  // p1 is a pointer since i'm going to delete it in order to test if
1265  // parsers after copy construction still refer to members of it.
1266  // !! If this is the case this function will crash !!
1267 
1268  p1.reset(new mu::Parser());
1269  // Add constants
1270  p1->DefineConst( _T("pi"), (value_type)PARSER_CONST_PI);
1271  p1->DefineConst( _T("e"), (value_type)PARSER_CONST_E);
1272  p1->DefineConst( _T("const"), 1);
1273  p1->DefineConst( _T("const1"), 2);
1274  p1->DefineConst( _T("const2"), 3);
1275  // string constants
1276  p1->DefineStrConst( _T("str1"), _T("1.11"));
1277  p1->DefineStrConst( _T("str2"), _T("2.22"));
1278  // variables
1279  value_type vVarVal[] = { 1, 2, 3, -2};
1280  p1->DefineVar( _T("a"), &vVarVal[0]);
1281  p1->DefineVar( _T("aa"), &vVarVal[1]);
1282  p1->DefineVar( _T("b"), &vVarVal[1]);
1283  p1->DefineVar( _T("c"), &vVarVal[2]);
1284  p1->DefineVar( _T("d"), &vVarVal[3]);
1285 
1286  // custom value ident functions
1287  p1->AddValIdent(&ParserTester::IsHexVal);
1288 
1289  // functions
1290  p1->DefineFun( _T("ping"), Ping);
1291  p1->DefineFun( _T("f1of1"), f1of1); // one parameter
1292  p1->DefineFun( _T("f1of2"), f1of2); // two parameter
1293  p1->DefineFun( _T("f2of2"), f2of2);
1294  p1->DefineFun( _T("f1of3"), f1of3); // three parameter
1295  p1->DefineFun( _T("f2of3"), f2of3);
1296  p1->DefineFun( _T("f3of3"), f3of3);
1297  p1->DefineFun( _T("f1of4"), f1of4); // four parameter
1298  p1->DefineFun( _T("f2of4"), f2of4);
1299  p1->DefineFun( _T("f3of4"), f3of4);
1300  p1->DefineFun( _T("f4of4"), f4of4);
1301  p1->DefineFun( _T("f1of5"), f1of5); // five parameter
1302  p1->DefineFun( _T("f2of5"), f2of5);
1303  p1->DefineFun( _T("f3of5"), f3of5);
1304  p1->DefineFun( _T("f4of5"), f4of5);
1305  p1->DefineFun( _T("f5of5"), f5of5);
1306 
1307  // binary operators
1308  p1->DefineOprt( _T("add"), add, 0);
1309  p1->DefineOprt( _T("++"), add, 0);
1310  p1->DefineOprt( _T("&"), land, prLAND);
1311 
1312  // sample functions
1313  p1->DefineFun( _T("min"), Min);
1314  p1->DefineFun( _T("max"), Max);
1315  p1->DefineFun( _T("sum"), Sum);
1316  p1->DefineFun( _T("valueof"), ValueOf);
1317  p1->DefineFun( _T("atof"), StrToFloat);
1318  p1->DefineFun( _T("strfun1"), StrFun1);
1319  p1->DefineFun( _T("strfun2"), StrFun2);
1320  p1->DefineFun( _T("strfun3"), StrFun3);
1321  p1->DefineFun( _T("lastArg"), LastArg);
1322  p1->DefineFun( _T("firstArg"), FirstArg);
1323  p1->DefineFun( _T("order"), FirstArg);
1324 
1325  // infix / postfix operator
1326  // Note: Identifiers used here do not have any meaning
1327  // they are mere placeholders to test certain features.
1328  p1->DefineInfixOprt( _T("$"), sign, prPOW+1); // sign with high priority
1329  p1->DefineInfixOprt( _T("~"), plus2); // high priority
1330  p1->DefineInfixOprt( _T("~~"), plus2);
1331  p1->DefinePostfixOprt( _T("{m}"), Milli);
1332  p1->DefinePostfixOprt( _T("{M}"), Mega);
1333  p1->DefinePostfixOprt( _T("m"), Milli);
1334  p1->DefinePostfixOprt( _T("meg"), Mega);
1335  p1->DefinePostfixOprt( _T("#"), times3);
1336  p1->DefinePostfixOprt( _T("'"), sqr);
1337  p1->SetExpr(a_str);
1338 
1339  // Test bytecode integrity
1340  // String parsing and bytecode parsing must yield the same result
1341  fVal[0] = p1->Eval(); // result from stringparsing
1342  fVal[1] = p1->Eval(); // result from bytecode
1343  if (fVal[0]!=fVal[1])
1344  throw Parser::exception_type( _T("Bytecode / string parsing mismatch.") );
1345 
1346  // Test copy and assignment operators
1347  try
1348  {
1349  // Test copy constructor
1350  std::vector<mu::Parser> vParser;
1351  vParser.push_back(*(p1.get()));
1352  mu::Parser p4 = vParser[0]; // take parser from vector
1353 
1354  // destroy the originals from p2
1355  vParser.clear(); // delete the vector
1356  p1.reset(0);
1357 
1358  fVal[2] = p4.Eval();
1359 
1360  // Test assignment operator
1361  // additionally disable Optimizer this time
1362  mu::Parser p5;
1363  p5 = p4;
1364  p5.EnableOptimizer(false);
1365  fVal[3] = p5.Eval();
1366 
1367  // Test Eval function for multiple return values
1368  // use p2 since it has the optimizer enabled!
1369  int nNum;
1370  value_type *v = p4.Eval(nNum);
1371  fVal[4] = v[nNum-1];
1372  }
1373  catch(std::exception &e)
1374  {
1375  mu::console() << _T("\n ") << e.what() << _T("\n");
1376  }
1377 
1378  // limited floating point accuracy requires the following test
1379  bool bCloseEnough(true);
1380  for (unsigned i=0; i<sizeof(fVal)/sizeof(value_type); ++i)
1381  {
1382  bCloseEnough &= (fabs(a_fRes-fVal[i]) <= fabs(fVal[i]*0.00001));
1383 
1384  // The tests equations never result in infinity, if they do thats a bug.
1385  // reference:
1386  // http://sourceforge.net/projects/muparser/forums/forum/462843/topic/5037825
1387  #ifdef _MSC_VER
1388  #pragma warning(push)
1389  #pragma warning(disable:4127)
1390  #endif
1391  if (std::numeric_limits<value_type>::has_infinity)
1392  #ifdef _MSC_VER
1393  #pragma warning(pop)
1394  #endif
1395  {
1396  bCloseEnough &= (fabs(fVal[i]) != numeric_limits<value_type>::infinity());
1397  }
1398  }
1399 
1400  iRet = ((bCloseEnough && a_fPass) || (!bCloseEnough && !a_fPass)) ? 0 : 1;
1401 
1402 
1403  if (iRet==1)
1404  {
1405  mu::console() << _T("\n fail: ") << a_str.c_str()
1406  << _T(" (incorrect result; expected: ") << a_fRes
1407  << _T(" ;calculated: ") << fVal[0] << _T(",")
1408  << fVal[1] << _T(",")
1409  << fVal[2] << _T(",")
1410  << fVal[3] << _T(",")
1411  << fVal[4] << _T(").");
1412  }
1413  }
1414  catch(Parser::exception_type &e)
1415  {
1416  if (a_fPass)
1417  {
1418  if (fVal[0]!=fVal[2] && fVal[0]!=-999 && fVal[1]!=-998)
1419  mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (copy construction)");
1420  else
1421  mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (") << e.GetMsg() << _T(")");
1422  return 1;
1423  }
1424  }
1425  catch(std::exception &e)
1426  {
1427  mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (") << e.what() << _T(")");
1428  return 1; // always return a failure since this exception is not expected
1429  }
1430  catch(...)
1431  {
1432  mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (unexpected exception)");
1433  return 1; // exceptions other than ParserException are not allowed
1434  }
1435 
1436  return iRet;
1437  }
1438 
1439  //---------------------------------------------------------------------------
1440  int ParserTester::EqnTestInt(const string_type &a_str, double a_fRes, bool a_fPass)
1441  {
1443 
1444  value_type vVarVal[] = {1, 2, 3}; // variable values
1445  int iRet(0);
1446 
1447  try
1448  {
1449  value_type fVal[2] = {-99, -999}; // results: initially should be different
1450  ParserInt p;
1451  p.DefineConst( _T("const1"), 1);
1452  p.DefineConst( _T("const2"), 2);
1453  p.DefineVar( _T("a"), &vVarVal[0]);
1454  p.DefineVar( _T("b"), &vVarVal[1]);
1455  p.DefineVar( _T("c"), &vVarVal[2]);
1456 
1457  p.SetExpr(a_str);
1458  fVal[0] = p.Eval(); // result from stringparsing
1459  fVal[1] = p.Eval(); // result from bytecode
1460 
1461  if (fVal[0]!=fVal[1])
1462  throw Parser::exception_type( _T("Bytecode corrupt.") );
1463 
1464  iRet = ( (a_fRes==fVal[0] && a_fPass) ||
1465  (a_fRes!=fVal[0] && !a_fPass) ) ? 0 : 1;
1466  if (iRet==1)
1467  {
1468  mu::console() << _T("\n fail: ") << a_str.c_str()
1469  << _T(" (incorrect result; expected: ") << a_fRes
1470  << _T(" ;calculated: ") << fVal[0]<< _T(").");
1471  }
1472  }
1473  catch(Parser::exception_type &e)
1474  {
1475  if (a_fPass)
1476  {
1477  mu::console() << _T("\n fail: ") << e.GetExpr() << _T(" : ") << e.GetMsg();
1478  iRet = 1;
1479  }
1480  }
1481  catch(...)
1482  {
1483  mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (unexpected exception)");
1484  iRet = 1; // exceptions other than ParserException are not allowed
1485  }
1486 
1487  return iRet;
1488  }
1489 
1490  //---------------------------------------------------------------------------
1492  int ParserTester::EqnTestBulk(const string_type &a_str, double a_fRes[4], bool a_fPass)
1493  {
1495 
1496  // Define Bulk Variables
1497  int nBulkSize = 4;
1498  value_type vVariableA[] = { 1, 2, 3, 4 }; // variable values
1499  value_type vVariableB[] = { 2, 2, 2, 2 }; // variable values
1500  value_type vVariableC[] = { 3, 3, 3, 3 }; // variable values
1501  value_type vResults[] = { 0, 0, 0, 0 }; // variable values
1502  int iRet(0);
1503 
1504  try
1505  {
1506  Parser p;
1507  p.DefineConst(_T("const1"), 1);
1508  p.DefineConst(_T("const2"), 2);
1509  p.DefineVar(_T("a"), vVariableA);
1510  p.DefineVar(_T("b"), vVariableB);
1511  p.DefineVar(_T("c"), vVariableC);
1512 
1513  p.SetExpr(a_str);
1514  p.Eval(vResults, nBulkSize);
1515 
1516  bool bCloseEnough(true);
1517  for (int i = 0; i < nBulkSize; ++i)
1518  {
1519  bCloseEnough &= (fabs(a_fRes[i] - vResults[i]) <= fabs(a_fRes[i] * 0.00001));
1520  }
1521 
1522  iRet = ((bCloseEnough && a_fPass) || (!bCloseEnough && !a_fPass)) ? 0 : 1;
1523  if (iRet == 1)
1524  {
1525  mu::console() << _T("\n fail: ") << a_str.c_str()
1526  << _T(" (incorrect result; expected: {") << a_fRes[0] << _T(",") << a_fRes[1] << _T(",") << a_fRes[2] << _T(",") << a_fRes[3] << _T("}")
1527  << _T(" ;calculated: ") << vResults[0] << _T(",") << vResults[1] << _T(",") << vResults[2] << _T(",") << vResults[3] << _T("}");
1528  }
1529  }
1530  catch (Parser::exception_type &e)
1531  {
1532  if (a_fPass)
1533  {
1534  mu::console() << _T("\n fail: ") << e.GetExpr() << _T(" : ") << e.GetMsg();
1535  iRet = 1;
1536  }
1537  }
1538  catch (...)
1539  {
1540  mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (unexpected exception)");
1541  iRet = 1; // exceptions other than ParserException are not allowed
1542  }
1543 
1544  return iRet;
1545  }
1546 
1547  //---------------------------------------------------------------------------
1549  void ParserTester::Abort() const
1550  {
1551  mu::console() << _T("Test failed (internal error in test class)") << endl;
1552  while (!getchar());
1553  exit(-1);
1554  }
1555  } // namespace test
1556 } // namespace mu