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