File indexing completed on 2024-11-03 09:47:06

0001 /*
0002     File                 : ParserTest.cpp
0003     Project              : LabPlot
0004     Description          : Tests for the Parser
0005     --------------------------------------------------------------------
0006     SPDX-FileCopyrightText: 2020 Stefan Gerlach <stefan.gerlach@uni.kn>
0007 
0008     SPDX-License-Identifier: GPL-2.0-or-later
0009 */
0010 
0011 #include "ParserTest.h"
0012 
0013 #include "backend/gsl/parser.h"
0014 
0015 #include <gsl/gsl_const_mksa.h>
0016 #include <gsl/gsl_errno.h>
0017 
0018 //**********************************************************
0019 //****************** Function tests ************************
0020 //**********************************************************
0021 
0022 void ParserTest::testBasics() {
0023     const QVector<QPair<QString, double>> tests{{QStringLiteral("42"), 42.},
0024                                                 {QStringLiteral("1."), 1.},
0025                                                 {QStringLiteral("1+1"), 2.},
0026                                                 {QStringLiteral("1+2+3+4+5"), 15.},
0027                                                 {QStringLiteral("2*3"), 6.},
0028                                                 {QStringLiteral("3/2"), 1.5},
0029                                                 {QStringLiteral("2 -4 +6 -1 -1- 0 +8"), 10.},
0030                                                 {QStringLiteral("1/3+1/3+1/3"), 1.},
0031                                                 {QStringLiteral("1.5 + 2.5"), 4.},
0032                                                 {QStringLiteral("4*2.5 + 8.5+1.5 / 3.0"), 19.},
0033                                                 {QStringLiteral("5.0005 + 0.0095"), 5.01},
0034                                                 {QStringLiteral("pi"), M_PI},
0035                                                 {QStringLiteral("e"), M_E},
0036                                                 {QStringLiteral("e^1"), M_E},
0037                                                 {QStringLiteral("hbar"), GSL_CONST_MKSA_PLANCKS_CONSTANT_HBAR},
0038                                                 {QStringLiteral(" 1   +   1  "), 2.},
0039                                                 {QStringLiteral("1-    2"), -1.},
0040                                                 {QStringLiteral("2*    2.5"), 5.},
0041                                                 {QStringLiteral("3 + 8/5 -1 -2*5"), -6.4},
0042                                                 {QStringLiteral("(1)"), 1.},
0043                                                 {QStringLiteral("-(1)"), -1.},
0044                                                 {QStringLiteral("(1+1)"), 2},
0045                                                 {QStringLiteral("(sin(0))"), 0.},
0046                                                 {QStringLiteral("(( ((2)) + 4))*((5))"), 30.},
0047                                                 {QStringLiteral("2^2"), 4.},
0048                                                 {QStringLiteral("3**2"), 9.},
0049                                                 {QStringLiteral("1%1"), 0.},
0050                                                 {QStringLiteral("3%2"), 1.},
0051                                                 {QStringLiteral("1.e-5"), 1.e-5},
0052                                                 {QStringLiteral("9.5E3"), 9500.},
0053                                                 {QStringLiteral("|1.5|"), 1.5},
0054                                                 {QStringLiteral("|-2.5|"), 2.5},
0055                                                 {QStringLiteral("0!"), 1},
0056                                                 {QStringLiteral("4!"), 24},
0057                                                 {QStringLiteral("-3!"), -6.},
0058                                                 {QStringLiteral("exp(0)"), 1.},
0059                                                 {QStringLiteral("exp(1)"), M_E},
0060                                                 {QStringLiteral("sqrt(0)"), 0.},
0061                                                 {QStringLiteral("sin(0)"), 0.},
0062                                                 {QStringLiteral("cos(pi)"), -1.}};
0063 
0064     for (auto& expr : tests)
0065         QCOMPARE(parse(qPrintable(expr.first), "C"), expr.second);
0066 
0067     const QVector<QPair<QString, double>> testsFuzzy{{QStringLiteral("(sin(pi))"), 0.}};
0068 
0069     for (const auto& expr : testsFuzzy)
0070         FuzzyCompare(parse(qPrintable(expr.first), "C"), expr.second, 1.e-15);
0071 }
0072 
0073 void ParserTest::testErrors() {
0074     gsl_set_error_handler_off(); // do not crash
0075 
0076     const QVector<QString> testsNan{QString(),
0077                                     QStringLiteral("a"),
0078                                     QStringLiteral("1+"),
0079                                     QStringLiteral("a+1"),
0080                                     QStringLiteral("&"),
0081                                     QStringLiteral("%"),
0082                                     QStringLiteral("+"),
0083                                     QStringLiteral("*"),
0084                                     QStringLiteral("/"),
0085                                     QStringLiteral("{1}"),
0086                                     QStringLiteral("{1*2}"),
0087                                     QStringLiteral("(1+1))"),
0088                                     QStringLiteral("a/0"),
0089                                     QStringLiteral("0/0"),
0090                                     QStringLiteral("1/0 + a"),
0091                                     QStringLiteral("sqrt(-1)"),
0092                                     QStringLiteral("log(-1)"),
0093                                     QStringLiteral("log(0)"),
0094                                     QStringLiteral("asin(2)")};
0095 
0096     for (auto& expr : testsNan)
0097         QVERIFY(std::isnan(parse(qPrintable(expr), "C")));
0098 
0099     const QVector<QString> testsInf{QStringLiteral("1/0"), QStringLiteral("-1/0"), QStringLiteral("1+1/0")};
0100 
0101     for (auto& expr : testsInf)
0102         QVERIFY(std::isinf(parse(qPrintable(expr), "C")));
0103 }
0104 
0105 void ParserTest::testVariables() {
0106     assign_symbol("a", 1.);
0107     const QVector<QPair<QString, double>> tests{{QStringLiteral("a"), 1.},
0108                                                 {QStringLiteral("a+1"), 2.},
0109                                                 {QStringLiteral("a+1.5"), 2.5},
0110                                                 {QStringLiteral("a!"), 1.}};
0111 
0112     for (auto& expr : tests)
0113         QCOMPARE(parse(qPrintable(expr.first), "C"), expr.second);
0114 
0115     assign_symbol("a", 0.); // only vars set to zero get removed
0116     remove_symbol("a");
0117     for (auto& expr : tests)
0118         QVERIFY(std::isnan(parse(qPrintable(expr.first), "C")));
0119 
0120     // longer var name
0121     assign_symbol("sina", 1.5);
0122     const QVector<QPair<QString, double>> tests2{{QStringLiteral("sina"), 1.5},
0123                                                  {QStringLiteral("sina+1"), 2.5},
0124                                                  {QStringLiteral("sina+1.5"), 3.},
0125                                                  {QStringLiteral("2*sina"), 3.}};
0126 
0127     for (auto& expr : tests2)
0128         QCOMPARE(parse(qPrintable(expr.first), "C"), expr.second);
0129 
0130     // parse_with_vars()
0131     parser_var vars[] = {{"x", 1.}, {"y", 2.}};
0132     QCOMPARE(parse_with_vars("x + y", vars, 2, "C"), 3.);
0133 }
0134 
0135 void ParserTest::testLocale() {
0136 // TODO: locale test currently does not work on FreeBSD
0137 #ifndef __FreeBSD__
0138     const QVector<QPair<QString, double>> tests{{QStringLiteral("1,"), 1.},
0139                                                 {QStringLiteral("1,5"), 1.5},
0140                                                 {QStringLiteral("1+0,5"), 1.5},
0141                                                 {QStringLiteral("2*1,5"), 3.}};
0142 
0143     for (auto& expr : tests)
0144         QCOMPARE(parse(qPrintable(expr.first), "de_DE"), expr.second);
0145 #endif
0146 }
0147 
0148 ///////////// Performance ////////////////////////////////
0149 // see https://github.com/ArashPartow/math-parser-benchmark-project
0150 
0151 void ParserTest::testPerformance1() {
0152     const int N = 1e5;
0153 
0154     QBENCHMARK {
0155         for (int i = 0; i < N; i++) {
0156             const double x = i / 100.;
0157             assign_symbol("x", i / 100.);
0158             QCOMPARE(parse("x+1.", "C"), x + 1.);
0159         }
0160     }
0161 }
0162 
0163 void ParserTest::testPerformance2() {
0164     const int N = 1e5;
0165 
0166     QBENCHMARK {
0167         for (int i = 0; i < N; i++) {
0168             assign_symbol("alpha", i / 100.);
0169             QCOMPARE(parse("sin(alpha)^2 + cos(alpha)^2", "C"), 1.);
0170         }
0171     }
0172 }
0173 
0174 QTEST_MAIN(ParserTest)