From 6b83fdf7b332c6db8c7c1e3b899d543c09b3a63b Mon Sep 17 00:00:00 2001 From: Beat Hangartner Date: Wed, 7 Oct 2026 21:03:12 +0200 Subject: [PATCH] Read a folio's freeze flags back as the words they are saved as Diagram::toXml() writes freezeNewElement and freezeNewConductor as "true"/"false", but Diagram::fromXml() read them with toInt(), which is 0 for both words. So "freeze new elements" and "freeze new conductors" were off again on every folio after a project was saved and reopened, since the day the flags were added. Compare the attribute with "true" instead. The project-level flags in QETProject already do this. No file-format change: the attributes are written exactly as before, and a file without them still loads with both flags off. Tests: tst_foliofreezeflags runs the binary's --resave on a fixture with one folio per combination (both, elements only, none, attributes missing) and reads the saved attributes back. The two frozen folios fail on master. Co-Authored-By: Claude Fable 5.1 Signed-off-by: Beat Hangartner --- sources/diagram.cpp | 8 +- tests/qttest/CMakeLists.txt | 12 +++ tests/qttest/fixtures/folio_freeze_flags.qet | 36 +++++++ tests/qttest/tst_foliofreezeflags.cpp | 103 +++++++++++++++++++ 4 files changed, 157 insertions(+), 2 deletions(-) create mode 100644 tests/qttest/fixtures/folio_freeze_flags.qet create mode 100644 tests/qttest/tst_foliofreezeflags.cpp diff --git a/sources/diagram.cpp b/sources/diagram.cpp index f257729c0..978614106 100644 --- a/sources/diagram.cpp +++ b/sources/diagram.cpp @@ -1614,10 +1614,14 @@ bool Diagram::fromXml(QDomElement &document, m_conductors_autonum_name = root.attribute(QStringLiteral("conductorAutonum")); // Load Freeze New Element - m_freeze_new_elements = root.attribute(QStringLiteral("freezeNewElement")).toInt(); + // Written as "true"/"false" by toXml(), so compare the text: + // toInt() of either word is 0. + m_freeze_new_elements = root.attribute(QStringLiteral("freezeNewElement")) + == QLatin1String("true"); // Load Freeze New Conductor - m_freeze_new_conductors_ = root.attribute(QStringLiteral("freezeNewConductor")).toInt(); + m_freeze_new_conductors_ = root.attribute(QStringLiteral("freezeNewConductor")) + == QLatin1String("true"); //Load Element Folio Sequential folioSequentialsFromXml(root, diff --git a/tests/qttest/CMakeLists.txt b/tests/qttest/CMakeLists.txt index bd8a82c01..d20eb3711 100644 --- a/tests/qttest/CMakeLists.txt +++ b/tests/qttest/CMakeLists.txt @@ -908,6 +908,18 @@ target_compile_definitions(tst_resaveunchanged PRIVATE "QET_TEST_BINARY_PATH=\"$\"" "QET_EXAMPLES_DIR=\"${QET_DIR}/examples\"") +# A folio's "freeze new elements/conductors" flags, saved as the words +# "true"/"false", are read back as words: the real binary's --resave on +# fixtures/folio_freeze_flags.qet, one folio per combination. +add_executable( + tst_foliofreezeflags + tst_foliofreezeflags.cpp) +add_test(NAME tst_foliofreezeflags COMMAND tst_foliofreezeflags) +add_dependencies(tst_foliofreezeflags qelectrotech) +target_link_libraries(tst_foliofreezeflags PRIVATE Qt::Test Qt::Xml) +target_compile_definitions(tst_foliofreezeflags PRIVATE + "QET_TEST_BINARY_PATH=\"$\"") + # Replacing a symbol's definition in a project keeps its terminal uuids, so # the wires saved against them still load: TerminalUuids::keep() on its own, # then the real binary's --info on an example whose symbols were replaced. diff --git a/tests/qttest/fixtures/folio_freeze_flags.qet b/tests/qttest/fixtures/folio_freeze_flags.qet new file mode 100644 index 000000000..a2e3c6661 --- /dev/null +++ b/tests/qttest/fixtures/folio_freeze_flags.qet @@ -0,0 +1,36 @@ + + + folio_freeze_flags + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Imported elements + + + + diff --git a/tests/qttest/tst_foliofreezeflags.cpp b/tests/qttest/tst_foliofreezeflags.cpp new file mode 100644 index 000000000..6824215a8 --- /dev/null +++ b/tests/qttest/tst_foliofreezeflags.cpp @@ -0,0 +1,103 @@ +/* + Copyright 2006-2026 The QElectroTech Team + This file is part of QElectroTech. + + QElectroTech is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + QElectroTech is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with QElectroTech. If not, see . +*/ +#include +#include +#include +#include + +/** + A folio's "freeze new elements" and "freeze new conductors" flags are + saved as freezeNewElement="true" and freezeNewConductor="true" on its + . Loading must read the words back: the flags used to be read + with toInt(), which is 0 for "true" as well as for "false", so both were + off again after every reload. Runs the real binary's --resave on a + project with one folio per combination and reads the saved attributes. +*/ +class tst_foliofreezeflags : public QObject +{ + Q_OBJECT + + QTemporaryDir m_dir; + + static bool runQet(const QStringList &arguments) + { + QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); + env.insert(QStringLiteral("QT_QPA_PLATFORM"), QStringLiteral("offscreen")); + QProcess proc; + proc.setProcessEnvironment(env); + proc.start(QStringLiteral(QET_TEST_BINARY_PATH), arguments); + return proc.waitForFinished(60000) + && proc.exitStatus() == QProcess::NormalExit + && proc.exitCode() == 0; + } + + /// The elements of a saved project, in file order. + static QList diagrams(const QString &path) + { + QFile file(path); + QDomDocument doc; + if (!file.open(QIODevice::ReadOnly) || !doc.setContent(&file)) return {}; + QList list; + for (QDomElement e = doc.documentElement().firstChildElement(QStringLiteral("diagram")); + !e.isNull(); + e = e.nextSiblingElement(QStringLiteral("diagram"))) + list << e; + return list; + } + +private slots: + void initTestCase() + { + QVERIFY2(QFile::exists(QStringLiteral(QET_TEST_BINARY_PATH)), "qelectrotech binary not found"); + QVERIFY(m_dir.isValid()); + } + + // Folio 1 has both flags, folio 2 only the element one, folio 3 none, + // and folio 4 is an older file without the attributes at all. + void flagsSurviveASave_data() + { + QTest::addColumn("folio"); + QTest::addColumn("element"); + QTest::addColumn("conductor"); + QTest::newRow("both frozen") << 0 << "true" << "true"; + QTest::newRow("elements frozen") << 1 << "true" << "false"; + QTest::newRow("not frozen") << 2 << "false" << "false"; + QTest::newRow("no attributes") << 3 << "false" << "false"; + } + + void flagsSurviveASave() + { + QFETCH(int, folio); + QFETCH(QString, element); + QFETCH(QString, conductor); + + const QString fixture = QFINDTESTDATA("fixtures/folio_freeze_flags.qet"); + QVERIFY2(!fixture.isEmpty(), "fixture project not found"); + const QString out = m_dir.filePath(QStringLiteral("resaved%1.qet").arg(folio)); + QVERIFY2(runQet({QStringLiteral("--resave"), fixture, out}), "--resave failed"); + + const QList list = diagrams(out); + QCOMPARE(list.size(), 4); + const QDomElement e = list.at(folio); + QCOMPARE(e.attribute(QStringLiteral("freezeNewElement")), element); + QCOMPARE(e.attribute(QStringLiteral("freezeNewConductor")), conductor); + } +}; + +QTEST_MAIN(tst_foliofreezeflags) +#include "tst_foliofreezeflags.moc"