okular/autotests/documenttest.cpp
Nicolas Fella 80afe26873 Implement event.change
This represents the newly entered data for each keystroke. This is often a single added character, but for cases like pasting text it can be more complex.

The PDF API reference doesn't specify any algorithm to use.

The algorithm used here works by iterating through both strings from the start until the first different character is encountered. Then the rest of the new text is considered the difference.

This doesn't produce the theoretically optimal/minimal diff, but seems to work well enough for practical application.

When text is removed the diff is empty
2022-09-13 21:51:15 +00:00

180 lines
6.5 KiB
C++

/*
SPDX-FileCopyrightText: 2013 Fabio D 'Urso <fabiodurso@hotmail.it>
Work sponsored by the LiMux project of the city of Munich:
SPDX-FileCopyrightText: 2017 Klarälvdalens Datakonsult AB a KDAB Group company <info@kdab.com>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include <QMimeDatabase>
#include <QTemporaryFile>
#include <QTest>
#include <threadweaver/queue.h>
#include "../core/annotations.h"
#include "../core/document.h"
#include "../core/document_p.h"
#include "../core/generator.h"
#include "../core/observer.h"
#include "../core/page.h"
#include "../core/rotationjob_p.h"
#include "../settings_core.h"
class DocumentTest : public QObject
{
Q_OBJECT
private Q_SLOTS:
void testCloseDuringRotationJob();
void testDocdataMigration();
void testDiff_data();
void testDiff();
};
// Test that we don't crash if the document is closed while a RotationJob
// is enqueued/running
void DocumentTest::testCloseDuringRotationJob()
{
Okular::SettingsCore::instance(QStringLiteral("documenttest"));
Okular::Document *m_document = new Okular::Document(nullptr);
const QString testFile = QStringLiteral(KDESRCDIR "data/file1.pdf");
QMimeDatabase db;
const QMimeType mime = db.mimeTypeForFile(testFile);
Okular::DocumentObserver *dummyDocumentObserver = new Okular::DocumentObserver();
m_document->addObserver(dummyDocumentObserver);
m_document->openDocument(testFile, QUrl(), mime);
m_document->setRotation(1);
// Tell ThreadWeaver not to start any new job
ThreadWeaver::Queue::instance()->suspend();
// Request a pixmap. A RotationJob will be enqueued but not started
Okular::PixmapRequest *pixmapReq = new Okular::PixmapRequest(dummyDocumentObserver, 0, 100, 100, qApp->devicePixelRatio(), 1, Okular::PixmapRequest::NoFeature);
m_document->requestPixmaps({pixmapReq});
// Delete the document
delete m_document;
// Resume job processing and wait for the RotationJob to finish
ThreadWeaver::Queue::instance()->resume();
ThreadWeaver::Queue::instance()->finish();
qApp->processEvents();
delete dummyDocumentObserver;
}
// Test that, if there's a XML file in docdata referring to a document, we
// detect that it must be migrated, that it doesn't get wiped out if you close
// the document without migrating and that it does get wiped out after migrating
void DocumentTest::testDocdataMigration()
{
Okular::SettingsCore::instance(QStringLiteral("documenttest"));
const QUrl testFileUrl = QUrl::fromLocalFile(QStringLiteral(KDESRCDIR "data/file1.pdf"));
const QString testFilePath = testFileUrl.toLocalFile();
const qint64 testFileSize = QFileInfo(testFilePath).size();
// Copy XML file to the docdata/ directory
const QString docDataPath = Okular::DocumentPrivate::docDataFileName(testFileUrl, testFileSize);
QFile::remove(docDataPath);
QVERIFY(QFile::copy(QStringLiteral(KDESRCDIR "data/file1-docdata.xml"), docDataPath));
// Open our document
Okular::Document *m_document = new Okular::Document(nullptr);
QMimeDatabase db;
const QMimeType mime = db.mimeTypeForFile(testFilePath);
QCOMPARE(m_document->openDocument(testFilePath, testFileUrl, mime), Okular::Document::OpenSuccess);
// Check that the annotation from file1-docdata.xml was loaded
QCOMPARE(m_document->page(0)->annotations().size(), 1);
QCOMPARE(m_document->page(0)->annotations().first()->uniqueName(), QStringLiteral("testannot"));
// Check that we detect that it must be migrated
QVERIFY(m_document->isDocdataMigrationNeeded());
m_document->closeDocument();
// Reopen the document and check that the annotation is still present
// (because we have not migrated)
QCOMPARE(m_document->openDocument(testFilePath, testFileUrl, mime), Okular::Document::OpenSuccess);
QCOMPARE(m_document->page(0)->annotations().size(), 1);
QCOMPARE(m_document->page(0)->annotations().first()->uniqueName(), QStringLiteral("testannot"));
QVERIFY(m_document->isDocdataMigrationNeeded());
// Do the migration
QTemporaryFile migratedSaveFile(QStringLiteral("%1/okrXXXXXX.pdf").arg(QDir::tempPath()));
QVERIFY(migratedSaveFile.open());
migratedSaveFile.close();
QVERIFY(m_document->saveChanges(migratedSaveFile.fileName()));
m_document->docdataMigrationDone();
QVERIFY(!m_document->isDocdataMigrationNeeded());
m_document->closeDocument();
// Now the docdata file should have no annotations, let's check
QCOMPARE(m_document->openDocument(testFilePath, testFileUrl, mime), Okular::Document::OpenSuccess);
QCOMPARE(m_document->page(0)->annotations().size(), 0);
QVERIFY(!m_document->isDocdataMigrationNeeded());
m_document->closeDocument();
// And the new file should have 1 annotation, let's check
QCOMPARE(m_document->openDocument(migratedSaveFile.fileName(), QUrl::fromLocalFile(migratedSaveFile.fileName()), mime), Okular::Document::OpenSuccess);
QCOMPARE(m_document->page(0)->annotations().size(), 1);
QVERIFY(!m_document->isDocdataMigrationNeeded());
m_document->closeDocument();
delete m_document;
}
void DocumentTest::testDiff_data()
{
QTest::addColumn<QString>("oldVal");
QTest::addColumn<QString>("newVal");
QTest::addColumn<QString>("expectedDiff");
QTest::addRow("empty") << ""
<< ""
<< "";
QTest::addRow("a") << ""
<< "a"
<< "a";
QTest::addRow("ab") << "a"
<< "b"
<< "b";
QTest::addRow("ab2") << "a"
<< "ab"
<< "b";
QTest::addRow("kaesekuchen") << "Käse"
<< "Käsekuchen"
<< "kuchen";
QTest::addRow("replace") << "kuchen"
<< "wurst"
<< "wurst";
QTest::addRow("okular") << "Oku"
<< "Okular"
<< "lar";
QTest::addRow("removal1") << "a"
<< ""
<< "";
QTest::addRow("removal2") << "ab"
<< "a"
<< "";
QTest::addRow("unicode") << "☮🤌"
<< "☮🤌❤️"
<< "❤️";
}
void DocumentTest::testDiff()
{
QFETCH(QString, oldVal);
QFETCH(QString, newVal);
QFETCH(QString, expectedDiff);
QCOMPARE(Okular::DocumentPrivate::diff(oldVal, newVal), expectedDiff);
}
QTEST_MAIN(DocumentTest)
#include "documenttest.moc"