File indexing completed on 2024-05-12 05:52:21
0001 /* 0002 SPDX-FileCopyrightText: 2023 Gabriel Barrantes <gabriel.barrantes.dev@outlook.com> 0003 SPDX-License-Identifier: GPL-2.0-or-later 0004 */ 0005 0006 #include "../kcalc_core.h" 0007 #include "../kcalc_parser.h" 0008 0009 #include <QQueue> 0010 #include <QTest> 0011 0012 #define QS(s) QStringLiteral(s) 0013 0014 /** 0015 * The main test class. 0016 */ 0017 class KCalcParserCoreTest : public QObject 0018 { 0019 Q_OBJECT 0020 0021 private Q_SLOTS: 0022 void initTestCase(); 0023 0024 void testParserCore_data(); 0025 void testParserCore(); 0026 0027 void testParserError_data(); 0028 void testParserError(); 0029 0030 void testCalculationError_data(); 0031 void testCalculationError(); 0032 0033 void cleanupTestCase(); 0034 0035 private: 0036 QQueue<KCalcToken> token_Queue_; 0037 CalcEngine core; 0038 KCalcParser parser; 0039 0040 int input_error_index_; 0041 }; 0042 0043 void KCalcParserCoreTest::initTestCase() 0044 { 0045 // load constants into parser 0046 } 0047 0048 void KCalcParserCoreTest::testParserCore_data() 0049 { 0050 QTest::addColumn<QString>("input"); 0051 QTest::addColumn<int>("base"); 0052 QTest::addColumn<QString>("expectedResult"); 0053 0054 // Simple operations // 0055 QTest::newRow("addition test") << QS("1+2") << 10 << QS("3"); 0056 QTest::newRow("subtaction test") << QS("7-2") << 10 << QS("5"); 0057 QTest::newRow("multiplication test 1") << QS("50*2") << 10 << QS("100"); 0058 QTest::newRow("multiplication test 2") << QS("50×2") << 10 << QS("100"); 0059 QTest::newRow("division test") << QS("50÷12") << 10 << QS("25/6"); 0060 QTest::newRow("div test using slash") << QS("1/2") << 10 << QS("1/2"); 0061 QTest::newRow("percentage") << QS("10×50%") << 10 << QS("5"); 0062 QTest::newRow("inverse test 1") << QS("10⁻¹") << 10 << QS("1/10"); 0063 QTest::newRow("inverse test 2") << QS("10⁻¹⁻¹") << 10 << QS("10"); 0064 QTest::newRow("sqrt test 2") << QS("√5") << 10 << QS("2.2360679775"); 0065 QTest::newRow("square test 1") << QS("2.2360679775²") << 10 << QS("5"); 0066 QTest::newRow("square test 2") << QS("2.2360679775²²") << 10 << QS("25"); 0067 QTest::newRow("power test 1") << QS("5^5") << 10 << QS("3125"); 0068 QTest::newRow("power test 2") << QS("2^2^2") << 10 << QS("16"); 0069 QTest::newRow("sin test") << QS("sin(90)") << 10 << QS("1"); 0070 QTest::newRow("sin test2") << QS("sin(45)") << 10 << QS("0.707106781187"); 0071 QTest::newRow("cos test") << QS("cos(90)") << 10 << QS("0"); 0072 QTest::newRow("tan test") << QS("tan(45)") << 10 << QS("1"); 0073 QTest::newRow("asin test") << QS("asin(0.707106781187)") << 10 << QS("45"); 0074 QTest::newRow("asin test") << QS("asin(1)") << 10 << QS("90"); 0075 QTest::newRow("acos test") << QS("acos(0)") << 10 << QS("90"); 0076 QTest::newRow("atan test") << QS("atan(1)") << 10 << QS("45"); 0077 0078 QTest::newRow("sinh test 1") << QS("sinh(1)") << 10 << QS("1.17520119364"); 0079 QTest::newRow("cosh test 1") << QS("cosh(1)") << 10 << QS("1.54308063482"); 0080 QTest::newRow("tanh test 1") << QS("tanh(2000.90645)") << 10 << QS("1"); 0081 QTest::newRow("tanh test 2") << QS("tanh(0.5)") << 10 << QS("0.46211715726"); 0082 QTest::newRow("asinh test 1") << QS("asinh(1.17520119364)") << 10 << QS("0.999999999998"); 0083 QTest::newRow("acosh test 2") << QS("acosh(1.54308063481)") << 10 << QS("0.999999999996"); 0084 QTest::newRow("atanh test 3") << QS("atanh(0.46211715726)") << 10 << QS("0.5"); 0085 0086 QTest::newRow("ln test 1") << QS("ln(2.71)") << 10 << QS("0.996948634892"); 0087 QTest::newRow("ln test 2") << QS("ln(2.718281828460)") << 10 << QS("1"); 0088 QTest::newRow("log test 1") << QS("log(10)") << 10 << QS("1"); 0089 QTest::newRow("log test 2") << QS("log(100)") << 10 << QS("2"); 0090 QTest::newRow("log test 3") << QS("log(1000)") << 10 << QS("3"); 0091 0092 QTest::newRow("exp test") << QS("exp(1)") << 10 << QS("2.71828182846"); 0093 QTest::newRow("exp10 test") << QS("5⏨2") << 10 << QS("500"); 0094 0095 QTest::newRow("- test 1") << QS("-590") << 10 << QS("-590"); 0096 QTest::newRow("- test 2") << QS("-1cos(45)") << 10 << QS("-0.707106781187"); 0097 QTest::newRow("- test 3") << QS("-cos(45)") << 10 << QS("-0.707106781187"); 0098 QTest::newRow("- test 4") << QS("-20-cos(45)") << 10 << QS("-20.7071067812"); 0099 QTest::newRow("- test 5") << QS("-1×-1") << 10 << QS("1"); 0100 QTest::newRow("- test 6") << QS("-1÷-1") << 10 << QS("1"); 0101 QTest::newRow("- test 7") << QS("-7 mod 5") << 10 << QS("-2"); 0102 QTest::newRow("- test 8") << QS("5×--5") << 10 << QS("25"); 0103 QTest::newRow("- test 9") << QS("5×---5") << 10 << QS("-25"); 0104 QTest::newRow("- test 10") << QS("7 mod -5") << 10 << QS("2"); 0105 QTest::newRow("-- test 1") << QS("--5") << 10 << QS("5"); 0106 QTest::newRow("-- test 2") << QS("--5+6") << 10 << QS("11"); 0107 QTest::newRow("-- test 3") << QS("--4--9+100") << 10 << QS("113"); 0108 QTest::newRow("-- test 4") << QS("--4--9-100") << 10 << QS("-87"); 0109 QTest::newRow("-- test 5") << QS("--4--9×100") << 10 << QS("904"); 0110 QTest::newRow("-- test 6") << QS("--4×45--9×100") << 10 << QS("1080"); 0111 QTest::newRow("-- test 7") << QS("--4×45--9×100") << 10 << QS("1080"); 0112 0113 QTest::newRow("+ test 1") << QS("+7") << 10 << QS("7"); 0114 QTest::newRow("++ test 1") << QS("++7") << 10 << QS("7"); 0115 QTest::newRow("+++ test 1") << QS("+++7") << 10 << QS("7"); 0116 QTest::newRow("+++ test 2") << QS("+++7-7²") << 10 << QS("-42"); 0117 QTest::newRow("+++ test 3") << QS("+++7--7²") << 10 << QS("56"); 0118 QTest::newRow("+ test 2") << QS("+7--1") << 10 << QS("8"); 0119 QTest::newRow("+ test 3") << QS("+7--20") << 10 << QS("27"); 0120 QTest::newRow("+ test 4") << QS("+7-20") << 10 << QS("-13"); 0121 QTest::newRow("+ test 5") << QS("+7-20+30") << 10 << QS("17"); 0122 QTest::newRow("+ test 6") << QS("+7----1") << 10 << QS("8"); 0123 0124 QTest::newRow("& test 1") << QS("0b10 & 0b100") << 10 << QS("0"); 0125 QTest::newRow("& test 2") << QS("0b10 & 0b11 & 0b110") << 10 << QS("2"); 0126 QTest::newRow("| test 1") << QS("0b10 | 0b1") << 10 << QS("3"); 0127 QTest::newRow("~ test 1") << QS("~~0b10") << 10 << QS("2"); 0128 QTest::newRow("<< test 1") << QS("0b10<<1") << 10 << QS("4"); 0129 QTest::newRow(">> test 1") << QS("0b10>>1") << 10 << QS("1"); 0130 0131 QTest::newRow("mod test 1") << QS("15 mod 10") << 10 << QS("5"); 0132 QTest::newRow("mod test 2") << QS("100 mod 101 mod 90 mod 8") << 10 << QS("2"); 0133 QTest::newRow("div test 1") << QS("15 div 10") << 10 << QS("1"); 0134 QTest::newRow("div test 2") << QS("25 div 10") << 10 << QS("2"); 0135 QTest::newRow("factorial test 1") << QS("5!") << 10 << QS("120"); 0136 0137 QTest::newRow("0x test 1") << QS("0xA+10") << 10 << QS("20"); 0138 QTest::newRow("0b test 1") << QS("0b100+1") << 10 << QS("5"); 0139 QTest::newRow("0 test 1") << QS("010+8") << 10 << QS("16"); 0140 QTest::newRow("base test 1") << QS("0xFF & 0b1111 & 07") << 10 << QS("7"); 0141 // parenthesis input 0142 QTest::newRow("parenthesis test 1") << QS("(√5)²") << 10 << QS("5"); 0143 QTest::newRow("parenthesis test 2") << QS("(1+3)") << 10 << QS("4"); 0144 QTest::newRow("parenthesis test 3") << QS("(1+3)²") << 10 << QS("16"); 0145 QTest::newRow("parenthesis test 4") << QS("5×(1+3)") << 10 << QS("20"); 0146 QTest::newRow("parenthesis test 5") << QS("5×(1+3)+2") << 10 << QS("22"); 0147 QTest::newRow("parenthesis test 6") << QS("5×(1+3)-2") << 10 << QS("18"); 0148 QTest::newRow("parenthesis test 7") << QS("2(5×(1+3)-2)") << 10 << QS("36"); 0149 QTest::newRow("parenthesis test 8") << QS("5×(1+3)²") << 10 << QS("80"); 0150 QTest::newRow("parenthesis test 9") << QS("cos(1+2+87)") << 10 << QS("0"); 0151 QTest::newRow("parenthesis test 10") << QS("(1)(2)(3)") << 10 << QS("6"); 0152 QTest::newRow("parenthesis test 11") << QS("(((((-1)))))") << 10 << QS("-1"); 0153 QTest::newRow("parenthesis test 12") << QS("(((((-1)))))+2") << 10 << QS("1"); 0154 QTest::newRow("parenthesis test 13") << QS("√(1+2+3!+91)") << 10 << QS("10"); 0155 QTest::newRow("parenthesis test 14") << QS("sin(sin(sin(sin(0))))") << 10 << QS("0"); 0156 QTest::newRow("parenthesis test 15") << QS("ln(exp(1))") << 10 << QS("1"); 0157 QTest::newRow("parenthesis test 16") << QS("ln(exp(100.45))") << 10 << QS("100.45"); 0158 } 0159 0160 void KCalcParserCoreTest::testParserCore() 0161 { 0162 QFETCH(QString, input); 0163 QFETCH(int, base); 0164 QFETCH(QString, expectedResult); 0165 0166 int parsing_result, calculation_result, errorIndex; 0167 parsing_result = parser.stringToTokenQueue(input, base, token_Queue_, errorIndex); 0168 QCOMPARE(parsing_result, 0); // successful parsing 0169 0170 calculation_result = core.calculate(token_Queue_, errorIndex); 0171 0172 QCOMPARE(calculation_result, 0); // successful calculation 0173 0174 QString coreResult = core.getResult().toQString(12, -1); 0175 coreResult.replace(KNumber::decimalSeparator().at(0), QLatin1Char('.')); 0176 coreResult.replace(QLatin1Char(','), QLatin1Char('.')); 0177 QCOMPARE(coreResult, expectedResult); 0178 } 0179 0180 void KCalcParserCoreTest::testParserError_data() 0181 { 0182 QTest::addColumn<QString>("input"); 0183 QTest::addColumn<int>("expectedErrorIndex"); 0184 0185 // invalid characters in input // 0186 QTest::newRow("parsing error test 1") << QS("1+s2") << 2; 0187 QTest::newRow("parsing error test 2") << QS("126d") << 3; 0188 QTest::newRow("parsing error test 3") << QS("1+1+1+1+1+m") << 10; 0189 } 0190 0191 void KCalcParserCoreTest::testParserError() 0192 { 0193 QFETCH(QString, input); 0194 QFETCH(int, expectedErrorIndex); 0195 0196 int parsing_result, errorIndex; 0197 parsing_result = parser.stringToTokenQueue(input, 10, token_Queue_, errorIndex); 0198 0199 QCOMPARE_NE(parsing_result, 0); // fail on parsing 0200 QCOMPARE(errorIndex, expectedErrorIndex); // index indicating error position 0201 } 0202 0203 void KCalcParserCoreTest::testCalculationError_data() 0204 { 0205 QTest::addColumn<QString>("input"); 0206 QTest::addColumn<int>("expectedErrorIndex"); 0207 0208 // invalid input // 0209 QTest::newRow("calculation error test 1") << QS("1××5") << 3; 0210 QTest::newRow("calculation error test 2") << QS("1+8×!+2") << 5; 0211 QTest::newRow("calculation error test 3") << QS("tan(%)+2+3") << 5; 0212 } 0213 0214 void KCalcParserCoreTest::testCalculationError() 0215 { 0216 QFETCH(QString, input); 0217 QFETCH(int, expectedErrorIndex); 0218 0219 int parsing_result, calculation_result, errorIndex; 0220 parsing_result = parser.stringToTokenQueue(input, 10, token_Queue_, errorIndex); 0221 0222 QCOMPARE(parsing_result, 0); // successful parsing 0223 0224 calculation_result = core.calculate(token_Queue_, errorIndex); 0225 0226 QCOMPARE_NE(calculation_result, 0); // fail on calculation 0227 0228 errorIndex = token_Queue_.at(errorIndex).getStringIndex(); 0229 0230 QCOMPARE(errorIndex, expectedErrorIndex); // index indicating error position 0231 } 0232 0233 void KCalcParserCoreTest::cleanupTestCase() 0234 { 0235 } 0236 0237 QTEST_GUILESS_MAIN(KCalcParserCoreTest) 0238 0239 #include "kcalc_parser_core_test.moc"