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