mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-10-18 03:54:14 +02:00
Merge pull request #1504 from ispyisail/feat/qetz-recover
Add recovering what can be read of a damaged .qetz project (--recover)
This commit is contained in:
@@ -797,6 +797,119 @@ private slots:
|
||||
QString error;
|
||||
QVERIFY(!QetContainer::join({{QStringLiteral("mimetype"), "application/zip", false}}, &back, &error));
|
||||
}
|
||||
|
||||
// recover() reads what it can of a damaged .qetz: each kind of damage
|
||||
// costs what it held and nothing else, and is said
|
||||
void recoverLeavesOutOnlyTheDamage_data()
|
||||
{
|
||||
QTest::addColumn<QString>("damage");
|
||||
QTest::addColumn<QString>("said");
|
||||
QTest::addColumn<int>("folios");
|
||||
QTest::addColumn<int>("wires");
|
||||
QTest::newRow("nothing") << QString() << QString() << 0 << 0;
|
||||
QTest::newRow("folio file missing") << QStringLiteral("folio") << QStringLiteral("is missing") << -1 << 0;
|
||||
QTest::newRow("wire row deleted") << QStringLiteral("row") << QStringLiteral("not in the database") << 0 << -1;
|
||||
QTest::newRow("database page overwritten") << QStringLiteral("page") << QStringLiteral("cannot be read") << 0 << -1000;
|
||||
}
|
||||
void recoverLeavesOutOnlyTheDamage()
|
||||
{
|
||||
QFETCH(QString, damage);
|
||||
QFETCH(QString, said);
|
||||
QFETCH(int, folios);
|
||||
QFETCH(int, wires);
|
||||
QDomDocument original;
|
||||
QList<QetZip::Entry> entries = splitFile(QStringLiteral(QET_EXAMPLES_DIR "/industrial.qet"), &original);
|
||||
QVERIFY(!entries.isEmpty());
|
||||
auto count = [](const QDomDocument &d, const QString &tag) {
|
||||
return int(d.documentElement().elementsByTagName(tag).size());
|
||||
};
|
||||
const int folios_before = count(original, QStringLiteral("diagram"));
|
||||
const int wires_before = count(original, QStringLiteral("conductor"));
|
||||
if (damage == QLatin1String("folio")) {
|
||||
for (int i = 0 ; i < entries.size() ; ++i)
|
||||
if (entries.at(i).name.startsWith(QStringLiteral("folios/"))) { entries.removeAt(i); break; }
|
||||
} else if (damage == QLatin1String("row")) {
|
||||
alterDatabase(entries, "DELETE FROM conductor WHERE rowid = (SELECT min(rowid) FROM conductor)");
|
||||
} else if (damage == QLatin1String("page")) {
|
||||
for (QetZip::Entry &entry : entries) {
|
||||
if (entry.name != QLatin1String("project.sqlite")) continue;
|
||||
const int page_size = qFromBigEndian<quint16>(entry.data.constData() + 16);
|
||||
const int page = int(entry.data.size() / page_size / 2);
|
||||
entry.data.replace(page * page_size, page_size, QByteArray(page_size, char(0xff)));
|
||||
}
|
||||
}
|
||||
QByteArray zip;
|
||||
QString error;
|
||||
QVERIFY2(QetZip::toBytes(entries, &error).size() > 0, qPrintable(error));
|
||||
zip = QetZip::toBytes(entries, &error);
|
||||
|
||||
QDomDocument back;
|
||||
QStringList lost;
|
||||
QVERIFY2(QetContainer::recover(zip, &back, &lost, &error), qPrintable(error));
|
||||
if (said.isEmpty()) {
|
||||
QVERIFY2(lost.isEmpty(), qPrintable(lost.join(QLatin1Char('\n'))));
|
||||
} else {
|
||||
QVERIFY2(lost.join(QLatin1Char('\n')).contains(said), qPrintable(lost.join(QLatin1Char('\n'))));
|
||||
// Strict reading refuses it
|
||||
QDomDocument strict;
|
||||
QVERIFY(!QetContainer::join(entries, &strict));
|
||||
}
|
||||
QCOMPARE(count(back, QStringLiteral("diagram")), folios_before + folios);
|
||||
if (wires == -1000)
|
||||
QCOMPARE(count(back, QStringLiteral("conductor")), 0);
|
||||
else
|
||||
QCOMPARE(count(back, QStringLiteral("conductor")), wires_before + wires);
|
||||
// Nothing of the container's own left in the document
|
||||
QVERIFY(!back.toString().contains(QStringLiteral("qetz-")));
|
||||
}
|
||||
|
||||
// A picture's file missing (F118 wrote such projects): the picture is
|
||||
// left out, the rest read
|
||||
void recoverMissingPicture()
|
||||
{
|
||||
QList<QetZip::Entry> entries;
|
||||
QString error;
|
||||
QVERIFY2(QetZip::fromBytes(read(QStringLiteral(QET_FIXTURES_DIR "/qetz_format2.qetz")), &entries, &error),
|
||||
qPrintable(error));
|
||||
QDomDocument document;
|
||||
QVERIFY2(QetContainer::join(entries, &document, &error), qPrintable(error));
|
||||
// A picture on the first folio, then saved and its file dropped
|
||||
QDomElement folio = document.documentElement().firstChildElement(QStringLiteral("diagram"));
|
||||
QDomElement images = folio.firstChildElement(QStringLiteral("images"));
|
||||
if (images.isNull()) images = folio.appendChild(document.createElement(QStringLiteral("images"))).toElement();
|
||||
QDomElement image = document.createElement(QStringLiteral("image"));
|
||||
image.setAttribute(QStringLiteral("type"), QStringLiteral("png"));
|
||||
image.appendChild(document.createTextNode(QStringLiteral(
|
||||
"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg==")));
|
||||
images.appendChild(image);
|
||||
QList<QetZip::Entry> saved = QetContainer::split(document, QString(), &error);
|
||||
QVERIFY2(!saved.isEmpty(), qPrintable(error));
|
||||
bool dropped = false;
|
||||
for (int i = 0 ; i < saved.size() ; ++i)
|
||||
if (saved.at(i).name.startsWith(QStringLiteral("images/"))) { saved.removeAt(i); dropped = true; break; }
|
||||
QVERIFY(dropped);
|
||||
QDomDocument strict;
|
||||
QVERIFY(!QetContainer::join(saved, &strict, &error));
|
||||
QVERIFY(error.contains(QStringLiteral("picture")));
|
||||
|
||||
QDomDocument back;
|
||||
QStringList lost;
|
||||
QVERIFY2(QetContainer::recover(QetZip::toBytes(saved), &back, &lost, &error), qPrintable(error));
|
||||
QCOMPARE(lost.size(), 1);
|
||||
QVERIFY(lost.first().contains(QStringLiteral("picture")));
|
||||
QCOMPARE(int(back.documentElement().elementsByTagName(QStringLiteral("image")).size()), 0);
|
||||
QVERIFY(back.toString().contains(QStringLiteral("<elementInformation ")));
|
||||
}
|
||||
|
||||
// What cannot be read as a zip at all is still refused
|
||||
void recoverNotAZipRefused()
|
||||
{
|
||||
QDomDocument back;
|
||||
QStringList lost;
|
||||
QString error;
|
||||
QVERIFY(!QetContainer::recover(QByteArray("not a zip").repeated(10), &back, &lost, &error));
|
||||
QVERIFY(!error.isEmpty());
|
||||
}
|
||||
};
|
||||
|
||||
QTEST_APPLESS_MAIN(tst_qetcontainer)
|
||||
|
||||
Reference in New Issue
Block a user