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