Warning, file /utilities/okteta/kasten/controllers/test/primitivearraytest.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: 2012 Alex Richardson <alex.richardson@gmx.de> 0005 * 0006 * SPDX-License-Identifier: LGPL-2.1-or-later 0007 */ 0008 0009 #include <QTest> 0010 #include <QScriptEngine> 0011 #if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)) 0012 #include <QRandomGenerator> 0013 #endif 0014 #include <limits> 0015 0016 #include <Okteta/ByteArrayModel> 0017 0018 #include "view/structures/datatypes/array/arraydatainformation.hpp" 0019 #include "view/structures/datatypes/array/primitivearraydata.hpp" 0020 #include "view/structures/datatypes/topleveldatainformation.hpp" 0021 #include "view/structures/datatypes/primitive/primitivetemplateinfo.hpp" 0022 #include "view/structures/datatypes/primitivefactory.hpp" 0023 #include "view/structures/script/scriptengineinitializer.hpp" 0024 0025 class PrimitiveArrayTest : public QObject 0026 { 0027 Q_OBJECT 0028 0029 private: 0030 /** Tests user defined overrides of byteOrder, typeName, and toStringFunc. */ 0031 template <PrimitiveDataType primType, typename T> void testReadCustomizedPrimitiveInternal(); 0032 template <PrimitiveDataType primType, typename T> void testReadPrimitiveInternal(); 0033 template <PrimitiveDataType primType> void testReadPrimitive(); 0034 template <typename T> bool compareItems(T first, T second, uint index); 0035 0036 private Q_SLOTS: 0037 void initTestCase(); 0038 void testReadFloat(); 0039 void testReadDouble(); 0040 void testReadChar(); 0041 void testReadInt8(); 0042 void testReadInt16(); 0043 void testReadInt32(); 0044 void testReadInt64(); 0045 void testReadUInt8(); 0046 void testReadUInt16(); 0047 void testReadUInt32(); 0048 void testReadUInt64(); 0049 void testReadBool8(); 0050 void testReadBool16(); 0051 void testReadBool32(); 0052 void testReadBool64(); 0053 0054 private: 0055 QScopedArrayPointer<Okteta::Byte> data; 0056 QScopedPointer<Okteta::ByteArrayModel> model; 0057 QScopedArrayPointer<Okteta::Byte> endianData; 0058 QScopedPointer<Okteta::ByteArrayModel> endianModel; 0059 }; 0060 0061 #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN 0062 #define CURRENT_BYTE_ORDER (DataInformation::DataInformationEndianess::EndianessLittle) 0063 #define NON_CURRENT_BYTE_ORDER (DataInformation::DataInformationEndianess::EndianessBig) 0064 #elif Q_BYTE_ORDER == Q_BIG_ENDIAN 0065 #define CURRENT_BYTE_ORDER (DataInformation::DataInformationEndianess::EndianessBig) 0066 #define NON_CURRENT_BYTE_ORDER (DataInformation::DataInformationEndianess::EndianessLittle) 0067 #else 0068 #error unknown byte order 0069 #endif 0070 0071 static constexpr uint SIZE = 8192; 0072 static constexpr uint ENDIAN_SIZE = 16; 0073 0074 void PrimitiveArrayTest::initTestCase() 0075 { 0076 #if (QT_VERSION < QT_VERSION_CHECK(5, 10, 0)) 0077 qsrand(QTime::currentTime().msec()); 0078 #endif 0079 data.reset(new Okteta::Byte[SIZE]); 0080 // ensure that we have at least one NaN (quiet + signalling) 0081 AllPrimitiveTypes quietDouble(std::numeric_limits<double>::quiet_NaN()); 0082 AllPrimitiveTypes signallingDouble(std::numeric_limits<double>::signaling_NaN()); 0083 for (int i = 0; i < 8; ++i) { 0084 data[i] = quietDouble.allBytes[i]; 0085 data[8 + i] = signallingDouble.allBytes[i]; 0086 } 0087 0088 AllPrimitiveTypes quietFloat(std::numeric_limits<float>::quiet_NaN()); 0089 AllPrimitiveTypes signallingFloat(std::numeric_limits<float>::signaling_NaN()); 0090 for (int i = 0; i < 4; ++i) { 0091 data[16 + i] = quietFloat.allBytes[i]; 0092 data[20 + i] = signallingFloat.allBytes[i]; 0093 } 0094 0095 #if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)) 0096 auto* randomGenerator = QRandomGenerator::global(); 0097 #endif 0098 for (uint i = 24; i < SIZE; ++i) { 0099 #if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)) 0100 data[i] = static_cast<Okteta::Byte>(randomGenerator->bounded(256)); 0101 #else 0102 data[i] = char(qrand() & 0xff); 0103 #endif 0104 } 0105 0106 auto* copy = new Okteta::Byte[SIZE]; 0107 memcpy(copy, data.data(), SIZE); 0108 model.reset(new Okteta::ByteArrayModel(copy, SIZE)); 0109 model->setAutoDelete(true); 0110 QCOMPARE(model->size(), Okteta::Size(SIZE)); 0111 0112 endianData.reset(new Okteta::Byte[ENDIAN_SIZE]); 0113 for (uint i = 0; i < ENDIAN_SIZE; ++i) { 0114 endianData[i] = i; 0115 } 0116 0117 auto* endianCopy = new Okteta::Byte[SIZE]; 0118 memcpy(endianCopy, endianData.data(), ENDIAN_SIZE); 0119 endianModel.reset(new Okteta::ByteArrayModel(endianCopy, ENDIAN_SIZE)); 0120 endianModel->setAutoDelete(true); 0121 QCOMPARE(endianModel->size(), Okteta::Size(ENDIAN_SIZE)); 0122 } 0123 0124 template <typename T> 0125 bool PrimitiveArrayTest::compareItems(T first, T second, uint index) 0126 { 0127 Q_UNUSED(index); 0128 return first == second; 0129 } 0130 0131 template <> 0132 bool PrimitiveArrayTest::compareItems(float first, float second, uint index) 0133 { 0134 if (first != first) { 0135 qDebug() << "first was NaN at index" << index; 0136 // NaN 0137 if (second != second) { 0138 // second is NaN too; 0139 union 0140 { 0141 float floating; 0142 QIntegerForSizeof<float>::Unsigned integer; 0143 } firstUn, secondUn; 0144 firstUn.floating = first; 0145 secondUn.floating = second; 0146 return firstUn.integer == secondUn.integer; 0147 } 0148 0149 return false; 0150 } 0151 return first == second; 0152 } 0153 0154 template <> 0155 bool PrimitiveArrayTest::compareItems(double first, double second, uint index) 0156 { 0157 if (first != first) { 0158 qDebug() << "first was NaN at index" << index; 0159 // NaN 0160 if (second != second) { 0161 // second is NaN too; 0162 union 0163 { 0164 double floating; 0165 QIntegerForSizeof<double>::Unsigned integer; 0166 } firstUn, secondUn; 0167 firstUn.floating = first; 0168 secondUn.floating = second; 0169 return firstUn.integer == secondUn.integer; 0170 } 0171 0172 return false; 0173 } 0174 return first == second; 0175 } 0176 0177 template <PrimitiveDataType primType> 0178 inline void PrimitiveArrayTest::testReadPrimitive() 0179 { 0180 testReadPrimitiveInternal<primType, typename PrimitiveInfo<primType>::valueType>(); 0181 testReadCustomizedPrimitiveInternal<primType, typename PrimitiveInfo<primType>::valueType>(); 0182 } 0183 0184 QScriptValue customToStringFunc(QScriptContext* context, QScriptEngine* engine) 0185 { 0186 Q_UNUSED(context); 0187 Q_UNUSED(engine); 0188 return QStringLiteral("myvalue"); 0189 } 0190 0191 template <PrimitiveDataType primType, typename T> 0192 void PrimitiveArrayTest::testReadCustomizedPrimitiveInternal() 0193 { 0194 LoggerWithContext lwc(nullptr, QString()); 0195 QScriptEngine* engine = ScriptEngineInitializer::newEngine(); 0196 0197 PrimitiveDataInformation* primInfo(PrimitiveFactory::newInstance(QStringLiteral("value"), primType, lwc)); 0198 primInfo->setByteOrder(NON_CURRENT_BYTE_ORDER); 0199 primInfo->setCustomTypeName(QStringLiteral("mytype")); 0200 primInfo->setToStringFunction(engine->newFunction(customToStringFunc)); 0201 0202 auto* dataInf = new ArrayDataInformation(QStringLiteral("values"), 0203 endianModel->size() / sizeof(T), 0204 primInfo); 0205 QScopedPointer<TopLevelDataInformation> top(new TopLevelDataInformation(dataInf, nullptr, engine)); 0206 0207 QCOMPARE(dataInf->childCount(), uint(ENDIAN_SIZE / sizeof(T))); 0208 quint8 bitOffs = 0; 0209 qint64 result = dataInf->readData(endianModel.data(), 0, endianModel->size() * 8, &bitOffs); 0210 QCOMPARE(Okteta::Size(result), endianModel->size() * 8); 0211 T* dataAsT = reinterpret_cast<T*>(endianData.data()); 0212 QVERIFY(!dataInf->mData->isComplex()); 0213 auto* arrayData = static_cast<PrimitiveArrayData<primType>*>(dataInf->mData.data()); 0214 0215 // Verify byteOrder of values. The data is set up without palindromes. 0216 if (sizeof(T) > 1) { 0217 for (uint i = 0; i < dataInf->childCount(); ++i) { 0218 AllPrimitiveTypes childDataAll = arrayData->valueAt(i); 0219 T childData = childDataAll.value<T>(); 0220 T expected = dataAsT[i]; 0221 // TODO comparison for float and double: nan != nan 0222 if (compareItems<T>(childData, expected, i)) { 0223 QByteArray desc = "i=" + QByteArray::number(i) + ", model[i]=" 0224 + QByteArray::number(childData) 0225 + ", data[i]=" + QByteArray::number(expected); 0226 QVERIFY2(!compareItems<T>(childData, expected, i), desc.constData()); 0227 } 0228 } 0229 } 0230 // Verify typeName as the user will see it. 0231 QCOMPARE(arrayData->dataAt(0, DataInformation::ColumnType, Qt::DisplayRole).toString(), 0232 QStringLiteral("mytype")); 0233 // Verify value string as the user will see it. 0234 QCOMPARE(arrayData->dataAt(0, DataInformation::ColumnValue, Qt::DisplayRole).toString(), 0235 QStringLiteral("myvalue")); 0236 } 0237 0238 template <PrimitiveDataType primType, typename T> 0239 void PrimitiveArrayTest::testReadPrimitiveInternal() 0240 { 0241 LoggerWithContext lwc(nullptr, QString()); 0242 auto* dataInf = new ArrayDataInformation(QStringLiteral("values"), 0243 model->size() / sizeof(T), 0244 PrimitiveFactory::newInstance(QStringLiteral("value"), primType, lwc)); 0245 dataInf->setByteOrder(CURRENT_BYTE_ORDER); 0246 QScopedPointer<TopLevelDataInformation> top(new TopLevelDataInformation(dataInf, nullptr, 0247 ScriptEngineInitializer::newEngine())); 0248 QCOMPARE(dataInf->childCount(), uint(SIZE / sizeof(T))); 0249 quint8 bitOffs = 0; 0250 qint64 result = dataInf->readData(model.data(), 0, model->size() * 8, &bitOffs); 0251 QCOMPARE(Okteta::Size(result), model->size() * 8); 0252 T* dataAsT = reinterpret_cast<T*>(data.data()); 0253 QVERIFY(!dataInf->mData->isComplex()); 0254 auto* arrayData = static_cast<PrimitiveArrayData<primType>*>(dataInf->mData.data()); 0255 for (uint i = 0; i < dataInf->childCount(); ++i) { 0256 AllPrimitiveTypes childDataAll = arrayData->valueAt(i); 0257 T childData = childDataAll.value<T>(); 0258 T expected = dataAsT[i]; 0259 // TODO comparison for float and double: nan != nan 0260 if (!compareItems<T>(childData, expected, i)) { 0261 QByteArray desc = "i=" + QByteArray::number(i) + ", model[i]=" 0262 + QByteArray::number(childData) 0263 + ", data[i]=" + QByteArray::number(expected); 0264 QVERIFY2(compareItems<T>(childData, expected, i), desc.constData()); 0265 } 0266 } 0267 } 0268 0269 void PrimitiveArrayTest::testReadFloat() 0270 { 0271 testReadPrimitive<PrimitiveDataType::Float>(); 0272 } 0273 0274 void PrimitiveArrayTest::testReadDouble() 0275 { 0276 testReadPrimitive<PrimitiveDataType::Double>(); 0277 } 0278 0279 void PrimitiveArrayTest::testReadChar() 0280 { 0281 testReadPrimitive<PrimitiveDataType::Char>(); 0282 } 0283 0284 void PrimitiveArrayTest::testReadInt8() 0285 { 0286 testReadPrimitive<PrimitiveDataType::Int8>(); 0287 } 0288 0289 void PrimitiveArrayTest::testReadInt16() 0290 { 0291 testReadPrimitive<PrimitiveDataType::Int16>(); 0292 } 0293 0294 void PrimitiveArrayTest::testReadInt32() 0295 { 0296 testReadPrimitive<PrimitiveDataType::Int32>(); 0297 } 0298 0299 void PrimitiveArrayTest::testReadInt64() 0300 { 0301 testReadPrimitive<PrimitiveDataType::Int64>(); 0302 } 0303 0304 void PrimitiveArrayTest::testReadUInt8() 0305 { 0306 testReadPrimitive<PrimitiveDataType::UInt8>(); 0307 } 0308 0309 void PrimitiveArrayTest::testReadUInt16() 0310 { 0311 testReadPrimitive<PrimitiveDataType::UInt16>(); 0312 } 0313 0314 void PrimitiveArrayTest::testReadUInt32() 0315 { 0316 testReadPrimitive<PrimitiveDataType::UInt32>(); 0317 } 0318 0319 void PrimitiveArrayTest::testReadUInt64() 0320 { 0321 testReadPrimitive<PrimitiveDataType::UInt64>(); 0322 } 0323 0324 void PrimitiveArrayTest::testReadBool8() 0325 { 0326 testReadPrimitive<PrimitiveDataType::Bool8>(); 0327 } 0328 0329 void PrimitiveArrayTest::testReadBool16() 0330 { 0331 testReadPrimitive<PrimitiveDataType::Bool16>(); 0332 } 0333 0334 void PrimitiveArrayTest::testReadBool32() 0335 { 0336 testReadPrimitive<PrimitiveDataType::Bool32>(); 0337 } 0338 0339 void PrimitiveArrayTest::testReadBool64() 0340 { 0341 testReadPrimitive<PrimitiveDataType::Bool64>(); 0342 } 0343 0344 QTEST_GUILESS_MAIN(PrimitiveArrayTest) 0345 0346 #include "primitivearraytest.moc"