File indexing completed on 2024-05-19 04:32:48
0001 /* 0002 * Copyright 2004, The University of Toronto 0003 * Licensed under GPL. 0004 */ 0005 0006 //#define DUMP_FAIL_MSGS 0007 0008 #include "ksttestcase.h" 0009 #include <enodes.h> 0010 #include <eparse-eh.h> 0011 0012 extern "C" int yyparse(); 0013 extern "C" void *ParsedEquation; 0014 extern "C" struct yy_buffer_state *yy_scan_string(const char*); 0015 0016 bool optimizerFailed = false; 0017 0018 KstVectorMap vectorsUsed; 0019 KstVectorPtr xVector; 0020 0021 int rc = KstTestSuccess; 0022 0023 void testText(const char *equation, const char *expect) { 0024 bool failure = false; 0025 QString txt; 0026 yy_scan_string(equation); 0027 int rc = yyparse(); 0028 if (rc == 0) { 0029 vectorsUsed.clear(); 0030 Equation::Node *eq = static_cast<Equation::Node*>(ParsedEquation); 0031 assert(eq); 0032 ParsedEquation = 0L; 0033 //eq->collectVectors(vectorsUsed); 0034 txt = eq->text(); 0035 failure = txt != expect; 0036 delete eq; 0037 } else { 0038 // Parse error 0039 delete (Equation::Node*)ParsedEquation; 0040 ParsedEquation = 0L; 0041 failure = true; 0042 } 0043 0044 if (failure) { 0045 if (!Equation::errorStack.isEmpty()) { 0046 printf("Failures on [%s] -------------------------\n", equation); 0047 for (QStringList::ConstIterator i = Equation::errorStack.constBegin(); i != Equation::errorStack.constEnd(); ++i) { 0048 printf("%s\n", (*i).toLatin1().data()); 0049 } 0050 printf("------------------------------------------\n"); 0051 } else { 0052 printf("Got [%s], expected [%s]\n", txt.toLatin1().data(), expect); 0053 } 0054 --rc; 0055 } 0056 } 0057 0058 0059 bool doTest(const char *equation, double x, double result, const double tol = 0.00000000001) { 0060 yy_scan_string(equation); 0061 int rc = yyparse(); 0062 if (rc == 0) { 0063 vectorsUsed.clear(); 0064 Equation::Node *eq = static_cast<Equation::Node*>(ParsedEquation); 0065 assert(eq); 0066 ParsedEquation = 0L; 0067 Equation::Context ctx; 0068 ctx.sampleCount = 2; 0069 ctx.noPoint = NOPOINT; 0070 ctx.x = x; 0071 ctx.xVector = xVector; 0072 if (xVector) { 0073 ctx.sampleCount = xVector->length(); 0074 } 0075 Equation::FoldVisitor vis(&ctx, &eq); 0076 if (eq->isConst() && !dynamic_cast<Equation::Number*>(eq)) { 0077 if (!optimizerFailed) { 0078 optimizerFailed = true; 0079 ::rc--; 0080 printf("Optimizer bug: found an unoptimized const equation. Optimizing for coverage purposes.\n"); 0081 } 0082 double v = eq->value(&ctx); 0083 delete eq; 0084 eq = new Equation::Number(v); 0085 } 0086 KstScalarMap scm; 0087 KstStringMap stm; 0088 eq->collectObjects(vectorsUsed, scm, stm); 0089 eq->update(-1, &ctx); 0090 double v = eq->value(&ctx); 0091 delete eq; 0092 if (fabs(v - result) < tol || (result != result && v != v) || (result == INF && v == INF) || (result == -INF && v == -INF)) { 0093 return true; 0094 } else { 0095 printf("Result: %.16f\n", v); 0096 return false; 0097 } 0098 } else { 0099 // Parse error 0100 printf("Failures on [%s] -------------------------\n", equation); 0101 for (QStringList::ConstIterator i = Equation::errorStack.constBegin(); i != Equation::errorStack.constEnd(); ++i) { 0102 printf("%s\n", (*i).toLatin1().data()); 0103 } 0104 printf("------------------------------------------\n"); 0105 delete (Equation::Node*)ParsedEquation; 0106 ParsedEquation = 0L; 0107 return false; 0108 } 0109 } 0110 0111 0112 void test(const char *equation, double x, double result, const double tol = 0.00000000001) { 0113 if (!doTest(equation, x, result, tol)) { 0114 rc--; 0115 printf("Test of (%s)[%.16f] == %.16f failed.\n", equation, x, result); 0116 } 0117 } 0118 0119 0120 void testParseFail(const char *equation) { 0121 yy_scan_string(equation); 0122 if (0 == yyparse()) { 0123 printf("Test of (%s) parsing passed, but should have failed.\n", equation); 0124 rc--; 0125 } else { 0126 if (Equation::errorStack.count() == 1 && (Equation::errorStack.first() == "parse error" || Equation::errorStack.first() == "syntax error")) { 0127 printf("ERROR: [%s] doesn't have error handling yet!\n", equation); 0128 rc--; 0129 #ifdef DUMP_FAIL_MSGS 0130 } else { 0131 printf("Failures on [%s] -------------------------\n", equation); 0132 for (QStringList::ConstIterator i = Equation::errorStack.constBegin(); i != Equation::errorStack.constEnd(); ++i) { 0133 printf("%s\n", (*i).toLatin1().data()); 0134 } 0135 printf("------------------------------------------\n"); 0136 #endif 0137 } 0138 } 0139 } 0140 0141 0142 static void exitHelper() { 0143 xVector = 0L; 0144 vectorsUsed.clear(); 0145 KST::vectorList.clear(); 0146 KST::scalarList.clear(); 0147 } 0148 0149 0150 extern int yydebug; 0151 0152 int main(int argc, char **argv) { 0153 atexit(exitHelper); 0154 0155 QCoreApplication app(argc, argv); 0156 0157 // Base cases 0158 test("0", 1.0, 0.0); 0159 test("1.0", 2.0, 1.0); 0160 0161 // Basics 0162 test("x", -1.0, -1.0); 0163 test("-x", -1.0, 1.0); 0164 test("x^2", -1.0, 1.0); 0165 test(" x^2", -1.0, 1.0); 0166 test(" x^2 ", -1.0, 1.0); 0167 test("x^2 ", -1.0, 1.0); 0168 test("x^2 + x^2", -1.0, 2.0); 0169 test("y", 0.0, NOPOINT); 0170 test("foo()", 0.0, NOPOINT); 0171 test("foo(1.0, 2.0, 3.0)", 0.0, NOPOINT); 0172 0173 // Order of evaluation and parser issues 0174 test("-x^2", 2.0, -4.0); 0175 test("(-x)^2", 2.0, 4.0); 0176 test("-(x^2)", 2.0, -4.0); 0177 test("(-x^2)", 2.0, -4.0); 0178 test("x*x+5", 2.0, 9.0); 0179 test("5+x*x", 2.0, 9.0); 0180 test("5*4/2*5", 1.0, 50.0); 0181 test("asin(sin(x))", 3.14159265358979323, 0.0); 0182 test("x^(1/2)", 2.0, sqrt(2.0)); 0183 test("x^(1/2)*2", 2.0, 2.0*sqrt(2.0)); 0184 test("(1/2)*x^2+3*x-5", 1.0, -1.5); 0185 test("2^3^4", 0.0, 2417851639229258349412352.0); 0186 test("sin(x)^2", 0.5*3.14159265358979323, 1.0); 0187 test("(2)^(3)", 0.0, 8); 0188 test("(2*3)^(3*4)", 0.0, 2176782336.0); 0189 test("sin(x^2)", sqrt(3.14159265358979323), 0.0); 0190 test("5*4/2", 0.0, 10.0); 0191 test("5/4*2", 0.0, 2.5); 0192 test("10%2", 0.0, 0.0); 0193 test("10.5%2", 0.0, 0.5); 0194 test("0%2", 0.0, 0.0); 0195 test("2%0", 0.0, NOPOINT); 0196 test("--x", 1.0, 1.0); 0197 test("--x", -1.0, -1.0); 0198 test("---x", -1.0, 1.0); 0199 test("---x", 1.0, -1.0); 0200 0201 // Constants 0202 test("e", 0.0, 2.7128182846); 0203 test("pi", 0.0, 3.1415926536); 0204 0205 // Functions 0206 test("sin()", 0.0, NOPOINT); 0207 test("sin(0.0)", 0.0, 0.0); 0208 test("sin(3.14159265358979323)", 0.0, 0.0); 0209 test("sin(3.14159265358979323/2.00000000000000000000000000)", 0.0, 1.0); 0210 test("cos()", 0.0, NOPOINT); 0211 test("cos(0.0)", 0.0, 1.0); 0212 test("cos(3.14159265358979323)", 0.0, -1.0); 0213 test("cos(3.14159265358979323/2.00000000000000000000000000)", 0.0, 0.0); 0214 test("sec(x) == 1/cos(x)", 0.2332744, 1.0); 0215 test("csc(x) == 1/sin(x)", 0.2332744, 1.0); 0216 test("cot(x) == 1/tan(x)", 0.2332744, 1.0); 0217 0218 test("abs(0.0)", 0.0, 0.0); 0219 test("abs(x)", 1.0, 1.0); 0220 test("abs(x)", -1.0, 1.0); 0221 test("abs(x)", NOPOINT, NOPOINT); 0222 test("abs(x)", INF, INF); 0223 test("abs(x)", -INF, INF); 0224 test("abs(-0.000000000001)", 0.0, 0.000000000001); 0225 0226 test("cos(acos(x))", 0.3875823288, 0.3875823288, 0.0000000001); 0227 test("acos(cos(x))", 2.3875823288, 2.3875823288, 0.0000000001); 0228 test("asin(sin(x))", 0.7540103248, 0.7540103248, 0.0000000001); 0229 test("sin(asin(x))", 0.3875823288, 0.3875823288, 0.0000000001); 0230 test("tan(atan(x))", 2.3875823288, 2.3875823288, 0.0000000001); 0231 test("atan(tan(x))", 0.3875823288, 0.3875823288, 0.0000000001); 0232 0233 test("sqrt(4) == 2.0", 0.0, 1.0); 0234 test("sqrt(0) == 0.0", 0.0, 1.0); 0235 test("sqrt(-1)", 0.0, NOPOINT); 0236 test("sqrt(2)", 0.0, 1.4142135623730951); 0237 0238 test("cbrt(0.0) == 0.0", 0.0, 1.0); 0239 test("cbrt(8.0) == 2.0", 0.0, 1.0); 0240 test("cbrt(-1)", 0.0, -1.0); 0241 test("cbrt(2)", 0.0, 1.2599210498948734); 0242 0243 // TODO: cosh, exp, log, ln, sinh, tanh 0244 0245 // Expressions / Comparison 0246 test("0.0>0.0", 0.0, 0.0); 0247 test("0.0>=0.0", 0.0, 1.0); 0248 test("0.0<0.0", 0.0, 0.0); 0249 test("0.0<=0.0", 0.0, 1.0); 0250 test("0.0=0.0", 0.0, 1.0); 0251 test("0.0!=0.0", 0.0, 0.0); 0252 test("1.0!=0.0", 0.0, 1.0); 0253 test("sin(1.0)!=sin(0.0)", 0.0, 1.0); 0254 test("sin()!=sin()", 0.0, 1.0); 0255 test("0.0==0.0", 0.0, 1.0); 0256 test("1.0>0.0", 0.0, 1.0); 0257 test("1.0>=0.0", 0.0, 1.0); 0258 test("0.0>1.0", 0.0, 0.0); 0259 test("0.0>=1.0", 0.0, 0.0); 0260 test("1.0<0.0", 0.0, 0.0); 0261 test("1.0<=0.0", 0.0, 0.0); 0262 test("0.0<1.0", 0.0, 1.0); 0263 test("0.0<=1.0", 0.0, 1.0); 0264 test("(0.0/0.0)==(0.0/0.0)", 0.0, 0.0); 0265 test("(0.0/0.0)==(1.0/0.0)", 0.0, 0.0); 0266 test("(1.0/0.0)==(1.0/0.0)", 0.0, 1.0); // inf == inf 0267 test("(1.0/0.0)==-(1.0/0.0)", 0.0, 0.0); 0268 test("(0.0/0.0)==-(1.0/0.0)", 0.0, 0.0); 0269 test("(1.0/0.0)==(0.0/0.0)", 0.0, 0.0); 0270 test("1&&1", 0.0, 1.0); 0271 test("1&&0", 0.0, 0.0); 0272 test("0&&1", 0.0, 0.0); 0273 test("0&&2", 0.0, 0.0); 0274 test("3&&2", 0.0, 1.0); 0275 test("1||1", 0.0, 1.0); 0276 test("0||1", 0.0, 1.0); 0277 test("1||0", 0.0, 1.0); 0278 test("0||0", 0.0, 0.0); 0279 test("2||4", 0.0, 1.0); 0280 test("1||(2&&0)", 0.0, 1.0); 0281 test("(1||2)&&0", 0.0, 0.0); 0282 test("1||2&&0", 0.0, 1.0); 0283 test("2&&0||1", 0.0, 1.0); 0284 test("2&&1||0", 0.0, 1.0); 0285 test("0||1&&0", 0.0, 0.0); 0286 test("1.0 == (1.0 == 1.0)", 0.0, 1.0); 0287 test("1.0 != (1.0 == 0.0)", 0.0, 1.0); 0288 test("1.0 != (1.0 == 1.0)", 0.0, 0.0); 0289 test("0.0 == (1.0 == 0.0)", 0.0, 1.0); 0290 test("-1==1", 0.0, 0.0); 0291 test("-1==-1", 0.0, 1.0); 0292 test("1==-1", 0.0, 0.0); 0293 test("1!=-1", 0.0, 1.0); 0294 test("-1!=1", 0.0, 1.0); 0295 test("-1!=-1", 0.0, 0.0); 0296 test("!0.0", 0.0, 1.0); 0297 test("!1.0", 0.0, 0.0); 0298 test("!-1.0", 0.0, 0.0); 0299 test("!2.0", 0.0, 0.0); 0300 test("!x", INF, 0.0); 0301 test("!x", NOPOINT, 1.0); 0302 test("!(1 > 2)", 0.0, 1.0); 0303 test("!1.0 > -1.0", 0.0, 1.0); // (!1.0) > -1.0 0304 test("!!x", 1.0, 1.0); 0305 test("!!!x", 1.0, 0.0); 0306 test("!!!!x", 1.0, 1.0); 0307 0308 // Bit operations 0309 test("32&4", 0.0, 0.0); 0310 test("32&4|2", 0.0, 2.0); 0311 test("32|4&2", 0.0, 0.0); 0312 test("32|4", 0.0, 36.0); 0313 test("0&257", 0.0, 0.0); 0314 test("257&0", 0.0, 0.0); 0315 test("257|0", 0.0, 257.0); 0316 test("0|257", 0.0, 257.0); 0317 test("-1|257", 0.0, -1); 0318 test("257|-1", 0.0, -1); 0319 0320 // Scalars 0321 new KstScalar(KstObjectTag::fromString("test1"), 0L, 1.0, true); 0322 new KstScalar(KstObjectTag::fromString("test2"), 0L, 0.0, true); 0323 new KstScalar(KstObjectTag::fromString("test3"), 0L, -1.0, true); 0324 new KstScalar(KstObjectTag::fromString("test4"), 0L, NOPOINT, true); 0325 new KstScalar(KstObjectTag::fromString("test5"), 0L, INF, true); 0326 new KstScalar(KstObjectTag::fromString("test6"), 0L, -INF, true); 0327 0328 test("[test1]", 0.0, 1.0); 0329 test("[test4]", 0.0, NOPOINT); 0330 test("[test4] - [test4]", 0.0, NOPOINT); 0331 test("[test4] - [test5]", 0.0, NOPOINT); 0332 test("[test4]*[test5]", 0.0, NOPOINT); 0333 test("[sdf]", 0.0, NOPOINT); 0334 0335 test("[=10+10]", 0.0, 20.0); 0336 0337 // Vectors 0338 KstVector::generateVector(0, 1.0, 10, KstObjectTag::fromString("1")); 0339 KstVector::generateVector(0, 1.0, 10, KstObjectTag::fromString("V1")); 0340 KstVector::generateVector(1.0, 2.0, 10, KstObjectTag::fromString("V2")); 0341 KstVector::generateVector(0, 1.0, 2, KstObjectTag::fromString("V3")); 0342 KstVector::generateVector(-1.0, 1.0, 1000, KstObjectTag::fromString("V4")); 0343 KstVector::generateVector(-1.0, 1.0, 1000, KstObjectTag::fromString("V5-%+-_!")); 0344 test("[V2] - [V1]", 0.0, 1.0); 0345 test("[V2[9]]", 0.0, 2.0); 0346 test("[V2[5+4]]", 0.0, 2.0); 0347 test("[V2[]]", 0.0, 1.0); 0348 test("2*sin([V5-%+-_!])", 0.0, -1.6829419696157930); 0349 // TODO: interpolation, more vector combinations 0350 0351 // Plugins 0352 test("2*plugin(bin, [V4], 12)", 1.0, -1.9779779779779778); 0353 test("4*plugin(bin, [V4], x)", 5.0, -3.9839839839839839); 0354 test("-3*plugin(bin, x, 12)", 2.0, NOPOINT); 0355 xVector = KstVector::generateVector(0, 100, 2000, KstObjectTag::fromString("XVector")); 0356 test("-3*plugin(bin, x, 12)", 2.0, -0.8254127063531767); 0357 test("-3*plugin(bin, y, 12)", 2.0, NOPOINT); 0358 0359 // TODO: more plugin tests 0360 0361 // TODO: float notation 0362 0363 // Combinations 0364 test("1|0&&0", 0.0, 0.0); 0365 test("0&&0|1", 0.0, 0.0); 0366 test("0&&1|0", 0.0, 0.0); 0367 test("0||1&1", 0.0, 1.0); 0368 test("0||2&1", 0.0, 0.0); 0369 test("2&1||0", 0.0, 0.0); 0370 test("1-1||0", 0.0, 0.0); 0371 test("2-2||0", 0.0, 0.0); 0372 test("0||2-2", 0.0, 0.0); 0373 test("8|2*2", 0.0, 12.0); 0374 test("2*2|8", 0.0, 12.0); 0375 test("[V1] > 0.0", 0.0, 0.0); 0376 test("[V1] > -1.0", 0.0, 1.0); 0377 test("[1] > 0.0", 0.0, 0.0); 0378 test("[1] > -1.0", 0.0, 1.0); 0379 0380 test("-([V1]*sin([V1]*[V2])+[V3]*cos([V3]*[V3]))", 0.0, 0.0); 0381 test("[V3] * -1", 0.0, 0.0); 0382 0383 /* Wrap a testcase with this and run bison with -t in order to get a trace 0384 * of the parse stack */ 0385 #if 0 0386 yydebug = 1; 0387 yydebug = 0; 0388 #endif 0389 // Errors: 0390 testParseFail(""); 0391 testParseFail(" "); 0392 testParseFail("\t"); 0393 testParseFail(" \t \t"); 0394 testParseFail("[]"); 0395 testParseFail("[[]"); 0396 testParseFail("[]]"); 0397 testParseFail("]"); 0398 testParseFail("["); 0399 testParseFail("]["); 0400 testParseFail("[]["); 0401 testParseFail("foo(, 3)"); 0402 testParseFail("foo(3,)"); 0403 testParseFail("foo(3,,5)"); 0404 testParseFail("foo([])"); 0405 testParseFail("foo(4, [])"); 0406 testParseFail("/"); 0407 testParseFail("/2"); 0408 testParseFail("2/"); 0409 testParseFail("2//2"); 0410 testParseFail("%"); 0411 testParseFail("%2"); 0412 testParseFail("2%"); 0413 testParseFail("2%%2"); 0414 testParseFail("|"); 0415 testParseFail("||"); 0416 testParseFail("|2"); 0417 testParseFail("2|"); 0418 testParseFail("||2"); 0419 testParseFail("2||"); 0420 testParseFail("2|||2"); 0421 testParseFail("&"); 0422 testParseFail("&&"); 0423 testParseFail("&2"); 0424 testParseFail("2&"); 0425 testParseFail("&&2"); 0426 testParseFail("2&&"); 0427 testParseFail("2&&&2"); 0428 testParseFail("*"); 0429 testParseFail("*2"); 0430 testParseFail("2*"); 0431 testParseFail("2**2"); 0432 testParseFail("^"); 0433 testParseFail("^2"); 0434 testParseFail("2^^2"); 0435 testParseFail("2^"); 0436 testParseFail("+"); 0437 testParseFail("+2"); 0438 testParseFail("2+"); 0439 testParseFail("2++2"); 0440 testParseFail("-"); 0441 testParseFail("2-"); 0442 testParseFail("-2-"); 0443 testParseFail("2!"); 0444 testParseFail("!"); 0445 testParseFail("()"); 0446 testParseFail("2()"); 0447 testParseFail("()2"); 0448 testParseFail("_"); 0449 testParseFail("#"); 0450 testParseFail("$"); 0451 testParseFail(")"); 0452 testParseFail("("); 0453 testParseFail(")("); 0454 testParseFail("2&|2"); 0455 testParseFail("2&&||2"); 0456 testParseFail("2&&+2"); 0457 testParseFail("2+&&2"); 0458 testParseFail("2*&&2"); 0459 testParseFail("2&&*2"); 0460 testParseFail("2<>2"); 0461 testParseFail("2=<2"); 0462 testParseFail("2=>2"); 0463 testParseFail("2><2"); 0464 testParseFail("<"); 0465 testParseFail("<2"); 0466 testParseFail("2<"); 0467 testParseFail("2<<2"); 0468 testParseFail(">"); 0469 testParseFail(">2"); 0470 testParseFail("2>"); 0471 testParseFail("2>>2"); 0472 testParseFail(">="); 0473 testParseFail(">=2"); 0474 testParseFail("2>="); 0475 testParseFail("2>=>=2"); 0476 testParseFail("<="); 0477 testParseFail("<=2"); 0478 testParseFail("2<="); 0479 testParseFail("2<=<=2"); 0480 testParseFail("2<==2"); 0481 testParseFail("."); 0482 testParseFail(".2"); 0483 testParseFail("2."); 0484 testParseFail(","); 0485 testParseFail(",2"); 0486 testParseFail("2,"); // Doesn't give a specific error - how to catch this? 0487 testParseFail("2*sin(x"); 0488 testParseFail("2*sin(x)()"); 0489 0490 testText("3*x", "3*x"); 0491 testText("(3*x)", "(3*x)"); 0492 testText("3*(x)", "3*x"); 0493 testText("((3*x))", "(3*x)"); 0494 testText(" ((3 * x)) ", "(3*x)"); 0495 testText(" ((3 * x)) ", "(3*x)"); 0496 testText("(-3)", "(-3)"); 0497 testText("(x)", "x"); 0498 testText("(3*(-(x+5)))", "(3*(-(x+5)))"); 0499 testText("(sin((x)))", "sin(x)"); 0500 0501 exitHelper(); 0502 if (rc == KstTestSuccess) { 0503 printf("All tests passed!\n"); 0504 } 0505 return -rc; 0506 } 0507 0508 // vim: ts=2 sw=2 et