public void Conflict_Range_Moves_Correctly()
        {
            VisualDiffOutput vdo = new VisualDiffOutput();
            vdo.AddLine("line 0", Algorithm.Diff.ChangeType.None);
            vdo.AddLine("line 1", Algorithm.Diff.ChangeType.User, true);
            vdo.AddLine("line 2", Algorithm.Diff.ChangeType.Template, true);
            vdo.ConflictRanges.Add(new VisualDiffOutput.ConflictRange(1, 3));

            Assert.That(vdo.IsLineInConflict(0), Is.False, "First line is not in conflict.");
            Assert.That(vdo.IsLineInConflict(1), "Second line is in conflict.");
            Assert.That(vdo.IsLineInConflict(2), "Third line is in conflict.");

            vdo.RemoveLine(0);

            Assert.That(vdo.LineCount, Is.EqualTo(2));
            Assert.That(vdo.IsLineInConflict(0), "First line is in conflict.");
            Assert.That(vdo.IsLineInConflict(1), "Second line is in conflict.");
        }
        public VisualDiffOutput ProcessMergeOutput()
        {
            if (fileInformation.UserFile.HasContents == false)
            {
                throw new InvalidOperationException("Cannot merge: User file has no contents");
            }
            if (fileInformation.NewGenFile.HasContents == false)
            {
                throw new InvalidOperationException("Cannot merge: Template file has no contents");
            }

            VisualDiffOutput vdo = new VisualDiffOutput();

            string leftText  = Common.Utility.StandardizeLineBreaks(fileInformation.NewGenFile.GetContents(), Common.Utility.LineBreaks.Unix);
            string rightText = Common.Utility.StandardizeLineBreaks(fileInformation.UserFile.GetContents(), Common.Utility.LineBreaks.Unix);

            StringUtility.RemoveTrailingLineBreaks(ref leftText);
            StringUtility.RemoveTrailingLineBreaks(ref rightText);

            leftText  = Common.Utility.StandardizeLineBreaks(leftText, Common.Utility.LineBreaks.Unix);
            rightText = Common.Utility.StandardizeLineBreaks(rightText, Common.Utility.LineBreaks.Unix);

            string[] leftLines  = leftText.Split('\n');
            string[] rightLines = rightText.Split('\n');

            Diff diff = new Diff(leftLines, rightLines, true, true);

            foreach (Diff.Hunk h in diff)
            {
                if (h.Same)
                {
                    foreach (string line in h.Original())
                    {
                        vdo.AddLine(line, ChangeType.None);
                    }
                    continue;
                }

                // Is this a conflict?
                if (h.Left.Count > 0 && h.Right.Count > 0)
                {
                    int startIndex = vdo.LineCount;

                    foreach (string line in h.Right)
                    {
                        vdo.LeftLines.Add(new DiffLine(line, ChangeType.User));
                    }
                    foreach (string line in h.Left)
                    {
                        vdo.LeftLines.Add(new DiffLine(line, ChangeType.Template));
                    }

                    for (int i = 0; i < h.Right.Count; i++)
                    {
                        vdo.RightLines.Add(new DiffLine("", ChangeType.None, true));
                    }
                    for (int i = 0; i < h.Left.Count; i++)
                    {
                        vdo.RightLines.Add(new DiffLine("", ChangeType.None, true));
                    }

                    vdo.ConflictRanges.Add(new VisualDiffOutput.ConflictRange(startIndex, vdo.LineCount));

                    continue;
                }

                // Not a conflict. Just add the new lines and put virtual lines on the left.

                // Only one of these will actually run - we've already handled the case where
                // both sides of the hunk have lines.
                foreach (string line in h.Left)
                {
                    vdo.RightLines.Add(new DiffLine(line, ChangeType.Template));
                    vdo.LeftLines.Add(new DiffLine("", ChangeType.None, true));
                }
                foreach (string line in h.Right)
                {
                    vdo.RightLines.Add(new DiffLine(line, ChangeType.User));
                    vdo.LeftLines.Add(new DiffLine("", ChangeType.None, true));
                }
            }
            if (vdo.LineCount > 0)
            {
                vdo.RemoveLine(vdo.LineCount - 1);
            }

            return(vdo);
        }
        public VisualDiffOutput ProcessMergeOutput()
        {
            if (fileInformation.UserFile.HasContents == false)
                throw new InvalidOperationException("Cannot merge: User file has no contents");
            if (fileInformation.NewGenFile.HasContents == false)
                throw new InvalidOperationException("Cannot merge: Template file has no contents");

            VisualDiffOutput vdo = new VisualDiffOutput();

            string leftText = Common.Utility.StandardizeLineBreaks(fileInformation.NewGenFile.GetContents(), Common.Utility.LineBreaks.Unix);
            string rightText = Common.Utility.StandardizeLineBreaks(fileInformation.UserFile.GetContents(), Common.Utility.LineBreaks.Unix);

            StringUtility.RemoveTrailingLineBreaks(ref leftText);
            StringUtility.RemoveTrailingLineBreaks(ref rightText);

            leftText = Common.Utility.StandardizeLineBreaks(leftText, Common.Utility.LineBreaks.Unix);
            rightText = Common.Utility.StandardizeLineBreaks(rightText, Common.Utility.LineBreaks.Unix);

            string[] leftLines = leftText.Split('\n');
            string[] rightLines = rightText.Split('\n');

            Diff diff = new Diff(leftLines, rightLines, true, true);

            foreach(Diff.Hunk h in diff)
            {
                if(h.Same)
                {
                    foreach(string line in h.Original())
                    {
                        vdo.AddLine(line, ChangeType.None);
                    }
                    continue;
                }

                // Is this a conflict?
                if(h.Left.Count > 0 && h.Right.Count > 0)
                {
                    int startIndex = vdo.LineCount;

                    foreach (string line in h.Right)
                    {
                        vdo.LeftLines.Add(new DiffLine(line, ChangeType.User));
                    }
                    foreach (string line in h.Left)
                    {
                        vdo.LeftLines.Add(new DiffLine(line, ChangeType.Template));
                    }

                    for (int i = 0; i < h.Right.Count; i++)
                    {
                        vdo.RightLines.Add(new DiffLine("", ChangeType.None, true));
                    }
                    for (int i = 0; i < h.Left.Count; i++)
                    {
                        vdo.RightLines.Add(new DiffLine("", ChangeType.None, true));
                    }

                    vdo.ConflictRanges.Add(new VisualDiffOutput.ConflictRange(startIndex, vdo.LineCount));

                    continue;
                }

                // Not a conflict. Just add the new lines and put virtual lines on the left.

                // Only one of these will actually run - we've already handled the case where
                // both sides of the hunk have lines.
                foreach(string line in h.Left)
                {
                    vdo.RightLines.Add(new DiffLine(line, ChangeType.Template));
                    vdo.LeftLines.Add(new DiffLine("", ChangeType.None, true));
                }
                foreach (string line in h.Right)
                {
                    vdo.RightLines.Add(new DiffLine(line, ChangeType.User));
                    vdo.LeftLines.Add(new DiffLine("", ChangeType.None, true));
                }
            }
            if(vdo.LineCount > 0)
                vdo.RemoveLine(vdo.LineCount - 1);

            return vdo;
        }
Beispiel #4
0
        public VisualDiffOutput ProcessMergeOutput()
        {
            vdo = new VisualDiffOutput();

            if (!fileInfo.NewGenFile.HasContents &&
               !fileInfo.UserFile.HasContents &&
               !fileInfo.PrevGenFile.HasContents)
            {
                vdo.DiffType = TypeOfDiff.ExactCopy;
                return vdo;
            }

            if (fileInfo.PrevGenFile.HasContents == false)
            {
                if (fileInfo.NewGenFile.HasContents == false)
                {
                    // prevGen and NewGen are missing. Copy everything from user and mark exact copy.
                    AddAllLinesFromList(user, ChangeType.None);
                    return vdo;
                }
                if (fileInfo.UserFile.HasContents == false)
                {
                    // prevGen and user are missing. Copy everything from NewGen and mark exact copy.
                    AddAllLinesFromList(newgen, ChangeType.None);
                    return vdo;
                }
                prevgen = ExtractFileToStringList(fileInfo.NewGenFile);
            }
            else
            {
                if (fileInfo.UserFile.HasContents == false && fileInfo.NewGenFile.HasContents)
                    user = ExtractFileToStringList(fileInfo.PrevGenFile);
                else if (fileInfo.NewGenFile.HasContents == false && fileInfo.UserFile.HasContents)
                    newgen = ExtractFileToStringList(fileInfo.PrevGenFile);
                else if (fileInfo.NewGenFile.HasContents == false && fileInfo.UserFile.HasContents == false)
                {
                    // User and NewGen are missing. Copy everything from prevgen and mark everything missing.
                    AddAllLinesFromList(prevgen, ChangeType.UserAndTemplate);
                    return vdo;
                }
            }

            Queue<Merge.Conflict> conflicts;
            Queue<ExtendedRange> ranges;

            // We need to add a blank line to the bottom of each file, or any lines that are added
            // at the bottom of the new files will be discarded by the diff/merge. I have spent far
            // too long trying to work out why, this work around works so I'm going with it. If someone
            // fixes the underlying problem, this should still work fine. We remove the last line of the
            // merged lines to compensate for this.
            /* Begin Hack */
            prevgen.Add("");
            user.Add("");
            newgen.Add("");
            /* End Hack */

            // Do the initial 3 way diff
            Merge.MergeLists(prevgen, user, newgen, out conflicts, out ranges);

            while (conflicts.Count + ranges.Count > 0)
            {
                // Get the next range or conflict
                int conflictStart = int.MaxValue, rangeStart = int.MaxValue;
                if (conflicts.Count > 0)
                {
                    conflictStart = conflicts.Peek().Ranges[0].Start;
                }
                if (ranges.Count > 0)
                {
                    rangeStart = ranges.Peek().ChangedRange.Start;
                }
                // If the next range came first, process it next. Otherwise process the next conflict.
                if (rangeStart < conflictStart)
                    ProcessRange(ranges.Dequeue());
                else
                    ProcessConflict(conflicts.Dequeue());
            }
            // Other half of the above hack.
            if (vdo.LeftLines[vdo.LeftLines.Count - 1].Text == "" && vdo.RightLines[vdo.RightLines.Count - 1].Text == "")
                vdo.RemoveLine(vdo.LeftLines.Count - 1);
            return vdo;
        }
        public VisualDiffOutput ProcessMergeOutput()
        {
            vdo = new VisualDiffOutput();

            if (!fileInfo.NewGenFile.HasContents &&
               !fileInfo.UserFile.HasContents &&
               !fileInfo.PrevGenFile.HasContents)
            {
                vdo.DiffType = TypeOfDiff.ExactCopy;
                return vdo;
            }

            if (fileInfo.PrevGenFile.HasContents == false)
            {
                if (fileInfo.NewGenFile.HasContents == false)
                {
                    // prevGen and NewGen are missing. Copy everything from user and mark exact copy.
                    AddAllLinesFromList(user, ChangeType.None);
                    return vdo;
                }
                if (fileInfo.UserFile.HasContents == false)
                {
                    // prevGen and user are missing. Copy everything from NewGen and mark exact copy.
                    AddAllLinesFromList(newgen, ChangeType.None);
                    return vdo;
                }
                prevgen = ExtractFileToStringList(fileInfo.NewGenFile);
            }
            else
            {
                if (fileInfo.UserFile.HasContents == false && fileInfo.NewGenFile.HasContents)
                    user = ExtractFileToStringList(fileInfo.PrevGenFile);
                else if (fileInfo.NewGenFile.HasContents == false && fileInfo.UserFile.HasContents)
                    newgen = ExtractFileToStringList(fileInfo.PrevGenFile);
                else if (fileInfo.NewGenFile.HasContents == false && fileInfo.UserFile.HasContents == false)
                {
                    // User and NewGen are missing. Copy everything from prevgen and mark everything missing.
                    AddAllLinesFromList(prevgen, ChangeType.UserAndTemplate);
                    return vdo;
                }
            }

            Queue<Merge.Conflict> conflicts;
            Queue<ExtendedRange> ranges;

            // We need to add a blank line to the bottom of each file, or any lines that are added
            // at the bottom of the new files will be discarded by the diff/merge. I have spent far
            // too long trying to work out why, this work around works so I'm going with it. If someone
            // fixes the underlying problem, this should still work fine. We remove the last line of the
            // merged lines to compensate for this.
            /* Begin Hack */
            prevgen.Add("");
            user.Add("");
            newgen.Add("");
            /* End Hack */

            // Do the initial 3 way diff
            Merge.MergeLists(prevgen, user, newgen, out conflicts, out ranges);

            while (conflicts.Count + ranges.Count > 0)
            {
                // Get the next range or conflict
                int conflictStart = int.MaxValue, rangeStart = int.MaxValue;
                if (conflicts.Count > 0)
                {
                    conflictStart = conflicts.Peek().Ranges[0].Start;
                }
                if (ranges.Count > 0)
                {
                    rangeStart = ranges.Peek().ChangedRange.Start;
                }
                // If the next range came first, process it next. Otherwise process the next conflict.
                if (rangeStart < conflictStart)
                    ProcessRange(ranges.Dequeue());
                else
                    ProcessConflict(conflicts.Dequeue());
            }
            // Other half of the above hack.
            if (vdo.LeftLines[vdo.LeftLines.Count - 1].Text == "" && vdo.RightLines[vdo.RightLines.Count - 1].Text == "")
                vdo.RemoveLine(vdo.LeftLines.Count - 1);
            return vdo;
        }