package dehub import ( "bytes" "encoding/binary" "hash" "testing" "gopkg.in/src-d/go-git.v4/plumbing" "gopkg.in/src-d/go-git.v4/plumbing/filemode" ) type testHash struct { bytes.Buffer } var _ hash.Hash = new(testHash) func (th *testHash) Sum(b []byte) []byte { return append(b, th.Buffer.Bytes()...) } func (th *testHash) Size() int { return th.Buffer.Len() } func (th *testHash) BlockSize() int { return 1 } func (th *testHash) assertContents(t *testing.T, parts [][]byte) { b := th.Buffer.Bytes() for _, part := range parts { if len(part) > len(b) || !bytes.Equal(part, b[:len(part)]) { t.Fatalf("expected %q but only found %q", part, b) } b = b[len(part):] } if len(b) != 0 { t.Fatalf("unexpected extra bytes written to testHash: %q", b) } } func uvarint(i uint64) []byte { buf := make([]byte, binary.MaxVarintLen64) n := binary.PutUvarint(buf, i) return buf[:n] } func TestGenCommentFingerprint(t *testing.T) { type test struct { descr string comment string exp [][]byte } tests := []test{ { descr: "empty comment", comment: "", exp: [][]byte{uvarint(0)}, }, { descr: "normal comment", comment: "this is a normal comment", exp: [][]byte{uvarint(24), []byte("this is a normal comment")}, }, { descr: "comment with unicode", comment: "sick comment ⚡", exp: [][]byte{uvarint(16), []byte("sick comment ⚡")}, }, } for _, test := range tests { t.Run(test.descr, func(t *testing.T) { th := new(testHash) genCommentFingerprint(th, test.comment) th.assertContents(t, test.exp) }) } } func TestGenChangeFingerprint(t *testing.T) { type test struct { descr string msg string changedFiles []ChangedFile exp [][]byte } hash := func(i byte) plumbing.Hash { var h plumbing.Hash h[0] = i return h } hashB := func(i byte) []byte { h := hash(i) return h[:] } tests := []test{ { descr: "empty", msg: "", changedFiles: nil, exp: [][]byte{uvarint(0), uvarint(0)}, }, { descr: "empty changes", msg: "some msg", changedFiles: nil, exp: [][]byte{uvarint(8), []byte("some msg"), uvarint(0)}, }, { descr: "empty msg", msg: "", changedFiles: []ChangedFile{{ Path: "foo", ToMode: filemode.Regular, ToHash: hash(1), }}, exp: [][]byte{uvarint(0), uvarint(1), uvarint(3), []byte("foo"), filemode.Empty.Bytes(), hashB(0), filemode.Regular.Bytes(), hashB(1)}, }, { descr: "files added", msg: "a", changedFiles: []ChangedFile{ { Path: "foo", ToMode: filemode.Regular, ToHash: hash(1), }, { Path: "somedir/bar", ToMode: filemode.Executable, ToHash: hash(2), }, }, exp: [][]byte{uvarint(1), []byte("a"), uvarint(2), uvarint(3), []byte("foo"), filemode.Empty.Bytes(), hashB(0), filemode.Regular.Bytes(), hashB(1), uvarint(11), []byte("somedir/bar"), filemode.Empty.Bytes(), hashB(0), filemode.Executable.Bytes(), hashB(2), }, }, { descr: "files added (unordered)", msg: "a", changedFiles: []ChangedFile{ { Path: "somedir/bar", ToMode: filemode.Executable, ToHash: hash(2), }, { Path: "foo", ToMode: filemode.Regular, ToHash: hash(1), }, }, exp: [][]byte{uvarint(1), []byte("a"), uvarint(2), uvarint(3), []byte("foo"), filemode.Empty.Bytes(), hashB(0), filemode.Regular.Bytes(), hashB(1), uvarint(11), []byte("somedir/bar"), filemode.Empty.Bytes(), hashB(0), filemode.Executable.Bytes(), hashB(2), }, }, { descr: "file modified", msg: "a", changedFiles: []ChangedFile{{ Path: "foo", FromMode: filemode.Regular, FromHash: hash(1), ToMode: filemode.Executable, ToHash: hash(2), }}, exp: [][]byte{uvarint(1), []byte("a"), uvarint(1), uvarint(3), []byte("foo"), filemode.Regular.Bytes(), hashB(1), filemode.Executable.Bytes(), hashB(2), }, }, { descr: "file removed", msg: "a", changedFiles: []ChangedFile{{ Path: "foo", FromMode: filemode.Regular, FromHash: hash(1), }}, exp: [][]byte{uvarint(1), []byte("a"), uvarint(1), uvarint(3), []byte("foo"), filemode.Regular.Bytes(), hashB(1), filemode.Empty.Bytes(), hashB(0), }, }, { descr: "files added, modified, and removed", msg: "aaa", changedFiles: []ChangedFile{ { Path: "foo", ToMode: filemode.Regular, ToHash: hash(1), }, { Path: "bar", FromMode: filemode.Regular, FromHash: hash(2), ToMode: filemode.Regular, ToHash: hash(3), }, { Path: "baz", FromMode: filemode.Executable, FromHash: hash(4), }, }, exp: [][]byte{uvarint(3), []byte("aaa"), uvarint(3), uvarint(3), []byte("bar"), filemode.Regular.Bytes(), hashB(2), filemode.Regular.Bytes(), hashB(3), uvarint(3), []byte("baz"), filemode.Executable.Bytes(), hashB(4), filemode.Empty.Bytes(), hashB(0), uvarint(3), []byte("foo"), filemode.Empty.Bytes(), hashB(0), filemode.Regular.Bytes(), hashB(1), }, }, } for _, test := range tests { t.Run(test.descr, func(t *testing.T) { th := new(testHash) genChangeFingerprint(th, test.msg, test.changedFiles) th.assertContents(t, test.exp) }) } }