File: DatabaseTest.cpp

package info (click to toggle)
kaidan 0.15.0-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 9,376 kB
  • sloc: cpp: 30,143; xml: 1,623; sh: 522; python: 34; makefile: 5
file content (132 lines) | stat: -rw-r--r-- 4,132 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
// SPDX-FileCopyrightText: 2024 Linus Jahn <lnj@kaidan.im>
//
// SPDX-License-Identifier: LGPL-2.1-or-later

// std
#include <ranges>
// Qt
#include <QSqlDatabase>
#include <QSqlField>
#include <QSqlQuery>
#include <QSqlRecord>
#include <QTest>
// Kaidan
#include "Algorithms.h"
#include "Database.h"
#include "Settings.h"
#include "SqlUtils.h"
#include "Test.h"

using namespace SqlUtils;
using std::ranges::sort;
using std::views::iota;
using std::views::zip;

static auto dbTableRecords(QSqlDatabase &db)
{
    auto tables = db.tables();
    std::sort(tables.begin(), tables.end());

    auto records = transform(tables, [&](const auto &tableName) {
        return db.record(tableName);
    });

    return std::tuple{std::move(tables), std::move(records)};
}

static auto fieldNames(const QSqlRecord &record)
{
    QStringList fieldNames;
    for (int i : iota(0, record.count())) {
        fieldNames.push_back(record.fieldName(i));
    }
    return fieldNames;
}

class DatabaseTest : public Test
{
    Q_OBJECT

private:
    Q_SLOT void conversion();
};

void DatabaseTest::conversion()
{
    new Settings(this);
    Database db;
    auto sqlDb = db.currentDatabase();

    // create database using conversion functions
    db.createV3Database();
    db.createTables();

    // dump tables
    auto [tableNamesConversion, recordsConversion] = dbTableRecords(sqlDb);

    // remove all created tables
    QSqlQuery query(sqlDb);
    for (const auto &tableName : sqlDb.tables()) {
        execQuery(query, QStringLiteral("DROP TABLE ") + tableName);
    }
    for (const auto &viewName : sqlDb.tables(QSql::Views)) {
        execQuery(query, QStringLiteral("DROP VIEW ") + viewName);
    }

    // create tables directly (without conversion functions)
    db.createNewDatabase();

    // dump tables
    auto [tableNamesNew, recordsNew] = dbTableRecords(sqlDb);

    // check the same tables exist in both cases
    QCOMPARE(tableNamesConversion, tableNamesNew);

    Q_ASSERT(tableNamesConversion.size() == recordsConversion.size());
    Q_ASSERT(tableNamesNew.size() == recordsNew.size());

    // check records of each table
    for (const auto &[tableName, recordC, recordN] : zip(tableNamesConversion, recordsConversion, recordsNew)) {
        auto fieldNamesC = fieldNames(recordC);
        auto fieldNamesN = fieldNames(recordN);

        bool orderMatches = (fieldNamesC == fieldNamesN);

        // compare without order
        std::sort(fieldNamesC.begin(), fieldNamesC.end());
        std::sort(fieldNamesN.begin(), fieldNamesN.end());
        QCOMPARE(fieldNamesC.join(u", "), fieldNamesN.join(u", "));

        // print warning if order does not match
        if (!orderMatches) {
            qWarning() << "Order of fields of" << tableName << "does not match between conversion/new variant.";
            qWarning() << "  " << fieldNames(recordC);
            qWarning() << "  " << fieldNames(recordN);
        }

        // check optional/required property of each field
        for (const auto &fieldName : fieldNamesC) {
            auto fieldC = recordC.field(recordC.indexOf(fieldName));
            auto fieldN = recordN.field(recordN.indexOf(fieldName));

            // check 'NOT NULL'
            if (fieldC.requiredStatus() != fieldN.requiredStatus()) {
                qDebug() << tableName << fieldName << "has wrong required status (NOT NULL)!";
                qDebug() << "  Conversion variant is:" << fieldC.requiredStatus();
                qDebug() << "  New variant is:" << fieldN.requiredStatus();
                QFAIL("Field required status of conversion/new variant does not match.");
            }

            // check data type
            if (fieldC.metaType() != fieldN.metaType()) {
                qDebug() << tableName << fieldName << "data type mismatch!";
                qDebug() << "  Conversion variant:" << fieldC.metaType();
                qDebug() << "  New variant is:" << fieldN.metaType();
                QFAIL("Field data type of conversion/new variant does not match.");
            }
        }
    }
}

QTEST_GUILESS_MAIN(DatabaseTest)
#include "DatabaseTest.moc"