mirror of
https://github.com/keepassxreboot/keepassxc.git
synced 2025-05-02 22:54:59 -04:00
Introduce synchronize merge method
* Create history-based merging that keeps older data in history instead of discarding or deleting it * Extract merge logic into the Merger class * Allows special merge behavior * Improve handling of deletion and changes on groups * Enable basic change tracking while merging * Prevent unintended timestamp changes while merging * Handle differences in timestamp precision * Introduce comparison operators to allow for more sophisticated comparisons (ignore special properties, ...) * Introduce Clock class to handle datetime across the app Merge Strategies: * Default (use inherited/fallback method) * Duplicate (duplicate conflicting nodes, apply all deletions) * KeepLocal (use local values, but apply all deletions) * KeepRemote (use remote values, but apply all deletions) * KeepNewer (merge history only) * Synchronize (merge history, newest value stays on top, apply all deletions)
This commit is contained in:
parent
b40e5686dc
commit
c1e9f45df9
43 changed files with 2777 additions and 585 deletions
|
@ -17,6 +17,7 @@
|
|||
|
||||
#include "TestKeePass2Format.h"
|
||||
#include "TestGlobal.h"
|
||||
#include "stub/TestClock.h"
|
||||
|
||||
#include "core/Metadata.h"
|
||||
#include "crypto/Crypto.h"
|
||||
|
@ -77,14 +78,14 @@ void TestKeePass2Format::testXmlMetadata()
|
|||
{
|
||||
QCOMPARE(m_xmlDb->metadata()->generator(), QString("KeePass"));
|
||||
QCOMPARE(m_xmlDb->metadata()->name(), QString("ANAME"));
|
||||
QCOMPARE(m_xmlDb->metadata()->nameChanged(), Test::datetime(2010, 8, 8, 17, 24, 53));
|
||||
QCOMPARE(m_xmlDb->metadata()->nameChanged(), TestClock::datetimeUtc(2010, 8, 8, 17, 24, 53));
|
||||
QCOMPARE(m_xmlDb->metadata()->description(), QString("ADESC"));
|
||||
QCOMPARE(m_xmlDb->metadata()->descriptionChanged(), Test::datetime(2010, 8, 8, 17, 27, 12));
|
||||
QCOMPARE(m_xmlDb->metadata()->descriptionChanged(), TestClock::datetimeUtc(2010, 8, 8, 17, 27, 12));
|
||||
QCOMPARE(m_xmlDb->metadata()->defaultUserName(), QString("DEFUSERNAME"));
|
||||
QCOMPARE(m_xmlDb->metadata()->defaultUserNameChanged(), Test::datetime(2010, 8, 8, 17, 27, 45));
|
||||
QCOMPARE(m_xmlDb->metadata()->defaultUserNameChanged(), TestClock::datetimeUtc(2010, 8, 8, 17, 27, 45));
|
||||
QCOMPARE(m_xmlDb->metadata()->maintenanceHistoryDays(), 127);
|
||||
QCOMPARE(m_xmlDb->metadata()->color(), QColor(0xff, 0xef, 0x00));
|
||||
QCOMPARE(m_xmlDb->metadata()->masterKeyChanged(), Test::datetime(2012, 4, 5, 17, 9, 34));
|
||||
QCOMPARE(m_xmlDb->metadata()->masterKeyChanged(), TestClock::datetimeUtc(2012, 4, 5, 17, 9, 34));
|
||||
QCOMPARE(m_xmlDb->metadata()->masterKeyChangeRec(), 101);
|
||||
QCOMPARE(m_xmlDb->metadata()->masterKeyChangeForce(), -1);
|
||||
QCOMPARE(m_xmlDb->metadata()->protectTitle(), false);
|
||||
|
@ -95,9 +96,9 @@ void TestKeePass2Format::testXmlMetadata()
|
|||
QCOMPARE(m_xmlDb->metadata()->recycleBinEnabled(), true);
|
||||
QVERIFY(m_xmlDb->metadata()->recycleBin() != nullptr);
|
||||
QCOMPARE(m_xmlDb->metadata()->recycleBin()->name(), QString("Recycle Bin"));
|
||||
QCOMPARE(m_xmlDb->metadata()->recycleBinChanged(), Test::datetime(2010, 8, 25, 16, 12, 57));
|
||||
QCOMPARE(m_xmlDb->metadata()->recycleBinChanged(), TestClock::datetimeUtc(2010, 8, 25, 16, 12, 57));
|
||||
QVERIFY(m_xmlDb->metadata()->entryTemplatesGroup() == nullptr);
|
||||
QCOMPARE(m_xmlDb->metadata()->entryTemplatesGroupChanged(), Test::datetime(2010, 8, 8, 17, 24, 19));
|
||||
QCOMPARE(m_xmlDb->metadata()->entryTemplatesGroupChanged(), TestClock::datetimeUtc(2010, 8, 8, 17, 24, 19));
|
||||
QVERIFY(m_xmlDb->metadata()->lastSelectedGroup() != nullptr);
|
||||
QCOMPARE(m_xmlDb->metadata()->lastSelectedGroup()->name(), QString("NewDatabase"));
|
||||
QVERIFY(m_xmlDb->metadata()->lastTopVisibleGroup() == m_xmlDb->metadata()->lastSelectedGroup());
|
||||
|
@ -135,13 +136,13 @@ void TestKeePass2Format::testXmlGroupRoot()
|
|||
QCOMPARE(group->iconUuid(), QUuid());
|
||||
QVERIFY(group->isExpanded());
|
||||
TimeInfo ti = group->timeInfo();
|
||||
QCOMPARE(ti.lastModificationTime(), Test::datetime(2010, 8, 8, 17, 24, 27));
|
||||
QCOMPARE(ti.creationTime(), Test::datetime(2010, 8, 7, 17, 24, 27));
|
||||
QCOMPARE(ti.lastAccessTime(), Test::datetime(2010, 8, 9, 9, 9, 44));
|
||||
QCOMPARE(ti.expiryTime(), Test::datetime(2010, 8, 8, 17, 24, 17));
|
||||
QCOMPARE(ti.lastModificationTime(), TestClock::datetimeUtc(2010, 8, 8, 17, 24, 27));
|
||||
QCOMPARE(ti.creationTime(), TestClock::datetimeUtc(2010, 8, 7, 17, 24, 27));
|
||||
QCOMPARE(ti.lastAccessTime(), TestClock::datetimeUtc(2010, 8, 9, 9, 9, 44));
|
||||
QCOMPARE(ti.expiryTime(), TestClock::datetimeUtc(2010, 8, 8, 17, 24, 17));
|
||||
QVERIFY(!ti.expires());
|
||||
QCOMPARE(ti.usageCount(), 52);
|
||||
QCOMPARE(ti.locationChanged(), Test::datetime(2010, 8, 8, 17, 24, 27));
|
||||
QCOMPARE(ti.locationChanged(), TestClock::datetimeUtc(2010, 8, 8, 17, 24, 27));
|
||||
QCOMPARE(group->defaultAutoTypeSequence(), QString(""));
|
||||
QCOMPARE(group->autoTypeEnabled(), Group::Inherit);
|
||||
QCOMPARE(group->searchingEnabled(), Group::Inherit);
|
||||
|
@ -202,13 +203,13 @@ void TestKeePass2Format::testXmlEntry1()
|
|||
QCOMPARE(entry->tags(), QString("a b c"));
|
||||
|
||||
const TimeInfo ti = entry->timeInfo();
|
||||
QCOMPARE(ti.lastModificationTime(), Test::datetime(2010, 8, 25, 16, 19, 25));
|
||||
QCOMPARE(ti.creationTime(), Test::datetime(2010, 8, 25, 16, 13, 54));
|
||||
QCOMPARE(ti.lastAccessTime(), Test::datetime(2010, 8, 25, 16, 19, 25));
|
||||
QCOMPARE(ti.expiryTime(), Test::datetime(2010, 8, 25, 16, 12, 57));
|
||||
QCOMPARE(ti.lastModificationTime(), TestClock::datetimeUtc(2010, 8, 25, 16, 19, 25));
|
||||
QCOMPARE(ti.creationTime(), TestClock::datetimeUtc(2010, 8, 25, 16, 13, 54));
|
||||
QCOMPARE(ti.lastAccessTime(), TestClock::datetimeUtc(2010, 8, 25, 16, 19, 25));
|
||||
QCOMPARE(ti.expiryTime(), TestClock::datetimeUtc(2010, 8, 25, 16, 12, 57));
|
||||
QVERIFY(!ti.expires());
|
||||
QCOMPARE(ti.usageCount(), 8);
|
||||
QCOMPARE(ti.locationChanged(), Test::datetime(2010, 8, 25, 16, 13, 54));
|
||||
QCOMPARE(ti.locationChanged(), TestClock::datetimeUtc(2010, 8, 25, 16, 13, 54));
|
||||
|
||||
QList<QString> attrs = entry->attributes()->keys();
|
||||
QCOMPARE(entry->attributes()->value("Notes"), QString("Notes"));
|
||||
|
@ -307,7 +308,7 @@ void TestKeePass2Format::testXmlEntryHistory()
|
|||
const Entry* entry = entryMain->historyItems().at(0);
|
||||
QCOMPARE(entry->uuid(), entryMain->uuid());
|
||||
QVERIFY(!entry->parent());
|
||||
QCOMPARE(entry->timeInfo().lastModificationTime(), Test::datetime(2010, 8, 25, 16, 13, 54));
|
||||
QCOMPARE(entry->timeInfo().lastModificationTime(), TestClock::datetimeUtc(2010, 8, 25, 16, 13, 54));
|
||||
QCOMPARE(entry->timeInfo().usageCount(), 3);
|
||||
QCOMPARE(entry->title(), QString("Sample Entry"));
|
||||
QCOMPARE(entry->url(), QString("http://www.somesite.com/"));
|
||||
|
@ -317,7 +318,7 @@ void TestKeePass2Format::testXmlEntryHistory()
|
|||
const Entry* entry = entryMain->historyItems().at(1);
|
||||
QCOMPARE(entry->uuid(), entryMain->uuid());
|
||||
QVERIFY(!entry->parent());
|
||||
QCOMPARE(entry->timeInfo().lastModificationTime(), Test::datetime(2010, 8, 25, 16, 15, 43));
|
||||
QCOMPARE(entry->timeInfo().lastModificationTime(), TestClock::datetimeUtc(2010, 8, 25, 16, 15, 43));
|
||||
QCOMPARE(entry->timeInfo().usageCount(), 7);
|
||||
QCOMPARE(entry->title(), QString("Sample Entry 1"));
|
||||
QCOMPARE(entry->url(), QString("http://www.somesite.com/"));
|
||||
|
@ -331,11 +332,11 @@ void TestKeePass2Format::testXmlDeletedObjects()
|
|||
|
||||
delObj = objList.takeFirst();
|
||||
QCOMPARE(delObj.uuid, QUuid::fromRfc4122(QByteArray::fromBase64("5K/bzWCSmkCv5OZxYl4N/w==")));
|
||||
QCOMPARE(delObj.deletionTime, Test::datetime(2010, 8, 25, 16, 14, 12));
|
||||
QCOMPARE(delObj.deletionTime, TestClock::datetimeUtc(2010, 8, 25, 16, 14, 12));
|
||||
|
||||
delObj = objList.takeFirst();
|
||||
QCOMPARE(delObj.uuid, QUuid::fromRfc4122(QByteArray::fromBase64("80h8uSNWgkKhKCp1TgXF7g==")));
|
||||
QCOMPARE(delObj.deletionTime, Test::datetime(2010, 8, 25, 16, 14, 14));
|
||||
QCOMPARE(delObj.deletionTime, TestClock::datetimeUtc(2010, 8, 25, 16, 14, 14));
|
||||
|
||||
QVERIFY(objList.isEmpty());
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue