mirror of
https://github.com/bluekeyes/go-gitdiff
synced 2026-06-08 13:18:30 +00:00
1c950ee854
The tests were already split up in this way, so it makes sense to have the parsing functions split as well.
315 lines
6.8 KiB
Go
315 lines
6.8 KiB
Go
package gitdiff
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"io"
|
|
"reflect"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestParseBinaryMarker(t *testing.T) {
|
|
tests := map[string]struct {
|
|
Input string
|
|
IsBinary bool
|
|
HasData bool
|
|
Err bool
|
|
}{
|
|
"binaryPatch": {
|
|
Input: "GIT binary patch\n",
|
|
IsBinary: true,
|
|
HasData: true,
|
|
},
|
|
"binaryFileNoPatch": {
|
|
Input: "Binary files differ\n",
|
|
IsBinary: true,
|
|
HasData: false,
|
|
},
|
|
"textFile": {
|
|
Input: "@@ -10,14 +22,31 @@\n",
|
|
IsBinary: false,
|
|
HasData: false,
|
|
},
|
|
}
|
|
|
|
for name, test := range tests {
|
|
t.Run(name, func(t *testing.T) {
|
|
p := newTestParser(test.Input, true)
|
|
|
|
isBinary, hasData, err := p.ParseBinaryMarker()
|
|
if test.Err {
|
|
if err == nil || err == io.EOF {
|
|
t.Fatalf("expected error parsing binary marker, but got %v", err)
|
|
}
|
|
return
|
|
}
|
|
if err != nil {
|
|
t.Fatalf("unexpected error parsing binary marker: %v", err)
|
|
}
|
|
if test.IsBinary != isBinary {
|
|
t.Errorf("incorrect isBinary value: expected %t, actual %t", test.IsBinary, isBinary)
|
|
}
|
|
if test.HasData != hasData {
|
|
t.Errorf("incorrect hasData value: expected %t, actual %t", test.HasData, hasData)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestParseBinaryFragmentHeader(t *testing.T) {
|
|
tests := map[string]struct {
|
|
Input string
|
|
Output *BinaryFragment
|
|
Err bool
|
|
}{
|
|
"delta": {
|
|
Input: "delta 1234\n",
|
|
Output: &BinaryFragment{
|
|
Method: BinaryPatchDelta,
|
|
Size: 1234,
|
|
},
|
|
},
|
|
"literal": {
|
|
Input: "literal 1234\n",
|
|
Output: &BinaryFragment{
|
|
Method: BinaryPatchLiteral,
|
|
Size: 1234,
|
|
},
|
|
},
|
|
"unknownMethod": {
|
|
Input: "compressed 1234\n",
|
|
Output: nil,
|
|
},
|
|
"notAHeader": {
|
|
Input: "Binary files differ\n",
|
|
Output: nil,
|
|
},
|
|
"invalidSize": {
|
|
Input: "delta 123abc\n",
|
|
Err: true,
|
|
},
|
|
}
|
|
|
|
for name, test := range tests {
|
|
t.Run(name, func(t *testing.T) {
|
|
p := newTestParser(test.Input, true)
|
|
|
|
frag, err := p.ParseBinaryFragmentHeader()
|
|
if test.Err {
|
|
if err == nil || err == io.EOF {
|
|
t.Fatalf("expected error parsing binary header, but got %v", err)
|
|
}
|
|
return
|
|
}
|
|
if err != nil {
|
|
t.Fatalf("unexpected error parsing binary header: %v", err)
|
|
}
|
|
if !reflect.DeepEqual(test.Output, frag) {
|
|
t.Errorf("incorrect binary fragment\nexpected: %+v\n actual: %+v", test.Output, frag)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestParseBinaryChunk(t *testing.T) {
|
|
tests := map[string]struct {
|
|
Input string
|
|
Fragment BinaryFragment
|
|
Output []byte
|
|
Err string
|
|
}{
|
|
"singleline": {
|
|
Input: "TcmZQzU|?i`U?w2V48*Je09XJG\n\n",
|
|
Fragment: BinaryFragment{
|
|
Size: 20,
|
|
},
|
|
Output: fib(5, binary.BigEndian),
|
|
},
|
|
"multiline": {
|
|
Input: "zcmZQzU|?i`U?w2V48*KJ%mKu_Kr9NxN<eH5#F0Qe0f=7$l~*z_FeL$%-)3N7vt?l5\n" +
|
|
"zl3-vE2xVZ9%4J~CI>f->s?WfX|B-=Vs{#X~svra7Ekg#T|4s}nH;WnAZ)|1Y*`&cB\n" +
|
|
"s(sh?X(Uz6L^!Ou&aF*u`J!eibJifSrv0z>$Q%Hd(^HIJ<Y?5`S0gT5UE&u=k\n\n",
|
|
Fragment: BinaryFragment{
|
|
Size: 160,
|
|
},
|
|
Output: fib(40, binary.BigEndian),
|
|
},
|
|
"shortLine": {
|
|
Input: "A00\n\n",
|
|
Err: "corrupt data line",
|
|
},
|
|
"underpaddedLine": {
|
|
Input: "H00000000\n\n",
|
|
Err: "corrupt data line",
|
|
},
|
|
"invalidLengthByte": {
|
|
Input: "!00000\n\n",
|
|
Err: "invalid length byte",
|
|
},
|
|
"miscountedLine": {
|
|
Input: "H00000\n\n",
|
|
Err: "incorrect byte count",
|
|
},
|
|
"invalidEncoding": {
|
|
Input: "TcmZQzU|?i'U?w2V48*Je09XJG\n",
|
|
Err: "invalid base85 byte",
|
|
},
|
|
"noTrailingEmptyLine": {
|
|
Input: "TcmZQzU|?i`U?w2V48*Je09XJG\n",
|
|
Err: "unexpected EOF",
|
|
},
|
|
"invalidCompression": {
|
|
Input: "F007GV%KiWV\n\n",
|
|
Err: "zlib",
|
|
},
|
|
"incorrectSize": {
|
|
Input: "TcmZQzU|?i`U?w2V48*Je09XJG\n\n",
|
|
Fragment: BinaryFragment{
|
|
Size: 16,
|
|
},
|
|
Err: "16 byte fragment inflated to 20",
|
|
},
|
|
}
|
|
|
|
for name, test := range tests {
|
|
t.Run(name, func(t *testing.T) {
|
|
p := newTestParser(test.Input, true)
|
|
|
|
frag := test.Fragment
|
|
err := p.ParseBinaryChunk(&frag)
|
|
if test.Err != "" {
|
|
if err == nil || !strings.Contains(err.Error(), test.Err) {
|
|
t.Fatalf("expected error containing %q parsing binary chunk, but got %v", test.Err, err)
|
|
}
|
|
return
|
|
}
|
|
if err != nil {
|
|
t.Fatalf("unexpected error parsing binary chunk: %v", err)
|
|
}
|
|
if !reflect.DeepEqual(test.Output, frag.Data) {
|
|
t.Errorf("incorrect binary chunk\nexpected: %+v\n actual: %+v", test.Output, frag.Data)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestParseBinaryFragments(t *testing.T) {
|
|
tests := map[string]struct {
|
|
Input string
|
|
File File
|
|
|
|
Binary bool
|
|
Fragment *BinaryFragment
|
|
ReverseFragment *BinaryFragment
|
|
Err bool
|
|
}{
|
|
"dataWithReverse": {
|
|
Input: `GIT binary patch
|
|
literal 40
|
|
gcmZQzU|?i` + "`" + `U?w2V48*KJ%mKu_Kr9NxN<eH500b)lkN^Mx
|
|
|
|
literal 0
|
|
HcmV?d00001
|
|
|
|
`,
|
|
Binary: true,
|
|
Fragment: &BinaryFragment{
|
|
Method: BinaryPatchLiteral,
|
|
Size: 40,
|
|
Data: fib(10, binary.BigEndian),
|
|
},
|
|
ReverseFragment: &BinaryFragment{
|
|
Method: BinaryPatchLiteral,
|
|
Size: 0,
|
|
Data: []byte{},
|
|
},
|
|
},
|
|
"dataWithoutReverse": {
|
|
Input: `GIT binary patch
|
|
literal 40
|
|
gcmZQzU|?i` + "`" + `U?w2V48*KJ%mKu_Kr9NxN<eH500b)lkN^Mx
|
|
|
|
`,
|
|
Binary: true,
|
|
Fragment: &BinaryFragment{
|
|
Method: BinaryPatchLiteral,
|
|
Size: 40,
|
|
Data: fib(10, binary.BigEndian),
|
|
},
|
|
},
|
|
"noData": {
|
|
Input: "Binary files differ\n",
|
|
Binary: true,
|
|
},
|
|
"text": {
|
|
Input: `@@ -1 +1 @@
|
|
-old line
|
|
+new line
|
|
`,
|
|
Binary: false,
|
|
},
|
|
"missingData": {
|
|
Input: "GIT binary patch\n",
|
|
Err: true,
|
|
},
|
|
"invalidData": {
|
|
Input: `GIT binary patch
|
|
literal 20
|
|
TcmZQzU|?i'U?w2V48*Je09XJG
|
|
|
|
`,
|
|
Err: true,
|
|
},
|
|
"invalidReverseData": {
|
|
Input: `GIT binary patch
|
|
literal 20
|
|
TcmZQzU|?i` + "`" + `U?w2V48*Je09XJG
|
|
|
|
literal 0
|
|
zcmV?d00001
|
|
|
|
`,
|
|
Err: true,
|
|
},
|
|
}
|
|
|
|
for name, test := range tests {
|
|
t.Run(name, func(t *testing.T) {
|
|
p := newTestParser(test.Input, true)
|
|
|
|
file := test.File
|
|
_, err := p.ParseBinaryFragments(&file)
|
|
if test.Err {
|
|
if err == nil || err == io.EOF {
|
|
t.Fatalf("expected error parsing binary fragments, but got %v", err)
|
|
}
|
|
return
|
|
}
|
|
if err != nil {
|
|
t.Fatalf("unexpected error parsing binary fragments: %v", err)
|
|
}
|
|
if test.Binary != file.IsBinary {
|
|
t.Errorf("incorrect binary state: expected %t, actual %t", test.Binary, file.IsBinary)
|
|
}
|
|
if !reflect.DeepEqual(test.Fragment, file.BinaryFragment) {
|
|
t.Errorf("incorrect binary fragment\nexpected: %+v\n actual: %+v", test.Fragment, file.BinaryFragment)
|
|
}
|
|
if !reflect.DeepEqual(test.ReverseFragment, file.ReverseBinaryFragment) {
|
|
t.Errorf("incorrect reverse binary fragment\nexpected: %+v\n actual: %+v", test.ReverseFragment, file.ReverseBinaryFragment)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func fib(n int, ord binary.ByteOrder) []byte {
|
|
buf := make([]byte, 4*n)
|
|
for i := 0; i < len(buf); i += 4 {
|
|
if i < 8 {
|
|
ord.PutUint32(buf[i:], 1)
|
|
} else {
|
|
ord.PutUint32(buf[i:], ord.Uint32(buf[i-4:])+ord.Uint32(buf[i-8:]))
|
|
}
|
|
}
|
|
return buf
|
|
}
|