public void SkipConvertingElementToTextElementInAnotherFile() { // Hack conversion skip, because Flex exported some lift-ranges stuff that wasn't legal. const string data = @"<?xml version='1.0' encoding='utf-8'?> <foo> <range id='theone' attr='data' > <form lang='ldb-fonipa-x-emic'> <element name='text'>myStuff</element> </form> </range> </foo>"; var originalValue = XmlMergeService.RemoveAmbiguousChildNodes; XmlMergeService.RemoveAmbiguousChildNodes = true; var doc = new XmlDocument(); doc.LoadXml(data); XmlMergeService.RemoveAmbiguousChildren(new ListenerForUnitTests(), new MergeStrategies(), doc.DocumentElement); XmlMergeService.RemoveAmbiguousChildNodes = originalValue; Assert.That(doc.DocumentElement.OuterXml, Does.Not.Contain("<text>myStuff</text>"), "Converted <element> element to <text>, but should not have."); Assert.That(doc.DocumentElement.OuterXml, Does.Contain("<element name=\"text\">myStuff</element>"), "Element <element> went away, but should have been present."); }
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']"); } }
public void Do3WayMerge(MergeOrder order) { XmlMergeService.Do3WayMerge(order, new ChorusNotesAnnotationMergingStrategy(order), false, null, "annotation", "guid"); }
[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"); } }
public void Do3WayMerge(MergeOrder mergeOrder) { // <mergenotice> // When the WeSay1.3 branch gets merged, do this: // 1. Keep this code and reject the WeSay1.3 changes. They were done as a partial port of some other code changes. // 2. Remove this <mergenotice> comment and its 'end tag' comment. // 3. The parm change from 'false' to 'true' is to be kept. XmlMergeService.Do3WayMerge(mergeOrder, new LiftEntryMergingStrategy(mergeOrder), true, "header", "entry", "guid"); // </mergenotice> }
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); } }); }
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 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]"); } }
internal void WarningOccurred(IConflict warning) { if (_htmlContextGenerator == null) { _htmlContextGenerator = new SimpleHtmlGenerator(); } XmlMergeService.AddWarningToListener( EventListener, warning, _oursContext, _theirsContext, _ancestorContext, _htmlContextGenerator); }
internal void ConflictOccurred(IConflict conflict) { if (_htmlContextGenerator == null) { _htmlContextGenerator = new SimpleHtmlGenerator(); } XmlMergeService.AddConflictToListener( EventListener, conflict, _oursContext, _theirsContext, _ancestorContext, _htmlContextGenerator); }
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']"); } }
internal void ConflictOccurred(IConflict conflict, XmlNode nodeToFindGeneratorFrom) { var contextDescriptorGenerator = GetContextDescriptorGenerator(nodeToFindGeneratorFrom); _htmlContextGenerator = (contextDescriptorGenerator as IGenerateHtmlContext) ?? new SimpleHtmlGenerator(); XmlMergeService.AddConflictToListener( EventListener, conflict, _oursContext, _theirsContext, _ancestorContext, _htmlContextGenerator, this, nodeToFindGeneratorFrom); }
public void DuplicateSpecialElementsAreRemoved() { const string badData = @"<ldml> <special xmlns:palaso='urn://palaso.org/ldmlExtensions/v1' /> <special xmlns:palaso='urn://palaso.org/ldmlExtensions/v1' goner='true' /> <special xmlns:palaso2='urn://palaso.org/ldmlExtensions/v2' /> <special xmlns:palaso2='urn://palaso.org/ldmlExtensions/v2' goner='true' /> <special xmlns:fw='urn://fieldworks.sil.org/ldmlExtensions/v1' /> <special xmlns:fw='urn://fieldworks.sil.org/ldmlExtensions/v1' goner='true' /> </ldml>"; var doc = new XmlDocument(); var badRootNode = XmlUtilities.GetDocumentNodeFromRawXml(badData, doc); var merger = new XmlMerger(new NullMergeSituation()); merger.EventListener = new ListenerForUnitTests(); LdmlFileHandler.SetupElementStrategies(merger); var oldValue = XmlMergeService.RemoveAmbiguousChildNodes; XmlMergeService.RemoveAmbiguousChildNodes = true; XmlMergeService.RemoveAmbiguousChildren(merger.EventListener, merger.MergeStrategies, badRootNode); XmlMergeService.RemoveAmbiguousChildNodes = oldValue; var childNodes = badRootNode.SelectNodes("special"); Assert.IsTrue(childNodes.Count == 3); for (var idx = 0; idx < 3; ++idx) { XmlNode currentNode = childNodes[idx]; switch (idx) { case 0: Assert.IsNotNull(currentNode.Attributes["xmlns:palaso"]); break; case 1: Assert.IsNotNull(currentNode.Attributes["xmlns:palaso2"]); break; case 2: Assert.IsNotNull(currentNode.Attributes["xmlns:fw"]); break; } Assert.IsNull(currentNode.Attributes["goner"]); } }
public void Do3WayMerge(MergeOrder mergeOrder) { // Debug.Fail("john"); Guard.AgainstNull(mergeOrder, "mergeOrder"); XmlMergeService.AddConflictToListener(mergeOrder.EventListener, new UnmergableFileTypeConflict(mergeOrder.MergeSituation)); switch (mergeOrder.MergeSituation.ConflictHandlingMode) { default: // just leave our file there break; case MergeOrder.ConflictHandlingModeChoices.WeWin: break; // just leave our file there case MergeOrder.ConflictHandlingModeChoices.TheyWin: File.Copy(mergeOrder.pathToTheirs, mergeOrder.pathToOurs, true); break; } }
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); } }
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"); } }
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 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 DuplicateWritingSystemsElementsAreRemoved() { const string badData = @"<UserLexiconSettings> <WritingSystems /> <WritingSystems goner='true' /> </UserLexiconSettings>"; var doc = new XmlDocument(); var badRootNode = XmlUtilities.GetDocumentNodeFromRawXml(badData, doc); var merger = new XmlMerger(new NullMergeSituation()); merger.EventListener = new ListenerForUnitTests(); ProjectLexiconSettingsFileHandler.SetupElementStrategies(merger); var oldValue = XmlMergeService.RemoveAmbiguousChildNodes; XmlMergeService.RemoveAmbiguousChildNodes = true; XmlMergeService.RemoveAmbiguousChildren(merger.EventListener, merger.MergeStrategies, badRootNode); XmlMergeService.RemoveAmbiguousChildNodes = oldValue; var childNodes = badRootNode.SelectNodes("WritingSystems"); Assert.That(childNodes, Is.Not.Null); Assert.That(childNodes.Count, Is.EqualTo(1)); Assert.That(childNodes[0].Attributes["goner"], Is.Null); }
public void ConvertBogusElementToTextElementInLiftRangesFile() { // Hack conversion, because Flex exported some lift-ranges stuff that wasn't legal. const string data = @"<range id='theone' attr='data' > <form lang='ldb-fonipa-x-emic'> <element name='text'>myStuff</element> </form> </range>" ; var originalValue = XmlMergeService.RemoveAmbiguousChildNodes; XmlMergeService.RemoveAmbiguousChildNodes = true; var doc = new XmlDocument(); doc.LoadXml(data); var results = XmlMergeService.RemoveAmbiguousChildren(new ListenerForUnitTests(), new MergeStrategies(), data, "some.lift-ranges"); XmlMergeService.RemoveAmbiguousChildNodes = originalValue; Assert.That(results, Does.Not.Contain("<element name=\"text\">first</element>"), "Still has bogus <element> element."); Assert.That(results, Does.Contain("<text>myStuff</text>"), "Converted <text> element is not present."); }
public void ConvertBogusElementToTextElementInLiftFile() { // Hack conversion, because Flex exported some lift-ranges stuff that wasn't legal. const string data = @"<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'> <element name='text'>myStuff</element> </form> </lexical-unit> </entry>" ; var originalValue = XmlMergeService.RemoveAmbiguousChildNodes; XmlMergeService.RemoveAmbiguousChildNodes = true; var result = XmlMergeService.RemoveAmbiguousChildren(new ListenerForUnitTests(), new MergeStrategies(), data, "some.lift"); XmlMergeService.RemoveAmbiguousChildNodes = originalValue; Assert.That(result, Does.Not.Contain("<element name=\"text\">first</element>"), "Still has bogus <element> element."); Assert.That(result, Does.Contain("<text>myStuff</text>"), "Converted <text> element is not present."); }
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 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']"); } }
private void RoundTripData(Stopwatch breakupTimer, Stopwatch restoreTimer, Stopwatch ambiguousTimer, StringBuilder sbValidation) { File.Copy(_srcFwdataPathname, _srcFwdataPathname + ".orig", true); // Keep it safe. GetFreshMdc(); // Want it fresh. breakupTimer.Start(); FLExProjectSplitter.PushHumptyOffTheWall(new NullProgress(), _srcFwdataPathname); breakupTimer.Stop(); GC.Collect(2, GCCollectionMode.Forced); if (_cbCheckAmbiguousElements.Checked) { var allDataFiles = new HashSet <string>(); var currentDir = Path.Combine(_workingDir, "Linguistics"); if (Directory.Exists(currentDir)) { allDataFiles.UnionWith(from pathname in Directory.GetFiles(currentDir, "*.*", SearchOption.AllDirectories) where !pathname.ToLowerInvariant().EndsWith("chorusnotes") select pathname); } currentDir = Path.Combine(_workingDir, "Anthropology"); if (Directory.Exists(currentDir)) { allDataFiles.UnionWith(from pathname in Directory.GetFiles(currentDir, "*.*", SearchOption.AllDirectories) where !pathname.ToLowerInvariant().EndsWith("chorusnotes") select pathname); } currentDir = Path.Combine(_workingDir, "Other"); if (Directory.Exists(currentDir)) { allDataFiles.UnionWith( from pathname in Directory.GetFiles(currentDir, "*.*", SearchOption.AllDirectories) where !pathname.ToLowerInvariant().EndsWith("chorusnotes") select pathname); } currentDir = Path.Combine(_workingDir, "General"); if (Directory.Exists(currentDir)) { allDataFiles.UnionWith(from pathname in Directory.GetFiles(currentDir, "*.*", SearchOption.AllDirectories) where !pathname.ToLowerInvariant().EndsWith("chorusnotes") select pathname); } var mergeOrder = new MergeOrder(null, null, null, new NullMergeSituation()) { EventListener = new ChangeAndConflictAccumulator() }; var merger = FieldWorksMergeServices.CreateXmlMergerForFieldWorksData(mergeOrder, MetadataCache.MdCache); ambiguousTimer.Start(); foreach (var dataFile in allDataFiles) { var extension = Path.GetExtension(dataFile).Substring(1); string optionalElementName = null; string mainRecordName = null; switch (extension) { case SharedConstants.Style: mainRecordName = SharedConstants.StStyle; break; case SharedConstants.List: mainRecordName = SharedConstants.CmPossibilityList; break; case SharedConstants.langproj: mainRecordName = SharedConstants.LangProject; break; case SharedConstants.Annotation: mainRecordName = SharedConstants.CmAnnotation; break; case SharedConstants.Filter: mainRecordName = SharedConstants.CmFilter; break; case SharedConstants.orderings: mainRecordName = SharedConstants.VirtualOrdering; break; case SharedConstants.pictures: mainRecordName = SharedConstants.CmPicture; break; case SharedConstants.ArchivedDraft: mainRecordName = SharedConstants.ScrDraft; break; case SharedConstants.ImportSetting: mainRecordName = SharedConstants.ScrImportSet; break; case SharedConstants.Srs: mainRecordName = SharedConstants.ScrRefSystem; break; case SharedConstants.Trans: mainRecordName = SharedConstants.Scripture; break; case SharedConstants.bookannotations: mainRecordName = SharedConstants.ScrBookAnnotations; break; case SharedConstants.book: mainRecordName = SharedConstants.ScrBook; break; case SharedConstants.Ntbk: optionalElementName = SharedConstants.Header; mainRecordName = SharedConstants.RnGenericRec; break; case SharedConstants.Reversal: optionalElementName = SharedConstants.Header; mainRecordName = SharedConstants.ReversalIndexEntry; break; case SharedConstants.Lexdb: optionalElementName = SharedConstants.Header; mainRecordName = SharedConstants.LexEntry; break; case SharedConstants.TextInCorpus: mainRecordName = SharedConstants.Text; break; case SharedConstants.Inventory: optionalElementName = SharedConstants.Header; mainRecordName = SharedConstants.WfiWordform; break; case SharedConstants.DiscourseExt: optionalElementName = SharedConstants.Header; mainRecordName = SharedConstants.DsChart; break; case SharedConstants.Featsys: mainRecordName = SharedConstants.FsFeatureSystem; break; case SharedConstants.Phondata: mainRecordName = SharedConstants.PhPhonData; break; case SharedConstants.Morphdata: mainRecordName = SharedConstants.MoMorphData; break; case SharedConstants.Agents: mainRecordName = SharedConstants.CmAgent; break; } using (var fastSplitter = new FastXmlElementSplitter(dataFile)) { bool foundOptionalFirstElement; foreach (var record in fastSplitter.GetSecondLevelElementBytes(optionalElementName, mainRecordName, out foundOptionalFirstElement)) { XmlMergeService.RemoveAmbiguousChildren(merger.EventListener, merger.MergeStrategies, CreateXmlNodeFromBytes(record)); } } } ambiguousTimer.Stop(); foreach (var warning in ((ChangeAndConflictAccumulator)merger.EventListener).Warnings) { sbValidation.AppendLine(warning.Description); sbValidation.AppendLine(); sbValidation.AppendLine(warning.HtmlDetails); sbValidation.AppendLine(); } GC.Collect(2, GCCollectionMode.Forced); } restoreTimer.Start(); FLExProjectUnifier.PutHumptyTogetherAgain(new NullProgress(), _srcFwdataPathname); restoreTimer.Stop(); GC.Collect(2, GCCollectionMode.Forced); }
public NodeMergeResult Merge(XmlNode ourParent, XmlNode ours, XmlNode theirs, XmlNode ancestor) { SendMergeHeartbeat(); if (ours == null && theirs == null && ancestor == null) { throw new InvalidOperationException("At least one node has to exist."); } var result = new NodeMergeResult(); var listener = EventListener as DispatchingMergeEventListener; if (listener == null) { var dispatcher = new DispatchingMergeEventListener(); dispatcher.AddEventListener(result); if (EventListener != null) { dispatcher.AddEventListener(EventListener); } EventListener = dispatcher; } else { listener.AddEventListener(result); } if (XmlMergeService.RemoveAmbiguousChildNodes) { // Remove any duplicate child nodes in all three. XmlMergeService.RemoveAmbiguousChildren(EventListener, MergeStrategies, ours); XmlMergeService.RemoveAmbiguousChildren(EventListener, MergeStrategies, theirs); XmlMergeService.RemoveAmbiguousChildren(EventListener, MergeStrategies, ancestor); } if (ancestor == null) { if (ours == null) { // tested EventListener.ChangeOccurred(new XmlAdditionChangeReport(MergeSituation.PathToFileInRepository, theirs)); result.MergedNode = theirs; } else if (theirs == null) { // tested EventListener.ChangeOccurred(new XmlAdditionChangeReport(MergeSituation.PathToFileInRepository, ours)); result.MergedNode = ours; } else { // Both added. if (XmlUtilities.AreXmlElementsEqual(ours, theirs)) { // Same thing. (tested) EventListener.ChangeOccurred(new XmlBothAddedSameChangeReport(MergeSituation.PathToFileInRepository, ours)); result.MergedNode = ours; } else { // But, not the same thing. if (MergeSituation.ConflictHandlingMode == MergeOrder.ConflictHandlingModeChoices.WeWin) { // tested ConflictOccurred(new BothAddedMainElementButWithDifferentContentConflict(ours.Name, ours, theirs, MergeSituation, MergeStrategies.GetElementStrategy(ours), MergeSituation.AlphaUserId)); result.MergedNode = ours; } else { // tested ConflictOccurred(new BothAddedMainElementButWithDifferentContentConflict(theirs.Name, theirs, ours, MergeSituation, MergeStrategies.GetElementStrategy(ours), MergeSituation.BetaUserId)); result.MergedNode = theirs; } } } return(result); } // ancestor exists if (ours == null && theirs == null) { // tested EventListener.ChangeOccurred(new XmlBothDeletionChangeReport(MergeSituation.PathToFileInRepository, ancestor)); result.MergedNode = null; return(result); } if (ours == null) { if (XmlUtilities.AreXmlElementsEqual(ancestor, theirs)) { // tested EventListener.ChangeOccurred(new XmlDeletionChangeReport(MergeSituation.PathToFileInRepository, ancestor, theirs)); result.MergedNode = null; } else { // tested ConflictOccurred(new RemovedVsEditedElementConflict(ancestor.Name, null, theirs, ancestor, MergeSituation, MergeStrategies.GetElementStrategy(ancestor), MergeSituation.BetaUserId)); result.MergedNode = theirs; } return(result); } if (theirs == null) { if (XmlUtilities.AreXmlElementsEqual(ancestor, ours)) { // tested EventListener.ChangeOccurred(new XmlDeletionChangeReport(MergeSituation.PathToFileInRepository, ancestor, ours)); result.MergedNode = null; } else { // tested ConflictOccurred(new EditedVsRemovedElementConflict(ancestor.Name, ours, null, ancestor, MergeSituation, MergeStrategies.GetElementStrategy(ancestor), MergeSituation.AlphaUserId)); result.MergedNode = ours; } return(result); } // All three nodes exist. MergeInner(ourParent, ref ours, theirs, ancestor); result.MergedNode = ours; return(result); }
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); } }
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); } }); }