package collections_test import ( "context" "encoding/json" "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 toValues(scopes []*core.Scope) []core.Value { res := make([]core.Value, 0, len(scopes)) for _, scope := range scopes { res = append(res, scope.MustGetVariable(collections.DefaultValueVar)) } return res } func toArrayOfValues(scopes []*core.Scope) *values.Array { return values.NewArrayWith(toValues(scopes)...) } func TestSort(t *testing.T) { Convey("Should sort asc", t, func() { arr := []core.Value{ values.NewInt(5), values.NewInt(1), values.NewInt(3), values.NewInt(4), values.NewInt(2), } s, _ := collections.NewSorter( func(ctx context.Context, first, second *core.Scope) (int64, error) { return first.MustGetVariable(collections.DefaultValueVar).Compare(second.MustGetVariable(collections.DefaultValueVar)), nil }, collections.SortDirectionAsc, ) iter, err := collections.NewSortIterator( sliceIterator(arr), s, ) So(err, ShouldBeNil) ctx := context.Background() scope, _ := core.NewRootScope() res, err := collections.ToSlice(ctx, scope, iter) So(err, ShouldBeNil) numbers := []int{1, 2, 3, 4, 5} for idx, num := range numbers { So(res[idx].MustGetVariable(collections.DefaultValueVar).Unwrap(), ShouldEqual, num) } }) Convey("Should sort desc", t, func() { arr := []core.Value{ values.NewInt(5), values.NewInt(1), values.NewInt(3), values.NewInt(4), values.NewInt(2), } s, _ := collections.NewSorter( func(ctx context.Context, first, second *core.Scope) (int64, error) { return first.MustGetVariable(collections.DefaultValueVar).Compare(second.MustGetVariable(collections.DefaultValueVar)), nil }, collections.SortDirectionDesc, ) iter, err := collections.NewSortIterator( sliceIterator(arr), s, ) So(err, ShouldBeNil) ctx := context.Background() scope, _ := core.NewRootScope() res, err := collections.ToSlice(ctx, scope, iter) So(err, ShouldBeNil) numbers := []int{5, 4, 3, 2, 1} for idx, num := range numbers { So(res[idx].MustGetVariable(collections.DefaultValueVar).Unwrap(), ShouldEqual, num) } }) Convey("Should sort asc with multiple sorters", t, func() { makeObj := func(one, two int) *values.Object { obj := values.NewObject() obj.Set("one", values.NewInt(one)) obj.Set("two", values.NewInt(two)) return obj } arr := []core.Value{ makeObj(1, 2), makeObj(1, 1), makeObj(3, 1), makeObj(4, 2), makeObj(2, 1), makeObj(3, 2), makeObj(4, 1), makeObj(2, 2), } s1, _ := collections.NewSorter( func(ctx context.Context, first, second *core.Scope) (int64, error) { o1, _ := first.MustGetVariable(collections.DefaultValueVar).(*values.Object).Get("one") o2, _ := second.MustGetVariable(collections.DefaultValueVar).(*values.Object).Get("one") return o1.Compare(o2), nil }, collections.SortDirectionAsc, ) s2, _ := collections.NewSorter( func(ctx context.Context, first, second *core.Scope) (int64, error) { o1, _ := first.MustGetVariable(collections.DefaultValueVar).(*values.Object).Get("two") o2, _ := second.MustGetVariable(collections.DefaultValueVar).(*values.Object).Get("two") return o1.Compare(o2), nil }, collections.SortDirectionAsc, ) iter, err := collections.NewSortIterator( sliceIterator(arr), s1, s2, ) So(err, ShouldBeNil) ctx := context.Background() scope, _ := core.NewRootScope() sets, err := collections.ToSlice(ctx, scope, iter) So(err, ShouldBeNil) res := toValues(sets) j, _ := json.Marshal(res) So(string(j), ShouldEqual, `[{"one":1,"two":1},{"one":1,"two":2},{"one":2,"two":1},{"one":2,"two":2},{"one":3,"two":1},{"one":3,"two":2},{"one":4,"two":1},{"one":4,"two":2}]`) }) Convey("Should sort desc with multiple sorters", t, func() { makeObj := func(one, two int) *values.Object { obj := values.NewObject() obj.Set("one", values.NewInt(one)) obj.Set("two", values.NewInt(two)) return obj } arr := []core.Value{ makeObj(1, 2), makeObj(1, 1), makeObj(3, 1), makeObj(4, 2), makeObj(2, 1), makeObj(3, 2), makeObj(4, 1), makeObj(2, 2), } s1, _ := collections.NewSorter( func(ctx context.Context, first, second *core.Scope) (int64, error) { o1, _ := first.MustGetVariable(collections.DefaultValueVar).(*values.Object).Get("one") o2, _ := second.MustGetVariable(collections.DefaultValueVar).(*values.Object).Get("one") return o1.Compare(o2), nil }, collections.SortDirectionDesc, ) s2, _ := collections.NewSorter( func(ctx context.Context, first, second *core.Scope) (int64, error) { o1, _ := first.MustGetVariable(collections.DefaultValueVar).(*values.Object).Get("two") o2, _ := second.MustGetVariable(collections.DefaultValueVar).(*values.Object).Get("two") return o1.Compare(o2), nil }, collections.SortDirectionDesc, ) iter, err := collections.NewSortIterator( sliceIterator(arr), s1, s2, ) So(err, ShouldBeNil) ctx := context.Background() scope, _ := core.NewRootScope() sets, err := collections.ToSlice(ctx, scope, iter) So(err, ShouldBeNil) res := toValues(sets) j, _ := json.Marshal(res) So(string(j), ShouldEqual, `[{"one":4,"two":2},{"one":4,"two":1},{"one":3,"two":2},{"one":3,"two":1},{"one":2,"two":2},{"one":2,"two":1},{"one":1,"two":2},{"one":1,"two":1}]`) }) Convey("Should sort asc and desc with multiple sorters", t, func() { makeObj := func(one, two int) *values.Object { obj := values.NewObject() obj.Set("one", values.NewInt(one)) obj.Set("two", values.NewInt(two)) return obj } arr := []core.Value{ makeObj(1, 2), makeObj(1, 1), makeObj(3, 1), makeObj(4, 2), makeObj(2, 1), makeObj(3, 2), makeObj(4, 1), makeObj(2, 2), } s1, _ := collections.NewSorter( func(ctx context.Context, first, second *core.Scope) (int64, error) { o1, _ := first.MustGetVariable(collections.DefaultValueVar).(*values.Object).Get("one") o2, _ := second.MustGetVariable(collections.DefaultValueVar).(*values.Object).Get("one") return o1.Compare(o2), nil }, collections.SortDirectionAsc, ) s2, _ := collections.NewSorter( func(ctx context.Context, first, second *core.Scope) (int64, error) { o1, _ := first.MustGetVariable(collections.DefaultValueVar).(*values.Object).Get("two") o2, _ := second.MustGetVariable(collections.DefaultValueVar).(*values.Object).Get("two") return o1.Compare(o2), nil }, collections.SortDirectionDesc, ) iter, err := collections.NewSortIterator( sliceIterator(arr), s1, s2, ) So(err, ShouldBeNil) ctx := context.Background() scope, _ := core.NewRootScope() sets, err := collections.ToSlice(ctx, scope, iter) So(err, ShouldBeNil) res := toValues(sets) j, _ := json.Marshal(res) So(string(j), ShouldEqual, `[{"one":1,"two":2},{"one":1,"two":1},{"one":2,"two":2},{"one":2,"two":1},{"one":3,"two":2},{"one":3,"two":1},{"one":4,"two":2},{"one":4,"two":1}]`) }) Convey("Should sort desc and asc with multiple sorters", t, func() { makeObj := func(one, two int) *values.Object { obj := values.NewObject() obj.Set("one", values.NewInt(one)) obj.Set("two", values.NewInt(two)) return obj } arr := []core.Value{ makeObj(1, 2), makeObj(1, 1), makeObj(3, 1), makeObj(4, 2), makeObj(2, 1), makeObj(3, 2), makeObj(4, 1), makeObj(2, 2), } s1, _ := collections.NewSorter( func(ctx context.Context, first, second *core.Scope) (int64, error) { o1, _ := first.MustGetVariable(collections.DefaultValueVar).(*values.Object).Get("one") o2, _ := second.MustGetVariable(collections.DefaultValueVar).(*values.Object).Get("one") return o1.Compare(o2), nil }, collections.SortDirectionDesc, ) s2, _ := collections.NewSorter( func(ctx context.Context, first, second *core.Scope) (int64, error) { o1, _ := first.MustGetVariable(collections.DefaultValueVar).(*values.Object).Get("two") o2, _ := second.MustGetVariable(collections.DefaultValueVar).(*values.Object).Get("two") return o1.Compare(o2), nil }, collections.SortDirectionAsc, ) src, err := collections.NewSortIterator( sliceIterator(arr), s1, s2, ) So(err, ShouldBeNil) ctx := context.Background() scope, _ := core.NewRootScope() sets, err := collections.ToSlice(ctx, scope, src) So(err, ShouldBeNil) res := toValues(sets) j, _ := json.Marshal(res) So(string(j), ShouldEqual, `[{"one":4,"two":1},{"one":4,"two":2},{"one":3,"two":1},{"one":3,"two":2},{"one":2,"two":1},{"one":2,"two":2},{"one":1,"two":1},{"one":1,"two":2}]`) }) }