refactor: remove unused merge methods

This commit is contained in:
louib 2023-08-06 16:37:51 -04:00 committed by Jonathan White
parent cc0530ba46
commit f7fd3881e3
6 changed files with 3 additions and 219 deletions

View File

@ -5615,22 +5615,6 @@ We recommend you use the AppImage available on our downloads page.</source>
<source>older entry merged from database &quot;%1&quot;</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Adding backup for older target %1 [%2]</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Adding backup for older source %1 [%2]</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Reapplying older target entry on top of newer source %1 [%2]</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Reapplying older source entry on top of newer target %1 [%2]</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Synchronizing from newer source %1 [%2]</source>
<translation type="unfinished"></translation>

View File

@ -39,9 +39,6 @@ public:
enum MergeMode
{
Default, // Determine merge strategy from parent or fallback (Synchronize)
Duplicate, // lossy strategy regarding deletions, duplicate older changes in a new entry
KeepLocal, // merge history forcing local as top regardless of age
KeepRemote, // merge history forcing remote as top regardless of age
KeepNewer, // merge history
Synchronize, // merge history keeping most recent as top entry and applying deletions
};

View File

@ -257,76 +257,6 @@ void Merger::eraseGroup(Group* group)
database->setDeletedObjects(deletions);
}
Merger::ChangeList
Merger::resolveEntryConflict_Duplicate(const MergeContext& context, const Entry* sourceEntry, Entry* targetEntry)
{
ChangeList changes;
const int comparison = compare(targetEntry->timeInfo().lastModificationTime(),
sourceEntry->timeInfo().lastModificationTime(),
CompareItemIgnoreMilliseconds);
// if one entry is newer, create a clone and add it to the group
if (comparison < 0) {
Entry* clonedEntry = sourceEntry->clone(Entry::CloneNewUuid | Entry::CloneIncludeHistory);
moveEntry(clonedEntry, context.m_targetGroup);
markOlderEntry(targetEntry);
changes << tr("Adding backup for older target %1 [%2]").arg(targetEntry->title(), targetEntry->uuidToHex());
} else if (comparison > 0) {
Entry* clonedEntry = sourceEntry->clone(Entry::CloneNewUuid | Entry::CloneIncludeHistory);
moveEntry(clonedEntry, context.m_targetGroup);
markOlderEntry(clonedEntry);
changes << tr("Adding backup for older source %1 [%2]").arg(sourceEntry->title(), sourceEntry->uuidToHex());
}
return changes;
}
Merger::ChangeList
Merger::resolveEntryConflict_KeepLocal(const MergeContext& context, const Entry* sourceEntry, Entry* targetEntry)
{
Q_UNUSED(context);
ChangeList changes;
const int comparison = compare(targetEntry->timeInfo().lastModificationTime(),
sourceEntry->timeInfo().lastModificationTime(),
CompareItemIgnoreMilliseconds);
if (comparison < 0) {
// we need to make our older entry "newer" than the new entry - therefore
// we just create a new history entry without any changes - this preserves
// the old state before merging the new state and updates the timestamp
// the merge takes care, that the newer entry is sorted inbetween both entries
// this type of merge changes the database timestamp since reapplying the
// old entry is an active change of the database!
changes << tr("Reapplying older target entry on top of newer source %1 [%2]")
.arg(targetEntry->title(), targetEntry->uuidToHex());
Entry* agedTargetEntry = targetEntry->clone(Entry::CloneNoFlags);
targetEntry->addHistoryItem(agedTargetEntry);
}
return changes;
}
Merger::ChangeList
Merger::resolveEntryConflict_KeepRemote(const MergeContext& context, const Entry* sourceEntry, Entry* targetEntry)
{
Q_UNUSED(context);
ChangeList changes;
const int comparison = compare(targetEntry->timeInfo().lastModificationTime(),
sourceEntry->timeInfo().lastModificationTime(),
CompareItemIgnoreMilliseconds);
if (comparison > 0) {
// we need to make our older entry "newer" than the new entry - therefore
// we just create a new history entry without any changes - this preserves
// the old state before merging the new state and updates the timestamp
// the merge takes care, that the newer entry is sorted inbetween both entries
// this type of merge changes the database timestamp since reapplying the
// old entry is an active change of the database!
changes << tr("Reapplying older source entry on top of newer target %1 [%2]")
.arg(targetEntry->title(), targetEntry->uuidToHex());
targetEntry->beginUpdate();
targetEntry->copyDataFrom(sourceEntry);
targetEntry->endUpdate();
// History item is created by endUpdate since we should have changes
}
return changes;
}
Merger::ChangeList Merger::resolveEntryConflict_MergeHistories(const MergeContext& context,
const Entry* sourceEntry,
Entry* targetEntry,
@ -366,38 +296,12 @@ Merger::ChangeList Merger::resolveEntryConflict_MergeHistories(const MergeContex
Merger::ChangeList
Merger::resolveEntryConflict(const MergeContext& context, const Entry* sourceEntry, Entry* targetEntry)
{
ChangeList changes;
// We need to cut off the milliseconds since the persistent format only supports times down to seconds
// so when we import data from a remote source, it may represent the (or even some msec newer) data
// which may be discarded due to higher runtime precision
Group::MergeMode mergeMode = m_mode == Group::Default ? context.m_targetGroup->mergeMode() : m_mode;
switch (mergeMode) {
case Group::Duplicate:
changes << resolveEntryConflict_Duplicate(context, sourceEntry, targetEntry);
break;
case Group::KeepLocal:
changes << resolveEntryConflict_KeepLocal(context, sourceEntry, targetEntry);
changes << resolveEntryConflict_MergeHistories(context, sourceEntry, targetEntry, mergeMode);
break;
case Group::KeepRemote:
changes << resolveEntryConflict_KeepRemote(context, sourceEntry, targetEntry);
changes << resolveEntryConflict_MergeHistories(context, sourceEntry, targetEntry, mergeMode);
break;
case Group::Synchronize:
case Group::KeepNewer:
// nothing special to do since resolveEntryConflictMergeHistories takes care to use the newest entry
changes << resolveEntryConflict_MergeHistories(context, sourceEntry, targetEntry, mergeMode);
break;
default:
// do nothing
break;
}
return changes;
return resolveEntryConflict_MergeHistories(context, sourceEntry, targetEntry, mergeMode);
}
bool Merger::mergeHistory(const Entry* sourceEntry, Entry* targetEntry, Group::MergeMode mergeMethod)
@ -408,8 +312,8 @@ bool Merger::mergeHistory(const Entry* sourceEntry, Entry* targetEntry, Group::M
const int comparison = compare(sourceEntry->timeInfo().lastModificationTime(),
targetEntry->timeInfo().lastModificationTime(),
CompareItemIgnoreMilliseconds);
const bool preferLocal = mergeMethod == Group::KeepLocal || comparison < 0;
const bool preferRemote = mergeMethod == Group::KeepRemote || comparison > 0;
const bool preferLocal = comparison < 0;
const bool preferRemote = comparison > 0;
QMap<QDateTime, Entry*> merged;
for (Entry* historyItem : targetHistoryItems) {

View File

@ -59,12 +59,6 @@ private:
void eraseGroup(Group* group);
ChangeList resolveEntryConflict(const MergeContext& context, const Entry* existingEntry, Entry* otherEntry);
ChangeList resolveGroupConflict(const MergeContext& context, const Group* existingGroup, Group* otherGroup);
Merger::ChangeList
resolveEntryConflict_Duplicate(const MergeContext& context, const Entry* sourceEntry, Entry* targetEntry);
Merger::ChangeList
resolveEntryConflict_KeepLocal(const MergeContext& context, const Entry* sourceEntry, Entry* targetEntry);
Merger::ChangeList
resolveEntryConflict_KeepRemote(const MergeContext& context, const Entry* sourceEntry, Entry* targetEntry);
Merger::ChangeList resolveEntryConflict_MergeHistories(const MergeContext& context,
const Entry* sourceEntry,
Entry* targetEntry,

View File

@ -29,13 +29,6 @@ QTEST_GUILESS_MAIN(TestMerge)
namespace
{
TimeInfo modificationTime(TimeInfo timeInfo, int years, int months, int days)
{
const QDateTime time = timeInfo.lastModificationTime();
timeInfo.setLastModificationTime(time.addYears(years).addMonths(months).addDays(days));
return timeInfo;
}
MockClock* m_clock = nullptr;
} // namespace
@ -258,50 +251,6 @@ void TestMerge::testResolveConflictExisting()
}
}
/**
* Tests the KeepBoth merge mode.
*/
void TestMerge::testResolveConflictDuplicate()
{
QScopedPointer<Database> dbDestination(createTestDatabase());
QScopedPointer<Database> dbSource(
createTestDatabaseStructureClone(dbDestination.data(), Entry::CloneIncludeHistory, Group::CloneIncludeEntries));
// sanity check
QCOMPARE(dbDestination->rootGroup()->children().at(0)->entries().size(), 2);
// make this entry newer than in original db
QPointer<Entry> updatedDestinationEntry = dbDestination->rootGroup()->children().at(0)->entries().at(0);
const TimeInfo initialEntryTimeInfo = updatedDestinationEntry->timeInfo();
const TimeInfo updatedEntryTimeInfo = modificationTime(initialEntryTimeInfo, 1, 0, 0);
updatedDestinationEntry->setTimeInfo(updatedEntryTimeInfo);
dbDestination->rootGroup()->setMergeMode(Group::MergeMode::Duplicate);
// Make sure the merge changes have a different timestamp.
m_clock->advanceSecond(1);
Merger merger(dbSource.data(), dbDestination.data());
merger.merge();
// one entry is duplicated because of mode
QCOMPARE(dbDestination->rootGroup()->children().at(0)->entries().size(), 3);
QCOMPARE(dbDestination->rootGroup()->children().at(0)->entries().at(0)->historyItems().isEmpty(), false);
// the older entry was merged from the other db as last in the group
QPointer<Entry> newerEntry = dbDestination->rootGroup()->children().at(0)->entries().at(0);
QPointer<Entry> olderEntry = dbDestination->rootGroup()->children().at(0)->entries().at(2);
QVERIFY(newerEntry->title() == olderEntry->title());
QVERIFY2(!newerEntry->attributes()->hasKey("merged"), "newer entry is not marked with an attribute \"merged\"");
QVERIFY2(olderEntry->attributes()->hasKey("merged"), "older entry is marked with an attribute \"merged\"");
QCOMPARE(olderEntry->historyItems().isEmpty(), false);
QCOMPARE(newerEntry->timeInfo(), updatedEntryTimeInfo);
// TODO HNH: this may be subject to discussions since the entry itself is newer but represents an older one
// QCOMPARE(olderEntry->timeInfo(), initialEntryTimeInfo);
QVERIFY2(olderEntry->uuidToHex() != updatedDestinationEntry->uuidToHex(),
"KeepBoth should not reuse the UUIDs when cloning.");
}
void TestMerge::testResolveConflictTemplate(
int mergeMode,
std::function<void(Database*, const QMap<const char*, QDateTime>&)> verification)
@ -733,26 +682,11 @@ void TestMerge::testDeletionConflictEntry_Synchronized()
testDeletionConflictTemplate(Group::Synchronize, &TestMerge::assertDeletionNewerOnly);
}
void TestMerge::testDeletionConflictEntry_KeepLocal()
{
testDeletionConflictTemplate(Group::KeepLocal, &TestMerge::assertDeletionLocalOnly);
}
void TestMerge::testDeletionConflictEntry_KeepRemote()
{
testDeletionConflictTemplate(Group::KeepRemote, &TestMerge::assertDeletionLocalOnly);
}
void TestMerge::testDeletionConflictEntry_KeepNewer()
{
testDeletionConflictTemplate(Group::KeepNewer, &TestMerge::assertDeletionLocalOnly);
}
void TestMerge::testDeletionConflictEntry_Duplicate()
{
testDeletionConflictTemplate(Group::Duplicate, &TestMerge::assertDeletionLocalOnly);
}
/**
* Tests the KeepNewer mode concerning history.
*/
@ -766,29 +700,6 @@ void TestMerge::testResolveConflictEntry_Synchronize()
});
}
/**
* Tests the KeepExisting mode concerning history.
*/
void TestMerge::testResolveConflictEntry_KeepLocal()
{
testResolveConflictTemplate(Group::KeepLocal, [](Database* db, const QMap<const char*, QDateTime>& timestamps) {
QPointer<Group> mergedRootGroup = db->rootGroup();
QPointer<Group> mergedGroup1 = mergedRootGroup->children().at(0);
TestMerge::assertUpdateMergedEntry1(mergedGroup1->entries().at(0), timestamps);
TestMerge::assertUpdateReappliedEntry2(mergedGroup1->entries().at(1), timestamps);
});
}
void TestMerge::testResolveConflictEntry_KeepRemote()
{
testResolveConflictTemplate(Group::KeepRemote, [](Database* db, const QMap<const char*, QDateTime>& timestamps) {
QPointer<Group> mergedRootGroup = db->rootGroup();
QPointer<Group> mergedGroup1 = mergedRootGroup->children().at(0);
TestMerge::assertUpdateReappliedEntry1(mergedGroup1->entries().at(0), timestamps);
TestMerge::assertUpdateMergedEntry2(mergedGroup1->entries().at(1), timestamps);
});
}
void TestMerge::testResolveConflictEntry_KeepNewer()
{
testResolveConflictTemplate(Group::KeepNewer, [](Database* db, const QMap<const char*, QDateTime>& timestamps) {

View File

@ -35,15 +35,9 @@ private slots:
void testResolveGroupConflictOlder();
void testMergeNotModified();
void testMergeModified();
void testResolveConflictDuplicate();
void testResolveConflictEntry_Synchronize();
void testResolveConflictEntry_KeepLocal();
void testResolveConflictEntry_KeepRemote();
void testResolveConflictEntry_KeepNewer();
void testDeletionConflictEntry_Duplicate();
void testDeletionConflictEntry_Synchronized();
void testDeletionConflictEntry_KeepLocal();
void testDeletionConflictEntry_KeepRemote();
void testDeletionConflictEntry_KeepNewer();
void testMoveEntry();
void testMoveEntryPreserveChanges();