github.com/MontFerret/ferret@v0.18.0/pkg/compiler/compiler_let_test.go (about)

     1  package compiler_test
     2  
     3  import (
     4  	"context"
     5  	"testing"
     6  
     7  	. "github.com/smartystreets/goconvey/convey"
     8  
     9  	"github.com/MontFerret/ferret/pkg/compiler"
    10  	"github.com/MontFerret/ferret/pkg/runtime"
    11  	"github.com/MontFerret/ferret/pkg/runtime/core"
    12  	"github.com/MontFerret/ferret/pkg/runtime/values"
    13  )
    14  
    15  func TestLet(t *testing.T) {
    16  	Convey("Should compile LET i = NONE RETURN i", t, func() {
    17  		c := compiler.New()
    18  
    19  		p, err := c.Compile(`
    20  			LET i = NONE
    21  			RETURN i
    22  		`)
    23  
    24  		So(err, ShouldBeNil)
    25  		So(p, ShouldHaveSameTypeAs, &runtime.Program{})
    26  
    27  		out, err := p.Run(context.Background())
    28  
    29  		So(err, ShouldBeNil)
    30  		So(string(out), ShouldEqual, "null")
    31  	})
    32  
    33  	Convey("Should compile LET i = TRUE RETURN i", t, func() {
    34  		c := compiler.New()
    35  
    36  		p, err := c.Compile(`
    37  			LET i = TRUE
    38  			RETURN i
    39  		`)
    40  
    41  		So(err, ShouldBeNil)
    42  		So(p, ShouldHaveSameTypeAs, &runtime.Program{})
    43  
    44  		out, err := p.Run(context.Background())
    45  
    46  		So(err, ShouldBeNil)
    47  		So(string(out), ShouldEqual, "true")
    48  	})
    49  
    50  	Convey("Should compile LET i = 1 RETURN i", t, func() {
    51  		c := compiler.New()
    52  
    53  		p, err := c.Compile(`
    54  			LET i = 1
    55  			RETURN i
    56  		`)
    57  
    58  		So(err, ShouldBeNil)
    59  		So(p, ShouldHaveSameTypeAs, &runtime.Program{})
    60  
    61  		out, err := p.Run(context.Background())
    62  
    63  		So(err, ShouldBeNil)
    64  		So(string(out), ShouldEqual, "1")
    65  	})
    66  
    67  	Convey("Should compile LET i = 1.1 RETURN i", t, func() {
    68  		c := compiler.New()
    69  
    70  		p, err := c.Compile(`
    71  			LET i = 1.1
    72  			RETURN i
    73  		`)
    74  
    75  		So(err, ShouldBeNil)
    76  		So(p, ShouldHaveSameTypeAs, &runtime.Program{})
    77  
    78  		out, err := p.Run(context.Background())
    79  
    80  		So(err, ShouldBeNil)
    81  		So(string(out), ShouldEqual, "1.1")
    82  	})
    83  
    84  	Convey("Should compile LET i = 'foo' RETURN i", t, func() {
    85  		c := compiler.New()
    86  
    87  		p, err := c.Compile(`
    88  			LET i = "foo"
    89  			RETURN i
    90  		`)
    91  
    92  		So(err, ShouldBeNil)
    93  		So(p, ShouldHaveSameTypeAs, &runtime.Program{})
    94  
    95  		out, err := p.Run(context.Background())
    96  
    97  		So(err, ShouldBeNil)
    98  		So(string(out), ShouldEqual, "\"foo\"")
    99  	})
   100  
   101  	Convey("Should compile LET i = [] RETURN i", t, func() {
   102  		c := compiler.New()
   103  
   104  		p, err := c.Compile(`
   105  			LET i = []
   106  			RETURN i
   107  		`)
   108  
   109  		So(err, ShouldBeNil)
   110  		So(p, ShouldHaveSameTypeAs, &runtime.Program{})
   111  
   112  		out, err := p.Run(context.Background())
   113  
   114  		So(err, ShouldBeNil)
   115  		So(string(out), ShouldEqual, "[]")
   116  	})
   117  
   118  	Convey("Should compile LET i = [1, 2, 3] RETURN i", t, func() {
   119  		c := compiler.New()
   120  
   121  		p, err := c.Compile(`
   122  			LET i = [1, 2, 3]
   123  			RETURN i
   124  		`)
   125  
   126  		So(err, ShouldBeNil)
   127  		So(p, ShouldHaveSameTypeAs, &runtime.Program{})
   128  
   129  		out, err := p.Run(context.Background())
   130  
   131  		So(err, ShouldBeNil)
   132  		So(string(out), ShouldEqual, "[1,2,3]")
   133  	})
   134  
   135  	Convey("Should compile LET i = {} RETURN i", t, func() {
   136  		c := compiler.New()
   137  
   138  		p, err := c.Compile(`
   139  			LET i = {}
   140  			RETURN i
   141  		`)
   142  
   143  		So(err, ShouldBeNil)
   144  		So(p, ShouldHaveSameTypeAs, &runtime.Program{})
   145  
   146  		out, err := p.Run(context.Background())
   147  
   148  		So(err, ShouldBeNil)
   149  		So(string(out), ShouldEqual, "{}")
   150  	})
   151  
   152  	Convey("Should compile LET i = {a: 'foo', b: 1, c: TRUE, d: [], e: {}} RETURN i", t, func() {
   153  		c := compiler.New()
   154  
   155  		p, err := c.Compile(`
   156  			LET i = {a: 'foo', b: 1, c: TRUE, d: [], e: {}}
   157  			RETURN i
   158  		`)
   159  
   160  		So(err, ShouldBeNil)
   161  		So(p, ShouldHaveSameTypeAs, &runtime.Program{})
   162  
   163  		out, err := p.Run(context.Background())
   164  
   165  		So(err, ShouldBeNil)
   166  		So(string(out), ShouldEqual, "{\"a\":\"foo\",\"b\":1,\"c\":true,\"d\":[],\"e\":{}}")
   167  	})
   168  
   169  	Convey("Should compile LET i = (FOR i IN [1,2,3] RETURN i) RETURN i", t, func() {
   170  		c := compiler.New()
   171  
   172  		p, err := c.Compile(`
   173  			LET i = (FOR i IN [1,2,3] RETURN i)
   174  			RETURN i
   175  		`)
   176  
   177  		So(err, ShouldBeNil)
   178  		So(p, ShouldHaveSameTypeAs, &runtime.Program{})
   179  
   180  		out, err := p.Run(context.Background())
   181  
   182  		So(err, ShouldBeNil)
   183  		So(string(out), ShouldEqual, "[1,2,3]")
   184  	})
   185  
   186  	Convey("Should compile LET src = NONE LET i = (FOR i IN NONE RETURN i)? RETURN i == NONE", t, func() {
   187  		c := compiler.New()
   188  
   189  		p, err := c.Compile(`
   190  			LET src = NONE
   191  			LET i = (FOR i IN src RETURN i)?
   192  			RETURN i == NONE
   193  		`)
   194  
   195  		So(err, ShouldBeNil)
   196  		So(p, ShouldHaveSameTypeAs, &runtime.Program{})
   197  
   198  		out, err := p.Run(context.Background())
   199  
   200  		So(err, ShouldBeNil)
   201  		So(string(out), ShouldEqual, "true")
   202  	})
   203  
   204  	Convey("Should compile LET i = (FOR i WHILE COUNTER() < 5 RETURN i) RETURN i", t, func() {
   205  		c := compiler.New()
   206  		counter := -1
   207  		c.RegisterFunction("COUNTER", func(ctx context.Context, args ...core.Value) (core.Value, error) {
   208  			counter++
   209  
   210  			return values.NewInt(counter), nil
   211  		})
   212  
   213  		p, err := c.Compile(`
   214  			LET i = (FOR i WHILE COUNTER() < 5 RETURN i)
   215  			RETURN i
   216  		`)
   217  
   218  		So(err, ShouldBeNil)
   219  		So(p, ShouldHaveSameTypeAs, &runtime.Program{})
   220  
   221  		out, err := p.Run(context.Background())
   222  
   223  		So(err, ShouldBeNil)
   224  		So(string(out), ShouldEqual, "[0,1,2,3,4]")
   225  	})
   226  
   227  	Convey("Should compile LET i = (FOR i WHILE COUNTER() < 5 T::FAIL() RETURN i)? RETURN i == NONE", t, func() {
   228  		c := compiler.New()
   229  		counter := -1
   230  		c.RegisterFunction("COUNTER", func(ctx context.Context, args ...core.Value) (core.Value, error) {
   231  			counter++
   232  
   233  			return values.NewInt(counter), nil
   234  		})
   235  
   236  		p, err := c.Compile(`
   237  			LET i = (FOR i WHILE COUNTER() < 5 T::FAIL() RETURN i)?
   238  			RETURN i == NONE
   239  		`)
   240  
   241  		So(err, ShouldBeNil)
   242  		So(p, ShouldHaveSameTypeAs, &runtime.Program{})
   243  
   244  		out, err := p.Run(context.Background())
   245  
   246  		So(err, ShouldBeNil)
   247  		So(string(out), ShouldEqual, "true")
   248  	})
   249  
   250  	Convey("Should compile LET i = { items: [1,2,3]}  FOR el IN i.items RETURN i", t, func() {
   251  		c := compiler.New()
   252  
   253  		p, err := c.Compile(`
   254  			LET obj = { items: [1,2,3] }
   255  	
   256  			FOR i IN obj.items
   257  				RETURN i
   258  		`)
   259  
   260  		So(err, ShouldBeNil)
   261  		So(p, ShouldHaveSameTypeAs, &runtime.Program{})
   262  
   263  		out, err := p.Run(context.Background())
   264  
   265  		So(err, ShouldBeNil)
   266  		So(string(out), ShouldEqual, "[1,2,3]")
   267  	})
   268  
   269  	Convey("Should not compile FOR foo IN foo", t, func() {
   270  		c := compiler.New()
   271  
   272  		_, err := c.Compile(`
   273  			FOR foo IN foo
   274  				RETURN foo
   275  		`)
   276  
   277  		So(err, ShouldNotBeNil)
   278  	})
   279  
   280  	Convey("Should not compile if a variable not defined", t, func() {
   281  		c := compiler.New()
   282  
   283  		_, err := c.Compile(`
   284  			RETURN foo
   285  		`)
   286  
   287  		So(err, ShouldNotBeNil)
   288  	})
   289  
   290  	Convey("Should not compile if a variable is not unique", t, func() {
   291  		c := compiler.New()
   292  
   293  		_, err := c.Compile(`
   294  			LET foo = "bar"
   295  			LET foo = "baz"
   296  
   297  			RETURN foo
   298  		`)
   299  
   300  		So(err, ShouldNotBeNil)
   301  	})
   302  
   303  	SkipConvey("Should use value returned from WAITFOR EVENT", t, func() {
   304  		out, err := newCompilerWithObservable().MustCompile(`
   305  			LET obj = X::VAL("event", ["data"])
   306  
   307  			LET res = (WAITFOR EVENT "event" IN obj)
   308  
   309  			RETURN res
   310  		`).Run(context.Background())
   311  
   312  		So(err, ShouldBeNil)
   313  		So(string(out), ShouldEqual, `"data"`)
   314  	})
   315  
   316  	SkipConvey("Should handle error from WAITFOR EVENT", t, func() {
   317  		out, err := newCompilerWithObservable().MustCompile(`
   318  			LET obj = X::VAL("foo", ["data"])
   319  
   320  			LET res = (WAITFOR EVENT "event" IN obj TIMEOUT 100)?
   321  
   322  			RETURN res == NONE
   323  		`).Run(context.Background())
   324  
   325  		So(err, ShouldBeNil)
   326  		So(string(out), ShouldEqual, `true`)
   327  	})
   328  
   329  	SkipConvey("Should compare result of handled error", t, func() {
   330  		out, err := newCompilerWithObservable().MustCompile(`
   331  			LET obj = X::VAL("event", ["foo"], 1000)
   332  
   333  			LET res = (WAITFOR EVENT "event" IN obj TIMEOUT 100)? != NONE
   334  
   335  			RETURN res
   336  		`).Run(context.Background())
   337  
   338  		So(err, ShouldBeNil)
   339  		So(string(out), ShouldEqual, `false`)
   340  	})
   341  
   342  	Convey("Should use ignorable variable name", t, func() {
   343  		out, err := newCompilerWithObservable().MustCompile(`
   344  			LET _ = (FOR i IN 1..100 RETURN NONE)
   345  
   346  			RETURN TRUE
   347  		`).Run(context.Background())
   348  
   349  		So(err, ShouldBeNil)
   350  		So(string(out), ShouldEqual, `true`)
   351  	})
   352  
   353  	Convey("Should allow to declare a variable name using _", t, func() {
   354  		c := compiler.New()
   355  
   356  		out, err := c.MustCompile(`
   357  			LET _ = (FOR i IN 1..100 RETURN NONE)
   358  			LET _ = (FOR i IN 1..100 RETURN NONE)
   359  
   360  			RETURN TRUE
   361  		`).Run(context.Background())
   362  
   363  		So(err, ShouldBeNil)
   364  		So(string(out), ShouldEqual, `true`)
   365  	})
   366  
   367  	Convey("Should not allow to use ignorable variable name", t, func() {
   368  		c := compiler.New()
   369  
   370  		_, err := c.Compile(`
   371  			LET _ = (FOR i IN 1..100 RETURN NONE)
   372  
   373  			RETURN _
   374  		`)
   375  
   376  		So(err, ShouldNotBeNil)
   377  	})
   378  }