Warning, file /utilities/okteta/kasten/controllers/test/scriptvalueconvertertest.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 * This file is part of the Okteta Kasten module, made within the KDE community. 0003 * 0004 * SPDX-FileCopyrightText: 2011, 2012 Alex Richardson <alex.richardson@gmx.de> 0005 * 0006 * SPDX-License-Identifier: LGPL-2.1-or-later 0007 */ 0008 0009 #include "view/structures/script/scriptengineinitializer.hpp" 0010 #include "view/structures/allprimitivetypes.hpp" 0011 0012 #include <QTest> 0013 #include <QString> 0014 #include <QDebug> 0015 #include <QScriptEngine> 0016 #include "view/structures/parsers/scriptvalueconverter.hpp" 0017 #include "view/structures/datatypes/datainformation.hpp" 0018 #include "view/structures/datatypes/primitive/primitivedatainformation.hpp" 0019 #include "view/structures/datatypes/primitive/enumdatainformation.hpp" 0020 #include "view/structures/script/scriptlogger.hpp" 0021 #include "view/structures/parsers/parserutils.hpp" 0022 0023 class ScriptValueConverterTest : public QObject 0024 { 0025 Q_OBJECT 0026 0027 private Q_SLOTS: 0028 void initTestCase(); 0029 void testPrimitives(); 0030 void testPrimitives_data(); 0031 void testParseEnum(); 0032 void basicConverterTest(); 0033 void testParseEnum_data(); 0034 0035 private: 0036 DataInformation* convert(const QString& code); 0037 DataInformation* convert(const QScriptValue& value); 0038 QScriptValue evaluate(const char* code); 0039 void dumpLoggerOutput(); 0040 QScopedPointer<QScriptEngine> engine; 0041 QScopedPointer<ScriptLogger> logger; 0042 }; 0043 0044 DataInformation* ScriptValueConverterTest::convert(const QString& code) 0045 { 0046 QScriptValue value = engine->evaluate(code); 0047 return ScriptValueConverter::convert(value, QStringLiteral("value"), logger.data()); 0048 } 0049 0050 DataInformation* ScriptValueConverterTest::convert(const QScriptValue& value) 0051 { 0052 return ScriptValueConverter::convert(value, QStringLiteral("value"), logger.data()); 0053 } 0054 0055 QScriptValue ScriptValueConverterTest::evaluate(const char* code) 0056 { 0057 return engine->evaluate(QString::fromUtf8(code)); 0058 } 0059 0060 void ScriptValueConverterTest::initTestCase() 0061 { 0062 engine.reset(ScriptEngineInitializer::newEngine()); 0063 logger.reset(new ScriptLogger()); 0064 } 0065 0066 void ScriptValueConverterTest::basicConverterTest() 0067 { 0068 logger->clear(); 0069 // check that passing functions works 0070 QScriptValue sVal = evaluate("var foo = { value : uint8(),\n" 0071 " str : struct({first : uint8(), second : uint16()}),\n" 0072 " obj : array(uint32(), 10) \n}\n foo"); 0073 QVector<DataInformation*> converted = ScriptValueConverter::convertValues(sVal, logger.data()); 0074 QCOMPARE(converted.size(), 3); 0075 QVERIFY(converted[0]->isPrimitive()); 0076 QCOMPARE(converted[0]->name(), QStringLiteral("value")); 0077 QVERIFY(converted[1]->isStruct()); 0078 QCOMPARE(converted[1]->name(), QStringLiteral("str")); 0079 QCOMPARE(converted[1]->childCount(), 2u); 0080 QVERIFY(converted[2]->isArray()); 0081 QCOMPARE(converted[2]->name(), QStringLiteral("obj")); 0082 QCOMPARE(converted[2]->childCount(), 10u); 0083 0084 // test with an array now 0085 sVal = evaluate("var foo = [uint8(), uint16(), uint32()]; foo"); 0086 qDeleteAll(converted); 0087 converted = ScriptValueConverter::convertValues(sVal, logger.data()); 0088 QCOMPARE(converted.size(), 3); 0089 QVERIFY(converted[0]->isPrimitive()); 0090 QVERIFY(converted[1]->isPrimitive()); 0091 QVERIFY(converted[2]->isPrimitive()); 0092 QVERIFY(converted[0]->asPrimitive()->type() == PrimitiveDataType::UInt8); 0093 QVERIFY(converted[1]->asPrimitive()->type() == PrimitiveDataType::UInt16); 0094 QVERIFY(converted[2]->asPrimitive()->type() == PrimitiveDataType::UInt32); 0095 QCOMPARE(converted[0]->name(), QStringLiteral("0")); 0096 QCOMPARE(converted[1]->name(), QStringLiteral("1")); 0097 QCOMPARE(converted[2]->name(), QStringLiteral("2")); 0098 0099 // check number is not a valid object 0100 sVal = evaluate("1 + 2"); 0101 QVERIFY(sVal.isNumber()); 0102 QVERIFY2(!convert(sVal), " numbers should not be valid!"); 0103 QCOMPARE(logger->rowCount(QModelIndex()), 1); 0104 0105 // should be exactly 1 error message 0106 sVal = evaluate("function foo() { return uint8(); }; foo"); 0107 QVERIFY(sVal.isFunction()); 0108 QVERIFY2(!convert(sVal), "functions should not be valid!"); 0109 QCOMPARE(logger->rowCount(QModelIndex()), 2); 0110 0111 // should be exactly 2 error messages 0112 sVal = evaluate("var x = /.*/; x"); 0113 QVERIFY(sVal.isRegExp()); 0114 QVERIFY2(!convert(sVal), " regexp should not be valid!"); 0115 QCOMPARE(logger->rowCount(QModelIndex()), 3); 0116 0117 sVal = evaluate("var obj = { x : 1 }; obj.x();"); 0118 QVERIFY(sVal.isError()); 0119 QVERIFY2(!convert(sVal), " error objects should not be valid!"); 0120 QCOMPARE(logger->rowCount(QModelIndex()), 4); 0121 0122 sVal = evaluate("var x = [1, 2, 3]; x"); 0123 QVERIFY(sVal.isArray()); 0124 QVERIFY2(!convert(sVal), " array objects should not be valid!"); 0125 QCOMPARE(logger->rowCount(QModelIndex()), 5); 0126 0127 sVal = evaluate("var x = new Date(); x"); 0128 QVERIFY(sVal.isDate()); 0129 QVERIFY2(!convert(sVal), " date objects should not be valid!"); 0130 QCOMPARE(logger->rowCount(QModelIndex()), 6); 0131 0132 sVal = evaluate("var x = true; x"); 0133 QVERIFY(sVal.isBool()); 0134 QVERIFY2(!convert(sVal), " bool objects should not be valid!"); 0135 QCOMPARE(logger->rowCount(QModelIndex()), 7); 0136 0137 sVal = evaluate("var x = null; x"); 0138 QVERIFY(sVal.isNull()); 0139 QVERIFY2(!convert(sVal), " null should not be valid!"); 0140 QCOMPARE(logger->rowCount(QModelIndex()), 8); 0141 0142 sVal = evaluate("var x = undefined; x"); 0143 QVERIFY(sVal.isUndefined()); 0144 QVERIFY2(!convert(sVal), " undefined should not be valid!"); 0145 QCOMPARE(logger->rowCount(QModelIndex()), 9); 0146 0147 // object with invalid entry 0148 sVal = evaluate("var foo = { value : function() { return 1; },\n" 0149 " str : struct({first : uint8(), second : uint16()}),\n" 0150 " obj : array(uint32(), 10) \n}\n foo"); 0151 qDeleteAll(converted); 0152 converted = ScriptValueConverter::convertValues(sVal, logger.data()); 0153 QCOMPARE(converted.size(), 2); 0154 // first entry is invalid 0155 QCOMPARE(logger->rowCount(QModelIndex()), 11); 0156 // this should cause 2 error messages -> 11 now 0157 // qDebug() << logger->messages(); 0158 qDeleteAll(converted); 0159 } 0160 0161 void ScriptValueConverterTest::testPrimitives_data() 0162 { 0163 QTest::addColumn<QString>("code"); 0164 QTest::addColumn<QString>("code2"); 0165 QTest::addColumn<QString>("typeString"); 0166 QTest::addColumn<int>("expectedType"); 0167 0168 QTest::newRow("uint8") << "uint8()" << "new uint8()" << "UInt8" << (int) PrimitiveDataType::UInt8; 0169 QTest::newRow("uint16") << "uint16()" << "new uint16()" << "UInt16" << (int) PrimitiveDataType::UInt16; 0170 QTest::newRow("uint32") << "uint32()" << "new uint32()" << "UInt32" << (int) PrimitiveDataType::UInt32; 0171 QTest::newRow("uint64") << "uint64()" << "new uint64()" << "UInt64" << (int) PrimitiveDataType::UInt64; 0172 QTest::newRow("int8") << "int8()" << "new int8()" << "Int8" << (int) PrimitiveDataType::Int8; 0173 QTest::newRow("int16") << "int16()" << "new int16()" << "Int16" << (int) PrimitiveDataType::Int16; 0174 QTest::newRow("int32") << "int32()" << "new int32()" << "Int32" << (int) PrimitiveDataType::Int32; 0175 QTest::newRow("int64") << "int64()" << "new int64()" << "Int64" << (int) PrimitiveDataType::Int64; 0176 QTest::newRow("bool8") << "bool8()" << "new bool8()" << "Bool8" << (int) PrimitiveDataType::Bool8; 0177 QTest::newRow("bool16") << "bool16()" << "new bool16()" << "Bool16" << (int) PrimitiveDataType::Bool16; 0178 QTest::newRow("bool32") << "bool32()" << "new bool32()" << "Bool32" << (int) PrimitiveDataType::Bool32; 0179 QTest::newRow("bool64") << "bool64()" << "new bool64()" << "Bool64" << (int) PrimitiveDataType::Bool64; 0180 QTest::newRow("char") << "char()" << "new char()" << "Char" << (int) PrimitiveDataType::Char; 0181 QTest::newRow("float") << "float()" << "new float()" << "Float" << (int) PrimitiveDataType::Float; 0182 QTest::newRow("double") << "double()" << "new double()" << "Double" << (int) PrimitiveDataType::Double; 0183 } 0184 0185 void ScriptValueConverterTest::testPrimitives() 0186 { 0187 QFETCH(QString, code); 0188 QFETCH(QString, code2); 0189 QFETCH(QString, typeString); 0190 QFETCH(int, expectedType); 0191 logger->clear(); 0192 auto type = static_cast<PrimitiveDataType>(expectedType); 0193 0194 QScriptValue val1 = engine->evaluate(code); 0195 QScriptValue val2 = engine->evaluate(code2); 0196 QCOMPARE(val1.property(ParserStrings::PROPERTY_TYPE()).toString(), typeString); 0197 QCOMPARE(val2.property(ParserStrings::PROPERTY_TYPE()).toString(), typeString); 0198 QCOMPARE(val1.property(ParserStrings::PROPERTY_INTERNAL_TYPE()).toString(), ParserStrings::TYPE_PRIMITIVE()); 0199 QCOMPARE(val2.property(ParserStrings::PROPERTY_INTERNAL_TYPE()).toString(), ParserStrings::TYPE_PRIMITIVE()); 0200 0201 if (type == PrimitiveDataType::Invalid) { 0202 return; // the cast will fail 0203 } 0204 QScopedPointer<DataInformation> data1(ScriptValueConverter::convert(val1, QStringLiteral("val1"), 0205 logger.data())); 0206 QScopedPointer<DataInformation> data2(ScriptValueConverter::convert(val2, QStringLiteral("val2"), 0207 logger.data())); 0208 QVERIFY(data1); 0209 QVERIFY(data2); 0210 PrimitiveDataInformation* p1 = data1->asPrimitive(); 0211 PrimitiveDataInformation* p2 = data2->asPrimitive(); 0212 QVERIFY(p1); 0213 QVERIFY(p2); 0214 QCOMPARE(p1->type(), type); 0215 QCOMPARE(p2->type(), type); 0216 if (type == PrimitiveDataType::Bitfield) { 0217 return; // the following tests don't work with bitfields 0218 } 0219 QScopedPointer<DataInformation> data3(convert(QStringLiteral("\"%1\"").arg(typeString))); 0220 QVERIFY(data3); 0221 PrimitiveDataInformation* p3 = data3->asPrimitive(); 0222 QVERIFY(p3); 0223 QCOMPARE(p3->type(), type); 0224 } 0225 0226 void ScriptValueConverterTest::testParseEnum() 0227 { 0228 // QFETCH(QString, name); 0229 QFETCH(QString, code); 0230 QFETCH(int, expectedCount); 0231 0232 QScriptValue val = engine->evaluate(code); 0233 0234 QVERIFY(val.isValid()); 0235 QVERIFY(!val.isNull()); 0236 QVERIFY(!val.isUndefined()); 0237 QVERIFY(val.isObject()); 0238 QCOMPARE(val.property(ParserStrings::PROPERTY_INTERNAL_TYPE()).toString(), QStringLiteral("enum")); 0239 0240 QScopedPointer<DataInformation> data(ScriptValueConverter::convert(val, QStringLiteral("val"), logger.data())); 0241 if (expectedCount > 0) { 0242 QVERIFY(data); 0243 } else { 0244 QVERIFY(!data); 0245 return; 0246 } 0247 EnumDataInformation* e = data->asEnum(); 0248 QVERIFY(e); 0249 0250 QMap<AllPrimitiveTypes, QString> enumVals = e->enumValues()->values(); 0251 QCOMPARE(enumVals.size(), expectedCount); 0252 0253 if (expectedCount != 0) { 0254 QFETCH(quint64, expectedValue); 0255 // to ensure it does not match when value is not found add 1 to the default 0256 AllPrimitiveTypes result = enumVals.key(QStringLiteral("value"), expectedValue + 1); 0257 QCOMPARE(result.value<quint64>(), expectedValue); 0258 } 0259 } 0260 0261 namespace { 0262 inline QString arg2(const QString& str, const char* arg_1, const char* arg_2) 0263 { 0264 return str.arg(QString::fromUtf8(arg_1), QString::fromUtf8(arg_2)); 0265 } 0266 } 0267 0268 void ScriptValueConverterTest::testParseEnum_data() 0269 { 0270 QString baseStr = QStringLiteral("enumeration(\"someValues\", %1, { value : %2})"); 0271 QTest::addColumn<QString>("code"); 0272 QTest::addColumn<int>("expectedCount"); 0273 QTest::addColumn<quint64>("expectedValue"); 0274 0275 QTest::newRow("invalid_type_struct") << arg2(baseStr, "struct({ val : uint8() })", "1234.234") 0276 << 0 << quint64(0); 0277 QTest::newRow("invalid_type_array") << arg2(baseStr, "array(uint8(), 1)", "1234.234") << 0 0278 << quint64(0); 0279 QTest::newRow("invalid_type_union") << arg2(baseStr, "union({ val : uint8() })", "1234.234") 0280 << 0 << quint64(0); 0281 QTest::newRow("invalid_type_double") << arg2(baseStr, "double()", "1234.234") << 0 << quint64(0); 0282 QTest::newRow("invalid_type_float") << arg2(baseStr, "float()", "1234.234") << 0 << quint64(0); 0283 QTest::newRow("invalid_type_string") << arg2(baseStr, "string()", "1234.234") << 0 << quint64(0); 0284 0285 QTest::newRow("float2int8") << arg2(baseStr, "uint8()", "1.234") << 1 << quint64(1); 0286 QTest::newRow("float2int8_range") << arg2(baseStr, "uint8()", "1234.234") << 0 << quint64(0); 0287 QTest::newRow("float2int32") << arg2(baseStr, "uint32()", "1234.1234") << 1 << quint64(1234); 0288 QTest::newRow("float2int32_range") << arg2(baseStr, "uint32()", "5294967296.234") << 0 << quint64(0); 0289 QTest::newRow("float2int64") << arg2(baseStr, "uint64()", "5294967296.234") << 1 0290 << quint64(5294967296UL); 0291 QTest::newRow("double_overflow") << arg2(baseStr, "uint64()", "9007199254740993.0") << 0 0292 << quint64(9007199254740993UL); // only 992 and 994 can be represented as a double 0293 QTest::newRow("uint64_max_hex") << arg2(baseStr, "uint64()", "new String(\"0xFFFFFFFFFFFFFFFF\")") << 1 0294 << quint64(0xFFFFFFFFFFFFFFFFL); 0295 QTest::newRow("uint64_max") << arg2(baseStr, "uint64()", "new String(\"18446744073709551615\")") << 1 0296 << quint64(18446744073709551615UL); 0297 } 0298 0299 QTEST_GUILESS_MAIN(ScriptValueConverterTest) 0300 0301 #include "scriptvalueconvertertest.moc"