diff options
Diffstat (limited to 'utils')
-rw-r--r-- | utils/binary/write_test.go (renamed from utils/binary/writer_test.go) | 0 | ||||
-rw-r--r-- | utils/diff/diff.go | 45 | ||||
-rw-r--r-- | utils/diff/diff_ext_test.go | 109 | ||||
-rw-r--r-- | utils/ioutil/common.go | 20 |
4 files changed, 174 insertions, 0 deletions
diff --git a/utils/binary/writer_test.go b/utils/binary/write_test.go index 1380280..1380280 100644 --- a/utils/binary/writer_test.go +++ b/utils/binary/write_test.go diff --git a/utils/diff/diff.go b/utils/diff/diff.go new file mode 100644 index 0000000..b840ad6 --- /dev/null +++ b/utils/diff/diff.go @@ -0,0 +1,45 @@ +// Package diff implements line oriented diffs, similar to the ancient +// Unix diff command. +// +// The current implementation is just a wrapper around Sergi's +// go-diff/diffmatchpatch library, which is a go port of Neil +// Fraser's google-diff-match-patch code +package diff + +import ( + "bytes" + + "github.com/sergi/go-diff/diffmatchpatch" +) + +// Do computes the (line oriented) modifications needed to turn the src +// string into the dst string. +func Do(src, dst string) (diffs []diffmatchpatch.Diff) { + dmp := diffmatchpatch.New() + wSrc, wDst, warray := dmp.DiffLinesToChars(src, dst) + diffs = dmp.DiffMain(wSrc, wDst, false) + diffs = dmp.DiffCharsToLines(diffs, warray) + return diffs +} + +// Dst computes and returns the destination text. +func Dst(diffs []diffmatchpatch.Diff) string { + var text bytes.Buffer + for _, d := range diffs { + if d.Type != diffmatchpatch.DiffDelete { + text.WriteString(d.Text) + } + } + return text.String() +} + +// Src computes and returns the source text +func Src(diffs []diffmatchpatch.Diff) string { + var text bytes.Buffer + for _, d := range diffs { + if d.Type != diffmatchpatch.DiffInsert { + text.WriteString(d.Text) + } + } + return text.String() +} diff --git a/utils/diff/diff_ext_test.go b/utils/diff/diff_ext_test.go new file mode 100644 index 0000000..adda276 --- /dev/null +++ b/utils/diff/diff_ext_test.go @@ -0,0 +1,109 @@ +package diff_test + +import ( + "testing" + + "gopkg.in/src-d/go-git.v4/utils/diff" + + "github.com/sergi/go-diff/diffmatchpatch" + . "gopkg.in/check.v1" +) + +func Test(t *testing.T) { TestingT(t) } + +type suiteCommon struct{} + +var _ = Suite(&suiteCommon{}) + +var diffTests = [...]struct { + src string // the src string to diff + dst string // the dst string to diff +}{ + // equal inputs + {"", ""}, + {"a", "a"}, + {"a\n", "a\n"}, + {"a\nb", "a\nb"}, + {"a\nb\n", "a\nb\n"}, + {"a\nb\nc", "a\nb\nc"}, + {"a\nb\nc\n", "a\nb\nc\n"}, + // missing '\n' + {"", "\n"}, + {"\n", ""}, + {"a", "a\n"}, + {"a\n", "a"}, + {"a\nb", "a\nb"}, + {"a\nb\n", "a\nb\n"}, + {"a\nb\nc", "a\nb\nc"}, + {"a\nb\nc\n", "a\nb\nc\n"}, + // generic + {"a\nbbbbb\n\tccc\ndd\n\tfffffffff\n", "bbbbb\n\tccc\n\tDD\n\tffff\n"}, +} + +func (s *suiteCommon) TestAll(c *C) { + for i, t := range diffTests { + diffs := diff.Do(t.src, t.dst) + src := diff.Src(diffs) + dst := diff.Dst(diffs) + c.Assert(src, Equals, t.src, Commentf("subtest %d, src=%q, dst=%q, bad calculated src", i, t.src, t.dst)) + c.Assert(dst, Equals, t.dst, Commentf("subtest %d, src=%q, dst=%q, bad calculated dst", i, t.src, t.dst)) + } +} + +var doTests = [...]struct { + src, dst string + exp []diffmatchpatch.Diff +}{ + { + src: "", + dst: "", + exp: []diffmatchpatch.Diff{}, + }, + { + src: "a", + dst: "a", + exp: []diffmatchpatch.Diff{ + { + Type: 0, + Text: "a", + }, + }, + }, + { + src: "", + dst: "abc\ncba", + exp: []diffmatchpatch.Diff{ + { + Type: 1, + Text: "abc\ncba", + }, + }, + }, + { + src: "abc\ncba", + dst: "", + exp: []diffmatchpatch.Diff{ + { + Type: -1, + Text: "abc\ncba", + }, + }, + }, + { + src: "abc\nbcd\ncde", + dst: "000\nabc\n111\nBCD\n", + exp: []diffmatchpatch.Diff{ + {Type: 1, Text: "000\n"}, + {Type: 0, Text: "abc\n"}, + {Type: -1, Text: "bcd\ncde"}, + {Type: 1, Text: "111\nBCD\n"}, + }, + }, +} + +func (s *suiteCommon) TestDo(c *C) { + for i, t := range doTests { + diffs := diff.Do(t.src, t.dst) + c.Assert(diffs, DeepEquals, t.exp, Commentf("subtest %d", i)) + } +} diff --git a/utils/ioutil/common.go b/utils/ioutil/common.go index f5b78df..a847abd 100644 --- a/utils/ioutil/common.go +++ b/utils/ioutil/common.go @@ -62,3 +62,23 @@ func (writeNopCloser) Close() error { return nil } func WriteNopCloser(w io.Writer) io.WriteCloser { return writeNopCloser{w} } + +// CheckClose is used with defer to close the given io.Closer and check its +// returned error value. If Close returns an error and the given *error +// is not nil, *error is set to the error returned by Close. +// +// CheckClose is typically used with named return values like so: +// +// func do(obj *Object) (err error) { +// w, err := obj.Writer() +// if err != nil { +// return nil +// } +// defer CheckClose(w, &err) +// // work with w +// } +func CheckClose(c io.Closer, err *error) { + if cerr := c.Close(); cerr != nil && *err == nil { + *err = cerr + } +} |