File indexing completed on 2024-05-12 15:19:52
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"