File indexing completed on 2024-05-19 05:14:15

0001 /*
0002     SPDX-FileCopyrightText: 2018 Volker Krause <vkrause@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "modelverificationpoint.h"
0008 
0009 #include <KItinerary/JsonLdDocument>
0010 
0011 #include <QAbstractItemModel>
0012 #include <QDebug>
0013 #include <QFile>
0014 #include <QJsonArray>
0015 #include <QJsonDocument>
0016 #include <QJsonObject>
0017 #include <QProcess>
0018 
0019 ModelVerificationPoint::ModelVerificationPoint(const QString &refFile)
0020     : m_refFile(refFile)
0021 {
0022 }
0023 
0024 ModelVerificationPoint::~ModelVerificationPoint() = default;
0025 
0026 void ModelVerificationPoint::setRoleFilter(std::vector<int> &&filter)
0027 {
0028     m_roleFilter = std::move(filter);
0029 }
0030 
0031 void ModelVerificationPoint::setJsonPropertyFilter(std::vector<QString> &&filter)
0032 {
0033     m_jsonPropertyFilter = std::move(filter);
0034 }
0035 
0036 QJsonValue ModelVerificationPoint::variantToJson(const QVariant &v) const
0037 {
0038     switch (v.userType()) {
0039         case QMetaType::QString:
0040             return v.toString();
0041         case QMetaType::QStringList:
0042         {
0043             const auto l = v.toStringList();
0044             if (l.isEmpty()) {
0045                 return {};
0046             }
0047             QJsonArray a;
0048             std::copy(l.begin(), l.end(), std::back_inserter(a));
0049             return a;
0050         }
0051         case QMetaType::Bool:
0052             return v.toBool();
0053         case QMetaType::Int:
0054             return v.toInt();
0055         default:
0056             break;
0057     }
0058 
0059     if (QMetaType(v.userType()).metaObject()) {
0060         auto obj = KItinerary::JsonLdDocument::toJson(v);
0061         for (const auto &filter : m_jsonPropertyFilter) {
0062             obj.remove(filter);
0063         }
0064         return obj;
0065     } else if (v.userType() == qMetaTypeId<QVector<QVariant>>()) {
0066         return KItinerary::JsonLdDocument::toJson(v.value<QVector<QVariant>>());
0067     }
0068 
0069     return {};
0070 }
0071 
0072 bool ModelVerificationPoint::verify(QAbstractItemModel *model) const
0073 {
0074     // serialize model state
0075     QJsonArray array;
0076     const auto roleNames = model->roleNames();
0077     for (int i = 0; i < model->rowCount(); ++i) {
0078         const auto idx = model->index(i, 0);
0079         QJsonObject obj;
0080         for (auto it = roleNames.begin(); it != roleNames.end(); ++it) {
0081             if (std::find(m_roleFilter.begin(), m_roleFilter.end(), it.key()) != m_roleFilter.end()) {
0082                 continue;
0083             }
0084 
0085             const auto v = variantToJson(idx.data(it.key()));
0086             if (!v.isNull() && !(v.isArray() && v.toArray().isEmpty())) {
0087                 obj.insert(QString::fromUtf8(it.value()), v);
0088             }
0089         }
0090         array.push_back(obj);
0091     }
0092 
0093     // reference data
0094     QFile file(m_refFile);
0095     if (!file.open(QFile::ReadOnly)) {
0096         qWarning() << file.fileName() << file.errorString();
0097         return false;
0098     }
0099     const auto doc = QJsonDocument::fromJson(file.readAll());
0100     const auto refArray = doc.array();
0101 
0102     // compare
0103     if (array != refArray) {
0104         QFile failFile(m_refFile + QLatin1StringView(".fail"));
0105         failFile.open(QFile::WriteOnly);
0106         failFile.write(QJsonDocument(array).toJson());
0107         failFile.close();
0108 
0109         QProcess proc;
0110         proc.setProcessChannelMode(QProcess::ForwardedChannels);
0111         proc.start(QStringLiteral("diff"), {QStringLiteral("-u"), m_refFile, failFile.fileName()});
0112         proc.waitForFinished();
0113         return false;
0114     }
0115 
0116     return true;
0117 }