github.com/MontFerret/ferret@v0.18.0/pkg/runtime/expressions/for_in_test.go (about)

     1  package expressions_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/expressions"
    12  	"github.com/MontFerret/ferret/pkg/runtime/values"
    13  )
    14  
    15  var testIterableCollectionType = core.NewType("TestIterableCollection")
    16  
    17  type (
    18  	testIterableCollection struct {
    19  		values collections.IndexedCollection
    20  	}
    21  
    22  	testCollectionIterator struct {
    23  		values   collections.IndexedCollection
    24  		position values.Int
    25  	}
    26  
    27  	TestDataSourceExpression func(ctx context.Context, scope *core.Scope) (core.Value, error)
    28  )
    29  
    30  func (ds TestDataSourceExpression) Exec(ctx context.Context, scope *core.Scope) (core.Value, error) {
    31  	return ds(ctx, scope)
    32  }
    33  
    34  func (c *testIterableCollection) MarshalJSON() ([]byte, error) {
    35  	return nil, core.ErrInvalidOperation
    36  }
    37  func (c *testIterableCollection) Type() core.Type {
    38  	return testIterableCollectionType
    39  }
    40  func (c *testIterableCollection) String() string {
    41  	return ""
    42  }
    43  func (c *testIterableCollection) Compare(other core.Value) int64 {
    44  	return 1
    45  }
    46  func (c *testIterableCollection) Unwrap() interface{} {
    47  	return nil
    48  }
    49  func (c *testIterableCollection) Hash() uint64 {
    50  	return 0
    51  }
    52  func (c *testIterableCollection) Copy() core.Value {
    53  	return c
    54  }
    55  func (c *testIterableCollection) Iterate(ctx context.Context) (core.Iterator, error) {
    56  	return &testCollectionIterator{c.values, -1}, nil
    57  }
    58  
    59  func (i *testCollectionIterator) Next(ctx context.Context) (core.Value, core.Value, error) {
    60  	i.position++
    61  
    62  	if i.position > i.values.Length() {
    63  		return values.None, values.None, core.ErrNoMoreData
    64  	}
    65  
    66  	return i.values.Get(i.position), i.position, nil
    67  }
    68  
    69  func TestDataSource(t *testing.T) {
    70  	Convey(".Iterate", t, func() {
    71  		Convey("Should return custom iterable collection", func() {
    72  			arr := values.NewArrayWith(
    73  				values.NewInt(1),
    74  				values.NewInt(2),
    75  				values.NewInt(3),
    76  				values.NewInt(4),
    77  				values.NewInt(5),
    78  				values.NewInt(6),
    79  				values.NewInt(7),
    80  				values.NewInt(8),
    81  				values.NewInt(9),
    82  				values.NewInt(10),
    83  			)
    84  
    85  			ds, err := expressions.NewForInIterableExpression(
    86  				core.SourceMap{},
    87  				collections.DefaultValueVar,
    88  				collections.DefaultKeyVar,
    89  				TestDataSourceExpression(func(ctx context.Context, scope *core.Scope) (core.Value, error) {
    90  					return &testIterableCollection{arr}, nil
    91  				}),
    92  			)
    93  
    94  			So(err, ShouldBeNil)
    95  
    96  			rootScope, _ := core.NewRootScope()
    97  			ctx := context.Background()
    98  			scope := rootScope.Fork()
    99  			out, err := ds.Iterate(ctx, scope)
   100  
   101  			So(err, ShouldBeNil)
   102  
   103  			pos := -1
   104  
   105  			nextScope := scope
   106  
   107  			for {
   108  				nextScope, err = out.Next(ctx, nextScope.Fork())
   109  
   110  				if err != nil {
   111  					if core.IsNoMoreData(err) {
   112  						break
   113  					}
   114  
   115  					So(err, ShouldBeNil)
   116  				}
   117  
   118  				pos++
   119  
   120  				actualV, _ := nextScope.GetVariable(collections.DefaultValueVar)
   121  				actualK, _ := nextScope.GetVariable(collections.DefaultKeyVar)
   122  
   123  				expectedV := arr.Get(values.Int(pos))
   124  
   125  				So(actualV, ShouldEqual, expectedV)
   126  				So(actualK, ShouldEqual, values.Int(pos))
   127  			}
   128  
   129  			So(pos, ShouldEqual, int(arr.Length()))
   130  		})
   131  
   132  		Convey("Should stop an execution when context is cancelled", func() {
   133  			arr := values.NewArrayWith(
   134  				values.NewInt(1),
   135  				values.NewInt(2),
   136  				values.NewInt(3),
   137  				values.NewInt(4),
   138  				values.NewInt(5),
   139  				values.NewInt(6),
   140  				values.NewInt(7),
   141  				values.NewInt(8),
   142  				values.NewInt(9),
   143  				values.NewInt(10),
   144  			)
   145  
   146  			ds, err := expressions.NewForInIterableExpression(
   147  				core.SourceMap{},
   148  				collections.DefaultValueVar,
   149  				collections.DefaultKeyVar,
   150  				TestDataSourceExpression(func(ctx context.Context, scope *core.Scope) (core.Value, error) {
   151  					return &testIterableCollection{arr}, nil
   152  				}),
   153  			)
   154  
   155  			So(err, ShouldBeNil)
   156  
   157  			rootScope, _ := core.NewRootScope()
   158  			scope := rootScope.Fork()
   159  			ctx, cancel := context.WithCancel(context.Background())
   160  			cancel()
   161  
   162  			_, err = ds.Iterate(ctx, scope)
   163  
   164  			So(err, ShouldEqual, core.ErrTerminated)
   165  		})
   166  	})
   167  }