mirror of
				https://github.com/MontFerret/ferret.git
				synced 2025-10-30 23:37:40 +02:00 
			
		
		
		
	
							
								
								
									
										331
									
								
								pkg/compiler/compiler_array_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										331
									
								
								pkg/compiler/compiler_array_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,331 @@ | ||||
| package compiler_test | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"github.com/MontFerret/ferret/pkg/compiler" | ||||
| 	. "github.com/smartystreets/goconvey/convey" | ||||
| 	"testing" | ||||
| ) | ||||
|  | ||||
| func TestArrayOperator(t *testing.T) { | ||||
| 	Convey("ALL", t, func() { | ||||
| 		Convey("[1,2,3] ALL IN [1,2,3] should return true", func() { | ||||
| 			c := compiler.New() | ||||
|  | ||||
| 			prog, err := c.Compile(` | ||||
| 			RETURN [1,2,3] ALL IN [1,2,3] | ||||
| 		`) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
|  | ||||
| 			out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
| 			So(string(out), ShouldEqual, `true`) | ||||
| 		}) | ||||
|  | ||||
| 		Convey("[1,2,4] ALL IN [1,2,3] should return false", func() { | ||||
| 			c := compiler.New() | ||||
|  | ||||
| 			prog, err := c.Compile(` | ||||
| 			RETURN [1,2,4] ALL IN [1,2,3] | ||||
| 		`) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
|  | ||||
| 			out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
| 			So(string(out), ShouldEqual, `false`) | ||||
| 		}) | ||||
|  | ||||
| 		Convey("[4,5,6] ALL NOT IN [1,2,3] should return true", func() { | ||||
| 			c := compiler.New() | ||||
|  | ||||
| 			prog, err := c.Compile(` | ||||
| 			RETURN [4,5,6] ALL NOT IN [1,2,3] | ||||
| 		`) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
|  | ||||
| 			out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
| 			So(string(out), ShouldEqual, `true`) | ||||
| 		}) | ||||
|  | ||||
| 		Convey("[1,2,3] ALL > 0 should return true", func() { | ||||
| 			c := compiler.New() | ||||
|  | ||||
| 			prog, err := c.Compile(` | ||||
| 			RETURN [1,2,3] ALL > 0 | ||||
| 		`) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
|  | ||||
| 			out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
| 			So(string(out), ShouldEqual, `true`) | ||||
| 		}) | ||||
|  | ||||
| 		Convey("[1,2,3] ALL > 2 should return false", func() { | ||||
| 			c := compiler.New() | ||||
|  | ||||
| 			prog, err := c.Compile(` | ||||
| 			RETURN [1,2,3] ALL > 2 | ||||
| 		`) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
|  | ||||
| 			out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
| 			So(string(out), ShouldEqual, `false`) | ||||
| 		}) | ||||
|  | ||||
| 		Convey("[1,2,3] ALL >= 3 should return false", func() { | ||||
| 			c := compiler.New() | ||||
|  | ||||
| 			prog, err := c.Compile(` | ||||
| 			RETURN [1,2,3] ALL >= 3 | ||||
| 		`) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
|  | ||||
| 			out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
| 			So(string(out), ShouldEqual, `false`) | ||||
| 		}) | ||||
|  | ||||
| 		Convey("['foo','bar'] ALL != 'moo' should return true", func() { | ||||
| 			c := compiler.New() | ||||
|  | ||||
| 			prog, err := c.Compile(` | ||||
| 			RETURN ['foo', 'bar'] ALL != 'moo' | ||||
| 		`) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
|  | ||||
| 			out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
| 			So(string(out), ShouldEqual, `true`) | ||||
| 		}) | ||||
| 	}) | ||||
|  | ||||
| 	Convey("ANY", t, func() { | ||||
| 		Convey("[1,2,3] ANY IN [1,2,3] should return true", func() { | ||||
| 			c := compiler.New() | ||||
|  | ||||
| 			prog, err := c.Compile(` | ||||
| 			RETURN [1,2,3] ANY IN [1,2,3] | ||||
| 		`) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
|  | ||||
| 			out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
| 			So(string(out), ShouldEqual, `true`) | ||||
| 		}) | ||||
|  | ||||
| 		Convey("[4,2,5] ANY IN [1,2,3] should return true", func() { | ||||
| 			c := compiler.New() | ||||
|  | ||||
| 			prog, err := c.Compile(` | ||||
| 			RETURN [4,2,5] ANY IN [1,2,3] | ||||
| 		`) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
|  | ||||
| 			out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
| 			So(string(out), ShouldEqual, `true`) | ||||
| 		}) | ||||
|  | ||||
| 		Convey("[4,5,6] ANY IN [1,2,3] should return false", func() { | ||||
| 			c := compiler.New() | ||||
|  | ||||
| 			prog, err := c.Compile(` | ||||
| 			RETURN [4,5,6] ANY IN [1,2,3] | ||||
| 		`) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
|  | ||||
| 			out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
| 			So(string(out), ShouldEqual, `false`) | ||||
| 		}) | ||||
|  | ||||
| 		Convey("[4,5,6] ANY NOT IN [1,2,3] should return true", func() { | ||||
| 			c := compiler.New() | ||||
|  | ||||
| 			prog, err := c.Compile(` | ||||
| 			RETURN [4,5,6] ANY NOT IN [1,2,3] | ||||
| 		`) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
|  | ||||
| 			out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
| 			So(string(out), ShouldEqual, `true`) | ||||
| 		}) | ||||
|  | ||||
| 		Convey("[1,2,3 ] ANY == 2 should return true", func() { | ||||
| 			c := compiler.New() | ||||
|  | ||||
| 			prog, err := c.Compile(` | ||||
| 			RETURN [1,2,3 ] ANY == 2 | ||||
| 		`) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
|  | ||||
| 			out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
| 			So(string(out), ShouldEqual, `true`) | ||||
| 		}) | ||||
|  | ||||
| 		Convey("[1,2,3 ] ANY == 4 should return false", func() { | ||||
| 			c := compiler.New() | ||||
|  | ||||
| 			prog, err := c.Compile(` | ||||
| 			RETURN [1,2,3 ] ANY == 4 | ||||
| 		`) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
|  | ||||
| 			out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
| 			So(string(out), ShouldEqual, `false`) | ||||
| 		}) | ||||
|  | ||||
| 		Convey("['foo','bar'] ANY == 'foo' should return true", func() { | ||||
| 			c := compiler.New() | ||||
|  | ||||
| 			prog, err := c.Compile(` | ||||
| 			RETURN ['foo', 'bar'] ANY == 'foo' | ||||
| 		`) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
|  | ||||
| 			out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
| 			So(string(out), ShouldEqual, `true`) | ||||
| 		}) | ||||
| 	}) | ||||
|  | ||||
| 	Convey("NONE", t, func() { | ||||
| 		Convey("[1,2,3] NONE IN [1,2,3] should return false", func() { | ||||
| 			c := compiler.New() | ||||
|  | ||||
| 			prog, err := c.Compile(` | ||||
| 			RETURN [1,2,3] NONE IN [1,2,3] | ||||
| 		`) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
|  | ||||
| 			out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
| 			So(string(out), ShouldEqual, `false`) | ||||
| 		}) | ||||
|  | ||||
| 		Convey("[4,2,5] NONE IN [1,2,3] should return false", func() { | ||||
| 			c := compiler.New() | ||||
|  | ||||
| 			prog, err := c.Compile(` | ||||
| 			RETURN [4,2,5] NONE IN [1,2,3] | ||||
| 		`) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
|  | ||||
| 			out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
| 			So(string(out), ShouldEqual, `false`) | ||||
| 		}) | ||||
|  | ||||
| 		Convey("[4,5,6] NONE IN [1,2,3] should return true", func() { | ||||
| 			c := compiler.New() | ||||
|  | ||||
| 			prog, err := c.Compile(` | ||||
| 			RETURN [4,5,6] NONE IN [1,2,3] | ||||
| 		`) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
|  | ||||
| 			out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
| 			So(string(out), ShouldEqual, `true`) | ||||
| 		}) | ||||
|  | ||||
| 		Convey("[4,5,6] NONE NOT IN [1,2,3] should return false", func() { | ||||
| 			c := compiler.New() | ||||
|  | ||||
| 			prog, err := c.Compile(` | ||||
| 			RETURN [4,5,6] NONE NOT IN [1,2,3] | ||||
| 		`) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
|  | ||||
| 			out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
| 			So(string(out), ShouldEqual, `false`) | ||||
| 		}) | ||||
|  | ||||
| 		Convey("[1,2,3] NONE > 99 should return false", func() { | ||||
| 			c := compiler.New() | ||||
|  | ||||
| 			prog, err := c.Compile(` | ||||
| 			RETURN [1,2,3] NONE > 99 | ||||
| 		`) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
|  | ||||
| 			out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
| 			So(string(out), ShouldEqual, `true`) | ||||
| 		}) | ||||
|  | ||||
| 		Convey("[1,2,3] NONE < 99 should return false", func() { | ||||
| 			c := compiler.New() | ||||
|  | ||||
| 			prog, err := c.Compile(` | ||||
| 			RETURN [1,2,3] NONE < 99 | ||||
| 		`) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
|  | ||||
| 			out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
| 			So(string(out), ShouldEqual, `false`) | ||||
| 		}) | ||||
|  | ||||
| 		Convey("['foo','bar'] NONE == 'foo' should return false", func() { | ||||
| 			c := compiler.New() | ||||
|  | ||||
| 			prog, err := c.Compile(` | ||||
| 			RETURN ['foo','bar'] NONE == 'foo' | ||||
| 		`) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
|  | ||||
| 			out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
| 			So(string(out), ShouldEqual, `false`) | ||||
| 		}) | ||||
| 	}) | ||||
| } | ||||
							
								
								
									
										27
									
								
								pkg/compiler/compiler_eq_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								pkg/compiler/compiler_eq_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | ||||
| package compiler_test | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"github.com/MontFerret/ferret/pkg/compiler" | ||||
| 	"github.com/MontFerret/ferret/pkg/runtime" | ||||
| 	. "github.com/smartystreets/goconvey/convey" | ||||
| 	"testing" | ||||
| ) | ||||
|  | ||||
| func TestEqualityOperators(t *testing.T) { | ||||
| 	Convey("Should compile RETURN 2 > 1", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		prog, err := c.Compile(` | ||||
| 			RETURN 2 > 1 | ||||
| 		`) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(prog, ShouldHaveSameTypeAs, &runtime.Program{}) | ||||
|  | ||||
| 		out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(string(out), ShouldEqual, "true") | ||||
| 	}) | ||||
| } | ||||
							
								
								
									
										94
									
								
								pkg/compiler/compiler_for_ternary_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								pkg/compiler/compiler_for_ternary_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,94 @@ | ||||
| package compiler_test | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"github.com/MontFerret/ferret/pkg/compiler" | ||||
| 	. "github.com/smartystreets/goconvey/convey" | ||||
| 	"testing" | ||||
| ) | ||||
|  | ||||
| func TestForTernaryExpression(t *testing.T) { | ||||
| 	Convey("RETURN foo ? TRUE : (FOR i IN 1..5 RETURN i*2)", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		out1, err := c.MustCompile(` | ||||
| 			LET foo = FALSE | ||||
| 			RETURN foo ? TRUE : (FOR i IN 1..5 RETURN i*2) | ||||
| 		`).Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(string(out1), ShouldEqual, `[2,4,6,8,10]`) | ||||
|  | ||||
| 		out2, err := c.MustCompile(` | ||||
| 			LET foo = TRUE | ||||
| 			RETURN foo ? TRUE : (FOR i IN 1..5 RETURN i*2) | ||||
| 		`).Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(string(out2), ShouldEqual, `true`) | ||||
| 	}) | ||||
|  | ||||
| 	Convey("RETURN foo ? (FOR i IN 1..5 RETURN i) : (FOR i IN 1..5 RETURN i*2)", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		out1, err := c.MustCompile(` | ||||
| 			LET foo = FALSE | ||||
| 			RETURN foo ? (FOR i IN 1..5 RETURN i) : (FOR i IN 1..5 RETURN i*2) | ||||
| 		`).Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(string(out1), ShouldEqual, `[2,4,6,8,10]`) | ||||
|  | ||||
| 		out2, err := c.MustCompile(` | ||||
| 			LET foo = TRUE | ||||
| 			RETURN foo ? (FOR i IN 1..5 RETURN i) : (FOR i IN 1..5 RETURN i*2) | ||||
| 		`).Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(string(out2), ShouldEqual, `[1,2,3,4,5]`) | ||||
| 	}) | ||||
|  | ||||
| 	Convey("LET res =  foo ? TRUE : (FOR i IN 1..5 RETURN i*2)", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		out1, err := c.MustCompile(` | ||||
| 			LET foo = FALSE | ||||
| 			LET res = foo ? TRUE : (FOR i IN 1..5 RETURN i*2)  | ||||
| 			RETURN res | ||||
| 		`).Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(string(out1), ShouldEqual, `[2,4,6,8,10]`) | ||||
|  | ||||
| 		out2, err := c.MustCompile(` | ||||
| 			LET foo = TRUE | ||||
| 			LET res = foo ? TRUE : (FOR i IN 1..5 RETURN i*2) | ||||
| 			RETURN res | ||||
| 		`).Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(string(out2), ShouldEqual, `true`) | ||||
| 	}) | ||||
|  | ||||
| 	Convey("LET res = foo ? (FOR i IN 1..5 RETURN i) : (FOR i IN 1..5 RETURN i*2)", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		out1, err := c.MustCompile(` | ||||
| 			LET foo = FALSE | ||||
| 			LET res = foo ? (FOR i IN 1..5 RETURN i) : (FOR i IN 1..5 RETURN i*2) | ||||
| 			RETURN res | ||||
| 		`).Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(string(out1), ShouldEqual, `[2,4,6,8,10]`) | ||||
|  | ||||
| 		out2, err := c.MustCompile(` | ||||
| 			LET foo = TRUE | ||||
| 			LET res = foo ? (FOR i IN 1..5 RETURN i) : (FOR i IN 1..5 RETURN i*2) | ||||
| 			RETURN res | ||||
| 		`).Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(string(out2), ShouldEqual, `[1,2,3,4,5]`) | ||||
| 	}) | ||||
| } | ||||
							
								
								
									
										513
									
								
								pkg/compiler/compiler_for_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										513
									
								
								pkg/compiler/compiler_for_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,513 @@ | ||||
| package compiler_test | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"encoding/json" | ||||
| 	"github.com/MontFerret/ferret/pkg/compiler" | ||||
| 	"github.com/MontFerret/ferret/pkg/runtime" | ||||
| 	. "github.com/smartystreets/goconvey/convey" | ||||
| 	"sort" | ||||
| 	"testing" | ||||
| ) | ||||
|  | ||||
| func TestFor(t *testing.T) { | ||||
| 	Convey("Should compile FOR i IN [] RETURN i", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		prog, err := c.Compile(` | ||||
| 			FOR i IN [] | ||||
| 				RETURN i | ||||
| 		`) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(prog, ShouldHaveSameTypeAs, &runtime.Program{}) | ||||
|  | ||||
| 		out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(string(out), ShouldEqual, "[]") | ||||
| 	}) | ||||
|  | ||||
| 	Convey("Should compile FOR i IN [1, 2, 3] RETURN i", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		prog, err := c.Compile(` | ||||
| 			FOR i IN [1, 2, 3] | ||||
| 				RETURN i | ||||
| 		`) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(prog, ShouldHaveSameTypeAs, &runtime.Program{}) | ||||
|  | ||||
| 		out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(string(out), ShouldEqual, "[1,2,3]") | ||||
| 	}) | ||||
|  | ||||
| 	Convey("Should compile FOR i, k IN [1, 2, 3] RETURN k", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		prog, err := c.Compile(` | ||||
| 			FOR i, k IN [1, 2, 3] | ||||
| 				RETURN k | ||||
| 		`) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(prog, ShouldHaveSameTypeAs, &runtime.Program{}) | ||||
|  | ||||
| 		out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(string(out), ShouldEqual, "[0,1,2]") | ||||
| 	}) | ||||
|  | ||||
| 	Convey("Should compile FOR i IN ['foo', 'bar', 'qaz'] RETURN i", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		prog, err := c.Compile(` | ||||
| 			FOR i IN ['foo', 'bar', 'qaz'] | ||||
| 				RETURN i | ||||
| 		`) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(prog, ShouldHaveSameTypeAs, &runtime.Program{}) | ||||
|  | ||||
| 		out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(string(out), ShouldEqual, "[\"foo\",\"bar\",\"qaz\"]") | ||||
| 	}) | ||||
|  | ||||
| 	Convey("Should compile FOR i IN {a: 'bar', b: 'foo', c: 'qaz'} RETURN i.name", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		prog, err := c.Compile(` | ||||
| 			FOR i IN {a: 'bar', b: 'foo', c: 'qaz'} | ||||
| 				RETURN i | ||||
| 		`) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(prog, ShouldHaveSameTypeAs, &runtime.Program{}) | ||||
|  | ||||
| 		out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
|  | ||||
| 		arr := make([]string, 0, 3) | ||||
| 		err = json.Unmarshal(out, &arr) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
|  | ||||
| 		sort.Strings(arr) | ||||
|  | ||||
| 		out, err = json.Marshal(arr) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
|  | ||||
| 		So(string(out), ShouldEqual, "[\"bar\",\"foo\",\"qaz\"]") | ||||
| 	}) | ||||
|  | ||||
| 	Convey("Should compile FOR i, k IN {a: 'foo', b: 'bar', c: 'qaz'} RETURN k", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		prog, err := c.Compile(` | ||||
| 			FOR i, k IN {a: 'foo', b: 'bar', c: 'qaz'} | ||||
| 				RETURN k | ||||
| 		`) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(prog, ShouldHaveSameTypeAs, &runtime.Program{}) | ||||
|  | ||||
| 		out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
|  | ||||
| 		arr := make([]string, 0, 3) | ||||
| 		err = json.Unmarshal(out, &arr) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
|  | ||||
| 		sort.Strings(arr) | ||||
|  | ||||
| 		out, err = json.Marshal(arr) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(string(out), ShouldEqual, "[\"a\",\"b\",\"c\"]") | ||||
| 	}) | ||||
|  | ||||
| 	Convey("Should compile FOR i IN [{name: 'foo'}, {name: 'bar'}, {name: 'qaz'}] RETURN i.name", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		prog, err := c.Compile(` | ||||
| 			FOR i IN [{name: 'foo'}, {name: 'bar'}, {name: 'qaz'}] | ||||
| 				RETURN i.name | ||||
| 		`) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(prog, ShouldHaveSameTypeAs, &runtime.Program{}) | ||||
|  | ||||
| 		out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(string(out), ShouldEqual, "[\"foo\",\"bar\",\"qaz\"]") | ||||
| 	}) | ||||
|  | ||||
| 	Convey("Should compile nested FOR operators", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		prog, err := c.Compile(` | ||||
| 			FOR prop IN ["a"] | ||||
| 				FOR val IN [1, 2, 3] | ||||
| 					RETURN {[prop]: val} | ||||
| 		`) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
|  | ||||
| 		out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
|  | ||||
| 		So(string(out), ShouldEqual, "[{\"a\":1},{\"a\":2},{\"a\":3}]") | ||||
| 	}) | ||||
|  | ||||
| 	Convey("Should compile deeply nested FOR operators", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		prog, err := c.Compile(` | ||||
| 			FOR prop IN ["a"] | ||||
| 				FOR val IN [1, 2, 3] | ||||
| 					FOR val2 IN [1, 2, 3] | ||||
| 						RETURN { [prop]: [val, val2] } | ||||
| 		`) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
|  | ||||
| 		out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
|  | ||||
| 		So(string(out), ShouldEqual, `[{"a":[1,1]},{"a":[1,2]},{"a":[1,3]},{"a":[2,1]},{"a":[2,2]},{"a":[2,3]},{"a":[3,1]},{"a":[3,2]},{"a":[3,3]}]`) | ||||
| 	}) | ||||
|  | ||||
| 	Convey("Should compile query with a sub query", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		prog, err := c.Compile(` | ||||
| 			FOR val IN [1, 2, 3] | ||||
| 				RETURN ( | ||||
| 					FOR prop IN ["a", "b", "c"] | ||||
| 						RETURN { [prop]: val } | ||||
| 				) | ||||
| 		`) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
|  | ||||
| 		out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
|  | ||||
| 		So(string(out), ShouldEqual, `[[{"a":1},{"b":1},{"c":1}],[{"a":2},{"b":2},{"c":2}],[{"a":3},{"b":3},{"c":3}]]`) | ||||
| 	}) | ||||
|  | ||||
| 	Convey("Should compile query with variable in a body", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		prog, err := c.Compile(` | ||||
| 			FOR val IN [1, 2, 3] | ||||
| 				LET sub = ( | ||||
| 					FOR prop IN ["a", "b", "c"] | ||||
| 						RETURN { [prop]: val } | ||||
| 				) | ||||
|  | ||||
| 				RETURN sub | ||||
| 		`) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
|  | ||||
| 		out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
|  | ||||
| 		So(string(out), ShouldEqual, `[[{"a":1},{"b":1},{"c":1}],[{"a":2},{"b":2},{"c":2}],[{"a":3},{"b":3},{"c":3}]]`) | ||||
| 	}) | ||||
|  | ||||
| 	Convey("Should compile query with RETURN DISTINCT", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		prog, err := c.Compile(` | ||||
| 			FOR i IN [ 1, 2, 3, 4, 1, 3 ] | ||||
| 				RETURN DISTINCT i | ||||
| 		`) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
|  | ||||
| 		out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
|  | ||||
| 		So(string(out), ShouldEqual, `[1,2,3,4]`) | ||||
| 	}) | ||||
|  | ||||
| 	Convey("Should compile query with LIMIT 2", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		prog, err := c.Compile(` | ||||
| 			FOR i IN [ 1, 2, 3, 4, 1, 3 ] | ||||
| 				LIMIT 2 | ||||
| 				RETURN i | ||||
| 		`) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
|  | ||||
| 		out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
|  | ||||
| 		So(string(out), ShouldEqual, `[1,2]`) | ||||
| 	}) | ||||
|  | ||||
| 	Convey("Should compile query with LIMIT 2, 2", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		// 4 is offset | ||||
| 		// 2 is count | ||||
| 		prog, err := c.Compile(` | ||||
| 			FOR i IN [ 1,2,3,4,5,6,7,8 ] | ||||
| 				LIMIT 4, 2 | ||||
| 				RETURN i | ||||
| 		`) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
|  | ||||
| 		out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
|  | ||||
| 		So(string(out), ShouldEqual, `[5,6]`) | ||||
| 	}) | ||||
|  | ||||
| 	Convey("Should compile query with FILTER i > 2", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		prog, err := c.Compile(` | ||||
| 			FOR i IN [ 1, 2, 3, 4, 1, 3 ] | ||||
| 				FILTER i > 2 | ||||
| 				RETURN i | ||||
| 		`) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
|  | ||||
| 		out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
|  | ||||
| 		So(string(out), ShouldEqual, `[3,4,3]`) | ||||
| 	}) | ||||
|  | ||||
| 	Convey("Should compile query with FILTER i > 1 AND i < 3", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		prog, err := c.Compile(` | ||||
| 			FOR i IN [ 1, 2, 3, 4, 1, 3 ] | ||||
| 				FILTER i > 1 AND i < 4 | ||||
| 				RETURN i | ||||
| 		`) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
|  | ||||
| 		out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
|  | ||||
| 		So(string(out), ShouldEqual, `[2,3,3]`) | ||||
| 	}) | ||||
|  | ||||
| 	Convey("Should compile query with multiple FILTER statements", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		prog, err := c.Compile(` | ||||
| 			LET users = [ | ||||
| 				{ | ||||
| 					active: true, | ||||
| 					age: 31, | ||||
| 					gender: "m" | ||||
| 				}, | ||||
| 				{ | ||||
| 					active: true, | ||||
| 					age: 29, | ||||
| 					gender: "f" | ||||
| 				}, | ||||
| 				{ | ||||
| 					active: true, | ||||
| 					age: 36, | ||||
| 					gender: "m" | ||||
| 				} | ||||
| 			] | ||||
| 			FOR u IN users | ||||
| 				FILTER u.active == true | ||||
| 				FILTER u.age < 35 | ||||
| 				RETURN u | ||||
| 		`) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
|  | ||||
| 		out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
|  | ||||
| 		So(string(out), ShouldEqual, `[{"active":true,"age":31,"gender":"m"},{"active":true,"age":29,"gender":"f"}]`) | ||||
| 	}) | ||||
|  | ||||
| 	Convey("Should compile query with multiple FILTER statements", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		prog, err := c.Compile(` | ||||
| 			LET users = [ | ||||
| 				{ | ||||
| 					active: true, | ||||
| 					age: 31, | ||||
| 					gender: "m" | ||||
| 				}, | ||||
| 				{ | ||||
| 					active: true, | ||||
| 					age: 29, | ||||
| 					gender: "f" | ||||
| 				}, | ||||
| 				{ | ||||
| 					active: true, | ||||
| 					age: 36, | ||||
| 					gender: "m" | ||||
| 				}, | ||||
| 				{ | ||||
| 					active: false, | ||||
| 					age: 69, | ||||
| 					gender: "m" | ||||
| 				} | ||||
| 			] | ||||
| 			FOR u IN users | ||||
| 				FILTER u.active == true | ||||
| 				LIMIT 2 | ||||
| 				FILTER u.gender == "m" | ||||
| 				RETURN u | ||||
| 		`) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
|  | ||||
| 		out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
|  | ||||
| 		So(string(out), ShouldEqual, `[{"active":true,"age":31,"gender":"m"}]`) | ||||
| 	}) | ||||
|  | ||||
| 	Convey("Should compile query with SORT statement", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		prog, err := c.Compile(` | ||||
| 			LET users = [ | ||||
| 				{ | ||||
| 					active: true, | ||||
| 					age: 31, | ||||
| 					gender: "m" | ||||
| 				}, | ||||
| 				{ | ||||
| 					active: true, | ||||
| 					age: 29, | ||||
| 					gender: "f" | ||||
| 				}, | ||||
| 				{ | ||||
| 					active: true, | ||||
| 					age: 36, | ||||
| 					gender: "m" | ||||
| 				} | ||||
| 			] | ||||
| 			FOR u IN users | ||||
| 				SORT u.age | ||||
| 				RETURN u | ||||
| 		`) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
|  | ||||
| 		out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
|  | ||||
| 		So(string(out), ShouldEqual, `[{"active":true,"age":29,"gender":"f"},{"active":true,"age":31,"gender":"m"},{"active":true,"age":36,"gender":"m"}]`) | ||||
| 	}) | ||||
|  | ||||
| 	Convey("Should compile query with SORT DESC statement", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		prog, err := c.Compile(` | ||||
| 			LET users = [ | ||||
| 				{ | ||||
| 					active: true, | ||||
| 					age: 31, | ||||
| 					gender: "m" | ||||
| 				}, | ||||
| 				{ | ||||
| 					active: true, | ||||
| 					age: 29, | ||||
| 					gender: "f" | ||||
| 				}, | ||||
| 				{ | ||||
| 					active: true, | ||||
| 					age: 36, | ||||
| 					gender: "m" | ||||
| 				} | ||||
| 			] | ||||
| 			FOR u IN users | ||||
| 				SORT u.age DESC | ||||
| 				RETURN u | ||||
| 		`) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
|  | ||||
| 		out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
|  | ||||
| 		So(string(out), ShouldEqual, `[{"active":true,"age":36,"gender":"m"},{"active":true,"age":31,"gender":"m"},{"active":true,"age":29,"gender":"f"}]`) | ||||
| 	}) | ||||
|  | ||||
| 	Convey("Should compile query with SORT statement with multiple expressions", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		prog, err := c.Compile(` | ||||
| 			LET users = [ | ||||
| 				{ | ||||
| 					active: true, | ||||
| 					age: 31, | ||||
| 					gender: "m" | ||||
| 				}, | ||||
| 				{ | ||||
| 					active: true, | ||||
| 					age: 29, | ||||
| 					gender: "f" | ||||
| 				}, | ||||
| 				{ | ||||
| 					active: true, | ||||
| 					age: 31, | ||||
| 					gender: "f" | ||||
| 				}, | ||||
| 				{ | ||||
| 					active: true, | ||||
| 					age: 36, | ||||
| 					gender: "m" | ||||
| 				} | ||||
| 			] | ||||
| 			FOR u IN users | ||||
| 				SORT u.age, u.gender | ||||
| 				RETURN u | ||||
| 		`) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
|  | ||||
| 		out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
|  | ||||
| 		So(string(out), ShouldEqual, `[{"active":true,"age":29,"gender":"f"},{"active":true,"age":31,"gender":"f"},{"active":true,"age":31,"gender":"m"},{"active":true,"age":36,"gender":"m"}]`) | ||||
| 	}) | ||||
| } | ||||
							
								
								
									
										84
									
								
								pkg/compiler/compiler_func_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								pkg/compiler/compiler_func_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,84 @@ | ||||
| package compiler_test | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"github.com/MontFerret/ferret/pkg/compiler" | ||||
| 	. "github.com/smartystreets/goconvey/convey" | ||||
| 	"testing" | ||||
| ) | ||||
|  | ||||
| func TestFunctionCall(t *testing.T) { | ||||
| 	Convey("Should compile RETURN TYPENAME(1)", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		prog, err := c.Compile(` | ||||
| 			RETURN TYPENAME(1) | ||||
| 		`) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
|  | ||||
| 		out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
|  | ||||
| 		So(string(out), ShouldEqual, `"int"`) | ||||
| 	}) | ||||
|  | ||||
| 	Convey("Should compile WAIT(10) RETURN 1", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		prog, err := c.Compile(` | ||||
| 			WAIT(10) | ||||
| 			RETURN 1 | ||||
| 		`) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
|  | ||||
| 		out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
|  | ||||
| 		So(string(out), ShouldEqual, `1`) | ||||
| 	}) | ||||
|  | ||||
| 	Convey("Should compile LET duration = 10 WAIT(duration) RETURN 1", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		prog, err := c.Compile(` | ||||
| 			LET duration = 10 | ||||
|  | ||||
| 			WAIT(duration) | ||||
|  | ||||
| 			RETURN 1 | ||||
| 		`) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
|  | ||||
| 		out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
|  | ||||
| 		So(string(out), ShouldEqual, `1`) | ||||
| 	}) | ||||
|  | ||||
| 	Convey("Should compile function call inside FOR IN statement", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		prog, err := c.Compile(` | ||||
| 			FOR i IN [1, 2, 3, 4] | ||||
| 				LET duration = 10 | ||||
|  | ||||
| 				WAIT(duration) | ||||
|  | ||||
| 				RETURN i * 2 | ||||
| 		`) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
|  | ||||
| 		out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
|  | ||||
| 		So(string(out), ShouldEqual, `[2,4,6,8]`) | ||||
| 	}) | ||||
| } | ||||
							
								
								
									
										55
									
								
								pkg/compiler/compiler_in_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								pkg/compiler/compiler_in_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,55 @@ | ||||
| package compiler_test | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"github.com/MontFerret/ferret/pkg/compiler" | ||||
| 	. "github.com/smartystreets/goconvey/convey" | ||||
| 	"testing" | ||||
| ) | ||||
|  | ||||
| func TestInOperator(t *testing.T) { | ||||
| 	Convey("1 IN [1,2,3] should return true", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		prog, err := c.Compile(` | ||||
| 			RETURN 1 IN [1,2,3] | ||||
| 		`) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
|  | ||||
| 		out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(string(out), ShouldEqual, `true`) | ||||
| 	}) | ||||
|  | ||||
| 	Convey("4 IN [1,2,3] should return false", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		prog, err := c.Compile(` | ||||
| 			RETURN 4 IN [1,2,3] | ||||
| 		`) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
|  | ||||
| 		out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(string(out), ShouldEqual, `false`) | ||||
| 	}) | ||||
|  | ||||
| 	Convey("4 NOT IN [1,2,3] should return true", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		prog, err := c.Compile(` | ||||
| 			RETURN 4 NOT IN [1,2,3] | ||||
| 		`) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
|  | ||||
| 		out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(string(out), ShouldEqual, `true`) | ||||
| 	}) | ||||
| } | ||||
							
								
								
									
										200
									
								
								pkg/compiler/compiler_let_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										200
									
								
								pkg/compiler/compiler_let_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,200 @@ | ||||
| package compiler_test | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"github.com/MontFerret/ferret/pkg/compiler" | ||||
| 	"github.com/MontFerret/ferret/pkg/runtime" | ||||
| 	. "github.com/smartystreets/goconvey/convey" | ||||
| 	"testing" | ||||
| ) | ||||
|  | ||||
| func TestLet(t *testing.T) { | ||||
| 	Convey("Should compile LET i = NONE RETURN i", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		prog, err := c.Compile(` | ||||
| 			LET i = NONE | ||||
| 			RETURN i | ||||
| 		`) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(prog, ShouldHaveSameTypeAs, &runtime.Program{}) | ||||
|  | ||||
| 		out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(string(out), ShouldEqual, "null") | ||||
| 	}) | ||||
|  | ||||
| 	Convey("Should compile LET i = TRUE RETURN i", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		prog, err := c.Compile(` | ||||
| 			LET i = TRUE | ||||
| 			RETURN i | ||||
| 		`) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(prog, ShouldHaveSameTypeAs, &runtime.Program{}) | ||||
|  | ||||
| 		out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(string(out), ShouldEqual, "true") | ||||
| 	}) | ||||
|  | ||||
| 	Convey("Should compile LET i = 1 RETURN i", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		prog, err := c.Compile(` | ||||
| 			LET i = 1 | ||||
| 			RETURN i | ||||
| 		`) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(prog, ShouldHaveSameTypeAs, &runtime.Program{}) | ||||
|  | ||||
| 		out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(string(out), ShouldEqual, "1") | ||||
| 	}) | ||||
|  | ||||
| 	Convey("Should compile LET i = 1.1 RETURN i", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		prog, err := c.Compile(` | ||||
| 			LET i = 1.1 | ||||
| 			RETURN i | ||||
| 		`) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(prog, ShouldHaveSameTypeAs, &runtime.Program{}) | ||||
|  | ||||
| 		out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(string(out), ShouldEqual, "1.1") | ||||
| 	}) | ||||
|  | ||||
| 	Convey("Should compile LET i = 'foo' RETURN i", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		prog, err := c.Compile(` | ||||
| 			LET i = "foo" | ||||
| 			RETURN i | ||||
| 		`) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(prog, ShouldHaveSameTypeAs, &runtime.Program{}) | ||||
|  | ||||
| 		out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(string(out), ShouldEqual, "\"foo\"") | ||||
| 	}) | ||||
|  | ||||
| 	Convey("Should compile LET i = [] RETURN i", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		prog, err := c.Compile(` | ||||
| 			LET i = [] | ||||
| 			RETURN i | ||||
| 		`) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(prog, ShouldHaveSameTypeAs, &runtime.Program{}) | ||||
|  | ||||
| 		out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(string(out), ShouldEqual, "[]") | ||||
| 	}) | ||||
|  | ||||
| 	Convey("Should compile LET i = [1, 2, 3] RETURN i", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		prog, err := c.Compile(` | ||||
| 			LET i = [1, 2, 3] | ||||
| 			RETURN i | ||||
| 		`) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(prog, ShouldHaveSameTypeAs, &runtime.Program{}) | ||||
|  | ||||
| 		out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(string(out), ShouldEqual, "[1,2,3]") | ||||
| 	}) | ||||
|  | ||||
| 	Convey("Should compile LET i = {} RETURN i", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		prog, err := c.Compile(` | ||||
| 			LET i = {} | ||||
| 			RETURN i | ||||
| 		`) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(prog, ShouldHaveSameTypeAs, &runtime.Program{}) | ||||
|  | ||||
| 		out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(string(out), ShouldEqual, "{}") | ||||
| 	}) | ||||
|  | ||||
| 	Convey("Should compile LET i = {a: 'foo', b: 1, c: TRUE, d: [], e: {}} RETURN i", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		prog, err := c.Compile(` | ||||
| 			LET i = {a: 'foo', b: 1, c: TRUE, d: [], e: {}} | ||||
| 			RETURN i | ||||
| 		`) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(prog, ShouldHaveSameTypeAs, &runtime.Program{}) | ||||
|  | ||||
| 		out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(string(out), ShouldEqual, "{\"a\":\"foo\",\"b\":1,\"c\":true,\"d\":[],\"e\":{}}") | ||||
| 	}) | ||||
|  | ||||
| 	Convey("Should compile LET i = (FOR i IN [1,2,3] RETURN i) RETURN i", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		prog, err := c.Compile(` | ||||
| 			LET i = (FOR i IN [1,2,3] RETURN i) | ||||
| 			RETURN i | ||||
| 		`) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(prog, ShouldHaveSameTypeAs, &runtime.Program{}) | ||||
|  | ||||
| 		out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(string(out), ShouldEqual, "[1,2,3]") | ||||
| 	}) | ||||
|  | ||||
| 	Convey("Should compile LET i = { items: [1,2,3]}  FOR el IN i.items RETURN i", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		prog, err := c.Compile(` | ||||
| 			LET obj = { items: [1,2,3] } | ||||
| 	 | ||||
| 			FOR i IN obj.items | ||||
| 				RETURN i | ||||
| 		`) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(prog, ShouldHaveSameTypeAs, &runtime.Program{}) | ||||
|  | ||||
| 		out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(string(out), ShouldEqual, "[1,2,3]") | ||||
| 	}) | ||||
| } | ||||
							
								
								
									
										150
									
								
								pkg/compiler/compiler_logical_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										150
									
								
								pkg/compiler/compiler_logical_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,150 @@ | ||||
| package compiler_test | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"github.com/MontFerret/ferret/pkg/compiler" | ||||
| 	"github.com/MontFerret/ferret/pkg/runtime" | ||||
| 	. "github.com/smartystreets/goconvey/convey" | ||||
| 	"testing" | ||||
| ) | ||||
|  | ||||
| func TestLogicalOperators(t *testing.T) { | ||||
| 	Convey("Should compile RETURN 2 > 1 AND 1 > 0", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		prog, err := c.Compile(` | ||||
| 			RETURN 2 > 1 AND 1 > 0 | ||||
| 		`) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(prog, ShouldHaveSameTypeAs, &runtime.Program{}) | ||||
|  | ||||
| 		out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(string(out), ShouldEqual, "true") | ||||
| 	}) | ||||
|  | ||||
| 	Convey("Should compile RETURN 2 > 1 OR 1 < 0", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		prog, err := c.Compile(` | ||||
| 			RETURN 2 > 1 OR 1 < 0 | ||||
| 		`) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(prog, ShouldHaveSameTypeAs, &runtime.Program{}) | ||||
|  | ||||
| 		out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(string(out), ShouldEqual, "true") | ||||
| 	}) | ||||
|  | ||||
| 	Convey("1 || 7  should return 1", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		prog, err := c.Compile(` | ||||
| 			RETURN 1 || 7 | ||||
| 		`) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
|  | ||||
| 		out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(string(out), ShouldEqual, "1") | ||||
| 	}) | ||||
|  | ||||
| 	Convey("NONE || 'foo'  should return 'foo'", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		prog, err := c.Compile(` | ||||
| 			RETURN NONE || 'foo' | ||||
| 		`) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
|  | ||||
| 		out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(string(out), ShouldEqual, `"foo"`) | ||||
| 	}) | ||||
|  | ||||
| 	Convey("NONE && true  should return null", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		prog, err := c.Compile(` | ||||
| 			RETURN NONE && true | ||||
| 		`) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
|  | ||||
| 		out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(string(out), ShouldEqual, `null`) | ||||
| 	}) | ||||
|  | ||||
| 	Convey("'' && true  should return ''", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		prog, err := c.Compile(` | ||||
| 			RETURN '' && true | ||||
| 		`) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
|  | ||||
| 		out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(string(out), ShouldEqual, `""`) | ||||
| 	}) | ||||
|  | ||||
| 	Convey("true && 23  should return '23", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		prog, err := c.Compile(` | ||||
| 			RETURN true && 23  | ||||
| 		`) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
|  | ||||
| 		out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(string(out), ShouldEqual, `23`) | ||||
| 	}) | ||||
|  | ||||
| 	Convey("NOT TRUE should return false", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		prog, err := c.Compile(` | ||||
| 			RETURN NOT TRUE | ||||
| 		`) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
|  | ||||
| 		out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(string(out), ShouldEqual, `false`) | ||||
| 	}) | ||||
|  | ||||
| 	Convey("NOT u.valid should return true", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		prog, err := c.Compile(` | ||||
| 			LET u = { valid: false } | ||||
|  | ||||
| 			RETURN NOT u.valid | ||||
| 		`) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
|  | ||||
| 		out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(string(out), ShouldEqual, `true`) | ||||
| 	}) | ||||
| } | ||||
							
								
								
									
										193
									
								
								pkg/compiler/compiler_math_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										193
									
								
								pkg/compiler/compiler_math_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,193 @@ | ||||
| package compiler_test | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"github.com/MontFerret/ferret/pkg/compiler" | ||||
| 	"github.com/MontFerret/ferret/pkg/runtime" | ||||
| 	. "github.com/smartystreets/goconvey/convey" | ||||
| 	"testing" | ||||
| ) | ||||
|  | ||||
| func TestMathOperators(t *testing.T) { | ||||
| 	Convey("Integers", t, func() { | ||||
| 		Convey("Should compile RETURN 1 + 1", func() { | ||||
| 			c := compiler.New() | ||||
|  | ||||
| 			prog, err := c.Compile(` | ||||
| 			RETURN 1 + 1 | ||||
| 		`) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
| 			So(prog, ShouldHaveSameTypeAs, &runtime.Program{}) | ||||
|  | ||||
| 			out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
| 			So(string(out), ShouldEqual, "2") | ||||
| 		}) | ||||
|  | ||||
| 		Convey("Should compile RETURN 1 - 1", func() { | ||||
| 			c := compiler.New() | ||||
|  | ||||
| 			prog, err := c.Compile(` | ||||
| 			RETURN 1 - 1 | ||||
| 		`) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
| 			So(prog, ShouldHaveSameTypeAs, &runtime.Program{}) | ||||
|  | ||||
| 			out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
| 			So(string(out), ShouldEqual, "0") | ||||
| 		}) | ||||
|  | ||||
| 		Convey("Should compile RETURN 2*2", func() { | ||||
| 			c := compiler.New() | ||||
|  | ||||
| 			prog, err := c.Compile(` | ||||
| 			RETURN 2*2 | ||||
| 		`) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
| 			So(prog, ShouldHaveSameTypeAs, &runtime.Program{}) | ||||
|  | ||||
| 			out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
| 			So(string(out), ShouldEqual, "4") | ||||
| 		}) | ||||
|  | ||||
| 		Convey("Should compile RETURN 4/2", func() { | ||||
| 			c := compiler.New() | ||||
|  | ||||
| 			prog, err := c.Compile(` | ||||
| 			RETURN 4/2 | ||||
| 		`) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
| 			So(prog, ShouldHaveSameTypeAs, &runtime.Program{}) | ||||
|  | ||||
| 			out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
| 			So(string(out), ShouldEqual, "2") | ||||
| 		}) | ||||
|  | ||||
| 		Convey("Should compile RETURN 5 % 2", func() { | ||||
| 			c := compiler.New() | ||||
|  | ||||
| 			prog, err := c.Compile(` | ||||
| 			RETURN 5 % 2 | ||||
| 		`) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
| 			So(prog, ShouldHaveSameTypeAs, &runtime.Program{}) | ||||
|  | ||||
| 			out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
| 			So(string(out), ShouldEqual, "1") | ||||
| 		}) | ||||
| 	}) | ||||
|  | ||||
| 	Convey("Floats", t, func() { | ||||
| 		Convey("Should compile RETURN 1.2 + 1", func() { | ||||
| 			c := compiler.New() | ||||
|  | ||||
| 			prog, err := c.Compile(` | ||||
| 			RETURN 1.2 + 1 | ||||
| 		`) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
| 			So(prog, ShouldHaveSameTypeAs, &runtime.Program{}) | ||||
|  | ||||
| 			out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
| 			So(string(out), ShouldEqual, "2.2") | ||||
| 		}) | ||||
|  | ||||
| 		Convey("Should compile RETURN 1.1 - 1", func() { | ||||
| 			c := compiler.New() | ||||
|  | ||||
| 			prog, err := c.Compile(` | ||||
| 			RETURN 1.1 - 1 | ||||
| 		`) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
| 			So(prog, ShouldHaveSameTypeAs, &runtime.Program{}) | ||||
|  | ||||
| 			out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
| 			So(string(out), ShouldEqual, "0.10000000000000009") | ||||
| 		}) | ||||
|  | ||||
| 		Convey("Should compile RETURN 2.1*2", func() { | ||||
| 			c := compiler.New() | ||||
|  | ||||
| 			prog, err := c.Compile(` | ||||
| 			RETURN 2.1*2 | ||||
| 		`) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
| 			So(prog, ShouldHaveSameTypeAs, &runtime.Program{}) | ||||
|  | ||||
| 			out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
| 			So(string(out), ShouldEqual, "4.2") | ||||
| 		}) | ||||
|  | ||||
| 		Convey("Should compile RETURN 4.4/2", func() { | ||||
| 			c := compiler.New() | ||||
|  | ||||
| 			prog, err := c.Compile(` | ||||
| 			RETURN 4.4/2 | ||||
| 		`) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
| 			So(prog, ShouldHaveSameTypeAs, &runtime.Program{}) | ||||
|  | ||||
| 			out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
| 			So(string(out), ShouldEqual, "2.2") | ||||
| 		}) | ||||
|  | ||||
| 		Convey("Should compile RETURN 5.5 % 2", func() { | ||||
| 			c := compiler.New() | ||||
|  | ||||
| 			prog, err := c.Compile(` | ||||
| 			RETURN 5.5 % 2 | ||||
| 		`) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
| 			So(prog, ShouldHaveSameTypeAs, &runtime.Program{}) | ||||
|  | ||||
| 			out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
| 			So(string(out), ShouldEqual, "1") | ||||
| 		}) | ||||
| 	}) | ||||
|  | ||||
| 	Convey("Strings", t, func() { | ||||
| 		Convey("Should concat two strings RETURN 'Foo' + 'Bar'", func() { | ||||
| 			c := compiler.New() | ||||
|  | ||||
| 			prog, err := c.Compile(` | ||||
| 			RETURN 'Foo' + 'Bar' | ||||
| 		`) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
| 			So(prog, ShouldHaveSameTypeAs, &runtime.Program{}) | ||||
|  | ||||
| 			out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
| 			So(string(out), ShouldEqual, `"FooBar"`) | ||||
| 		}) | ||||
| 	}) | ||||
| } | ||||
							
								
								
									
										86
									
								
								pkg/compiler/compiler_member_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								pkg/compiler/compiler_member_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,86 @@ | ||||
| package compiler_test | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"github.com/MontFerret/ferret/pkg/compiler" | ||||
| 	. "github.com/smartystreets/goconvey/convey" | ||||
| 	"testing" | ||||
| ) | ||||
|  | ||||
| func TestMember(t *testing.T) { | ||||
| 	Convey("Computed properties", t, func() { | ||||
| 		Convey("Array by literal", func() { | ||||
| 			c := compiler.New() | ||||
|  | ||||
| 			prog, err := c.Compile(` | ||||
| 				LET arr = [1,2,3,4] | ||||
|  | ||||
| 				RETURN arr[1] | ||||
| 			`) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
|  | ||||
| 			out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
|  | ||||
| 			So(string(out), ShouldEqual, `2`) | ||||
| 		}) | ||||
|  | ||||
| 		Convey("Array by variable", func() { | ||||
| 			c := compiler.New() | ||||
|  | ||||
| 			prog, err := c.Compile(` | ||||
| 				LET arr = [1,2,3,4] | ||||
| 				LET idx = 1 | ||||
|  | ||||
| 				RETURN arr[idx] | ||||
| 			`) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
|  | ||||
| 			out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
|  | ||||
| 			So(string(out), ShouldEqual, `2`) | ||||
| 		}) | ||||
|  | ||||
| 		Convey("Object by literal", func() { | ||||
| 			c := compiler.New() | ||||
|  | ||||
| 			prog, err := c.Compile(` | ||||
| 				LET obj = { foo: "bar", qaz: "wsx"} | ||||
|  | ||||
| 				RETURN obj["qaz"] | ||||
| 			`) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
|  | ||||
| 			out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
|  | ||||
| 			So(string(out), ShouldEqual, `"wsx"`) | ||||
| 		}) | ||||
|  | ||||
| 		Convey("Object by variable", func() { | ||||
| 			c := compiler.New() | ||||
|  | ||||
| 			prog, err := c.Compile(` | ||||
| 				LET obj = { foo: "bar", qaz: "wsx"} | ||||
| 				LET key = "qaz" | ||||
|  | ||||
| 				RETURN obj[key] | ||||
| 			`) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
|  | ||||
| 			out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
|  | ||||
| 			So(string(out), ShouldEqual, `"wsx"`) | ||||
| 		}) | ||||
| 	}) | ||||
| } | ||||
							
								
								
									
										65
									
								
								pkg/compiler/compiler_param_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								pkg/compiler/compiler_param_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,65 @@ | ||||
| package compiler_test | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"github.com/MontFerret/ferret/pkg/compiler" | ||||
| 	"github.com/MontFerret/ferret/pkg/runtime" | ||||
| 	. "github.com/smartystreets/goconvey/convey" | ||||
| 	"testing" | ||||
| ) | ||||
|  | ||||
| func TestParam(t *testing.T) { | ||||
| 	Convey("Should be possible to use as a return value", t, func() { | ||||
| 		out := compiler.New(). | ||||
| 			MustCompile(` | ||||
| 			RETURN @param | ||||
| 		`). | ||||
| 			MustRun(context.Background(), runtime.WithParam("param", "foobar")) | ||||
|  | ||||
| 		So(string(out), ShouldEqual, `"foobar"`) | ||||
| 	}) | ||||
|  | ||||
| 	Convey("Should be possible to use as a FOR source", t, func() { | ||||
| 		out := compiler.New(). | ||||
| 			MustCompile(` | ||||
| 			FOR i IN @values | ||||
| 			SORT i | ||||
| 			RETURN i | ||||
| 		`). | ||||
| 			MustRun(context.Background(), runtime.WithParam("values", []int{1, 2, 3, 4})) | ||||
|  | ||||
| 		So(string(out), ShouldEqual, `[1,2,3,4]`) | ||||
|  | ||||
| 		out2 := compiler.New(). | ||||
| 			MustCompile(` | ||||
| 			FOR i IN @values | ||||
| 			SORT i | ||||
| 			RETURN i | ||||
| 		`). | ||||
| 			MustRun(context.Background(), runtime.WithParam("values", map[string]int{ | ||||
| 				"foo": 1, | ||||
| 				"bar": 2, | ||||
| 				"faz": 3, | ||||
| 				"qaz": 4, | ||||
| 			})) | ||||
|  | ||||
| 		So(string(out2), ShouldEqual, `[1,2,3,4]`) | ||||
| 	}) | ||||
|  | ||||
| 	Convey("Should be possible to use in range", t, func() { | ||||
| 		out := compiler.New(). | ||||
| 			MustCompile(` | ||||
| 			FOR i IN @start..@end | ||||
| 			SORT i | ||||
| 			RETURN i | ||||
| 		`). | ||||
| 			MustRun( | ||||
| 				context.Background(), | ||||
| 				runtime.WithParam("start", 1), | ||||
| 				runtime.WithParam("end", 4), | ||||
| 			) | ||||
|  | ||||
| 		So(string(out), ShouldEqual, `[1,2,3,4]`) | ||||
|  | ||||
| 	}) | ||||
| } | ||||
							
								
								
									
										91
									
								
								pkg/compiler/compiler_range_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								pkg/compiler/compiler_range_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,91 @@ | ||||
| package compiler_test | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"github.com/MontFerret/ferret/pkg/compiler" | ||||
| 	. "github.com/smartystreets/goconvey/convey" | ||||
| 	"testing" | ||||
| ) | ||||
|  | ||||
| func TestRangeOperator(t *testing.T) { | ||||
| 	Convey("Should compile RETURN 1..10", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		prog, err := c.Compile(` | ||||
| 				RETURN 1..10 | ||||
| 			`) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
|  | ||||
| 		out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
|  | ||||
| 		So(string(out), ShouldEqual, `[1,2,3,4,5,6,7,8,9,10]`) | ||||
| 	}) | ||||
|  | ||||
| 	Convey("Should compile FOR i IN 1..10 RETURN i * 2", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		prog, err := c.Compile(` | ||||
| 				FOR i IN 1..10 | ||||
| 					RETURN i * 2 | ||||
| 			`) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
|  | ||||
| 		out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
|  | ||||
| 		So(string(out), ShouldEqual, `[2,4,6,8,10,12,14,16,18,20]`) | ||||
| 	}) | ||||
|  | ||||
| 	Convey("Should compile LET arr = 1..10 FOR i IN arr RETURN i * 2", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		prog, err := c.Compile(` | ||||
| 				LET arr = 1..10 | ||||
| 				FOR i IN arr | ||||
| 					RETURN i * 2 | ||||
| 			`) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
|  | ||||
| 		out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
|  | ||||
| 		So(string(out), ShouldEqual, `[2,4,6,8,10,12,14,16,18,20]`) | ||||
| 	}) | ||||
|  | ||||
| 	Convey("Should use variables", t, func() { | ||||
| 		out := compiler.New().MustCompile(` | ||||
| 				LET max = 10 | ||||
| 				 | ||||
| 				FOR i IN 1..max | ||||
| 					RETURN i * 2 | ||||
| 		`).MustRun(context.Background()) | ||||
|  | ||||
| 		So(string(out), ShouldEqual, `[2,4,6,8,10,12,14,16,18,20]`) | ||||
|  | ||||
| 		out2 := compiler.New().MustCompile(` | ||||
| 				LET min = 1 | ||||
| 				 | ||||
| 				FOR i IN min..10 | ||||
| 					RETURN i * 2 | ||||
| 		`).MustRun(context.Background()) | ||||
|  | ||||
| 		So(string(out2), ShouldEqual, `[2,4,6,8,10,12,14,16,18,20]`) | ||||
|  | ||||
| 		out3 := compiler.New().MustCompile(` | ||||
| 				LET min = 1 | ||||
| 				LET max = 10 | ||||
| 				 | ||||
| 				FOR i IN min..max | ||||
| 					RETURN i * 2 | ||||
| 		`).MustRun(context.Background()) | ||||
|  | ||||
| 		So(string(out3), ShouldEqual, `[2,4,6,8,10,12,14,16,18,20]`) | ||||
| 	}) | ||||
| } | ||||
							
								
								
									
										235
									
								
								pkg/compiler/compiler_return_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										235
									
								
								pkg/compiler/compiler_return_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,235 @@ | ||||
| package compiler_test | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"github.com/MontFerret/ferret/pkg/compiler" | ||||
| 	"github.com/MontFerret/ferret/pkg/runtime" | ||||
| 	. "github.com/smartystreets/goconvey/convey" | ||||
| 	"testing" | ||||
| ) | ||||
|  | ||||
| func TestReturn(t *testing.T) { | ||||
| 	Convey("Should compile RETURN NONE", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		prog, err := c.Compile(` | ||||
| 			RETURN NONE | ||||
| 		`) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(prog, ShouldHaveSameTypeAs, &runtime.Program{}) | ||||
|  | ||||
| 		out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(string(out), ShouldEqual, "null") | ||||
| 	}) | ||||
|  | ||||
| 	Convey("Should compile RETURN TRUE", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		prog, err := c.Compile(` | ||||
| 			RETURN TRUE | ||||
| 		`) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(prog, ShouldHaveSameTypeAs, &runtime.Program{}) | ||||
|  | ||||
| 		out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(string(out), ShouldEqual, "true") | ||||
| 	}) | ||||
|  | ||||
| 	Convey("Should compile RETURN 1", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		prog, err := c.Compile(` | ||||
| 			RETURN 1 | ||||
| 		`) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(prog, ShouldHaveSameTypeAs, &runtime.Program{}) | ||||
|  | ||||
| 		out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(string(out), ShouldEqual, "1") | ||||
| 	}) | ||||
|  | ||||
| 	Convey("Should compile RETURN 1.1", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		prog, err := c.Compile(` | ||||
| 			RETURN 1.1 | ||||
| 		`) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(prog, ShouldHaveSameTypeAs, &runtime.Program{}) | ||||
|  | ||||
| 		out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(string(out), ShouldEqual, "1.1") | ||||
| 	}) | ||||
|  | ||||
| 	Convey("Should compile RETURN 'foo'", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		prog, err := c.Compile(` | ||||
| 			RETURN 'foo' | ||||
| 		`) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(prog, ShouldHaveSameTypeAs, &runtime.Program{}) | ||||
|  | ||||
| 		out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(string(out), ShouldEqual, "\"foo\"") | ||||
| 	}) | ||||
|  | ||||
| 	Convey("Should compile RETURN \"foo\"", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		prog, err := c.Compile(` | ||||
| 			RETURN "foo" | ||||
| 		`) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(prog, ShouldHaveSameTypeAs, &runtime.Program{}) | ||||
|  | ||||
| 		out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(string(out), ShouldEqual, "\"foo\"") | ||||
| 	}) | ||||
|  | ||||
| 	Convey("Should compile RETURN \"\"", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		prog, err := c.Compile(` | ||||
| 			RETURN "" | ||||
| 		`) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(prog, ShouldHaveSameTypeAs, &runtime.Program{}) | ||||
|  | ||||
| 		out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(string(out), ShouldEqual, "\"\"") | ||||
| 	}) | ||||
|  | ||||
| 	Convey("Should compile RETURN []", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		prog, err := c.Compile(` | ||||
| 			RETURN [] | ||||
| 		`) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(prog, ShouldHaveSameTypeAs, &runtime.Program{}) | ||||
|  | ||||
| 		out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(string(out), ShouldEqual, "[]") | ||||
| 	}) | ||||
|  | ||||
| 	Convey("Should compile RETURN [1, 2, 3, 4]", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		prog, err := c.Compile(` | ||||
| 			RETURN [1, 2, 3, 4] | ||||
| 		`) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(prog, ShouldHaveSameTypeAs, &runtime.Program{}) | ||||
|  | ||||
| 		out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(string(out), ShouldEqual, "[1,2,3,4]") | ||||
| 	}) | ||||
|  | ||||
| 	Convey("Should compile RETURN ['foo', 'bar', 'qaz']", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		prog, err := c.Compile(` | ||||
| 			RETURN ['foo', 'bar', 'qaz'] | ||||
| 		`) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(prog, ShouldHaveSameTypeAs, &runtime.Program{}) | ||||
|  | ||||
| 		out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(string(out), ShouldEqual, "[\"foo\",\"bar\",\"qaz\"]") | ||||
| 	}) | ||||
|  | ||||
| 	Convey("Should compile RETURN ['foo', 'bar', 1, 2]", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		prog, err := c.Compile(` | ||||
| 			RETURN ['foo', 'bar', 1, 2] | ||||
| 		`) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(prog, ShouldHaveSameTypeAs, &runtime.Program{}) | ||||
|  | ||||
| 		out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(string(out), ShouldEqual, "[\"foo\",\"bar\",1,2]") | ||||
| 	}) | ||||
|  | ||||
| 	Convey("Should compile RETURN {}", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		prog, err := c.Compile(` | ||||
| 			RETURN {} | ||||
| 		`) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(prog, ShouldHaveSameTypeAs, &runtime.Program{}) | ||||
|  | ||||
| 		out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(string(out), ShouldEqual, "{}") | ||||
| 	}) | ||||
|  | ||||
| 	Convey("Should compile RETURN {a: 'foo', b: 'bar'}", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		prog, err := c.Compile(` | ||||
| 			RETURN { a: "foo", b: "bar" } | ||||
| 		`) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(prog, ShouldHaveSameTypeAs, &runtime.Program{}) | ||||
|  | ||||
| 		out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(string(out), ShouldEqual, "{\"a\":\"foo\",\"b\":\"bar\"}") | ||||
| 	}) | ||||
|  | ||||
| 	Convey("Should compile RETURN {['a']: 'foo'}", t, func() { | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		prog, err := c.Compile(` | ||||
| 			RETURN { ["a"]: "foo" } | ||||
| 		`) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(prog, ShouldHaveSameTypeAs, &runtime.Program{}) | ||||
|  | ||||
| 		out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(string(out), ShouldEqual, "{\"a\":\"foo\"}") | ||||
| 	}) | ||||
| } | ||||
							
								
								
									
										23
									
								
								pkg/compiler/compiler_str_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								pkg/compiler/compiler_str_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| package compiler_test | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"github.com/MontFerret/ferret/pkg/compiler" | ||||
| 	. "github.com/smartystreets/goconvey/convey" | ||||
| 	"testing" | ||||
| ) | ||||
|  | ||||
| func TestString(t *testing.T) { | ||||
| 	Convey("Should be possible to use multi line string", t, func() { | ||||
| 		out := compiler.New(). | ||||
| 			MustCompile(` | ||||
| 			RETURN " | ||||
| FOO | ||||
| BAR | ||||
| " | ||||
| 		`). | ||||
| 			MustRun(context.Background()) | ||||
|  | ||||
| 		So(string(out), ShouldEqual, `"\nFOO\nBAR\n"`) | ||||
| 	}) | ||||
| } | ||||
							
								
								
									
										86
									
								
								pkg/compiler/compiler_ternary_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								pkg/compiler/compiler_ternary_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,86 @@ | ||||
| package compiler_test | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"fmt" | ||||
| 	"github.com/MontFerret/ferret/pkg/compiler" | ||||
| 	. "github.com/smartystreets/goconvey/convey" | ||||
| 	"testing" | ||||
| ) | ||||
|  | ||||
| func TestTernaryOperator(t *testing.T) { | ||||
| 	Convey("Should compile ternary operator", t, func() { | ||||
| 		c := compiler.New() | ||||
| 		prog, err := c.Compile(` | ||||
| 			FOR i IN [1, 2, 3, 4, 5, 6] | ||||
| 				RETURN i < 3 ? i * 3 : i * 2; | ||||
| 		`) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
|  | ||||
| 		out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
|  | ||||
| 		So(string(out), ShouldEqual, `[3,6,6,8,10,12]`) | ||||
| 	}) | ||||
|  | ||||
| 	Convey("Should compile ternary operator with shortcut", t, func() { | ||||
| 		c := compiler.New() | ||||
| 		prog, err := c.Compile(` | ||||
| 			FOR i IN [1, 2, 3, 4, 5, 6] | ||||
| 				RETURN i < 3 ? : i * 2 | ||||
| 		`) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
|  | ||||
| 		out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
|  | ||||
| 		So(string(out), ShouldEqual, `[true,true,6,8,10,12]`) | ||||
| 	}) | ||||
|  | ||||
| 	Convey("Should compile ternary operator with shortcut with nones", t, func() { | ||||
| 		c := compiler.New() | ||||
| 		prog, err := c.Compile(` | ||||
| 			FOR i IN [NONE, 2, 3, 4, 5, 6] | ||||
| 				RETURN i ? : i | ||||
| 		`) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
|  | ||||
| 		out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
|  | ||||
| 		So(string(out), ShouldEqual, `[null,2,3,4,5,6]`) | ||||
| 	}) | ||||
|  | ||||
| 	Convey("Should compile ternary operator with default values", t, func() { | ||||
| 		vals := []string{ | ||||
| 			"0", | ||||
| 			"0.0", | ||||
| 			"''", | ||||
| 			"NONE", | ||||
| 			"FALSE", | ||||
| 		} | ||||
|  | ||||
| 		c := compiler.New() | ||||
|  | ||||
| 		for _, val := range vals { | ||||
| 			prog, err := c.Compile(fmt.Sprintf(` | ||||
| 			FOR i IN [%s, 1, 2, 3] | ||||
| 				RETURN i ? i * 2 : 'no value' | ||||
| 		`, val)) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
|  | ||||
| 			out, err := prog.Run(context.Background()) | ||||
|  | ||||
| 			So(err, ShouldBeNil) | ||||
|  | ||||
| 			So(string(out), ShouldEqual, `["no value",2,4,6]`) | ||||
| 		} | ||||
| 	}) | ||||
| } | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -79,6 +79,7 @@ In: 'IN'; | ||||
| Param: '@'; | ||||
| Identifier: Letter+ (Symbols (Identifier)*)* (Digit (Identifier)*)*; | ||||
| StringLiteral: SQString | DQSring; | ||||
| TemplateStringLiteral: '`' ('\\`' | ~'`')* '`'; | ||||
| IntegerLiteral: [0-9]+; | ||||
| FloatLiteral | ||||
|     : DecimalIntegerLiteral Dot [0-9]+ ExponentPart? | ||||
|   | ||||
| @@ -57,8 +57,9 @@ In=56 | ||||
| Param=57 | ||||
| Identifier=58 | ||||
| StringLiteral=59 | ||||
| IntegerLiteral=60 | ||||
| FloatLiteral=61 | ||||
| TemplateStringLiteral=60 | ||||
| IntegerLiteral=61 | ||||
| FloatLiteral=62 | ||||
| ':'=5 | ||||
| ';'=6 | ||||
| '.'=7 | ||||
|   | ||||
| @@ -154,6 +154,7 @@ booleanLiteral | ||||
|  | ||||
| stringLiteral | ||||
|     : StringLiteral | ||||
|     | TemplateStringLiteral | ||||
|     ; | ||||
|  | ||||
| integerLiteral | ||||
|   | ||||
		Reference in New Issue
	
	Block a user