3 _____ __ _____________ _______ ______ ___________
4 / \| | \____ \__ \\_ __ \/ ___// __ \_ __ \
5 | Y Y \ | / |_> > __ \| | \/\___ \\ ___/| | \/
6 |__|_| /____/| __(____ /__| /____ >\___ >__|
8 Copyright (C) 2004 - 2020 Ingo Berg
10 Redistribution and use in source and binary forms, with or without modification, are permitted
11 provided that the following conditions are met:
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.
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.
29 #include "muParserTest.h"
39 \brief This file contains the implementation of parser test cases.
46 int ParserTester::c_iCount = 0;
48 //---------------------------------------------------------------------------------------------
49 ParserTester::ParserTester()
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);
66 ParserTester::c_iCount = 0;
69 //---------------------------------------------------------------------------------------------
70 int ParserTester::IsHexVal(const char_type* a_szExpr, int* a_iPos, value_type* a_fVal)
72 if (a_szExpr[1] == 0 || (a_szExpr[0] != '0' || a_szExpr[1] != 'x'))
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;
83 if (nPos == (stringstream_type::pos_type)0)
86 *a_iPos += (int)(2 + nPos);
87 *a_fVal = (value_type)iVal;
91 //---------------------------------------------------------------------------------------------
92 int ParserTester::TestInterface()
95 mu::console() << _T("testing member functions...");
98 value_type afVal[3] = { 1,2,3 };
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"));
111 iStat += 1; // this is not supposed to happen
116 p.RemoveVar(_T("c"));
118 iStat += 1; // not supposed to reach this, nonexisting variable "c" deleted...
122 // failure is expected...
126 mu::console() << _T("passed") << endl;
128 mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl;
133 //---------------------------------------------------------------------------------------------
134 int ParserTester::TestStrArg()
137 mu::console() << _T("testing string arguments...");
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);
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);
147 // from oss-fuzz: https://oss-fuzz.com/testcase-detail/5106868061208576
148 iStat += ThrowTest(_T(R"("","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","",8)"), ecSTR_RESULT);
150 iStat += ThrowTest(_T(R"("","",9)"), ecSTR_RESULT);
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);
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);
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);
168 iStat += EqnTest(_T("atof(str1)+atof(str2)"), 3.33, true);
171 mu::console() << _T("passed") << endl;
173 mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl;
178 //---------------------------------------------------------------------------------------------
179 int ParserTester::TestBulkMode()
182 mu::console() << _T("testing bulkmode...");
184 #define EQN_TEST_BULK(EXPR, R1, R2, R3, R4, PASS) \
186 double res[] = { R1, R2, R3, R4 }; \
187 iStat += EqnTestBulk(_T(EXPR), res, (PASS)); \
190 // Bulk Variables for the test:
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)
205 mu::console() << _T("passed") << endl;
207 mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl;
212 //---------------------------------------------------------------------------------------------
213 int ParserTester::TestBinOprt()
216 mu::console() << _T("testing binary operators...");
218 // built in operators
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);
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);
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);
261 iStat += EqnTest(_T("2^2^3"), 256, true);
262 iStat += EqnTest(_T("1/2/3"), 1.0 / 6.0, true);
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);
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);
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);
322 // incorrect: '^' is yor here, not power
323 // iStat += EqnTestInt("-(1+2)^2", -9, true);
324 // iStat += EqnTestInt("-1^3", -1, true);
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);
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);
341 mu::console() << _T("passed") << endl;
343 mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl;
348 //---------------------------------------------------------------------------------------------
349 /** \brief Check muParser name restriction enforcement. */
350 int ParserTester::TestNames()
355 mu::console() << "testing name restriction enforcement...";
359 #define PARSER_THROWCHECK(DOMAIN, FAIL, EXPR, ARG) \
361 ParserTester::c_iCount++; \
364 p.Define##DOMAIN(EXPR, ARG); \
365 iErr = (FAIL) ? 0 : 1; \
369 iErr = (!FAIL) ? 0 : 1; \
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)
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)
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)
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)
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)
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
459 mu::console() << _T("passed") << endl;
461 mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl;
466 //---------------------------------------------------------------------------
467 int ParserTester::TestSyntax()
470 mu::console() << _T("testing syntax engine...");
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
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
508 mu::console() << _T("passed") << endl;
510 mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl;
515 //---------------------------------------------------------------------------
516 int ParserTester::TestVarConst()
519 mu::console() << _T("testing variable/constant detection...");
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);
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);
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);
547 // custom value recognition
548 iStat += EqnTest(_T("0xff"), 255, true);
549 iStat += EqnTest(_T("0x97 + 0xff"), 406, true);
551 // Finally test querying of used variables
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]);
563 // Test lookup of defined variables
565 p.SetExpr(_T("a+b+c+d"));
566 mu::varmap_type UsedVar = p.GetUsedVar();
567 int iCount = (int)UsedVar.size();
571 // the next check will fail if the parser
572 // erroneously creates new variables internally
573 if (p.GetVar().size() != 5)
576 mu::varmap_type::const_iterator item = UsedVar.begin();
577 for (idx = 0; item != UsedVar.end(); ++item)
579 if (&vVarVal[idx++] != item->second)
583 // Test lookup of undefined variables
584 p.SetExpr(_T("undef1+undef2+undef3"));
585 UsedVar = p.GetUsedVar();
586 iCount = (int)UsedVar.size();
590 // the next check will fail if the parser
591 // erroneously creates new variables internally
592 if (p.GetVar().size() != 5)
595 for (item = UsedVar.begin(); item != UsedVar.end(); ++item)
597 if (item->second != 0)
598 throw false; // all pointers to undefined variables must be null
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;
617 mu::console() << _T("passed") << endl;
619 mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl;
624 //---------------------------------------------------------------------------
625 int ParserTester::TestMultiArg()
628 mu::console() << _T("testing multiarg functions...");
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);
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);
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);
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);
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);
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);
714 mu::console() << _T("passed") << endl;
716 mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl;
722 //---------------------------------------------------------------------------
723 int ParserTester::TestInfixOprt()
726 mu::console() << "testing infix operators...";
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);
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);
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);
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
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);
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);
786 mu::console() << _T("passed") << endl;
788 mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl;
794 //---------------------------------------------------------------------------
795 int ParserTester::TestPostFix()
798 mu::console() << _T("testing postfix operators...");
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);
816 // can postfix operators "m" und "meg" be told apart properly?
817 iStat += EqnTest(_T("2*3000meg+2"), 2 * 3e9 + 2, true);
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);
835 iStat += ThrowTest(_T("multi*1.0"), ecUNASSIGNABLE_TOKEN);
838 mu::console() << _T("passed") << endl;
840 mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl;
845 //---------------------------------------------------------------------------
846 int ParserTester::TestExpression()
849 mu::console() << _T("testing expression samples...");
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);
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);
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);
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);
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);
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);
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);
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);
906 // long formula (Reference: Matlab)
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);
915 // long formula (Reference: Matlab)
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);
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);
924 mu::console() << _T("passed") << endl;
926 mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl;
933 //---------------------------------------------------------------------------
934 int ParserTester::TestIfThenElse()
937 mu::console() << _T("testing if-then-else operator...");
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);
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);
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);
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);
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);
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);
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);
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);
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);
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
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);
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);
1047 mu::console() << _T("passed") << endl;
1049 mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl;
1054 //---------------------------------------------------------------------------
1055 int ParserTester::TestException()
1058 mu::console() << _T("testing error codes...");
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);
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);
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);
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);
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);
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);
1124 mu::console() << _T("passed") << endl;
1126 mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl;
1132 //---------------------------------------------------------------------------
1133 void ParserTester::AddTest(testfun_type a_pFun)
1135 m_vTestFun.push_back(a_pFun);
1138 //---------------------------------------------------------------------------
1139 int ParserTester::Run()
1144 for (int i = 0; i < (int)m_vTestFun.size(); ++i)
1145 iStat += (this->*m_vTestFun[i])();
1147 catch (Parser::exception_type& e)
1149 mu::console() << "\n" << e.GetMsg() << endl;
1150 mu::console() << e.GetToken() << endl;
1153 catch (std::exception& e)
1155 mu::console() << e.what() << endl;
1160 mu::console() << "Internal error";
1166 mu::console() << "Test passed (" << ParserTester::c_iCount << " expressions)" << endl;
1170 mu::console() << "Test failed with " << iStat
1171 << " errors (" << ParserTester::c_iCount
1172 << " expressions)" << endl;
1174 ParserTester::c_iCount = 0;
1179 //---------------------------------------------------------------------------
1180 int ParserTester::ThrowTest(const string_type& a_str, int a_iErrc, bool a_expectedToFail)
1182 ParserTester::c_iCount++;
1186 value_type fVal[] = { 1,1,1 };
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);
1202 // p.EnableDebugDump(1, 0);
1205 catch (ParserError& e)
1207 // output the formula in case of an failed test
1208 if (a_expectedToFail == false || (a_expectedToFail == true && a_iErrc != e.GetCode()))
1210 mu::console() << _T("\n ")
1211 << _T("Expression: ") << a_str
1212 << _T(" Code:") << e.GetCode() << _T("(") << e.GetMsg() << _T(")")
1213 << _T(" Expected:") << a_iErrc;
1216 return (a_iErrc == e.GetCode()) ? 0 : 1;
1219 // if a_expectedToFail == false no exception is expected
1220 bool bRet((a_expectedToFail == false) ? 0 : 1);
1223 mu::console() << _T("\n ")
1224 << _T("Expression: ") << a_str
1225 << _T(" did evaluate; Expected error:") << a_iErrc;
1231 //---------------------------------------------------------------------------
1232 /** \brief Evaluate a tet expression.
1234 \return 1 in case of a failure, 0 otherwise.
1236 int ParserTester::EqnTestWithVarChange(const string_type& a_str,
1242 ParserTester::c_iCount++;
1246 value_type fVal[2] = { -999, -999 }; // should be equal
1252 p.DefineVar(_T("a"), &var);
1261 if (fabs(a_fRes1 - fVal[0]) > 0.0000000001)
1262 throw std::runtime_error("incorrect result (first pass)");
1264 if (fabs(a_fRes2 - fVal[1]) > 0.0000000001)
1265 throw std::runtime_error("incorrect result (second pass)");
1267 catch (Parser::exception_type& e)
1269 mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (") << e.GetMsg() << _T(")");
1272 catch (std::exception& e)
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
1279 mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (unexpected exception)");
1280 return 1; // exceptions other than ParserException are not allowed
1286 //---------------------------------------------------------------------------
1287 /** \brief Evaluate a tet expression.
1289 \return 1 in case of a failure, 0 otherwise.
1291 int ParserTester::EqnTest(const string_type& a_str, double a_fRes, bool a_fPass)
1293 ParserTester::c_iCount++;
1295 value_type fVal[5] = { -999, -998, -997, -996, -995 }; // initially should be different
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 !!
1306 p1.reset(new mu::Parser());
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);
1314 p1->DefineStrConst(_T("str1"), _T("1.11"));
1315 p1->DefineStrConst(_T("str2"), _T("2.22"));
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]);
1324 // custom value ident functions
1325 p1->AddValIdent(&ParserTester::IsHexVal);
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);
1347 p1->DefineOprt(_T("add"), add, 0);
1348 p1->DefineOprt(_T("++"), add, 0);
1349 p1->DefineOprt(_T("&"), land, prLAND);
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);
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);
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."));
1387 // Test copy and assignment operators
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
1395 // destroy the originals from p2
1396 vParser.clear(); // delete the vector
1399 fVal[2] = p4.Eval();
1401 // Test assignment operator
1402 // additionally disable Optimizer this time
1405 p5.EnableOptimizer(false);
1406 fVal[3] = p5.Eval();
1408 // Test Eval function for multiple return values
1409 // use p2 since it has the optimizer enabled!
1411 value_type* v = p4.Eval(nNum);
1412 fVal[4] = v[nNum - 1];
1414 catch (std::exception& e)
1416 mu::console() << _T("\n ") << e.what() << _T("\n");
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)
1423 bCloseEnough &= (fabs(a_fRes - fVal[i]) <= fabs(fVal[i] * 0.00001));
1425 // The tests equations never result in infinity, if they do thats a bug.
1427 // http://sourceforge.net/projects/muparser/forums/forum/462843/topic/5037825
1429 #pragma warning(push)
1430 #pragma warning(disable:4127)
1432 if (std::numeric_limits<value_type>::has_infinity)
1434 #pragma warning(pop)
1437 bCloseEnough &= (fabs(fVal[i]) != numeric_limits<value_type>::infinity());
1441 iRet = ((bCloseEnough && a_fPass) || (!bCloseEnough && !a_fPass)) ? 0 : 1;
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(").");
1455 catch (Parser::exception_type& e)
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)");
1462 mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (") << e.GetMsg() << _T(")");
1466 catch (std::exception& e)
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
1473 mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (unexpected exception)");
1474 return 1; // exceptions other than ParserException are not allowed
1480 //---------------------------------------------------------------------------
1481 int ParserTester::EqnTestInt(const string_type& a_str, double a_fRes, bool a_fPass)
1483 ParserTester::c_iCount++;
1485 value_type vVarVal[] = { 1, 2, 3 }; // variable values
1490 value_type fVal[2] = { -99, -999 }; // results: initially should be different
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]);
1499 fVal[0] = p.Eval(); // result from stringparsing
1500 fVal[1] = p.Eval(); // result from bytecode
1502 if (fVal[0] != fVal[1])
1503 throw Parser::exception_type(_T("Bytecode corrupt."));
1505 iRet = ((a_fRes == fVal[0] && a_fPass) ||
1506 (a_fRes != fVal[0] && !a_fPass)) ? 0 : 1;
1509 mu::console() << _T("\n fail: ") << a_str.c_str()
1510 << _T(" (incorrect result; expected: ") << a_fRes
1511 << _T(" ;calculated: ") << fVal[0] << _T(").");
1514 catch (Parser::exception_type& e)
1518 mu::console() << _T("\n fail: ") << e.GetExpr() << _T(" : ") << e.GetMsg();
1524 mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (unexpected exception)");
1525 iRet = 1; // exceptions other than ParserException are not allowed
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)
1535 ParserTester::c_iCount++;
1537 // Define Bulk Variables
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
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);
1555 p.Eval(vResults, nBulkSize);
1557 bool bCloseEnough(true);
1558 for (int i = 0; i < nBulkSize; ++i)
1560 bCloseEnough &= (fabs(a_fRes[i] - vResults[i]) <= fabs(a_fRes[i] * 0.00001));
1563 iRet = ((bCloseEnough && a_fPass) || (!bCloseEnough && !a_fPass)) ? 0 : 1;
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("}");
1571 catch (Parser::exception_type& e)
1575 mu::console() << _T("\n fail: ") << e.GetExpr() << _T(" : ") << e.GetMsg();
1581 mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (unexpected exception)");
1582 iRet = 1; // exceptions other than ParserException are not allowed
1588 //---------------------------------------------------------------------------
1589 /** \brief Internal error in test class Test is going to be aborted. */
1590 void ParserTester::Abort() const
1592 mu::console() << _T("Test failed (internal error in test class)") << endl;