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("&quot;")){
0061                 out += '"';
0062                 i+=5;
0063             } else if(in.mid(i,4)==QLatin1String("&gt;")){
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"