public void Merge_EditAndDeleteEntry_GeneratesConflictWithContext() { const string pattern = @"<?xml version='1.0' encoding='utf-8'?> <lift version='0.10' producer='WeSay 1.0.0.0'> <entry dateCreated='2011-03-09T17:08:44Z' dateModified='2012-05-18T08:31:54Z' id='00853b73-fda2-4b12-8a89-6957cc7e7e79' guid='00853b73-fda2-4b12-8a89-6957cc7e7e79'> <lexical-unit> <form lang='ldb-fonipa-x-emic'> <text>{0}</text> </form> </lexical-unit> </entry> </lift>" ; // We edited the text of the form slightly. string ours = string.Format(pattern, "asaten"); string ancestor = string.Format(pattern, "asat"); // they deleted the whole entry const string theirs = @"<?xml version='1.0' encoding='utf-8'?> <lift version='0.10' producer='WeSay 1.0.0.0'> </lift>" ; using (var oursTemp = new TempFile(ours)) using (var theirsTemp = new TempFile(theirs)) using (var ancestorTemp = new TempFile(ancestor)) { var listener = new ListenerForUnitTests(); var situation = new NullMergeSituation(); var mergeOrder = new MergeOrder(oursTemp.Path, ancestorTemp.Path, theirsTemp.Path, situation) { EventListener = listener }; var mergeStrategy = new LiftEntryMergingStrategy(mergeOrder); var strategies = mergeStrategy.GetStrategies(); var entryStrategy = strategies.ElementStrategies["entry"]; entryStrategy.ContextDescriptorGenerator = new EnhancedEntrycontextGenerator(); XmlMergeService.Do3WayMerge(mergeOrder, mergeStrategy, false, "header", "entry", "guid"); var result = File.ReadAllText(mergeOrder.pathToOurs); var conflict = listener.Conflicts[0]; Assert.That(conflict, Is.InstanceOf <EditedVsRemovedElementConflict>()); Assert.That(conflict.HtmlDetails, Is.StringContaining("my silly context"), "merger should have used the context generator to make the html details"); Assert.That(conflict.HtmlDetails.IndexOf("my silly context"), Is.EqualTo(conflict.HtmlDetails.LastIndexOf("my silly context")), "since one change is a delete, the details should only be present once"); var context = conflict.Context; Assert.That(context, Is.Not.Null, "the merge should supply a context for the conflict"); Assert.That(context.PathToUserUnderstandableElement, Is.Not.Null); XmlTestHelper.AssertXPathMatchesExactlyOne(result, "lift/entry/lexical-unit/form[@lang='ldb-fonipa-x-emic']/text[text()='asaten']"); } }
[Test] // See http://jira.palaso.org/issues/browse/CHR-18 public void Merge_DuplicateGuidsInEntry_ResultHasWarningReport() { const string ours = @"<?xml version='1.0' encoding='utf-8'?> <lift version='0.10' producer='WeSay 1.0.0.0'> <entry id='00853b73-fda2-4b12-8a89-6957cc7e7e79' guid='00853b73-fda2-4b12-8a89-6957cc7e7e79'> </entry> </lift>" ; const string theirs = @"<?xml version='1.0' encoding='utf-8'?> <lift version='0.10' producer='WeSay 1.0.0.0'> <entry id='00853b73-fda2-4b12-8a89-6957cc7e7e79' guid='00853b73-fda2-4b12-8a89-6957cc7e7e79'> </entry> </lift>" ; const string ancestor = @"<?xml version='1.0' encoding='utf-8'?> <lift version='0.10' producer='WeSay 1.0.0.0'> <entry id='00853b73-fda2-4b12-8a89-6957cc7e7e79' guid='00853b73-fda2-4b12-8a89-6957cc7e7e79'> </entry> <entry id='00853b73-fda2-4b12-8a89-6957cc7e7e79' guid='00853b73-fda2-4b12-8a89-6957cc7e7e79'> <lexical-unit> <form lang='en'> <text>goner form</text> </form> </lexical-unit> </entry> </lift>" ; using (var oursTemp = new TempFile(ours)) using (var theirsTemp = new TempFile(theirs)) using (var ancestorTemp = new TempFile(ancestor)) { var listener = new ListenerForUnitTests(); var situation = new NullMergeSituation(); 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); // Check that there is only one entry in the merged file. XmlTestHelper.AssertXPathMatchesExactlyOne(result, "lift/entry[@guid='00853b73-fda2-4b12-8a89-6957cc7e7e79']"); XmlTestHelper.AssertXPathIsNull(result, "lift/entry[@guid='00853b73-fda2-4b12-8a89-6957cc7e7e79']/lexical-unit"); Assert.AreEqual(typeof(MergeWarning), listener.Warnings[0].GetType()); } }
public void GetMergedLift_ConflictingGlosses_ListenerIsNotifiedOfBothEditedConflict() { const string ours = @"<?xml version='1.0' encoding='utf-8'?> <lift version='0.10' producer='WeSay 1.0.0.0'> <entry id='test' guid='F169EB3D-16F2-4eb0-91AA-FDB91636F8F6'> <sense id='123'> <gloss lang='a'> <text>ourSense</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='test' guid='F169EB3D-16F2-4eb0-91AA-FDB91636F8F6'> <sense id='123'> <gloss lang='a'> <text>theirSense</text> </gloss> </sense> </entry> </lift>" ; const string ancestor = @"<?xml version='1.0' encoding='utf-8'?> <lift version='0.10' producer='WeSay 1.0.0.0'> <entry id='test' guid='F169EB3D-16F2-4eb0-91AA-FDB91636F8F6'> <sense id='123'> <gloss lang='a'> <text>original</text> </gloss> </sense> </entry> </lift>" ; using (var oursTemp = new TempFile(ours)) using (var theirsTemp = new TempFile(theirs)) using (var ancestorTemp = new TempFile(ancestor)) { var listener = new ListenerForUnitTests(); var situation = new NullMergeSituation(); var mergeOrder = new MergeOrder(oursTemp.Path, ancestorTemp.Path, theirsTemp.Path, situation) { EventListener = listener }; XmlMergeService.Do3WayMerge(mergeOrder, new LiftEntryMergingStrategy(mergeOrder), false, "header", "entry", "guid"); var conflict = listener.Conflicts[0]; AssertConflictType <XmlTextBothEditedTextConflict>(conflict); const string expectedContext = "lift://unknown?type=entry&id=F169EB3D-16F2-4eb0-91AA-FDB91636F8F6"; Assert.AreEqual(expectedContext, listener.Contexts[0].PathToUserUnderstandableElement, "the listener wasn't give the expected context"); } }
internal static string DoMerge( IChorusFileTypeHandler chorusFileHandler, TempFile ourFile, string ourContent, TempFile commonFile, string commonAncestor, TempFile theirFile, string theirContent, IEnumerable <string> matchesExactlyOne, IEnumerable <string> isNull, int expectedConflictCount, List <Type> conflictTypes, int expectedChangesCount, List <Type> changeTypes, out List <IConflict> resultingConflicts) { File.WriteAllText(ourFile.Path, ourContent); if (commonFile != null) { File.WriteAllText(commonFile.Path, commonAncestor); } File.WriteAllText(theirFile.Path, theirContent); var situation = new NullMergeSituation(); var mergeOrder = new MergeOrder(ourFile.Path, (commonFile == null ? null : commonFile.Path), theirFile.Path, situation); var eventListener = new ListenerForUnitTests(); mergeOrder.EventListener = eventListener; chorusFileHandler.Do3WayMerge(mergeOrder); var result = File.ReadAllText(ourFile.Path); if (matchesExactlyOne != null) { foreach (var query in matchesExactlyOne) { XmlTestHelper.AssertXPathMatchesExactlyOne(result, query); } } if (isNull != null) { foreach (var query in isNull) { XmlTestHelper.AssertXPathIsNull(result, query); } } eventListener.AssertExpectedConflictCount(expectedConflictCount); Assert.AreEqual(conflictTypes.Count, eventListener.Conflicts.Count); for (var idx = 0; idx < conflictTypes.Count; ++idx) { Assert.AreSame(conflictTypes[idx], eventListener.Conflicts[idx].GetType()); } eventListener.AssertExpectedChangesCount(expectedChangesCount); Assert.AreEqual(changeTypes.Count, eventListener.Changes.Count); for (var idx = 0; idx < changeTypes.Count; ++idx) { Assert.AreSame(changeTypes[idx], eventListener.Changes[idx].GetType()); } resultingConflicts = eventListener.Conflicts; return(result); }
public void EachHasNewSense_BothSensesCoveyed() { const string ours = @"<?xml version='1.0' encoding='utf-8'?> <lift version='0.10' producer='WeSay 1.0.0.0'> <entry id='test' guid='F169EB3D-16F2-4eb0-91AA-FDB91636F8F6'> <sense id='123'> <gloss lang='a'> <text>ourSense</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='test' guid='F169EB3D-16F2-4eb0-91AA-FDB91636F8F6'> <sense id='456'> <gloss lang='a'> <text>theirSense</text> </gloss> </sense> </entry> </lift>" ; const string ancestor = @"<?xml version='1.0' encoding='utf-8'?> <lift version='0.10' producer='WeSay 1.0.0.0'> <entry id='test' guid='F169EB3D-16F2-4eb0-91AA-FDB91636F8F6' /> </lift>" ; using (var oursTemp = new TempFile(ours)) using (var theirsTemp = new TempFile(theirs)) using (var ancestorTemp = new TempFile(ancestor)) { var listener = new ListenerForUnitTests(); var situation = new NullMergeSituation(); var mergeOrder = new MergeOrder(oursTemp.Path, ancestorTemp.Path, theirsTemp.Path, situation) { EventListener = listener }; XmlMergeService.Do3WayMerge(mergeOrder, new LiftEntryMergingStrategy(mergeOrder), false, "header", "entry", "guid"); //this doesn't seem particular relevant, but senses are, in fact, ordered, so there is some ambiguity here Assert.AreEqual(typeof(AmbiguousInsertConflict), listener.Conflicts[0].GetType()); var result = File.ReadAllText(mergeOrder.pathToOurs); XmlTestHelper.AssertXPathMatchesExactlyOne(result, "lift/entry[@id='test']"); XmlTestHelper.AssertXPathMatchesExactlyOne(result, "lift/entry[@id='test' and sense[@id='123']/gloss/text='ourSense']"); XmlTestHelper.AssertXPathMatchesExactlyOne(result, "lift/entry[@id='test' and sense[@id='456']/gloss/text='theirSense']"); } }
public void Merge_DuplicateKeyInGloss_NoThrow() { var ancestor = @"<?xml version='1.0' encoding='utf-8'?> <lift version='0.13' producer='FLEx 7.2.4'><entry id='lovely_f1c5a4c8-a24f-4351-8551-2b70d53a9256' guid='f1c5a4c8-a24f-4351-8551-2b70d53a9256'> <lexical-unit> <form lang='fr'><text>lovely</text></form> </lexical-unit> <trait name='morph-type' value='stem'/> <sense id='fist_0e0fc867-e56a-4df5-861a-1cb24d861037'> <grammatical-info value='Noun' /> <gloss lang='en'> <text>base</text> </gloss> <gloss lang='swh'> <text>ngumi / mangumi</text> </gloss> <gloss lang='swh'> <text>konde / makonde</text> </gloss> </sense> </entry></lift>" ; var ours = ancestor.Replace("base", "ours"); var theirs = ancestor.Replace("base", "theirs"); Assert.DoesNotThrow(() => { using (var oursTemp = new TempFile(ours)) using (var theirsTemp = new TempFile(theirs)) using (var ancestorTemp = new TempFile(ancestor)) { var listener = new ListenerForUnitTests(); var situation = new NullMergeSituation(); 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); //AssertThatXmlIn.String(result).HasSpecifiedNumberOfMatchesForXpath(@"/lift/entry/relation", 2); } }); }
private string DoMerge(string commonAncestor, string ourContent, string theirContent, Dictionary <string, string> namespaces, IEnumerable <string> matchesExactlyOne, IEnumerable <string> isNull, int expectedConflictCount, List <Type> expectedConflictTypes, int expectedChangesCount, List <Type> expectedChangeTypes) { string result; using (var ours = new TempFile(ourContent)) using (var theirs = new TempFile(theirContent)) using (var ancestor = new TempFile(commonAncestor)) { var situation = new NullMergeSituation(); var mergeOrder = new MergeOrder(ours.Path, ancestor.Path, theirs.Path, situation); _eventListener = new ListenerForUnitTests(); mergeOrder.EventListener = _eventListener; _ldmlFileHandler.Do3WayMerge(mergeOrder); result = File.ReadAllText(ours.Path); foreach (var query in matchesExactlyOne) { XmlTestHelper.AssertXPathMatchesExactlyOne(result, query, namespaces); } if (isNull != null) { foreach (var query in isNull) { XmlTestHelper.AssertXPathIsNull(result, query, namespaces); } } _eventListener.AssertExpectedConflictCount(expectedConflictCount); expectedConflictTypes = expectedConflictTypes ?? new List <Type>(); Assert.AreEqual(expectedConflictTypes.Count, _eventListener.Conflicts.Count, "Expected conflict count and actual number found differ."); for (var idx = 0; idx < expectedConflictTypes.Count; ++idx) { Assert.AreSame(expectedConflictTypes[idx], _eventListener.Conflicts[idx].GetType()); } _eventListener.AssertExpectedChangesCount(expectedChangesCount); expectedChangeTypes = expectedChangeTypes ?? new List <Type>(); Assert.AreEqual(expectedChangeTypes.Count, _eventListener.Changes.Count, "Expected change count and actual number found differ."); for (var idx = 0; idx < expectedChangeTypes.Count; ++idx) { Assert.AreSame(expectedChangeTypes[idx], _eventListener.Changes[idx].GetType()); } } return(result); }
public void Conflict_TheirsAppearsInCollisionNote() { const string ours = @"<?xml version='1.0' encoding='utf-8'?> <lift version='0.10' producer='WeSay 1.0.0.0'> <entry id='lexicalformcollission' guid='c1ed1fa7-e382-11de-8a39-0800200c9a66' > <lexical-unit> <form lang='x'> <text>ours</text> </form> </lexical-unit> </entry> </lift>" ; const string theirs = @"<?xml version='1.0' encoding='utf-8'?> <lift version='0.10' producer='WeSay 1.0.0.0'> <entry id='lexicalformcollission' guid='c1ed1fa7-e382-11de-8a39-0800200c9a66' > <lexical-unit> <form lang='x'> <text>theirs</text> </form> </lexical-unit> </entry> </lift>" ; const string ancestor = @"<?xml version='1.0' encoding='utf-8'?> <lift version='0.10' producer='WeSay 1.0.0.0'> <entry id='lexicalformcollission' guid='c1ed1fa7-e382-11de-8a39-0800200c9a66' /> </lift>" ; using (var oursTemp = new TempFile(ours)) using (var theirsTemp = new TempFile(theirs)) using (var ancestorTemp = new TempFile(ancestor)) { var listener = new ListenerForUnitTests(); var situation = new NullMergeSituation(); var mergeOrder = new MergeOrder(oursTemp.Path, ancestorTemp.Path, theirsTemp.Path, situation) { EventListener = listener }; XmlMergeService.Do3WayMerge(mergeOrder, new PoorMansMergeStrategy(), false, "header", "entry", "guid"); var result = File.ReadAllText(mergeOrder.pathToOurs); XmlTestHelper.AssertXPathMatchesExactlyOne(result, "lift/entry[@id='lexicalformcollission']"); XmlTestHelper.AssertXPathMatchesExactlyOne(result, "lift/entry"); //just one XmlTestHelper.AssertXPathMatchesExactlyOne(result, "lift/entry/field[@type='mergeConflict']/trait[@name = 'looserData']"); XmlTestHelper.AssertXPathMatchesExactlyOne(result, "lift/entry/field[@type='mergeConflict' and @dateCreated]"); } }
public void EachHasNewSense_BothSensesCoveyed() { const string ours = @"<?xml version='1.0' encoding='utf-8'?> <lift version='0.10' producer='WeSay 1.0.0.0'> <entry id='test' guid='c1ed1fa8-e382-11de-8a39-0800200c9a66' > <sense> <gloss lang='a'> <text>ourSense</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='test' guid='c1ed1fa8-e382-11de-8a39-0800200c9a66' > <sense> <gloss lang='a'> <text>theirSense</text> </gloss> </sense> </entry> </lift>" ; const string ancestor = @"<?xml version='1.0' encoding='utf-8'?> <lift version='0.10' producer='WeSay 1.0.0.0'> <entry id='test' guid='c1ed1fa8-e382-11de-8a39-0800200c9a66' /> </lift>" ; using (var oursTemp = new TempFile(ours)) using (var theirsTemp = new TempFile(theirs)) using (var ancestorTemp = new TempFile(ancestor)) { var listener = new ListenerForUnitTests(); var situation = new NullMergeSituation(); 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='test']"); XmlTestHelper.AssertXPathMatchesExactlyOne(result, "lift/entry[@id='test' and sense/gloss/text='ourSense']"); XmlTestHelper.AssertXPathMatchesExactlyOne(result, "lift/entry[@id='test' and sense/gloss/text='theirSense']"); } }
private MergeResult DoMerge(string commonAncestor, string ourContent, string theirContent) { var result = new MergeResult(); using (var ours = new TempFile(ourContent)) using (var theirs = new TempFile(theirContent)) using (var ancestor = new TempFile(commonAncestor)) { var situation = new NullMergeSituation(); var mergeOrder = new MergeOrder(ours.Path, ancestor.Path, theirs.Path, situation); result.listener = new ListenerForUnitTests(); mergeOrder.EventListener = result.listener; new BloomHtmlFileTypeHandler().Do3WayMerge(mergeOrder); result.resultString = File.ReadAllText(ours.Path); } return(result); }
public void RangeSectionMergedCorrectly() { using (var oursTemp = new TempFile(_ours)) using (var theirsTemp = new TempFile(_theirs)) using (var ancestorTemp = new TempFile(_ancestor)) { var listener = new ListenerForUnitTests(); var situation = new NullMergeSituation(); 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='usOnly']"); AssertThatXmlIn.String(result).HasSpecifiedNumberOfMatchesForXpath(@"lift/header/ranges/range", 4); } }
private string DoMerge(string commonAncestor, string ourContent, string theirContent, int expectedConflictCount, int expectedChangesCount) { string result; using (var ours = new TempFile(ourContent)) using (var theirs = new TempFile(theirContent)) using (var ancestor = new TempFile(commonAncestor)) { var situation = new NullMergeSituation(); var mergeOrder = new MergeOrder(ours.Path, ancestor.Path, theirs.Path, situation); _eventListener = new ListenerForUnitTests(); mergeOrder.EventListener = _eventListener; _liftRangesFileHandler.Do3WayMerge(mergeOrder); result = File.ReadAllText(ours.Path); _eventListener.AssertExpectedConflictCount(expectedConflictCount); _eventListener.AssertExpectedChangesCount(expectedChangesCount); } return(result); }
public void OneEditedExampleWhileOtherAddedTranslation_MergesButRaiseWarning() { const string ancestor = @"<?xml version='1.0' encoding='utf-8'?> <lift version='0.10' producer='WeSay 1.0.0.0'> <entry id='test' guid='F169EB3D-16F2-4eb0-91AA-FDB91636F8F6'> <sense id='123'> <example> <form lang='chorus'> <text>This is my example sentence.</text> </form> </example> </sense> </entry> </lift>"; var ours = ancestor.Replace("This is my", "This is our"); var theirs = ancestor.Replace("</example>", "<translation><form lang='en'><text>hello</text></form></translation></example>"); using (var oursTemp = new TempFile(ours)) using (var theirsTemp = new TempFile(theirs)) using (var ancestorTemp = new TempFile(ancestor)) { var listener = new ListenerForUnitTests(); var situation = new NullMergeSituation(); 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); Assert.AreEqual(1, listener.Conflicts.Count); var warning = listener.Warnings[0]; Assert.AreEqual(typeof(BothEditedDifferentPartsOfDependentPiecesOfDataWarning), warning.GetType(), warning.ToString()); XmlTestHelper.AssertXPathMatchesExactlyOne(result, "//example"); } }
private void TestBodyMerge(string ancestorBody, string ourBody, string theirBody, Action <string> testsOnResultingFile, Action <ListenerForUnitTests> testsOnEventListener) { string ancestor = @"<?xml version='1.0' encoding='utf-8'?><html><body>" + ancestorBody + "</body></html>"; string theirs = @"<?xml version='1.0' encoding='utf-8'?><html><body>" + theirBody + "</body></html>"; string ours = @"<?xml version='1.0' encoding='utf-8'?><html><body>" + ourBody + "</body></html>"; using (var oursTemp = new TempFile(ours)) using (var theirsTemp = new TempFile(theirs)) using (var ancestorTemp = new TempFile(ancestor)) { var listener = new ListenerForUnitTests(); var situation = new NullMergeSituation(); var mergeOrder = new MergeOrder(oursTemp.Path, ancestorTemp.Path, theirsTemp.Path, situation) { EventListener = listener }; new Bloom_ChorusPlugin.BloomHtmlFileTypeHandler().Do3WayMerge(mergeOrder); testsOnResultingFile(mergeOrder.pathToOurs); testsOnEventListener(listener); } }
public void BothModifiedExampleFormTextWorksWithConflict() { const string ancestor = @"<?xml version='1.0' encoding='utf-8'?> <lift version='0.10' producer='WeSay 1.0.0.0'> <entry id='test' guid='F169EB3D-16F2-4eb0-91AA-FDB91636F8F6'> <sense id='123'> <example> <form lang='chorus'> <text>This is my example sentence.</text> </form> </example> </sense> </entry> </lift>"; var ours = ancestor.Replace(@"This is my example", @"This was your example"); var theirs = ancestor.Replace(@"This is my example", @"It's mine don't touch it."); using (var oursTemp = new TempFile(ours)) using (var theirsTemp = new TempFile(theirs)) using (var ancestorTemp = new TempFile(ancestor)) { var listener = new ListenerForUnitTests(); var situation = new NullMergeSituation(); 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); Assert.AreEqual(1, listener.Conflicts.Count); var warning = listener.Conflicts[0]; Assert.AreEqual(typeof(XmlTextBothEditedTextConflict), warning.GetType(), warning.ToString()); XmlTestHelper.AssertXPathMatchesExactlyOne(result, "//example/form"); } }
public void OneAddedOneTranslationWhileOtherAddedAnother_Merged() { const string ancestor = @"<?xml version='1.0' encoding='utf-8'?> <lift version='0.10' producer='WeSay 1.0.0.0'> <entry id='test' guid='F169EB3D-16F2-4eb0-91AA-FDB91636F8F6'> <sense id='123'> <example> <form lang='chorus'> <text>This is my example sentence.</text> </form> </example> </sense> </entry> </lift>"; var ours = ancestor.Replace("</example>", "<translation><form lang='tp'><text>Dispela em i sentens bilong mi.</text></form></translation></example>"); var theirs = ancestor.Replace("</example>", "<translation><form lang='en'><text>hello</text></form></translation></example>"); using (var oursTemp = new TempFile(ours)) using (var theirsTemp = new TempFile(theirs)) using (var ancestorTemp = new TempFile(ancestor)) { var listener = new ListenerForUnitTests(); var situation = new NullMergeSituation(); 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, "//example"); } }
public void OneAddedOneTranslationOtherEditedFormText() { const string ancestor = @"<?xml version='1.0' encoding='utf-8'?> <lift version='0.10' producer='WeSay 1.0.0.0'> <entry id='test' guid='F169EB3D-16F2-4eb0-91AA-FDB91636F8F6'> <sense id='123'> <example> <form lang='chorus'> <text>This is my example sentence.</text> </form> </example> </sense> </entry> </lift>"; var ours = ancestor.Replace(@"This is my example", @"This was your example"); var theirs = ancestor.Replace(@"</example>", @"<form lang='en'><text>hello new entry</text></form></example>"); using (var oursTemp = new TempFile(ours)) using (var theirsTemp = new TempFile(theirs)) using (var ancestorTemp = new TempFile(ancestor)) { var listener = new ListenerForUnitTests(); var situation = new NullMergeSituation(); 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, "//example"); AssertThatXmlIn.String(result).HasSpecifiedNumberOfMatchesForXpath("//example/form", 2); } }
public void RelationsMergeWithoutThrowing() { var ancestor = @"<?xml version='1.0' encoding='utf-8'?> <lift version='0.13' producer='FLEx 7.2.4'><entry id='lovely_f1c5a4c8-a24f-4351-8551-2b70d53a9256' guid='f1c5a4c8-a24f-4351-8551-2b70d53a9256'> <lexical-unit> <form lang='fr'><text>lovely</text></form> </lexical-unit> <trait name='morph-type' value='stem'/> <sense id='de53a9a1-5b70-49e5-8dbe-171bff37d624'> <example> <form lang='fr'><text>This is example sentence one</text></form> </example> <example> <form lang='fr'><text>This is example sentence two.</text></form> <translation type='Free translation'> <form lang='en'><text>This is a translation of two</text></form> </translation> </example> </sense> </entry> <entry id='love_92b74399-ce6e-4f24-8412-784e0227d3eb' guid='92b74399-ce6e-4f24-8412-784e0227d3eb'> <lexical-unit> <form lang='fr'><text>love</text></form> </lexical-unit> <trait name='morph-type' value='stem'/> <etymology type='proto' source='French'> <form lang='fr'><text>It came from </text></form> <form lang='en'><text>the deep</text></form> </etymology> <relation type='_component-lexeme' ref='lovely_f1c5a4c8-a24f-4351-8551-2b70d53a9256'> <trait name='is-primary' value='true'/> <trait name='complex-form-type' value=''/> </relation> <sense id='3185e889-eec3-4148-8df9-8f446bc498b7'> </sense> </entry></lift>" ; var ours = ancestor.Replace(@"It came from", @"May have come from"); var theirs = ancestor.Replace(@"</entry></lift>", @"</entry><entry id='newentry' guid='fffffff-ffff-ffff-ffff-ffffffff'><lexical-unit><form lang='fr'><text>loverly</text></form></lexical-unit></entry></lift>"); theirs = theirs.Replace(@"</relation>", @"</relation><relation type='_component-lexeme' ref='newentry'><trait name='is-primary' value='true'/><trait name='complex-form-type' value=''/></relation>"); Assert.DoesNotThrow(() => { using (var oursTemp = new TempFile(ours)) using (var theirsTemp = new TempFile(theirs)) using (var ancestorTemp = new TempFile(ancestor)) { var listener = new ListenerForUnitTests(); var situation = new NullMergeSituation(); 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); AssertThatXmlIn.String(result).HasSpecifiedNumberOfMatchesForXpath(@"/lift/entry/relation", 2); } }); }
public void Merge_TheirDuplicateRelationDoesNotResultInEmptyRelationElement() { const string ours = @"<?xml version='1.0' encoding='utf-8'?> <lift version='0.10' producer='Whoever'> <entry dateCreated='2012-04-16T07:27:11Z' dateModified='2012-08-12T09:46:54Z' id='आप्चो_27fcb6ac-b509-4463-aa12-36427ac9b427' guid='27fcb6ac-b509-4463-aa12-36427ac9b427'> <lexical-unit> <form lang='bhj'> <text>आप्चो</text> </form> </lexical-unit> <relation type='Compare' ref='आम्मे_1cc3b8eb-cc46-4ee9-9a53-9195a30cb6b4' /> <sense id='d4c1b46b-554a-4fc6-846b-b136b118817b' order='1'> <definition> <form lang='en'> <text>shoot</text> </form> <form lang='ne'> <text>हिर्काउ</text> </form> </definition> </sense> </entry> </lift>" ; const string theirs = @"<?xml version='1.0' encoding='utf-8'?> <lift version='0.10' producer='Whoever'> <entry dateCreated='2012-04-16T07:27:11Z' dateModified='2012-06-21T01:37:26Z' id='आप्चो_27fcb6ac-b509-4463-aa12-36427ac9b427' guid='27fcb6ac-b509-4463-aa12-36427ac9b427'> <lexical-unit> <form lang='bhj'> <text>आप्चो</text> </form> </lexical-unit> <relation type='Compare' ref='आम्मे_1cc3b8eb-cc46-4ee9-9a53-9195a30cb6b4' /> <relation type='Compare' ref='आम्मे_1cc3b8eb-cc46-4ee9-9a53-9195a30cb6b4' /> <sense id='d4c1b46b-554a-4fc6-846b-b136b118817b' order='1'> <definition> <form lang='en'> <text>shoot</text> </form> <form lang='ne'> <text>हीर्काउँ</text> </form> </definition> </sense> </entry> </lift>" ; const string ancestor = @"<?xml version='1.0' encoding='utf-8'?> <lift version='0.10' producer='Whoever'> <entry dateCreated='2012-04-16T07:27:11Z' dateModified='2012-06-21T01:37:26Z' id='आप्चो_27fcb6ac-b509-4463-aa12-36427ac9b427' guid='27fcb6ac-b509-4463-aa12-36427ac9b427'> <lexical-unit> <form lang='bhj'> <text>आप्चो</text> </form> </lexical-unit> <relation type='Compare' ref='आम्मे_1cc3b8eb-cc46-4ee9-9a53-9195a30cb6b4' /> <sense id='d4c1b46b-554a-4fc6-846b-b136b118817b' order='1'> <definition> <form lang='en'> <text>shoot</text> </form> <form lang='ne'> <text>हीर्काउँ</text> </form> </definition> </sense> </entry> </lift>" ; using (var oursTemp = new TempFile(ours)) using (var theirsTemp = new TempFile(theirs)) using (var ancestorTemp = new TempFile(ancestor)) { var listener = new ListenerForUnitTests(); var situation = new NullMergeSituation(); var mergeOrder = new MergeOrder(oursTemp.Path, ancestorTemp.Path, theirsTemp.Path, situation) { EventListener = listener }; XmlMergeService.Do3WayMerge(mergeOrder, new LiftEntryMergingStrategy(mergeOrder), false, "header", "entry", "guid"); //this doesn't seem particular relevant, but senses are, in fact, ordered, so there is some ambiguity here var result = File.ReadAllText(mergeOrder.pathToOurs); //Assert.AreEqual(typeof(AmbiguousInsertConflict), listener.Conflicts[0].GetType()); // Check that the audio made it into the merge. XmlTestHelper.AssertXPathIsNull(result, "//relation[not(@type)]"); } }
[Test] // See http://jira.palaso.org/issues/browse/CHR-18 public void Merge_DefinitionAncestorAndOursSameTheirsHasAdditionalForm_ResultHasAdditionalFormAlso() { const string ours = @"<?xml version='1.0' encoding='utf-8'?> <lift version='0.10' producer='WeSay 1.0.0.0'> <entry dateCreated='2011-03-09T17:08:44Z' dateModified='2012-05-18T08:31:54Z' id='???_00853b73-fda2-4b12-8a89-6957cc7e7e79' guid='00853b73-fda2-4b12-8a89-6957cc7e7e79'> <sense id='123'> <definition> <form lang='a'> <text>aSense</text> </form> </definition> </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='???_00853b73-fda2-4b12-8a89-6957cc7e7e79' dateCreated='2011-03-09T05:08:44Z' dateModified='2012-05-14T02:38:00Z' guid='00853b73-fda2-4b12-8a89-6957cc7e7e79'> <sense id='123'> <definition> <form lang='a'> <text>aSense</text> </form> <form lang='b'> <text>bSense</text> </form> </definition> </sense> </entry> </lift>" ; const string ancestor = @"<?xml version='1.0' encoding='utf-8'?> <lift version='0.10' producer='WeSay 1.0.0.0'> <entry dateCreated='2011-03-09T17:08:44Z' dateModified='2011-04-08T16:53:45Z' id='???_00853b73-fda2-4b12-8a89-6957cc7e7e79' guid='00853b73-fda2-4b12-8a89-6957cc7e7e79'> <sense id='123'> <definition> <form lang='a'> <text>aSense</text> </form> </definition> </sense> </entry> </lift>" ; using (var oursTemp = new TempFile(ours)) using (var theirsTemp = new TempFile(theirs)) using (var ancestorTemp = new TempFile(ancestor)) { var listener = new ListenerForUnitTests(); var situation = new NullMergeSituation(); var mergeOrder = new MergeOrder(oursTemp.Path, ancestorTemp.Path, theirsTemp.Path, situation) { EventListener = listener }; XmlMergeService.Do3WayMerge(mergeOrder, new LiftEntryMergingStrategy(mergeOrder), false, "header", "entry", "guid"); //this doesn't seem particular relevant, but senses are, in fact, ordered, so there is some ambiguity here var result = File.ReadAllText(mergeOrder.pathToOurs); //Assert.AreEqual(typeof(AmbiguousInsertConflict), listener.Conflicts[0].GetType()); // Check that the audio made it into the merge. XmlTestHelper.AssertXPathMatchesExactlyOne(result, "lift/entry/sense/definition/form[@lang='a']"); XmlTestHelper.AssertXPathMatchesExactlyOne(result, "lift/entry/sense/definition/form[@lang='b']"); } }
public void GetMergedLift_MysteryDroppedGloss() { const string ours = @"<?xml version='1.0' encoding='utf-8'?> <lift version='0.13' producer='WeSay 1.0.0.0'> <entry id='nɪntɔnnʊ_49327c35-759e-4db3-984a-b7dc5af1b1b0' dateCreated='2012-01-30T10:45:04Z' dateModified='2012-02-23T08:52:25Z' guid='49327c35-759e-4db3-984a-b7dc5af1b1b0'> <lexical-unit> <form lang='vag-fonipa-x-etic'> <text>nɪ́ntɔ́nnʊ̄</text> </form> </lexical-unit> <field type='pl'> <form lang='vag-fonipa-x-etic'> <text>nɪ́ntɔ́ntʊ́</text> </form> </field> <field type='tn'> <form lang='fr'> <text>HHM</text> </form> </field> <field type='tnpl'> <form lang='fr'> <text>HHH</text> </form> </field> <sense id='lip_39e4b942-0bf6-4494-aa9b-7f5163feb2bc'> <grammatical-info value='Noun' /> <gloss lang='en'> <text>lip</text> </gloss> <gloss lang='es'> <text>labio</text> </gloss> <gloss lang='fr'> <text>lèvre</text> </gloss> <gloss lang='ha'> <text>bā̀kī</text> </gloss> <gloss lang='nku-fonipa-x-etic'> <text>nwɔ́gbɛ́ɟɛ̀</text> </gloss> <gloss lang='swh'> <text>mdomo / midomo</text> </gloss> <definition> <form lang='en'> <text>lip</text> </form> <form lang='es'> <text>labio</text> </form> <form lang='fr'> <text>lèvre</text> </form> <form lang='ha'> <text>bā̀kī</text> </form> <form lang='id'> <text>bibir</text> </form> <form lang='pt'> <text>lábio</text> </form> <form lang='swh'> <text>mdomo / midomo</text> </form> </definition> <note type='source'> <form lang='x-unk'> <text> 00<span lang='en'>16</span></text> </form> </note> <field type='SILCAWL'> <form lang='en'> <text>0016</text> </form> </field> <trait name='semantic-domain-ddp4' value='2.1.1.4 Mouth' /> </sense> </entry> </lift>" ; const string theirs = @"<?xml version='1.0' encoding='utf-8'?> <lift version='0.13' producer='WeSay 1.0.0.0'> <entry id='nɪntɔnnʊ_49327c35-759e-4db3-984a-b7dc5af1b1b0' dateCreated='2012-01-30T10:45:04Z' dateModified='2012-01-30T10:59:31Z' guid='49327c35-759e-4db3-984a-b7dc5af1b1b0'> <lexical-unit> <form lang='vag-fonipa-x-etic'> <text>nɪ́ntɔ́nnʊ̄</text> </form> </lexical-unit> <field type='pl'> <form lang='vag-fonipa-x-etic'> <text>nɪ́ntɔ́ntʊ́</text> </form> </field> <note> <form lang='fr'> <text>Homonyme avec l'ethnie lobi sg pl. A faire.</text> </form> </note> <field type='tn'> <form lang='fr'> <text>HHM</text> </form> </field> <field type='tnpl'> <form lang='fr'> <text>HHH</text> </form> </field> <sense id='lip_39e4b942-0bf6-4494-aa9b-7f5163feb2bc'> <grammatical-info value='Noun' /> <gloss lang='en'> <text>lip</text> </gloss> <gloss lang='es'> <text>labio</text> </gloss> <gloss lang='fr'> <text>lèvre</text> </gloss> <gloss lang='ha'> <text>bā̀kī</text> </gloss> <gloss lang='swh'> <text>mdomo / midomo</text> </gloss> <definition> <form lang='en'> <text>lip</text> </form> <form lang='es'> <text>labio</text> </form> <form lang='fr'> <text>lèvre</text> </form> <form lang='ha'> <text>bā̀kī</text> </form> <form lang='id'> <text>bibir</text> </form> <form lang='pt'> <text>lábio</text> </form> <form lang='swh'> <text>mdomo / midomo</text> </form> </definition> <note type='source'> <form lang='x-unk'> <text> 00<span lang='en'>16</span></text> </form> </note> <field type='SILCAWL'> <form lang='en'> <text>0016</text> </form> </field> <trait name='semantic-domain-ddp4' value='2.1.1.4 Mouth' /> </sense> </entry> </lift>" ; const string ancestor = @"<?xml version='1.0' encoding='utf-8'?> <lift version='0.13' producer='WeSay 1.0.0.0'> <entry id='nɪntɔnnʊ_49327c35-759e-4db3-984a-b7dc5af1b1b0' dateCreated='2012-01-30T10:45:04Z' dateModified='2012-01-30T10:59:31Z' guid='49327c35-759e-4db3-984a-b7dc5af1b1b0'> <lexical-unit> <form lang='vag-fonipa-x-etic'> <text>nɪ́ntɔ́nnʊ̄</text> </form> </lexical-unit> <annotation name='sorted-index' value='10' /> <field type='pl'> <form lang='vag-fonipa-x-etic'> <text>nɪ́ntɔ́ntʊ́</text> </form> </field> <field type='tn'> <form lang='fr'> <text>HHM</text> </form> </field> <field type='tnpl'> <form lang='fr'> <text>HHH</text> </form> </field> <sense id='lip_39e4b942-0bf6-4494-aa9b-7f5163feb2bc'> <grammatical-info value='Noun' /> <gloss lang='en'> <text>lip</text> </gloss> <gloss lang='es'> <text>labio</text> </gloss> <gloss lang='fr'> <text>lèvre</text> </gloss> <gloss lang='ha'> <text>bā̀kī</text> </gloss> <gloss lang='swh'> <text>mdomo / midomo</text> </gloss> <definition> <form lang='en'> <text>lip</text> </form> <form lang='es'> <text>labio</text> </form> <form lang='fr'> <text>lèvre</text> </form> <form lang='ha'> <text>bā̀kī</text> </form> <form lang='id'> <text>bibir</text> </form> <form lang='pt'> <text>lábio</text> </form> <form lang='swh'> <text>mdomo / midomo</text> </form> </definition> <note type='source'> <form lang='x-unk'> <text> 00<span lang='en'>16</span></text> </form> </note> <field type='SILCAWL'> <form lang='en'> <text>0016</text> </form> </field> <trait name='semantic-domain-ddp4' value='2.1.1.4 Mouth' /> </sense> </entry> </lift>" ; using (var oursTemp = new TempFile(ours)) using (var theirsTemp = new TempFile(theirs)) using (var ancestorTemp = new TempFile(ancestor)) { var listener = new ListenerForUnitTests(); var situation = new NullMergeSituation(); 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); //each of these are things we saw go wrong in the user's failed merge. we combined all the missing data //into a single entry. This never did demonstrate the problem, but it ruled out that the problem //was a simple one of failure to merge entries properly! //glosses like this were being lost XmlTestHelper.AssertXPathMatchesExactlyOne(result, "lift/entry/sense/gloss[@lang='nku-fonipa-x-etic']"); //there was a case where the <annotation> was in the base, but not the piers, yet it showed up in the merge! XmlTestHelper.AssertXPathIsNull(result, "lift/entry/annotation"); //notes were being lost XmlTestHelper.AssertXPathMatchesExactlyOne(result, "lift/entry/note/form[@lang='fr']"); } }
public void ClassSpansMerge() { var ancestor = @"<?xml version='1.0' encoding='utf-8'?> <lift version='0.13' producer='FLEx 7.2.4'> <entry id='lovely_f1c5a4c8-a24f-4351-8551-2b70d53a9256' guid='f1c5a4c8-a24f-4351-8551-2b70d53a9256'> <lexical-unit> <form lang='fr'><text>lovely</text></form> </lexical-unit> <trait name='morph-type' value='stem'/> <sense id='de53a9a1-5b70-49e5-8dbe-171bff37d624'> <example> <form lang='fr'> <text>This is <span class='Strong'>an</span> example.</text> </form> <translation type='Free translation'> <form lang='en'> <text>A translation of <span class='Strong'>the</span> example</text> </form> </translation> </example> </sense> </entry> </lift>" ; var ours = // add 'sentence' to example @"<?xml version='1.0' encoding='utf-8'?> <lift version='0.13' producer='FLEx 7.2.4'> <entry id='lovely_f1c5a4c8-a24f-4351-8551-2b70d53a9256' guid='f1c5a4c8-a24f-4351-8551-2b70d53a9256'> <lexical-unit> <form lang='fr'><text>lovely</text></form> </lexical-unit> <trait name='morph-type' value='stem'/> <sense id='de53a9a1-5b70-49e5-8dbe-171bff37d624'> <example> <form lang='fr'> <text>This is <span class='Strong'>an</span> example sentence.</text> </form> <translation type='Free translation'> <form lang='en'> <text>A translation of <span class='Strong'>the</span> example</text> </form> </translation> </example> </sense> </entry> </lift>" ; var theirs = // add 'sentence' to TRANSLATION of example @"<?xml version='1.0' encoding='utf-8'?> <lift version='0.13' producer='FLEx 7.2.4'> <entry id='lovely_f1c5a4c8-a24f-4351-8551-2b70d53a9256' guid='f1c5a4c8-a24f-4351-8551-2b70d53a9256'> <lexical-unit> <form lang='fr'><text>lovely</text></form> </lexical-unit> <trait name='morph-type' value='stem'/> <sense id='de53a9a1-5b70-49e5-8dbe-171bff37d624'> <example> <form lang='fr'> <text>This is <span class='Strong'>an</span> example.</text> </form> <translation type='Free translation'> <form lang='en'> <text>A translation of <span class='Strong'>the</span> example sentence</text> </form> </translation> </example> </sense> </entry> </lift>" ; using (var oursTemp = new TempFile(ours)) using (var theirsTemp = new TempFile(theirs)) using (var ancestorTemp = new TempFile(ancestor)) { var listener = new ListenerForUnitTests(); var situation = new NullMergeSituation(); 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); AssertThatXmlIn.String(result).HasSpecifiedNumberOfMatchesForXpath(@"/lift/entry/sense/example/form/text/span", 1); AssertThatXmlIn.String(result).HasSpecifiedNumberOfMatchesForXpath(@"/lift/entry/sense/example/translation/form/text/span", 1); } }