File indexing completed on 2024-05-19 03:43:03
0001 /************************************************************************************* 0002 * Copyright (C) 2007 by Aleix Pol <aleixpol@kde.org> * 0003 * * 0004 * This program is free software; you can redistribute it and/or * 0005 * modify it under the terms of the GNU General Public License * 0006 * as published by the Free Software Foundation; either version 2 * 0007 * of the License, or (at your option) any later version. * 0008 * * 0009 * This program is distributed in the hope that it will be useful, * 0010 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0012 * GNU General Public License for more details. * 0013 * * 0014 * You should have received a copy of the GNU General Public License * 0015 * along with this program; if not, write to the Free Software * 0016 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * 0017 *************************************************************************************/ 0018 0019 #include "expressiontest.h" 0020 #include "analyzer.h" 0021 #include "explexer.h" 0022 #include "expressionparser.h" 0023 0024 #include <cmath> 0025 #include <analitzautils.h> 0026 #include <QTest> 0027 0028 using namespace std; 0029 using Analitza::Expression; 0030 0031 QTEST_MAIN( ExpressionTest ) 0032 0033 ExpressionTest::ExpressionTest(QObject *parent) 0034 : QObject(parent) 0035 {} 0036 0037 ExpressionTest::~ExpressionTest() 0038 {} 0039 0040 void ExpressionTest::initTestCase() 0041 { 0042 e=new Expression; 0043 } 0044 0045 void ExpressionTest::cleanupTestCase() 0046 { 0047 delete e; 0048 } 0049 0050 static QString removeTags(const QString& in) 0051 { 0052 bool tag=false; 0053 QString out; 0054 for(int i=0; i<in.length(); i++){ 0055 if(!tag && in[i]=='<') 0056 tag=true; 0057 else if(tag && in[i]=='>') 0058 tag=false; 0059 else if(!tag) { 0060 if(in.mid(i,6)==QLatin1String(""")){ 0061 out += '"'; 0062 i+=5; 0063 } else if(in.mid(i,4)==QLatin1String(">")){ 0064 out += '>'; 0065 i+=3; 0066 } else 0067 out += in[i]; 0068 } 0069 } 0070 return out; 0071 } 0072 0073 void ExpressionTest::testConversion_data() 0074 { 0075 QTest::addColumn<QString>("input"); 0076 0077 QTest::newRow("empty") << ""; 0078 QTest::newRow("value") << "2.323232"; 0079 QTest::newRow("addition") << "2+4"; 0080 QTest::newRow("addition with var") << "2+x"; 0081 QTest::newRow("function definition") << "f:=x->x+1"; 0082 QTest::newRow("polynomial definition") << "x->x^2-x-6"; 0083 QTest::newRow("simple addition and subtraction") << "(2+x)-3"; 0084 QTest::newRow("simple addition and unary minus") << "-x+y"; 0085 QTest::newRow("minusplus") << "-(x+y)"; 0086 QTest::newRow("minuspower") << "-x^2"; 0087 QTest::newRow("sum") << "sum(x^2:x=1..10)"; 0088 QTest::newRow("piecewise") << "piecewise { x ? y, ? 33 }"; 0089 QTest::newRow("function call") << "f(2)"; 0090 QTest::newRow("vector") << "vector { x, y, z }"; 0091 QTest::newRow("bounded") << "diff(x^2:x)"; 0092 QTest::newRow("lambda call") << "(x->x+2)(2)"; 0093 QTest::newRow("lambda call") << "(f[1])(2)"; 0094 QTest::newRow("vectorselect") << "vector { 1, 2, 3 }[1]"; 0095 QTest::newRow("vectorselect2") << "(vector { 1, 2, 3 }+k)[1]"; 0096 QTest::newRow("eq") << "2=2"; 0097 QTest::newRow("vector") << "vector { 1, 2, 3 }"; 0098 QTest::newRow("list") << "list { }"; 0099 QTest::newRow("listbvar") << "sum(p:x@mylist)"; 0100 QTest::newRow("division") << "a/(b/2)"; 0101 QTest::newRow("power") << "2^(2^(2^x))"; 0102 0103 QTest::newRow("string2") << "\"a\""; 0104 QTest::newRow("string3") << "\"a&b\""; 0105 QTest::newRow("string4") << "\"a\\\"b\""; 0106 0107 QTest::newRow("matrix") << "matrix { matrixrow { 1 } }"; 0108 } 0109 0110 void ExpressionTest::testConversion() 0111 { 0112 QFETCH(QString, input); 0113 0114 ExpLexer lex(input); 0115 ExpressionParser parser; 0116 bool corr=parser.parse(&lex); 0117 0118 if(!parser.error().isEmpty()) 0119 qDebug() << ">>> " << parser.mathML() << "errors:" << parser.error(); 0120 QVERIFY(corr); 0121 QVERIFY(parser.error().isEmpty()); 0122 // qDebug() << "result:" << parser.mathML(); 0123 0124 e->setMathML(parser.mathML()); 0125 if(!e->isCorrect()) 0126 qDebug() << "semantic errors: " << e->error(); 0127 0128 QVERIFY(e->isCorrect()); 0129 QCOMPARE(e->toString(), input); 0130 QCOMPARE(removeTags(e->toHtml()), input); 0131 QCOMPARE(parser.mathML(), e->toMathML()); 0132 } 0133 0134 void ExpressionTest::testCopy_data() 0135 { 0136 QTest::addColumn<QString>("input"); 0137 0138 QTest::newRow("simple addition") << "2+4"; 0139 QTest::newRow("simple addition with var") << "2+x"; 0140 QTest::newRow("function definition") << "f:=x->x+1"; 0141 QTest::newRow("function call") << "f(x, y)"; 0142 QTest::newRow("summatory") << "sum(x:x=1..10)"; 0143 QTest::newRow("conditional") << "piecewise { x ? y, ? 33 }"; 0144 QTest::newRow("vector") << "vector { x, y, z }"; 0145 0146 QTest::newRow("simple addition") << "2+4"; 0147 QTest::newRow("simple addition with var") << "2+x"; 0148 QTest::newRow("function definition") << "f:=x->x+1"; 0149 QTest::newRow("summatory") << "sum(x:x=1..10)"; 0150 QTest::newRow("conditional") << "piecewise { x ? y, ? 33 }"; 0151 QTest::newRow("empty") << ""; 0152 } 0153 0154 void ExpressionTest::testCopy() 0155 { 0156 QFETCH(QString, input); 0157 e->setText(input); 0158 0159 Expression e2(*e); 0160 QVERIFY(e->isCorrect() && e2.isCorrect()); 0161 QCOMPARE(*e, e2); 0162 QCOMPARE(e->toString(), input); 0163 QCOMPARE(removeTags(e->toHtml()), input); 0164 } 0165 0166 void ExpressionTest::testUncorrection_data() 0167 { 0168 QTest::addColumn<QString>("input"); 0169 0170 QTest::newRow("incorrect bounds") << "product(x,1:3)"; 0171 0172 QTest::newRow("addition with missing operand") << "2+"; 0173 QTest::newRow("function definition") << "f:=n->"; 0174 QTest::newRow("piecewise") << "piecewise { ?3, 2 }"; 0175 0176 QTest::newRow("limits") << "f:=n->3.."; 0177 QTest::newRow("summatory with unknown uplimit") << "sum(x=1.. : x)"; 0178 //FIXME: Should be false in runtime, controlling it on the compiler. 0179 //There is no way to have uplimit/downlimit separatedly with the current Exp parser 0180 0181 QTest::newRow("uncotextualized bounds") << "9..99"; 0182 QTest::newRow("uncotextualized bounds") << "9..(9+9)"; 0183 QTest::newRow("uncotextualized bounds") << "x:=9..(9+9)"; 0184 QTest::newRow("uncotextualized bounds") << "3+(9..(9+9))"; 0185 QTest::newRow("uncotextualized bounds") << "3+9..(9+9)"; 0186 QTest::newRow("missing )") << "("; 0187 QTest::newRow("missing }") << "vector{"; 0188 QTest::newRow("wrong piecewise") << "piecewise { 0 ? 0 ? 0 }"; 0189 QTest::newRow("vector piece") << "vector { 0 ? 0 }"; 0190 QTest::newRow("wrong assignation") << "2:=3"; 0191 QTest::newRow("non-condition in piecewise") << "piecewise{ 2, ?3 }"; 0192 QTest::newRow("not-a-container") << "or{ x }"; 0193 QTest::newRow("different tag") << "prp { x, y, z }"; 0194 QTest::newRow("different tag") << "a+a=10.."; 0195 QTest::newRow("xxx") << "piecewise {scalarproduct(vector{x, 1/x})}"; 0196 QTest::newRow("wrong piece") << "plus(piece{2+2}, 1,2,3)"; 0197 QTest::newRow("wrong sum") << "sum(x : x)"; 0198 QTest::newRow("nopiece") << "fib:=n->piecewise { eq(n,0)?0, eq(n,1)?1, fib(n-1)+fib(n-2) }"; 0199 QTest::newRow("wrong count") << "plus(1)"; 0200 QTest::newRow("wrong parameters") << "selector(vector{1,1/3})"; 0201 QTest::newRow("empty vector") << "vector{}"; 0202 QTest::newRow("bounded sinus") << "sin(x:x)"; 0203 0204 QTest::newRow("summatory with unknown uplimit") << "sum(x : x=1..)"; 0205 QTest::newRow("summatory with unknown downlimit") << "sum(x : x=..3)"; 0206 0207 QTest::newRow("same args") << "(x,x)->x"; 0208 QTest::newRow("same boundings") << "sum(x : (x,x)=1..10)"; 0209 0210 QTest::newRow("empty minus") << "minus()"; 0211 } 0212 0213 void ExpressionTest::testUncorrection() 0214 { 0215 QFETCH(QString, input); 0216 for(int i=0; i<input.length(); i++) 0217 e->setText(input.mid(0, i)); 0218 0219 e->setText(input); 0220 0221 QVERIFY(!e->isCorrect()); 0222 QVERIFY(!e->error().isEmpty()); 0223 0224 QVERIFY(!e->error().contains(QString())); 0225 } 0226 0227 0228 0229 #include "moc_expressiontest.cpp"