fork of go-gitdiff with jj support
at v0.7.1 7.0 kB view raw
1package gitdiff 2 3import ( 4 "encoding/binary" 5 "io" 6 "reflect" 7 "strings" 8 "testing" 9) 10 11func TestParseBinaryMarker(t *testing.T) { 12 tests := map[string]struct { 13 Input string 14 IsBinary bool 15 HasData bool 16 Err bool 17 }{ 18 "binaryPatch": { 19 Input: "GIT binary patch\n", 20 IsBinary: true, 21 HasData: true, 22 }, 23 "binaryFileNoPatch": { 24 Input: "Binary files differ\n", 25 IsBinary: true, 26 HasData: false, 27 }, 28 "textFile": { 29 Input: "@@ -10,14 +22,31 @@\n", 30 IsBinary: false, 31 HasData: false, 32 }, 33 } 34 35 for name, test := range tests { 36 t.Run(name, func(t *testing.T) { 37 p := newTestParser(test.Input, true) 38 39 isBinary, hasData, err := p.ParseBinaryMarker() 40 if test.Err { 41 if err == nil || err == io.EOF { 42 t.Fatalf("expected error parsing binary marker, but got %v", err) 43 } 44 return 45 } 46 if err != nil { 47 t.Fatalf("unexpected error parsing binary marker: %v", err) 48 } 49 if test.IsBinary != isBinary { 50 t.Errorf("incorrect isBinary value: expected %t, actual %t", test.IsBinary, isBinary) 51 } 52 if test.HasData != hasData { 53 t.Errorf("incorrect hasData value: expected %t, actual %t", test.HasData, hasData) 54 } 55 }) 56 } 57} 58 59func TestParseBinaryFragmentHeader(t *testing.T) { 60 tests := map[string]struct { 61 Input string 62 Output *BinaryFragment 63 Err bool 64 }{ 65 "delta": { 66 Input: "delta 1234\n", 67 Output: &BinaryFragment{ 68 Method: BinaryPatchDelta, 69 Size: 1234, 70 }, 71 }, 72 "literal": { 73 Input: "literal 1234\n", 74 Output: &BinaryFragment{ 75 Method: BinaryPatchLiteral, 76 Size: 1234, 77 }, 78 }, 79 "unknownMethod": { 80 Input: "compressed 1234\n", 81 Output: nil, 82 }, 83 "notAHeader": { 84 Input: "Binary files differ\n", 85 Output: nil, 86 }, 87 "invalidSize": { 88 Input: "delta 123abc\n", 89 Err: true, 90 }, 91 } 92 93 for name, test := range tests { 94 t.Run(name, func(t *testing.T) { 95 p := newTestParser(test.Input, true) 96 97 frag, err := p.ParseBinaryFragmentHeader() 98 if test.Err { 99 if err == nil || err == io.EOF { 100 t.Fatalf("expected error parsing binary header, but got %v", err) 101 } 102 return 103 } 104 if err != nil { 105 t.Fatalf("unexpected error parsing binary header: %v", err) 106 } 107 if !reflect.DeepEqual(test.Output, frag) { 108 t.Errorf("incorrect binary fragment\nexpected: %+v\n actual: %+v", test.Output, frag) 109 } 110 }) 111 } 112} 113 114func TestParseBinaryChunk(t *testing.T) { 115 tests := map[string]struct { 116 Input string 117 Fragment BinaryFragment 118 Output []byte 119 Err string 120 }{ 121 "singleline": { 122 Input: "TcmZQzU|?i`U?w2V48*Je09XJG\n\n", 123 Fragment: BinaryFragment{ 124 Size: 20, 125 }, 126 Output: fib(5, binary.BigEndian), 127 }, 128 "multiline": { 129 Input: "zcmZQzU|?i`U?w2V48*KJ%mKu_Kr9NxN<eH5#F0Qe0f=7$l~*z_FeL$%-)3N7vt?l5\n" + 130 "zl3-vE2xVZ9%4J~CI>f->s?WfX|B-=Vs{#X~svra7Ekg#T|4s}nH;WnAZ)|1Y*`&cB\n" + 131 "s(sh?X(Uz6L^!Ou&aF*u`J!eibJifSrv0z>$Q%Hd(^HIJ<Y?5`S0gT5UE&u=k\n\n", 132 Fragment: BinaryFragment{ 133 Size: 160, 134 }, 135 Output: fib(40, binary.BigEndian), 136 }, 137 "shortLine": { 138 Input: "A00\n\n", 139 Err: "corrupt data line", 140 }, 141 "underpaddedLine": { 142 Input: "H00000000\n\n", 143 Err: "corrupt data line", 144 }, 145 "invalidLengthByte": { 146 Input: "!00000\n\n", 147 Err: "invalid length byte", 148 }, 149 "miscountedLine": { 150 Input: "H00000\n\n", 151 Err: "incorrect byte count", 152 }, 153 "invalidEncoding": { 154 Input: "TcmZQzU|?i'U?w2V48*Je09XJG\n", 155 Err: "invalid base85 byte", 156 }, 157 "noTrailingEmptyLine": { 158 Input: "TcmZQzU|?i`U?w2V48*Je09XJG\n", 159 Err: "unexpected EOF", 160 }, 161 "invalidCompression": { 162 Input: "F007GV%KiWV\n\n", 163 Err: "zlib", 164 }, 165 "incorrectSize": { 166 Input: "TcmZQzU|?i`U?w2V48*Je09XJG\n\n", 167 Fragment: BinaryFragment{ 168 Size: 16, 169 }, 170 Err: "16 byte fragment inflated to 20", 171 }, 172 } 173 174 for name, test := range tests { 175 t.Run(name, func(t *testing.T) { 176 p := newTestParser(test.Input, true) 177 178 frag := test.Fragment 179 err := p.ParseBinaryChunk(&frag) 180 if test.Err != "" { 181 if err == nil || !strings.Contains(err.Error(), test.Err) { 182 t.Fatalf("expected error containing %q parsing binary chunk, but got %v", test.Err, err) 183 } 184 return 185 } 186 if err != nil { 187 t.Fatalf("unexpected error parsing binary chunk: %v", err) 188 } 189 if !reflect.DeepEqual(test.Output, frag.Data) { 190 t.Errorf("incorrect binary chunk\nexpected: %+v\n actual: %+v", test.Output, frag.Data) 191 } 192 }) 193 } 194} 195 196func TestParseBinaryFragments(t *testing.T) { 197 tests := map[string]struct { 198 Input string 199 File File 200 201 Binary bool 202 Fragment *BinaryFragment 203 ReverseFragment *BinaryFragment 204 Err bool 205 }{ 206 "dataWithReverse": { 207 Input: `GIT binary patch 208literal 40 209gcmZQzU|?i` + "`" + `U?w2V48*KJ%mKu_Kr9NxN<eH500b)lkN^Mx 210 211literal 0 212HcmV?d00001 213 214`, 215 Binary: true, 216 Fragment: &BinaryFragment{ 217 Method: BinaryPatchLiteral, 218 Size: 40, 219 Data: fib(10, binary.BigEndian), 220 }, 221 ReverseFragment: &BinaryFragment{ 222 Method: BinaryPatchLiteral, 223 Size: 0, 224 Data: []byte{}, 225 }, 226 }, 227 "dataWithoutReverse": { 228 Input: `GIT binary patch 229literal 40 230gcmZQzU|?i` + "`" + `U?w2V48*KJ%mKu_Kr9NxN<eH500b)lkN^Mx 231 232`, 233 Binary: true, 234 Fragment: &BinaryFragment{ 235 Method: BinaryPatchLiteral, 236 Size: 40, 237 Data: fib(10, binary.BigEndian), 238 }, 239 }, 240 "noData": { 241 Input: "Binary files differ\n", 242 Binary: true, 243 }, 244 "text": { 245 Input: `@@ -1 +1 @@ 246-old line 247+new line 248`, 249 Binary: false, 250 }, 251 "missingData": { 252 Input: "GIT binary patch\n", 253 Err: true, 254 }, 255 "invalidData": { 256 Input: `GIT binary patch 257literal 20 258TcmZQzU|?i'U?w2V48*Je09XJG 259 260`, 261 Err: true, 262 }, 263 "invalidReverseData": { 264 Input: `GIT binary patch 265literal 20 266TcmZQzU|?i` + "`" + `U?w2V48*Je09XJG 267 268literal 0 269zcmV?d00001 270 271`, 272 Err: true, 273 }, 274 } 275 276 for name, test := range tests { 277 t.Run(name, func(t *testing.T) { 278 p := newTestParser(test.Input, true) 279 280 file := test.File 281 _, err := p.ParseBinaryFragments(&file) 282 if test.Err { 283 if err == nil || err == io.EOF { 284 t.Fatalf("expected error parsing binary fragments, but got %v", err) 285 } 286 return 287 } 288 if err != nil { 289 t.Fatalf("unexpected error parsing binary fragments: %v", err) 290 } 291 if test.Binary != file.IsBinary { 292 t.Errorf("incorrect binary state: expected %t, actual %t", test.Binary, file.IsBinary) 293 } 294 if !reflect.DeepEqual(test.Fragment, file.BinaryFragment) { 295 t.Errorf("incorrect binary fragment\nexpected: %+v\n actual: %+v", test.Fragment, file.BinaryFragment) 296 } 297 if !reflect.DeepEqual(test.ReverseFragment, file.ReverseBinaryFragment) { 298 t.Errorf("incorrect reverse binary fragment\nexpected: %+v\n actual: %+v", test.ReverseFragment, file.ReverseBinaryFragment) 299 } 300 }) 301 } 302} 303 304func fib(n int, ord binary.ByteOrder) []byte { 305 buf := make([]byte, 4*n) 306 for i := 0; i < len(buf); i += 4 { 307 if i < 8 { 308 ord.PutUint32(buf[i:], 1) 309 } else { 310 ord.PutUint32(buf[i:], ord.Uint32(buf[i-4:])+ord.Uint32(buf[i-8:])) 311 } 312 } 313 return buf 314}