| Index: go/src/infra/libs/git/tree_test.go
|
| diff --git a/go/src/infra/libs/git/tree_test.go b/go/src/infra/libs/git/tree_test.go
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..a05091f9421168366615f9ed5eac6ddb679be8ba
|
| --- /dev/null
|
| +++ b/go/src/infra/libs/git/tree_test.go
|
| @@ -0,0 +1,558 @@
|
| +// Copyright 2014 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +package git
|
| +
|
| +import (
|
| + "fmt"
|
| + "strings"
|
| + "testing"
|
| +
|
| + . "github.com/smartystreets/goconvey/convey"
|
| +
|
| + "infra/libs/infra_util"
|
| +)
|
| +
|
| +type FakeGitEntry struct {
|
| + data string
|
| + typ ObjectType
|
| + size int
|
| +}
|
| +
|
| +type FakeGitService map[ObjectID]FakeGitEntry
|
| +
|
| +func (f FakeGitService) GetObjectID(id Identifiable) (InternableObject, error) {
|
| + if id.ID().RawString() == "TestsFailureObjectID" {
|
| + return &Blob{}, fmt.Errorf("Cannot get TestsFailureObjectID")
|
| + }
|
| + obj, ok := f[*id.ID()]
|
| + if !ok {
|
| + return nil, nil
|
| + }
|
| + return ObjectFromRawWithID(id, obj.typ, []byte(obj.data))
|
| +}
|
| +
|
| +func (f FakeGitService) HasObjectID(id Identifiable) bool {
|
| + o, _ := f.GetObjectID(id)
|
| + return o != nil
|
| +}
|
| +
|
| +func (f FakeGitService) ObjectInfo(objectish string) *ObjectInfo {
|
| + // technically this needs to implement all of rev-parse, but we'll just
|
| + // cheat for the bits we need right now (e.g. <hash>:)
|
| + id, err := MakeObjectIDErr(objectish[:len(objectish)-1])
|
| + if err != nil {
|
| + Println("FakeGitService cannot process", objectish)
|
| + return nil
|
| + }
|
| + if objectish[len(objectish)-1] == ':' {
|
| + o, err := f.GetObjectID(id)
|
| + if err != nil {
|
| + return nil
|
| + }
|
| + if commit, ok := o.(*Commit); !ok {
|
| + Println("Has is not a commit", objectish)
|
| + return nil
|
| + } else {
|
| + return f.ObjectInfoID(commit.Tree())
|
| + }
|
| + } else {
|
| + Println("FakeGitService cannot process", objectish)
|
| + return nil
|
| + }
|
| +}
|
| +
|
| +func (f FakeGitService) ObjectInfoID(id Identifiable) *ObjectInfo {
|
| + obj, ok := f[*id.ID()]
|
| + if !ok {
|
| + return nil
|
| + }
|
| + return &ObjectInfo{obj.typ, obj.size, id.ID()}
|
| +}
|
| +
|
| +func (f FakeGitService) Intern(o InternableObject) (*ObjectID, error) {
|
| + return InternImpl(f, o, func(data string) (string, error) {
|
| + f[*o.ID()] = FakeGitEntry{data, o.Type(), len(data)}
|
| + return o.ID().String(), nil
|
| + })
|
| +}
|
| +
|
| +func TestTree(t *testing.T) {
|
| + t.Parallel()
|
| +
|
| + Convey("Tree", t, func() {
|
| +
|
| + Convey("Constructors", func() {
|
| +
|
| + Convey("Text", func() {
|
| +
|
| + Convey("Should parse", func() {
|
| + txt := strings.Join([]string{
|
| + "100644 blob 302296b172eb2152d249734ed93690c7213f0ea0\t.gitignore",
|
| + "100644 blob d0225511d9de0193a95f81900c70cbc50b759818\t.gitmodules",
|
| + "100644 blob dcd5f302bb21c46488d813a57a543f6afa94b8b4\t.netrwhist",
|
| + "040000 tree c7dcb4bbcdaf65ea75ea7735c7694d412f66ddb6\tAudio",
|
| + "160000 commit 3bb7c33fbb5721e2be5ff963f8f3ba78e4878983\tLS_COLORS",
|
| + "100644 blob 1402d9c72db11e48bb15a5c4163e5fbbbd1a6218\tREADME.md",
|
| + "040000 tree 3bfce6fec987eb7a42434e15a7033c7818c684fe\tUltiSnips",
|
| + }, "\n")
|
| +
|
| + tree, err := NewTreeFromText([]byte(txt))
|
| + So(err, ShouldBeNil)
|
| + So(tree.Type(), ShouldEqual, TreeType)
|
| + So(tree.NumChildren(), ShouldEqual, 7)
|
| +
|
| + So(tree.Complete(), ShouldBeTrue)
|
| + So(tree.ID().String(), ShouldEqual, "27932b52d6c0f6381fbfe8505d08ee45c33b7b88")
|
| + })
|
| +
|
| + Convey("Should parse with quoted paths", func() {
|
| + txt := "100644 blob 302296b172eb2152d249734ed93690c7213f0ea0\t\"foo\\nbar\"\n"
|
| +
|
| + tree, err := NewTreeFromText([]byte(txt))
|
| + So(err, ShouldBeNil)
|
| + So(tree.NumChildren(), ShouldEqual, 1)
|
| +
|
| + c := tree.GetChild("foo\nbar")
|
| + So(c, ShouldNotBeNil)
|
| + So(c.Object.Type(), ShouldEqual, BlobType)
|
| + })
|
| +
|
| + Convey("Should reject bad text", func() {
|
| + bads := []string{
|
| + "",
|
| + "100644 blob nubsauce\t\"wat\"\n",
|
| + "hi blob 302296b172eb2152d249734ed93690c7213f0ea0\t\"wat\"\n",
|
| + "100644 blob 302296b172eb2152d249734ed93690c7213f0ea0\t\"wat\n",
|
| + "100644 blob 302296b172eb2152d249734ed93690c7213f0ea0 bob\n",
|
| + "blob 302296b172eb2152d249734ed93690c7213f0ea0\tbob\n",
|
| + "100644 302296b172eb2152d249734ed93690c7213f0ea0\tbob\n",
|
| + "0 blob 302296b172eb2152d249734ed93690c7213f0ea0\tbob\n",
|
| + "100644 blob 302296b172eb2152d249734ed93690c7213f0ea0\t\n",
|
| + }
|
| + for _, txt := range bads {
|
| + txt := txt
|
| + Convey(fmt.Sprintf("%#v", txt), func() {
|
| + _, err := NewTreeFromText([]byte(txt))
|
| + So(err, ShouldNotBeNil)
|
| + })
|
| + }
|
| + })
|
| +
|
| + Convey("Should reject nil", func() {
|
| + _, err := NewTreeFromText(nil)
|
| + So(err, ShouldNotBeNil)
|
| + })
|
| + })
|
| +
|
| + Convey("Binary", func() {
|
| +
|
| + Convey("Should parse", func() {
|
| + bin := strings.Join([]string{
|
| + "100644 .gitignore\x000\"\x96\xb1r\xeb!R\xd2IsN\xd96\x90\xc7!?\x0e\xa0",
|
| + "100644 .gitmodules\x00\xd0\"U\x11\xd9\xde\x01\x93\xa9_\x81\x90\x0cp\xcb\xc5\x0bu\x98\x18",
|
| + "100644 .netrwhist\x00\xa3\xea\xdd\x97*\x16\x08\x88\x11\x17\xee7I\x8a\t\xb1\xbd\x82et",
|
| + "40000 Audio\x00\xc7\xdc\xb4\xbb\xcd\xafe\xeau\xeaw5\xc7iMA/f\xdd\xb6",
|
| + "160000 LS_COLORS\x00;\xb7\xc3?\xbbW!\xe2\xbe_\xf9c\xf8\xf3\xbax\xe4\x87\x89\x83",
|
| + "100644 README.md\x00\x14\x02\xd9\xc7-\xb1\x1eH\xbb\x15\xa5\xc4\x16>_\xbb\xbd\x1ab\x18",
|
| + "40000 UltiSnips\x00;\xfc\xe6\xfe\xc9\x87\xebzBCN\x15\xa7\x03<x\x18\xc6\x84\xfe",
|
| + }, "")
|
| +
|
| + tree, err := NewTreeFromRaw([]byte(bin))
|
| + So(err, ShouldBeNil)
|
| + So(tree.NumChildren(), ShouldEqual, 7)
|
| + So(tree.ID().String(), ShouldEqual, "c86f07a67fcfadb63a9686a4bb1851cc4b01d7bc")
|
| +
|
| + Convey("Round-trip", func() {
|
| + So(tree.RawString(), ShouldEqual, bin)
|
| + })
|
| + })
|
| +
|
| + Convey("Empty should parse", func() {
|
| + tree, err := NewTreeFromRaw(nil)
|
| + So(err, ShouldBeNil)
|
| + So(tree.NumChildren(), ShouldEqual, 0)
|
| + So(tree.ID().String(), ShouldEqual, EmptyTreeHash)
|
| +
|
| + Convey("Round-trip", func() {
|
| + So(tree.RawString(), ShouldEqual, "")
|
| + })
|
| +
|
| + Convey("Matches NewEmptyTree", func() {
|
| + empty := NewEmptyTree(&NoID, 0)
|
| + empty.RawString() // re-calculate the empty hash
|
| + So(empty.ID(), ShouldResemble, tree.ID())
|
| + })
|
| + })
|
| +
|
| + Convey("Should reject bad binaries", func() {
|
| + bads := []string{
|
| + "hi .gitignore\x000\"\x96\xb1r\xeb!R\xd2IsN\xd96\x90\xc7!?\x0e\xa0",
|
| + "0 .gitignore\x000\"\x96\xb1r\xeb!R\xd2IsN\xd96\x90\xc7!?\x0e\xa0",
|
| + "100644\x000\"\x96\xb1r\xeb!R\xd2IsN\xd96\x90\xc7!?\x0e\xa0",
|
| + "100644 bob\x000\"\x96\xb1\xeb!R\xd2IsN\xd96\x90\xc7!?\x0e\xa0",
|
| + }
|
| + for _, bin := range bads {
|
| + bin := bin
|
| + Convey(fmt.Sprintf("%#v", bin), func() {
|
| + _, err := NewTreeFromRaw([]byte(bin))
|
| + So(err, ShouldNotBeNil)
|
| + })
|
| + }
|
| + })
|
| + })
|
| + })
|
| +
|
| + Convey("TreeManipulation", func() {
|
| + tree := NewEmptyTree(&NoID, 0)
|
| +
|
| + Convey("GetChild", func() {
|
| + names := []string{
|
| + "",
|
| + "bob",
|
| + "bob\nnewline",
|
| + "bob/subitem",
|
| + }
|
| + for _, name := range names {
|
| + name := name
|
| + Convey(fmt.Sprintf("Returns nil with no children: %#v", name), func() {
|
| + So(tree.GetChild(name), ShouldBeNil)
|
| + })
|
| + }
|
| + })
|
| +
|
| + Convey("SetChild", func() {
|
| + Convey("cannot set a child on the empty path", func() {
|
| + So(func() { tree.SetChild("", BlankTreeChild(0)) }, ShouldPanic)
|
| + })
|
| +
|
| + Convey("can create intermediate trees for a child", func() {
|
| + c, err := NewEmptyChild(0100644, &NoID)
|
| + So(err, ShouldBeNil)
|
| + So(c.Object.Type(), ShouldEqual, BlobType)
|
| + tree.SetChild("rootblob", c)
|
| + tree.SetChild("bob/blob", c)
|
| +
|
| + c, err = NewEmptyChild(040000, MakeObjectID(EmptyTreeHash))
|
| + So(err, ShouldBeNil)
|
| + tree.SetChild("bob/blank_subtree", c)
|
| +
|
| + c, err = NewEmptyChild(040000, MakeObjectID("deadbeefdeadbeefdeadbeefdeadbeefdeadbeef"))
|
| + So(err, ShouldBeNil)
|
| + tree.SetChild("bob/nonblank_subtree", c)
|
| +
|
| + Convey("the tree was set up correctly", func() {
|
| + So(tree.NumChildren(), ShouldEqual, 2)
|
| + for k := range tree.children {
|
| + So(k, ShouldBeIn, []string{"bob", "rootblob"})
|
| + }
|
| +
|
| + So(tree.GetChild("bob").Object.(*Tree).NumChildren(), ShouldEqual, 3)
|
| + for k := range tree.GetChild("bob").Object.(*Tree).children {
|
| + So(k, ShouldBeIn, []string{"blank_subtree", "blob", "nonblank_subtree"})
|
| + }
|
| + })
|
| +
|
| + Convey("but will panic if you try to create a child of a non-tree", func() {
|
| + So(func() { tree.SetChild("bob/blob/fail", BlankTreeChild(0)) }, ShouldPanic)
|
| + })
|
| +
|
| + Convey("getting the child of a non-tree is also a panic", func() {
|
| + So(func() { tree.GetChild("bob/blob/fail") }, ShouldPanic)
|
| + })
|
| +
|
| + Convey("setting a child of a placeholder tree will panic", func() {
|
| + So(func() { tree.SetChild("bob/nonblank_subtree/happy_days", BlankTreeChild(0)) }, ShouldPanic)
|
| + })
|
| +
|
| + Convey("however, setting a child of an empty placeholder tree will cause it to exist", func() {
|
| + c, err := NewEmptyChild(0100644, &NoID)
|
| + So(err, ShouldBeNil)
|
| + tree.SetChild("bob/blank_subtree/happy_days", c)
|
| + So(tree.GetChild("bob/blank_subtree").Object, ShouldHaveSameTypeAs, tree)
|
| + })
|
| +
|
| + Convey("DelChild", func() {
|
| + Convey("returns when you delete something that's not there", func() {
|
| + So(tree.DelChild("nerd"), ShouldBeFalse)
|
| + So(tree.DelChild("whatnow/sup"), ShouldBeFalse)
|
| + So(tree.DelChild("bob/nothere"), ShouldBeFalse)
|
| + })
|
| +
|
| + Convey("but will panic if you try to delete a subordinate of a blob", func() {
|
| + So(func() { tree.DelChild("rootblob/boom") }, ShouldPanic)
|
| + })
|
| +
|
| + Convey("It will also clean out directories when they are empty", func() {
|
| + So(tree.DelChild("bob/blank_subtree"), ShouldBeTrue)
|
| + So(tree.DelChild("bob/nonblank_subtree"), ShouldBeTrue)
|
| + So(tree.DelChild("bob/blob"), ShouldBeTrue)
|
| + So(tree.NumChildren(), ShouldEqual, 1)
|
| + for k := range tree.children {
|
| + So(k, ShouldBeIn, []string{"rootblob"})
|
| + }
|
| + })
|
| +
|
| + Convey("It can also remove directories with content", func() {
|
| + So(tree.DelChild("bob"), ShouldBeTrue)
|
| + So(tree.NumChildren(), ShouldEqual, 1)
|
| + for k := range tree.children {
|
| + So(k, ShouldBeIn, []string{"rootblob"})
|
| + }
|
| + })
|
| + })
|
| + })
|
| +
|
| + Convey("Intern(FakeGitService)", func() {
|
| + s := make(FakeGitService)
|
| +
|
| + Convey("In an empty tree", func() {
|
| + Convey("allowMissing should succeed", func() {
|
| + id, err := tree.Intern(s, true)
|
| + So(err, ShouldBeNil)
|
| + So(id.String(), ShouldEqual, EmptyTreeHash)
|
| + })
|
| +
|
| + Convey("!allowMissing should succeed", func() {
|
| + id, err := tree.Intern(s, true)
|
| + So(err, ShouldBeNil)
|
| + So(id.String(), ShouldEqual, EmptyTreeHash)
|
| + })
|
| + })
|
| +
|
| + Convey("In a tree with an EmptyObject", func() {
|
| + c, err := NewEmptyChild(0100644, MakeObjectIDForData(BlobType, []byte("sup")))
|
| + So(err, ShouldBeNil)
|
| + tree.SetChild("nest/blob", c)
|
| +
|
| + Convey("allowMissing should succeed", func() {
|
| + id, err := tree.Intern(s, true)
|
| + So(err, ShouldBeNil)
|
| + So(id.String(), ShouldEqual, "730bdd0d9d5cb610df9b00df7a622cee291a5453")
|
| + So(len(s), ShouldEqual, 2)
|
| + })
|
| +
|
| + Convey("!allowMissing should fail", func() {
|
| + _, err := tree.Intern(s, false)
|
| + So(err, ShouldNotBeNil)
|
| + expect := infra_util.StringSetFrom(
|
| + "ME[\"missing non-internable object: EmptyObject(0b90e2b8567ab715f87fb49c6a0a08ce6f2eb312, blob)\"]")
|
| + So(err.(*infra_util.MultiError).ErrorStrings(), ShouldResemble, expect)
|
| + So(s, ShouldBeEmpty)
|
| + })
|
| + })
|
| +
|
| + Convey("In a tree with a nested Blob", func() {
|
| + tree.SetChild("nest/blob", &Child{NewBlobFromRaw([]byte("sup")), Mode(0100644)})
|
| +
|
| + Convey("allowMissing should succeed", func() {
|
| + id, err := tree.Intern(s, true)
|
| + So(err, ShouldBeNil)
|
| + So(id.String(), ShouldEqual, "730bdd0d9d5cb610df9b00df7a622cee291a5453")
|
| + So(len(s), ShouldEqual, 3)
|
| + })
|
| +
|
| + Convey("!allowMissing should succeed", func() {
|
| + id, err := tree.Intern(s, false)
|
| + So(err, ShouldBeNil)
|
| + So(id.String(), ShouldEqual, "730bdd0d9d5cb610df9b00df7a622cee291a5453")
|
| + So(len(s), ShouldEqual, 3)
|
| + })
|
| + })
|
| +
|
| + Convey("In a tree with a NoID EmptyObject", func() {
|
| + c, err := NewEmptyChild(0100644, &NoID)
|
| + So(err, ShouldBeNil)
|
| + tree.SetChild("nest/blob", c)
|
| +
|
| + Convey("allowMissing should fail", func() {
|
| + _, err := tree.Intern(s, true)
|
| + So(err, ShouldNotBeNil)
|
| + expect := infra_util.StringSetFrom(
|
| + "ME[\"object has an ID of <NoID>\"]")
|
| + So(err.(*infra_util.MultiError).ErrorStrings(), ShouldResemble, expect)
|
| + So(s, ShouldBeEmpty)
|
| + })
|
| +
|
| + Convey("!allowMissing should fail", func() {
|
| + _, err := tree.Intern(s, false)
|
| + So(err, ShouldNotBeNil)
|
| + expect := infra_util.StringSetFrom(
|
| + "ME[\"missing non-internable object: EmptyObject(<NoID>, blob)\"]")
|
| + So(err.(*infra_util.MultiError).ErrorStrings(), ShouldResemble, expect)
|
| + So(s, ShouldBeEmpty)
|
| + })
|
| + })
|
| +
|
| + Convey("In a tree with an empty (but ID'd) subtree", func() {
|
| + sub_id := "a7d0c997159313b124cf5daec4715ba59c5993d3"
|
| + c, err := NewEmptyChild(040000, MakeObjectID(sub_id))
|
| + So(err, ShouldBeNil)
|
| + tree.SetChild("nest", c)
|
| +
|
| + Convey("allowMissing should succeed", func() {
|
| + _, err := tree.Intern(s, true)
|
| + So(err, ShouldBeNil)
|
| + So(len(s), ShouldEqual, 1)
|
| +
|
| + Convey("and the subtree should retain its ID", func() {
|
| + So(tree.GetChild("nest").Object.ID().String(), ShouldEqual, sub_id)
|
| + })
|
| + })
|
| +
|
| + Convey("!allowMissing should fail", func() {
|
| + _, err := tree.Intern(s, false)
|
| + expect := infra_util.StringSetFrom(fmt.Sprintf(
|
| + "missing non-internable object: EmptyObject(%s, tree)", sub_id))
|
| + So(err, ShouldNotBeNil)
|
| + So(err.(*infra_util.MultiError).ErrorStrings(), ShouldResemble, expect)
|
| + So(s, ShouldBeEmpty)
|
| + })
|
| + })
|
| + })
|
| + })
|
| + })
|
| +
|
| + Convey("LoadFullTree", func() {
|
| + s := make(FakeGitService)
|
| +
|
| + LT := func(id Identifiable, withBlobs, missingErr bool) (*Tree, error) {
|
| + o, err := LoadFullTree(s, id, withBlobs, missingErr)
|
| + if err != nil {
|
| + return nil, err
|
| + }
|
| + return o.(*Tree), nil
|
| + }
|
| +
|
| + Convey("with a fully-populated tree", func() {
|
| + thash := "9fe3bef872f85138118766d83ce0d528fdb522ad"
|
| + tree := NewEmptyTree(&NoID, 3)
|
| + tree.SetChild("sub/blob", &Child{NewBlobFromRaw([]byte("hi")), 0100755})
|
| + tree.SetChild("sub/happy", &Child{NewBlobFromRaw([]byte("happy")), 0100755})
|
| + tree.SetChild("maybeMissing/blob", &Child{NewBlobFromRaw([]byte("sup")), 0100644})
|
| + tree.SetChild("nerd", &Child{NewBlobFromRaw([]byte("hi")), 0100644})
|
| + id, err := tree.Intern(s, false)
|
| + So(err, ShouldBeNil)
|
| + So(id.String(), ShouldEqual, thash)
|
| +
|
| + Convey("Aborts nicely if GetObjectID fails", func() {
|
| + failID := &ObjectID{}
|
| + copy(failID.raw[:], "TestsFailureObjectID")
|
| + c, err := NewEmptyChild(040000, failID)
|
| + So(err, ShouldBeNil)
|
| + tree.SetChild("fail/failington", c)
|
| + id, err := tree.Intern(s, false)
|
| + So(err, ShouldBeNil)
|
| + wat, err := LT(id, true, true)
|
| + Print(wat)
|
| + So(err, ShouldNotBeNil)
|
| + })
|
| +
|
| + Convey("from a missing tree is an error", func() {
|
| + _, err := LT(MakeObjectIDForData(TreeType, []byte("bob")), true, true)
|
| + So(err, ShouldNotBeNil)
|
| + })
|
| +
|
| + Convey("from a blob is an error", func() {
|
| + bID, err := s.Intern(NewBlobFromRaw([]byte("sup")))
|
| + So(err, ShouldBeNil)
|
| + _, err = LT(bID, true, true)
|
| + So(err, ShouldNotBeNil)
|
| + })
|
| +
|
| + Convey("from a commit which points to a missing tree is an error", func() {
|
| + c, err := NewCommitFromRaw([]byte(fmt.Sprintf(`tree %s
|
| +author Jane Janerton <bob@chromium.org> 123456789 +0000
|
| +committer Bob Boberton <bob@chromium.org> 123456789 +0000
|
| +
|
| +Super cool tree commit`, MakeObjectIDForData(TreeType, []byte("bob")))))
|
| + So(err, ShouldBeNil)
|
| + s.Intern(c)
|
| + _, err = LT(c.ID(), true, true)
|
| + So(err, ShouldNotBeNil)
|
| + })
|
| +
|
| + Convey("noBlobs", func() {
|
| + Convey("missingErr (success)", func() {
|
| + loaded, err := LT(id, false, true)
|
| + So(err, ShouldBeNil)
|
| + Println(loaded.GetChild("nerd"))
|
| + So(loaded.children, ShouldNotResemble, tree.children)
|
| + for k := range loaded.children {
|
| + So(k, ShouldBeIn, []string{"sub", "maybeMissing", "nerd"})
|
| + }
|
| + So(loaded.GetChild("sub").Object.ID(), ShouldResemble,
|
| + tree.GetChild("sub").Object.ID())
|
| + So(loaded.GetChild("sub/blob").Object.ID(), ShouldResemble,
|
| + tree.GetChild("sub/blob").Object.ID())
|
| + So(loaded.GetChild("sub/blob").Object, ShouldHaveSameTypeAs,
|
| + (*EmptyObject)(nil))
|
| + })
|
| +
|
| + Convey("removing a tree (maybeMissing)", func() {
|
| + mObjID := tree.GetChild("maybeMissing").Object.ID()
|
| + delete(s, *mObjID)
|
| +
|
| + Convey("missingErr", func() {
|
| + _, err := LT(id, false, true)
|
| + So(err, ShouldNotBeNil)
|
| + })
|
| +
|
| + Convey("allowMissing", func() {
|
| + loaded, err := LT(id, false, false)
|
| + So(err, ShouldBeNil)
|
| +
|
| + Println(loaded.GetChild("maybeMissing"))
|
| + So(loaded.GetChild("maybeMissing").Object, ShouldHaveSameTypeAs, &EmptyObject{})
|
| + So(loaded.GetChild("maybeMissing").Object.ID(), ShouldResemble, mObjID)
|
| + })
|
| + })
|
| + })
|
| +
|
| + Convey("withBlobs", func() {
|
| + Convey("missingErr (succeeds)", func() {
|
| + loaded, err := LT(id, true, true)
|
| + So(err, ShouldBeNil)
|
| + loaded.RawString()
|
| + So(loaded.Complete(), ShouldBeTrue)
|
| + So(loaded, ShouldResemble, tree)
|
| +
|
| + Convey("also works from a commit object", func() {
|
| + c, err := NewCommitFromRaw([]byte(fmt.Sprintf(`tree %s
|
| +author Jane Janerton <bob@chromium.org> 123456789 +0000
|
| +committer Bob Boberton <bob@chromium.org> 123456789 +0000
|
| +
|
| +Super cool tree commit`, tree.ID())))
|
| + So(err, ShouldBeNil)
|
| + s.Intern(c)
|
| + cloaded, err := LT(c.ID(), true, true)
|
| + So(cloaded.Complete(), ShouldBeTrue)
|
| + So(cloaded, ShouldResemble, loaded)
|
| +
|
| + })
|
| +
|
| + Convey("removing a blob (maybeMissing/blob)", func() {
|
| + mObjID := tree.GetChild("maybeMissing/blob").Object.ID()
|
| + delete(s, *mObjID)
|
| + So(s.HasObjectID(mObjID), ShouldBeFalse)
|
| +
|
| + Convey("missingErr", func() {
|
| + _, err := LT(id, true, true)
|
| + So(err, ShouldNotBeNil)
|
| + })
|
| +
|
| + Convey("allowMissing", func() {
|
| + loaded, err := LT(id, true, false)
|
| + So(err, ShouldBeNil)
|
| + So(loaded.GetChild("maybeMissing/blob").Object, ShouldHaveSameTypeAs, &EmptyObject{})
|
| + So(loaded.GetChild("maybeMissing/blob").Object.ID(), ShouldResemble, mObjID)
|
| + })
|
| +
|
| + })
|
| + })
|
| + })
|
| + })
|
| + })
|
| + })
|
| +}
|
|
|