Add error tests for BinaryFragment#Apply

These cover some of the possible errors with delta fragments. Many of
the same tests could be implemented slightly easier by testing the
helper functions, but the infrastructure is already set up to test the
full function.

This is made easier by the bin.go CLI, which can parse and encode binary
patch data. Once parsed, fragments were manipulated with truncate and
dd, encoded, and placed in the patch files.
This commit is contained in:
Billy Keyes
2020-01-16 22:34:19 -08:00
parent 194589f001
commit a34334d6ef
7 changed files with 196 additions and 13 deletions
+124
View File
@@ -0,0 +1,124 @@
//+build ignore
// bin.go is a helper CLI to manipulate binary diff data for testing purposes.
// It can decode patches generated by git using the standard parsing functions
// or it can encode binary data back into the format expected by Git. It
// operates on stdin writes results (possibly binary) to stdout.
package main
import (
"bytes"
"compress/zlib"
"encoding/binary"
"flag"
"io/ioutil"
"log"
"os"
"strings"
"github.com/bluekeyes/go-gitdiff/gitdiff"
)
var (
b85Powers = []uint32{52200625, 614125, 7225, 85, 1}
b85Alpha = []byte(
"0123456789" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "!#$%&()*+-;<=>?@^_`{|}~",
)
)
var mode string
func base85Encode(data []byte) []byte {
chunks, remaining := len(data)/4, len(data)%4
if remaining > 0 {
data = append(data, make([]byte, 4-remaining)...)
chunks++
}
var n int
out := make([]byte, 5*chunks)
for i := 0; i < len(data); i += 4 {
v := binary.BigEndian.Uint32(data[i : i+4])
for j := 0; j < 5; j++ {
p := v / b85Powers[j]
out[n+j] = b85Alpha[p]
v -= b85Powers[j] * p
}
n += 5
}
return out
}
func compress(data []byte) ([]byte, error) {
var b bytes.Buffer
w := zlib.NewWriter(&b)
if _, err := w.Write(data); err != nil {
return nil, err
}
if err := w.Close(); err != nil {
return nil, err
}
return b.Bytes(), nil
}
func wrap(data []byte) string {
var s strings.Builder
for i := 0; i < len(data); i += 52 {
c := 52
if c > len(data)-i {
c = len(data) - i
}
b := (c / 5) * 4
if b <= 26 {
s.WriteByte(byte('A' + b - 1))
} else {
s.WriteByte(byte('a' + b - 27))
}
s.Write(data[i : i+c])
s.WriteByte('\n')
}
return s.String()
}
func init() {
flag.StringVar(&mode, "mode", "parse", "operation mode, one of 'parse' or 'encode'")
}
func main() {
flag.Parse()
switch mode {
case "parse":
files, _, err := gitdiff.Parse(os.Stdin)
if err != nil {
log.Fatalf("failed to parse file: %v", err)
}
if len(files) != 1 {
log.Fatalf("patch contains more than one file: %d", len(files))
}
if files[0].BinaryFragment == nil {
log.Fatalf("patch file does not contain a binary fragment")
}
os.Stdout.Write(files[0].BinaryFragment.Data)
case "encode":
data, err := ioutil.ReadAll(os.Stdin)
if err != nil {
log.Fatalf("failed to read input: %v", err)
}
data, err = compress(data)
if err != nil {
log.Fatalf("failed to compress data: %v", err)
}
os.Stdout.WriteString(wrap(base85Encode(data)))
default:
log.Fatalf("unknown mode: %s", mode)
}
}
Binary file not shown.
@@ -0,0 +1,5 @@
diff --git a/gitdiff/testdata/apply/bin_fragment_delta_error.src b/gitdiff/testdata/apply/bin_fragment_delta_error.src
GIT binary patch
delta 18
fc${itY+{<=z`_4AtEhVK$zKyatN;N30RR6$D+j^=
@@ -0,0 +1,5 @@
diff --git a/gitdiff/testdata/apply/bin_fragment_delta_error.src b/gitdiff/testdata/apply/bin_fragment_delta_error.src
GIT binary patch
delta 11
Xc${itY+{_?z`_4As|XMP0RR6K8UwQc
@@ -0,0 +1,5 @@
diff --git a/gitdiff/testdata/apply/bin_fragment_delta_error.src b/gitdiff/testdata/apply/bin_fragment_delta_error.src
GIT binary patch
delta 17
fc${itY+{_?z`_4AtEhVK$zKya00961|Nl5!2ZsOv
@@ -0,0 +1,5 @@
diff --git a/gitdiff/testdata/apply/bin_fragment_delta_error.src b/gitdiff/testdata/apply/bin_fragment_delta_error.src
GIT binary patch
delta 18
fc${itYGRz=z`_4AtEhVK$zKyatN;N30RR6$EeFB?