public void ApplyingPatchesUpdatesPreviousToCurrent(FileSet set)
        {
            var updated = new List <string>(set.PreviousLines);
            var results = LinePatchOps.ApplyPatches(set.ReviewPatch, updated);

            Assert.That(updated, Is.EqualTo(set.CurrentLines));
            Assert.That(results.All(x => x), Is.True);
        }
        public void PatchMatchesText_Previous(FileSet set)
        {
            var updatedPreviousText = new List <string>(set.PreviousLines);

            foreach (var(patchIdx, patch) in set.ReviewPatch.AsIndexed())
            {
                var actual   = updatedPreviousText.Slice(patch.Start1, patch.Length1);
                var expected = patch.PreviousLines().ToList();

                Assert.That(actual, Is.EqualTo(expected), $"Patch index {patchIdx} Expected position: {patch.Start1}");

                LinePatchOps.ApplyPatch(patch, updatedPreviousText);
            }
        }
        public static List <(DiffClassification classification, LinePatch Patch)> ClassifyPatches(List <string> reviewText1, List <LinePatch> basePatch,
                                                                                                  List <LinePatch> reviewPatch)
        {
            var classifiedPatches = new List <(DiffClassification classification, LinePatch Patch)>();
            var unusedBasePatches = new List <LinePatch>(basePatch);
            var rollingText       = new List <string>(reviewText1);

            foreach (var patch in reviewPatch)
            {
                LinePatchOps.ApplyPatch(patch, rollingText);
                var basePatchIndex = unusedBasePatches.FindIndex(bp => ArePatchesMatching(bp, rollingText, patch));

                if (basePatchIndex == -1)
                {
                    classifiedPatches.Add((DiffClassification.ReviewChange, patch));
                    continue;
                }

                classifiedPatches.Add((DiffClassification.BaseChange, patch));
                unusedBasePatches.RemoveRange(0, basePatchIndex + 1);
            }

            return(classifiedPatches);
        }
        public static bool ArePatchesMatching(LinePatch basePatch, List <string> reviewText, LinePatch reviewPatch)
        {
            var baseTextFromDiffs   = basePatch.CurrentLines().ToList();
            var reviewTextFromDiffs = reviewPatch.CurrentLines().ToList();

            {
                var reviewInBase = baseTextFromDiffs.IndexOf(reviewTextFromDiffs, StringComparison.InvariantCulture);

                if (reviewInBase >= 0 && reviewPatch.Start2 - reviewInBase >= 0)
                {
                    // extend review to match base
                    var prefix = reviewText.Slice(reviewPatch.Start2 - reviewInBase, reviewInBase);
                    var suffix = reviewText.Slice(reviewPatch.Start2 + reviewPatch.Length2, baseTextFromDiffs.Count - reviewPatch.Length2 - reviewInBase);

                    var extended = prefix.Concat(reviewTextFromDiffs).Concat(suffix);

                    if (extended.SequenceEqual(baseTextFromDiffs))
                    {
                        return(true);
                    }
                }
            }

            {
                var baseInReview = reviewTextFromDiffs.IndexOf(baseTextFromDiffs, StringComparison.InvariantCulture);

                if (baseInReview >= 0)
                {
                    Console.WriteLine("!!!!Base in review expand");
                    // TODO
                    return(true);
                }
            }

            {
                var baseChangeNoContextDiffs = basePatch.Diffs.Where(x => !x.Operation.IsDelete).SkipWhile(x => x.Operation.IsEqual).TakeWhile(x => x.Operation.IsInsert).ToList();
                var baseChangeNoContext      = LinePatchOps.DiffsCurrentText(baseChangeNoContextDiffs);

                var reviewChangeNoContextDiffs = reviewPatch.Diffs.Where(x => !x.Operation.IsDelete).SkipWhile(x => x.Operation.IsEqual).TakeWhile(x => x.Operation.IsInsert).ToList();
                var reviewChangeNoContext      = LinePatchOps.DiffsCurrentText(reviewChangeNoContextDiffs);

                var reviewInBaseNoContext = baseChangeNoContext.IndexOf(reviewChangeNoContext, StringComparison.InvariantCulture);

                if (reviewInBaseNoContext >= 0 && reviewChangeNoContextDiffs.Any() && baseChangeNoContextDiffs.Any())
                {
                    var baseContextPrefixDiffs  = basePatch.Diffs.Where(x => !x.Operation.IsDelete).TakeWhile(x => x.Operation.IsEqual).ToList();
                    var baseContextPrefixLength = baseContextPrefixDiffs.Sum(x => x.Lines.Count);

                    var reviewContextPrefixDiffs  = reviewPatch.Diffs.Where(x => !x.Operation.IsDelete).TakeWhile(x => x.Operation.IsEqual).ToList();
                    var reviewContextPrefixLength = reviewContextPrefixDiffs.Sum(x => x.Lines.Count);

                    var reviewDiffNoContextStart = reviewPatch.Start2 + reviewContextPrefixLength;
                    var reviewDiffNoContextEnd   = reviewDiffNoContextStart + reviewChangeNoContextDiffs.Sum(x => x.Lines.Count);

                    var contextPrefixLength = baseContextPrefixLength + reviewInBaseNoContext;
                    var contextSuffixLength = baseTextFromDiffs.Count(x => x != "") - baseContextPrefixLength - baseChangeNoContextDiffs.Sum(x => x.Lines.Count);

                    if (reviewDiffNoContextStart >= contextPrefixLength)
                    {
                        var remainingReviewText = reviewText.Count - reviewDiffNoContextEnd;

                        var prefix = reviewText.Slice(reviewDiffNoContextStart - contextPrefixLength, contextPrefixLength);
                        var suffix = reviewText.Slice(reviewDiffNoContextEnd, Math.Min(contextSuffixLength, remainingReviewText));

                        var reviewTextReconstructedContext = prefix.Concat(reviewChangeNoContext).Concat(suffix);

                        if (reviewTextReconstructedContext.ConcatText() == baseTextFromDiffs.ConcatText())
                        {
                            return(true);
                        }
                    }
                }
            }

            {
                var(basePrefix, baseChanges, baseSuffix)       = basePatch.SplitPatchAffix();
                var(reviewPrefix, reviewChanges, reviewSuffix) = reviewPatch.SplitPatchAffix();

                if (LinePatchOps.DiffsCurrentText(baseChanges).ConcatText() == LinePatchOps.DiffsCurrentText(reviewChanges).ConcatText())
                {
                    var basePrefixLines   = LinePatchOps.DiffsCurrentText(basePrefix);
                    var reviewPrefixLines = LinePatchOps.DiffsCurrentText(reviewPrefix);
                    var minPrefixLength   = Math.Min(basePrefixLines.Count, reviewPrefixLines.Count);

                    if (basePrefixLines.TakeLast(minPrefixLength).ConcatText() == reviewPrefixLines.TakeLast(minPrefixLength).ConcatText())
                    {
                        var baseSuffixLines   = LinePatchOps.DiffsCurrentText(baseSuffix);
                        var reviewSuffixLines = LinePatchOps.DiffsCurrentText(reviewSuffix);
                        var minSuffixLength   = Math.Min(baseSuffixLines.Count, reviewSuffixLines.Count);

                        if (baseSuffixLines.Take(minSuffixLength).ConcatText() == reviewSuffixLines.Take(minSuffixLength).ConcatText())
                        {
                            return(true);
                        }
                    }
                }
            }

            return(false);
        }