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"