github.com/driusan/dgit@v0.0.0-20221118233547-f39f0c15edbb/git/writetree_test.go (about) 1 package git 2 3 import ( 4 "io/ioutil" 5 "os" 6 "strings" 7 "testing" 8 ) 9 10 func unsafeSha1FromString(str string) Sha1 { 11 s, err := Sha1FromString(str) 12 if err != nil { 13 panic(err) 14 } 15 return s 16 } 17 func hashString(str string) Sha1 { 18 s, _, err := HashReader("blob", strings.NewReader(str)) 19 if err != nil { 20 panic(err) 21 } 22 return s 23 } 24 25 func TestWriteIndex(t *testing.T) { 26 testcases := []struct { 27 IndexObjects []*IndexEntry 28 Sha1 string 29 ExpectError bool 30 Prefix string 31 }{ 32 { 33 nil, 34 // An empty tree hashes to this, not 0 (even with the official git client), because 35 // of the type prefix in the blob. 36 "4b825dc642cb6eb9a060e54bf8d69288fbee4904", 37 false, 38 "", 39 }, 40 // Simple case, a single file 41 { 42 []*IndexEntry{&IndexEntry{ 43 PathName: IndexPath("foo"), 44 FixedIndexEntry: FixedIndexEntry{ 45 Mode: ModeBlob, 46 Fsize: 4, 47 Sha1: hashString("bar\n"), 48 }, 49 }, 50 }, 51 "6a09c59ce8eb1b5b4f89450103e67ff9b3a3b1ae", 52 false, 53 "", 54 }, 55 // Same as case 1, but with the executable bit set. 56 { 57 []*IndexEntry{&IndexEntry{ 58 PathName: IndexPath("foo"), 59 FixedIndexEntry: FixedIndexEntry{ 60 Mode: ModeExec, 61 Fsize: 4, 62 Sha1: hashString("bar\n"), 63 }, 64 }, 65 }, 66 "e10d3585c7b4bec6b573e40d6a0c097a7e790abe", 67 false, 68 "", 69 }, 70 // A symlink from bar to foo. 71 { 72 []*IndexEntry{&IndexEntry{ 73 PathName: IndexPath("bar"), 74 FixedIndexEntry: FixedIndexEntry{ 75 Mode: ModeSymlink, 76 Fsize: 3, 77 Sha1: hashString("foo"), 78 }, 79 }, 80 }, 81 "985badfa7a966612b9f9adadbaa6a30aa3e0b1f5", 82 false, 83 "", 84 }, 85 // Simple case, two files 86 { 87 []*IndexEntry{ 88 &IndexEntry{ 89 PathName: IndexPath("bar"), 90 FixedIndexEntry: FixedIndexEntry{ 91 Mode: ModeBlob, 92 Fsize: 4, 93 Sha1: hashString("bar\n"), 94 }, 95 }, 96 &IndexEntry{ 97 PathName: IndexPath("foo"), 98 FixedIndexEntry: FixedIndexEntry{ 99 Mode: ModeBlob, 100 Fsize: 4, 101 Sha1: hashString("foo\n"), 102 }, 103 }, 104 }, 105 "89ff1a2aefcbff0f09197f0fd8beeb19a7b6e51c", 106 false, 107 "", 108 }, 109 // A single file in a subdirectory 110 { 111 []*IndexEntry{&IndexEntry{ 112 PathName: IndexPath("foo/bar"), 113 FixedIndexEntry: FixedIndexEntry{ 114 Mode: ModeBlob, 115 Fsize: 4, 116 Sha1: hashString("bar\n"), 117 }, 118 }, 119 }, 120 "7b74f9ae4e4f7232e386fd8bcb9a240e6713fadf", 121 false, 122 "", 123 }, 124 // Two files in a subdirectory 125 { 126 []*IndexEntry{ 127 &IndexEntry{ 128 PathName: IndexPath("foo/bar"), 129 FixedIndexEntry: FixedIndexEntry{ 130 Mode: ModeBlob, 131 Fsize: 4, 132 Sha1: hashString("bar\n"), 133 }, 134 }, 135 &IndexEntry{ 136 PathName: IndexPath("foo/foo"), 137 FixedIndexEntry: FixedIndexEntry{ 138 Mode: ModeBlob, 139 Fsize: 4, 140 Sha1: hashString("foo\n"), 141 }, 142 }, 143 }, 144 "e3331a4b901802f18658544c4ae320de93ab14ef", 145 false, 146 "", 147 }, 148 // Both a file and a subtree 149 { 150 []*IndexEntry{ 151 &IndexEntry{ 152 PathName: IndexPath("bar"), 153 FixedIndexEntry: FixedIndexEntry{ 154 Mode: ModeBlob, 155 Fsize: 4, 156 Sha1: hashString("bar\n"), 157 }, 158 }, 159 &IndexEntry{ 160 PathName: IndexPath("foo/foo"), 161 FixedIndexEntry: FixedIndexEntry{ 162 Mode: ModeBlob, 163 Fsize: 4, 164 Sha1: hashString("foo\n"), 165 }, 166 }, 167 }, 168 "17278814743a70ed99aca0271ecdf5b544f10e5b", 169 false, 170 "", 171 }, 172 // A file and a subtree with multiple entries 173 { 174 []*IndexEntry{ 175 &IndexEntry{ 176 PathName: IndexPath("bar"), 177 FixedIndexEntry: FixedIndexEntry{ 178 Mode: ModeBlob, 179 Fsize: 4, 180 Sha1: hashString("bar\n"), 181 }, 182 }, 183 &IndexEntry{ 184 PathName: IndexPath("foo/bar"), 185 FixedIndexEntry: FixedIndexEntry{ 186 Mode: ModeBlob, 187 Fsize: 4, 188 Sha1: hashString("bar\n"), 189 }, 190 }, 191 &IndexEntry{ 192 PathName: IndexPath("foo/foo"), 193 FixedIndexEntry: FixedIndexEntry{ 194 Mode: ModeBlob, 195 Fsize: 4, 196 Sha1: hashString("foo\n"), 197 }, 198 }, 199 }, 200 "18473c7faa0d4bb4913fd41a6768dbcf5fa70723", 201 false, 202 "", 203 }, 204 // A deep subtree 205 { 206 []*IndexEntry{ 207 &IndexEntry{ 208 PathName: IndexPath("foo/bar/baz"), 209 FixedIndexEntry: FixedIndexEntry{ 210 Mode: ModeBlob, 211 Fsize: 4, 212 Sha1: hashString("baz\n"), 213 }, 214 }, 215 }, 216 "cc1846d0911b1790fd15859ffdf48598cb46b7b0", 217 false, 218 "", 219 }, 220 // Two different subtrees 221 { 222 []*IndexEntry{ 223 &IndexEntry{ 224 PathName: IndexPath("bar/bar"), 225 FixedIndexEntry: FixedIndexEntry{ 226 Mode: ModeBlob, 227 Fsize: 4, 228 Sha1: hashString("bar\n"), 229 }, 230 }, 231 &IndexEntry{ 232 PathName: IndexPath("foo/foo"), 233 FixedIndexEntry: FixedIndexEntry{ 234 Mode: ModeBlob, 235 Fsize: 4, 236 Sha1: hashString("foo\n"), 237 }, 238 }, 239 }, 240 "65de833961e3dc313b13a2cf0a35a3bab772fc0b", 241 false, 242 "", 243 }, 244 // Tree followed by a file. 245 { 246 []*IndexEntry{ 247 &IndexEntry{ 248 PathName: IndexPath("bar/bar"), 249 FixedIndexEntry: FixedIndexEntry{ 250 Mode: ModeBlob, 251 Fsize: 4, 252 Sha1: hashString("bar\n"), 253 }, 254 }, 255 &IndexEntry{ 256 PathName: IndexPath("foo"), 257 FixedIndexEntry: FixedIndexEntry{ 258 Mode: ModeBlob, 259 Fsize: 4, 260 Sha1: hashString("foo\n"), 261 }, 262 }, 263 }, 264 "615b1bd6b48087f25d16cc78279ea48ce5b1b59d", 265 false, 266 "", 267 }, 268 { 269 []*IndexEntry{ 270 &IndexEntry{ 271 PathName: IndexPath("bar/bar"), 272 FixedIndexEntry: FixedIndexEntry{ 273 Mode: ModeBlob, 274 Fsize: 4, 275 Sha1: hashString("bar\n"), 276 }, 277 }, 278 &IndexEntry{ 279 PathName: IndexPath("baz/baz"), 280 FixedIndexEntry: FixedIndexEntry{ 281 Mode: ModeBlob, 282 Fsize: 4, 283 Sha1: hashString("baz\n"), 284 }, 285 }, 286 &IndexEntry{ 287 PathName: IndexPath("foo/foo"), 288 FixedIndexEntry: FixedIndexEntry{ 289 Mode: ModeBlob, 290 Fsize: 4, 291 Sha1: hashString("foo\n"), 292 }, 293 }, 294 }, 295 "8b9f58ced67de613a7570726233ec83fa56a3d52", 296 false, 297 "", 298 }, 299 // A file sandwiched between 2 trees 300 { 301 []*IndexEntry{ 302 &IndexEntry{ 303 PathName: IndexPath("bar/bar"), 304 FixedIndexEntry: FixedIndexEntry{ 305 Mode: ModeBlob, 306 Fsize: 4, 307 Sha1: hashString("bar\n"), 308 }, 309 }, 310 &IndexEntry{ 311 PathName: IndexPath("baz"), 312 FixedIndexEntry: FixedIndexEntry{ 313 Mode: ModeBlob, 314 Fsize: 4, 315 Sha1: hashString("baz\n"), 316 }, 317 }, 318 &IndexEntry{ 319 PathName: IndexPath("foo/foo"), 320 FixedIndexEntry: FixedIndexEntry{ 321 Mode: ModeBlob, 322 Fsize: 4, 323 Sha1: hashString("foo\n"), 324 }, 325 }, 326 }, 327 "18a6e5a95bb59e96dba722025de6abc692661bb6", 328 false, 329 "", 330 }, 331 // An index with any non-stage0 entry should produce an error 332 { 333 []*IndexEntry{ 334 &IndexEntry{ 335 PathName: IndexPath("foo"), 336 FixedIndexEntry: FixedIndexEntry{ 337 Mode: ModeBlob, 338 Fsize: 4, 339 Sha1: hashString("bar\n"), 340 Flags: uint16(Stage1) << 12, 341 }, 342 }, 343 }, 344 "", 345 true, 346 "", 347 }, 348 { 349 []*IndexEntry{ 350 &IndexEntry{ 351 PathName: IndexPath("foo"), 352 FixedIndexEntry: FixedIndexEntry{ 353 Mode: ModeBlob, 354 Fsize: 4, 355 Sha1: hashString("bar\n"), 356 Flags: uint16(Stage2) << 12, 357 }, 358 }, 359 }, 360 "", 361 true, 362 "", 363 }, 364 { 365 []*IndexEntry{ 366 &IndexEntry{ 367 PathName: IndexPath("foo"), 368 FixedIndexEntry: FixedIndexEntry{ 369 Mode: ModeBlob, 370 Fsize: 4, 371 Sha1: hashString("bar\n"), 372 Flags: uint16(Stage3) << 12, 373 }, 374 }, 375 }, 376 "", 377 true, 378 "", 379 }, 380 { 381 // Regression from the official git test suite. This was causing 382 // an infinite loop in dgit when called with a prefix of path3/ 383 // First we check that it matches without the prefix, then we check that 384 // it matches with the prefix. 385 []*IndexEntry{ 386 &IndexEntry{ 387 PathName: IndexPath("path0"), 388 FixedIndexEntry: FixedIndexEntry{ 389 Mode: ModeBlob, 390 Fsize: 12, 391 Sha1: unsafeSha1FromString("f87290f8eb2cbbea7857214459a0739927eab154"), 392 }, 393 }, 394 &IndexEntry{ 395 PathName: IndexPath("path2/file2"), 396 FixedIndexEntry: FixedIndexEntry{ 397 Mode: ModeBlob, 398 Fsize: 18, 399 Sha1: unsafeSha1FromString("3feff949ed00a62d9f7af97c15cd8a30595e7ac7"), 400 }, 401 }, 402 &IndexEntry{ 403 PathName: IndexPath("path3/file3"), 404 FixedIndexEntry: FixedIndexEntry{ 405 Mode: ModeBlob, 406 Fsize: 18, 407 Sha1: unsafeSha1FromString("0aa34cae68d0878578ad119c86ca2b5ed5b28376"), 408 }, 409 }, 410 &IndexEntry{ 411 PathName: IndexPath("path3/subp3/file3"), 412 FixedIndexEntry: FixedIndexEntry{ 413 Mode: ModeBlob, 414 Fsize: 24, 415 Sha1: unsafeSha1FromString("00fb5908cb97c2564a9783c0c64087333b3b464f"), 416 }, 417 }, 418 }, 419 "8e18edf7d7edcf4371a3ac6ae5f07c2641db7c46", 420 false, 421 "", 422 }, 423 { 424 // same as above, with a prefix of "path3". 425 []*IndexEntry{ 426 &IndexEntry{ 427 PathName: IndexPath("path0"), 428 FixedIndexEntry: FixedIndexEntry{ 429 Mode: ModeBlob, 430 Fsize: 12, 431 Sha1: unsafeSha1FromString("f87290f8eb2cbbea7857214459a0739927eab154"), 432 }, 433 }, 434 &IndexEntry{ 435 PathName: IndexPath("path2/file2"), 436 FixedIndexEntry: FixedIndexEntry{ 437 Mode: ModeBlob, 438 Fsize: 18, 439 Sha1: unsafeSha1FromString("3feff949ed00a62d9f7af97c15cd8a30595e7ac7"), 440 }, 441 }, 442 &IndexEntry{ 443 PathName: IndexPath("path3/file3"), 444 FixedIndexEntry: FixedIndexEntry{ 445 Mode: ModeBlob, 446 Fsize: 18, 447 Sha1: unsafeSha1FromString("0aa34cae68d0878578ad119c86ca2b5ed5b28376"), 448 }, 449 }, 450 &IndexEntry{ 451 PathName: IndexPath("path3/subp3/file3"), 452 FixedIndexEntry: FixedIndexEntry{ 453 Mode: ModeBlob, 454 Fsize: 24, 455 Sha1: unsafeSha1FromString("00fb5908cb97c2564a9783c0c64087333b3b464f"), 456 }, 457 }, 458 }, 459 "cfb8591b2f65de8b8cc1020cd7d9e67e7793b325", 460 false, 461 "path3", 462 }, 463 } 464 465 gitdir, err := ioutil.TempDir("", "gitwriteindex") 466 if err != nil { 467 t.Fatal(err) 468 } 469 defer os.RemoveAll(gitdir) 470 471 c, err := Init(nil, InitOptions{Quiet: true}, gitdir) 472 if err != nil { 473 t.Fatal(err) 474 } 475 476 for i, tc := range testcases { 477 treeid, err := writeTree(c, tc.Prefix, tc.IndexObjects) 478 if err != nil { 479 if !tc.ExpectError { 480 t.Error(err) 481 } 482 continue 483 } 484 if tc.ExpectError && err == nil { 485 t.Errorf("Case %d: Expected error, got none", i) 486 continue 487 } 488 489 expected, err := Sha1FromString(tc.Sha1) 490 if err != nil { 491 t.Fatal(err) 492 } 493 if treeid != TreeID(expected) { 494 t.Errorf("Unexpected hash for test case %d: got %v want %v", i, treeid, expected) 495 } 496 } 497 }