This commit is contained in:
vuurvli3g 2025-03-31 23:46:35 -07:00 committed by GitHub
commit 39ed40ff32
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 219 additions and 54 deletions

View file

@ -990,10 +990,15 @@ Entry* Entry::clone(CloneFlags flags) const
if (flags & CloneResetTimeInfo) { if (flags & CloneResetTimeInfo) {
QDateTime now = Clock::currentDateTimeUtc(); QDateTime now = Clock::currentDateTimeUtc();
entry->m_data.timeInfo.setCreationTime(now); if (flags & CloneResetCreationTime) {
entry->m_data.timeInfo.setLastModificationTime(now); entry->m_data.timeInfo.setCreationTime(now);
entry->m_data.timeInfo.setLastAccessTime(now); }
entry->m_data.timeInfo.setLocationChanged(now); if (flags & CloneResetLastAccessTime) {
entry->m_data.timeInfo.setLastAccessTime(now);
}
if (flags & CloneResetLocationChangedTime) {
entry->m_data.timeInfo.setLocationChanged(now);
}
} }
if (flags & CloneRenameTitle) { if (flags & CloneRenameTitle) {
@ -1370,10 +1375,8 @@ void Entry::setGroup(Group* group, bool trackPrevious)
m_group->database()->addDeletedObject(m_uuid); m_group->database()->addDeletedObject(m_uuid);
// copy custom icon to the new database // copy custom icon to the new database
if (!iconUuid().isNull() && group->database() && m_group->database()->metadata()->hasCustomIcon(iconUuid()) if (group->database()) {
&& !group->database()->metadata()->hasCustomIcon(iconUuid())) { group->database()->metadata()->copyCustomIcon(iconUuid(), m_group->database()->metadata());
group->database()->metadata()->addCustomIcon(iconUuid(),
m_group->database()->metadata()->customIcon(iconUuid()));
} }
} else if (trackPrevious && m_group->database() && group != m_group) { } else if (trackPrevious && m_group->database() && group != m_group) {
setPreviousParentGroup(m_group); setPreviousParentGroup(m_group);
@ -1596,7 +1599,10 @@ QUuid Entry::previousParentGroupUuid() const
void Entry::setPreviousParentGroupUuid(const QUuid& uuid) void Entry::setPreviousParentGroupUuid(const QUuid& uuid)
{ {
bool prevUpdateTimeinfo = m_updateTimeinfo;
m_updateTimeinfo = false; // prevent update of LastModificationTime
set(m_data.previousParentGroupUuid, uuid); set(m_data.previousParentGroupUuid, uuid);
m_updateTimeinfo = prevUpdateTimeinfo;
} }
void Entry::setPreviousParentGroup(const Group* group) void Entry::setPreviousParentGroup(const Group* group)

View file

@ -182,13 +182,18 @@ public:
{ {
CloneNoFlags = 0, CloneNoFlags = 0,
CloneNewUuid = 1, // generate a random uuid for the clone CloneNewUuid = 1, // generate a random uuid for the clone
CloneResetTimeInfo = 2, // set all TimeInfo attributes to the current time CloneResetCreationTime = 2, // set timeInfo.CreationTime to the current time
CloneIncludeHistory = 4, // clone the history items CloneResetLastAccessTime = 4, // set timeInfo.LastAccessTime to the current time
CloneResetLocationChangedTime = 8, // set timeInfo.LocationChangedTime to the current time
CloneIncludeHistory = 16, // clone the history items
CloneRenameTitle = 32, // add "-Clone" after the original title
CloneUserAsRef = 64, // Add the user as a reference to the original entry
ClonePassAsRef = 128, // Add the password as a reference to the original entry
CloneResetTimeInfo = CloneResetCreationTime | CloneResetLastAccessTime | CloneResetLocationChangedTime,
CloneExactCopy = CloneIncludeHistory,
CloneCopy = CloneExactCopy | CloneNewUuid | CloneResetTimeInfo,
CloneDefault = CloneNewUuid | CloneResetTimeInfo, CloneDefault = CloneNewUuid | CloneResetTimeInfo,
CloneCopy = CloneNewUuid | CloneResetTimeInfo | CloneIncludeHistory,
CloneRenameTitle = 8, // add "-Clone" after the original title
CloneUserAsRef = 16, // Add the user as a reference to the original entry
ClonePassAsRef = 32, // Add the password as a reference to the original entry
}; };
Q_DECLARE_FLAGS(CloneFlags, CloneFlag) Q_DECLARE_FLAGS(CloneFlags, CloneFlag)

View file

@ -77,11 +77,11 @@ Group::~Group()
cleanupParent(); cleanupParent();
} }
template <class P, class V> inline bool Group::set(P& property, const V& value) template <class P, class V> inline bool Group::set(P& property, const V& value, bool preserveTimeinfo)
{ {
if (property != value) { if (property != value) {
property = value; property = value;
emitModified(); emitModifiedEx(preserveTimeinfo);
return true; return true;
} else { } else {
return false; return false;
@ -454,6 +454,15 @@ const Group* Group::parentGroup() const
return m_parent; return m_parent;
} }
void Group::emitModifiedEx(bool preserveTimeinfo) {
bool prevUpdateTimeinfo = m_updateTimeinfo;
if (preserveTimeinfo) {
m_updateTimeinfo = false; // prevent update of LastModificationTime
}
emitModified();
m_updateTimeinfo = prevUpdateTimeinfo;
}
void Group::setParent(Group* parent, int index, bool trackPrevious) void Group::setParent(Group* parent, int index, bool trackPrevious)
{ {
Q_ASSERT(parent); Q_ASSERT(parent);
@ -483,9 +492,8 @@ void Group::setParent(Group* parent, int index, bool trackPrevious)
recCreateDelObjects(); recCreateDelObjects();
// copy custom icon to the new database // copy custom icon to the new database
if (!iconUuid().isNull() && parent->m_db && m_db->metadata()->hasCustomIcon(iconUuid()) if (parent->m_db) {
&& !parent->m_db->metadata()->hasCustomIcon(iconUuid())) { parent->m_db->metadata()->copyCustomIcon(iconUuid(), m_db->metadata());
parent->m_db->metadata()->addCustomIcon(iconUuid(), m_db->metadata()->customIcon(iconUuid()));
} }
} }
if (m_db != parent->m_db) { if (m_db != parent->m_db) {
@ -511,7 +519,7 @@ void Group::setParent(Group* parent, int index, bool trackPrevious)
m_data.timeInfo.setLocationChanged(Clock::currentDateTimeUtc()); m_data.timeInfo.setLocationChanged(Clock::currentDateTimeUtc());
} }
emitModified(); emitModifiedEx(true);
if (!moveWithinDatabase) { if (!moveWithinDatabase) {
emit groupAdded(); emit groupAdded();
@ -960,12 +968,16 @@ Group* Group::clone(Entry::CloneFlags entryFlags, Group::CloneFlags groupFlags)
clonedGroup->setUpdateTimeinfo(true); clonedGroup->setUpdateTimeinfo(true);
if (groupFlags & Group::CloneResetTimeInfo) { if (groupFlags & Group::CloneResetTimeInfo) {
QDateTime now = Clock::currentDateTimeUtc(); QDateTime now = Clock::currentDateTimeUtc();
clonedGroup->m_data.timeInfo.setCreationTime(now); if (groupFlags & Group::CloneResetCreationTime) {
clonedGroup->m_data.timeInfo.setLastModificationTime(now); clonedGroup->m_data.timeInfo.setCreationTime(now);
clonedGroup->m_data.timeInfo.setLastAccessTime(now); }
clonedGroup->m_data.timeInfo.setLocationChanged(now); if (groupFlags & Group::CloneResetLastAccessTime) {
clonedGroup->m_data.timeInfo.setLastAccessTime(now);
}
if (groupFlags & Group::CloneResetLocationChangedTime) {
clonedGroup->m_data.timeInfo.setLocationChanged(now);
}
} }
if (groupFlags & Group::CloneRenameTitle) { if (groupFlags & Group::CloneRenameTitle) {
@ -997,7 +1009,7 @@ void Group::addEntry(Entry* entry)
connect(entry, &Entry::modified, m_db, &Database::markAsModified); connect(entry, &Entry::modified, m_db, &Database::markAsModified);
} }
emitModified(); emitModifiedEx(true);
emit entryAdded(entry); emit entryAdded(entry);
} }
@ -1014,7 +1026,7 @@ void Group::removeEntry(Entry* entry)
entry->disconnect(m_db); entry->disconnect(m_db);
} }
m_entries.removeAll(entry); m_entries.removeAll(entry);
emitModified(); emitModifiedEx(true);
emit entryRemoved(entry); emit entryRemoved(entry);
} }
@ -1085,7 +1097,7 @@ void Group::cleanupParent()
if (m_parent) { if (m_parent) {
emit groupAboutToRemove(this); emit groupAboutToRemove(this);
m_parent->m_children.removeAll(this); m_parent->m_children.removeAll(this);
emitModified(); emitModifiedEx(true);
emit groupRemoved(); emit groupRemoved();
} }
} }
@ -1236,7 +1248,7 @@ void Group::sortChildrenRecursively(bool reverse)
child->sortChildrenRecursively(reverse); child->sortChildrenRecursively(reverse);
} }
emitModified(); emitModifiedEx(true);
} }
const Group* Group::previousParentGroup() const const Group* Group::previousParentGroup() const
@ -1254,7 +1266,7 @@ QUuid Group::previousParentGroupUuid() const
void Group::setPreviousParentGroupUuid(const QUuid& uuid) void Group::setPreviousParentGroupUuid(const QUuid& uuid)
{ {
set(m_data.previousParentGroupUuid, uuid); set(m_data.previousParentGroupUuid, uuid, true);
} }
void Group::setPreviousParentGroup(const Group* group) void Group::setPreviousParentGroup(const Group* group)

View file

@ -47,10 +47,16 @@ public:
{ {
CloneNoFlags = 0, CloneNoFlags = 0,
CloneNewUuid = 1, // generate a random uuid for the clone CloneNewUuid = 1, // generate a random uuid for the clone
CloneResetTimeInfo = 2, // set all TimeInfo attributes to the current time CloneResetCreationTime = 2, // set timeInfo.CreationTime to the current time
CloneIncludeEntries = 4, // clone the group entries CloneResetLastAccessTime = 4, // set timeInfo.LastAccessTime to the current time
CloneDefault = CloneNewUuid | CloneResetTimeInfo | CloneIncludeEntries, CloneResetLocationChangedTime = 8, // set timeInfo.LocationChangedTime to the current time
CloneRenameTitle = 8, // add "- Clone" after the original title CloneIncludeEntries = 16, // clone the group entries
CloneRenameTitle = 32, // add "- Clone" after the original title
CloneResetTimeInfo = CloneResetCreationTime | CloneResetLastAccessTime | CloneResetLocationChangedTime,
CloneExactCopy = CloneIncludeEntries,
CloneCopy = CloneExactCopy | CloneNewUuid | CloneResetTimeInfo,
CloneDefault = CloneCopy,
}; };
Q_DECLARE_FLAGS(CloneFlags, CloneFlag) Q_DECLARE_FLAGS(CloneFlags, CloneFlag)
@ -204,8 +210,9 @@ private slots:
void updateTimeinfo(); void updateTimeinfo();
private: private:
template <class P, class V> bool set(P& property, const V& value); template <class P, class V> bool set(P& property, const V& value, bool preserveTimeinfo = false);
void emitModifiedEx(bool preserveTimeinfo);
void setParent(Database* db); void setParent(Database* db);
void connectDatabaseSignalsRecursive(Database* db); void connectDatabaseSignalsRecursive(Database* db);

View file

@ -419,14 +419,21 @@ QUuid Metadata::findCustomIcon(const QByteArray& candidate)
return m_customIconsHashes.value(hash, QUuid()); return m_customIconsHashes.value(hash, QUuid());
} }
void Metadata::copyCustomIcon(const QUuid& iconUuid, const Metadata* otherMetadata)
{
if (iconUuid.isNull()) {
return;
}
Q_ASSERT(otherMetadata->hasCustomIcon(iconUuid));
if (!hasCustomIcon(iconUuid) && otherMetadata->hasCustomIcon(iconUuid)) {
addCustomIcon(iconUuid, otherMetadata->customIcon(iconUuid));
}
}
void Metadata::copyCustomIcons(const QSet<QUuid>& iconList, const Metadata* otherMetadata) void Metadata::copyCustomIcons(const QSet<QUuid>& iconList, const Metadata* otherMetadata)
{ {
for (const QUuid& uuid : iconList) { for (const QUuid& uuid : iconList) {
Q_ASSERT(otherMetadata->hasCustomIcon(uuid)); copyCustomIcon(uuid, otherMetadata);
if (!hasCustomIcon(uuid) && otherMetadata->hasCustomIcon(uuid)) {
addCustomIcon(uuid, otherMetadata->customIcon(uuid));
}
} }
} }

View file

@ -138,6 +138,7 @@ public:
const QString& name = {}, const QString& name = {},
const QDateTime& lastModified = {}); const QDateTime& lastModified = {});
void removeCustomIcon(const QUuid& uuid); void removeCustomIcon(const QUuid& uuid);
void copyCustomIcon(const QUuid& iconUuid, const Metadata* otherMetadata);
void copyCustomIcons(const QSet<QUuid>& iconList, const Metadata* otherMetadata); void copyCustomIcons(const QSet<QUuid>& iconList, const Metadata* otherMetadata);
QUuid findCustomIcon(const QByteArray& candidate); QUuid findCustomIcon(const QByteArray& candidate);
void setRecycleBinEnabled(bool value); void setRecycleBinEnabled(bool value);

View file

@ -258,14 +258,16 @@ bool GroupModel::dropMimeData(const QMimeData* data,
Group* group = dragGroup; Group* group = dragGroup;
if (sourceDb != targetDb) { if (sourceDb != targetDb) {
QSet<QUuid> customIcons = group->customIconsRecursive(); targetDb->metadata()->copyCustomIcons(group->customIconsRecursive(), sourceDb->metadata());
targetDb->metadata()->copyCustomIcons(customIcons, sourceDb->metadata());
// Always clone the group across db's to reset UUIDs
group = dragGroup->clone(Entry::CloneDefault | Entry::CloneIncludeHistory);
if (action == Qt::MoveAction) { if (action == Qt::MoveAction) {
// Remove the original group from the sourceDb // For cross-db moves use a clone with new UUID but original CreationTime
group = dragGroup->clone(Entry::CloneFlags(Entry::CloneCopy & ~Entry::CloneResetCreationTime),
Group::CloneFlags(Group::CloneCopy & ~Group::CloneResetCreationTime));
// Remove the original from the sourceDb to allow this change to sync to other dbs
delete dragGroup; delete dragGroup;
} else {
group = dragGroup->clone(Entry::CloneCopy);
} }
} else if (action == Qt::CopyAction) { } else if (action == Qt::CopyAction) {
group = dragGroup->clone(Entry::CloneCopy); group = dragGroup->clone(Entry::CloneCopy);
@ -298,15 +300,16 @@ bool GroupModel::dropMimeData(const QMimeData* data,
Entry* entry = dragEntry; Entry* entry = dragEntry;
if (sourceDb != targetDb) { if (sourceDb != targetDb) {
QUuid customIcon = entry->iconUuid(); targetDb->metadata()->copyCustomIcon(entry->iconUuid(), sourceDb->metadata());
if (!customIcon.isNull() && !targetDb->metadata()->hasCustomIcon(customIcon)) {
targetDb->metadata()->addCustomIcon(customIcon, sourceDb->metadata()->customIcon(customIcon).data);
}
// Reset the UUID when moving across db boundary // Reset the UUID when moving across db boundary
entry = dragEntry->clone(Entry::CloneDefault | Entry::CloneIncludeHistory);
if (action == Qt::MoveAction) { if (action == Qt::MoveAction) {
// For cross-db moves use a clone with new UUID but original CreationTime
entry = dragEntry->clone(Entry::CloneFlags(Entry::CloneCopy & ~Entry::CloneResetCreationTime));
// Remove the original from the sourceDb to allow this change to sync to other dbs
delete dragEntry; delete dragEntry;
} else {
entry = dragEntry->clone(Entry::CloneCopy);
} }
} else if (action == Qt::CopyAction) { } else if (action == Qt::CopyAction) {
entry = dragEntry->clone(Entry::CloneCopy); entry = dragEntry->clone(Entry::CloneCopy);

View file

@ -168,7 +168,7 @@ if(WITH_XC_SSHAGENT)
endif() endif()
add_unit_test(NAME testentry SOURCES TestEntry.cpp add_unit_test(NAME testentry SOURCES TestEntry.cpp
LIBS ${TEST_LIBRARIES}) LIBS testsupport ${TEST_LIBRARIES})
add_unit_test(NAME testmerge SOURCES TestMerge.cpp add_unit_test(NAME testmerge SOURCES TestMerge.cpp
LIBS testsupport ${TEST_LIBRARIES}) LIBS testsupport ${TEST_LIBRARIES})

View file

@ -25,13 +25,34 @@
#include "core/TimeInfo.h" #include "core/TimeInfo.h"
#include "crypto/Crypto.h" #include "crypto/Crypto.h"
#include "mock/MockClock.h"
QTEST_GUILESS_MAIN(TestEntry) QTEST_GUILESS_MAIN(TestEntry)
namespace
{
MockClock* m_clock = nullptr;
}
void TestEntry::initTestCase() void TestEntry::initTestCase()
{ {
QVERIFY(Crypto::init()); QVERIFY(Crypto::init());
} }
void TestEntry::init()
{
Q_ASSERT(m_clock == nullptr);
m_clock = new MockClock(2010, 5, 5, 10, 30, 10);
MockClock::setup(m_clock);
}
void TestEntry::cleanup()
{
MockClock::teardown();
m_clock = nullptr;
}
void TestEntry::testHistoryItemDeletion() void TestEntry::testHistoryItemDeletion()
{ {
QScopedPointer<Entry> entry(new Entry()); QScopedPointer<Entry> entry(new Entry());
@ -110,6 +131,8 @@ void TestEntry::testClone()
QCOMPARE(entryCloneNewUuid->timeInfo().creationTime(), entryOrg->timeInfo().creationTime()); QCOMPARE(entryCloneNewUuid->timeInfo().creationTime(), entryOrg->timeInfo().creationTime());
// Reset modification time // Reset modification time
entryOrgTime.setLastAccessTime(Clock::datetimeUtc(60));
entryOrgTime.setLocationChanged(Clock::datetimeUtc(60));
entryOrgTime.setLastModificationTime(Clock::datetimeUtc(60)); entryOrgTime.setLastModificationTime(Clock::datetimeUtc(60));
entryOrg->setTimeInfo(entryOrgTime); entryOrg->setTimeInfo(entryOrgTime);
@ -123,7 +146,12 @@ void TestEntry::testClone()
QCOMPARE(entryCloneResetTime->uuid(), entryOrg->uuid()); QCOMPARE(entryCloneResetTime->uuid(), entryOrg->uuid());
QCOMPARE(entryCloneResetTime->title(), QString("New Title")); QCOMPARE(entryCloneResetTime->title(), QString("New Title"));
QCOMPARE(entryCloneResetTime->historyItems().size(), 0); QCOMPARE(entryCloneResetTime->historyItems().size(), 0);
// Cloning with CloneResetTimeInfo should affect the CreationTime, LocationChanged, LastAccessTime
QVERIFY(entryCloneResetTime->timeInfo().creationTime() != entryOrg->timeInfo().creationTime()); QVERIFY(entryCloneResetTime->timeInfo().creationTime() != entryOrg->timeInfo().creationTime());
QVERIFY(entryCloneResetTime->timeInfo().locationChanged() != entryOrg->timeInfo().locationChanged());
QVERIFY(entryCloneResetTime->timeInfo().lastAccessTime() != entryOrg->timeInfo().lastAccessTime());
// Cloning with CloneResetTimeInfo should not affect the LastModificationTime
QCOMPARE(entryCloneResetTime->timeInfo().lastModificationTime(), entryOrg->timeInfo().lastModificationTime());
// Date back history of original entry // Date back history of original entry
Entry* firstHistoryItem = entryOrg->historyItems()[0]; Entry* firstHistoryItem = entryOrg->historyItems()[0];
@ -851,3 +879,33 @@ void TestEntry::testPreviousParentGroup()
QVERIFY(entry->previousParentGroupUuid() == group1->uuid()); QVERIFY(entry->previousParentGroupUuid() == group1->uuid());
QVERIFY(entry->previousParentGroup() == group1); QVERIFY(entry->previousParentGroup() == group1);
} }
void TestEntry::testTimeinfoChanges()
{
Database db;
auto* root = db.rootGroup();
auto* subgroup = new Group();
subgroup->setUuid(QUuid::createUuid());
subgroup->setParent(root);
QDateTime startTime = Clock::currentDateTimeUtc();
TimeInfo startTimeinfo;
startTimeinfo.setCreationTime(startTime);
startTimeinfo.setLastModificationTime(startTime);
startTimeinfo.setLocationChanged(startTime);
startTimeinfo.setLastAccessTime(startTime);
m_clock->advanceMinute(1);
QScopedPointer<Entry> entry(new Entry());
entry->setUuid(QUuid::createUuid());
entry->setGroup(root);
entry->setTimeInfo(startTimeinfo);
entry->setPreviousParentGroup(subgroup);
// setting previous parent group should not affect the LastModificationTime
QCOMPARE(entry->timeInfo().lastModificationTime(), startTime);
entry->setGroup(subgroup);
// changing group should not affect LastModicationTime, CreationTime
QCOMPARE(entry->timeInfo().creationTime(), startTime);
QCOMPARE(entry->timeInfo().lastModificationTime(), startTime);
// changing group should affect the LocationChanged time
QCOMPARE(entry->timeInfo().locationChanged(), Clock::currentDateTimeUtc());
}

View file

@ -28,6 +28,8 @@ class TestEntry : public QObject
private slots: private slots:
void initTestCase(); void initTestCase();
void init();
void cleanup();
void testHistoryItemDeletion(); void testHistoryItemDeletion();
void testCopyDataFrom(); void testCopyDataFrom();
void testClone(); void testClone();
@ -42,6 +44,7 @@ private slots:
void testIsRecycled(); void testIsRecycled();
void testMoveUpDown(); void testMoveUpDown();
void testPreviousParentGroup(); void testPreviousParentGroup();
void testTimeinfoChanges();
}; };
#endif // KEEPASSX_TESTENTRY_H #endif // KEEPASSX_TESTENTRY_H

View file

@ -382,18 +382,21 @@ void TestGroup::testClone()
QCOMPARE(clonedGroup->iconNumber(), 42); QCOMPARE(clonedGroup->iconNumber(), 42);
QCOMPARE(clonedGroup->children().size(), 1); QCOMPARE(clonedGroup->children().size(), 1);
QCOMPARE(clonedGroup->entries().size(), 1); QCOMPARE(clonedGroup->entries().size(), 1);
QCOMPARE(clonedGroup->timeInfo(), originalGroup->timeInfo());
Entry* clonedGroupEntry = clonedGroup->entries().at(0); Entry* clonedGroupEntry = clonedGroup->entries().at(0);
QVERIFY(clonedGroupEntry->uuid() != originalGroupEntry->uuid()); QVERIFY(clonedGroupEntry->uuid() != originalGroupEntry->uuid());
QCOMPARE(clonedGroupEntry->title(), QString("GroupEntry")); QCOMPARE(clonedGroupEntry->title(), QString("GroupEntry"));
QCOMPARE(clonedGroupEntry->iconNumber(), 43); QCOMPARE(clonedGroupEntry->iconNumber(), 43);
QCOMPARE(clonedGroupEntry->historyItems().size(), 0); QCOMPARE(clonedGroupEntry->historyItems().size(), 0);
QCOMPARE(clonedGroupEntry->timeInfo(), originalGroupEntry->timeInfo());
Group* clonedSubGroup = clonedGroup->children().at(0); Group* clonedSubGroup = clonedGroup->children().at(0);
QVERIFY(clonedSubGroup->uuid() != subGroup->uuid()); QVERIFY(clonedSubGroup->uuid() != subGroup->uuid());
QCOMPARE(clonedSubGroup->name(), QString("SubGroup")); QCOMPARE(clonedSubGroup->name(), QString("SubGroup"));
QCOMPARE(clonedSubGroup->children().size(), 0); QCOMPARE(clonedSubGroup->children().size(), 0);
QCOMPARE(clonedSubGroup->entries().size(), 1); QCOMPARE(clonedSubGroup->entries().size(), 1);
QCOMPARE(clonedSubGroup->timeInfo(), subGroup->timeInfo());
Entry* clonedSubGroupEntry = clonedSubGroup->entries().at(0); Entry* clonedSubGroupEntry = clonedSubGroup->entries().at(0);
QVERIFY(clonedSubGroupEntry->uuid() != subGroupEntry->uuid()); QVERIFY(clonedSubGroupEntry->uuid() != subGroupEntry->uuid());
@ -411,15 +414,17 @@ void TestGroup::testClone()
QCOMPARE(clonedGroupNewUuid->entries().size(), 0); QCOMPARE(clonedGroupNewUuid->entries().size(), 0);
QVERIFY(clonedGroupNewUuid->uuid() != originalGroup->uuid()); QVERIFY(clonedGroupNewUuid->uuid() != originalGroup->uuid());
// Making sure the new modification date is not the same. // Verify Timeinfo modifications for CloneResetTimeInfo
m_clock->advanceSecond(1); m_clock->advanceSecond(1);
QScopedPointer<Group> clonedGroupResetTimeInfo( QScopedPointer<Group> clonedGroupResetTimeInfo(
originalGroup->clone(Entry::CloneNoFlags, Group::CloneNewUuid | Group::CloneResetTimeInfo)); originalGroup->clone(Entry::CloneNoFlags, Group::CloneNewUuid | Group::CloneResetTimeInfo));
QCOMPARE(clonedGroupResetTimeInfo->entries().size(), 0); QCOMPARE(clonedGroupResetTimeInfo->entries().size(), 0);
QVERIFY(clonedGroupResetTimeInfo->uuid() != originalGroup->uuid()); QVERIFY(clonedGroupResetTimeInfo->uuid() != originalGroup->uuid());
QVERIFY(clonedGroupResetTimeInfo->timeInfo().lastModificationTime() QVERIFY(clonedGroupResetTimeInfo->timeInfo().creationTime() != originalGroup->timeInfo().creationTime());
!= originalGroup->timeInfo().lastModificationTime()); QVERIFY(clonedGroupResetTimeInfo->timeInfo().lastAccessTime() != originalGroup->timeInfo().lastAccessTime());
QVERIFY(clonedGroupResetTimeInfo->timeInfo().locationChanged() != originalGroup->timeInfo().locationChanged());
QCOMPARE(clonedGroupResetTimeInfo->timeInfo().lastModificationTime(), originalGroup->timeInfo().lastModificationTime());
} }
void TestGroup::testCopyCustomIcons() void TestGroup::testCopyCustomIcons()
@ -1319,3 +1324,60 @@ void TestGroup::testAutoTypeState()
QVERIFY(!entry1->groupAutoTypeEnabled()); QVERIFY(!entry1->groupAutoTypeEnabled());
QVERIFY(entry2->groupAutoTypeEnabled()); QVERIFY(entry2->groupAutoTypeEnabled());
} }
void TestGroup::testTimeinfoChanges()
{
Database db, db2;
auto* root = db.rootGroup();
auto* subgroup1 = new Group();
auto* subgroup2 = new Group();
subgroup1->setUuid(QUuid::createUuid());
subgroup1->setParent(root);
subgroup2->setUuid(QUuid::createUuid());
subgroup2->setParent(root);
QDateTime startTime = Clock::currentDateTimeUtc();
TimeInfo startTimeinfo;
startTimeinfo.setCreationTime(startTime);
startTimeinfo.setLastModificationTime(startTime);
startTimeinfo.setLocationChanged(startTime);
startTimeinfo.setLastAccessTime(startTime);
m_clock->advanceMinute(1);
root->setTimeInfo(startTimeinfo);
subgroup1->setTimeInfo(startTimeinfo);
subgroup2->setTimeInfo(startTimeinfo);
subgroup2->setPreviousParentGroup(subgroup1);
// setting previous parent group should not affect the LastModificationTime
QCOMPARE(subgroup2->timeInfo().lastModificationTime(), startTime);
subgroup2->setPreviousParentGroup(nullptr);
subgroup2->setParent(subgroup1);
QCOMPARE(root->timeInfo(), startTimeinfo);
QCOMPARE(subgroup1->timeInfo(), startTimeinfo);
// changing group should not affect LastModificationTime, CreationTime
QCOMPARE(subgroup2->timeInfo().creationTime(), startTime);
QCOMPARE(subgroup2->timeInfo().lastModificationTime(), startTime);
// changing group should affect the LocationChanged time
QCOMPARE(subgroup2->timeInfo().locationChanged(), Clock::currentDateTimeUtc());
// cross-db move
db2.rootGroup()->setTimeInfo(startTimeinfo);
m_clock->advanceMinute(1);
subgroup2->setParent(db2.rootGroup());
QCOMPARE(subgroup2->timeInfo().creationTime(), startTime);
QCOMPARE(subgroup2->timeInfo().lastModificationTime(), startTime);
QCOMPARE(subgroup2->timeInfo().locationChanged(), Clock::currentDateTimeUtc());
QCOMPARE(db2.rootGroup()->timeInfo(), startTimeinfo);
QScopedPointer<Entry> entry1(new Entry());
entry1->setGroup(subgroup1);
// adding/removing an entry should not affect the LastModificationTime
QCOMPARE(subgroup1->timeInfo().lastModificationTime(), startTime);
entry1.reset(); // delete
QCOMPARE(subgroup1->timeInfo().lastModificationTime(), startTime);
// sorting should not affect the LastModificationTime
root->sortChildrenRecursively(true);
root->sortChildrenRecursively(false);
QCOMPARE(root->timeInfo().lastModificationTime(), startTime);
QCOMPARE(subgroup1->timeInfo().lastModificationTime(), startTime);
}

View file

@ -50,6 +50,7 @@ private slots:
void testMoveUpDown(); void testMoveUpDown();
void testPreviousParentGroup(); void testPreviousParentGroup();
void testAutoTypeState(); void testAutoTypeState();
void testTimeinfoChanges();
}; };
#endif // KEEPASSX_TESTGROUP_H #endif // KEEPASSX_TESTGROUP_H