mirror of
https://invent.kde.org/graphics/okular
synced 2024-10-02 14:14:10 +00:00
80afe26873
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
180 lines
6.5 KiB
C++
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"
|