NCBI C++ ToolKit
muParserTest.cpp
Go to the documentation of this file.

Go to the SVN repository for this file.

1 /*
2  __________
3  _____ __ __\______ \_____ _______ ______ ____ _______
4  / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \
5  | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/
6  |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__|
7  \/ \/ \/ \/
8  Copyright (C) 2004-2008 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 #include <ncbi_pch.hpp>
27 
28 #include <cstdio>
29 #include <cmath>
30 #include <iostream>
31 
32 #define PARSER_CONST_PI 3.141592653589793238462643
33 #define PARSER_CONST_E 2.718281828459045235360287
34 
35 #define wxT(x) MUP_T(x)
36 
37 using namespace std;
38 
39 /** \file
40  \brief This file contains the implementation of parser test cases.
41 */
42 
43 
44 namespace mu
45 {
46  namespace Test
47  {
48  int ParserTester::c_iCount = 0;
49 
50  //---------------------------------------------------------------------------
51  ParserTester::ParserTester()
52  :m_vTestFun()
53  {
66 
68  }
69 
70  //---------------------------------------------------------------------------
72  {
73  int iStat = 0;
74  mu::console() << wxT("testing member functions...");
75 
76  // Test RemoveVar
77  value_type afVal[3] = {1,2,3};
78  Parser p;
79 
80  try
81  {
82  p.DefineVar( wxT("a"), &afVal[0]);
83  p.DefineVar( wxT("b"), &afVal[1]);
84  p.DefineVar( wxT("c"), &afVal[2]);
85  p.SetExpr( wxT("a+b+c") );
86  p.Eval();
87  }
88  catch(...)
89  {
90  iStat += 1; // this is not supposed to happen
91  }
92 
93  try
94  {
95  p.RemoveVar( wxT("c") );
96  p.Eval();
97  iStat += 1; // not supposed to reach this, nonexisting variable "c" deleted...
98  }
99  catch(...)
100  {
101  // failure is expected...
102  }
103 
104  if (iStat==0)
105  mu::console() << wxT("passed") << endl;
106  else
107  mu::console() << wxT("\n failed with ") << iStat << wxT(" errors") << endl;
108 
109  return iStat;
110  }
111 
112  //---------------------------------------------------------------------------
114  {
115  int iStat = 0;
116  mu::console() << wxT("testing string arguments...");
117 
118  iStat += EqnTest(wxT("valueof(\"aaa\")+valueof(\"bbb\") "), 246, true);
119  iStat += EqnTest(wxT("2*(valueof(\"aaa\")-23)+valueof(\"bbb\")"), 323, true);
120  // use in expressions with variables
121  iStat += EqnTest(wxT("a*(atof(\"10\")-b)"), 8, true);
122  iStat += EqnTest(wxT("a-(atof(\"10\")*b)"), -19, true);
123  // string + numeric arguments
124  iStat += EqnTest(wxT("strfun1(\"100\")"), 100, true);
125  iStat += EqnTest(wxT("strfun2(\"100\",1)"), 101, true);
126  iStat += EqnTest(wxT("strfun3(\"99\",1,2)"), 102, true);
127 
128  if (iStat==0)
129  mu::console() << wxT("passed") << endl;
130  else
131  mu::console() << wxT("\n failed with ") << iStat << wxT(" errors") << endl;
132 
133  return iStat;
134  }
135 
136  //---------------------------------------------------------------------------
138  {
139  int iStat = 0;
140  mu::console() << wxT("testing binary operators...");
141 
142  // built in operators
143  // xor operator
144  iStat += EqnTest(wxT("1 xor 2"), 3, true);
145  iStat += EqnTest(wxT("a xor b"), 3, true); // with a=1 and b=2
146  iStat += EqnTest(wxT("1 xor 2 xor 3"), 0, true);
147  iStat += EqnTest(wxT("a xor b xor 3"), 0, true); // with a=1 and b=2
148  iStat += EqnTest(wxT("a xor b xor c"), 0, true); // with a=1 and b=2
149  iStat += EqnTest(wxT("(1 xor 2) xor 3"), 0, true);
150  iStat += EqnTest(wxT("(a xor b) xor c"), 0, true); // with a=1 and b=2
151  iStat += EqnTest(wxT("(a) xor (b) xor c"), 0, true); // with a=1 and b=2
152  iStat += EqnTest(wxT("1 or 2"), 3, true);
153  iStat += EqnTest(wxT("a or b"), 3, true); // with a=1 and b=2
154 
155  // Assignement operator
156  iStat += EqnTest(wxT("a = b"), 2, true);
157  iStat += EqnTest(wxT("a = sin(b)"), 0.909297, true);
158  iStat += EqnTest(wxT("a = 1+sin(b)"), 1.909297, true);
159 
160  // Test user defined binary operators
161  iStat += EqnTestInt(wxT("1 | 2"), 3, true);
162  iStat += EqnTestInt(wxT("1 || 2"), 1, true);
163  iStat += EqnTestInt(wxT("123 & 456"), 72, true);
164  iStat += EqnTestInt(wxT("(123 & 456) % 10"), 2, true);
165  iStat += EqnTestInt(wxT("1 && 0"), 0, true);
166  iStat += EqnTestInt(wxT("123 && 456"), 1, true);
167  iStat += EqnTestInt(wxT("1 << 3"), 8, true);
168  iStat += EqnTestInt(wxT("8 >> 3"), 1, true);
169  iStat += EqnTestInt(wxT("10 ^ 10"), 0, true);
170  iStat += EqnTestInt(wxT("10 * 10 ^ 99"), 7, true);
171  iStat += EqnTestInt(wxT("9 / 4"), 2, true);
172  iStat += EqnTestInt(wxT("9 % 4"), 1, true);
173  iStat += EqnTestInt(wxT("if(5%2,1,0)"), 1, true);
174  iStat += EqnTestInt(wxT("if(4%2,1,0)"), 0, true);
175  iStat += EqnTestInt(wxT("-10+1"), -9, true);
176  iStat += EqnTestInt(wxT("1+2*3"), 7, true);
177  iStat += EqnTestInt(wxT("const1 != const2"), 1, true);
178  iStat += EqnTestInt(wxT("const1 != const2"), 0, false);
179  iStat += EqnTestInt(wxT("const1 == const2"), 0, true);
180  iStat += EqnTestInt(wxT("const1 == 1"), 1, true);
181  iStat += EqnTestInt(wxT("10*(const1 == 1)"), 10, true);
182  iStat += EqnTestInt(wxT("2*(const1 | const2)"), 6, true);
183  iStat += EqnTestInt(wxT("2*(const1 | const2)"), 7, false);
184  iStat += EqnTestInt(wxT("const1 < const2"), 1, true);
185  iStat += EqnTestInt(wxT("const2 > const1"), 1, true);
186  iStat += EqnTestInt(wxT("const1 <= 1"), 1, true);
187  iStat += EqnTestInt(wxT("const2 >= 2"), 1, true);
188  iStat += EqnTestInt(wxT("2*(const1 + const2)"), 6, true);
189  iStat += EqnTestInt(wxT("2*(const1 - const2)"), -2, true);
190 
191  iStat += EqnTestInt(wxT("a != b"), 1, true);
192  iStat += EqnTestInt(wxT("a != b"), 0, false);
193  iStat += EqnTestInt(wxT("a == b"), 0, true);
194  iStat += EqnTestInt(wxT("a == 1"), 1, true);
195  iStat += EqnTestInt(wxT("10*(a == 1)"), 10, true);
196  iStat += EqnTestInt(wxT("2*(a | b)"), 6, true);
197  iStat += EqnTestInt(wxT("2*(a | b)"), 7, false);
198  iStat += EqnTestInt(wxT("a < b"), 1, true);
199  iStat += EqnTestInt(wxT("b > a"), 1, true);
200  iStat += EqnTestInt(wxT("a <= 1"), 1, true);
201  iStat += EqnTestInt(wxT("b >= 2"), 1, true);
202  iStat += EqnTestInt(wxT("2*(a + b)"), 6, true);
203  iStat += EqnTestInt(wxT("2*(a - b)"), -2, true);
204  iStat += EqnTestInt(wxT("a + (a << b)"), 5, true);
205  iStat += EqnTestInt(wxT("-2^2"), -4, true);
206 // incorrect: '^' is yor here, not power
207 // iStat += EqnTestInt("-(1+2)^2", -9, true);
208 // iStat += EqnTestInt("-1^3", -1, true);
209 
210  // Test precedence
211  // a=1, b=2, c=3
212  iStat += EqnTestInt(wxT("a + b * c"), 7, true);
213  iStat += EqnTestInt(wxT("a * b + c"), 5, true);
214  iStat += EqnTestInt(wxT("a<b && b>10"), 0, true);
215  iStat += EqnTestInt(wxT("a<b && b<10"), 1, true);
216 
217  iStat += EqnTestInt(wxT("a + b << c"), 17, true);
218  iStat += EqnTestInt(wxT("a << b + c"), 7, true);
219  iStat += EqnTestInt(wxT("c * b < a"), 0, true);
220  iStat += EqnTestInt(wxT("c * b == 6 * a"), 1, true);
221 
222  if (iStat==0)
223  mu::console() << wxT("passed") << endl;
224  else
225  mu::console() << wxT("\n failed with ") << iStat << wxT(" errors") << endl;
226 
227  return iStat;
228  }
229 
230  //---------------------------------------------------------------------------
231  /** \brief Check muParser name restriction enforcement. */
233  {
234  int iStat= 0,
235  iErr = 0;
236 
237  mu::console() << "testing name restriction enforcement...";
238 
239  Parser p;
240 
241  #define PARSER_THROWCHECK(DOMAIN, FAIL, EXPR, ARG) \
242  iErr = 0; \
243  ParserTester::c_iCount++; \
244  try \
245  { \
246  p.Define##DOMAIN(EXPR, ARG); \
247  } \
248  catch(Parser::exception_type&) \
249  { \
250  iErr = (FAIL==false) ? 0 : 1; \
251  } \
252  iStat += iErr;
253 
254  // constant names
255  PARSER_THROWCHECK(Const, false, wxT("0a"), 1)
256  PARSER_THROWCHECK(Const, false, wxT("9a"), 1)
257  PARSER_THROWCHECK(Const, false, wxT("+a"), 1)
258  PARSER_THROWCHECK(Const, false, wxT("-a"), 1)
259  PARSER_THROWCHECK(Const, false, wxT("a-"), 1)
260  PARSER_THROWCHECK(Const, false, wxT("a*"), 1)
261  PARSER_THROWCHECK(Const, false, wxT("a?"), 1)
262  PARSER_THROWCHECK(Const, true, wxT("a"), 1)
263  PARSER_THROWCHECK(Const, true, wxT("a_min"), 1)
264  PARSER_THROWCHECK(Const, true, wxT("a_min0"), 1)
265  PARSER_THROWCHECK(Const, true, wxT("a_min9"), 1)
266  // variable names
267  value_type a;
268  p.ClearConst();
269  PARSER_THROWCHECK(Var, false, wxT("123abc"), &a)
270  PARSER_THROWCHECK(Var, false, wxT("9a"), &a)
271  PARSER_THROWCHECK(Var, false, wxT("0a"), &a)
272  PARSER_THROWCHECK(Var, false, wxT("+a"), &a)
273  PARSER_THROWCHECK(Var, false, wxT("-a"), &a)
274  PARSER_THROWCHECK(Var, false, wxT("?a"), &a)
275  PARSER_THROWCHECK(Var, false, wxT("!a"), &a)
276  PARSER_THROWCHECK(Var, false, wxT("a+"), &a)
277  PARSER_THROWCHECK(Var, false, wxT("a-"), &a)
278  PARSER_THROWCHECK(Var, false, wxT("a*"), &a)
279  PARSER_THROWCHECK(Var, false, wxT("a?"), &a)
280  PARSER_THROWCHECK(Var, true, wxT("a"), &a)
281  PARSER_THROWCHECK(Var, true, wxT("a_min"), &a)
282  PARSER_THROWCHECK(Var, true, wxT("a_min0"), &a)
283  PARSER_THROWCHECK(Var, true, wxT("a_min9"), &a)
284  PARSER_THROWCHECK(Var, false, wxT("a_min9"), 0)
285  // Postfix operators
286  // fail
287  PARSER_THROWCHECK(PostfixOprt, false, wxT("(k"), f1of1)
288  PARSER_THROWCHECK(PostfixOprt, false, wxT("9+"), f1of1)
289  PARSER_THROWCHECK(PostfixOprt, false, wxT("+"), 0)
290  // pass
291  PARSER_THROWCHECK(PostfixOprt, true, wxT("-a"), f1of1)
292  PARSER_THROWCHECK(PostfixOprt, true, wxT("?a"), f1of1)
293  PARSER_THROWCHECK(PostfixOprt, true, wxT("_"), f1of1)
294  PARSER_THROWCHECK(PostfixOprt, true, wxT("#"), f1of1)
295  PARSER_THROWCHECK(PostfixOprt, true, wxT("&&"), f1of1)
296  PARSER_THROWCHECK(PostfixOprt, true, wxT("||"), f1of1)
297  PARSER_THROWCHECK(PostfixOprt, true, wxT("&"), f1of1)
298  PARSER_THROWCHECK(PostfixOprt, true, wxT("|"), f1of1)
299  PARSER_THROWCHECK(PostfixOprt, true, wxT("++"), f1of1)
300  PARSER_THROWCHECK(PostfixOprt, true, wxT("--"), f1of1)
301  PARSER_THROWCHECK(PostfixOprt, true, wxT("?>"), f1of1)
302  PARSER_THROWCHECK(PostfixOprt, true, wxT("?<"), f1of1)
303  PARSER_THROWCHECK(PostfixOprt, true, wxT("**"), f1of1)
304  PARSER_THROWCHECK(PostfixOprt, true, wxT("xor"), f1of1)
305  PARSER_THROWCHECK(PostfixOprt, true, wxT("and"), f1of1)
306  PARSER_THROWCHECK(PostfixOprt, true, wxT("or"), f1of1)
307  PARSER_THROWCHECK(PostfixOprt, true, wxT("not"), f1of1)
308  PARSER_THROWCHECK(PostfixOprt, true, wxT("!"), f1of1)
309  // Binary operator
310  // The following must fail with builtin operators activated
311  // p.EnableBuiltInOp(true); -> this is the default
312  PARSER_THROWCHECK(Oprt, false, wxT("+"), f1of2)
313  PARSER_THROWCHECK(Oprt, false, wxT("-"), f1of2)
314  PARSER_THROWCHECK(Oprt, false, wxT("*"), f1of2)
315  PARSER_THROWCHECK(Oprt, false, wxT("/"), f1of2)
316  // without activated built in operators it should work
317  p.EnableBuiltInOprt(false);
318  PARSER_THROWCHECK(Oprt, true, wxT("+"), f1of2)
319  PARSER_THROWCHECK(Oprt, true, wxT("-"), f1of2)
320  PARSER_THROWCHECK(Oprt, true, wxT("*"), f1of2)
321  PARSER_THROWCHECK(Oprt, true, wxT("/"), f1of2)
322  #undef PARSER_THROWCHECK
323 
324  if (iStat==0)
325  mu::console() << wxT("passed") << endl;
326  else
327  mu::console() << wxT("\n failed with ") << iStat << wxT(" errors") << endl;
328 
329  return iStat;
330  }
331 
332  //---------------------------------------------------------------------------
334  {
335  int iStat = 0;
336  mu::console() << wxT("testing syntax engine...");
337 
338  iStat += EqnTest(wxT("(1+ 2*a)"), 3, true); // Spaces within formula
339  iStat += EqnTest(wxT("sqrt((4))"), 2, true); // Multiple brackets
340  iStat += EqnTest(wxT("sqrt((2)+2)"), 2, true);// Multiple brackets
341  iStat += EqnTest(wxT("sqrt(2+(2))"), 2, true);// Multiple brackets
342  iStat += EqnTest(wxT("sqrt(a+(3))"), 2, true);// Multiple brackets
343  iStat += EqnTest(wxT("sqrt((3)+a)"), 2, true);// Multiple brackets
344  iStat += EqnTest(wxT("order(1,2)"), 1, true); // May not cause name collision with operator "or"
345  iStat += EqnTest(wxT("(2+"), 0, false); // missing closing bracket
346  iStat += EqnTest(wxT("2++4"), 0, false); // unexpected operator
347  iStat += EqnTest(wxT("2+-4"), 0, false); // unexpected operator
348  iStat += EqnTest(wxT("(2+)"), 0, false); // unexpected closing bracket
349  iStat += EqnTest(wxT("--2"), 0, false); // double sign
350  iStat += EqnTest(wxT("ksdfj"), 0, false); // unknown token
351  iStat += EqnTest(wxT("()"), 0, false); // empty bracket without a function
352  iStat += EqnTest(wxT("5+()"), 0, false); // empty bracket without a function
353  iStat += EqnTest(wxT("sin(cos)"), 0, false); // unexpected function
354  iStat += EqnTest(wxT("5t6"), 0, false); // unknown token
355  iStat += EqnTest(wxT("5 t 6"), 0, false); // unknown token
356  iStat += EqnTest(wxT("8*"), 0, false); // unexpected end of formula
357  iStat += EqnTest(wxT(",3"), 0, false); // unexpected comma
358  iStat += EqnTest(wxT("3,5"), 0, false); // unexpected comma
359  iStat += EqnTest(wxT("sin(8,8)"), 0, false); // too many function args
360  iStat += EqnTest(wxT("(7,8)"), 0, false); // too many function args
361  iStat += EqnTest(wxT("sin)"), 0, false); // unexpected closing bracket
362  iStat += EqnTest(wxT("a)"), 0, false); // unexpected closing bracket
363  iStat += EqnTest(wxT("pi)"), 0, false); // unexpected closing bracket
364  iStat += EqnTest(wxT("sin(())"), 0, false); // unexpected closing bracket
365  iStat += EqnTest(wxT("sin()"), 0, false); // unexpected closing bracket
366 
367  if (iStat==0)
368  mu::console() << wxT("passed") << endl;
369  else
370  mu::console() << wxT("\n failed with ") << iStat << wxT(" errors") << endl;
371 
372  return iStat;
373  }
374 
375  //---------------------------------------------------------------------------
377  {
378  int iStat = 0;
379  mu::console() << wxT("testing variable/constant name recognition...");
380 
381  // distinguish constants with same basename
382  iStat += EqnTest( wxT("const"), 1, true);
383  iStat += EqnTest( wxT("const1"), 2, true);
384  iStat += EqnTest( wxT("const2"), 3, true);
385  iStat += EqnTest( wxT("2*const"), 2, true);
386  iStat += EqnTest( wxT("2*const1"), 4, true);
387  iStat += EqnTest( wxT("2*const2"), 6, true);
388  iStat += EqnTest( wxT("2*const+1"), 3, true);
389  iStat += EqnTest( wxT("2*const1+1"), 5, true);
390  iStat += EqnTest( wxT("2*const2+1"), 7, true);
391  iStat += EqnTest( wxT("const"), 0, false);
392  iStat += EqnTest( wxT("const1"), 0, false);
393  iStat += EqnTest( wxT("const2"), 0, false);
394 
395  // distinguish variables with same basename
396  iStat += EqnTest( wxT("a"), 1, true);
397  iStat += EqnTest( wxT("aa"), 2, true);
398  iStat += EqnTest( wxT("2*a"), 2, true);
399  iStat += EqnTest( wxT("2*aa"), 4, true);
400  iStat += EqnTest( wxT("2*a-1"), 1, true);
401  iStat += EqnTest( wxT("2*aa-1"), 3, true);
402 
403  // Finally test querying of used variables
404  try
405  {
406  int idx;
407  mu::Parser p;
408  mu::value_type vVarVal[] = { 1, 2, 3, 4, 5};
409  p.DefineVar( wxT("a"), &vVarVal[0]);
410  p.DefineVar( wxT("b"), &vVarVal[1]);
411  p.DefineVar( wxT("c"), &vVarVal[2]);
412  p.DefineVar( wxT("d"), &vVarVal[3]);
413  p.DefineVar( wxT("e"), &vVarVal[4]);
414 
415  // Test lookup of defined variables
416  // 4 used variables
417  p.SetExpr( wxT("a+b+c+d") );
418  mu::varmap_type UsedVar = p.GetUsedVar();
419  int iCount = (int)UsedVar.size();
420  if (iCount!=4) throw false;
421 
422  mu::varmap_type::const_iterator item = UsedVar.begin();
423  for (idx=0; item!=UsedVar.end(); ++item)
424  {
425  if (&vVarVal[idx++]!=item->second)
426  throw false;
427  }
428 
429  // Test lookup of undefined variables
430  p.SetExpr( wxT("undef1+undef2+undef3") );
431  UsedVar = p.GetUsedVar();
432  iCount = (int)UsedVar.size();
433  if (iCount!=3) throw false;
434 
435  for (item = UsedVar.begin(); item!=UsedVar.end(); ++item)
436  {
437  if (item->second!=0)
438  throw false; // all pointers to undefined variables must be null
439  }
440 
441  // 1 used variables
442  p.SetExpr( wxT("a+b") );
443  UsedVar = p.GetUsedVar();
444  iCount = (int)UsedVar.size();
445  if (iCount!=2) throw false;
446  item = UsedVar.begin();
447  for (idx=0; item!=UsedVar.end(); ++item)
448  if (&vVarVal[idx++]!=item->second) throw false;
449 
450  }
451  catch(...)
452  {
453  iStat += 1;
454  }
455 
456  if (iStat==0)
457  mu::console() << wxT("passed") << endl;
458  else
459  mu::console() << wxT("\n failed with ") << iStat << wxT(" errors") << endl;
460 
461  return iStat;
462  }
463 
464  //---------------------------------------------------------------------------
466  {
467  int iStat = 0;
468  mu::console() << wxT("testing multiarg functions...");
469 
470  // picking the right argument
471  iStat += EqnTest( wxT("f1of1(1)"), 1, true);
472  iStat += EqnTest( wxT("f1of2(1, 2)"), 1, true);
473  iStat += EqnTest( wxT("f2of2(1, 2)"), 2, true);
474  iStat += EqnTest( wxT("f1of3(1, 2, 3)"), 1, true);
475  iStat += EqnTest( wxT("f2of3(1, 2, 3)"), 2, true);
476  iStat += EqnTest( wxT("f3of3(1, 2, 3)"), 3, true);
477  iStat += EqnTest( wxT("f1of4(1, 2, 3, 4)"), 1, true);
478  iStat += EqnTest( wxT("f2of4(1, 2, 3, 4)"), 2, true);
479  iStat += EqnTest( wxT("f3of4(1, 2, 3, 4)"), 3, true);
480  iStat += EqnTest( wxT("f4of4(1, 2, 3, 4)"), 4, true);
481  iStat += EqnTest( wxT("f1of5(1, 2, 3, 4, 5)"), 1, true);
482  iStat += EqnTest( wxT("f2of5(1, 2, 3, 4, 5)"), 2, true);
483  iStat += EqnTest( wxT("f3of5(1, 2, 3, 4, 5)"), 3, true);
484  iStat += EqnTest( wxT("f4of5(1, 2, 3, 4, 5)"), 4, true);
485  iStat += EqnTest( wxT("f5of5(1, 2, 3, 4, 5)"), 5, true);
486  // Too few arguments / Too many arguments
487  iStat += EqnTest( wxT("1+ping()"), 11, true);
488  iStat += EqnTest( wxT("ping()+1"), 11, true);
489  iStat += EqnTest( wxT("2*ping()"), 20, true);
490  iStat += EqnTest( wxT("ping()*2"), 20, true);
491  iStat += EqnTest( wxT("ping(1,2)"), 0, false);
492  iStat += EqnTest( wxT("1+ping(1,2)"), 0, false);
493  iStat += EqnTest( wxT("f1of1(1,2)"), 0, false);
494  iStat += EqnTest( wxT("f1of1()"), 0, false);
495  iStat += EqnTest( wxT("f1of2(1, 2, 3)"), 0, false);
496  iStat += EqnTest( wxT("f1of2(1)"), 0, false);
497  iStat += EqnTest( wxT("f1of3(1, 2, 3, 4)"), 0, false);
498  iStat += EqnTest( wxT("f1of3(1)"), 0, false);
499  iStat += EqnTest( wxT("f1of4(1, 2, 3, 4, 5)"), 0, false);
500  iStat += EqnTest( wxT("f1of4(1)"), 0, false);
501  iStat += EqnTest( wxT("(1,2,3)"), 0, false);
502  iStat += EqnTest( wxT("1,2,3"), 0, false);
503  iStat += EqnTest( wxT("(1*a,2,3)"), 0, false);
504  iStat += EqnTest( wxT("1,2*a,3"), 0, false);
505 
506  // correct calculation of arguments
507  iStat += EqnTest( wxT("min(a, 1)"), 1, true);
508  iStat += EqnTest( wxT("min(3*2, 1)"), 1, true);
509  iStat += EqnTest( wxT("min(3*2, 1)"), 6, false);
510  iStat += EqnTest( wxT("firstArg(2,3,4)"), 2, true);
511  iStat += EqnTest( wxT("lastArg(2,3,4)"), 4, true);
512  iStat += EqnTest( wxT("min(3*a+1, 1)"), 1, true);
513  iStat += EqnTest( wxT("max(3*a+1, 1)"), 4, true);
514  iStat += EqnTest( wxT("max(3*a+1, 1)*2"), 8, true);
515  iStat += EqnTest( wxT("2*max(3*a+1, 1)+2"), 10, true);
516 
517  // functions with Variable argument count
518  iStat += EqnTest( wxT("sum(a)"), 1, true);
519  iStat += EqnTest( wxT("sum(1,2,3)"), 6, true);
520  iStat += EqnTest( wxT("sum(a,b,c)"), 6, true);
521  iStat += EqnTest( wxT("sum(1,-max(1,2),3)*2"), 4, true);
522  iStat += EqnTest( wxT("2*sum(1,2,3)"), 12, true);
523  iStat += EqnTest( wxT("2*sum(1,2,3)+2"), 14, true);
524  iStat += EqnTest( wxT("2*sum(-1,2,3)+2"), 10, true);
525  iStat += EqnTest( wxT("2*sum(-1,2,-(-a))+2"), 6, true);
526  iStat += EqnTest( wxT("2*sum(-1,10,-a)+2"), 18, true);
527  iStat += EqnTest( wxT("2*sum(1,2,3)*2"), 24, true);
528  iStat += EqnTest( wxT("sum(1,-max(1,2),3)*2"), 4, true);
529  iStat += EqnTest( wxT("sum(1*3, 4, a+2)"), 10, true);
530  iStat += EqnTest( wxT("sum(1*3, 2*sum(1,2,2), a+2)"), 16, true);
531  iStat += EqnTest( wxT("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);
532 
533  // some failures
534  iStat += EqnTest( wxT("sum()"), 0, false);
535  iStat += EqnTest( wxT("sum(,)"), 0, false);
536  iStat += EqnTest( wxT("sum(1,2,)"), 0, false);
537  iStat += EqnTest( wxT("sum(,1,2)"), 0, false);
538 
539  if (iStat==0)
540  mu::console() << wxT("passed") << endl;
541  else
542  mu::console() << wxT("\n failed with ") << iStat << wxT(" errors") << endl;
543 
544  return iStat;
545  }
546 
547 
548  //---------------------------------------------------------------------------
550  {
551  int iStat(0);
552  mu::console() << "testing infix operators...";
553 
554  iStat += EqnTest( wxT("-1"), -1, true);
555  iStat += EqnTest( wxT("-(-1)"), 1, true);
556  iStat += EqnTest( wxT("-(-1)*2"), 2, true);
557  iStat += EqnTest( wxT("-(-2)*sqrt(4)"), 4, true);
558  iStat += EqnTest( wxT("-a"), -1, true);
559  iStat += EqnTest( wxT("-(a)"), -1, true);
560  iStat += EqnTest( wxT("-(-a)"), 1, true);
561  iStat += EqnTest( wxT("-(-a)*2"), 2, true);
562  iStat += EqnTest( wxT("-(8)"), -8, true);
563  iStat += EqnTest( wxT("-8"), -8, true);
564  iStat += EqnTest( wxT("-(2+1)"), -3, true);
565  iStat += EqnTest( wxT("-(f1of1(1+2*3)+1*2)"), -9, true);
566  iStat += EqnTest( wxT("-(-f1of1(1+2*3)+1*2)"), 5, true);
567  iStat += EqnTest( wxT("-sin(8)"), -0.989358, true);
568  iStat += EqnTest( wxT("3-(-a)"), 4, true);
569  iStat += EqnTest( wxT("3--a"), 4, true);
570 
571  // Postfix / infix priorities
572  iStat += EqnTest( wxT("~2#"), 8, true);
573  iStat += EqnTest( wxT("~f1of1(2)#"), 8, true);
574  iStat += EqnTest( wxT("~(b)#"), 8, true);
575  iStat += EqnTest( wxT("(~b)#"), 12, true);
576  iStat += EqnTest( wxT("~(2#)"), 8, true);
577  iStat += EqnTest( wxT("~(f1of1(2)#)"), 8, true);
578  //
579  iStat += EqnTest( wxT("-2^2"),-4, true);
580  iStat += EqnTest( wxT("-(a+b)^2"),-9, true);
581  iStat += EqnTest( wxT("(-3)^2"),9, true);
582  iStat += EqnTest( wxT("-(-2^2)"),4, true);
583  iStat += EqnTest( wxT("3+-3^2"),-6, true);
584  // The following assumes use of sqr as postfix operator ("?") together
585  // withn a sign operator of low priority:
586  iStat += EqnTest( wxT("-2?"), -4, true);
587  iStat += EqnTest( wxT("-(1+1)?"),-4, true);
588  iStat += EqnTest( wxT("2+-(1+1)?"),-2, true);
589  iStat += EqnTest( wxT("2+-2?"), -2, true);
590  // This is the classic behaviour of the infix sign operator (here: "$") which is
591  // now deprecated:
592  iStat += EqnTest( wxT("$2^2"),4, true);
593  iStat += EqnTest( wxT("$(a+b)^2"),9, true);
594  iStat += EqnTest( wxT("($3)^2"),9, true);
595  iStat += EqnTest( wxT("$($2^2)"),-4, true);
596  iStat += EqnTest( wxT("3+$3^2"),12, true);
597 
598  if (iStat==0)
599  mu::console() << wxT("passed") << endl;
600  else
601  mu::console() << wxT("\n failed with ") << iStat << wxT(" errors") << endl;
602 
603  return iStat;
604  }
605 
606 
607  //---------------------------------------------------------------------------
609  {
610  int iStat = 0;
611  mu::console() << wxT("testing postfix operators...");
612 
613  // application
614  iStat += EqnTest( wxT("3m+5"), 5.003, true);
615  iStat += EqnTest( wxT("1000m"), 1, true);
616  iStat += EqnTest( wxT("1000 m"), 1, true);
617  iStat += EqnTest( wxT("(a)m"), 1e-3, true);
618  iStat += EqnTest( wxT("-(a)m"), -1e-3, true);
619  iStat += EqnTest( wxT("-2m"), -2e-3, true);
620  iStat += EqnTest( wxT("f1of1(1000)m"), 1, true);
621  iStat += EqnTest( wxT("-f1of1(1000)m"), -1, true);
622  iStat += EqnTest( wxT("-f1of1(-1000)m"), 1, true);
623  iStat += EqnTest( wxT("f4of4(0,0,0,1000)m"), 1, true);
624  iStat += EqnTest( wxT("2+(a*1000)m"), 3, true);
625  // some incorrect results
626  iStat += EqnTest( wxT("1000m"), 0.1, false);
627  iStat += EqnTest( wxT("(a)m"), 2, false);
628  // failure due to syntax checking
629  iStat += EqnTest( wxT("a m"), 0, false);
630  iStat += EqnTest( wxT("4 + m"), 0, false);
631  iStat += EqnTest( wxT("m4"), 0, false);
632  iStat += EqnTest( wxT("sin(m)"), 0, false);
633  iStat += EqnTest( wxT("m m"), 0, false);
634  iStat += EqnTest( wxT("m(8)"), 0, false);
635  iStat += EqnTest( wxT("4,m"), 0, false);
636  iStat += EqnTest( wxT("-m"), 0, false);
637  iStat += EqnTest( wxT("2(-m)"), 0, false);
638  iStat += EqnTest( wxT("2(m)"), 0, false);
639 
640  if (iStat==0)
641  mu::console() << wxT("passed") << endl;
642  else
643  mu::console() << wxT("\n failed with ") << iStat << wxT(" errors") << endl;
644 
645  return iStat;
646  }
647 
648  //---------------------------------------------------------------------------
649  /** \brief Test volatile (nonoptimizeable functions). */
651  {
652  int iStat = 0;
653  mu::console() << "testing volatile/nonvolatile functions...";
654 
655  // First test with volatile flag turned on
656  try
657  {
658  mu::Parser p;
659  p.DefineFun( wxT("rnd"), Rnd, false);
660  p.DefineFun( wxT("valueof"), RndWithString, false);
661 
662  // 1st test, compare results from sucessive calculations
663  p.SetExpr( wxT("3+rnd(8)") );
664  if (p.Eval()==p.Eval()) iStat += 1;
665 
666  // 2nd test, force bytecode creation, compare two results both
667  // calculated from bytecode
668  p.SetExpr( wxT("3+rnd(8)") );
669  p.Eval(); //<- Force bytecode creation
670  if (p.Eval()==p.Eval()) iStat += 1;
671 
672  p.SetExpr( wxT("3*rnd(8)+3") );
673  p.Eval(); //<- Force bytecode creation
674  if (p.Eval()==p.Eval()) iStat += 1;
675 
676  p.SetExpr( wxT("10+3*sin(rnd(8))-1") );
677  p.Eval(); //<- Force bytecode creation
678  if (p.Eval()==p.Eval()) iStat += 1;
679 
680  p.SetExpr( wxT("3+rnd(rnd(8))*2") );
681  p.Eval(); //<- Force bytecode creation
682  if (p.Eval()==p.Eval()) iStat += 1;
683 
684  p.SetExpr( wxT("valueof(\"Das ist ein Test\")") );
685  p.Eval(); //<- Force bytecode creation
686  if (p.Eval()==p.Eval()) iStat += 1;
687  }
688  catch(Parser::exception_type &e)
689  {
690  mu::console() << wxT("\n ") << e.GetExpr() << wxT(" : ") << e.GetMsg();
691  iStat += 1;
692  }
693 
694  // Second test with volatile flag turned off
695  try
696  {
697  mu::Parser p;
698  p.DefineFun( wxT("rnd"), Rnd);
699  p.DefineFun( wxT("valueof"), RndWithString);
700 
701  // compare string parsing with bytecode
702  p.SetExpr( wxT("3+rnd(8)") );
703  if (p.Eval()!=p.Eval()) iStat += 1;
704 
705  p.SetExpr( wxT("3+rnd(8)") );
706  p.Eval(); //<- Force bytecode creation
707  if (p.Eval()!=p.Eval()) iStat += 1;
708 
709  p.SetExpr( wxT("3*rnd(8)+3") );
710  p.Eval(); //<- Force bytecode creation
711  if (p.Eval()!=p.Eval()) iStat += 1;
712 
713  p.SetExpr( wxT("10+3*sin(rnd(8))-1") );
714  p.Eval(); //<- Force bytecode creation
715  if (p.Eval()!=p.Eval()) iStat += 1;
716 
717  p.SetExpr( wxT("3+rnd(rnd(8))*2") );
718  p.Eval(); //<- Force bytecode creation
719  if (p.Eval()!=p.Eval()) iStat += 1;
720  }
721  catch(Parser::exception_type &e)
722  {
723  mu::console() << wxT("\n ") << e.GetExpr() << wxT(" : ") << e.GetMsg();
724  iStat += 1;
725  }
726 
727  if (iStat==0)
728  mu::console() << wxT("passed") << endl;
729  else
730  mu::console() << wxT("\n failed with ") << iStat << wxT(" errors") << endl;
731 
732  return iStat;
733  }
734 
735  //---------------------------------------------------------------------------
737  {
738  int iStat = 0;
739  mu::console() << wxT("testing sample formulas...");
740 
741  // operator precedencs
742  iStat += EqnTest( wxT("1+2-3*4/5^6"), 2.99923, true);
743  iStat += EqnTest( wxT("1^2/3*4-5+6"), 2.3333, true);
744  iStat += EqnTest( wxT("1+2*3"), 7, true);
745  iStat += EqnTest( wxT("1+2*3"), 7, true);
746  iStat += EqnTest( wxT("(1+2)*3"), 9, true);
747  iStat += EqnTest( wxT("(1+2)*(-3)"), -9, true);
748  iStat += EqnTest( wxT("2/4"), 0.5, true);
749 
750  iStat += EqnTest( wxT("exp(ln(7))"), 7, true);
751  iStat += EqnTest( wxT("e^ln(7)"), 7, true);
752  iStat += EqnTest( wxT("e^(ln(7))"), 7, true);
753  iStat += EqnTest( wxT("(e^(ln(7)))"), 7, true);
754  iStat += EqnTest( wxT("1-(e^(ln(7)))"), -6, true);
755  iStat += EqnTest( wxT("2*(e^(ln(7)))"), 14, true);
756  iStat += EqnTest( wxT("10^log(5)"), 5, true);
757  iStat += EqnTest( wxT("10^log10(5)"), 5, true);
758  iStat += EqnTest( wxT("2^log2(4)"), 4, true);
759  iStat += EqnTest( wxT("-(sin(0)+1)"), -1, true);
760  iStat += EqnTest( wxT("-(2^1.1)"), -2.14354692, true);
761 
762  iStat += EqnTest( wxT("(cos(2.41)/b)"), -0.372056, true);
763 
764 #if !defined(MUP_UNICODE)
765  // I can't translate the following two tests to unicode without loosing
766  // readability.
767 
768  // long formula (Reference: Matlab)
769  iStat += EqnTest(
770  "(((-9))-e/(((((((pi-(((-7)+(-3)/4/e))))/(((-5))-2)-((pi+(-0))*(sqrt((e+e))*(-8))*(((-pi)+(-pi)-(-9)*(6*5))"
771  "/(-e)-e))/2)/((((sqrt(2/(-e)+6)-(4-2))+((5/(-2))/(1*(-pi)+3))/8)*pi*((pi/((-2)/(-6)*1*(-1))*(-6)+(-e)))))/"
772  "((e+(-2)+(-e)*((((-3)*9+(-e)))+(-9)))))))-((((e-7+(((5/pi-(3/1+pi)))))/e)/(-5))/(sqrt((((((1+(-7))))+((((-"
773  "e)*(-e)))-8))*(-5)/((-e)))*(-6)-((((((-2)-(-9)-(-e)-1)/3))))/(sqrt((8+(e-((-6))+(9*(-9))))*(((3+2-8))*(7+6"
774  "+(-5))+((0/(-e)*(-pi))+7)))+(((((-e)/e/e)+((-6)*5)*e+(3+(-5)/pi))))+pi))/sqrt((((9))+((((pi))-8+2))+pi))/e"
775  "*4)*((-5)/(((-pi))*(sqrt(e)))))-(((((((-e)*(e)-pi))/4+(pi)*(-9)))))))+(-pi)", -12.23016549, true);
776 
777  // long formula (Reference: Matlab)
778  iStat += EqnTest(
779  "(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"
780  ")+a)))*2.77)", -2.16995656, true);
781 #endif
782 
783  // long formula (Reference: Matlab)
784  iStat += EqnTest( wxT("1+2-3*4/5^6*(2*(1-5+(3*7^9)*(4+6*7-3)))+12"), -7995810.09926, true);
785 
786  if (iStat==0)
787  mu::console() << wxT("passed") << endl;
788  else
789  mu::console() << wxT("\n failed with ") << iStat << wxT(" errors") << endl;
790 
791  return iStat;
792  }
793 
794 
795  //---------------------------------------------------------------------------
797  {
798  int iStat = 0;
799  mu::console() << wxT("testing error codes...");
800 
801  iStat += ThrowTest(wxT("3+"), ecUNEXPECTED_EOF);
802  iStat += ThrowTest(wxT("3+)"), ecUNEXPECTED_PARENS);
803  iStat += ThrowTest(wxT("()"), ecUNEXPECTED_PARENS);
804  iStat += ThrowTest(wxT("3+()"), ecUNEXPECTED_PARENS);
805  iStat += ThrowTest(wxT("sin(3,4)"), ecTOO_MANY_PARAMS);
806  iStat += ThrowTest(wxT("3,4"), ecUNEXPECTED_ARG_SEP);
807  iStat += ThrowTest(wxT("if(3)"), ecTOO_FEW_PARAMS);
808  iStat += ThrowTest(wxT("(1+2"), ecMISSING_PARENS);
809  iStat += ThrowTest(wxT("sin(3)3"), ecUNEXPECTED_VAL);
810  iStat += ThrowTest(wxT("sin(3)xyz"), ecUNASSIGNABLE_TOKEN);
811  iStat += ThrowTest(wxT("sin(3)cos(3)"), ecUNEXPECTED_FUN);
812  iStat += ThrowTest(wxT("a+b+c=10"), ecUNEXPECTED_OPERATOR);
813  iStat += ThrowTest(wxT("a=b=3"), ecUNEXPECTED_OPERATOR);
814 
815  // functions without parameter
816  iStat += ThrowTest( wxT("3+ping(2)"), ecTOO_MANY_PARAMS);
817  iStat += ThrowTest( wxT("3+ping(a+2)"), ecTOO_MANY_PARAMS);
818  iStat += ThrowTest( wxT("3+ping(sin(a)+2)"), ecTOO_MANY_PARAMS);
819  iStat += ThrowTest( wxT("3+ping(1+sin(a))"), ecTOO_MANY_PARAMS);
820 
821  // String function related
822  iStat += ThrowTest( wxT("valueof(\"xxx\")"), 999, false);
823  iStat += ThrowTest( wxT("valueof()"), ecUNEXPECTED_PARENS);
824  iStat += ThrowTest( wxT("1+valueof(\"abc\""), ecMISSING_PARENS);
825  iStat += ThrowTest( wxT("valueof(\"abc\""), ecMISSING_PARENS);
826  iStat += ThrowTest( wxT("valueof(\"abc"), ecUNTERMINATED_STRING);
827  iStat += ThrowTest( wxT("valueof(\"abc\",3)"), ecTOO_MANY_PARAMS);
828  iStat += ThrowTest( wxT("valueof(3)"), ecSTRING_EXPECTED);
829  iStat += ThrowTest( wxT("sin(\"abc\")"), ecVAL_EXPECTED);
830  iStat += ThrowTest( wxT("valueof(\"\\\"abc\\\"\")"), 999, false);
831  iStat += ThrowTest( wxT("\"hello world\""), ecSTR_RESULT);
832  iStat += ThrowTest( wxT("(\"hello world\")"), ecSTR_RESULT);
833  iStat += ThrowTest( wxT("\"abcd\"+100"), ecOPRT_TYPE_CONFLICT);
834  iStat += ThrowTest( wxT("\"a\"+\"b\""), ecOPRT_TYPE_CONFLICT);
835  iStat += ThrowTest( wxT("strfun1(\"100\",3)"), ecTOO_MANY_PARAMS);
836  iStat += ThrowTest( wxT("strfun2(\"100\",3,5)"), ecTOO_MANY_PARAMS);
837  iStat += ThrowTest( wxT("strfun3(\"100\",3,5,6)"), ecTOO_MANY_PARAMS);
838  iStat += ThrowTest( wxT("strfun2(\"100\")"), ecTOO_FEW_PARAMS);
839  iStat += ThrowTest( wxT("strfun3(\"100\",6)"), ecTOO_FEW_PARAMS);
840  iStat += ThrowTest( wxT("strfun2(1,1)"), ecSTRING_EXPECTED);
841  iStat += ThrowTest( wxT("strfun2(a,1)"), ecSTRING_EXPECTED);
842  iStat += ThrowTest( wxT("strfun2(1,1,1)"), ecTOO_MANY_PARAMS);
843  iStat += ThrowTest( wxT("strfun2(a,1,1)"), ecTOO_MANY_PARAMS);
844  iStat += ThrowTest( wxT("strfun3(1,2,3)"), ecSTRING_EXPECTED);
845  iStat += ThrowTest( wxT("strfun3(1, \"100\",3)"), ecSTRING_EXPECTED);
846  iStat += ThrowTest( wxT("strfun3(\"1\", \"100\",3)"), ecVAL_EXPECTED);
847  iStat += ThrowTest( wxT("strfun3(\"1\", 3, \"100\")"), ecVAL_EXPECTED);
848  iStat += ThrowTest( wxT("strfun3(\"1\", \"100\", \"100\", \"100\")"), ecTOO_MANY_PARAMS);
849 
850  // assignement operator
851  iStat += ThrowTest( wxT("3=4"), ecUNEXPECTED_OPERATOR);
852  iStat += ThrowTest( wxT("sin(8)=4"), ecUNEXPECTED_OPERATOR);
853  iStat += ThrowTest( wxT("\"test\"=a"), ecUNEXPECTED_OPERATOR);
854  iStat += ThrowTest( wxT("sin=9"), ecUNEXPECTED_OPERATOR);
855  iStat += ThrowTest( wxT("(8)=5"), ecUNEXPECTED_OPERATOR);
856  iStat += ThrowTest( wxT("(a)=5"), ecUNEXPECTED_OPERATOR);
857  iStat += ThrowTest( wxT("a=\"tttt\""), ecOPRT_TYPE_CONFLICT);
858 
859  if (iStat==0)
860  mu::console() << wxT("passed") << endl;
861  else
862  mu::console() << wxT("\n failed with ") << iStat << wxT(" errors") << endl;
863 
864  return iStat;
865  }
866 
867 
868  //---------------------------------------------------------------------------
869  void ParserTester::AddTest(testfun_type a_pFun)
870  {
871  m_vTestFun.push_back(a_pFun);
872  }
873 
874  //---------------------------------------------------------------------------
876  {
877  int iStat = 0;
878  try
879  {
880  for (int i=0; i<(int)m_vTestFun.size(); ++i)
881  iStat += (this->*m_vTestFun[i])();
882  }
883  catch(Parser::exception_type &e)
884  {
885  mu::console() << "\n" << e.GetMsg() << endl;
886  mu::console() << e.GetToken() << endl;
887  Abort();
888  }
889  catch(std::exception &e)
890  {
891  mu::console() << e.what() << endl;
892  Abort();
893  }
894  catch(...)
895  {
896  mu::console() << "Internal error";
897  Abort();
898  }
899 
900  if (iStat==0)
901  {
902  mu::console() << "Test passed (" << ParserTester::c_iCount << " expressions)" << endl;
903  }
904  else
905  {
906  mu::console() << "Test failed with " << iStat
907  << " errors (" << ParserTester::c_iCount
908  << " expressions)" << endl;
909  }
911  }
912 
913 
914  //---------------------------------------------------------------------------
915  int ParserTester::ThrowTest(const string_type &a_str, int a_iErrc, bool a_bFail)
916  {
918 
919  try
920  {
921  value_type fVal[] = {1,1,1};
922  Parser p;
923 
924  p.DefineVar( wxT("a"), &fVal[0]);
925  p.DefineVar( wxT("b"), &fVal[1]);
926  p.DefineVar( wxT("c"), &fVal[2]);
927 
928  p.DefineFun( wxT("ping"), Ping);
929  p.DefineFun( wxT("valueof"), ValueOf);
930  p.DefineFun( wxT("strfun1"), StrFun1);
931  p.DefineFun( wxT("strfun2"), StrFun2);
932  p.DefineFun( wxT("strfun3"), StrFun3);
933  p.SetExpr(a_str);
934  p.Eval();
935  }
936  catch(Parser::exception_type &e)
937  {
938  // output the formula in case of an failed test
939  if (a_bFail==false || (a_bFail==true && a_iErrc!=e.GetCode()) )
940  {
941  mu::console() << wxT("\n ")
942  << wxT("Expression: ") << a_str
943  << wxT(" Code:") << e.GetCode()
944  << wxT(" Expected:") << a_iErrc;
945  }
946 
947  return (a_iErrc==e.GetCode()) ? 0 : 1;
948  }
949 
950  // if a_bFail==false no exception is expected
951  bool bRet((a_bFail==false) ? 0 : 1);
952  if (bRet==1)
953  {
954  mu::console() << wxT("\n ")
955  << wxT("Expression: ") << a_str
956  << wxT(" did evaluate; Expected error:") << a_iErrc;
957  }
958 
959  return bRet;
960  }
961 
962  //---------------------------------------------------------------------------
963  /** \brief Evaluate a tet expression.
964 
965  \return 1 in case of a failure, 0 otherwise.
966  */
967  int ParserTester::EqnTest(const string_type &a_str, double a_fRes, bool a_fPass)
968  {
970  int iRet(0);
971 
972  try
973  {
974  Parser *p1, p2, p3; // three parser objects
975  // they will be used for testing copy and assihnment operators
976  // p1 is a pointer since i'm going to delete it in order to test if
977  // parsers after copy construction still refer to members of it.
978  // !! If this is the case this function will crash !!
979 
980  p1 = new mu::Parser();
981  // Add constants
984  p1->DefineConst( wxT("const"), 1);
985  p1->DefineConst( wxT("const1"), 2);
986  p1->DefineConst( wxT("const2"), 3);
987  // variables
988  value_type vVarVal[] = { 1, 2, 3, -2};
989  p1->DefineVar( wxT("a"), &vVarVal[0]);
990  p1->DefineVar( wxT("aa"), &vVarVal[1]);
991  p1->DefineVar( wxT("b"), &vVarVal[1]);
992  p1->DefineVar( wxT("c"), &vVarVal[2]);
993  p1->DefineVar( wxT("d"), &vVarVal[3]);
994  // functions
995  p1->DefineFun( wxT("ping"), Ping);
996  p1->DefineFun( wxT("f1of1"), f1of1); // one parameter
997  p1->DefineFun( wxT("f1of2"), f1of2); // two parameter
998  p1->DefineFun( wxT("f2of2"), f2of2);
999  p1->DefineFun( wxT("f1of3"), f1of3); // three parameter
1000  p1->DefineFun( wxT("f2of3"), f2of3);
1001  p1->DefineFun( wxT("f3of3"), f3of3);
1002  p1->DefineFun( wxT("f1of4"), f1of4); // four parameter
1003  p1->DefineFun( wxT("f2of4"), f2of4);
1004  p1->DefineFun( wxT("f3of4"), f3of4);
1005  p1->DefineFun( wxT("f4of4"), f4of4);
1006  p1->DefineFun( wxT("f1of5"), f1of5); // five parameter
1007  p1->DefineFun( wxT("f2of5"), f2of5);
1008  p1->DefineFun( wxT("f3of5"), f3of5);
1009  p1->DefineFun( wxT("f4of5"), f4of5);
1010  p1->DefineFun( wxT("f5of5"), f5of5);
1011  // sample functions
1012  p1->DefineFun( wxT("min"), Min);
1013  p1->DefineFun( wxT("max"), Max);
1014  p1->DefineFun( wxT("sum"), Sum);
1015  p1->DefineFun( wxT("valueof"), ValueOf);
1016  p1->DefineFun( wxT("atof"), StrToFloat);
1017  p1->DefineFun( wxT("strfun1"), StrFun1);
1018  p1->DefineFun( wxT("strfun2"), StrFun2);
1019  p1->DefineFun( wxT("strfun3"), StrFun3);
1020  p1->DefineFun( wxT("lastArg"), LastArg);
1021  p1->DefineFun( wxT("firstArg"), FirstArg);
1022  p1->DefineFun( wxT("order"), FirstArg);
1023 
1024  // infix / postfix operator
1025  // (identifiers used here do not have any meaning or make any sense at all)
1026  p1->DefineInfixOprt( wxT("$"), sign, prPOW+1); // sign with high priority
1027  p1->DefineInfixOprt( wxT("~"), plus2); // high priority
1028  p1->DefinePostfixOprt( wxT("m"), Milli);
1029  p1->DefinePostfixOprt( wxT("#"), times3);
1030  p1->DefinePostfixOprt( wxT("?"), sqr); //
1031  p1->SetExpr(a_str);
1032 
1033  // Test bytecode integrity
1034  // String parsing and bytecode parsing must yield the same result
1035  value_type fVal[4] = {-999, -998, -997, -996}; // initially should be different
1036  fVal[0] = p1->Eval(); // result from stringparsing
1037  fVal[1] = p1->Eval(); // result from bytecode
1038  if (fVal[0]!=fVal[1])
1039  throw Parser::exception_type( wxT("Bytecode / string parsing mismatch.") );
1040 
1041  // Test copy and assignement operators
1042  try
1043  {
1044  // Test copy constructor
1045  std::vector<mu::Parser> vParser;
1046  vParser.push_back(*p1);
1047  mu::Parser p2 = vParser[0]; // take parser from vector
1048 
1049  // destroy the originals from p2
1050  vParser.clear(); // delete the vector
1051  delete p1; // delete the original
1052  p1 = 0;
1053 
1054  fVal[2] = p2.Eval();
1055 
1056  // Test assignement operator
1057  // additionally disable Optimizer this time
1058  mu::Parser p3;
1059  p3 = p2;
1060  p3.EnableOptimizer(false);
1061  fVal[3] = p3.Eval();
1062  }
1063  catch(std::exception &e)
1064  {
1065  mu::console() << wxT("\n ") << e.what() << wxT("\n");
1066  }
1067 
1068  // limited floating point accuracy requires the following test
1069  bool bCloseEnough(true);
1070  for (int i=0; i<4; ++i)
1071  {
1072  bCloseEnough &= (fabs(a_fRes-fVal[i]) <= fabs(fVal[i]*0.0001));
1073  }
1074 
1075  iRet = ((bCloseEnough && a_fPass) || (!bCloseEnough && !a_fPass)) ? 0 : 1;
1076  if (iRet==1)
1077  {
1078  mu::console() << wxT("\n fail: ") << a_str.c_str()
1079  << wxT(" (incorrect result; expected: ") << a_fRes
1080  << wxT(" ;calculated: ") << fVal[0]<< wxT(").");
1081  }
1082  }
1083  catch(Parser::exception_type &e)
1084  {
1085  if (a_fPass)
1086  {
1087  mu::console() << wxT("\n fail: ") << a_str.c_str() << wxT(" (") << e.GetMsg() << wxT(")");
1088  return 1;
1089  }
1090  }
1091  catch(std::exception &e)
1092  {
1093  mu::console() << wxT("\n fail: ") << a_str.c_str() << wxT(" (") << e.what() << wxT(")");
1094  return 1; // always return a failure since this exception is not expected
1095  }
1096  catch(...)
1097  {
1098  mu::console() << wxT("\n fail: ") << a_str.c_str() << wxT(" (unexpected exception)");
1099  return 1; // exceptions other than ParserException are not allowed
1100  }
1101 
1102  return iRet;
1103  }
1104 
1105  //---------------------------------------------------------------------------
1106  int ParserTester::EqnTestInt(const string_type &a_str, double a_fRes, bool a_fPass)
1107  {
1109 
1110  value_type vVarVal[] = {1, 2, 3}; // variable values
1111  value_type fVal[2] = {-99, -999}; // results: initially should be different
1112  int iRet(0);
1113 
1114  try
1115  {
1116  ParserInt p;
1117  p.DefineConst( wxT("const1"), 1);
1118  p.DefineConst( wxT("const2"), 2);
1119  p.DefineVar( wxT("a"), &vVarVal[0]);
1120  p.DefineVar( wxT("b"), &vVarVal[1]);
1121  p.DefineVar( wxT("c"), &vVarVal[2]);
1122 
1123  p.SetExpr(a_str);
1124  fVal[0] = p.Eval(); // result from stringparsing
1125  fVal[1] = p.Eval(); // result from bytecode
1126 
1127  if (fVal[0]!=fVal[1])
1128  throw Parser::exception_type( wxT("Bytecode corrupt.") );
1129 
1130  iRet = ( (a_fRes==fVal[0] && a_fPass) ||
1131  (a_fRes!=fVal[0] && !a_fPass) ) ? 0 : 1;
1132  if (iRet==1)
1133  {
1134  mu::console() << wxT("\n fail: ") << a_str.c_str()
1135  << wxT(" (incorrect result; expected: ") << a_fRes
1136  << wxT(" ;calculated: ") << fVal[0]<< wxT(").");
1137  }
1138  }
1139  catch(Parser::exception_type &e)
1140  {
1141  if (a_fPass)
1142  {
1143  mu::console() << wxT("\n fail: ") << e.GetExpr() << wxT(" : ") << e.GetMsg();
1144  iRet = 1;
1145  }
1146  }
1147  catch(...)
1148  {
1149  mu::console() << wxT("\n fail: ") << a_str.c_str() << wxT(" (unexpected exception)");
1150  iRet = 1; // exceptions other than ParserException are not allowed
1151  }
1152 
1153  return iRet;
1154  }
1155 
1156  //---------------------------------------------------------------------------
1157  /** \brief Internal error in test class Test is going to be aborted. */
1158  void ParserTester::Abort() const
1159  {
1160  mu::console() << wxT("Test failed (internal error in test class)") << endl;
1161  while (!getchar());
1162  exit(-1);
1163  }
1164  } // namespace test
1165 } // namespace mu
void EnableOptimizer(bool a_bIsOn=true)
Enable or disable the formula optimization feature.
void DefineInfixOprt(const string_type &a_strName, fun_type1 a_pOprt, int a_iPrec=prINFIX, bool a_bAllowOpt=true)
Add a user defined operator.
value_type Eval() const
Calculate the result.
Definition: muParserBase.h:116
void DefineVar(const string_type &a_sName, value_type *a_fVar)
Add a user defined variable.
void DefineConst(const string_type &a_sName, value_type a_fVal)
Add a user defined constant.
void RemoveVar(const string_type &a_strVarName)
Remove a variable from internal storage.
ParserError exception_type
Type of the error class.
Definition: muParserBase.h:92
void ClearConst()
Clear all user defined constants.
void EnableBuiltInOprt(bool a_bIsOn=true)
Enable or disable the built in binary operators.
void DefinePostfixOprt(const string_type &a_strFun, fun_type1 a_pOprt, bool a_bAllowOpt=true)
Add a user defined operator.
void SetExpr(const string_type &a_sExpr)
Set the formula.
void DefineFun(const string_type &a_strName, fun_type0 a_pFun, bool a_bAllowOpt=true)
Definition: muParserBase.h:138
const varmap_type & GetUsedVar() const
Return a map containing the used variables only.
Error class of the parser.
EErrorCodes GetCode() const
Return the error code.
const string_type & GetMsg() const
Returns the message string for this error.
const string_type & GetExpr() const
gets the expression related tp this error.
const string_type & GetToken() const
Return string related with this token (if available).
Mathematical expressions parser.
Definition: muParserInt.h:46
Mathematical expressions parser.
Definition: muParser.h:53
static value_type f2of4(value_type, value_type v, value_type, value_type)
Definition: muParserTest.h:63
static value_type ValueOf(const char_type *)
Definition: muParserTest.h:122
static value_type Sum(const value_type *a_afArg, int a_iArgc)
Definition: muParserTest.h:97
static value_type f2of3(value_type, value_type v, value_type)
Definition: muParserTest.h:59
static value_type StrFun3(const char_type *v1, value_type v2, value_type v3)
Definition: muParserTest.h:141
std::vector< testfun_type > m_vTestFun
Definition: muParserTest.h:185
void Abort() const
Internal error in test class Test is going to be aborted.
static value_type Min(value_type a_fVal1, value_type a_fVal2)
Definition: muParserTest.h:73
int ThrowTest(const string_type &a_str, int a_iErrc, bool a_bFail=true)
int EqnTestInt(const string_type &a_str, double a_fRes, bool a_fPass)
static value_type f4of5(value_type, value_type, value_type, value_type v, value_type)
Definition: muParserTest.h:70
static value_type Milli(value_type v)
Definition: muParserTest.h:159
static value_type f3of3(value_type, value_type, value_type v)
Definition: muParserTest.h:60
static value_type FirstArg(const value_type *a_afArg, int a_iArgc)
Definition: muParserTest.h:81
static value_type plus2(value_type v1)
Definition: muParserTest.h:76
static value_type times3(value_type v1)
Definition: muParserTest.h:77
static value_type RndWithString(const char_type *)
Definition: muParserTest.h:112
int TestVolatile()
Test volatile (nonoptimizeable functions).
static value_type LastArg(const value_type *a_afArg, int a_iArgc)
Definition: muParserTest.h:89
static value_type Ping()
Definition: muParserTest.h:117
static value_type Rnd(value_type v)
Definition: muParserTest.h:107
static value_type f2of2(value_type, value_type v)
Definition: muParserTest.h:56
static value_type f4of4(value_type, value_type, value_type, value_type v)
Definition: muParserTest.h:65
static value_type f1of4(value_type v, value_type, value_type, value_type)
Definition: muParserTest.h:62
static value_type Max(value_type a_fVal1, value_type a_fVal2)
Definition: muParserTest.h:74
static value_type sign(value_type v)
Definition: muParserTest.h:79
void AddTest(testfun_type a_pFun)
int EqnTest(const string_type &a_str, double a_fRes, bool a_fPass)
Evaluate a tet expression.
static value_type f3of4(value_type, value_type, value_type v, value_type)
Definition: muParserTest.h:64
static value_type f2of5(value_type, value_type v, value_type, value_type, value_type)
Definition: muParserTest.h:68
static value_type StrFun1(const char_type *v1)
Definition: muParserTest.h:127
int TestNames()
Check muParser name restriction enforcement.
static value_type f1of3(value_type v, value_type, value_type)
Definition: muParserTest.h:58
static value_type f1of1(value_type v)
Definition: muParserTest.h:53
static value_type f3of5(value_type, value_type, value_type v, value_type, value_type)
Definition: muParserTest.h:69
static value_type StrToFloat(const char_type *a_szMsg)
Definition: muParserTest.h:148
static value_type f5of5(value_type, value_type, value_type, value_type, value_type v)
Definition: muParserTest.h:71
static value_type f1of2(value_type v, value_type)
Definition: muParserTest.h:55
static value_type sqr(value_type v1)
Definition: muParserTest.h:78
static value_type f1of5(value_type v, value_type, value_type, value_type, value_type)
Definition: muParserTest.h:67
static value_type StrFun2(const char_type *v1, value_type v2)
Definition: muParserTest.h:134
static void Test(const char *bind1, SQLSMALLINT type1, const char *bind2, SQLSMALLINT type2)
Definition: convert_error.c:15
unsigned int
A callback function used to compare two keys in a database.
Definition: types.hpp:1210
exit(2)
int i
#define PARSER_CONST_E
#define PARSER_CONST_PI
#define PARSER_THROWCHECK(DOMAIN, FAIL, EXPR, ARG)
#define wxT(x)
This file contains the parser test class.
Namespace for mathematical applications.
Definition: muParser.h:41
std::ostream & console()
Encapsulate cout.
Definition: muParserDef.h:139
std::map< string_type, value_type * > varmap_type
Type used for storing variables.
Definition: muParserDef.h:256
@ prPOW
power operator priority (highest)
Definition: muParserDef.h:214
@ ecUNASSIGNABLE_TOKEN
Token cant be identified.
Definition: muParserError.h:50
@ ecMISSING_PARENS
Missing parens. (Example: "3*sin(3")
Definition: muParserError.h:60
@ ecUNEXPECTED_EOF
Unexpected end of formula. (Example: "2+sin(")
Definition: muParserError.h:51
@ ecSTRING_EXPECTED
A string function has been called with a different type of argument.
Definition: muParserError.h:58
@ ecTOO_MANY_PARAMS
Too many function parameters.
Definition: muParserError.h:63
@ ecVAL_EXPECTED
A numerical function has been called with a non value type of argument.
Definition: muParserError.h:59
@ ecUNEXPECTED_FUN
Unexpected function found. (Example: "sin(8)cos(9)")
Definition: muParserError.h:61
@ ecSTR_RESULT
result is a string
Definition: muParserError.h:66
@ ecUNEXPECTED_OPERATOR
Unexpected binary operator found.
Definition: muParserError.h:49
@ ecOPRT_TYPE_CONFLICT
binary operators may only be applied to value items of the same type
Definition: muParserError.h:65
@ ecUNEXPECTED_PARENS
Unexpected Parenthesis, opening or closing.
Definition: muParserError.h:56
@ ecUNEXPECTED_ARG_SEP
An unexpected comma has been found. (Example: "1,23")
Definition: muParserError.h:52
@ ecUNTERMINATED_STRING
unterminated string constant. (Example: "3*valueof("hello)")
Definition: muParserError.h:62
@ ecTOO_FEW_PARAMS
Too few function parameters. (Example: "ite(1<2,2)")
Definition: muParserError.h:64
@ ecUNEXPECTED_VAL
An unexpected value token has been found.
Definition: muParserError.h:54
double value_type
The numeric datatype used by the parser.
Definition: muParserDef.h:228
std::string string_type
The stringtype used by the parser.
Definition: muParserDef.h:234
#define fabs(v)
Definition: ncbi_dispd.c:46
unsigned int a
Definition: ncbi_localip.c:102
Modified on Sat Dec 02 09:20:31 2023 by modify_doxy.py rev. 669887