File indexing completed on 2024-05-12 05:55:45

0001 /*
0002     This file is part of the Okteta Kasten module, made within the KDE community.
0003 
0004     SPDX-FileCopyrightText: 2019 Friedrich W. H. Kossebau <kossebau@kde.org>
0005 
0006     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0007 */
0008 
0009 #include "replacejobtest.hpp"
0010 
0011 // test object
0012 #include "../view/replace/replacejob.hpp"
0013 #include "../view/replace/replaceuserqueryable.hpp"
0014 // Okteta Kasten gui
0015 #include <Kasten/Okteta/ByteArrayView>
0016 // Okteta Kasten core
0017 #include <Kasten/Okteta/ByteArrayDocument>
0018 // Okteta Core
0019 #include <Okteta/PieceTableByteArrayModel>
0020 // Qt
0021 #include <QTest>
0022 #include <QSignalSpy>
0023 
0024 
0025 Q_DECLARE_METATYPE(QVector<Kasten::ReplaceBehaviour>)
0026 
0027 class TestReplaceUserQueryAgent : public QObject
0028                                 , public Kasten::If::ReplaceUserQueryable
0029 {
0030     Q_OBJECT
0031     Q_INTERFACES(
0032         Kasten::If::ReplaceUserQueryable
0033     )
0034 
0035 public:
0036     explicit TestReplaceUserQueryAgent(const QVector<Kasten::ReplaceBehaviour>& replies)
0037         : m_replies(replies)
0038     {}
0039 
0040 public:
0041     int noOfReplacements() const { return m_noOfReplacements; }
0042 
0043 public: // If::ReplaceUserQueryable API
0044     void queryContinue(Kasten::FindDirection direction, int noOfReplacements) override;
0045     void queryReplaceCurrent() override;
0046 
0047 Q_SIGNALS: // If::ReplaceUserQueryable API
0048     void queryContinueFinished(bool result) override;
0049     void queryReplaceCurrentFinished(Kasten::ReplaceBehaviour result) override;
0050 
0051 private:
0052     QVector<Kasten::ReplaceBehaviour> m_replies;
0053     int m_noOfReplacements = 0;
0054 };
0055 
0056 void TestReplaceUserQueryAgent::queryContinue(Kasten::FindDirection direction, int noOfReplacements)
0057 {
0058     Q_UNUSED(direction);
0059     m_noOfReplacements = noOfReplacements;
0060     Q_EMIT queryContinueFinished(true);
0061 }
0062 
0063 void TestReplaceUserQueryAgent::queryReplaceCurrent()
0064 {
0065     Q_ASSERT(!m_replies.isEmpty());
0066     Q_EMIT queryReplaceCurrentFinished(m_replies.takeFirst());
0067 }
0068 
0069 
0070 void ReplaceJobTest::compare(const Okteta::PieceTableByteArrayModel* byteArrayModel,
0071                              const QByteArray& expectedData)
0072 {
0073     QByteArray actualData(byteArrayModel->size(), 'd');
0074     byteArrayModel->copyTo(reinterpret_cast<Okteta::Byte*>(actualData.data()), 0, byteArrayModel->size());
0075 
0076     QCOMPARE(actualData, expectedData);
0077 }
0078 
0079 template<int N> QByteArray byteArrayFromLiteral(const char (&data)[N])
0080 {
0081    return QByteArray::fromRawData(data, N-1);
0082 }
0083 
0084 void ReplaceJobTest::init()
0085 {
0086     qRegisterMetaType<Okteta::AddressRange>("Okteta::AddressRange");
0087 }
0088 
0089 void ReplaceJobTest::testReplace_data()
0090 {
0091     QTest::addColumn<QByteArray>("originalData");
0092     QTest::addColumn<QByteArray>("searchData");
0093     QTest::addColumn<QByteArray>("replaceData");
0094     QTest::addColumn<QByteArray>("expectedData");
0095     QTest::addColumn<int>("expectedReplacementCount");
0096     QTest::addColumn<Okteta::Address>("startIndex");
0097     QTest::addColumn<bool>("backwards");
0098     QTest::addColumn<QVector<Kasten::ReplaceBehaviour>>("replies");
0099 
0100     const struct {
0101         QString name;
0102         QByteArray originalData;
0103         QByteArray expectedData;
0104         int expectedReplacementCount;
0105         QByteArray searchData;
0106         QByteArray replaceData;
0107     }
0108     testData[] = {{
0109         QStringLiteral("full-1-1"),
0110         byteArrayFromLiteral("11111111"),
0111         byteArrayFromLiteral("22222222"),
0112         8,
0113         byteArrayFromLiteral("1"),
0114         byteArrayFromLiteral("2")
0115     }, {
0116         QStringLiteral("full-1-2"),
0117         byteArrayFromLiteral("11111111"),
0118         byteArrayFromLiteral("2323232323232323"),
0119         8,
0120         byteArrayFromLiteral("1"),
0121         byteArrayFromLiteral("23"),
0122     }, {
0123         QStringLiteral("full-2-1"),
0124         byteArrayFromLiteral("1313131313131313"),
0125         byteArrayFromLiteral("22222222"),
0126         8,
0127         byteArrayFromLiteral("13"),
0128         byteArrayFromLiteral("2")
0129     }, {
0130         QStringLiteral("partial-1-1"),
0131         byteArrayFromLiteral("01001000"),
0132         byteArrayFromLiteral("02002000"),
0133         2,
0134         byteArrayFromLiteral("1"),
0135         byteArrayFromLiteral("2")
0136     }, {
0137         QStringLiteral("partial-1-2"),
0138         byteArrayFromLiteral("01001000"),
0139         byteArrayFromLiteral("0230023000"),
0140         2,
0141         byteArrayFromLiteral("1"),
0142         byteArrayFromLiteral("23"),
0143     }, {
0144         QStringLiteral("partial-2-1"),
0145         byteArrayFromLiteral("0130013000"),
0146         byteArrayFromLiteral("02002000"),
0147         2,
0148         byteArrayFromLiteral("13"),
0149         byteArrayFromLiteral("2")
0150     }};
0151 
0152     for (const auto& data : testData) {
0153         QTest::newRow(QString(data.name+QLatin1String("-forward-frombegin")).toLatin1().constData())
0154             << data.originalData << data.searchData
0155             << data.replaceData << data.expectedData << data.expectedReplacementCount
0156             << Okteta::Address(0) << false << QVector<Kasten::ReplaceBehaviour>();
0157         QTest::newRow(QString(data.name+QLatin1String("-backward-fromend")).toLatin1().constData())
0158             << data.originalData << data.searchData
0159             << data.replaceData << data.expectedData << data.expectedReplacementCount
0160             << Okteta::Address(data.originalData.length()) << true << QVector<Kasten::ReplaceBehaviour>();
0161         QTest::newRow(QString(data.name+QLatin1String("-forward-frommiddle")).toLatin1().constData())
0162             << data.originalData << data.searchData
0163             << data.replaceData << data.expectedData << data.expectedReplacementCount
0164             << Okteta::Address(4) << false << QVector<Kasten::ReplaceBehaviour>();
0165         QTest::newRow(QString(data.name+QLatin1String("-backward-frommiddle")).toLatin1().constData())
0166             << data.originalData << data.searchData
0167             << data.replaceData << data.expectedData << data.expectedReplacementCount
0168             << Okteta::Address(3) << true << QVector<Kasten::ReplaceBehaviour>();
0169     }
0170 
0171     {
0172         const QByteArray originalData = byteArrayFromLiteral("11111111");
0173         const QByteArray expectedData = byteArrayFromLiteral("22222222");
0174         const int expectedReplacementCount = 8;
0175         const QByteArray searchData = byteArrayFromLiteral("1");
0176         const QByteArray replaceData = byteArrayFromLiteral("2");
0177 
0178         QTest::newRow("replies-forward-replaceall")
0179             << originalData << searchData
0180             << replaceData << expectedData << expectedReplacementCount
0181             << Okteta::Address(0) << false
0182             << QVector<Kasten::ReplaceBehaviour>{ Kasten::ReplaceAll };
0183 
0184         QTest::newRow("replies-forward-replace8x")
0185             << originalData << searchData
0186             << replaceData << expectedData << expectedReplacementCount
0187             << Okteta::Address(0) << false
0188             << QVector<Kasten::ReplaceBehaviour>(8, Kasten::ReplaceCurrent);
0189 
0190         QTest::newRow("replies-forward-replace3xreplaceall")
0191             << originalData << searchData
0192             << replaceData << expectedData << expectedReplacementCount
0193             << Okteta::Address(0) << false
0194             << QVector<Kasten::ReplaceBehaviour>{Kasten::ReplaceCurrent, Kasten::ReplaceCurrent, Kasten::ReplaceCurrent, Kasten::ReplaceAll };
0195     }
0196 
0197     {
0198         QTest::newRow("replies-forward-replaceskipalternate")
0199             << byteArrayFromLiteral("11111111") << byteArrayFromLiteral("1")
0200             << byteArrayFromLiteral("2") << byteArrayFromLiteral("12121212") << 4
0201             << Okteta::Address(0) << false
0202             << QVector<Kasten::ReplaceBehaviour>{ Kasten::SkipCurrent, Kasten::ReplaceCurrent,
0203                 Kasten::SkipCurrent, Kasten::ReplaceCurrent, Kasten::SkipCurrent, Kasten::ReplaceCurrent,
0204                 Kasten::SkipCurrent, Kasten::ReplaceCurrent };
0205     }
0206 
0207     {
0208         const QByteArray originalData = byteArrayFromLiteral("11111111");
0209         const QByteArray expectedData = byteArrayFromLiteral("11111111");
0210         const int expectedReplacementCount = 0;
0211         const QByteArray searchData = byteArrayFromLiteral("1");
0212         const QByteArray replaceData = byteArrayFromLiteral("2");
0213 
0214         QTest::newRow("replies-forward-cancel")
0215             << originalData << searchData
0216             << replaceData << expectedData << expectedReplacementCount
0217             << Okteta::Address(0) << false
0218             << QVector<Kasten::ReplaceBehaviour>{ Kasten::CancelReplacing };
0219 
0220         QTest::newRow("replies-forward-skip8x")
0221             << originalData << searchData
0222             << replaceData << expectedData << expectedReplacementCount
0223             << Okteta::Address(0) << false
0224             << QVector<Kasten::ReplaceBehaviour>(8, Kasten::SkipCurrent);
0225 
0226         QTest::newRow("replies-forward-skip3xcancel")
0227             << originalData << searchData
0228             << replaceData << expectedData << expectedReplacementCount
0229             << Okteta::Address(0) << false
0230             << QVector<Kasten::ReplaceBehaviour>{Kasten::SkipCurrent, Kasten::SkipCurrent, Kasten::SkipCurrent, Kasten::CancelReplacing };
0231     }
0232 }
0233 
0234 void ReplaceJobTest::testReplace()
0235 {
0236     QFETCH(Okteta::Address, startIndex);
0237     QFETCH(bool, backwards);
0238     QFETCH(QByteArray, originalData);
0239     QFETCH(QByteArray, searchData);
0240     QFETCH(QByteArray, replaceData);
0241     QFETCH(QByteArray, expectedData);
0242     QFETCH(int, expectedReplacementCount);
0243     QFETCH(QVector<Kasten::ReplaceBehaviour>, replies);
0244 
0245     TestReplaceUserQueryAgent* queryAgent = replies.isEmpty() ? nullptr : new TestReplaceUserQueryAgent(replies);
0246 
0247     auto* byteArray = new Okteta::PieceTableByteArrayModel(originalData);
0248     auto* document = new Kasten::ByteArrayDocument(byteArray, QStringLiteral("init"));
0249     auto* view = new Kasten::ByteArrayView(document, nullptr);
0250 
0251     Okteta::Address  replaceFirstIndex;
0252     Okteta::Address  replaceLastIndex;
0253     if (!backwards && startIndex > 0) {
0254         replaceFirstIndex = startIndex;
0255         replaceLastIndex =  startIndex - 1;
0256     } else if (backwards && startIndex < byteArray->size())  {
0257         replaceFirstIndex = startIndex + 1;
0258         replaceLastIndex =  startIndex;
0259     } else {
0260         replaceFirstIndex = 0;
0261         replaceLastIndex =  byteArray->size() - 1;
0262     }
0263 
0264     auto* job = new Kasten::ReplaceJob(view, byteArray, queryAgent);
0265     job->setSearchData(searchData);
0266     job->setReplaceData(replaceData);
0267     job->setRange(replaceFirstIndex, replaceLastIndex,
0268                   backwards ? Kasten::FindBackward : Kasten::FindForward);
0269     job->setDoPrompt(queryAgent != nullptr);
0270 
0271     QSignalSpy finishedSpy(job, &Kasten::ReplaceJob::finished);
0272 
0273     job->start();
0274     if (finishedSpy.size() == 0) {
0275         QVERIFY(finishedSpy.wait());
0276     }
0277 
0278     QCOMPARE(finishedSpy.size(), 1);
0279 
0280     compare(byteArray, expectedData);
0281 
0282     const int beforeWrap = queryAgent ? queryAgent->noOfReplacements() : 0;
0283     const QList<QVariant> arguments = finishedSpy.takeFirst();
0284     QCOMPARE(arguments.at(0).toBool(), true);
0285     QCOMPARE(arguments.at(1).toInt() + beforeWrap, expectedReplacementCount);
0286 
0287     delete job;
0288     delete view;
0289     delete document;
0290 
0291     delete queryAgent;
0292 }
0293 
0294 QTEST_MAIN(ReplaceJobTest)
0295 
0296 #include "replacejobtest.moc"
0297 #include "moc_replacejobtest.cpp"