fork of go-git with some jj specific features
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 434 lines 12 kB view raw
1package object 2 3import ( 4 "context" 5 "sort" 6 "testing" 7 8 fixtures "github.com/go-git/go-git-fixtures/v4" 9 "github.com/go-git/go-git/v5/plumbing" 10 "github.com/go-git/go-git/v5/plumbing/cache" 11 "github.com/go-git/go-git/v5/plumbing/filemode" 12 "github.com/go-git/go-git/v5/plumbing/format/diff" 13 "github.com/go-git/go-git/v5/plumbing/storer" 14 "github.com/go-git/go-git/v5/storage/filesystem" 15 "github.com/go-git/go-git/v5/utils/merkletrie" 16 "github.com/stretchr/testify/suite" 17) 18 19type ChangeFixtureSuite struct { 20 fixtures.Suite 21} 22 23type ChangeSuite struct { 24 suite.Suite 25 ChangeFixtureSuite 26 Storer storer.EncodedObjectStorer 27 Fixture *fixtures.Fixture 28} 29 30func (s *ChangeSuite) SetupSuite() { 31 s.Fixture = fixtures.ByURL("https://github.com/src-d/go-git.git"). 32 ByTag(".git").One() 33 sto := filesystem.NewStorage(s.Fixture.DotGit(), cache.NewObjectLRUDefault()) 34 s.Storer = sto 35} 36 37func (s *ChangeSuite) tree(h plumbing.Hash) *Tree { 38 t, err := GetTree(s.Storer, h) 39 s.NoError(err) 40 return t 41} 42 43func TestChangeSuite(t *testing.T) { 44 suite.Run(t, new(ChangeSuite)) 45} 46 47func (s *ChangeSuite) TestInsert() { 48 // Commit a5078b19f08f63e7948abd0a5e2fb7d319d3a565 of the go-git 49 // fixture inserted "examples/clone/main.go". 50 // 51 // On that commit, the "examples/clone" tree is 52 // 6efca3ff41cab651332f9ebc0c96bb26be809615 53 // 54 // and the "examples/colone/main.go" is 55 // f95dc8f7923add1a8b9f72ecb1e8db1402de601a 56 57 path := "examples/clone/main.go" 58 name := "main.go" 59 mode := filemode.Regular 60 blob := plumbing.NewHash("f95dc8f7923add1a8b9f72ecb1e8db1402de601a") 61 tree := plumbing.NewHash("6efca3ff41cab651332f9ebc0c96bb26be809615") 62 63 change := &Change{ 64 From: empty, 65 To: ChangeEntry{ 66 Name: path, 67 Tree: s.tree(tree), 68 TreeEntry: TreeEntry{ 69 Name: name, 70 Mode: mode, 71 Hash: blob, 72 }, 73 }, 74 } 75 76 action, err := change.Action() 77 s.NoError(err) 78 s.Equal(merkletrie.Insert, action) 79 80 from, to, err := change.Files() 81 s.NoError(err) 82 s.Nil(from) 83 s.Equal(name, to.Name) 84 s.Equal(blob, to.Blob.Hash) 85 86 p, err := change.Patch() 87 s.NoError(err) 88 s.Equal(1, len(p.FilePatches())) 89 s.Equal(1, len(p.FilePatches()[0].Chunks())) 90 s.Equal(diff.Add, p.FilePatches()[0].Chunks()[0].Type()) 91 92 p, err = change.PatchContext(context.Background()) 93 s.NoError(err) 94 s.Equal(1, len(p.FilePatches())) 95 s.Equal(1, len(p.FilePatches()[0].Chunks())) 96 s.Equal(diff.Add, p.FilePatches()[0].Chunks()[0].Type()) 97 98 str := change.String() 99 s.Equal("<Action: Insert, Path: examples/clone/main.go>", str) 100} 101 102func (s *ChangeSuite) TestDelete() { 103 // Commit f6011d65d57c2a866e231fc21a39cb618f86f9ea of the go-git 104 // fixture deleted "utils/difftree/difftree.go". 105 // 106 // The parent of that commit is 107 // 9b4a386db3d98a4362516a00ef3d04d4698c9bcd. 108 // 109 // On that parent commit, the "utils/difftree" tree is 110 // f3d11566401ce4b0808aab9dd6fad3d5abf1481a. 111 // 112 // and the "utils/difftree/difftree.go" is 113 // e2cb9a5719daf634d45a063112b4044ee81da13ea. 114 115 path := "utils/difftree/difftree.go" 116 name := "difftree.go" 117 mode := filemode.Regular 118 blob := plumbing.NewHash("e2cb9a5719daf634d45a063112b4044ee81da13e") 119 tree := plumbing.NewHash("f3d11566401ce4b0808aab9dd6fad3d5abf1481a") 120 121 change := &Change{ 122 From: ChangeEntry{ 123 Name: path, 124 Tree: s.tree(tree), 125 TreeEntry: TreeEntry{ 126 Name: name, 127 Mode: mode, 128 Hash: blob, 129 }, 130 }, 131 To: empty, 132 } 133 134 action, err := change.Action() 135 s.NoError(err) 136 s.Equal(merkletrie.Delete, action) 137 138 from, to, err := change.Files() 139 s.NoError(err) 140 s.Nil(to) 141 s.Equal(name, from.Name) 142 s.Equal(blob, from.Blob.Hash) 143 144 p, err := change.Patch() 145 s.NoError(err) 146 s.Equal(1, len(p.FilePatches())) 147 s.Equal(1, len(p.FilePatches()[0].Chunks())) 148 s.Equal(diff.Delete, p.FilePatches()[0].Chunks()[0].Type()) 149 150 p, err = change.PatchContext(context.Background()) 151 s.NoError(err) 152 s.Equal(1, len(p.FilePatches())) 153 s.Equal(1, len(p.FilePatches()[0].Chunks())) 154 s.Equal(diff.Delete, p.FilePatches()[0].Chunks()[0].Type()) 155 156 str := change.String() 157 s.Equal("<Action: Delete, Path: utils/difftree/difftree.go>", str) 158} 159 160func (s *ChangeSuite) TestModify() { 161 // Commit 7beaad711378a4daafccc2c04bc46d36df2a0fd1 of the go-git 162 // fixture modified "examples/latest/latest.go". 163 // the "examples/latest" tree is 164 // b1f01b730b855c82431918cb338ad47ed558999b. 165 // and "examples/latest/latest.go" is blob 166 // 05f583ace3a9a078d8150905a53a4d82567f125f. 167 // 168 // The parent of that commit is 169 // 337148ef6d751477796922ac127b416b8478fcc4. 170 // the "examples/latest" tree is 171 // 8b0af31d2544acb5c4f3816a602f11418cbd126e. 172 // and "examples/latest/latest.go" is blob 173 // de927fad935d172929aacf20e71f3bf0b91dd6f9. 174 175 path := "utils/difftree/difftree.go" 176 name := "difftree.go" 177 mode := filemode.Regular 178 fromBlob := plumbing.NewHash("05f583ace3a9a078d8150905a53a4d82567f125f") 179 fromTree := plumbing.NewHash("b1f01b730b855c82431918cb338ad47ed558999b") 180 toBlob := plumbing.NewHash("de927fad935d172929aacf20e71f3bf0b91dd6f9") 181 toTree := plumbing.NewHash("8b0af31d2544acb5c4f3816a602f11418cbd126e") 182 183 change := &Change{ 184 From: ChangeEntry{ 185 Name: path, 186 Tree: s.tree(fromTree), 187 TreeEntry: TreeEntry{ 188 Name: name, 189 Mode: mode, 190 Hash: fromBlob, 191 }, 192 }, 193 To: ChangeEntry{ 194 Name: path, 195 Tree: s.tree(toTree), 196 TreeEntry: TreeEntry{ 197 Name: name, 198 Mode: mode, 199 Hash: toBlob, 200 }, 201 }, 202 } 203 204 action, err := change.Action() 205 s.NoError(err) 206 s.Equal(merkletrie.Modify, action) 207 208 from, to, err := change.Files() 209 s.NoError(err) 210 211 s.Equal(name, from.Name) 212 s.Equal(fromBlob, from.Blob.Hash) 213 s.Equal(name, to.Name) 214 s.Equal(toBlob, to.Blob.Hash) 215 216 p, err := change.Patch() 217 s.NoError(err) 218 s.Equal(1, len(p.FilePatches())) 219 s.Equal(7, len(p.FilePatches()[0].Chunks())) 220 s.Equal(diff.Equal, p.FilePatches()[0].Chunks()[0].Type()) 221 s.Equal(diff.Delete, p.FilePatches()[0].Chunks()[1].Type()) 222 s.Equal(diff.Add, p.FilePatches()[0].Chunks()[2].Type()) 223 s.Equal(diff.Equal, p.FilePatches()[0].Chunks()[3].Type()) 224 s.Equal(diff.Delete, p.FilePatches()[0].Chunks()[4].Type()) 225 s.Equal(diff.Add, p.FilePatches()[0].Chunks()[5].Type()) 226 s.Equal(diff.Equal, p.FilePatches()[0].Chunks()[6].Type()) 227 228 p, err = change.PatchContext(context.Background()) 229 s.NoError(err) 230 s.Equal(1, len(p.FilePatches())) 231 s.Equal(7, len(p.FilePatches()[0].Chunks())) 232 s.Equal(diff.Equal, p.FilePatches()[0].Chunks()[0].Type()) 233 s.Equal(diff.Delete, p.FilePatches()[0].Chunks()[1].Type()) 234 s.Equal(diff.Add, p.FilePatches()[0].Chunks()[2].Type()) 235 s.Equal(diff.Equal, p.FilePatches()[0].Chunks()[3].Type()) 236 s.Equal(diff.Delete, p.FilePatches()[0].Chunks()[4].Type()) 237 s.Equal(diff.Add, p.FilePatches()[0].Chunks()[5].Type()) 238 s.Equal(diff.Equal, p.FilePatches()[0].Chunks()[6].Type()) 239 240 str := change.String() 241 s.Equal("<Action: Modify, Path: utils/difftree/difftree.go>", str) 242} 243 244func (s *ChangeSuite) TestEmptyChangeFails() { 245 change := &Change{} 246 247 _, err := change.Action() 248 s.ErrorContains(err, "malformed") 249 250 _, _, err = change.Files() 251 s.ErrorContains(err, "malformed") 252 253 str := change.String() 254 s.Equal("malformed change", str) 255} 256 257// test reproducing bug #317 258func (s *ChangeSuite) TestNoFileFilemodes() { 259 f := fixtures.ByURL("https://github.com/git-fixtures/submodule.git").One() 260 261 sto := filesystem.NewStorage(f.DotGit(), cache.NewObjectLRUDefault()) 262 263 iter, err := sto.IterEncodedObjects(plumbing.AnyObject) 264 s.NoError(err) 265 var commits []*Commit 266 iter.ForEach(func(o plumbing.EncodedObject) error { 267 if o.Type() == plumbing.CommitObject { 268 commit, err := GetCommit(sto, o.Hash()) 269 s.NoError(err) 270 commits = append(commits, commit) 271 272 } 273 274 return nil 275 }) 276 277 s.NotEqual(0, len(commits)) 278 279 var prev *Commit 280 for _, commit := range commits { 281 if prev == nil { 282 prev = commit 283 continue 284 } 285 tree, err := commit.Tree() 286 s.NoError(err) 287 prevTree, err := prev.Tree() 288 s.NoError(err) 289 changes, err := DiffTree(tree, prevTree) 290 s.NoError(err) 291 for _, change := range changes { 292 _, _, err := change.Files() 293 s.NoError(err) 294 } 295 296 prev = commit 297 } 298} 299 300func (s *ChangeSuite) TestErrorsFindingChildsAreDetected() { 301 // Commit 7beaad711378a4daafccc2c04bc46d36df2a0fd1 of the go-git 302 // fixture modified "examples/latest/latest.go". 303 // the "examples/latest" tree is 304 // b1f01b730b855c82431918cb338ad47ed558999b. 305 // and "examples/latest/latest.go" is blob 306 // 05f583ace3a9a078d8150905a53a4d82567f125f. 307 // 308 // The parent of that commit is 309 // 337148ef6d751477796922ac127b416b8478fcc4. 310 // the "examples/latest" tree is 311 // 8b0af31d2544acb5c4f3816a602f11418cbd126e. 312 // and "examples/latest/latest.go" is blob 313 // de927fad935d172929aacf20e71f3bf0b91dd6f9. 314 315 path := "utils/difftree/difftree.go" 316 name := "difftree.go" 317 mode := filemode.Regular 318 fromBlob := plumbing.NewHash("aaaa") // does not exists 319 fromTree := plumbing.NewHash("b1f01b730b855c82431918cb338ad47ed558999b") 320 toBlob := plumbing.NewHash("bbbb") // does not exists 321 toTree := plumbing.NewHash("8b0af31d2544acb5c4f3816a602f11418cbd126e") 322 323 change := &Change{ 324 From: ChangeEntry{ 325 Name: path, 326 Tree: s.tree(fromTree), 327 TreeEntry: TreeEntry{ 328 Name: name, 329 Mode: mode, 330 Hash: fromBlob, 331 }, 332 }, 333 To: ChangeEntry{}, 334 } 335 336 _, _, err := change.Files() 337 s.ErrorContains(err, "object not found") 338 339 change = &Change{ 340 From: empty, 341 To: ChangeEntry{ 342 Name: path, 343 Tree: s.tree(toTree), 344 TreeEntry: TreeEntry{ 345 Name: name, 346 Mode: mode, 347 Hash: toBlob, 348 }, 349 }, 350 } 351 352 _, _, err = change.Files() 353 s.ErrorContains(err, "object not found") 354} 355 356func (s *ChangeSuite) TestChangesString() { 357 expected := "[]" 358 changes := Changes{} 359 obtained := changes.String() 360 s.Equal(expected, obtained) 361 362 expected = "[<Action: Modify, Path: bla>]" 363 changes = make([]*Change, 1) 364 changes[0] = &Change{} 365 changes[0].From.Name = "bla" 366 changes[0].To.Name = "bla" 367 368 obtained = changes.String() 369 s.Equal(expected, obtained) 370 371 expected = "[<Action: Modify, Path: bla>, <Action: Delete, Path: foo/bar>]" 372 changes = make([]*Change, 2) 373 changes[0] = &Change{} 374 changes[0].From.Name = "bla" 375 changes[0].To.Name = "bla" 376 changes[1] = &Change{} 377 changes[1].From.Name = "foo/bar" 378 obtained = changes.String() 379 s.Equal(expected, obtained) 380} 381 382func (s *ChangeSuite) TestChangesSort() { 383 changes := make(Changes, 3) 384 changes[0] = &Change{} 385 changes[0].From.Name = "z" 386 changes[0].To.Name = "z" 387 changes[1] = &Change{} 388 changes[1].From.Name = "b/b" 389 changes[2] = &Change{} 390 changes[2].To.Name = "b/a" 391 392 expected := "[<Action: Insert, Path: b/a>, " + 393 "<Action: Delete, Path: b/b>, " + 394 "<Action: Modify, Path: z>]" 395 396 sort.Sort(changes) 397 s.Equal(expected, changes.String()) 398} 399 400func (s *ChangeSuite) TestCancel() { 401 // Commit a5078b19f08f63e7948abd0a5e2fb7d319d3a565 of the go-git 402 // fixture inserted "examples/clone/main.go". 403 // 404 // On that commit, the "examples/clone" tree is 405 // 6efca3ff41cab651332f9ebc0c96bb26be809615 406 // 407 // and the "examples/clone/main.go" is 408 // f95dc8f7923add1a8b9f72ecb1e8db1402de601a 409 410 path := "examples/clone/main.go" 411 name := "main.go" 412 mode := filemode.Regular 413 blob := plumbing.NewHash("f95dc8f7923add1a8b9f72ecb1e8db1402de601a") 414 tree := plumbing.NewHash("6efca3ff41cab651332f9ebc0c96bb26be809615") 415 416 change := &Change{ 417 From: empty, 418 To: ChangeEntry{ 419 Name: path, 420 Tree: s.tree(tree), 421 TreeEntry: TreeEntry{ 422 Name: name, 423 Mode: mode, 424 Hash: blob, 425 }, 426 }, 427 } 428 429 ctx, cancel := context.WithCancel(context.Background()) 430 cancel() 431 p, err := change.PatchContext(ctx) 432 s.Nil(p) 433 s.ErrorContains(err, "operation canceled") 434}