// SPDX-License-Identifier: GPL-2.0-or-later #include #include #include #include #include #include #include // Saving a project that was just saved must change nothing. Two things // made the second save differ from the first, both cleanup done on save // but not on load: // - symbol information whose values were all empty was written as an // empty block, which the next load read as no // information and the next save dropped (Projet_vierge.qet); // - information values were trimmed on save but not on load, so a label // with stray spaces kept them in its displayed copy until the project // was opened again (m_000.qet). // Runs the real binary's --resave twice on every example, and on a // project whose title block holds a value that is a single space (#973). class tst_resaveunchanged : public QObject { Q_OBJECT QTemporaryDir m_dir; int m_run = 0; // --resave @p in to a new file, in a sandbox of its own (so a running // QElectroTech cannot answer instead); returns the new file's path. QString resave(const QString &in) { const QString out = m_dir.filePath(QStringLiteral("out%1.qet").arg(m_run)); const QString home = m_dir.filePath(QStringLiteral("home%1").arg(m_run++)); QDir().mkpath(home); QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); env.insert(QStringLiteral("QT_QPA_PLATFORM"), QStringLiteral("offscreen")); env.insert(QStringLiteral("HOME"), home); env.insert(QStringLiteral("XDG_CONFIG_HOME"), home + QStringLiteral("/config")); env.insert(QStringLiteral("XDG_DATA_HOME"), home + QStringLiteral("/data")); QProcess proc; proc.setProcessEnvironment(env); proc.start(QStringLiteral(QET_TEST_BINARY_PATH), {QStringLiteral("--resave"), in, out}); if (!proc.waitForFinished(120000) || proc.exitCode() != 0) return {}; return out; } static QByteArray read(const QString &path) { QFile f(path); return f.open(QIODevice::ReadOnly) ? f.readAll() : QByteArray(); } private slots: void initTestCase() { QVERIFY(m_dir.isValid()); QVERIFY(QFile::exists(QStringLiteral(QET_TEST_BINARY_PATH))); } // Projet_vierge.qet has empty information values, m_000.qet values // with stray spaces; every other example is here so a new cause shows. void secondSaveChangesNothing_data() { QTest::addColumn("project"); const QDir examples(QStringLiteral(QET_EXAMPLES_DIR)); const QStringList projects = examples.entryList({QStringLiteral("*.qet")}, QDir::Files, QDir::Name); QVERIFY(!projects.isEmpty()); for (const QString &project : projects) QTest::newRow(project.toUtf8().constData()) << examples.filePath(project); } void secondSaveChangesNothing() { QFETCH(QString, project); const QString first = resave(project); QVERIFY2(!first.isEmpty(), "first --resave failed"); const QString second = resave(first); QVERIFY2(!second.isEmpty(), "second --resave failed"); const QByteArray a = read(first), b = read(second); QVERIFY(!a.isEmpty()); QVERIFY2(a == b, "the second save changed the file"); } // A title-block value that is a single space is kept through two saves // (#973), and a value with accents comes back as it went in. void singleSpaceValueKept() { QByteArray xml = read(QStringLiteral(QET_EXAMPLES_DIR "/Projet_vierge.qet")); QVERIFY(xml.contains("")); xml.replace("", "" " " "Armoire façade été"); const QString in = m_dir.filePath(QStringLiteral("space.qet")); QFile f(in); QVERIFY(f.open(QIODevice::WriteOnly)); f.write(xml); f.close(); const QString first = resave(in); QVERIFY2(!first.isEmpty(), "first --resave failed"); const QString second = resave(first); QVERIFY2(!second.isEmpty(), "second --resave failed"); const QByteArray a = read(first), b = read(second); QVERIFY2(a == b, "the second save changed the file"); const QString saved = QString::fromUtf8(b); QVERIFY2(saved.contains(QRegularExpression( QStringLiteral("]*name=\"space\"[^>]*> "))), "the single-space value was lost"); QVERIFY2(saved.contains(QRegularExpression( QStringLiteral("]*name=\"accents\"[^>]*>Armoire façade été"))), "the accented value changed"); } }; QTEST_APPLESS_MAIN(tst_resaveunchanged) #include "tst_resaveunchanged.moc"