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 }