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)