mirror of
https://github.com/MontFerret/ferret.git
synced 2024-12-14 11:23:02 +02:00
129 lines
3.1 KiB
Go
129 lines
3.1 KiB
Go
|
package collections_test
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"github.com/MontFerret/ferret/pkg/runtime/collections"
|
||
|
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||
|
"github.com/MontFerret/ferret/pkg/runtime/values"
|
||
|
. "github.com/smartystreets/goconvey/convey"
|
||
|
"testing"
|
||
|
)
|
||
|
|
||
|
func tapIterator(values collections.Iterator, predicate core.Expression) collections.Iterator {
|
||
|
iter, _ := collections.NewTapIterator(values, predicate)
|
||
|
|
||
|
return iter
|
||
|
}
|
||
|
|
||
|
type TestExpression struct {
|
||
|
fn func(ctx context.Context, scope *core.Scope) (core.Value, error)
|
||
|
}
|
||
|
|
||
|
func (exp *TestExpression) Exec(ctx context.Context, scope *core.Scope) (core.Value, error) {
|
||
|
return exp.fn(ctx, scope)
|
||
|
}
|
||
|
|
||
|
type ErrorIterator struct{}
|
||
|
|
||
|
func (iterator *ErrorIterator) Next(ctx context.Context, scope *core.Scope) (*core.Scope, error) {
|
||
|
return nil, core.ErrInvalidOperation
|
||
|
}
|
||
|
|
||
|
func TestTapIterator(t *testing.T) {
|
||
|
Convey("Should iterate over a given iterator and execute a predicate", t, func() {
|
||
|
arr := values.NewArrayWith(
|
||
|
values.NewInt(1),
|
||
|
values.NewInt(2),
|
||
|
values.NewInt(3),
|
||
|
values.NewInt(4),
|
||
|
values.NewInt(5),
|
||
|
)
|
||
|
|
||
|
counter := 0
|
||
|
|
||
|
iter := tapIterator(arrayIterator(arr), &TestExpression{
|
||
|
fn: func(ctx context.Context, scope *core.Scope) (core.Value, error) {
|
||
|
counter++
|
||
|
|
||
|
return values.None, nil
|
||
|
},
|
||
|
})
|
||
|
|
||
|
ctx := context.Background()
|
||
|
scope, _ := core.NewRootScope()
|
||
|
res, err := collections.ToSlice(ctx, scope, iter)
|
||
|
|
||
|
So(err, ShouldBeNil)
|
||
|
So(res, ShouldHaveLength, int(arr.Length()))
|
||
|
So(counter, ShouldEqual, int(arr.Length()))
|
||
|
})
|
||
|
|
||
|
Convey("Should stop when a predicate return an error", t, func() {
|
||
|
arr := values.NewArrayWith(
|
||
|
values.NewInt(1),
|
||
|
values.NewInt(2),
|
||
|
values.NewInt(3),
|
||
|
values.NewInt(4),
|
||
|
values.NewInt(5),
|
||
|
)
|
||
|
|
||
|
counter := 0
|
||
|
|
||
|
iter := tapIterator(arrayIterator(arr), &TestExpression{
|
||
|
fn: func(ctx context.Context, scope *core.Scope) (core.Value, error) {
|
||
|
counter++
|
||
|
|
||
|
return values.None, core.ErrInvalidOperation
|
||
|
},
|
||
|
})
|
||
|
|
||
|
ctx := context.Background()
|
||
|
scope, _ := core.NewRootScope()
|
||
|
_, err := collections.ToSlice(ctx, scope, iter)
|
||
|
|
||
|
So(err, ShouldNotBeNil)
|
||
|
So(counter, ShouldEqual, 1)
|
||
|
})
|
||
|
|
||
|
Convey("Should not invoke a predicate when underlying iterator returns error", t, func() {
|
||
|
counter := 0
|
||
|
|
||
|
iter := tapIterator(&ErrorIterator{}, &TestExpression{
|
||
|
fn: func(ctx context.Context, scope *core.Scope) (core.Value, error) {
|
||
|
counter++
|
||
|
|
||
|
return values.None, core.ErrInvalidOperation
|
||
|
},
|
||
|
})
|
||
|
|
||
|
ctx := context.Background()
|
||
|
scope, _ := core.NewRootScope()
|
||
|
_, err := collections.ToSlice(ctx, scope, iter)
|
||
|
|
||
|
So(err, ShouldNotBeNil)
|
||
|
So(counter, ShouldEqual, 0)
|
||
|
})
|
||
|
|
||
|
Convey("Should not invoke a predicate when underlying iterator is empty", t, func() {
|
||
|
arr := values.NewArray(0)
|
||
|
|
||
|
counter := 0
|
||
|
|
||
|
iter := tapIterator(arrayIterator(arr), &TestExpression{
|
||
|
fn: func(ctx context.Context, scope *core.Scope) (core.Value, error) {
|
||
|
counter++
|
||
|
|
||
|
return values.None, core.ErrInvalidOperation
|
||
|
},
|
||
|
})
|
||
|
|
||
|
ctx := context.Background()
|
||
|
scope, _ := core.NewRootScope()
|
||
|
res, err := collections.ToSlice(ctx, scope, iter)
|
||
|
|
||
|
So(err, ShouldBeNil)
|
||
|
So(res, ShouldHaveLength, 0)
|
||
|
So(counter, ShouldEqual, 0)
|
||
|
})
|
||
|
}
|