mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-10-17 19:34:13 +02:00
Keep the previous versions of a project when saving it
Saving replaced the project file with nothing kept of what it was: one
bad save -- a fault in QElectroTech, a full disk, a wrong edit saved by
mistake -- and the last good version was gone. AutoCAD keeps a .bak on
every save, KiCad several backups.
Before a project is saved over, the file as it was is now copied to a
folder beside it, "<name>-backups", named by the time that version was
saved ("industrial 2026-10-16 08-30-12.qetz"); only the newest are kept,
5 by default (Settings > General > Projects, 0 for none). A copy is
never a move, so a save that fails leaves the file in place; a copy that
fails only warns, the save goes on. The same bytes as the newest version
kept are not kept twice.
The prompt on opening ("Create a backup copy?"), which writes one dated
copy beside the project and never removes any, is left as it is.
New tst_previousversions (newest kept, same bytes once, same second,
nothing for a new file or a count of 0, a failed copy said); it fails
with the oldest never removed. Checked with the program: two scripted
saves of a .qetz leave the original and the first save in
industrial-backups, the project holds the second. ctest 107/107.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -940,6 +940,8 @@ set(QET_SRC_FILES
|
|||||||
${QET_DIR}/sources/utils/qetsettings.cpp
|
${QET_DIR}/sources/utils/qetsettings.cpp
|
||||||
${QET_DIR}/sources/utils/qetsettings.h
|
${QET_DIR}/sources/utils/qetsettings.h
|
||||||
${QET_DIR}/sources/utils/qetutils.cpp
|
${QET_DIR}/sources/utils/qetutils.cpp
|
||||||
|
${QET_DIR}/sources/utils/previousversions.cpp
|
||||||
|
${QET_DIR}/sources/utils/previousversions.h
|
||||||
${QET_DIR}/sources/utils/qetutils.h
|
${QET_DIR}/sources/utils/qetutils.h
|
||||||
|
|
||||||
${QET_DIR}/sources/materiallist/materialentrydialog.cpp
|
${QET_DIR}/sources/materiallist/materialentrydialog.cpp
|
||||||
|
|||||||
@@ -48,6 +48,7 @@
|
|||||||
#include "qetinformation.h"
|
#include "qetinformation.h"
|
||||||
#include "qetversion.h"
|
#include "qetversion.h"
|
||||||
#include "undocommand/adddiagramcommand.h"
|
#include "undocommand/adddiagramcommand.h"
|
||||||
|
#include "utils/previousversions.h"
|
||||||
|
|
||||||
#include <QCryptographicHash>
|
#include <QCryptographicHash>
|
||||||
#include <QElapsedTimer>
|
#include <QElapsedTimer>
|
||||||
@@ -2759,6 +2760,13 @@ QETResult QETProject::write()
|
|||||||
return(QString("the file %1 was opened read-only and thus will not be written").arg(m_file_path));
|
return(QString("the file %1 was opened read-only and thus will not be written").arg(m_file_path));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//The file as it was goes among its previous versions first
|
||||||
|
//(Settings > General > Projects); a copy that fails does not stop
|
||||||
|
//the save
|
||||||
|
QString backup_error;
|
||||||
|
if (!PreviousVersions::keep(m_file_path, PreviousVersions::count(), &backup_error))
|
||||||
|
qWarning().noquote() << "Previous version of" << m_file_path << "not kept:" << backup_error;
|
||||||
|
|
||||||
QString error_message;
|
QString error_message;
|
||||||
if (isContainerPath(m_file_path))
|
if (isContainerPath(m_file_path))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
#include "../../cablelist/cabletypelist.h"
|
#include "../../cablelist/cabletypelist.h"
|
||||||
#include "../../utils/qetsettings.h"
|
#include "../../utils/qetsettings.h"
|
||||||
#include "../../utils/qetutils.h"
|
#include "../../utils/qetutils.h"
|
||||||
|
#include "../../utils/previousversions.h"
|
||||||
#include "../../qetmessagebox.h"
|
#include "../../qetmessagebox.h"
|
||||||
#include "../../textgrid.h"
|
#include "../../textgrid.h"
|
||||||
#include "../../wiringrules.h"
|
#include "../../wiringrules.h"
|
||||||
@@ -190,6 +191,7 @@ GeneralConfigurationPage::GeneralConfigurationPage(QWidget *parent) :
|
|||||||
ui->m_use_folio_label->setChecked(settings.value("genericpanel/folio", true).toBool());
|
ui->m_use_folio_label->setChecked(settings.value("genericpanel/folio", true).toBool());
|
||||||
ui->m_border_0->setChecked(settings.value("border-columns_0", false).toBool());
|
ui->m_border_0->setChecked(settings.value("border-columns_0", false).toBool());
|
||||||
ui->m_autosave_sb->setValue(settings.value("diagrameditor/autosave-interval", 0).toInt());
|
ui->m_autosave_sb->setValue(settings.value("diagrameditor/autosave-interval", 0).toInt());
|
||||||
|
ui->m_previous_versions_sb->setValue(PreviousVersions::count());
|
||||||
|
|
||||||
QString fontInfos = settings.value("diagramitemfont", "Liberation Sans").toString() + " " +
|
QString fontInfos = settings.value("diagramitemfont", "Liberation Sans").toString() + " " +
|
||||||
settings.value("diagramitemsize", "9").toString() + " (" +
|
settings.value("diagramitemsize", "9").toString() + " (" +
|
||||||
@@ -417,6 +419,7 @@ void GeneralConfigurationPage::applyConf()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
settings.setValue("diagrameditor/autosave-interval", ui->m_autosave_sb->value());
|
settings.setValue("diagrameditor/autosave-interval", ui->m_autosave_sb->value());
|
||||||
|
PreviousVersions::setCount(ui->m_previous_versions_sb->value());
|
||||||
|
|
||||||
settings.setValue("diagrameditor/grid_display_startup", ui->grid_startup_cb->isChecked());
|
settings.setValue("diagrameditor/grid_display_startup", ui->grid_startup_cb->isChecked());
|
||||||
settings.setValue("diagrameditor/guides_display_startup", ui->guides_startup_cb->isChecked());
|
settings.setValue("diagrameditor/guides_display_startup", ui->guides_startup_cb->isChecked());
|
||||||
|
|||||||
@@ -365,6 +365,29 @@
|
|||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="7" column="0">
|
<item row="7" column="0">
|
||||||
|
<widget class="QLabel" name="m_previous_versions_label">
|
||||||
|
<property name="text">
|
||||||
|
<string>Previous versions kept when saving a project</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Before a project is saved, the file as it was is copied to a folder beside it, named after the project with "-backups". Only the newest are kept.</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="7" column="2">
|
||||||
|
<widget class="QSpinBox" name="m_previous_versions_sb">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Before a project is saved, the file as it was is copied to a folder beside it, named after the project with "-backups". Only the newest are kept.</string>
|
||||||
|
</property>
|
||||||
|
<property name="specialValueText">
|
||||||
|
<string>None</string>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>100</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="8" column="0">
|
||||||
<spacer name="verticalSpacer_2">
|
<spacer name="verticalSpacer_2">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Vertical</enum>
|
<enum>Qt::Vertical</enum>
|
||||||
@@ -1534,6 +1557,7 @@
|
|||||||
<tabstop>m_use_folio_label</tabstop>
|
<tabstop>m_use_folio_label</tabstop>
|
||||||
<tabstop>m_border_0</tabstop>
|
<tabstop>m_border_0</tabstop>
|
||||||
<tabstop>m_autosave_sb</tabstop>
|
<tabstop>m_autosave_sb</tabstop>
|
||||||
|
<tabstop>m_previous_versions_sb</tabstop>
|
||||||
<tabstop>m_common_elmt_path_cb</tabstop>
|
<tabstop>m_common_elmt_path_cb</tabstop>
|
||||||
<tabstop>m_custom_elmt_path_cb</tabstop>
|
<tabstop>m_custom_elmt_path_cb</tabstop>
|
||||||
<tabstop>m_custom_tbt_path_cb</tabstop>
|
<tabstop>m_custom_tbt_path_cb</tabstop>
|
||||||
|
|||||||
@@ -0,0 +1,113 @@
|
|||||||
|
/*
|
||||||
|
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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include "previousversions.h"
|
||||||
|
|
||||||
|
#include <QCryptographicHash>
|
||||||
|
#include <QDateTime>
|
||||||
|
#include <QDir>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QFileInfo>
|
||||||
|
#include <QSettings>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
const QString CountKey = QStringLiteral("diagrameditor/previous-versions");
|
||||||
|
constexpr int DefaultCount = 5;
|
||||||
|
|
||||||
|
//What a version of @p info is named, without the extension: its base
|
||||||
|
//name and a time
|
||||||
|
QString versionPrefix(const QFileInfo &info)
|
||||||
|
{
|
||||||
|
return info.completeBaseName() + QLatin1Char(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray digest(const QString &path)
|
||||||
|
{
|
||||||
|
QFile file(path);
|
||||||
|
if (!file.open(QIODevice::ReadOnly)) return {};
|
||||||
|
QCryptographicHash hash(QCryptographicHash::Sha256);
|
||||||
|
hash.addData(&file);
|
||||||
|
return hash.result();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int PreviousVersions::count()
|
||||||
|
{
|
||||||
|
return qMax(0, QSettings().value(CountKey, DefaultCount).toInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
void PreviousVersions::setCount(int count)
|
||||||
|
{
|
||||||
|
QSettings().setValue(CountKey, qMax(0, count));
|
||||||
|
}
|
||||||
|
|
||||||
|
QString PreviousVersions::folder(const QString &file_path)
|
||||||
|
{
|
||||||
|
const QFileInfo info(file_path);
|
||||||
|
return info.absoluteDir().filePath(info.completeBaseName() + QStringLiteral("-backups"));
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList PreviousVersions::kept(const QString &file_path)
|
||||||
|
{
|
||||||
|
const QFileInfo info(file_path);
|
||||||
|
const QDir dir(folder(file_path));
|
||||||
|
//Each copy has the time its version was saved (keep()); a .qet and
|
||||||
|
//a .qetz of the same project are versions of it alike
|
||||||
|
QStringList names = dir.entryList({versionPrefix(info) + QStringLiteral("????-??-?? ??-??-??*.qet"),
|
||||||
|
versionPrefix(info) + QStringLiteral("????-??-?? ??-??-??*.qetz")},
|
||||||
|
QDir::Files, QDir::Time);
|
||||||
|
QStringList paths;
|
||||||
|
for (const QString &name : std::as_const(names))
|
||||||
|
paths << dir.filePath(name);
|
||||||
|
return paths;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PreviousVersions::keep(const QString &file_path, int count, QString *error)
|
||||||
|
{
|
||||||
|
const QFileInfo info(file_path);
|
||||||
|
if (count <= 0 || !info.isFile()) return true;
|
||||||
|
|
||||||
|
const QStringList versions = kept(file_path);
|
||||||
|
if (!versions.isEmpty() && QFileInfo(versions.first()).size() == info.size()
|
||||||
|
&& digest(versions.first()) == digest(file_path))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
QDir dir(folder(file_path));
|
||||||
|
if (!dir.exists() && !QDir().mkpath(dir.path())) {
|
||||||
|
if (error) *error = QStringLiteral("cannot create the folder %1").arg(dir.path());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//Named by the time this version was saved, made unique if another
|
||||||
|
//was saved the same second
|
||||||
|
const QDateTime saved = info.lastModified();
|
||||||
|
const QString stem = versionPrefix(info) + saved.toString(QStringLiteral("yyyy-MM-dd HH-mm-ss"));
|
||||||
|
QString target = dir.filePath(stem + QLatin1Char('.') + info.suffix());
|
||||||
|
for (int n = 2 ; QFileInfo::exists(target) ; ++n)
|
||||||
|
target = dir.filePath(stem + QStringLiteral(" (%1).").arg(n) + info.suffix());
|
||||||
|
if (!QFile::copy(file_path, target)) {
|
||||||
|
if (error) *error = QStringLiteral("cannot copy %1 to %2").arg(file_path, target);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
QFile copy(target);
|
||||||
|
if (copy.open(QIODevice::ReadWrite))
|
||||||
|
copy.setFileTime(saved, QFileDevice::FileModificationTime);
|
||||||
|
|
||||||
|
const QStringList all = kept(file_path);
|
||||||
|
for (int i = count ; i < all.size() ; ++i)
|
||||||
|
QFile::remove(all.at(i));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#ifndef PREVIOUSVERSIONS_H
|
||||||
|
#define PREVIOUSVERSIONS_H
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
#include <QStringList>
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief The PreviousVersions namespace
|
||||||
|
The versions of a project file kept before it is saved over, as KiCad
|
||||||
|
and AutoCAD keep theirs: a copy of the file as it was goes in a folder
|
||||||
|
beside it, "<name>-backups", named by the time that version was saved
|
||||||
|
("industrial 2026-10-16 08-30-12.qetz"), and only the newest are kept.
|
||||||
|
The file is copied, never moved: a save that fails leaves it in place.
|
||||||
|
*/
|
||||||
|
namespace PreviousVersions
|
||||||
|
{
|
||||||
|
/// How many versions to keep (Settings > General > Projects); 0 keeps none
|
||||||
|
int count();
|
||||||
|
void setCount(int count);
|
||||||
|
/// The folder the versions of @p file_path go in
|
||||||
|
QString folder(const QString &file_path);
|
||||||
|
/// The versions kept of @p file_path, newest first
|
||||||
|
QStringList kept(const QString &file_path);
|
||||||
|
/// Copy @p file_path, about to be saved over, among its versions and
|
||||||
|
/// keep only the @p count newest. Nothing is copied when the file does
|
||||||
|
/// not exist, when @p count is 0, or when the newest version kept
|
||||||
|
/// holds the same bytes. @return false, with @p error, when the copy
|
||||||
|
/// could not be made: the save goes on all the same.
|
||||||
|
bool keep(const QString &file_path, int count, QString *error = nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // PREVIOUSVERSIONS_H
|
||||||
@@ -1264,6 +1264,17 @@ if(Qt6_VERSION VERSION_LESS 6.5.0)
|
|||||||
endforeach()
|
endforeach()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# The versions of a project kept before it is saved over: the newest
|
||||||
|
# kept, same bytes not kept twice, a failed copy said
|
||||||
|
# (sources/utils/previousversions.*).
|
||||||
|
add_executable(
|
||||||
|
tst_previousversions
|
||||||
|
tst_previousversions.cpp
|
||||||
|
${QET_DIR}/sources/utils/previousversions.cpp)
|
||||||
|
add_test(NAME tst_previousversions COMMAND tst_previousversions)
|
||||||
|
target_include_directories(tst_previousversions PRIVATE ${QET_DIR}/sources)
|
||||||
|
target_link_libraries(tst_previousversions PRIVATE Qt::Test)
|
||||||
|
|
||||||
# The zip a .qetz project is stored in: round trip, same bytes twice,
|
# The zip a .qetz project is stored in: round trip, same bytes twice,
|
||||||
# unsafe entry names refused (sources/container/qetzip.*, bundled miniz).
|
# unsafe entry names refused (sources/container/qetzip.*, bundled miniz).
|
||||||
add_executable(
|
add_executable(
|
||||||
|
|||||||
@@ -0,0 +1,127 @@
|
|||||||
|
/*
|
||||||
|
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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <QtTest>
|
||||||
|
|
||||||
|
#include <QDateTime>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QTemporaryDir>
|
||||||
|
|
||||||
|
#include "utils/previousversions.h"
|
||||||
|
|
||||||
|
// The versions of a project kept before it is saved over
|
||||||
|
// (sources/utils/previousversions.*)
|
||||||
|
class tst_previousversions : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
QTemporaryDir m_dir;
|
||||||
|
|
||||||
|
// @p path holding @p text, saved at @p when
|
||||||
|
static void write(const QString &path, const QByteArray &text, const QDateTime &when)
|
||||||
|
{
|
||||||
|
QFile file(path);
|
||||||
|
QVERIFY(file.open(QIODevice::WriteOnly | QIODevice::Truncate));
|
||||||
|
file.write(text);
|
||||||
|
file.flush(); //else closing writes, and sets the time to now
|
||||||
|
QVERIFY(file.setFileTime(when, QFileDevice::FileModificationTime));
|
||||||
|
}
|
||||||
|
|
||||||
|
static QByteArray read(const QString &path)
|
||||||
|
{
|
||||||
|
QFile file(path);
|
||||||
|
return file.open(QIODevice::ReadOnly) ? file.readAll() : QByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void initTestCase() { QVERIFY(m_dir.isValid()); }
|
||||||
|
|
||||||
|
// Each save keeps the file as it was, newest first, named by the time
|
||||||
|
// that version was saved, in "<name>-backups" beside it; only the
|
||||||
|
// newest are kept
|
||||||
|
void keepsTheNewest()
|
||||||
|
{
|
||||||
|
const QString project = m_dir.filePath(QStringLiteral("plant.qetz"));
|
||||||
|
const QDateTime start(QDate(2026, 10, 16), QTime(8, 0, 0));
|
||||||
|
for (int i = 0 ; i < 7 ; ++i) {
|
||||||
|
write(project, "version " + QByteArray::number(i), start.addSecs(60 * i));
|
||||||
|
QVERIFY(PreviousVersions::keep(project, 3));
|
||||||
|
}
|
||||||
|
const QStringList kept = PreviousVersions::kept(project);
|
||||||
|
QCOMPARE(kept.size(), 3);
|
||||||
|
QCOMPARE(read(kept.at(0)), QByteArray("version 6"));
|
||||||
|
QCOMPARE(read(kept.at(2)), QByteArray("version 4"));
|
||||||
|
QCOMPARE(QFileInfo(kept.at(0)).fileName(), QStringLiteral("plant 2026-10-16 08-06-00.qetz"));
|
||||||
|
QCOMPARE(QFileInfo(kept.at(0)).absolutePath(), m_dir.filePath(QStringLiteral("plant-backups")));
|
||||||
|
// The project itself is untouched
|
||||||
|
QCOMPARE(read(project), QByteArray("version 6"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Saving the same bytes again keeps no second copy
|
||||||
|
void sameBytesNotKeptTwice()
|
||||||
|
{
|
||||||
|
const QString project = m_dir.filePath(QStringLiteral("same.qet"));
|
||||||
|
const QDateTime when(QDate(2026, 10, 16), QTime(9, 0, 0));
|
||||||
|
write(project, "unchanged", when);
|
||||||
|
QVERIFY(PreviousVersions::keep(project, 5));
|
||||||
|
write(project, "unchanged", when.addSecs(30));
|
||||||
|
QVERIFY(PreviousVersions::keep(project, 5));
|
||||||
|
QCOMPARE(PreviousVersions::kept(project).size(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Two versions saved the same second both kept
|
||||||
|
void sameSecond()
|
||||||
|
{
|
||||||
|
const QString project = m_dir.filePath(QStringLiteral("fast.qetz"));
|
||||||
|
const QDateTime when(QDate(2026, 10, 16), QTime(10, 0, 0));
|
||||||
|
write(project, "first", when);
|
||||||
|
QVERIFY(PreviousVersions::keep(project, 5));
|
||||||
|
write(project, "second", when);
|
||||||
|
QVERIFY(PreviousVersions::keep(project, 5));
|
||||||
|
QCOMPARE(PreviousVersions::kept(project).size(), 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nothing kept for a new file, or when the count is 0; another
|
||||||
|
// project's versions in the same folder are not counted
|
||||||
|
void nothingToKeep()
|
||||||
|
{
|
||||||
|
const QString project = m_dir.filePath(QStringLiteral("new.qetz"));
|
||||||
|
QVERIFY(PreviousVersions::keep(project, 5));
|
||||||
|
QVERIFY(!QFileInfo::exists(PreviousVersions::folder(project)));
|
||||||
|
write(project, "x", QDateTime(QDate(2026, 10, 16), QTime(11, 0, 0)));
|
||||||
|
QVERIFY(PreviousVersions::keep(project, 0));
|
||||||
|
QVERIFY(!QFileInfo::exists(PreviousVersions::folder(project)));
|
||||||
|
QVERIFY(PreviousVersions::kept(m_dir.filePath(QStringLiteral("other.qetz"))).isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
// A copy that cannot be made says so, and leaves the project as it is
|
||||||
|
void copyFails()
|
||||||
|
{
|
||||||
|
const QString project = m_dir.filePath(QStringLiteral("blocked.qetz"));
|
||||||
|
write(project, "data", QDateTime(QDate(2026, 10, 16), QTime(12, 0, 0)));
|
||||||
|
// A file where the folder should be
|
||||||
|
write(PreviousVersions::folder(project), "", QDateTime::currentDateTime());
|
||||||
|
QString error;
|
||||||
|
QVERIFY(!PreviousVersions::keep(project, 5, &error));
|
||||||
|
QVERIFY(!error.isEmpty());
|
||||||
|
QCOMPARE(read(project), QByteArray("data"));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
QTEST_GUILESS_MAIN(tst_previousversions)
|
||||||
|
|
||||||
|
#include "tst_previousversions.moc"
|
||||||
Reference in New Issue
Block a user