package difftree import ( "os" "sort" "srcd.works/go-git.v4/plumbing" "srcd.works/go-git.v4/plumbing/object" "srcd.works/go-git.v4/plumbing/storer" "srcd.works/go-git.v4/storage/filesystem" "srcd.works/go-git.v4/utils/merkletrie" "srcd.works/go-git.v4/utils/merkletrie/noder" "github.com/src-d/go-git-fixtures" . "gopkg.in/check.v1" ) type ChangeAdaptorSuite struct { fixtures.Suite Storer storer.EncodedObjectStorer Fixture *fixtures.Fixture } func (s *ChangeAdaptorSuite) SetUpSuite(c *C) { s.Suite.SetUpSuite(c) s.Fixture = fixtures.Basic().One() sto, err := filesystem.NewStorage(s.Fixture.DotGit()) c.Assert(err, IsNil) s.Storer = sto } func (s *ChangeAdaptorSuite) tree(c *C, h plumbing.Hash) *object.Tree { t, err := object.GetTree(s.Storer, h) c.Assert(err, IsNil) return t } var _ = Suite(&ChangeAdaptorSuite{}) // utility function to build Noders from a tree and an tree entry. func newNoder(t *object.Tree, e object.TreeEntry) noder.Noder { return &treeNoder{ parent: t, name: e.Name, mode: e.Mode, hash: e.Hash, } } // utility function to build Paths func newPath(nn ...noder.Noder) noder.Path { return noder.Path(nn) } func (s *ChangeAdaptorSuite) TestTreeNoderHashHasMode(c *C) { hash := plumbing.NewHash("aaaa") mode := object.FileMode treeNoder := &treeNoder{ hash: hash, mode: mode, } expected := []byte{ 0xaa, 0xaa, 0x00, 0x00, // original hash is aaaa and 16 zeros 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x81, 0x00, 0x00, // object.FileMode in little endian } c.Assert(treeNoder.Hash(), DeepEquals, expected) } func (s *ChangeAdaptorSuite) TestNewChangeInsert(c *C) { tree := &object.Tree{} entry := object.TreeEntry{ Name: "name", Mode: os.FileMode(42), Hash: plumbing.NewHash("aaaaa"), } path := newPath(newNoder(tree, entry)) expectedTo, err := newChangeEntry(path) c.Assert(err, IsNil) src := merkletrie.Change{ From: nil, To: path, } obtained, err := newChange(src) c.Assert(err, IsNil) action, err := obtained.Action() c.Assert(err, IsNil) c.Assert(action, Equals, merkletrie.Insert) c.Assert(obtained.From, Equals, ChangeEntry{}) c.Assert(obtained.To, Equals, expectedTo) } func (s *ChangeAdaptorSuite) TestNewChangeDelete(c *C) { tree := &object.Tree{} entry := object.TreeEntry{ Name: "name", Mode: os.FileMode(42), Hash: plumbing.NewHash("aaaaa"), } path := newPath(newNoder(tree, entry)) expectedFrom, err := newChangeEntry(path) c.Assert(err, IsNil) src := merkletrie.Change{ From: path, To: nil, } obtained, err := newChange(src) c.Assert(err, IsNil) action, err := obtained.Action() c.Assert(err, IsNil) c.Assert(action, Equals, merkletrie.Delete) c.Assert(obtained.From, Equals, expectedFrom) c.Assert(obtained.To, Equals, ChangeEntry{}) } func (s *ChangeAdaptorSuite) TestNewChangeModify(c *C) { treeA := &object.Tree{} entryA := object.TreeEntry{ Name: "name", Mode: os.FileMode(42), Hash: plumbing.NewHash("aaaaa"), } pathA := newPath(newNoder(treeA, entryA)) expectedFrom, err := newChangeEntry(pathA) c.Assert(err, IsNil) treeB := &object.Tree{} entryB := object.TreeEntry{ Name: "name", Mode: os.FileMode(42), Hash: plumbing.NewHash("bbbb"), } pathB := newPath(newNoder(treeB, entryB)) expectedTo, err := newChangeEntry(pathB) c.Assert(err, IsNil) src := merkletrie.Change{ From: pathA, To: pathB, } obtained, err := newChange(src) c.Assert(err, IsNil) action, err := obtained.Action() c.Assert(err, IsNil) c.Assert(action, Equals, merkletrie.Modify) c.Assert(obtained.From, Equals, expectedFrom) c.Assert(obtained.To, Equals, expectedTo) } func (s *ChangeAdaptorSuite) TestEmptyChangeFails(c *C) { change := &Change{ From: empty, To: empty, } _, err := change.Action() c.Assert(err, ErrorMatches, "malformed change.*") _, _, err = change.Files() c.Assert(err, ErrorMatches, "malformed change.*") str := change.String() c.Assert(str, Equals, "malformed change") } type noderMock struct{ noder.Noder } func (s *ChangeAdaptorSuite) TestNewChangeFailsWithChangesFromOtherNoders(c *C) { src := merkletrie.Change{ From: newPath(noderMock{}), To: nil, } _, err := newChange(src) c.Assert(err, Not(IsNil)) src = merkletrie.Change{ From: nil, To: newPath(noderMock{}), } _, err = newChange(src) c.Assert(err, Not(IsNil)) } func (s *ChangeAdaptorSuite) TestChangeStringFrom(c *C) { expected := "" change := Change{} change.From.Name = "foo" obtained := change.String() c.Assert(obtained, Equals, expected) } func (s *ChangeAdaptorSuite) TestChangeStringTo(c *C) { expected := "" change := Change{} change.To.Name = "foo" obtained := change.String() c.Assert(obtained, Equals, expected) } func (s *ChangeAdaptorSuite) TestChangeFilesInsert(c *C) { tree := s.tree(c, plumbing.NewHash("a8d315b2b1c615d43042c3a62402b8a54288cf5c")) change := Change{} change.To.Name = "json/long.json" change.To.Tree = tree change.To.TreeEntry.Hash = plumbing.NewHash("49c6bb89b17060d7b4deacb7b338fcc6ea2352a9") from, to, err := change.Files() c.Assert(err, IsNil) c.Assert(from, IsNil) c.Assert(to.ID(), Equals, change.To.TreeEntry.Hash) } func (s *ChangeAdaptorSuite) TestChangeFilesInsertNotFound(c *C) { tree := s.tree(c, plumbing.NewHash("a8d315b2b1c615d43042c3a62402b8a54288cf5c")) change := Change{} change.To.Name = "json/long.json" change.To.Tree = tree // there is no object for this hash change.To.TreeEntry.Hash = plumbing.NewHash("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") _, _, err := change.Files() c.Assert(err, Not(IsNil)) } func (s *ChangeAdaptorSuite) TestChangeFilesDelete(c *C) { tree := s.tree(c, plumbing.NewHash("a8d315b2b1c615d43042c3a62402b8a54288cf5c")) change := Change{} change.From.Name = "json/long.json" change.From.Tree = tree change.From.TreeEntry.Hash = plumbing.NewHash("49c6bb89b17060d7b4deacb7b338fcc6ea2352a9") from, to, err := change.Files() c.Assert(err, IsNil) c.Assert(to, IsNil) c.Assert(from.ID(), Equals, change.From.TreeEntry.Hash) } func (s *ChangeAdaptorSuite) TestChangeFilesDeleteNotFound(c *C) { tree := s.tree(c, plumbing.NewHash("a8d315b2b1c615d43042c3a62402b8a54288cf5c")) change := Change{} change.From.Name = "json/long.json" change.From.Tree = tree // there is no object for this hash change.From.TreeEntry.Hash = plumbing.NewHash("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") _, _, err := change.Files() c.Assert(err, Not(IsNil)) } func (s *ChangeAdaptorSuite) TestChangeFilesModify(c *C) { tree := s.tree(c, plumbing.NewHash("a8d315b2b1c615d43042c3a62402b8a54288cf5c")) change := Change{} change.To.Name = "json/long.json" change.To.Tree = tree change.To.TreeEntry.Hash = plumbing.NewHash("49c6bb89b17060d7b4deacb7b338fcc6ea2352a9") change.From.Name = "json/long.json" change.From.Tree = tree change.From.TreeEntry.Hash = plumbing.NewHash("9a48f23120e880dfbe41f7c9b7b708e9ee62a492") from, to, err := change.Files() c.Assert(err, IsNil) c.Assert(to.ID(), Equals, change.To.TreeEntry.Hash) c.Assert(from.ID(), Equals, change.From.TreeEntry.Hash) } func (s *ChangeAdaptorSuite) TestChangeEntryFailsWithOtherNoders(c *C) { path := noder.Path{noderMock{}} _, err := newChangeEntry(path) c.Assert(err, Not(IsNil)) } func (s *ChangeAdaptorSuite) TestChangeEntryFromNilIsZero(c *C) { obtained, err := newChangeEntry(nil) c.Assert(err, IsNil) c.Assert(obtained, Equals, ChangeEntry{}) } func (s *ChangeAdaptorSuite) TestChangeEntryFromSortPath(c *C) { tree := &object.Tree{} entry := object.TreeEntry{ Name: "name", Mode: os.FileMode(42), Hash: plumbing.NewHash("aaaaa"), } path := newPath(newNoder(tree, entry)) obtained, err := newChangeEntry(path) c.Assert(err, IsNil) c.Assert(obtained.Name, Equals, entry.Name) c.Assert(obtained.Tree, Equals, tree) c.Assert(obtained.TreeEntry, DeepEquals, entry) } func (s *ChangeAdaptorSuite) TestChangeEntryFromLongPath(c *C) { treeA := &object.Tree{} entryA := object.TreeEntry{ Name: "nameA", Mode: os.FileMode(42), Hash: plumbing.NewHash("aaaa"), } treeB := &object.Tree{} entryB := object.TreeEntry{ Name: "nameB", Mode: os.FileMode(24), Hash: plumbing.NewHash("bbbb"), } path := newPath( newNoder(treeA, entryA), newNoder(treeB, entryB), ) obtained, err := newChangeEntry(path) c.Assert(err, IsNil) c.Assert(obtained.Name, Equals, entryA.Name+"/"+entryB.Name) c.Assert(obtained.Tree, Equals, treeB) c.Assert(obtained.TreeEntry, Equals, entryB) } func (s *ChangeAdaptorSuite) TestNewChangesEmpty(c *C) { expected := "[]" changes, err := newChanges(nil) c.Assert(err, IsNil) obtained := changes.String() c.Assert(obtained, Equals, expected) expected = "[]" changes, err = newChanges(merkletrie.Changes{}) c.Assert(err, IsNil) obtained = changes.String() c.Assert(obtained, Equals, expected) } func (s *ChangeAdaptorSuite) TestNewChanges(c *C) { treeA := &object.Tree{} entryA := object.TreeEntry{Name: "nameA"} pathA := newPath(newNoder(treeA, entryA)) changeA := merkletrie.Change{ From: nil, To: pathA, } treeB := &object.Tree{} entryB := object.TreeEntry{Name: "nameB"} pathB := newPath(newNoder(treeB, entryB)) changeB := merkletrie.Change{ From: pathB, To: nil, } src := merkletrie.Changes{changeA, changeB} changes, err := newChanges(src) c.Assert(err, IsNil) c.Assert(len(changes), Equals, 2) action, err := changes[0].Action() c.Assert(err, IsNil) c.Assert(action, Equals, merkletrie.Insert) c.Assert(changes[0].To.Name, Equals, "nameA") action, err = changes[1].Action() c.Assert(err, IsNil) c.Assert(action, Equals, merkletrie.Delete) c.Assert(changes[1].From.Name, Equals, "nameB") } func (s *ChangeAdaptorSuite) TestNewChangesFailsWithOtherNoders(c *C) { change := merkletrie.Change{ From: nil, To: newPath(noderMock{}), } src := merkletrie.Changes{change} _, err := newChanges(src) c.Assert(err, Not(IsNil)) } func (s *ChangeAdaptorSuite) TestSortChanges(c *C) { c1 := &Change{} c1.To.Name = "1" c2 := &Change{} c2.From.Name = "2" c2.To.Name = "2" c3 := &Change{} c3.From.Name = "3" changes := Changes{c3, c1, c2} sort.Sort(changes) c.Assert(changes[0].String(), Equals, "") c.Assert(changes[1].String(), Equals, "") c.Assert(changes[2].String(), Equals, "") }