public void BothAddedMainItemButWithDifferentContentHasOneConflictReport() { const string ancestor = @"<?xml version='1.0' encoding='utf-8'?> <lift version='0.10' producer='WeSay 1.0.0.0'> <entry id='noChangesInEither' guid='c1ed1f9d-e382-11de-8a39-0800200c9a66' /> </lift>"; const string ours = @"<?xml version='1.0' encoding='utf-8'?> <lift version='0.10' producer='WeSay 1.0.0.0'> <entry id='noChangesInEither' guid='c1ed1f9d-e382-11de-8a39-0800200c9a66' /> <entry id='addedByBoth' guid='c1ed1f9e-e382-11de-8a39-0800200c9a66' > <sense id='somesense'> <gloss lang='a'> <text>editedByUs</text> </gloss> </sense> </entry> </lift>"; const string theirs = @"<?xml version='1.0' encoding='utf-8'?> <lift version='0.10' producer='WeSay 1.0.0.0'> <entry id='noChangesInEither' guid='c1ed1f9d-e382-11de-8a39-0800200c9a66' /> <entry id='addedByBoth' guid='c1ed1f9e-e382-11de-8a39-0800200c9a66' > <sense id='somesense'> <gloss lang='a'> <text>editedByThem</text> </gloss> </sense> </entry> </lift>"; // We win merge situation. MergeSituation mergeSit = new NullMergeSituation(); DoMergeWithLiftEntryMergingStrategy(ancestor, ours, theirs, mergeSit, new[] { "lift/entry[@id='addedByBoth']/sense/gloss/text[text()='editedByUs']" }, new[] { "lift/entry[@id='addedByBoth']/sense/gloss/text[text()='editedByThem']" }, 1, new List<Type> { typeof(XmlTextBothAddedTextConflict) }, 4, new List<Type> { typeof(XmlAttributeBothAddedReport), typeof(XmlAttributeBothAddedReport), typeof(XmlAttributeBothAddedReport), typeof(XmlAttributeBothAddedReport) }); // They win merge situation. mergeSit = new NullMergeSituationTheyWin(); DoMergeWithLiftEntryMergingStrategy(ancestor, ours, theirs, mergeSit, new[] { "lift/entry[@id='addedByBoth']/sense/gloss/text[text()='editedByThem']" }, new[] { "lift/entry[@id='addedByBoth']/sense/gloss/text[text()='editedByUs']" }, 1, new List<Type> { typeof(XmlTextBothAddedTextConflict) }, 4, new List<Type> { typeof(XmlAttributeBothAddedReport), typeof(XmlAttributeBothAddedReport), typeof(XmlAttributeBothAddedReport), typeof(XmlAttributeBothAddedReport) }); }
public void BothEditedFoo_WithEditVsDeleteOfBar_AndNoChangesToDull_ProducesTwoConflictRreports() { const string ancestor = @"<?xml version='1.0' encoding='utf-8'?> <lift version='0.13' producer='WeSay 1.0.0.0'> <entry id='dull' guid='C1EDBBDE-E382-11DE-8A39-0800200C9A66'> <lexical-unit> <form lang='en'> <text>dull</text> </form> </lexical-unit> </entry> <entry id='foo' guid='C1EDBBDF-E382-11DE-8A39-0800200C9A66'> <lexical-unit> <form lang='en'> <text>foo</text> </form> </lexical-unit> </entry> <entry id='bar' guid='C1EDBBE0-E382-11DE-8A39-0800200C9A66'> <lexical-unit> <form lang='en'> <text>bar</text> </form> </lexical-unit> </entry> </lift>"; const string ours = @"<?xml version='1.0' encoding='utf-8'?> <lift version='0.13' producer='WeSay 1.0.0.0'> <entry id='dull' guid='C1EDBBDE-E382-11DE-8A39-0800200C9A66'> <lexical-unit> <form lang='en'> <text>dull</text> </form> </lexical-unit> </entry> <entry id='foo' guid='C1EDBBDF-E382-11DE-8A39-0800200C9A66'> <lexical-unit> <form lang='en'> <text>ourfoo</text> </form> </lexical-unit> </entry> <entry id='bar' guid='C1EDBBE0-E382-11DE-8A39-0800200C9A66'> <lexical-unit> <form lang='en'> <text>mybar</text> </form> </lexical-unit> </entry> </lift>"; const string theirs = @"<?xml version='1.0' encoding='utf-8'?> <lift version='0.13' producer='WeSay 1.0.0.0'> <entry id='dull' guid='C1EDBBDE-E382-11DE-8A39-0800200C9A66'> <lexical-unit> <form lang='en'> <text>dull</text> </form> </lexical-unit> </entry> <entry id='foo' guid='C1EDBBDF-E382-11DE-8A39-0800200C9A66'> <lexical-unit> <form lang='en'> <text>theirfoo</text> </form> </lexical-unit> </entry> </lift>"; // This tests: http://jira.palaso.org/issues/browse/CHR-13 // In a test where all I did was an edited vs. delete test, the resulting conflict note listed the element as "unknown". // In a test where all I both a) had both parties edit the same field on record A and b) had parties edit vs. delete record B, the all resulting conflict notes were attached to A. using (var oursTemp = new TempFile(ours)) using (var theirsTemp = new TempFile(theirs)) using (var ancestorTemp = new TempFile(ancestor)) { // 'We' (O) are set to win. // Both edited foo: O should win. // O edited bar, T deleted it. O should win. var listener = new ListenerForUnitTests(); var situation = new NullMergeSituation { AlphaUserId = "O", BetaUserId = "T" }; var mergeOrder = new MergeOrder(oursTemp.Path, ancestorTemp.Path, theirsTemp.Path, situation) { EventListener = listener }; XmlMergeService.Do3WayMerge(mergeOrder, new LiftEntryMergingStrategy(mergeOrder), false, "header", "entry", "guid"); var result = File.ReadAllText(mergeOrder.pathToOurs); XmlTestHelper.AssertXPathMatchesExactlyOne(result, "lift/entry[@id='dull']"); XmlTestHelper.AssertXPathMatchesExactlyOne(result, "lift/entry[@id='foo']/lexical-unit/form/text[text()='ourfoo']"); XmlTestHelper.AssertXPathMatchesExactlyOne(result, "lift/entry[@id='bar']"); Assert.AreEqual(2, listener.Conflicts.Count); var firstConflict = listener.Conflicts[0]; var secondConflict = listener.Conflicts[1]; Assert.AreEqual(typeof(XmlTextBothEditedTextConflict), firstConflict.GetType()); Assert.AreEqual(typeof(EditedVsRemovedElementConflict), secondConflict.GetType()); // Doesn't work with ListenerForUnitTests, as ListenerForUnitTests doesn't set the Context on the conflict, as does the Chorus notes listener. //var annotationXml = XmlTestHelper.WriteConflictAnnotation(firstConflict); //var annotationXml = XmlTestHelper.WriteConflictAnnotation(secondConflict); } using (var oursTemp = new TempFile(ours)) using (var theirsTemp = new TempFile(theirs)) using (var ancestorTemp = new TempFile(ancestor)) { // 'They' (T) are set to win. // Both edited foo: 'T' should win // O edited bar, T deleted it. O should win. var listener = new ListenerForUnitTests(); var situation = new NullMergeSituationTheyWin { AlphaUserId = "O", BetaUserId = "T" }; var mergeOrder = new MergeOrder(oursTemp.Path, ancestorTemp.Path, theirsTemp.Path, situation) { EventListener = listener }; XmlMergeService.Do3WayMerge(mergeOrder, new LiftEntryMergingStrategy(mergeOrder), false, "header", "entry", "guid"); var result = File.ReadAllText(mergeOrder.pathToOurs); XmlTestHelper.AssertXPathMatchesExactlyOne(result, "lift/entry[@id='dull']"); XmlTestHelper.AssertXPathMatchesExactlyOne(result, "lift/entry[@id='foo']/lexical-unit/form/text[text()='theirfoo']"); XmlTestHelper.AssertXPathMatchesExactlyOne(result, "lift/entry[@id='bar']"); Assert.AreEqual(2, listener.Conflicts.Count); var firstConflict = listener.Conflicts[0]; var secondConflict = listener.Conflicts[1]; Assert.AreEqual(typeof(XmlTextBothEditedTextConflict), firstConflict.GetType()); Assert.AreEqual(typeof(RemovedVsEditedElementConflict), secondConflict.GetType()); // Doesn't work with ListenerForUnitTests, as ListenerForUnitTests doesn't set the Context on the conflict, as does the Chorus notes listener. //var annotationXml = XmlTestHelper.WriteConflictAnnotation(firstConflict); //var annotationXml = XmlTestHelper.WriteConflictAnnotation(secondConflict); } }
public void WeEditedMainItemSenseGlossTheyDidNothingHasNoReports() { // New Style means the deleted entry was really removed from the file, not just marked as deleted. const string ancestor = @"<?xml version='1.0' encoding='utf-8'?> <lift version='0.10' producer='WeSay 1.0.0.0'> <entry id='noChangesInEither' guid='c1ed1f9d-e382-11de-8a39-0800200c9a66' /> <entry id='oneEdited' guid='c1ed1f9e-e382-11de-8a39-0800200c9a66' > <sense> <gloss lang='a'> <text>original</text> </gloss> </sense> </entry> </lift>"; const string ours = @"<?xml version='1.0' encoding='utf-8'?> <lift version='0.10' producer='WeSay 1.0.0.0'> <entry id='noChangesInEither' guid='c1ed1f9d-e382-11de-8a39-0800200c9a66' /> <entry id='oneEdited' guid='c1ed1f9e-e382-11de-8a39-0800200c9a66' > <sense> <gloss lang='a'> <text>ourNewGloss</text> </gloss> </sense> </entry> </lift>"; const string theirs = @"<?xml version='1.0' encoding='utf-8'?> <lift version='0.10' producer='WeSay 1.0.0.0'> <entry id='noChangesInEither' guid='c1ed1f9d-e382-11de-8a39-0800200c9a66' /> <entry id='oneEdited' guid='c1ed1f9e-e382-11de-8a39-0800200c9a66' > <sense> <gloss lang='a'> <text>original</text> </gloss> </sense> </entry> </lift>"; // We win merge situation. MergeSituation mergeSit = new NullMergeSituation(); DoMergeWithLiftEntryMergingStrategy(ancestor, ours, theirs, mergeSit, new[] { "lift/entry[@id='oneEdited']/sense/gloss/text[text()='ourNewGloss']" }, new[] { "lift/entry[@id='oneEdited']/sense/gloss/text[text()='original']" }, 0, null, 0, null); // They win merge situation. mergeSit = new NullMergeSituationTheyWin(); DoMergeWithLiftEntryMergingStrategy(ancestor, ours, theirs, mergeSit, new[] { "lift/entry[@id='oneEdited']/sense/gloss/text[text()='ourNewGloss']" }, new[] { "lift/entry[@id='oneEdited']/sense/gloss/text[text()='original']" }, 0, null, 0, null); }
public void TheyEditedOptionalFirstElementHasNoReports() { const string ancestor = @"<?xml version='1.0' encoding='utf-8'?> <lift version='0.10' producer='WeSay 1.0.0.0'> <header id='originalHeader'/> <entry id='noChangesInEither' guid='c1ed1f9d-e382-11de-8a39-0800200c9a66' /> </lift>"; const string ours = @"<?xml version='1.0' encoding='utf-8'?> <lift version='0.10' producer='WeSay 1.0.0.0'> <header id='originalHeader'/> <entry id='noChangesInEither' guid='c1ed1f9d-e382-11de-8a39-0800200c9a66' /> </lift>"; const string theirs = @"<?xml version='1.0' encoding='utf-8'?> <lift version='0.10' producer='WeSay 1.0.0.0'> <header id='theirNewHeader'/> <entry id='noChangesInEither' guid='c1ed1f9d-e382-11de-8a39-0800200c9a66' /> </lift>"; // We win merge situation. MergeSituation mergeSit = new NullMergeSituation(); DoMergeWithLiftEntryMergingStrategy(ancestor, ours, theirs, mergeSit, new[] { "lift/header[@id='theirNewHeader']", "lift/entry[@id='noChangesInEither']" }, null, 0, null, 0, null); // They win merge situation. mergeSit = new NullMergeSituationTheyWin(); DoMergeWithLiftEntryMergingStrategy(ancestor, ours, theirs, mergeSit, new[] { "lift/header[@id='theirNewHeader']", "lift/entry[@id='noChangesInEither']" }, null, 0, null, 0, null); }
public void OnlyOneDeletedMainItemHasNoChangeReport() { const string ancestor = @"<?xml version='1.0' encoding='utf-8'?> <lift version='0.10' producer='WeSay 1.0.0.0'> <entry id='noChangesInEither' guid='c1ed1f9d-e382-11de-8a39-0800200c9a66' /> <entry id='onlyOneDeleted' guid='c1ed1f9e-e382-11de-8a39-0800200c9a66' /> </lift>"; const string ours = @"<?xml version='1.0' encoding='utf-8'?> <lift version='0.10' producer='WeSay 1.0.0.0'> <entry id='noChangesInEither' guid='c1ed1f9d-e382-11de-8a39-0800200c9a66' /> </lift>"; const string theirs = @"<?xml version='1.0' encoding='utf-8'?> <lift version='0.10' producer='WeSay 1.0.0.0'> <entry id='noChangesInEither' guid='c1ed1f9d-e382-11de-8a39-0800200c9a66' /> <entry id='onlyOneDeleted' guid='c1ed1f9e-e382-11de-8a39-0800200c9a66' /> </lift>"; // We win merge situation. MergeSituation mergeSit = new NullMergeSituation(); DoMergeWithLiftEntryMergingStrategy(ancestor, ours, theirs, mergeSit, new[] { "lift/entry[@id='noChangesInEither']" }, new[] { "lift/entry[@id='onlyOneDeleted']" }, 0, null, 0, null); // They win merge situation. mergeSit = new NullMergeSituationTheyWin(); DoMergeWithLiftEntryMergingStrategy(ancestor, ours, theirs, mergeSit, new[] { "lift/entry[@id='noChangesInEither']" }, new[] { "lift/entry[@id='onlyOneDeleted']" }, 0, null, 0, null); }
public void OldStyleMainItemRemovedByUsEditedByThemHasCorrectRemovedEditConflicts() { // Old Style means the deleted entry was just marked as deleted with the dateDeleted attr. const string ancestor = @"<?xml version='1.0' encoding='utf-8'?> <lift version='0.10' producer='WeSay 1.0.0.0'> <entry id='noChangesInEither' guid='c1ed1f9d-e382-11de-8a39-0800200c9a66' /> <entry id='doomedByUsEditedByThem' guid='c1ed1f98-e382-11de-8a39-0800200c9a66' > <sense> <gloss lang='a'> <text>original</text> </gloss> </sense> </entry> </lift>"; const string ours = @"<?xml version='1.0' encoding='utf-8'?> <lift version='0.10' producer='WeSay 1.0.0.0'> <entry id='noChangesInEither' guid='c1ed1f9d-e382-11de-8a39-0800200c9a66' /> <entry id='doomedByUsEditedByThem' guid='c1ed1f98-e382-11de-8a39-0800200c9a66' dateDeleted='2011-03-15T12:15:05Z' /> </lift>"; const string theirs = @"<?xml version='1.0' encoding='utf-8'?> <lift version='0.10' producer='WeSay 1.0.0.0'> <entry id='noChangesInEither' guid='c1ed1f9d-e382-11de-8a39-0800200c9a66' /> <entry id='doomedByUsEditedByThem' guid='c1ed1f98-e382-11de-8a39-0800200c9a66' > <sense> <gloss lang='a'> <text>editedByThem</text> </gloss> </sense> </entry> </lift>"; // We win merge situation. MergeSituation mergeSit = new NullMergeSituation(); DoMergeWithLiftEntryMergingStrategy(ancestor, ours, theirs, mergeSit, new[] { "lift/entry[@id='doomedByUsEditedByThem']/sense/gloss/text[text()='editedByThem']" }, new[] { "lift/entry[@id='doomedByUsEditedByThem' and @dateDeleted='2011-03-15T12:15:05Z']" }, 1, new List<Type> {typeof (RemovedVsEditedElementConflict)}, 0, null); // They win merge situation. mergeSit = new NullMergeSituationTheyWin(); DoMergeWithLiftEntryMergingStrategy(ancestor, ours, theirs, mergeSit, new[] { "lift/entry[@id='doomedByUsEditedByThem']/sense/gloss/text[text()='editedByThem']" }, new[] { "lift/entry[@id='doomedByUsEditedByThem' and @dateDeleted='2011-03-15T12:15:05Z']" }, 1, new List<Type> { typeof(EditedVsRemovedElementConflict) }, 0, null); }
public void BothAddedMainItemWithSameContentHasNoChangeReport() { const string ancestor = @"<?xml version='1.0' encoding='utf-8'?> <lift version='0.10' producer='WeSay 1.0.0.0'> <entry id='noChangesInEither' guid='c1ed1f9d-e382-11de-8a39-0800200c9a66' /> </lift>"; const string ours = @"<?xml version='1.0' encoding='utf-8'?> <lift version='0.10' producer='WeSay 1.0.0.0'> <entry id='noChangesInEither' guid='c1ed1f9d-e382-11de-8a39-0800200c9a66' /> <entry id='addedByBoth' guid='c1ed1f9e-e382-11de-8a39-0800200c9a66' > <sense> <gloss lang='a'> <text>editedByBoth</text> </gloss> </sense> </entry> </lift>"; const string theirs = @"<?xml version='1.0' encoding='utf-8'?> <lift version='0.10' producer='WeSay 1.0.0.0'> <entry id='noChangesInEither' guid='c1ed1f9d-e382-11de-8a39-0800200c9a66' /> <entry id='addedByBoth' guid='c1ed1f9e-e382-11de-8a39-0800200c9a66' > <sense> <gloss lang='a'> <text>editedByBoth</text> </gloss> </sense> </entry> </lift>"; // We win merge situation. MergeSituation mergeSit = new NullMergeSituation(); DoMergeWithLiftEntryMergingStrategy(ancestor, ours, theirs, mergeSit, new[] { "lift/entry[@id='addedByBoth']/sense/gloss/text[text()='editedByBoth']" }, null, 0, null, 0, null); // They win merge situation. mergeSit = new NullMergeSituationTheyWin(); DoMergeWithLiftEntryMergingStrategy(ancestor, ours, theirs, mergeSit, new[] { "lift/entry[@id='addedByBoth']/sense/gloss/text[text()='editedByBoth']" }, null, 0, null, 0, null); }
public void BothAddedOptionalFirstElementButWithDifferentContentHasOneConflictReport() { const string ancestor = @"<?xml version='1.0' encoding='utf-8'?> <lift version='0.10' producer='WeSay 1.0.0.0'> <entry id='noChangesInEither' guid='c1ed1f9d-e382-11de-8a39-0800200c9a66' /> </lift>"; const string ours = @"<?xml version='1.0' encoding='utf-8'?> <lift version='0.10' producer='WeSay 1.0.0.0'> <header id='ourNewHeader'/> <entry id='noChangesInEither' guid='c1ed1f9d-e382-11de-8a39-0800200c9a66' /> </lift>"; const string theirs = @"<?xml version='1.0' encoding='utf-8'?> <lift version='0.10' producer='WeSay 1.0.0.0'> <header id='theirNewHeader'/> <entry id='noChangesInEither' guid='c1ed1f9d-e382-11de-8a39-0800200c9a66' /> </lift>"; // We win merge situation. MergeSituation mergeSit = new NullMergeSituation(); DoMergeWithLiftEntryMergingStrategy(ancestor, ours, theirs, mergeSit, new[] { "lift/header[@id='ourNewHeader']", "lift/entry[@id='noChangesInEither']" }, new[] { "lift/header[@id='theirNewHeader']" }, 1, new List<Type> { typeof(BothAddedAttributeConflict) }, 0, null); // They win merge situation. mergeSit = new NullMergeSituationTheyWin(); DoMergeWithLiftEntryMergingStrategy(ancestor, ours, theirs, mergeSit, new[] { "lift/header[@id='theirNewHeader']", "lift/entry[@id='noChangesInEither']" }, new[] { "lift/header[@id='ourNewHeader']" }, 1, new List<Type> { typeof(BothAddedAttributeConflict) }, 0, null); }
public void BothAddedNewFileWithNonConflictingDataHasNoChangeReports() { const string ours = @"<?xml version='1.0' encoding='utf-8'?> <lift version='0.10' producer='WeSay 1.0.0.0'> <entry id='addedByUs' guid='c1edbbe7-e382-11de-8a39-0800200c9a66' > <sense> <gloss lang='a'> <text>our gloss</text> </gloss> </sense> </entry> </lift>"; const string theirs = @"<?xml version='1.0' encoding='utf-8'?> <lift version='0.10' producer='WeSay 1.0.0.0'> <entry id='addedByThem' guid='c1edbbe8-e382-11de-8a39-0800200c9a66' > <sense> <gloss lang='a'> <text>their gloss</text> </gloss> </sense> </entry> </lift>"; // We win merge situation. MergeSituation mergeSit = new NullMergeSituation(); DoMergeWithLiftEntryMergingStrategy(null, ours, theirs, mergeSit, new[] { "lift/entry[@id='addedByUs']/sense/gloss/text[text()='our gloss']", "lift/entry[@id='addedByUs']/sense/gloss/text[text()='our gloss']" }, new string[0], 0, null, 0, null); // They win merge situation. mergeSit = new NullMergeSituationTheyWin(); DoMergeWithLiftEntryMergingStrategy(null, ours, theirs, mergeSit, new[] { "lift/entry[@id='addedByUs']/sense/gloss/text[text()='our gloss']", "lift/entry[@id='addedByUs']/sense/gloss/text[text()='our gloss']" }, new string[0], 0, null, 0, null); }
public void BothAddedNewFileWithConflictingDataHasConflict() { const string ours = @"<?xml version='1.0' encoding='utf-8'?> <lift version='0.10' producer='WeSay 1.0.0.0'> <entry id='addedByBoth' guid='c1ed1f98-e382-11de-8a39-0800200c9a66' > <sense id='somesense'> <gloss lang='a'> <text>our gloss</text> </gloss> </sense> </entry> </lift>"; const string theirs = @"<?xml version='1.0' encoding='utf-8'?> <lift version='0.10' producer='WeSay 1.0.0.0'> <entry id='addedByBoth' guid='c1ed1f98-e382-11de-8a39-0800200c9a66' > <sense id='somesense'> <gloss lang='a'> <text>their gloss</text> </gloss> </sense> </entry> </lift>"; // We win merge situation. MergeSituation mergeSit = new NullMergeSituation(); DoMergeWithLiftEntryMergingStrategy(null, ours, theirs, mergeSit, new[] { "lift/entry[@id='addedByBoth']/sense/gloss/text[text()='our gloss']" }, new[] { "lift/entry[@id='addedByBoth']/sense/gloss/text[text()='their gloss']" }, 1, new List<Type> { typeof(XmlTextBothAddedTextConflict) }, 4, new List<Type> { typeof(XmlAttributeBothAddedReport), typeof(XmlAttributeBothAddedReport), typeof(XmlAttributeBothAddedReport), typeof(XmlAttributeBothAddedReport) }); // They win merge situation. mergeSit = new NullMergeSituationTheyWin(); DoMergeWithLiftEntryMergingStrategy(null, ours, theirs, mergeSit, new[] { "lift/entry[@id='addedByBoth']/sense/gloss/text[text()='their gloss']" }, new[] { "lift/entry[@id='addedByBoth']/sense/gloss/text[text()='our gloss']" }, 1, new List<Type> { typeof(XmlTextBothAddedTextConflict) }, 4, new List<Type> { typeof(XmlAttributeBothAddedReport), typeof(XmlAttributeBothAddedReport), typeof(XmlAttributeBothAddedReport), typeof(XmlAttributeBothAddedReport) }); }