File indexing completed on 2024-05-05 16:00:17

0001 /***************************************************************************
0002     File                 : PrserTest.cpp
0003     Project              : LabPlot
0004     Description          : Tests for the Parser
0005     --------------------------------------------------------------------
0006     Copyright            : (C) 2020 Stefan Gerlach (stefan.gerlach@uni.kn)
0007  ***************************************************************************/
0008 
0009 /***************************************************************************
0010  *                                                                         *
0011  *  This program is free software; you can redistribute it and/or modify   *
0012  *  it under the terms of the GNU General Public License as published by   *
0013  *  the Free Software Foundation; either version 2 of the License, or      *
0014  *  (at your option) any later version.                                    *
0015  *                                                                         *
0016  *  This program is distributed in the hope that it will be useful,        *
0017  *  but WITHOUT ANY WARRANTY; without even the implied warranty of         *
0018  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          *
0019  *  GNU General Public License for more details.                           *
0020  *                                                                         *
0021  *   You should have received a copy of the GNU General Public License     *
0022  *   along with this program; if not, write to the Free Software           *
0023  *   Foundation, Inc., 51 Franklin Street, Fifth Floor,                    *
0024  *   Boston, MA  02110-1301  USA                                           *
0025  *                                                                         *
0026  ***************************************************************************/
0027 
0028 #include "ParserTest.h"
0029 
0030 extern "C" {
0031 #include "backend/gsl/parser.h"
0032 }
0033 
0034 #include <gsl/gsl_errno.h>
0035 #include <gsl/gsl_const_mksa.h>
0036 
0037 //**********************************************************
0038 //****************** Function tests ************************
0039 //**********************************************************
0040 
0041 void ParserTest::testBasics() {
0042     const QVector<QPair<QString, double>> tests{ 
0043         {"42", 42.}, {"1.", 1.}, {"1+1", 2.}, {"1+2+3+4+5", 15.}, {"2*3", 6.}, { "3/2", 1.5}, {"2 -4 +6 -1 -1- 0 +8", 10.},
0044         {"1/3+1/3+1/3", 1.}, {"1.5 + 2.5", 4.}, {"4*2.5 + 8.5+1.5 / 3.0", 19.}, {"5.0005 + 0.0095", 5.01},
0045         {"pi", M_PI}, {"e", M_E}, {"e^1", M_E},  {"hbar", GSL_CONST_MKSA_PLANCKS_CONSTANT_HBAR},
0046         {" 1   +   1  ", 2.}, {"1-    2", -1.}, {"2*    2.5", 5.}, {"3 + 8/5 -1 -2*5", -6.4},
0047         {"(1)", 1.}, {"-(1)", -1.}, {"(1+1)", 2}, {"(sin(0))", 0.} ,{"(( ((2)) + 4))*((5))", 30.},
0048         {"2^2", 4.}, {"3**2", 9.}, {"1%1", 0.}, {"3%2", 1.},
0049         {"1.e-5", 1.e-5}, {"9.5E3", 9500.}, {"|1.5|", 1.5}, {"|-2.5|", 2.5}, {"0!", 1}, {"4!", 24}, {"-3!", -6.},
0050         {"exp(0)", 1.}, {"exp(1)", M_E}, {"sqrt(0)", 0.}, {"sin(0)", 0.}, {"cos(pi)", -1.}
0051     };
0052 
0053     for ( auto& expr: tests)
0054         QCOMPARE(parse(qPrintable(expr.first), "C"), expr.second);
0055 
0056     const QVector<QPair<QString, double>> testsFuzzy{ 
0057         {"(sin(pi))", 0.}
0058     };
0059 
0060     for ( auto& expr: testsFuzzy)
0061         FuzzyCompare(parse(qPrintable(expr.first), "C"), expr.second, 1.e-15);
0062 }
0063 
0064 void ParserTest::testErrors() {
0065     gsl_set_error_handler_off();    // do not crash
0066 
0067     const QVector<QString> testsNan{
0068         "", "a", "1+", "a+1", "&", "%", "+", "*", "/", "{1}", "{1*2}", "(1+1))", "a/0", "0/0", "1/0 + a",
0069         "sqrt(-1)", "log(-1)", "log(0)", "asin(2)"
0070     };
0071 
0072     for ( auto& expr: testsNan)
0073         QVERIFY(qIsNaN(parse(qPrintable(expr), "C")));
0074     
0075     const QVector<QString> testsInf{
0076         "1/0", "-1/0",  "1+1/0"
0077     };
0078 
0079     for ( auto& expr: testsInf)
0080         QVERIFY(qIsInf(parse(qPrintable(expr), "C")));
0081 }
0082 
0083 void ParserTest::testVariables() {
0084     assign_symbol("a", 1.);
0085     const QVector<QPair<QString, double>> tests{ 
0086         {"a", 1.}, {"a+1", 2.}, {"a+1.5", 2.5}, {"a!", 1.}
0087     };
0088 
0089     for ( auto& expr: tests)
0090         QCOMPARE(parse(qPrintable(expr.first), "C"), expr.second);
0091 
0092     assign_symbol("a", 0.); // only vars set to zero get removed
0093     remove_symbol("a");
0094     for ( auto& expr: tests)
0095         QVERIFY(qIsNaN(parse(qPrintable(expr.first), "C")));
0096 
0097     // longer var name
0098     assign_symbol("sina", 1.5);
0099     const QVector<QPair<QString, double>> tests2{ 
0100         {"sina", 1.5}, {"sina+1", 2.5}, {"sina+1.5", 3.}, {"2*sina", 3.}
0101     };
0102 
0103     for ( auto& expr: tests2)
0104         QCOMPARE(parse(qPrintable(expr.first), "C"), expr.second);
0105 
0106     //parse_with_vars()
0107     parser_var vars[] = { {"x", 1.}, {"y", 2.}};
0108     QCOMPARE(parse_with_vars("x + y", vars, 2, "C"), 3.);
0109 }
0110 
0111 void ParserTest::testLocale() {
0112 //TODO: locale test currently does not work on FreeBSD
0113 #ifndef __FreeBSD__
0114     const QVector<QPair<QString, double>> tests{ 
0115         {"1,", 1.}, {"1,5", 1.5}, {"1+0,5", 1.5}, {"2*1,5", 3.}
0116     };
0117 
0118     for ( auto& expr: tests)
0119         QCOMPARE(parse(qPrintable(expr.first), "de_DE"), expr.second);
0120 #endif
0121 }
0122 
0123 ///////////// Performance ////////////////////////////////
0124 // see https://github.com/ArashPartow/math-parser-benchmark-project
0125 
0126 void ParserTest::testPerformance1() {
0127     const int N = 1e5;
0128     
0129     QBENCHMARK {
0130         for (int i = 0; i < N; i++) {
0131             const double x = i/100.;
0132             assign_symbol("x", i/100.);
0133             QCOMPARE(parse("x+1.", "C"), x+1.);
0134         }
0135     }
0136 }
0137 
0138 void ParserTest::testPerformance2() {
0139     const int N = 1e5;
0140     
0141     QBENCHMARK {
0142         for (int i = 0; i < N; i++) {
0143             assign_symbol("alpha", i/100.);
0144             QCOMPARE(parse("sin(alpha)^2 + cos(alpha)^2", "C"), 1.);
0145         }
0146     }
0147 }
0148 
0149 QTEST_MAIN(ParserTest)