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