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)