コード例 #1
0
        private static XmlNode HandleCaseOfNoAncestor(XmlMerger merger, XmlNode ours, XmlNode theirs)
        {
            var mainNodeStrategy       = merger.MergeStrategies.GetElementStrategy(ours ?? theirs);
            var mergeSituation         = merger.MergeSituation;
            var pathToFileInRepository = mergeSituation.PathToFileInRepository;

            if (ours == null)
            {
                // They added, we did nothing.
// Route tested, but the MergeChildrenMethod adds the change report for us.
                // So, theory has it one can't get here from any normal place.
                // But, keep it, in case MergeChildrenMethod gets 'fixed'.
                merger.EventListener.ChangeOccurred(new XmlAdditionChangeReport(pathToFileInRepository, theirs));
                return(theirs);
            }
            if (theirs == null)
            {
                // We added, they did nothing.
// Route tested.
                merger.EventListener.ChangeOccurred(new XmlAdditionChangeReport(pathToFileInRepository, ours));
                return(ours);
            }

            // Both added the special containing node.
            // Remove children nodes to see if main containing nodes are the same.
            if (XmlUtilities.AreXmlElementsEqual(ours, theirs))
            {
// Route tested.
                // Same content.
                merger.EventListener.ChangeOccurred(new XmlBothAddedSameChangeReport(pathToFileInRepository, ours));
            }
            else
            {
                // Different content.
                var ourChild   = GetElementChildren(ours).FirstOrDefault();
                var theirChild = GetElementChildren(theirs).FirstOrDefault();
                var ourClone   = MakeClone(ours);
                var theirClone = MakeClone(theirs);
                if (XmlUtilities.AreXmlElementsEqual(ourClone, theirClone))
                {
                    // new main elements are the same, but not the contained child
                    merger.EventListener.ChangeOccurred(new XmlBothAddedSameChangeReport(pathToFileInRepository, ourClone));
                    if (ourChild == null && theirChild == null)
                    {
                        return(ours);                        // Nobody added the child node.
                    }
                    if (ourChild == null)
                    {
                        merger.EventListener.ChangeOccurred(new XmlAdditionChangeReport(pathToFileInRepository, theirChild));
                        // ReSharper disable once PossibleNullReferenceException -- if ours.OwnerDocument is null, we have other problems
                        ours.AppendChild(ours.OwnerDocument.ImportNode(theirChild, true));
                        return(ours);
                    }
                    if (theirChild == null)
                    {
                        merger.EventListener.ChangeOccurred(new XmlAdditionChangeReport(pathToFileInRepository, ourChild));
                        return(ours);
                    }
                    // both children exist, but are different.
                    var mergeStrategyForChild = merger.MergeStrategies.GetElementStrategy(ourChild);
                    if (merger.MergeSituation.ConflictHandlingMode == MergeOrder.ConflictHandlingModeChoices.WeWin)
                    {
                        // Do the clone thing on the two child nodes to see if the diffs are in the child or lower down.
                        var ourChildClone   = MakeClone(ourChild);
                        var theirChildClone = MakeClone(theirChild);
                        if (XmlUtilities.AreXmlElementsEqual(ourChildClone, theirChildClone))
                        {
                            var ourChildReplacement = ourChild;
                            merger.MergeInner(ours, ref ourChildReplacement, theirChild, null);
                            if (!ReferenceEquals(ourChild, ourChildReplacement))
                            {
                                XmlUtilities.ReplaceOursWithTheirs(ours, ref ourChild, ourChildReplacement);
                            }
                        }
                        else
                        {
                            merger.ConflictOccurred(new BothAddedMainElementButWithDifferentContentConflict(ourChild.Name, ourChild, theirChild,
                                                                                                            mergeSituation, mergeStrategyForChild,
                                                                                                            mergeSituation.AlphaUserId));
                        }
                    }
                    else
                    {
                        // Do the clone thing on the two child nodes to see if the diffs are in the child or lower down.
                        var ourChildClone   = MakeClone(ourChild);
                        var theirChildClone = MakeClone(theirChild);
                        if (XmlUtilities.AreXmlElementsEqual(ourChildClone, theirChildClone))
                        {
                            var ourChildReplacement = ourChild;
                            merger.MergeInner(ours, ref ourChildReplacement, theirChild, null);
                            if (!ReferenceEquals(ourChild, ourChildReplacement))
                            {
                                XmlUtilities.ReplaceOursWithTheirs(ours, ref ourChild, ourChildReplacement);
                            }
                        }
                        else
                        {
                            merger.ConflictOccurred(new BothAddedMainElementButWithDifferentContentConflict(ourChild.Name, ourChild, theirChild,
                                                                                                            mergeSituation, mergeStrategyForChild,
                                                                                                            mergeSituation.AlphaUserId));
                            XmlUtilities.ReplaceOursWithTheirs(ours, ref ourChild, theirChild);
                        }
                    }
                    return(ours);
                }

                // Main containing element is not the same. Not to worry about child
                if (merger.MergeSituation.ConflictHandlingMode == MergeOrder.ConflictHandlingModeChoices.WeWin)
                {
                    merger.ConflictOccurred(new BothAddedMainElementButWithDifferentContentConflict(ours.Name, ours, theirs,
                                                                                                    mergeSituation, mainNodeStrategy,
                                                                                                    mergeSituation.AlphaUserId));
                }
                else
                {
                    merger.ConflictOccurred(new XmlTextBothAddedTextConflict(theirs.Name, theirs, ours, mergeSituation,
                                                                             mainNodeStrategy, mergeSituation.BetaUserId));
                    XmlUtilities.ReplaceOursWithTheirs(ours.ParentNode, ref ours, theirs);
                }
            }
            return(ours);
        }
コード例 #2
0
 public void XmlMergerDoesNotCallImmutableElementMergeServiceForMutableElement()
 {
     var listener = new ListenerForUnitTests();
     var merger = new XmlMerger(new NullMergeSituation())
     {
         EventListener = listener
     };
     var elemStrat = new ElementStrategy(false)
     {
         IsImmutable = false
     };
     merger.MergeStrategies.SetStrategy("MutableElemment", elemStrat);
     var ancestor = CreateNode("<MutableElemment attr='originalvalue' />");
     var ours = CreateNode("<MutableElemment attr='ourvalue' />");
     var theirs = CreateNode("<MutableElemment attr='originalvalue' />");
     merger.MergeInner(ref ours, theirs, ancestor);
     Assert.AreNotSame(ancestor, ours);
     Assert.AreEqual("<MutableElemment attr=\"ourvalue\" />", ours.OuterXml);
     listener.AssertExpectedChangesCount(1);
     listener.AssertFirstChangeType<XmlAttributeChangedReport>();
     listener.AssertExpectedConflictCount(0);
 }
コード例 #3
0
        private static XmlNode HandleCaseOfNoAncestorChild(XmlMerger merger, XmlNode ours, XmlNode ourChild, XmlNode theirChild)
        {
            var mergeSituation         = merger.MergeSituation;
            var pathToFileInRepository = mergeSituation.PathToFileInRepository;
            var mergeStrategyForChild  = merger.MergeStrategies.GetElementStrategy(ourChild ?? theirChild);

            if (ourChild == null)
            {
                // they added child.
                merger.EventListener.ChangeOccurred(new XmlAdditionChangeReport(pathToFileInRepository, theirChild));
                // ReSharper disable once PossibleNullReferenceException -- if ours.OwnerDocument is null, we have other problems
                ours.AppendChild(ours.OwnerDocument.ImportNode(theirChild, true));
                return(ours);
            }
            if (theirChild == null)
            {
                // We added child.
                merger.EventListener.ChangeOccurred(new XmlAdditionChangeReport(pathToFileInRepository, ourChild));
                return(ours);
            }
            // Both added child.
            if (XmlUtilities.AreXmlElementsEqual(ourChild, theirChild))
            {
                // Both are the same.
                merger.EventListener.ChangeOccurred(new XmlBothAddedSameChangeReport(pathToFileInRepository, ourChild));
                return(ours);
            }
            // Both are different.
            if (XmlUtilities.IsTextLevel(ourChild, theirChild, null))
            {
                if (merger.MergeSituation.ConflictHandlingMode == MergeOrder.ConflictHandlingModeChoices.WeWin)
                {
                    merger.ConflictOccurred(new XmlTextBothAddedTextConflict(ourChild.Name, ourChild, theirChild, mergeSituation,
                                                                             mergeStrategyForChild, mergeSituation.AlphaUserId));
                }
                else
                {
                    merger.ConflictOccurred(new XmlTextBothAddedTextConflict(theirChild.Name, theirChild, ourChild, mergeSituation,
                                                                             mergeStrategyForChild, mergeSituation.BetaUserId));
                    XmlUtilities.ReplaceOursWithTheirs(ours, ref ourChild, theirChild);
                }
            }
            else
            {
                if (merger.MergeSituation.ConflictHandlingMode == MergeOrder.ConflictHandlingModeChoices.WeWin)
                {
                    var ourChildClone   = MakeClone(ourChild);
                    var theirChildClone = MakeClone(theirChild);
                    if (XmlUtilities.AreXmlElementsEqual(ourChildClone, theirChildClone))
                    {
                        merger.EventListener.ChangeOccurred(new XmlAdditionChangeReport(pathToFileInRepository, ourChild));
                        var ourChildReplacement = ourChild;
                        merger.MergeInner(ours, ref ourChildReplacement, theirChild, null);
                        if (!ReferenceEquals(ourChild, ourChildReplacement))
                        {
                            XmlUtilities.ReplaceOursWithTheirs(ours, ref ourChild, ourChildReplacement);
                        }
                    }
                    else
                    {
                        merger.ConflictOccurred(new BothAddedMainElementButWithDifferentContentConflict(ourChild.Name, ourChild, theirChild,
                                                                                                        mergeSituation, mergeStrategyForChild,
                                                                                                        mergeSituation.AlphaUserId));
                    }
                }
                else
                {
                    var ourChildClone   = MakeClone(ourChild);
                    var theirChildClone = MakeClone(theirChild);
                    if (XmlUtilities.AreXmlElementsEqual(ourChildClone, theirChildClone))
                    {
                        merger.EventListener.ChangeOccurred(new XmlAdditionChangeReport(pathToFileInRepository, theirChild));
                        var ourChildReplacement = ourChild;
                        merger.MergeInner(ours, ref ourChildReplacement, theirChild, null);
                        if (!ReferenceEquals(ourChild, ourChildReplacement))
                        {
                            XmlUtilities.ReplaceOursWithTheirs(ours, ref ourChild, ourChildReplacement);
                        }
                    }
                    else
                    {
                        merger.ConflictOccurred(new BothAddedMainElementButWithDifferentContentConflict(theirChild.Name, theirChild, ourChild,
                                                                                                        mergeSituation, mergeStrategyForChild,
                                                                                                        mergeSituation.BetaUserId));
                        XmlUtilities.ReplaceOursWithTheirs(ours, ref ourChild, theirChild);
                    }
                }
            }
            return(ours);
        }
コード例 #4
0
        private static XmlNode HandleCaseOfNoAncestor(XmlMerger merger, XmlNode ours, XmlNode theirs)
        {
            var mainNodeStrategy = merger.MergeStrategies.GetElementStrategy(ours ?? theirs);
            var mergeSituation = merger.MergeSituation;
            var pathToFileInRepository = mergeSituation.PathToFileInRepository;
            if (ours == null)
            {
                // They added, we did nothing.
            // Route tested, but the MergeChildrenMethod adds the change report for us.
                // So, theory has it one can't get here from any normal place.
                // But, keep it, in case MergeChildrenMethod gets 'fixed'.
                merger.EventListener.ChangeOccurred(new XmlAdditionChangeReport(pathToFileInRepository, theirs));
                return theirs;
            }
            if (theirs == null)
            {
                // We added, they did nothing.
            // Route tested.
                merger.EventListener.ChangeOccurred(new XmlAdditionChangeReport(pathToFileInRepository, ours));
                return ours;
            }

            // Both added the special containing node.
            // Remove children nodes to see if main containing nodes are the same.
            if (XmlUtilities.AreXmlElementsEqual(ours, theirs))
            {
            // Route tested.
                // Same content.
                merger.EventListener.ChangeOccurred(new XmlBothAddedSameChangeReport(pathToFileInRepository, ours));
            }
            else
            {
                // Different content.
                var ourChild = GetElementChildren(ours).FirstOrDefault();
                var theirChild = GetElementChildren(theirs).FirstOrDefault();
                var ourClone = MakeClone(ours);
                var theirClone = MakeClone(theirs);
                if (XmlUtilities.AreXmlElementsEqual(ourClone, theirClone))
                {
                    // new main elements are the same, but not the contained child
                    merger.EventListener.ChangeOccurred(new XmlBothAddedSameChangeReport(pathToFileInRepository, ourClone));
                    if (ourChild == null && theirChild == null)
                        return ours; // Nobody added the child node.
                    if (ourChild == null)
                    {
                        merger.EventListener.ChangeOccurred(new XmlAdditionChangeReport(pathToFileInRepository, theirChild));
                        ours.AppendChild(theirChild);
                        return ours;
                    }
                    if (theirChild == null)
                    {
                        merger.EventListener.ChangeOccurred(new XmlAdditionChangeReport(pathToFileInRepository, ourChild));
                        return ours;
                    }
                    // both children exist, but are different.
                    var mergeStrategyForChild = merger.MergeStrategies.GetElementStrategy(ourChild);
                    if (merger.MergeSituation.ConflictHandlingMode == MergeOrder.ConflictHandlingModeChoices.WeWin)
                    {
                        // Do the clone thing on the two child nodes to see if the diffs are in the child or lower down.
                        var ourChildClone = MakeClone(ourChild);
                        var theirChildClone = MakeClone(theirChild);
                        if (XmlUtilities.AreXmlElementsEqual(ourChildClone, theirChildClone))
                        {
                            var ourChildReplacement = ourChild;
                            merger.MergeInner(ours, ref ourChildReplacement, theirChild, null);
                            if (!ReferenceEquals(ourChild, ourChildReplacement))
                            {
                                XmlUtilities.ReplaceOursWithTheirs(ours, ref ourChild, ourChildReplacement);
                            }
                        }
                        else
                        {
                            merger.ConflictOccurred(new BothAddedMainElementButWithDifferentContentConflict(ourChild.Name, ourChild, theirChild,
                                                                                                            mergeSituation, mergeStrategyForChild,
                                                                                                            mergeSituation.AlphaUserId));
                        }
                    }
                    else
                    {
                        // Do the clone thing on the two child nodes to see if the diffs are in the child or lower down.
                        var ourChildClone = MakeClone(ourChild);
                        var theirChildClone = MakeClone(theirChild);
                        if (XmlUtilities.AreXmlElementsEqual(ourChildClone, theirChildClone))
                        {
                            var ourChildReplacement = ourChild;
                            merger.MergeInner(ours, ref ourChildReplacement, theirChild, null);
                            if (!ReferenceEquals(ourChild, ourChildReplacement))
                            {
                                XmlUtilities.ReplaceOursWithTheirs(ours, ref ourChild, ourChildReplacement);
                            }
                        }
                        else
                        {
                            merger.ConflictOccurred(new BothAddedMainElementButWithDifferentContentConflict(ourChild.Name, ourChild, theirChild,
                                                                                                            mergeSituation, mergeStrategyForChild,
                                                                                                            mergeSituation.AlphaUserId));
                            XmlUtilities.ReplaceOursWithTheirs(ours, ref ourChild, theirChild);
                        }
                    }
                    return ours;
                }

                // Main containing element is not the same. Not to worry about child
                if (merger.MergeSituation.ConflictHandlingMode == MergeOrder.ConflictHandlingModeChoices.WeWin)
                {
                    merger.ConflictOccurred(new BothAddedMainElementButWithDifferentContentConflict(ours.Name, ours, theirs,
                                                                                                    mergeSituation, mainNodeStrategy,
                                                                                                    mergeSituation.AlphaUserId));
                }
                else
                {
                    merger.ConflictOccurred(new XmlTextBothAddedTextConflict(theirs.Name, theirs, ours, mergeSituation,
                                                                             mainNodeStrategy, mergeSituation.BetaUserId));
                    XmlUtilities.ReplaceOursWithTheirs(ours.ParentNode, ref ours, theirs);
                }
            }
            return ours;
        }
コード例 #5
0
 public void XmlMergerCallsImmutableElementMergeServiceForImmutableElement()
 {
     var listener = new ListenerForUnitTests();
     var merger = new XmlMerger(new NullMergeSituation())
     {
         EventListener = listener
     };
     var elemStrat = new ElementStrategy(false)
         {
             IsImmutable = true
         };
     merger.MergeStrategies.SetStrategy("ImmutableElemment", elemStrat);
     var ancestor = CreateNode("<ImmutableElemment attr='originalvalue' />");
     var ours = CreateNode("<ImmutableElemment attr='ourvalue' />");
     var theirs = CreateNode("<ImmutableElemment attr='theirvalue' />");
     merger.MergeInner(ref ours, theirs, ancestor);
     Assert.AreSame(ancestor, ours);
     Assert.AreEqual("<ImmutableElemment attr=\"originalvalue\" />", ancestor.OuterXml);
     listener.AssertExpectedChangesCount(0);
     listener.AssertExpectedConflictCount(0);
 }
コード例 #6
0
        private static XmlNode Run(XmlMerger merger, XmlNode ours, XmlNode theirs, XmlNode ancestor)
        {
            if (ours == null && theirs == null && ancestor == null)
                return null;

            if (ancestor == null)
            {
                return HandleCaseOfNoAncestor(merger, ours, theirs);
            }
            // ancestor is not null at this point.
            var mergeSituation = merger.MergeSituation;
            var pathToFileInRepository = mergeSituation.PathToFileInRepository;
            if (ours == null && theirs == null)
            {
                // We both deleted main node.
            // Route tested, but the MergeChildrenMethod adds the change report for us.
                merger.EventListener.ChangeOccurred(new XmlBothDeletionChangeReport(pathToFileInRepository, ancestor));
                return null;
            }
            if (ours == null)
            {
                return HandleOursNotPresent(merger, ancestor, theirs);
            }
            if (theirs == null)
            {
                return HandleTheirsNotPresent(merger, ancestor, ours);
            }
            // End of checking main parent node.

            // ancestor, ours, and theirs all exist here.
            var ourChild = GetElementChildren(ours).FirstOrDefault();
            var theirChild = GetElementChildren(theirs).FirstOrDefault();
            var ancestorChild = GetElementChildren(ancestor).FirstOrDefault();
            if (ourChild == null && theirChild == null && ancestorChild == null)
            {
                return ours; // All three are childless.
            }

            if (ancestorChild == null)
            {
                return HandleCaseOfNoAncestorChild(merger, ours, ourChild, theirChild);
            }
            var mergeStrategyForChild = merger.MergeStrategies.GetElementStrategy(ancestorChild);
            if (ourChild == null)
            {
                return HandleOurChildNotPresent(merger, ours, ancestor, theirChild, pathToFileInRepository, ancestorChild, mergeSituation, mergeStrategyForChild);
            }
            if (theirChild == null)
            {
                return HandleTheirChildNotPresent(merger, ours, ancestor, ancestorChild, ourChild, mergeSituation, mergeStrategyForChild, pathToFileInRepository);
            }

            // ancestorChild, ourChild, and theirChild all exist.
            // But, it could be that we or they deleted and added something.
            // Check for edit vs delete+add, or there can be two items in ours, which is not legal.
            var match = mergeStrategyForChild.MergePartnerFinder.GetNodeToMerge(ourChild, ancestor, SetFromChildren.Get(ancestor));
            if (match == null)
            {
                // we deleted it and added a new one.
                if (XmlUtilities.AreXmlElementsEqual(theirChild, ancestorChild))
                {
                    // Our delete+add wins, since they did nothing.
                    merger.EventListener.ChangeOccurred(new XmlDeletionChangeReport(pathToFileInRepository, ancestor, ancestorChild));
                    merger.EventListener.ChangeOccurred(new XmlAdditionChangeReport(pathToFileInRepository, ourChild));
                    return ours;
                }

                // They edited old one, so they win over our delete+add.
                merger.ConflictOccurred(new RemovedVsEditedElementConflict(theirChild.Name, theirChild, null, ancestorChild,
                                                                           mergeSituation, mergeStrategyForChild,
                                                                           mergeSituation.BetaUserId));
                XmlUtilities.ReplaceOursWithTheirs(ours, ref ourChild, theirChild);
                return ours;
            }
            match = mergeStrategyForChild.MergePartnerFinder.GetNodeToMerge(theirChild, ancestor, SetFromChildren.Get(ancestor));
            if (match == null)
            {
                // they deleted it and added a new one.
                if (XmlUtilities.AreXmlElementsEqual(ourChild, ancestorChild))
                {
                    // Their delete+add wins, since we did nothing.
                    merger.EventListener.ChangeOccurred(new XmlDeletionChangeReport(pathToFileInRepository, ancestor, ancestorChild));
                    merger.EventListener.ChangeOccurred(new XmlAdditionChangeReport(pathToFileInRepository, theirChild));
                    XmlUtilities.ReplaceOursWithTheirs(ours, ref ourChild, theirChild);
                    return ours;
                }

                // We edited old one, so we win over their delete+add.
                merger.ConflictOccurred(new RemovedVsEditedElementConflict(ourChild.Name, ourChild, null, ancestorChild,
                                                                           mergeSituation, mergeStrategyForChild,
                                                                           mergeSituation.AlphaUserId));
                return ours;
            }
            merger.MergeInner(ours, ref ourChild, theirChild, ancestorChild);
            // Route tested. (UsingWith_NumberOfChildrenAllowed_ZeroOrOne_DoesNotThrowWhenParentHasOneChildNode)
            return ours;
        }
コード例 #7
0
 private static XmlNode HandleCaseOfNoAncestorChild(XmlMerger merger, XmlNode ours, XmlNode ourChild, XmlNode theirChild)
 {
     var mergeSituation = merger.MergeSituation;
     var pathToFileInRepository = mergeSituation.PathToFileInRepository;
     var mergeStrategyForChild = merger.MergeStrategies.GetElementStrategy(ourChild ?? theirChild);
     if (ourChild == null)
     {
         // they added child.
         merger.EventListener.ChangeOccurred(new XmlAdditionChangeReport(pathToFileInRepository, theirChild));
         ours.AppendChild(theirChild);
         return ours;
     }
     if (theirChild == null)
     {
         // We added child.
         merger.EventListener.ChangeOccurred(new XmlAdditionChangeReport(pathToFileInRepository, ourChild));
         return ours;
     }
     // Both added child.
     if (XmlUtilities.AreXmlElementsEqual(ourChild, theirChild))
     {
         // Both are the same.
         merger.EventListener.ChangeOccurred(new XmlBothAddedSameChangeReport(pathToFileInRepository, ourChild));
         return ours;
     }
     // Both are different.
     if (XmlUtilities.IsTextLevel(ourChild, theirChild, null))
     {
         if (merger.MergeSituation.ConflictHandlingMode == MergeOrder.ConflictHandlingModeChoices.WeWin)
         {
             merger.ConflictOccurred(new XmlTextBothAddedTextConflict(ourChild.Name, ourChild, theirChild, mergeSituation,
                                                                      mergeStrategyForChild, mergeSituation.AlphaUserId));
         }
         else
         {
             merger.ConflictOccurred(new XmlTextBothAddedTextConflict(theirChild.Name, theirChild, ourChild, mergeSituation,
                                                                      mergeStrategyForChild, mergeSituation.BetaUserId));
             XmlUtilities.ReplaceOursWithTheirs(ours, ref ourChild, theirChild);
         }
     }
     else
     {
         if (merger.MergeSituation.ConflictHandlingMode == MergeOrder.ConflictHandlingModeChoices.WeWin)
         {
             var ourChildClone = MakeClone(ourChild);
             var theirChildClone = MakeClone(theirChild);
             if (XmlUtilities.AreXmlElementsEqual(ourChildClone, theirChildClone))
             {
                 merger.EventListener.ChangeOccurred(new XmlAdditionChangeReport(pathToFileInRepository, ourChild));
                 var ourChildReplacement = ourChild;
                 merger.MergeInner(ours, ref ourChildReplacement, theirChild, null);
                 if (!ReferenceEquals(ourChild, ourChildReplacement))
                 {
                     XmlUtilities.ReplaceOursWithTheirs(ours, ref ourChild, ourChildReplacement);
                 }
             }
             else
             {
                 merger.ConflictOccurred(new BothAddedMainElementButWithDifferentContentConflict(ourChild.Name, ourChild, theirChild,
                                                                                                 mergeSituation, mergeStrategyForChild,
                                                                                                 mergeSituation.AlphaUserId));
             }
         }
         else
         {
             var ourChildClone = MakeClone(ourChild);
             var theirChildClone = MakeClone(theirChild);
             if (XmlUtilities.AreXmlElementsEqual(ourChildClone, theirChildClone))
             {
                 merger.EventListener.ChangeOccurred(new XmlAdditionChangeReport(pathToFileInRepository, theirChild));
                 var ourChildReplacement = ourChild;
                 merger.MergeInner(ours, ref ourChildReplacement, theirChild, null);
                 if (!ReferenceEquals(ourChild, ourChildReplacement))
                 {
                     XmlUtilities.ReplaceOursWithTheirs(ours, ref ourChild, ourChildReplacement);
                 }
             }
             else
             {
                 merger.ConflictOccurred(new BothAddedMainElementButWithDifferentContentConflict(theirChild.Name, theirChild, ourChild,
                                                                                                 mergeSituation, mergeStrategyForChild,
                                                                                                 mergeSituation.BetaUserId));
                 XmlUtilities.ReplaceOursWithTheirs(ours, ref ourChild, theirChild);
             }
         }
     }
     return ours;
 }
コード例 #8
0
        private static XmlNode Run(XmlMerger merger, XmlNode ours, XmlNode theirs, XmlNode ancestor)
        {
            if (ours == null && theirs == null && ancestor == null)
                return null;

            var ourChild = GetElementChildren(ours).FirstOrDefault();
            var theirChild = GetElementChildren(theirs).FirstOrDefault();
            var ancestorChild = GetElementChildren(ancestor).FirstOrDefault();
            XmlNode ourReplacementChild;
            if (ancestor == null)
            {
                if (ours == null)
                {
                    // They added, we did nothing.
            // Route tested, but the MergeChildrenMethod adds the change report for us.
                    // So, theory has it one can't get here from any normal place.
                    // But, keep it, in case MergeChildrenMethod gets 'fixed'.
                    merger.EventListener.ChangeOccurred(new XmlAdditionChangeReport(merger.MergeSituation.PathToFileInRepository, theirs));
                    return theirs;
                }
                if (theirs == null)
                {
                    // We added, they did nothing.
            // Route tested.
                    merger.EventListener.ChangeOccurred(new XmlAdditionChangeReport(merger.MergeSituation.PathToFileInRepository, ours));
                    return ours;
                }

                // Both added the special containing node.
            // Route tested.
                merger.EventListener.ChangeOccurred(new XmlBothAddedSameChangeReport(merger.MergeSituation.PathToFileInRepository, ours));

                if (ourChild == null && theirChild == null && ancestorChild == null)
                    return null; // Route tested.

                if (ourChild == null && theirChild != null)
                {
            // Route tested.
                    merger.EventListener.ChangeOccurred(new XmlAdditionChangeReport(merger.MergeSituation.PathToFileInRepository, theirChild));
                    ours.AppendChild(theirChild);
                    return ours;
                }
                if (theirChild == null)
                {
            // Route tested.
                    merger.EventListener.ChangeOccurred(new XmlAdditionChangeReport(merger.MergeSituation.PathToFileInRepository, ourChild));
                    return ours;
                }

                // Both ourChild and theirChild exist, and may or may not be the same.
                var mergeStrategy = merger.MergeStrategies.GetElementStrategy(ourChild);
                var match = mergeStrategy.MergePartnerFinder.GetNodeToMerge(ourChild, theirs, SetFromChildren.Get(theirs));
                if (match == null)
                {
                    XmlNode winner;
                    string winnerId;
                    XmlNode loser;
                    // Work up conflict report (for both we and they win options), since the users didn't add the same thing.
                    if (merger.MergeSituation.ConflictHandlingMode == MergeOrder.ConflictHandlingModeChoices.WeWin)
                    {
                        winner = ourChild;
                        winnerId = merger.MergeSituation.AlphaUserId;
                        loser = theirChild;
                    }
                    else
                    {
                        winner = theirChild;
                        winnerId = merger.MergeSituation.BetaUserId;
                        loser = ourChild;
                        ours = theirs;
                    }
            // Route tested.
                    merger.ConflictOccurred(new BothAddedMainElementButWithDifferentContentConflict(winner.Name, winner, loser, merger.MergeSituation, mergeStrategy, winnerId));
                    return ours;
                }

                // Matched nodes, as far as that goes. But, are they the same or not?
                if (XmlUtilities.AreXmlElementsEqual(ourChild, theirChild))
                {
                    // Both added the same thing.
            // Route tested.
                    merger.EventListener.ChangeOccurred(new XmlBothAddedSameChangeReport(merger.MergeSituation.PathToFileInRepository, ourChild));
                    return ours;
                }

                // Move on down and merge them.
                // Both messed with the inner stuff, but not the same way.
            // Route tested.
                ourReplacementChild = ourChild;
                merger.MergeInner(ref ourReplacementChild, theirChild, ancestorChild);
                if (!ReferenceEquals(ourChild, ourReplacementChild))
                    ours.ReplaceChild(ours.OwnerDocument.ImportNode(ourReplacementChild, true), ourChild);

                return ours;
            }

            // ancestor is not null at this point.
            // Check the inner nodes
            if (ours == null && theirs == null)
            {
                // We both deleted main node.
            // Route tested, but the MergeChildrenMethod adds the change report for us.
                merger.EventListener.ChangeOccurred(new XmlBothDeletionChangeReport(merger.MergeSituation.PathToFileInRepository, ancestor));
                return null;
            }
            if (ours == null)
            {
                // We deleted it.
            // Route tested, but the MergeChildrenMethod adds the change report for us.
                merger.EventListener.ChangeOccurred(new XmlDeletionChangeReport(merger.MergeSituation.PathToFileInRepository, ancestor, theirs));
                ours = theirs;
                return ours;
            }
            if (theirs == null)
            {
                // They deleted it.
            // Route tested, but the MergeChildrenMethod adds the change report for us.
                merger.EventListener.ChangeOccurred(new XmlDeletionChangeReport(merger.MergeSituation.PathToFileInRepository, ancestor, ours));
                return ours;
            }

            // ours, theirs, and ancestor all exist here.
            new MergeChildrenMethod(ours, theirs, ancestor, merger).Run();

            // Route tested. (UsingWith_NumberOfChildrenAllowed_ZeroOrOne_DoesNotThrowWhenParentHasOneChildNode)
            return ours;
        }
コード例 #9
0
        /// <summary>
        /// Merges the children into the "ours" xmlnode, and uses the merger's listener to publish what happened
        /// </summary>
        public void Run()
        {
            // Pre-process three nodes to handle duplicates in each node, But only if finder is one of these:
            //		FindFirstElementWithSameName, FindByKeyAttribute, or FindByMultipleKeyAttributes.

            // Initialise lists of keepers to current ancestorChildren, ourChildren, theirChildren
            CopyChildrenToList(_ancestor, _childrenOfAncestorKeepers);
            CopyChildrenToList(_ours, _childrenOfOurKeepers);
            CopyChildrenToList(_theirs, _childrenOfTheirKeepers);

            // Deal with deletions.
            DoDeletions();

            // Allow the most promising parent's strategy to determine whether order is significant for children.
            // The default configuration of ElementStrategy uses an AskChildren strategy, which means individual
            // children determine whether their order is significant.
            var parentNode     = _ours ?? _theirs ?? _ancestor;
            var parentStrategy = _merger.MergeStrategies.GetElementStrategy(parentNode);
            var parentOrder    = parentStrategy == null ? ChildOrder.AskChildren : parentStrategy.ChildOrderPolicy.OrderSignificance(parentNode);
            // Determine if child order is important, we shouldn't create reordering conflicts if the order of children is unimportant
            var childOrderMatters = parentOrder == ChildOrder.Significant;

            if (parentOrder == ChildOrder.AskChildren && parentNode.HasChildNodes)
            {
                var childStrategy = _merger.MergeStrategies.GetElementStrategy(parentNode.FirstChild);
                if (childStrategy != null && childStrategy.OrderIsRelevant)
                {
                    childOrderMatters = true;
                }
            }

            ChildOrderer oursOrderer = new ChildOrderer(_childrenOfOurKeepers, _childrenOfTheirKeepers,
                                                        MakeCorrespondences(_childrenOfOurKeepers, _childrenOfTheirKeepers, _theirs), _merger, parentOrder);

            ChildOrderer resultOrderer = oursOrderer;             // default

            if (oursOrderer.OrderIsDifferent)
            {
                // The order of the two lists is not consistent. Compare with ancestor to see who changed.
                ChildOrderer ancestorOursOrderer = new ChildOrderer(_childrenOfAncestorKeepers, _childrenOfOurKeepers,
                                                                    MakeCorrespondences(_childrenOfAncestorKeepers, _childrenOfOurKeepers, _ours), _merger, parentOrder);

                ChildOrderer ancestorTheirsOrderer = new ChildOrderer(_childrenOfAncestorKeepers, _childrenOfTheirKeepers,
                                                                      MakeCorrespondences(_childrenOfAncestorKeepers, _childrenOfTheirKeepers, _theirs), _merger, parentOrder);

                if (ancestorTheirsOrderer.OrderIsDifferent)
                {
                    if (ancestorOursOrderer.OrderIsDifferent && childOrderMatters)
                    {
                        // stick with our orderer (we win), but report conflict.
                        // Route tested (XmlMergerTests).
                        _merger.ConflictOccurred(new BothReorderedElementConflict(_ours.Name, _ours,
                                                                                  _theirs, _ancestor, _merger.MergeSituation, _merger.MergeStrategies.GetElementStrategy(_ours),
                                                                                  _merger.MergeSituation.AlphaUserId));
                    }
                    else
                    {
                        // only they re-ordered; take their order as primary.
                        resultOrderer = new ChildOrderer(_childrenOfTheirKeepers, _childrenOfOurKeepers,
                                                         MakeCorrespondences(_childrenOfTheirKeepers, _childrenOfOurKeepers, _ours), _merger, parentOrder);
                    }
                }
                else if (!ancestorOursOrderer.OrderIsDifferent)
                {
                    // our order is different from theirs, but neither is different from the ancestor.
                    // the only way this can be true is if both inserted the same thing, but in
                    // different places. Stick with our orderer (we win), but report conflict.
                    // Route tested (XmlMergerTests).
                    _merger.ConflictOccurred(new BothInsertedAtDifferentPlaceConflict(_ours.Name, _ours,
                                                                                      _theirs, _ancestor, _merger.MergeSituation, _merger.MergeStrategies.GetElementStrategy(_ours),
                                                                                      _merger.MergeSituation.AlphaUserId));
                }
                // otherwise we re-ordered, but they didn't. That's not a problem, unless it resulted
                // in inconsistency or ambiguity in other stuff that someone added.
            }

            if (!resultOrderer.OrderIsConsistent ||
                (resultOrderer.OrderIsDifferent && resultOrderer.OrderIsAmbiguous))
            {
                // Route tested (XmlMergerTests[x2]).
                _merger.ConflictOccurred(new AmbiguousInsertReorderConflict(_ours.Name, _ours,
                                                                            _theirs, _ancestor, _merger.MergeSituation, _merger.MergeStrategies.GetElementStrategy(_ours),
                                                                            _merger.MergeSituation.AlphaUserId));
            }
            else if (resultOrderer.OrderIsAmbiguous)
            {
                // Route tested (MergeChildrenMethodTests, XmlMergerTests).
                _merger.ConflictOccurred(new AmbiguousInsertConflict(_ours.Name, _ours,
                                                                     _theirs, _ancestor, _merger.MergeSituation, _merger.MergeStrategies.GetElementStrategy(_ours),
                                                                     _merger.MergeSituation.AlphaUserId));
            }

            // Merge corresponding nodes.
            // 'resultsChildren' may contain nodes from either 'ours', 'theirs', or both,
            // as the 'resultsChildren' collection has been combined in the ordereing operation.
            List <XmlNode> resultsChildren = resultOrderer.GetResultList();

            for (int i = 0; i < resultsChildren.Count; i++)
            {
                XmlNode ourChild = resultsChildren[i];
                // The 'DoDeletions' method call, above, possibly called MergeTextNodesMethod.DoDeletions,
                // which may have added 'ourChild' to _skipInnerMergeFor,
                // as it did some fairly exotic work with full and partial deletions.
                // So, don't do those again here.
                if (_skipInnerMergeFor.Contains(ourChild))
                {
                    continue;
                }

                XmlNode theirChild;
                var     ancestorChild = FindMatchingNode(ourChild, _ancestor, new HashSet <XmlNode>(_childrenOfAncestorKeepers));

                if (resultOrderer.Correspondences.TryGetValue(ourChild, out theirChild) && !ChildrenAreSame(ourChild, theirChild))
                {
                    // Both 'ourChild' and 'theirChild exist. 'ancestorChild' may, or, may not, exist.
                    // There's a corresponding node and it isn't the same as ours...
                    // Route tested: MergeChildrenMethod_DiffOnlyTests.
                    _merger.MergeInner(ref ourChild, theirChild, ancestorChild);
                    resultsChildren[i] = ourChild;
                }
                else
                {
                    // 'theirChild' may, or may not, exist. But if it does exist, it is the same as 'ourChild'.

                    //Review JohnT (jh): Is this the correct interpretation?
                    if (ancestorChild == null)
                    {
                        if (XmlUtilities.IsTextNodeContainer(ourChild) == TextNodeStatus.IsTextNodeContainer)                         // No, it hasn't. MergeTextNodesMethod has already added the addition report.
                        {
                            if (theirChild == null)
                            {
                                // Route tested: MergeChildrenMethod_DiffOnlyTests & XmlMergerTests.
                                _merger.EventListener.ChangeOccurred(new XmlTextAddedReport(_merger.MergeSituation.PathToFileInRepository, ourChild));                                 // Route tested (x2).
                            }
                            else
                            {
                                _merger.EventListener.ChangeOccurred(new XmlTextBothAddedReport(_merger.MergeSituation.PathToFileInRepository, ourChild));                                 // Route tested
                            }
                        }
                        else if (!(ourChild is XmlCharacterData))
                        {
                            if (theirChild == null)
                            {
                                // Route tested (MergeChildrenMethodTests, XmlMergerTests).
                                _merger.EventListener.ChangeOccurred(new XmlAdditionChangeReport(_merger.MergeSituation.PathToFileInRepository, ourChild));
                            }
                            else
                            {
                                _merger.EventListener.ChangeOccurred(new XmlBothAddedSameChangeReport(_merger.MergeSituation.PathToFileInRepository, ourChild));
                            }
                        }
                    }
                    else
                    {
                        // ancestorChild is not null.
                        if (XmlUtilities.IsTextNodeContainer(ourChild) == TextNodeStatus.IsTextNodeContainer)
                        {
                            if (theirChild != null && !XmlUtilities.AreXmlElementsEqual(ourChild, ancestorChild))
                            {
                                _merger.EventListener.ChangeOccurred(new XmlTextBothMadeSameChangeReport(_merger.MergeSituation.PathToFileInRepository, ourChild));                                 // Route tested
                            }
                        }
                        else
                        {
                            _merger.MergeInner(ref ourChild, theirChild, ancestorChild);
                            resultsChildren[i] = ourChild;
                        }
                    }
                }
            }

            // Plug results back into 'ours'
            for (int i = 0; i < resultsChildren.Count; i++)
            {
                XmlNode ourChild = resultsChildren[i];
                while (_ours.ChildNodes.Count > i && ourChild != _ours.ChildNodes[i])
                {
                    _ours.RemoveChild(_ours.ChildNodes[i]);
                }
                if (_ours.ChildNodes.Count > i)
                {
                    continue;                     // we found the exact node already present, leave it alone.
                }
                if (ourChild.ParentNode == _ours)
                {
                    _ours.AppendChild(ourChild);
                }
                else
                {
                    if (ourChild is XmlElement)
                    {
                        _ours.AppendChild(_ours.OwnerDocument.ImportNode(ourChild, true));
                    }
                    else if (ourChild is XmlText)
                    {
                        _ours.AppendChild(_ours.OwnerDocument.CreateTextNode(ourChild.OuterXml));
                    }
                    else
                    {
                        Debug.Fail("so far we only know how to copy elements and text nodes at this point");
                    }
                }
            }
            // Remove any leftovers.
            while (_ours.ChildNodes.Count > resultsChildren.Count)
            {
                _ours.RemoveChild(_ours.ChildNodes[resultsChildren.Count]);
            }
        }
コード例 #10
0
        private static XmlNode Run(XmlMerger merger, XmlNode ours, XmlNode theirs, XmlNode ancestor)
        {
            if (ours == null && theirs == null && ancestor == null)
            {
                return(null);
            }

            if (ancestor == null)
            {
                return(HandleCaseOfNoAncestor(merger, ours, theirs));
            }
            // ancestor is not null at this point.
            var mergeSituation         = merger.MergeSituation;
            var pathToFileInRepository = mergeSituation.PathToFileInRepository;

            if (ours == null && theirs == null)
            {
                // We both deleted main node.
// Route tested, but the MergeChildrenMethod adds the change report for us.
                merger.EventListener.ChangeOccurred(new XmlBothDeletionChangeReport(pathToFileInRepository, ancestor));
                return(null);
            }
            if (ours == null)
            {
                return(HandleOursNotPresent(merger, ancestor, theirs));
            }
            if (theirs == null)
            {
                return(HandleTheirsNotPresent(merger, ancestor, ours));
            }
            // End of checking main parent node.

            // ancestor, ours, and theirs all exist here.
            var ourChild      = GetElementChildren(ours).FirstOrDefault();
            var theirChild    = GetElementChildren(theirs).FirstOrDefault();
            var ancestorChild = GetElementChildren(ancestor).FirstOrDefault();

            if (ourChild == null && theirChild == null && ancestorChild == null)
            {
                return(ours);                // All three are childless.
            }

            if (ancestorChild == null)
            {
                return(HandleCaseOfNoAncestorChild(merger, ours, ourChild, theirChild));
            }
            var mergeStrategyForChild = merger.MergeStrategies.GetElementStrategy(ancestorChild);

            if (ourChild == null)
            {
                return(HandleOurChildNotPresent(merger, ours, ancestor, theirChild, pathToFileInRepository, ancestorChild, mergeSituation, mergeStrategyForChild));
            }
            if (theirChild == null)
            {
                return(HandleTheirChildNotPresent(merger, ours, ancestor, ancestorChild, ourChild, mergeSituation, mergeStrategyForChild, pathToFileInRepository));
            }

            // ancestorChild, ourChild, and theirChild all exist.
            // But, it could be that we or they deleted and added something.
            // Check for edit vs delete+add, or there can be two items in ours, which is not legal.
            var match = mergeStrategyForChild.MergePartnerFinder.GetNodeToMerge(ourChild, ancestor, SetFromChildren.Get(ancestor));

            if (match == null)
            {
                // we deleted it and added a new one.
                if (XmlUtilities.AreXmlElementsEqual(theirChild, ancestorChild))
                {
                    // Our delete+add wins, since they did nothing.
                    merger.EventListener.ChangeOccurred(new XmlDeletionChangeReport(pathToFileInRepository, ancestor, ancestorChild));
                    merger.EventListener.ChangeOccurred(new XmlAdditionChangeReport(pathToFileInRepository, ourChild));
                    return(ours);
                }

                // They edited old one, so they win over our delete+add.
                merger.ConflictOccurred(new RemovedVsEditedElementConflict(theirChild.Name, theirChild, null, ancestorChild,
                                                                           mergeSituation, mergeStrategyForChild,
                                                                           mergeSituation.BetaUserId));
                ours.ReplaceChild(ours.OwnerDocument.ImportNode(theirChild, true), ourChild);
                return(ours);
            }
            match = mergeStrategyForChild.MergePartnerFinder.GetNodeToMerge(theirChild, ancestor, SetFromChildren.Get(ancestor));
            if (match == null)
            {
                // they deleted it and added a new one.
                if (XmlUtilities.AreXmlElementsEqual(ourChild, ancestorChild))
                {
                    // Their delete+add wins, since we did nothing.
                    merger.EventListener.ChangeOccurred(new XmlDeletionChangeReport(pathToFileInRepository, ancestor, ancestorChild));
                    merger.EventListener.ChangeOccurred(new XmlAdditionChangeReport(pathToFileInRepository, theirChild));
                    ours.ReplaceChild(ours.OwnerDocument.ImportNode(theirChild, true), ourChild);
                    return(ours);
                }

                // We edited old one, so we win over their delete+add.
                merger.ConflictOccurred(new RemovedVsEditedElementConflict(ourChild.Name, ourChild, null, ancestorChild,
                                                                           mergeSituation, mergeStrategyForChild,
                                                                           mergeSituation.AlphaUserId));
                return(ours);
            }

            merger.MergeInner(ref ourChild, theirChild, ancestorChild);

// Route tested. (UsingWith_NumberOfChildrenAllowed_ZeroOrOne_DoesNotThrowWhenParentHasOneChildNode)
            return(ours);
        }