void OneSideStrategy::resolveConflict(const MergeTask& task, Key& conflictKey, MergeResult& result) { string lookupPath; Key winningKey; switch (winningSide) { case BASE: lookupPath = rebasePath (conflictKey, task.mergeRoot, task.baseParent); winningKey = task.base.lookup(lookupPath); break; case OURS: lookupPath = rebasePath (conflictKey, task.mergeRoot, task.ourParent); winningKey = task.ours.lookup(lookupPath); break; case THEIRS: lookupPath = rebasePath (conflictKey, task.mergeRoot, task.theirParent); winningKey = task.theirs.lookup(lookupPath); break; } if (winningKey) { conflictKey.setString(winningKey.getString()); result.resolveConflict(conflictKey); result.addMergeKey(conflictKey); } else { result.resolveConflict(conflictKey); result.removeMergeKey(conflictKey); } }
void NewKeyStrategy::resolveConflict (const MergeTask & task, Key & conflictKey, MergeResult & result) { ConflictOperation ourOperation = getOurConflictOperation (conflictKey); ConflictOperation theirOperation = getTheirConflictOperation (conflictKey); string ourLookup = rebasePath (conflictKey, task.mergeRoot, task.ourParent); string theirLookup = rebasePath (conflictKey, task.mergeRoot, task.theirParent); // TODO: this is a subset of the automergestrategy // the automergestrategy could be split up into several smaller strategies switch (ourOperation) { case CONFLICT_SAME: if (theirOperation == CONFLICT_ADD) { Key source = task.theirs.lookup (theirLookup); copyKeyValue (source, conflictKey); result.resolveConflict (conflictKey); result.addMergeKey (conflictKey); } break; case CONFLICT_ADD: if (theirOperation == CONFLICT_SAME) { Key source = task.ours.lookup (ourLookup); copyKeyValue (source, conflictKey); result.resolveConflict (conflictKey); result.addMergeKey (conflictKey); } break; default: break; } }
void AutoMergeStrategy::resolveConflict(const MergeTask& task, Key& conflictKey, MergeResult& result) { ConflictOperation ourOperation = getOurConflictOperation(conflictKey); ConflictOperation theirOperation = getTheirConflictOperation(conflictKey); string ourLookup = rebasePath (conflictKey, task.mergeRoot, task.ourParent); string theirLookup = rebasePath (conflictKey, task.mergeRoot, task.theirParent); switch (ourOperation) { case SAME: if (theirOperation == MODIFY || theirOperation == ADD) { Key source = task.theirs.lookup(theirLookup); conflictKey.setString(source.getString()); result.resolveConflict(conflictKey); result.addMergeKey(conflictKey); } if (theirOperation == DELETE) { result.resolveConflict(conflictKey); } break; case MODIFY: case ADD: if (theirOperation == SAME) { Key source = task.ours.lookup(ourLookup); conflictKey.setString(source.getString()); result.resolveConflict(conflictKey); result.addMergeKey(conflictKey); } break; case DELETE: if (theirOperation == SAME) { result.resolveConflict(conflictKey); } break; case META: break; } }
TEST (MergeResult, ResolveConflictIgnoresOtherMeta) { MergeResult result; Key conflictKey = Key ("user/test/config/key1", KEY_VALUE, "testvalue", KEY_META, "order", "10", KEY_META, "noconflict/data", "testvalue", KEY_END); result.resolveConflict (conflictKey); EXPECT_EQ ("10", conflictKey.getMeta<string> ("order")); EXPECT_EQ ("testvalue", conflictKey.getMeta<string> ("noconflict/data")); }
TEST (MergeResult, ResolveConflictRemovesKeyFromConflicts) { Key conflictKey = Key ("user/test/config/key1", KEY_VALUE, "testvalue", KEY_END); KeySet conflicts; conflicts.append (conflictKey); KeySet merged; MergeResult result (conflicts, merged); result.resolveConflict (conflictKey); EXPECT_EQ (0, result.getConflictSet ().size ()); }
void MetaMergeStrategy::resolveConflict(const MergeTask& task, Key& conflictKey, MergeResult& result) { conflictKey.rewindMeta(); Key currentMeta; string baseLookup = rebasePath (conflictKey, task.mergeRoot, task.baseParent); string ourLookup = rebasePath (conflictKey, task.mergeRoot, task.ourParent); string theirLookup = rebasePath (conflictKey, task.mergeRoot, task.theirParent); Key baseKey = task.base.lookup(baseLookup); Key ourKey = task.ours.lookup(ourLookup); Key theirKey = task.theirs.lookup(theirLookup); Key root ("user/", KEY_END); KeySet baseMeta = getMetaKeys (baseKey); KeySet ourMeta = getMetaKeys (ourKey); KeySet theirMeta = getMetaKeys (theirKey); MergeTask metaTask(BaseMergeKeys (baseMeta, root), OurMergeKeys (ourMeta, root), TheirMergeKeys (theirMeta, root), root); MergeResult metaResult = innerMerger.mergeKeySet(metaTask); KeySet mergedMeta = metaResult.getMergedKeys(); Key current; mergedMeta.rewind(); while ((current = mergedMeta.next())) { string metaName = current.getName().substr(string("user/").length()); conflictKey.setMeta(metaName, current.getString()); } ConflictOperation ourOperation = getOurConflictOperation(conflictKey); ConflictOperation theirOperation = getTheirConflictOperation(conflictKey); if (!metaResult.hasConflicts ()) { if (ourOperation == CONFLICT_META && theirOperation == CONFLICT_META) { // TODO: addConflict deletes the key content // without this strategy restoring the value the value would be lost // this happens only for CONFLICT_META <--> CONFLICT_META conflicts // add a test for this behaviour copyKeyValue(ourKey, conflictKey); result.resolveConflict (conflictKey); result.addMergeKey (conflictKey); } } }
TEST (MergeResult, CountsResolvedKeysCorrectly) { Key conflictKey1 = Key ("user/test/config/key1", KEY_END); Key conflictKey2 = Key ("user/test/config/key2", KEY_END); KeySet conflicts; conflicts.append (conflictKey1); conflicts.append (conflictKey2); KeySet merged; MergeResult result (conflicts, merged); EXPECT_EQ (0, result.getNumberOfResolvedKeys ()); result.resolveConflict (conflictKey1); result.resolveConflict (conflictKey2); EXPECT_EQ (2, result.getNumberOfResolvedKeys ()); }
TEST (MergeResult, ResolveConflictDeletesConflictMeta) { MergeResult result; Key conflictKey = Key ("user/test/config/key1", KEY_VALUE, "testvalue", KEY_META, "conflict/operation/our", "delete", KEY_META, "conflict/operation/their", "modify", KEY_META, "conflict/test", "testvalue", KEY_END); Key test = Key ("", KEY_END); result.resolveConflict (conflictKey); EXPECT_FALSE (conflictKey.getMeta<const Key> ("conflict/operation/our")); EXPECT_FALSE (conflictKey.getMeta<const Key> ("conflict/operation/their")); EXPECT_FALSE (conflictKey.getMeta<const Key> ("conflict/test")); }
TEST (MergeResult, CountsEqualKeysCorrectly) { Key mergedKey1 = Key ("user/test/config/key1", KEY_END); Key mergedKey2 = Key ("user/test/config/key2", KEY_END); Key mergedKey3 = Key ("user/test/config/key3", KEY_END); Key conflictKey1 = Key ("user/test/config/key4", KEY_END); KeySet conflicts; conflicts.append (conflictKey1); KeySet merged; merged.append (mergedKey1); merged.append (mergedKey2); MergeResult result (conflicts, merged); EXPECT_EQ (2, result.getNumberOfEqualKeys ()) << "Initially merged keys not counted"; result.resolveConflict (conflictKey1); result.addMergeKey (conflictKey1); EXPECT_EQ (2, result.getNumberOfEqualKeys ()) << "Resolved key is counted as equal key"; result.addMergeKey (mergedKey3); EXPECT_EQ (3, result.getNumberOfEqualKeys ()) << "Merged key is not counted as equal key"; }
void OneSideValueStrategy::resolveConflict(const MergeTask& task, Key& conflictKey, MergeResult& result) { ConflictOperation ourOperation = getOurConflictOperation (conflictKey); ConflictOperation theirOperation = getTheirConflictOperation (conflictKey); string ourLookup = rebasePath (conflictKey, task.mergeRoot, task.ourParent); string theirLookup = rebasePath (conflictKey, task.mergeRoot, task.theirParent); // TODO: this is a subset of the onesidestrategy // the onesidestrategy could be split up into several smaller strategies if ((ourOperation == CONFLICT_SAME && theirOperation == CONFLICT_MODIFY) || (ourOperation == CONFLICT_MODIFY && theirOperation == CONFLICT_SAME)) { string lookupPath; Key winningKey; switch (winningSide) { case BASE: lookupPath = rebasePath (conflictKey, task.mergeRoot, task.baseParent); winningKey = task.base.lookup (lookupPath); break; case OURS: lookupPath = rebasePath (conflictKey, task.mergeRoot, task.ourParent); winningKey = task.ours.lookup (lookupPath); break; case THEIRS: lookupPath = rebasePath (conflictKey, task.mergeRoot, task.theirParent); winningKey = task.theirs.lookup (lookupPath); break; } if (winningKey) { conflictKey.setString (winningKey.getString ()); result.resolveConflict (conflictKey); result.addMergeKey (conflictKey); } } }