From 16e27ac471a4790d8b1aaed28b37961af55f1230 Mon Sep 17 00:00:00 2001 From: yuin Date: Sat, 15 May 2021 19:42:58 +0900 Subject: [PATCH] Add DiffPretty --- testutil/testutil.go | 102 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 101 insertions(+), 1 deletion(-) diff --git a/testutil/testutil.go b/testutil/testutil.go index 3e575b1..5c0a1e6 100644 --- a/testutil/testutil.go +++ b/testutil/testutil.go @@ -111,6 +111,9 @@ func DoTestCaseFile(m goldmark.Markdown, filename string, t TestingT, no ...int) buf = append(buf, text) } c.Expected = strings.Join(buf, "\n") + if len(c.Expected) != 0 { + c.Expected = c.Expected + "\n" + } shouldAdd := len(no) == 0 if !shouldAdd { for _, n := range no { @@ -172,8 +175,13 @@ Expected: Actual --------- %s + +Diff +--------- +%s ` - t.Errorf(format, testCase.No, description, testCase.Markdown, testCase.Expected, out.Bytes()) + t.Errorf(format, testCase.No, description, testCase.Markdown, testCase.Expected, out.Bytes(), + DiffPretty([]byte(testCase.Expected), out.Bytes())) } }() @@ -182,3 +190,95 @@ Actual } ok = bytes.Equal(bytes.TrimSpace(out.Bytes()), bytes.TrimSpace([]byte(testCase.Expected))) } + +type diffType int + +const ( + diffRemoved diffType = iota + diffAdded + diffNone +) + +type diff struct { + Type diffType + Lines [][]byte +} + +func simpleDiff(v1, v2 []byte) []diff { + return simpleDiffAux( + bytes.Split(v1, []byte("\n")), + bytes.Split(v2, []byte("\n"))) +} + +func simpleDiffAux(v1lines, v2lines [][]byte) []diff { + v1index := map[string][]int{} + for i, line := range v1lines { + key := util.BytesToReadOnlyString(line) + if _, ok := v1index[key]; !ok { + v1index[key] = []int{} + } + v1index[key] = append(v1index[key], i) + } + overlap := map[int]int{} + v1start := 0 + v2start := 0 + length := 0 + for v2pos, line := range v2lines { + newOverlap := map[int]int{} + key := util.BytesToReadOnlyString(line) + if _, ok := v1index[key]; !ok { + v1index[key] = []int{} + } + for _, v1pos := range v1index[key] { + value := 0 + if v1pos != 0 { + if v, ok := overlap[v1pos-1]; ok { + value = v + } + } + newOverlap[v1pos] = value + 1 + if newOverlap[v1pos] > length { + length = newOverlap[v1pos] + v1start = v1pos - length + 1 + v2start = v2pos - length + 1 + } + } + overlap = newOverlap + } + if length == 0 { + diffs := []diff{} + if len(v1lines) != 0 { + diffs = append(diffs, diff{diffRemoved, v1lines}) + } + if len(v2lines) != 0 { + diffs = append(diffs, diff{diffAdded, v2lines}) + } + return diffs + } + diffs := simpleDiffAux(v1lines[:v1start], v2lines[:v2start]) + diffs = append(diffs, diff{diffNone, v2lines[v2start : v2start+length]}) + diffs = append(diffs, simpleDiffAux(v1lines[v1start+length:], + v2lines[v2start+length:])...) + return diffs +} + +// DiffPretty returns pretty formatted diff between given bytes. +func DiffPretty(v1, v2 []byte) []byte { + var b bytes.Buffer + diffs := simpleDiff(v1, v2) + for _, diff := range diffs { + c := " " + switch diff.Type { + case diffAdded: + c = "+" + case diffRemoved: + c = "-" + case diffNone: + c = " " + } + for _, line := range diff.Lines { + b.WriteString(fmt.Sprintf("%s | %s\n", c, line)) + } + } + return b.Bytes() +}