github.com/MontFerret/ferret@v0.18.0/pkg/runtime/collections/tap_test.go (about)

     1  package collections_test
     2  
     3  import (
     4  	"context"
     5  	"testing"
     6  
     7  	. "github.com/smartystreets/goconvey/convey"
     8  
     9  	"github.com/MontFerret/ferret/pkg/runtime/collections"
    10  	"github.com/MontFerret/ferret/pkg/runtime/core"
    11  	"github.com/MontFerret/ferret/pkg/runtime/values"
    12  )
    13  
    14  func tapIterator(values collections.Iterator, predicate core.Expression) collections.Iterator {
    15  	iter, _ := collections.NewTapIterator(values, predicate)
    16  
    17  	return iter
    18  }
    19  
    20  type TestExpression struct {
    21  	fn func(ctx context.Context, scope *core.Scope) (core.Value, error)
    22  }
    23  
    24  func (exp *TestExpression) Exec(ctx context.Context, scope *core.Scope) (core.Value, error) {
    25  	return exp.fn(ctx, scope)
    26  }
    27  
    28  type ErrorIterator struct{}
    29  
    30  func (iterator *ErrorIterator) Next(ctx context.Context, scope *core.Scope) (*core.Scope, error) {
    31  	return nil, core.ErrInvalidOperation
    32  }
    33  
    34  func TestTapIterator(t *testing.T) {
    35  	Convey("Should iterate over a given iterator and execute a predicate", t, func() {
    36  		arr := values.NewArrayWith(
    37  			values.NewInt(1),
    38  			values.NewInt(2),
    39  			values.NewInt(3),
    40  			values.NewInt(4),
    41  			values.NewInt(5),
    42  		)
    43  
    44  		counter := 0
    45  
    46  		iter := tapIterator(arrayIterator(arr), &TestExpression{
    47  			fn: func(ctx context.Context, scope *core.Scope) (core.Value, error) {
    48  				counter++
    49  
    50  				return values.None, nil
    51  			},
    52  		})
    53  
    54  		ctx := context.Background()
    55  		scope, _ := core.NewRootScope()
    56  		res, err := collections.ToSlice(ctx, scope, iter)
    57  
    58  		So(err, ShouldBeNil)
    59  		So(res, ShouldHaveLength, int(arr.Length()))
    60  		So(counter, ShouldEqual, int(arr.Length()))
    61  	})
    62  
    63  	Convey("Should stop when a predicate return an error", t, func() {
    64  		arr := values.NewArrayWith(
    65  			values.NewInt(1),
    66  			values.NewInt(2),
    67  			values.NewInt(3),
    68  			values.NewInt(4),
    69  			values.NewInt(5),
    70  		)
    71  
    72  		counter := 0
    73  
    74  		iter := tapIterator(arrayIterator(arr), &TestExpression{
    75  			fn: func(ctx context.Context, scope *core.Scope) (core.Value, error) {
    76  				counter++
    77  
    78  				return values.None, core.ErrInvalidOperation
    79  			},
    80  		})
    81  
    82  		ctx := context.Background()
    83  		scope, _ := core.NewRootScope()
    84  		_, err := collections.ToSlice(ctx, scope, iter)
    85  
    86  		So(err, ShouldNotBeNil)
    87  		So(counter, ShouldEqual, 1)
    88  	})
    89  
    90  	Convey("Should not invoke a predicate when underlying iterator returns error", t, func() {
    91  		counter := 0
    92  
    93  		iter := tapIterator(&ErrorIterator{}, &TestExpression{
    94  			fn: func(ctx context.Context, scope *core.Scope) (core.Value, error) {
    95  				counter++
    96  
    97  				return values.None, core.ErrInvalidOperation
    98  			},
    99  		})
   100  
   101  		ctx := context.Background()
   102  		scope, _ := core.NewRootScope()
   103  		_, err := collections.ToSlice(ctx, scope, iter)
   104  
   105  		So(err, ShouldNotBeNil)
   106  		So(counter, ShouldEqual, 0)
   107  	})
   108  
   109  	Convey("Should not invoke a predicate when underlying iterator is empty", t, func() {
   110  		arr := values.NewArray(0)
   111  
   112  		counter := 0
   113  
   114  		iter := tapIterator(arrayIterator(arr), &TestExpression{
   115  			fn: func(ctx context.Context, scope *core.Scope) (core.Value, error) {
   116  				counter++
   117  
   118  				return values.None, core.ErrInvalidOperation
   119  			},
   120  		})
   121  
   122  		ctx := context.Background()
   123  		scope, _ := core.NewRootScope()
   124  		res, err := collections.ToSlice(ctx, scope, iter)
   125  
   126  		So(err, ShouldBeNil)
   127  		So(res, ShouldHaveLength, 0)
   128  		So(counter, ShouldEqual, 0)
   129  	})
   130  }