File indexing completed on 2024-05-12 03:41:59

0001 /*************************************************************************************
0002  *  Copyright (C) 2010 by Aleix Pol <aleixpol@kde.org>                               *
0003  *  Copyright (C) 2022 Stephen Swanson <stephen.swanson@mailbox.org>                 *
0004  *                                                                                   *
0005  *  This program is free software; you can redistribute it and/or                    *
0006  *  modify it under the terms of the GNU General Public License                      *
0007  *  as published by the Free Software Foundation; either version 2                   *
0008  *  of the License, or (at your option) any later version.                           *
0009  *                                                                                   *
0010  *  This program is distributed in the hope that it will be useful,                  *
0011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of                   *
0012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                    *
0013  *  GNU General Public License for more details.                                     *
0014  *                                                                                   *
0015  *  You should have received a copy of the GNU General Public License                *
0016  *  along with this program; if not, write to the Free Software                      *
0017  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA   *
0018  *************************************************************************************/
0019 
0020 #include "builtintest.h"
0021 
0022 #include <cmath>
0023 #include "expression.h"
0024 #include <expressiontypechecker.h>
0025 #include <builtinmethods.h>
0026 #include <value.h>
0027 #include <QTest>
0028 
0029 QTEST_MAIN( BuiltInTest )
0030 
0031 Q_DECLARE_METATYPE(int*)
0032 
0033 using namespace Analitza;
0034 
0035 class CFib : public Analitza::FunctionDefinition
0036 {
0037     public:
0038         int fib(uint n) {
0039             switch(n) {
0040                 case 0:
0041                     return 0;
0042                 case 1:
0043                     return 1;
0044                 default:
0045                     return fib(n-1)+fib(n-2);
0046             }
0047         }
0048         
0049         virtual Expression operator()(const QList<Expression>& args) override {
0050             int val = args.first().toReal().intValue();
0051             if(val>=0)
0052                 return Expression(Cn(fib(val)));
0053             else {
0054                 Expression err;
0055                 err.addError(QStringLiteral("cannot calculate negative fibonacci"));
0056                 return err;
0057             }
0058         }
0059 };
0060 
0061 class VehicleConstructor : public Analitza::FunctionDefinition
0062 {
0063     virtual Expression operator()(const QList< Expression >& args) override
0064     {
0065         return Expression::constructCustomObject(QVariant(args.first().toReal().intValue()),nullptr);
0066     }
0067 };
0068 
0069 class Tires : public Analitza::FunctionDefinition
0070 {
0071     virtual Expression operator()(const QList< Expression >& args) override
0072     {
0073         QVariant value = args.first().customObjectValue();
0074         return Expression(Cn(value.toInt()));
0075     }
0076 };
0077 
0078 class NewIntConstructor : public Analitza::FunctionDefinition
0079 {
0080     static void destroy(const QVariant& v)
0081     {
0082         int* vv=v.value<int*>();
0083         delete vv;
0084     }
0085     
0086     virtual Expression operator()(const QList< Expression >& args) override
0087     {
0088         int* pi=new int(args.first().toReal().intValue());
0089         return Expression::constructCustomObject(QVariant::fromValue<int*>(pi), destroy);
0090     }
0091 };
0092 
0093 class ReadInt : public Analitza::FunctionDefinition
0094 {
0095     virtual Expression operator()(const QList< Expression >& args) override
0096     {
0097         Cn n(*args.first().customObjectValue().value<int*>());
0098         return Expression(n);
0099     }
0100 };
0101 
0102 class CreateList : public Analitza::FunctionDefinition
0103 {
0104     virtual Expression operator()(const QList< Expression >& args) override
0105     {
0106         QList<Expression> exps;
0107         for(int i=0; i<10; i++)
0108             exps += Expression(Cn(i+args.first().toReal().value()));
0109         
0110         return Expression::constructList(exps);
0111     }
0112 };
0113 
0114 class Wrong : public Analitza::FunctionDefinition
0115 {
0116     virtual Expression operator()(const QList< Expression >& args) override
0117     {
0118         return args.first();
0119     }
0120 };
0121 
0122 class MeaningOfLife : public Analitza::FunctionDefinition
0123 {
0124     virtual Expression operator()(const QList< Expression >& args) override
0125     {
0126         Q_UNUSED(args)
0127         return Expression(Cn(42.));
0128     }
0129 };
0130 
0131 class JustCrash : public Analitza::FunctionDefinition
0132 {
0133     virtual Expression operator()(const QList< Expression >& args) override
0134     {
0135         Q_ASSERT(false);
0136         operator()(args);
0137         return Expression(Cn(true));
0138     }
0139 };
0140 
0141 BuiltInTest::BuiltInTest(QObject* parent)
0142     : QObject(parent)
0143 {
0144     //fibonacci tests
0145     ExpressionType fibType(ExpressionType::Lambda);
0146     fibType.addParameter(ExpressionType(ExpressionType::Value));
0147     fibType.addParameter(ExpressionType(ExpressionType::Value));
0148     a.builtinMethods()->insertFunction(QStringLiteral("fib"), fibType, new CFib);
0149     
0150     //object tests: tires
0151     ExpressionType tiresType(ExpressionType::Lambda);
0152     tiresType.addParameter(ExpressionType(QStringLiteral("Vehicle")));
0153     tiresType.addParameter(ExpressionType(ExpressionType::Value));
0154     a.builtinMethods()->insertFunction(QStringLiteral("tires"), tiresType, new Tires);
0155     
0156     //object tests: constructor
0157     ExpressionType vehicleType(ExpressionType::Lambda);
0158     vehicleType.addParameter(ExpressionType(ExpressionType::Value));
0159     vehicleType.addParameter(ExpressionType(QStringLiteral("Vehicle")));
0160     a.builtinMethods()->insertFunction(QStringLiteral("vehicle"), vehicleType, new VehicleConstructor);
0161     
0162     //object tests: newint
0163     ExpressionType refintType(ExpressionType::Lambda);
0164     refintType.addParameter(ExpressionType(ExpressionType::Value));
0165     refintType.addParameter(ExpressionType(QStringLiteral("RefInt")));
0166     a.builtinMethods()->insertFunction(QStringLiteral("refint"), refintType, new NewIntConstructor);
0167     
0168     //object tests: readint
0169     ExpressionType readintType(ExpressionType::Lambda);
0170     readintType.addParameter(ExpressionType(QStringLiteral("RefInt")));
0171     readintType.addParameter(ExpressionType(ExpressionType::Value));
0172     a.builtinMethods()->insertFunction(QStringLiteral("readint"), readintType, new ReadInt);
0173     
0174     //Returns a list
0175     ExpressionType createlistType(ExpressionType::Lambda);
0176     createlistType.addParameter(ExpressionType(ExpressionType::Value));
0177     createlistType.addParameter(ExpressionType(ExpressionType::List, ExpressionType(ExpressionType::Value)));
0178     a.builtinMethods()->insertFunction(QStringLiteral("createlist"), createlistType, new CreateList);
0179     
0180     ExpressionType wrongType(ExpressionType::Lambda);
0181     wrongType.addParameter(ExpressionType(ExpressionType::Value));
0182     wrongType.addParameter(ExpressionType(QStringLiteral("Wrong")));
0183     a.builtinMethods()->insertFunction(QStringLiteral("wrong"), refintType, new Wrong);
0184     
0185     ExpressionType justReturn(ExpressionType::Lambda);
0186     justReturn.addParameter(ExpressionType(ExpressionType::Value));
0187     a.builtinMethods()->insertFunction(QStringLiteral("lifesmeaning"), justReturn, new MeaningOfLife);
0188     
0189     ExpressionType justCrash(ExpressionType::Lambda);
0190     justCrash.addParameter(ExpressionType(ExpressionType::Value));
0191     justCrash.addParameter(ExpressionType(ExpressionType::Bool));
0192     a.builtinMethods()->insertFunction(QStringLiteral("justcrash"), justCrash, new JustCrash);
0193 }
0194 
0195 BuiltInTest::~BuiltInTest()
0196 {}
0197 
0198 #define IN QStringList() <<
0199 
0200 void BuiltInTest::testCall_data()
0201 {
0202     QTest::addColumn<QStringList>("inputs");
0203     QTest::addColumn<QString>("output");
0204     
0205     QTest::newRow("negfib") << (IN QStringLiteral("fib(-1)")) << "err";
0206     QTest::newRow("zerofib") << (IN QStringLiteral("fib(0)")) << "0";
0207     QTest::newRow("fib") << (IN QStringLiteral("fib(23)")) << "28657";
0208     QTest::newRow("fibmap") << (IN QStringLiteral("map(fib, list{1,5,10})")) << "list { 1, 5, 55 }";
0209     
0210     QTest::newRow("vechicle") << (IN QStringLiteral("tires(vehicle(2))")) << "2";
0211     QTest::newRow("varcar") << (IN QStringLiteral("car:=vehicle(4)") << QStringLiteral("tires(car)")) << "4";
0212     
0213     QTest::newRow("lambdaarg") << (IN QStringLiteral("call:=(x,y)->x(y)") << QStringLiteral("car:=call(vehicle,4)") << QStringLiteral("tires(car)")) << "4";
0214     
0215     QTest::newRow("ref") << (IN QStringLiteral("sum(readint(refint(x)) : x=1..10)")) << "55";
0216 
0217     QTest::newRow("comb") << (IN QStringLiteral("comb(5,2)")) << "10";
0218     QTest::newRow("perm") << (IN QStringLiteral("perm(5,2)")) << "20";
0219     
0220     QTest::newRow("sum") << (IN QStringLiteral("sum(x : x@createlist(3))")) << "75";
0221     QTest::newRow("sum2") << (IN QStringLiteral("f:=w->sum(x : x@w)") << QStringLiteral("f(createlist(3))")) << "75";
0222     QTest::newRow("comparison") << (IN QStringLiteral("vehicle(2)!=vehicle(3)")) << "true";
0223     QTest::newRow("comparison2") << (IN QStringLiteral("vehicle(2)!=vehicle(2)")) << "false";
0224     
0225     QTest::newRow("error1") << (IN QStringLiteral("tires(2)")) << "errcomp";
0226     QTest::newRow("error2") << (IN QStringLiteral("tires(createlist(3))")) << "errcomp";
0227     QTest::newRow("error3") << (IN QStringLiteral("tires(wrong(3))")) << "errcomp";
0228     
0229     QTest::newRow("onearg") << (IN QStringLiteral("lifesmeaning()")) << "42";
0230     
0231     QTest::newRow("and") << (IN QStringLiteral("and(false, justcrash(33))")) << "false";
0232     QTest::newRow("or") << (IN QStringLiteral("or(true, justcrash(33))")) << "true";
0233     QTest::newRow("and1") << (IN QStringLiteral("and(false, true, justcrash(33))")) << "false";
0234     QTest::newRow("or1") << (IN QStringLiteral("or(true, false, justcrash(33))")) << "true";
0235 
0236     QTest::newRow("img-powers") << QStringList{"realpower(-8, 1/3)"} << "-2";
0237 }
0238 
0239 void BuiltInTest::testCall()
0240 {
0241     QFETCH(QStringList, inputs);
0242     QFETCH(QString, output);
0243     
0244     Expression calc;
0245     foreach(const QString& input, inputs) {
0246         Expression ei(input);
0247         if(!ei.isCorrect()) qDebug() << "error:" << ei.error();
0248         QVERIFY(ei.isCorrect());
0249         
0250         a.setExpression(ei);
0251         if(!a.isCorrect()) {
0252             QCOMPARE(QStringLiteral("errcomp"), output);
0253             return;
0254         }
0255         
0256         qDebug() << "peee" << a.type().toString() << input;
0257         calc = a.calculate();
0258     }
0259     
0260     if(a.isCorrect())
0261         QCOMPARE(calc.toString(), output);
0262     else
0263         QCOMPARE(QStringLiteral("err"), output);
0264 
0265 //     Expression eval;
0266 //     foreach(const QString& input, inputs) {
0267 //         Expression ei(input);
0268 //         if(!ei.isCorrect()) qDebug() << "error:" << ei.error();
0269 //         QVERIFY(ei.isCorrect());
0270 //         a.setExpression(ei);
0271 //         QVERIFY(a.isCorrect());
0272 //         eval = a.evaluate();
0273 //     }
0274 //
0275 //     if(a.isCorrect())
0276 //         QCOMPARE(eval.toString(), output);
0277 //     else
0278 //         QCOMPARE(QStringLiteral("err"), output);
0279 }
0280 
0281 #include "moc_builtintest.cpp"