aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/object.go68
-rw-r--r--core/object_test.go129
2 files changed, 156 insertions, 41 deletions
diff --git a/core/object.go b/core/object.go
index 5b8b16b..06137d2 100644
--- a/core/object.go
+++ b/core/object.go
@@ -140,6 +140,7 @@ func (iter *ObjectLookupIter) Next() (Object, error) {
if iter.pos >= len(iter.series) {
return nil, io.EOF
}
+
hash := iter.series[iter.pos]
obj, err := iter.storage.Get(iter.t, hash)
if err == nil {
@@ -153,24 +154,7 @@ func (iter *ObjectLookupIter) Next() (Object, error) {
// an error happends or the end of the iter is reached. If ErrStop is sent
// the iteration is stop but no error is returned. The iterator is closed.
func (iter *ObjectLookupIter) ForEach(cb func(Object) error) error {
- defer iter.Close()
-
- for _, hash := range iter.series {
- obj, err := iter.storage.Get(AnyObject, hash)
- if err != nil {
- return err
- }
-
- if err := cb(obj); err != nil {
- if err == ErrStop {
- return nil
- }
-
- return nil
- }
- }
-
- return nil
+ return ForEachIterator(iter, cb)
}
// Close releases any resources used by the iterator.
@@ -199,11 +183,13 @@ func NewObjectSliceIter(series []Object) *ObjectSliceIter {
// the end it will return io.EOF as an error. If the object is retreieved
// successfully error will be nil.
func (iter *ObjectSliceIter) Next() (Object, error) {
- if iter.pos >= len(iter.series) {
+ if len(iter.series) == 0 {
return nil, io.EOF
}
- obj := iter.series[iter.pos]
- iter.pos++
+
+ obj := iter.series[0]
+ iter.series = iter.series[1:]
+
return obj, nil
}
@@ -211,23 +197,12 @@ func (iter *ObjectSliceIter) Next() (Object, error) {
// an error happends or the end of the iter is reached. If ErrStop is sent
// the iteration is stop but no error is returned. The iterator is closed.
func (iter *ObjectSliceIter) ForEach(cb func(Object) error) error {
- defer iter.Close()
- for _, o := range iter.series {
- if err := cb(o); err != nil {
- if err == ErrStop {
- return nil
- }
-
- return err
- }
- }
-
- return nil
+ return ForEachIterator(iter, cb)
}
// Close releases any resources used by the iterator.
func (iter *ObjectSliceIter) Close() {
- iter.pos = len(iter.series)
+ iter.series = []Object{}
}
// MultiObjectIter implements ObjectIter. It iterates over several ObjectIter,
@@ -265,6 +240,24 @@ func (iter *MultiObjectIter) Next() (Object, error) {
// an error happends or the end of the iter is reached. If ErrStop is sent
// the iteration is stop but no error is returned. The iterator is closed.
func (iter *MultiObjectIter) ForEach(cb func(Object) error) error {
+ return ForEachIterator(iter, cb)
+}
+
+// Close releases any resources used by the iterator.
+func (iter *MultiObjectIter) Close() {
+ for _, i := range iter.iters {
+ i.Close()
+ }
+}
+
+type bareIterator interface {
+ Next() (Object, error)
+ Close()
+}
+
+// ForEachIterator is a helper function to build iterators without need to
+// rewrite the same ForEach function each time.
+func ForEachIterator(iter bareIterator, cb func(Object) error) error {
defer iter.Close()
for {
obj, err := iter.Next()
@@ -285,10 +278,3 @@ func (iter *MultiObjectIter) ForEach(cb func(Object) error) error {
}
}
}
-
-// Close releases any resources used by the iterator.
-func (iter *MultiObjectIter) Close() {
- for _, i := range iter.iters {
- i.Close()
- }
-}
diff --git a/core/object_test.go b/core/object_test.go
index c9f4f2c..08c5dd2 100644
--- a/core/object_test.go
+++ b/core/object_test.go
@@ -6,6 +6,45 @@ type ObjectSuite struct{}
var _ = Suite(&ObjectSuite{})
+func (s *ObjectSuite) TestObjectTypeString(c *C) {
+ c.Assert(CommitObject.String(), Equals, "commit")
+ c.Assert(TreeObject.String(), Equals, "tree")
+ c.Assert(BlobObject.String(), Equals, "blob")
+ c.Assert(TagObject.String(), Equals, "tag")
+ c.Assert(REFDeltaObject.String(), Equals, "ref-delta")
+ c.Assert(OFSDeltaObject.String(), Equals, "ofs-delta")
+ c.Assert(AnyObject.String(), Equals, "any")
+ c.Assert(ObjectType(42).String(), Equals, "unknown")
+}
+
+func (s *ObjectSuite) TestObjectTypeBytes(c *C) {
+ c.Assert(CommitObject.Bytes(), DeepEquals, []byte("commit"))
+}
+
+func (s *ObjectSuite) TestObjectTypeValid(c *C) {
+ c.Assert(CommitObject.Valid(), Equals, true)
+ c.Assert(ObjectType(42).Valid(), Equals, false)
+}
+
+func (s *ObjectSuite) TestParseObjectType(c *C) {
+ for s, e := range map[string]ObjectType{
+ "commit": CommitObject,
+ "tree": TreeObject,
+ "blob": BlobObject,
+ "tag": TagObject,
+ "ref-delta": REFDeltaObject,
+ "ofs-delta": OFSDeltaObject,
+ } {
+ t, err := ParseObjectType(s)
+ c.Assert(err, IsNil)
+ c.Assert(e, Equals, t)
+ }
+
+ t, err := ParseObjectType("foo")
+ c.Assert(err, Equals, ErrInvalidType)
+ c.Assert(t, Equals, InvalidObject)
+}
+
func (s *ObjectSuite) TestMultiObjectIterNext(c *C) {
expected := []Object{
&MemoryObject{},
@@ -28,4 +67,94 @@ func (s *ObjectSuite) TestMultiObjectIterNext(c *C) {
i++
return nil
})
+
+ iter.Close()
+}
+
+func (s *ObjectSuite) TestObjectLookupIter(c *C) {
+ h := []Hash{
+ NewHash("0920f02906615b285040767a67c5cb30fe0f5e2c"),
+ NewHash("4921e391f1128010a2d957f8db15c5e729ccf94a"),
+ }
+
+ var count int
+
+ i := NewObjectLookupIter(&MockObjectStorage{}, CommitObject, h)
+ err := i.ForEach(func(o Object) error {
+ c.Assert(o, NotNil)
+ c.Assert(o.Hash().String(), Equals, h[count].String())
+ count++
+ return nil
+ })
+
+ c.Assert(err, IsNil)
+ i.Close()
+}
+
+func (s *ObjectSuite) TestObjectSliceIter(c *C) {
+ h := []Hash{
+ NewHash("0920f02906615b285040767a67c5cb30fe0f5e2c"),
+ NewHash("4921e391f1128010a2d957f8db15c5e729ccf94a"),
+ }
+
+ var count int
+
+ i := NewObjectSliceIter([]Object{
+ &MemoryObject{h: h[0]}, &MemoryObject{h: h[1]},
+ })
+
+ err := i.ForEach(func(o Object) error {
+ c.Assert(o, NotNil)
+ c.Assert(o.Hash().String(), Equals, h[count].String())
+ count++
+ return nil
+ })
+
+ c.Assert(count, Equals, 2)
+ c.Assert(err, IsNil)
+ c.Assert(i.series, HasLen, 0)
+}
+
+func (s *ObjectSuite) TestObjectSliceIterStop(c *C) {
+ h := []Hash{
+ NewHash("0920f02906615b285040767a67c5cb30fe0f5e2c"),
+ NewHash("4921e391f1128010a2d957f8db15c5e729ccf94a"),
+ }
+
+ i := NewObjectSliceIter([]Object{
+ &MemoryObject{h: h[0]}, &MemoryObject{h: h[1]},
+ })
+
+ var count = 0
+ err := i.ForEach(func(o Object) error {
+ c.Assert(o, NotNil)
+ c.Assert(o.Hash().String(), Equals, h[count].String())
+ count++
+ return ErrStop
+ })
+
+ c.Assert(count, Equals, 1)
+ c.Assert(err, IsNil)
+}
+
+type MockObjectStorage struct{}
+
+func (o *MockObjectStorage) NewObject() Object {
+ return nil
+}
+
+func (o *MockObjectStorage) Set(obj Object) (Hash, error) {
+ return ZeroHash, nil
+}
+
+func (o *MockObjectStorage) Get(t ObjectType, h Hash) (Object, error) {
+ return &MemoryObject{h: h}, nil
+}
+
+func (o *MockObjectStorage) Iter(t ObjectType) (ObjectIter, error) {
+ return nil, nil
+}
+
+func (o *MockObjectStorage) Begin() TxObjectStorage {
+ return nil
}