github.com/expr-lang/expr@v1.16.9/expr_test.go (about)

     1  package expr_test
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"fmt"
     7  	"os"
     8  	"reflect"
     9  	"sync"
    10  	"testing"
    11  	"time"
    12  
    13  	"github.com/expr-lang/expr/internal/testify/assert"
    14  	"github.com/expr-lang/expr/internal/testify/require"
    15  
    16  	"github.com/expr-lang/expr"
    17  	"github.com/expr-lang/expr/ast"
    18  	"github.com/expr-lang/expr/file"
    19  	"github.com/expr-lang/expr/test/mock"
    20  )
    21  
    22  func ExampleEval() {
    23  	output, err := expr.Eval("greet + name", map[string]any{
    24  		"greet": "Hello, ",
    25  		"name":  "world!",
    26  	})
    27  	if err != nil {
    28  		fmt.Printf("err: %v", err)
    29  		return
    30  	}
    31  
    32  	fmt.Printf("%v", output)
    33  
    34  	// Output: Hello, world!
    35  }
    36  
    37  func ExampleEval_runtime_error() {
    38  	_, err := expr.Eval(`map(1..3, {1 % (# - 3)})`, nil)
    39  	fmt.Print(err)
    40  
    41  	// Output: runtime error: integer divide by zero (1:14)
    42  	//  | map(1..3, {1 % (# - 3)})
    43  	//  | .............^
    44  }
    45  
    46  func ExampleCompile() {
    47  	env := map[string]any{
    48  		"foo": 1,
    49  		"bar": 99,
    50  	}
    51  
    52  	program, err := expr.Compile("foo in 1..99 and bar in 1..99", expr.Env(env))
    53  	if err != nil {
    54  		fmt.Printf("%v", err)
    55  		return
    56  	}
    57  
    58  	output, err := expr.Run(program, env)
    59  	if err != nil {
    60  		fmt.Printf("%v", err)
    61  		return
    62  	}
    63  
    64  	fmt.Printf("%v", output)
    65  
    66  	// Output: true
    67  }
    68  
    69  func ExampleEnv() {
    70  	type Segment struct {
    71  		Origin string
    72  	}
    73  	type Passengers struct {
    74  		Adults int
    75  	}
    76  	type Meta struct {
    77  		Tags map[string]string
    78  	}
    79  	type Env struct {
    80  		Meta
    81  		Segments   []*Segment
    82  		Passengers *Passengers
    83  		Marker     string
    84  	}
    85  
    86  	code := `all(Segments, {.Origin == "MOW"}) && Passengers.Adults > 0 && Tags["foo"] startsWith "bar"`
    87  
    88  	program, err := expr.Compile(code, expr.Env(Env{}))
    89  	if err != nil {
    90  		fmt.Printf("%v", err)
    91  		return
    92  	}
    93  
    94  	env := Env{
    95  		Meta: Meta{
    96  			Tags: map[string]string{
    97  				"foo": "bar",
    98  			},
    99  		},
   100  		Segments: []*Segment{
   101  			{Origin: "MOW"},
   102  		},
   103  		Passengers: &Passengers{
   104  			Adults: 2,
   105  		},
   106  		Marker: "test",
   107  	}
   108  
   109  	output, err := expr.Run(program, env)
   110  	if err != nil {
   111  		fmt.Printf("%v", err)
   112  		return
   113  	}
   114  
   115  	fmt.Printf("%v", output)
   116  
   117  	// Output: true
   118  }
   119  
   120  func ExampleEnv_tagged_field_names() {
   121  	env := struct {
   122  		FirstWord  string
   123  		Separator  string `expr:"Space"`
   124  		SecondWord string `expr:"second_word"`
   125  	}{
   126  		FirstWord:  "Hello",
   127  		Separator:  " ",
   128  		SecondWord: "World",
   129  	}
   130  
   131  	output, err := expr.Eval(`FirstWord + Space + second_word`, env)
   132  	if err != nil {
   133  		fmt.Printf("%v", err)
   134  		return
   135  	}
   136  
   137  	fmt.Printf("%v", output)
   138  
   139  	// Output : Hello World
   140  }
   141  
   142  func ExampleAsKind() {
   143  	program, err := expr.Compile("{a: 1, b: 2}", expr.AsKind(reflect.Map))
   144  	if err != nil {
   145  		fmt.Printf("%v", err)
   146  		return
   147  	}
   148  
   149  	output, err := expr.Run(program, nil)
   150  	if err != nil {
   151  		fmt.Printf("%v", err)
   152  		return
   153  	}
   154  
   155  	fmt.Printf("%v", output)
   156  
   157  	// Output: map[a:1 b:2]
   158  }
   159  
   160  func ExampleAsBool() {
   161  	env := map[string]int{
   162  		"foo": 0,
   163  	}
   164  
   165  	program, err := expr.Compile("foo >= 0", expr.Env(env), expr.AsBool())
   166  	if err != nil {
   167  		fmt.Printf("%v", err)
   168  		return
   169  	}
   170  
   171  	output, err := expr.Run(program, env)
   172  	if err != nil {
   173  		fmt.Printf("%v", err)
   174  		return
   175  	}
   176  
   177  	fmt.Printf("%v", output.(bool))
   178  
   179  	// Output: true
   180  }
   181  
   182  func ExampleAsBool_error() {
   183  	env := map[string]any{
   184  		"foo": 0,
   185  	}
   186  
   187  	_, err := expr.Compile("foo + 42", expr.Env(env), expr.AsBool())
   188  
   189  	fmt.Printf("%v", err)
   190  
   191  	// Output: expected bool, but got int
   192  }
   193  
   194  func ExampleAsInt() {
   195  	program, err := expr.Compile("42", expr.AsInt())
   196  	if err != nil {
   197  		fmt.Printf("%v", err)
   198  		return
   199  	}
   200  
   201  	output, err := expr.Run(program, nil)
   202  	if err != nil {
   203  		fmt.Printf("%v", err)
   204  		return
   205  	}
   206  
   207  	fmt.Printf("%T(%v)", output, output)
   208  
   209  	// Output: int(42)
   210  }
   211  
   212  func ExampleAsInt64() {
   213  	env := map[string]any{
   214  		"rating": 5.5,
   215  	}
   216  
   217  	program, err := expr.Compile("rating", expr.Env(env), expr.AsInt64())
   218  	if err != nil {
   219  		fmt.Printf("%v", err)
   220  		return
   221  	}
   222  
   223  	output, err := expr.Run(program, env)
   224  	if err != nil {
   225  		fmt.Printf("%v", err)
   226  		return
   227  	}
   228  
   229  	fmt.Printf("%v", output.(int64))
   230  
   231  	// Output: 5
   232  }
   233  
   234  func ExampleAsFloat64() {
   235  	program, err := expr.Compile("42", expr.AsFloat64())
   236  	if err != nil {
   237  		fmt.Printf("%v", err)
   238  		return
   239  	}
   240  
   241  	output, err := expr.Run(program, nil)
   242  	if err != nil {
   243  		fmt.Printf("%v", err)
   244  		return
   245  	}
   246  
   247  	fmt.Printf("%v", output.(float64))
   248  
   249  	// Output: 42
   250  }
   251  
   252  func ExampleAsFloat64_error() {
   253  	_, err := expr.Compile(`!!true`, expr.AsFloat64())
   254  
   255  	fmt.Printf("%v", err)
   256  
   257  	// Output: expected float64, but got bool
   258  }
   259  
   260  func ExampleWarnOnAny() {
   261  	// Arrays always have []any type. The expression return type is any.
   262  	// AsInt() instructs compiler to expect int or any, and cast to int,
   263  	// if possible. WarnOnAny() instructs to return an error on any type.
   264  	_, err := expr.Compile(`[42, true, "yes"][0]`, expr.AsInt(), expr.WarnOnAny())
   265  
   266  	fmt.Printf("%v", err)
   267  
   268  	// Output: expected int, but got interface {}
   269  }
   270  
   271  func ExampleOperator() {
   272  	code := `
   273  		Now() > CreatedAt &&
   274  		(Now() - CreatedAt).Hours() > 24
   275  	`
   276  
   277  	type Env struct {
   278  		CreatedAt time.Time
   279  		Now       func() time.Time
   280  		Sub       func(a, b time.Time) time.Duration
   281  		After     func(a, b time.Time) bool
   282  	}
   283  
   284  	options := []expr.Option{
   285  		expr.Env(Env{}),
   286  		expr.Operator(">", "After"),
   287  		expr.Operator("-", "Sub"),
   288  	}
   289  
   290  	program, err := expr.Compile(code, options...)
   291  	if err != nil {
   292  		fmt.Printf("%v", err)
   293  		return
   294  	}
   295  
   296  	env := Env{
   297  		CreatedAt: time.Date(2018, 7, 14, 0, 0, 0, 0, time.UTC),
   298  		Now:       func() time.Time { return time.Now() },
   299  		Sub:       func(a, b time.Time) time.Duration { return a.Sub(b) },
   300  		After:     func(a, b time.Time) bool { return a.After(b) },
   301  	}
   302  
   303  	output, err := expr.Run(program, env)
   304  	if err != nil {
   305  		fmt.Printf("%v", err)
   306  		return
   307  	}
   308  
   309  	fmt.Printf("%v", output)
   310  
   311  	// Output: true
   312  }
   313  
   314  func ExampleOperator_Decimal() {
   315  	type Decimal struct{ N float64 }
   316  	code := `A + B - C`
   317  
   318  	type Env struct {
   319  		A, B, C Decimal
   320  		Sub     func(a, b Decimal) Decimal
   321  		Add     func(a, b Decimal) Decimal
   322  	}
   323  
   324  	options := []expr.Option{
   325  		expr.Env(Env{}),
   326  		expr.Operator("+", "Add"),
   327  		expr.Operator("-", "Sub"),
   328  	}
   329  
   330  	program, err := expr.Compile(code, options...)
   331  	if err != nil {
   332  		fmt.Printf("Compile error: %v", err)
   333  		return
   334  	}
   335  
   336  	env := Env{
   337  		A:   Decimal{3},
   338  		B:   Decimal{2},
   339  		C:   Decimal{1},
   340  		Sub: func(a, b Decimal) Decimal { return Decimal{a.N - b.N} },
   341  		Add: func(a, b Decimal) Decimal { return Decimal{a.N + b.N} },
   342  	}
   343  
   344  	output, err := expr.Run(program, env)
   345  	if err != nil {
   346  		fmt.Printf("%v", err)
   347  		return
   348  	}
   349  
   350  	fmt.Printf("%v", output)
   351  
   352  	// Output: {4}
   353  }
   354  
   355  func fib(n int) int {
   356  	if n <= 1 {
   357  		return n
   358  	}
   359  	return fib(n-1) + fib(n-2)
   360  }
   361  
   362  func ExampleConstExpr() {
   363  	code := `[fib(5), fib(3+3), fib(dyn)]`
   364  
   365  	env := map[string]any{
   366  		"fib": fib,
   367  		"dyn": 0,
   368  	}
   369  
   370  	options := []expr.Option{
   371  		expr.Env(env),
   372  		expr.ConstExpr("fib"), // Mark fib func as constant expression.
   373  	}
   374  
   375  	program, err := expr.Compile(code, options...)
   376  	if err != nil {
   377  		fmt.Printf("%v", err)
   378  		return
   379  	}
   380  
   381  	// Only fib(5) and fib(6) calculated on Compile, fib(dyn) can be called at runtime.
   382  	env["dyn"] = 7
   383  
   384  	output, err := expr.Run(program, env)
   385  	if err != nil {
   386  		fmt.Printf("%v", err)
   387  		return
   388  	}
   389  
   390  	fmt.Printf("%v\n", output)
   391  
   392  	// Output: [5 8 13]
   393  }
   394  
   395  func ExampleAllowUndefinedVariables() {
   396  	code := `name == nil ? "Hello, world!" : sprintf("Hello, %v!", name)`
   397  
   398  	env := map[string]any{
   399  		"sprintf": fmt.Sprintf,
   400  	}
   401  
   402  	options := []expr.Option{
   403  		expr.Env(env),
   404  		expr.AllowUndefinedVariables(), // Allow to use undefined variables.
   405  	}
   406  
   407  	program, err := expr.Compile(code, options...)
   408  	if err != nil {
   409  		fmt.Printf("%v", err)
   410  		return
   411  	}
   412  
   413  	output, err := expr.Run(program, env)
   414  	if err != nil {
   415  		fmt.Printf("%v", err)
   416  		return
   417  	}
   418  	fmt.Printf("%v\n", output)
   419  
   420  	env["name"] = "you" // Define variables later on.
   421  
   422  	output, err = expr.Run(program, env)
   423  	if err != nil {
   424  		fmt.Printf("%v", err)
   425  		return
   426  	}
   427  	fmt.Printf("%v\n", output)
   428  
   429  	// Output: Hello, world!
   430  	// Hello, you!
   431  }
   432  
   433  func ExampleAllowUndefinedVariables_zero_value() {
   434  	code := `name == "" ? foo + bar : foo + name`
   435  
   436  	// If environment has different zero values, then undefined variables
   437  	// will have it as default value.
   438  	env := map[string]string{}
   439  
   440  	options := []expr.Option{
   441  		expr.Env(env),
   442  		expr.AllowUndefinedVariables(), // Allow to use undefined variables.
   443  	}
   444  
   445  	program, err := expr.Compile(code, options...)
   446  	if err != nil {
   447  		fmt.Printf("%v", err)
   448  		return
   449  	}
   450  
   451  	env = map[string]string{
   452  		"foo": "Hello, ",
   453  		"bar": "world!",
   454  	}
   455  
   456  	output, err := expr.Run(program, env)
   457  	if err != nil {
   458  		fmt.Printf("%v", err)
   459  		return
   460  	}
   461  	fmt.Printf("%v", output)
   462  
   463  	// Output: Hello, world!
   464  }
   465  
   466  func ExampleAllowUndefinedVariables_zero_value_functions() {
   467  	code := `words == "" ? Split("foo,bar", ",") : Split(words, ",")`
   468  
   469  	// Env is map[string]string type on which methods are defined.
   470  	env := mock.MapStringStringEnv{}
   471  
   472  	options := []expr.Option{
   473  		expr.Env(env),
   474  		expr.AllowUndefinedVariables(), // Allow to use undefined variables.
   475  	}
   476  
   477  	program, err := expr.Compile(code, options...)
   478  	if err != nil {
   479  		fmt.Printf("%v", err)
   480  		return
   481  	}
   482  
   483  	output, err := expr.Run(program, env)
   484  	if err != nil {
   485  		fmt.Printf("%v", err)
   486  		return
   487  	}
   488  	fmt.Printf("%v", output)
   489  
   490  	// Output: [foo bar]
   491  }
   492  
   493  type patcher struct{}
   494  
   495  func (p *patcher) Visit(node *ast.Node) {
   496  	switch n := (*node).(type) {
   497  	case *ast.MemberNode:
   498  		ast.Patch(node, &ast.CallNode{
   499  			Callee:    &ast.IdentifierNode{Value: "get"},
   500  			Arguments: []ast.Node{n.Node, n.Property},
   501  		})
   502  	}
   503  }
   504  
   505  func ExamplePatch() {
   506  	/*
   507  		type patcher struct{}
   508  
   509  		func (p *patcher) Visit(node *ast.Node) {
   510  			switch n := (*node).(type) {
   511  			case *ast.MemberNode:
   512  				ast.Patch(node, &ast.CallNode{
   513  					Callee:    &ast.IdentifierNode{Value: "get"},
   514  					Arguments: []ast.Node{n.Node, n.Property},
   515  				})
   516  			}
   517  		}
   518  	*/
   519  
   520  	program, err := expr.Compile(
   521  		`greet.you.world + "!"`,
   522  		expr.Patch(&patcher{}),
   523  	)
   524  	if err != nil {
   525  		fmt.Printf("%v", err)
   526  		return
   527  	}
   528  
   529  	env := map[string]any{
   530  		"greet": "Hello",
   531  		"get": func(a, b string) string {
   532  			return a + ", " + b
   533  		},
   534  	}
   535  
   536  	output, err := expr.Run(program, env)
   537  	if err != nil {
   538  		fmt.Printf("%v", err)
   539  		return
   540  	}
   541  	fmt.Printf("%v", output)
   542  
   543  	// Output : Hello, you, world!
   544  }
   545  
   546  func ExampleWithContext() {
   547  	env := map[string]any{
   548  		"fn": func(ctx context.Context, _, _ int) int {
   549  			// An infinite loop that can be canceled by context.
   550  			for {
   551  				select {
   552  				case <-ctx.Done():
   553  					return 42
   554  				}
   555  			}
   556  		},
   557  		"ctx": context.TODO(), // Context should be passed as a variable.
   558  	}
   559  
   560  	program, err := expr.Compile(`fn(1, 2)`,
   561  		expr.Env(env),
   562  		expr.WithContext("ctx"), // Pass context variable name.
   563  	)
   564  	if err != nil {
   565  		fmt.Printf("%v", err)
   566  		return
   567  	}
   568  
   569  	// Cancel context after 100 milliseconds.
   570  	ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*100)
   571  	defer cancel()
   572  
   573  	// After program is compiled, context can be passed to Run.
   574  	env["ctx"] = ctx
   575  
   576  	// Run will return 42 after 100 milliseconds.
   577  	output, err := expr.Run(program, env)
   578  	if err != nil {
   579  		fmt.Printf("%v", err)
   580  		return
   581  	}
   582  
   583  	fmt.Printf("%v", output)
   584  	// Output: 42
   585  }
   586  
   587  func ExampleWithTimezone() {
   588  	program, err := expr.Compile(`now().Location().String()`, expr.Timezone("Asia/Kamchatka"))
   589  	if err != nil {
   590  		fmt.Printf("%v", err)
   591  		return
   592  	}
   593  
   594  	output, err := expr.Run(program, nil)
   595  	if err != nil {
   596  		fmt.Printf("%v", err)
   597  		return
   598  	}
   599  
   600  	fmt.Printf("%v", output)
   601  	// Output: Asia/Kamchatka
   602  }
   603  
   604  func TestExpr_readme_example(t *testing.T) {
   605  	env := map[string]any{
   606  		"greet":   "Hello, %v!",
   607  		"names":   []string{"world", "you"},
   608  		"sprintf": fmt.Sprintf,
   609  	}
   610  
   611  	code := `sprintf(greet, names[0])`
   612  
   613  	program, err := expr.Compile(code, expr.Env(env))
   614  	require.NoError(t, err)
   615  
   616  	output, err := expr.Run(program, env)
   617  	require.NoError(t, err)
   618  
   619  	require.Equal(t, "Hello, world!", output)
   620  }
   621  
   622  func TestExpr(t *testing.T) {
   623  	date := time.Date(2017, time.October, 23, 18, 30, 0, 0, time.UTC)
   624  	oneDay, _ := time.ParseDuration("24h")
   625  	timeNowPlusOneDay := date.Add(oneDay)
   626  
   627  	env := mock.Env{
   628  		Embed:     mock.Embed{},
   629  		Ambiguous: "",
   630  		Any:       nil,
   631  		Bool:      true,
   632  		Float:     0,
   633  		Int64:     0,
   634  		Int32:     0,
   635  		Int:       0,
   636  		One:       1,
   637  		Two:       2,
   638  		Uint32:    0,
   639  		String:    "string",
   640  		BoolPtr:   nil,
   641  		FloatPtr:  nil,
   642  		IntPtr:    nil,
   643  		IntPtrPtr: nil,
   644  		StringPtr: nil,
   645  		Foo: mock.Foo{
   646  			Value: "foo",
   647  			Bar: mock.Bar{
   648  				Baz: "baz",
   649  			},
   650  		},
   651  		Abstract:           nil,
   652  		ArrayOfAny:         nil,
   653  		ArrayOfInt:         []int{1, 2, 3, 4, 5},
   654  		ArrayOfFoo:         []*mock.Foo{{Value: "foo"}, {Value: "bar"}, {Value: "baz"}},
   655  		MapOfFoo:           nil,
   656  		MapOfAny:           nil,
   657  		FuncParam:          nil,
   658  		FuncParamAny:       nil,
   659  		FuncTooManyReturns: nil,
   660  		FuncNamed:          nil,
   661  		NilAny:             nil,
   662  		NilFn:              nil,
   663  		NilStruct:          nil,
   664  		Variadic: func(head int, xs ...int) bool {
   665  			sum := 0
   666  			for _, x := range xs {
   667  				sum += x
   668  			}
   669  			return head == sum
   670  		},
   671  		Fast:        nil,
   672  		Time:        date,
   673  		TimePlusDay: timeNowPlusOneDay,
   674  		Duration:    oneDay,
   675  	}
   676  
   677  	tests := []struct {
   678  		code string
   679  		want any
   680  	}{
   681  		{
   682  			`1`,
   683  			1,
   684  		},
   685  		{
   686  			`-.5`,
   687  			-.5,
   688  		},
   689  		{
   690  			`true && false || false`,
   691  			false,
   692  		},
   693  		{
   694  			`Int == 0 && Int32 == 0 && Int64 == 0 && Float64 == 0 && Bool && String == "string"`,
   695  			true,
   696  		},
   697  		{
   698  			`-Int64 == 0`,
   699  			true,
   700  		},
   701  		{
   702  			`"a" != "b"`,
   703  			true,
   704  		},
   705  		{
   706  			`"a" != "b" || 1 == 2`,
   707  			true,
   708  		},
   709  		{
   710  			`Int + 0`,
   711  			0,
   712  		},
   713  		{
   714  			`Uint64 + 0`,
   715  			0,
   716  		},
   717  		{
   718  			`Uint64 + Int64`,
   719  			0,
   720  		},
   721  		{
   722  			`Int32 + Int64`,
   723  			0,
   724  		},
   725  		{
   726  			`Float64 + 0`,
   727  			float64(0),
   728  		},
   729  		{
   730  			`0 + Float64`,
   731  			float64(0),
   732  		},
   733  		{
   734  			`0 <= Float64`,
   735  			true,
   736  		},
   737  		{
   738  			`Float64 < 1`,
   739  			true,
   740  		},
   741  		{
   742  			`Int < 1`,
   743  			true,
   744  		},
   745  		{
   746  			`2 + 2 == 4`,
   747  			true,
   748  		},
   749  		{
   750  			`8 % 3`,
   751  			2,
   752  		},
   753  		{
   754  			`2 ** 8`,
   755  			float64(256),
   756  		},
   757  		{
   758  			`2 ^ 8`,
   759  			float64(256),
   760  		},
   761  		{
   762  			`-(2-5)**3-2/(+4-3)+-2`,
   763  			float64(23),
   764  		},
   765  		{
   766  			`"hello" + " " + "world"`,
   767  			"hello world",
   768  		},
   769  		{
   770  			`0 in -1..1 and 1 in 1..1`,
   771  			true,
   772  		},
   773  		{
   774  			`Int in 0..1`,
   775  			true,
   776  		},
   777  		{
   778  			`Int32 in 0..1`,
   779  			true,
   780  		},
   781  		{
   782  			`Int64 in 0..1`,
   783  			true,
   784  		},
   785  		{
   786  			`1 in [1, 2, 3] && "foo" in {foo: 0, bar: 1} && "Bar" in Foo`,
   787  			true,
   788  		},
   789  		{
   790  			`1 in [1.5] || 1 not in [1]`,
   791  			false,
   792  		},
   793  		{
   794  			`One in 0..1 && Two not in 0..1`,
   795  			true,
   796  		},
   797  		{
   798  			`Two not in 0..1`,
   799  			true,
   800  		},
   801  		{
   802  			`Two not    in 0..1`,
   803  			true,
   804  		},
   805  		{
   806  			`-1 not in [1]`,
   807  			true,
   808  		},
   809  		{
   810  			`Int32 in [10, 20]`,
   811  			false,
   812  		},
   813  		{
   814  			`String matches "s.+"`,
   815  			true,
   816  		},
   817  		{
   818  			`String matches ("^" + String + "$")`,
   819  			true,
   820  		},
   821  		{
   822  			`'foo' + 'bar' not matches 'foobar'`,
   823  			false,
   824  		},
   825  		{
   826  			`"foobar" contains "bar"`,
   827  			true,
   828  		},
   829  		{
   830  			`"foobar" startsWith "foo"`,
   831  			true,
   832  		},
   833  		{
   834  			`"foobar" endsWith "bar"`,
   835  			true,
   836  		},
   837  		{
   838  			`(0..10)[5]`,
   839  			5,
   840  		},
   841  		{
   842  			`Foo.Bar.Baz`,
   843  			"baz",
   844  		},
   845  		{
   846  			`Add(10, 5) + GetInt()`,
   847  			15,
   848  		},
   849  		{
   850  			`Foo.Method().Baz`,
   851  			`baz (from Foo.Method)`,
   852  		},
   853  		{
   854  			`Foo.MethodWithArgs("prefix ")`,
   855  			"prefix foo",
   856  		},
   857  		{
   858  			`len([1, 2, 3])`,
   859  			3,
   860  		},
   861  		{
   862  			`len([1, Two, 3])`,
   863  			3,
   864  		},
   865  		{
   866  			`len(["hello", "world"])`,
   867  			2,
   868  		},
   869  		{
   870  			`len("hello, world")`,
   871  			12,
   872  		},
   873  		{
   874  			`len(ArrayOfInt)`,
   875  			5,
   876  		},
   877  		{
   878  			`len({a: 1, b: 2, c: 2})`,
   879  			3,
   880  		},
   881  		{
   882  			`max([1, 2, 3])`,
   883  			3,
   884  		},
   885  		{
   886  			`max(1, 2, 3)`,
   887  			3,
   888  		},
   889  		{
   890  			`min([1, 2, 3])`,
   891  			1,
   892  		},
   893  		{
   894  			`min(1, 2, 3)`,
   895  			1,
   896  		},
   897  		{
   898  			`{foo: 0, bar: 1}`,
   899  			map[string]any{"foo": 0, "bar": 1},
   900  		},
   901  		{
   902  			`{foo: 0, bar: 1}`,
   903  			map[string]any{"foo": 0, "bar": 1},
   904  		},
   905  		{
   906  			`(true ? 0+1 : 2+3) + (false ? -1 : -2)`,
   907  			-1,
   908  		},
   909  		{
   910  			`filter(1..9, {# > 7})`,
   911  			[]any{8, 9},
   912  		},
   913  		{
   914  			`map(1..3, {# * #})`,
   915  			[]any{1, 4, 9},
   916  		},
   917  		{
   918  			`all(1..3, {# > 0})`,
   919  			true,
   920  		},
   921  		{
   922  			`count(1..30, {# % 3 == 0})`,
   923  			10,
   924  		},
   925  		{
   926  			`count([true, true, false])`,
   927  			2,
   928  		},
   929  		{
   930  			`"a" < "b"`,
   931  			true,
   932  		},
   933  		{
   934  			`Time.Sub(Time).String() == "0s"`,
   935  			true,
   936  		},
   937  		{
   938  			`1 + 1`,
   939  			2,
   940  		},
   941  		{
   942  			`(One * Two) * 3 == One * (Two * 3)`,
   943  			true,
   944  		},
   945  		{
   946  			`ArrayOfInt[1]`,
   947  			2,
   948  		},
   949  		{
   950  			`ArrayOfInt[0] < ArrayOfInt[1]`,
   951  			true,
   952  		},
   953  		{
   954  			`ArrayOfInt[-1]`,
   955  			5,
   956  		},
   957  		{
   958  			`ArrayOfInt[1:2]`,
   959  			[]int{2},
   960  		},
   961  		{
   962  			`ArrayOfInt[1:4]`,
   963  			[]int{2, 3, 4},
   964  		},
   965  		{
   966  			`ArrayOfInt[-4:-1]`,
   967  			[]int{2, 3, 4},
   968  		},
   969  		{
   970  			`ArrayOfInt[:3]`,
   971  			[]int{1, 2, 3},
   972  		},
   973  		{
   974  			`ArrayOfInt[3:]`,
   975  			[]int{4, 5},
   976  		},
   977  		{
   978  			`ArrayOfInt[0:5] == ArrayOfInt`,
   979  			true,
   980  		},
   981  		{
   982  			`ArrayOfInt[0:] == ArrayOfInt`,
   983  			true,
   984  		},
   985  		{
   986  			`ArrayOfInt[:5] == ArrayOfInt`,
   987  			true,
   988  		},
   989  		{
   990  			`ArrayOfInt[:] == ArrayOfInt`,
   991  			true,
   992  		},
   993  		{
   994  			`4 in 5..1`,
   995  			false,
   996  		},
   997  		{
   998  			`4..0`,
   999  			[]int{},
  1000  		},
  1001  		{
  1002  			`NilStruct`,
  1003  			(*mock.Foo)(nil),
  1004  		},
  1005  		{
  1006  			`NilAny == nil && nil == NilAny && nil == nil && NilAny == NilAny && NilInt == nil && NilSlice == nil && NilStruct == nil`,
  1007  			true,
  1008  		},
  1009  		{
  1010  			`0 == nil || "str" == nil || true == nil`,
  1011  			false,
  1012  		},
  1013  		{
  1014  			`Variadic(6, 1, 2, 3)`,
  1015  			true,
  1016  		},
  1017  		{
  1018  			`Variadic(0)`,
  1019  			true,
  1020  		},
  1021  		{
  1022  			`String[:]`,
  1023  			"string",
  1024  		},
  1025  		{
  1026  			`String[:3]`,
  1027  			"str",
  1028  		},
  1029  		{
  1030  			`String[:9]`,
  1031  			"string",
  1032  		},
  1033  		{
  1034  			`String[3:9]`,
  1035  			"ing",
  1036  		},
  1037  		{
  1038  			`String[7:9]`,
  1039  			"",
  1040  		},
  1041  		{
  1042  			`map(filter(ArrayOfInt, # >= 3), # + 1)`,
  1043  			[]any{4, 5, 6},
  1044  		},
  1045  		{
  1046  			`Time < Time + Duration`,
  1047  			true,
  1048  		},
  1049  		{
  1050  			`Time + Duration > Time`,
  1051  			true,
  1052  		},
  1053  		{
  1054  			`Time == Time`,
  1055  			true,
  1056  		},
  1057  		{
  1058  			`Time >= Time`,
  1059  			true,
  1060  		},
  1061  		{
  1062  			`Time <= Time`,
  1063  			true,
  1064  		},
  1065  		{
  1066  			`Time == Time + Duration`,
  1067  			false,
  1068  		},
  1069  		{
  1070  			`Time != Time`,
  1071  			false,
  1072  		},
  1073  		{
  1074  			`TimePlusDay - Duration`,
  1075  			date,
  1076  		},
  1077  		{
  1078  			`duration("1h") == duration("1h")`,
  1079  			true,
  1080  		},
  1081  		{
  1082  			`TimePlusDay - Time >= duration("24h")`,
  1083  			true,
  1084  		},
  1085  		{
  1086  			`duration("1h") > duration("1m")`,
  1087  			true,
  1088  		},
  1089  		{
  1090  			`duration("1h") < duration("1m")`,
  1091  			false,
  1092  		},
  1093  		{
  1094  			`duration("1h") >= duration("1m")`,
  1095  			true,
  1096  		},
  1097  		{
  1098  			`duration("1h") <= duration("1m")`,
  1099  			false,
  1100  		},
  1101  		{
  1102  			`duration("1h") > duration("1m")`,
  1103  			true,
  1104  		},
  1105  		{
  1106  			`duration("1h") + duration("1m")`,
  1107  			time.Hour + time.Minute,
  1108  		},
  1109  		{
  1110  			`7 * duration("1h")`,
  1111  			7 * time.Hour,
  1112  		},
  1113  		{
  1114  			`duration("1h") * 7`,
  1115  			7 * time.Hour,
  1116  		},
  1117  		{
  1118  			`duration("1s") * .5`,
  1119  			5e8,
  1120  		},
  1121  		{
  1122  			`1 /* one */ + 2 // two`,
  1123  			3,
  1124  		},
  1125  		{
  1126  			`let x = 1; x + 2`,
  1127  			3,
  1128  		},
  1129  		{
  1130  			`map(1..3, let x = #; let y = x * x; y * y)`,
  1131  			[]any{1, 16, 81},
  1132  		},
  1133  		{
  1134  			`map(1..2, let x = #; map(2..3, let y = #; x + y))`,
  1135  			[]any{[]any{3, 4}, []any{4, 5}},
  1136  		},
  1137  		{
  1138  			`len(filter(1..99, # % 7 == 0))`,
  1139  			14,
  1140  		},
  1141  		{
  1142  			`find(ArrayOfFoo, .Value == "baz")`,
  1143  			env.ArrayOfFoo[2],
  1144  		},
  1145  		{
  1146  			`findIndex(ArrayOfFoo, .Value == "baz")`,
  1147  			2,
  1148  		},
  1149  		{
  1150  			`filter(ArrayOfFoo, .Value == "baz")[0]`,
  1151  			env.ArrayOfFoo[2],
  1152  		},
  1153  		{
  1154  			`first(filter(ArrayOfFoo, .Value == "baz"))`,
  1155  			env.ArrayOfFoo[2],
  1156  		},
  1157  		{
  1158  			`first(filter(ArrayOfFoo, false))`,
  1159  			nil,
  1160  		},
  1161  		{
  1162  			`findLast(1..9, # % 2 == 0)`,
  1163  			8,
  1164  		},
  1165  		{
  1166  			`findLastIndex(1..9, # % 2 == 0)`,
  1167  			7,
  1168  		},
  1169  		{
  1170  			`filter(1..9, # % 2 == 0)[-1]`,
  1171  			8,
  1172  		},
  1173  		{
  1174  			`last(filter(1..9, # % 2 == 0))`,
  1175  			8,
  1176  		},
  1177  		{
  1178  			`map(filter(1..9, # % 2 == 0), # * 2)`,
  1179  			[]any{4, 8, 12, 16},
  1180  		},
  1181  		{
  1182  			`map(map(filter(1..9, # % 2 == 0), # * 2), # * 2)`,
  1183  			[]any{8, 16, 24, 32},
  1184  		},
  1185  		{
  1186  			`first(map(filter(1..9, # % 2 == 0), # * 2))`,
  1187  			4,
  1188  		},
  1189  		{
  1190  			`map(filter(1..9, # % 2 == 0), # * 2)[-1]`,
  1191  			16,
  1192  		},
  1193  		{
  1194  			`len(map(filter(1..9, # % 2 == 0), # * 2))`,
  1195  			4,
  1196  		},
  1197  		{
  1198  			`len(filter(map(1..9, # * 2), # % 2 == 0))`,
  1199  			9,
  1200  		},
  1201  		{
  1202  			`first(filter(map(1..9, # * 2), # % 2 == 0))`,
  1203  			2,
  1204  		},
  1205  		{
  1206  			`first(map(filter(1..9, # % 2 == 0), # * 2))`,
  1207  			4,
  1208  		},
  1209  		{
  1210  			`2^3 == 8`,
  1211  			true,
  1212  		},
  1213  		{
  1214  			`4/2 == 2`,
  1215  			true,
  1216  		},
  1217  		{
  1218  			`.5 in 0..1`,
  1219  			false,
  1220  		},
  1221  		{
  1222  			`.5 in ArrayOfInt`,
  1223  			false,
  1224  		},
  1225  		{
  1226  			`bitnot(10)`,
  1227  			-11,
  1228  		},
  1229  		{
  1230  			`bitxor(15, 32)`,
  1231  			47,
  1232  		},
  1233  		{
  1234  			`bitand(90, 34)`,
  1235  			2,
  1236  		},
  1237  		{
  1238  			`bitnand(35, 9)`,
  1239  			34,
  1240  		},
  1241  		{
  1242  			`bitor(10, 5)`,
  1243  			15,
  1244  		},
  1245  		{
  1246  			`bitshr(7, 2)`,
  1247  			1,
  1248  		},
  1249  		{
  1250  			`bitshl(7, 2)`,
  1251  			28,
  1252  		},
  1253  		{
  1254  			`bitushr(-100, 5)`,
  1255  			576460752303423484,
  1256  		},
  1257  		{
  1258  			`"hello"[1:3]`,
  1259  			"el",
  1260  		},
  1261  		{
  1262  			`[1, 2, 3]?.[0]`,
  1263  			1,
  1264  		},
  1265  		{
  1266  			`[[1, 2], 3, 4]?.[0]?.[1]`,
  1267  			2,
  1268  		},
  1269  		{
  1270  			`[nil, 3, 4]?.[0]?.[1]`,
  1271  			nil,
  1272  		},
  1273  		{
  1274  			`1 > 2 < 3`,
  1275  			false,
  1276  		},
  1277  		{
  1278  			`1 < 2 < 3`,
  1279  			true,
  1280  		},
  1281  		{
  1282  			`1 < 2 < 3 > 4`,
  1283  			false,
  1284  		},
  1285  		{
  1286  			`1 < 2 < 3 > 2`,
  1287  			true,
  1288  		},
  1289  		{
  1290  			`1 < 2 < 3 == true`,
  1291  			true,
  1292  		},
  1293  	}
  1294  
  1295  	for _, tt := range tests {
  1296  		t.Run(tt.code, func(t *testing.T) {
  1297  			{
  1298  				program, err := expr.Compile(tt.code, expr.Env(mock.Env{}))
  1299  				require.NoError(t, err, "compile error")
  1300  
  1301  				got, err := expr.Run(program, env)
  1302  				require.NoError(t, err, "run error")
  1303  				assert.Equal(t, tt.want, got)
  1304  			}
  1305  			{
  1306  				program, err := expr.Compile(tt.code, expr.Optimize(false))
  1307  				require.NoError(t, err, "unoptimized")
  1308  
  1309  				got, err := expr.Run(program, env)
  1310  				require.NoError(t, err, "unoptimized")
  1311  				assert.Equal(t, tt.want, got, "unoptimized")
  1312  			}
  1313  			{
  1314  				got, err := expr.Eval(tt.code, env)
  1315  				require.NoError(t, err, "eval")
  1316  				assert.Equal(t, tt.want, got, "eval")
  1317  			}
  1318  			{
  1319  				program, err := expr.Compile(tt.code, expr.Env(mock.Env{}), expr.Optimize(false))
  1320  				require.NoError(t, err)
  1321  
  1322  				code := program.Node().String()
  1323  				got, err := expr.Eval(code, env)
  1324  				require.NoError(t, err, code)
  1325  				assert.Equal(t, tt.want, got, code)
  1326  			}
  1327  		})
  1328  	}
  1329  }
  1330  
  1331  func TestExpr_error(t *testing.T) {
  1332  	env := mock.Env{
  1333  		ArrayOfAny: []any{1, "2", 3, true},
  1334  	}
  1335  
  1336  	tests := []struct {
  1337  		code string
  1338  		want string
  1339  	}{
  1340  		{
  1341  			`filter(1..9, # > 9)[0]`,
  1342  			`reflect: slice index out of range (1:20)
  1343   | filter(1..9, # > 9)[0]
  1344   | ...................^`,
  1345  		},
  1346  		{
  1347  			`ArrayOfAny[-7]`,
  1348  			`index out of range: -3 (array length is 4) (1:11)
  1349   | ArrayOfAny[-7]
  1350   | ..........^`,
  1351  		},
  1352  	}
  1353  
  1354  	for _, tt := range tests {
  1355  		t.Run(tt.code, func(t *testing.T) {
  1356  			program, err := expr.Compile(tt.code, expr.Env(mock.Env{}))
  1357  			require.NoError(t, err)
  1358  
  1359  			_, err = expr.Run(program, env)
  1360  			require.Error(t, err)
  1361  			assert.Equal(t, tt.want, err.Error())
  1362  		})
  1363  	}
  1364  }
  1365  
  1366  func TestExpr_optional_chaining(t *testing.T) {
  1367  	env := map[string]any{}
  1368  	program, err := expr.Compile("foo?.bar.baz", expr.Env(env), expr.AllowUndefinedVariables())
  1369  	require.NoError(t, err)
  1370  
  1371  	got, err := expr.Run(program, env)
  1372  	require.NoError(t, err)
  1373  	assert.Equal(t, nil, got)
  1374  }
  1375  
  1376  func TestExpr_optional_chaining_property(t *testing.T) {
  1377  	env := map[string]any{
  1378  		"foo": map[string]any{},
  1379  	}
  1380  	program, err := expr.Compile("foo.bar?.baz", expr.Env(env))
  1381  	require.NoError(t, err)
  1382  
  1383  	got, err := expr.Run(program, env)
  1384  	require.NoError(t, err)
  1385  	assert.Equal(t, nil, got)
  1386  }
  1387  
  1388  func TestExpr_optional_chaining_nested_chains(t *testing.T) {
  1389  	env := map[string]any{
  1390  		"foo": map[string]any{
  1391  			"id": 1,
  1392  			"bar": []map[string]any{
  1393  				1: {
  1394  					"baz": "baz",
  1395  				},
  1396  			},
  1397  		},
  1398  	}
  1399  	program, err := expr.Compile("foo?.bar[foo?.id]?.baz", expr.Env(env))
  1400  	require.NoError(t, err)
  1401  
  1402  	got, err := expr.Run(program, env)
  1403  	require.NoError(t, err)
  1404  	assert.Equal(t, "baz", got)
  1405  }
  1406  
  1407  func TestExpr_optional_chaining_array(t *testing.T) {
  1408  	env := map[string]any{}
  1409  	program, err := expr.Compile("foo?.[1]?.[2]?.[3]", expr.Env(env), expr.AllowUndefinedVariables())
  1410  	require.NoError(t, err)
  1411  
  1412  	got, err := expr.Run(program, env)
  1413  	require.NoError(t, err)
  1414  	assert.Equal(t, nil, got)
  1415  }
  1416  
  1417  func TestExpr_eval_with_env(t *testing.T) {
  1418  	_, err := expr.Eval("true", expr.Env(map[string]any{}))
  1419  	assert.Error(t, err)
  1420  	assert.Contains(t, err.Error(), "misused")
  1421  }
  1422  
  1423  func TestExpr_fetch_from_func(t *testing.T) {
  1424  	_, err := expr.Eval("foo.Value", map[string]any{
  1425  		"foo": func() {},
  1426  	})
  1427  	assert.Error(t, err)
  1428  	assert.Contains(t, err.Error(), "cannot fetch Value from func()")
  1429  }
  1430  
  1431  func TestExpr_map_default_values(t *testing.T) {
  1432  	env := map[string]any{
  1433  		"foo": map[string]string{},
  1434  		"bar": map[string]*string{},
  1435  	}
  1436  
  1437  	input := `foo['missing'] == '' && bar['missing'] == nil`
  1438  
  1439  	program, err := expr.Compile(input, expr.Env(env))
  1440  	require.NoError(t, err)
  1441  
  1442  	output, err := expr.Run(program, env)
  1443  	require.NoError(t, err)
  1444  	require.Equal(t, true, output)
  1445  }
  1446  
  1447  func TestExpr_map_default_values_compile_check(t *testing.T) {
  1448  	tests := []struct {
  1449  		env   any
  1450  		input string
  1451  	}{
  1452  		{
  1453  			mock.MapStringStringEnv{"foo": "bar"},
  1454  			`Split(foo, sep)`,
  1455  		},
  1456  		{
  1457  			mock.MapStringIntEnv{"foo": 1},
  1458  			`foo / bar`,
  1459  		},
  1460  	}
  1461  	for _, tt := range tests {
  1462  		_, err := expr.Compile(tt.input, expr.Env(tt.env), expr.AllowUndefinedVariables())
  1463  		require.NoError(t, err)
  1464  	}
  1465  }
  1466  
  1467  func TestExpr_calls_with_nil(t *testing.T) {
  1468  	env := map[string]any{
  1469  		"equals": func(a, b any) any {
  1470  			assert.Nil(t, a, "a is not nil")
  1471  			assert.Nil(t, b, "b is not nil")
  1472  			return a == b
  1473  		},
  1474  		"is": mock.Is{},
  1475  	}
  1476  
  1477  	p, err := expr.Compile(
  1478  		"a == nil && equals(b, nil) && is.Nil(c)",
  1479  		expr.Env(env),
  1480  		expr.Operator("==", "equals"),
  1481  		expr.AllowUndefinedVariables(),
  1482  	)
  1483  	require.NoError(t, err)
  1484  
  1485  	out, err := expr.Run(p, env)
  1486  	require.NoError(t, err)
  1487  	require.Equal(t, true, out)
  1488  }
  1489  
  1490  func TestExpr_call_float_arg_func_with_int(t *testing.T) {
  1491  	env := map[string]any{
  1492  		"cnv": func(f float64) any {
  1493  			return f
  1494  		},
  1495  	}
  1496  	tests := []struct {
  1497  		input    string
  1498  		expected float64
  1499  	}{
  1500  		{"-1", -1.0},
  1501  		{"1+1", 2.0},
  1502  		{"+1", 1.0},
  1503  		{"1-1", 0.0},
  1504  		{"1/1", 1.0},
  1505  		{"1*1", 1.0},
  1506  		{"1^1", 1.0},
  1507  	}
  1508  	for _, tt := range tests {
  1509  		t.Run(tt.input, func(t *testing.T) {
  1510  			p, err := expr.Compile(fmt.Sprintf("cnv(%s)", tt.input), expr.Env(env))
  1511  			require.NoError(t, err)
  1512  
  1513  			out, err := expr.Run(p, env)
  1514  			require.NoError(t, err)
  1515  			require.Equal(t, tt.expected, out)
  1516  		})
  1517  	}
  1518  }
  1519  
  1520  func TestConstExpr_error_panic(t *testing.T) {
  1521  	env := map[string]any{
  1522  		"divide": func(a, b int) int { return a / b },
  1523  	}
  1524  
  1525  	_, err := expr.Compile(
  1526  		`1 + divide(1, 0)`,
  1527  		expr.Env(env),
  1528  		expr.ConstExpr("divide"),
  1529  	)
  1530  	require.Error(t, err)
  1531  	require.Equal(t, "compile error: integer divide by zero (1:5)\n | 1 + divide(1, 0)\n | ....^", err.Error())
  1532  }
  1533  
  1534  type divideError struct{ Message string }
  1535  
  1536  func (e divideError) Error() string {
  1537  	return e.Message
  1538  }
  1539  
  1540  func TestConstExpr_error_as_error(t *testing.T) {
  1541  	env := map[string]any{
  1542  		"divide": func(a, b int) (int, error) {
  1543  			if b == 0 {
  1544  				return 0, divideError{"integer divide by zero"}
  1545  			}
  1546  			return a / b, nil
  1547  		},
  1548  	}
  1549  
  1550  	_, err := expr.Compile(
  1551  		`1 + divide(1, 0)`,
  1552  		expr.Env(env),
  1553  		expr.ConstExpr("divide"),
  1554  	)
  1555  	require.Error(t, err)
  1556  	require.Equal(t, "integer divide by zero", err.Error())
  1557  	require.IsType(t, divideError{}, err)
  1558  }
  1559  
  1560  func TestConstExpr_error_wrong_type(t *testing.T) {
  1561  	env := map[string]any{
  1562  		"divide": 0,
  1563  	}
  1564  	assert.Panics(t, func() {
  1565  		_, _ = expr.Compile(
  1566  			`1 + divide(1, 0)`,
  1567  			expr.Env(env),
  1568  			expr.ConstExpr("divide"),
  1569  		)
  1570  	})
  1571  }
  1572  
  1573  func TestConstExpr_error_no_env(t *testing.T) {
  1574  	assert.Panics(t, func() {
  1575  		_, _ = expr.Compile(
  1576  			`1 + divide(1, 0)`,
  1577  			expr.ConstExpr("divide"),
  1578  		)
  1579  	})
  1580  }
  1581  
  1582  var stringer = reflect.TypeOf((*fmt.Stringer)(nil)).Elem()
  1583  
  1584  type stringerPatcher struct{}
  1585  
  1586  func (p *stringerPatcher) Visit(node *ast.Node) {
  1587  	t := (*node).Type()
  1588  	if t == nil {
  1589  		return
  1590  	}
  1591  	if t.Implements(stringer) {
  1592  		ast.Patch(node, &ast.CallNode{
  1593  			Callee: &ast.MemberNode{
  1594  				Node:     *node,
  1595  				Property: &ast.StringNode{Value: "String"},
  1596  			},
  1597  		})
  1598  	}
  1599  }
  1600  
  1601  func TestPatch(t *testing.T) {
  1602  	program, err := expr.Compile(
  1603  		`Foo == "Foo.String"`,
  1604  		expr.Env(mock.Env{}),
  1605  		expr.Patch(&mock.StringerPatcher{}),
  1606  	)
  1607  	require.NoError(t, err)
  1608  
  1609  	output, err := expr.Run(program, mock.Env{})
  1610  	require.NoError(t, err)
  1611  	require.Equal(t, true, output)
  1612  }
  1613  
  1614  func TestCompile_exposed_error(t *testing.T) {
  1615  	_, err := expr.Compile(`1 == true`)
  1616  	require.Error(t, err)
  1617  
  1618  	fileError, ok := err.(*file.Error)
  1619  	require.True(t, ok, "error should be of type *file.Error")
  1620  	require.Equal(t, "invalid operation: == (mismatched types int and bool) (1:3)\n | 1 == true\n | ..^", fileError.Error())
  1621  	require.Equal(t, 2, fileError.Column)
  1622  	require.Equal(t, 1, fileError.Line)
  1623  
  1624  	b, err := json.Marshal(err)
  1625  	require.NoError(t, err)
  1626  	require.Equal(t,
  1627  		`{"from":2,"to":4,"line":1,"column":2,"message":"invalid operation: == (mismatched types int and bool)","snippet":"\n | 1 == true\n | ..^","prev":null}`,
  1628  		string(b),
  1629  	)
  1630  }
  1631  
  1632  func TestAsBool_exposed_error(t *testing.T) {
  1633  	_, err := expr.Compile(`42`, expr.AsBool())
  1634  	require.Error(t, err)
  1635  
  1636  	_, ok := err.(*file.Error)
  1637  	require.False(t, ok, "error must not be of type *file.Error")
  1638  	require.Equal(t, "expected bool, but got int", err.Error())
  1639  }
  1640  
  1641  func TestEval_exposed_error(t *testing.T) {
  1642  	_, err := expr.Eval(`1 % 0`, nil)
  1643  	require.Error(t, err)
  1644  
  1645  	fileError, ok := err.(*file.Error)
  1646  	require.True(t, ok, "error should be of type *file.Error")
  1647  	require.Equal(t, "integer divide by zero (1:3)\n | 1 % 0\n | ..^", fileError.Error())
  1648  	require.Equal(t, 2, fileError.Column)
  1649  	require.Equal(t, 1, fileError.Line)
  1650  }
  1651  
  1652  func TestIssue105(t *testing.T) {
  1653  	type A struct {
  1654  		Field string
  1655  	}
  1656  	type B struct {
  1657  		Field int
  1658  	}
  1659  	type C struct {
  1660  		A
  1661  		B
  1662  	}
  1663  	type Env struct {
  1664  		C
  1665  	}
  1666  
  1667  	code := `
  1668  		A.Field == '' &&
  1669  		C.A.Field == '' &&
  1670  		B.Field == 0 &&
  1671  		C.B.Field == 0
  1672  	`
  1673  
  1674  	_, err := expr.Compile(code, expr.Env(Env{}))
  1675  	require.NoError(t, err)
  1676  
  1677  	_, err = expr.Compile(`Field == ''`, expr.Env(Env{}))
  1678  	require.Error(t, err)
  1679  	require.Contains(t, err.Error(), "ambiguous identifier Field")
  1680  }
  1681  
  1682  func TestIssue_nested_closures(t *testing.T) {
  1683  	code := `all(1..3, { all(1..3, { # > 0 }) and # > 0 })`
  1684  
  1685  	program, err := expr.Compile(code)
  1686  	require.NoError(t, err)
  1687  
  1688  	output, err := expr.Run(program, nil)
  1689  	require.NoError(t, err)
  1690  	require.True(t, output.(bool))
  1691  }
  1692  
  1693  func TestIssue138(t *testing.T) {
  1694  	env := map[string]any{}
  1695  
  1696  	_, err := expr.Compile(`1 / (1 - 1)`, expr.Env(env))
  1697  	require.NoError(t, err)
  1698  
  1699  	_, err = expr.Compile(`1 % 0`, expr.Env(env))
  1700  	require.Error(t, err)
  1701  	require.Equal(t, "integer divide by zero (1:3)\n | 1 % 0\n | ..^", err.Error())
  1702  }
  1703  
  1704  func TestIssue154(t *testing.T) {
  1705  	type Data struct {
  1706  		Array  *[2]any
  1707  		Slice  *[]any
  1708  		Map    *map[string]any
  1709  		String *string
  1710  	}
  1711  
  1712  	type Env struct {
  1713  		Data *Data
  1714  	}
  1715  
  1716  	b := true
  1717  	i := 10
  1718  	s := "value"
  1719  
  1720  	Array := [2]any{
  1721  		&b,
  1722  		&i,
  1723  	}
  1724  
  1725  	Slice := []any{
  1726  		&b,
  1727  		&i,
  1728  	}
  1729  
  1730  	Map := map[string]any{
  1731  		"Bool": &b,
  1732  		"Int":  &i,
  1733  	}
  1734  
  1735  	env := Env{
  1736  		Data: &Data{
  1737  			Array:  &Array,
  1738  			Slice:  &Slice,
  1739  			Map:    &Map,
  1740  			String: &s,
  1741  		},
  1742  	}
  1743  
  1744  	tests := []string{
  1745  		`Data.Array[0] == true`,
  1746  		`Data.Array[1] == 10`,
  1747  		`Data.Slice[0] == true`,
  1748  		`Data.Slice[1] == 10`,
  1749  		`Data.Map["Bool"] == true`,
  1750  		`Data.Map["Int"] == 10`,
  1751  		`Data.String == "value"`,
  1752  	}
  1753  
  1754  	for _, input := range tests {
  1755  		program, err := expr.Compile(input, expr.Env(env))
  1756  		require.NoError(t, err, input)
  1757  
  1758  		output, err := expr.Run(program, env)
  1759  		require.NoError(t, err)
  1760  		assert.True(t, output.(bool), input)
  1761  	}
  1762  }
  1763  
  1764  func TestIssue270(t *testing.T) {
  1765  	env := map[string]any{
  1766  		"int8":     int8(1),
  1767  		"int16":    int16(3),
  1768  		"int32":    int32(5),
  1769  		"int64":    int64(7),
  1770  		"uint8":    uint8(11),
  1771  		"uint16":   uint16(13),
  1772  		"uint32":   uint32(17),
  1773  		"uint64":   uint64(19),
  1774  		"int8a":    uint(23),
  1775  		"int8b":    uint(29),
  1776  		"int16a":   uint(31),
  1777  		"int16b":   uint(37),
  1778  		"int32a":   uint(41),
  1779  		"int32b":   uint(43),
  1780  		"int64a":   uint(47),
  1781  		"int64b":   uint(53),
  1782  		"uint8a":   uint(59),
  1783  		"uint8b":   uint(61),
  1784  		"uint16a":  uint(67),
  1785  		"uint16b":  uint(71),
  1786  		"uint32a":  uint(73),
  1787  		"uint32b":  uint(79),
  1788  		"uint64a":  uint(83),
  1789  		"uint64b":  uint(89),
  1790  		"float32a": float32(97),
  1791  		"float32b": float32(101),
  1792  		"float64a": float64(103),
  1793  		"float64b": float64(107),
  1794  	}
  1795  	for _, each := range []struct {
  1796  		input string
  1797  	}{
  1798  		{"int8 / int16"},
  1799  		{"int32 / int64"},
  1800  		{"uint8 / uint16"},
  1801  		{"uint32 / uint64"},
  1802  		{"int8 / uint64"},
  1803  		{"int64 / uint8"},
  1804  		{"int8a / int8b"},
  1805  		{"int16a / int16b"},
  1806  		{"int32a / int32b"},
  1807  		{"int64a / int64b"},
  1808  		{"uint8a / uint8b"},
  1809  		{"uint16a / uint16b"},
  1810  		{"uint32a / uint32b"},
  1811  		{"uint64a / uint64b"},
  1812  		{"float32a / float32b"},
  1813  		{"float64a / float64b"},
  1814  	} {
  1815  		p, err := expr.Compile(each.input, expr.Env(env))
  1816  		require.NoError(t, err)
  1817  
  1818  		out, err := expr.Run(p, env)
  1819  		require.NoError(t, err)
  1820  		require.IsType(t, float64(0), out)
  1821  	}
  1822  }
  1823  
  1824  func TestIssue271(t *testing.T) {
  1825  	type BarArray []float64
  1826  
  1827  	type Foo struct {
  1828  		Bar BarArray
  1829  		Baz int
  1830  	}
  1831  
  1832  	type Env struct {
  1833  		Foo Foo
  1834  	}
  1835  
  1836  	code := `Foo.Bar[0]`
  1837  
  1838  	program, err := expr.Compile(code, expr.Env(Env{}))
  1839  	require.NoError(t, err)
  1840  
  1841  	output, err := expr.Run(program, Env{
  1842  		Foo: Foo{
  1843  			Bar: BarArray{1.0, 2.0, 3.0},
  1844  		},
  1845  	})
  1846  	require.NoError(t, err)
  1847  	require.Equal(t, 1.0, output)
  1848  }
  1849  
  1850  type Issue346Array []Issue346Type
  1851  
  1852  type Issue346Type struct {
  1853  	Bar string
  1854  }
  1855  
  1856  func (i Issue346Array) Len() int {
  1857  	return len(i)
  1858  }
  1859  
  1860  func TestIssue346(t *testing.T) {
  1861  	code := `Foo[0].Bar`
  1862  
  1863  	env := map[string]any{
  1864  		"Foo": Issue346Array{
  1865  			{Bar: "bar"},
  1866  		},
  1867  	}
  1868  	program, err := expr.Compile(code, expr.Env(env))
  1869  	require.NoError(t, err)
  1870  
  1871  	output, err := expr.Run(program, env)
  1872  	require.NoError(t, err)
  1873  	require.Equal(t, "bar", output)
  1874  }
  1875  
  1876  func TestCompile_allow_to_use_interface_to_get_an_element_from_map(t *testing.T) {
  1877  	code := `{"value": "ok"}[vars.key]`
  1878  	env := map[string]any{
  1879  		"vars": map[string]any{
  1880  			"key": "value",
  1881  		},
  1882  	}
  1883  
  1884  	program, err := expr.Compile(code, expr.Env(env))
  1885  	assert.NoError(t, err)
  1886  
  1887  	out, err := expr.Run(program, env)
  1888  	assert.NoError(t, err)
  1889  	assert.Equal(t, "ok", out)
  1890  
  1891  	t.Run("with allow undefined variables", func(t *testing.T) {
  1892  		code := `{'key': 'value'}[Key]`
  1893  		env := mock.MapStringStringEnv{}
  1894  		options := []expr.Option{
  1895  			expr.AllowUndefinedVariables(),
  1896  		}
  1897  
  1898  		program, err := expr.Compile(code, options...)
  1899  		assert.NoError(t, err)
  1900  
  1901  		out, err := expr.Run(program, env)
  1902  		assert.NoError(t, err)
  1903  		assert.Equal(t, nil, out)
  1904  	})
  1905  }
  1906  
  1907  func TestFastCall(t *testing.T) {
  1908  	env := map[string]any{
  1909  		"func": func(in any) float64 {
  1910  			return 8
  1911  		},
  1912  	}
  1913  	code := `func("8")`
  1914  
  1915  	program, err := expr.Compile(code, expr.Env(env))
  1916  	assert.NoError(t, err)
  1917  
  1918  	out, err := expr.Run(program, env)
  1919  	assert.NoError(t, err)
  1920  	assert.Equal(t, float64(8), out)
  1921  }
  1922  
  1923  func TestFastCall_OpCallFastErr(t *testing.T) {
  1924  	env := map[string]any{
  1925  		"func": func(...any) (any, error) {
  1926  			return 8, nil
  1927  		},
  1928  	}
  1929  	code := `func("8")`
  1930  
  1931  	program, err := expr.Compile(code, expr.Env(env))
  1932  	assert.NoError(t, err)
  1933  
  1934  	out, err := expr.Run(program, env)
  1935  	assert.NoError(t, err)
  1936  	assert.Equal(t, 8, out)
  1937  }
  1938  
  1939  func TestRun_custom_func_returns_an_error_as_second_arg(t *testing.T) {
  1940  	env := map[string]any{
  1941  		"semver": func(value string, cmp string) (bool, error) { return true, nil },
  1942  	}
  1943  
  1944  	p, err := expr.Compile(`semver("1.2.3", "= 1.2.3")`, expr.Env(env))
  1945  	assert.NoError(t, err)
  1946  
  1947  	out, err := expr.Run(p, env)
  1948  	assert.NoError(t, err)
  1949  	assert.Equal(t, true, out)
  1950  }
  1951  
  1952  func TestFunction(t *testing.T) {
  1953  	add := expr.Function(
  1954  		"add",
  1955  		func(p ...any) (any, error) {
  1956  			out := 0
  1957  			for _, each := range p {
  1958  				out += each.(int)
  1959  			}
  1960  			return out, nil
  1961  		},
  1962  		new(func(...int) int),
  1963  	)
  1964  
  1965  	p, err := expr.Compile(`add() + add(1) + add(1, 2) + add(1, 2, 3) + add(1, 2, 3, 4)`, add)
  1966  	assert.NoError(t, err)
  1967  
  1968  	out, err := expr.Run(p, nil)
  1969  	assert.NoError(t, err)
  1970  	assert.Equal(t, 20, out)
  1971  }
  1972  
  1973  // Nil coalescing operator
  1974  func TestRun_NilCoalescingOperator(t *testing.T) {
  1975  	env := map[string]any{
  1976  		"foo": map[string]any{
  1977  			"bar": "value",
  1978  		},
  1979  	}
  1980  
  1981  	t.Run("value", func(t *testing.T) {
  1982  		p, err := expr.Compile(`foo.bar ?? "default"`, expr.Env(env))
  1983  		assert.NoError(t, err)
  1984  
  1985  		out, err := expr.Run(p, env)
  1986  		assert.NoError(t, err)
  1987  		assert.Equal(t, "value", out)
  1988  	})
  1989  
  1990  	t.Run("default", func(t *testing.T) {
  1991  		p, err := expr.Compile(`foo.baz ?? "default"`, expr.Env(env))
  1992  		assert.NoError(t, err)
  1993  
  1994  		out, err := expr.Run(p, env)
  1995  		assert.NoError(t, err)
  1996  		assert.Equal(t, "default", out)
  1997  	})
  1998  
  1999  	t.Run("default with chain", func(t *testing.T) {
  2000  		p, err := expr.Compile(`foo?.bar ?? "default"`, expr.Env(env))
  2001  		assert.NoError(t, err)
  2002  
  2003  		out, err := expr.Run(p, map[string]any{})
  2004  		assert.NoError(t, err)
  2005  		assert.Equal(t, "default", out)
  2006  	})
  2007  }
  2008  
  2009  func TestEval_nil_in_maps(t *testing.T) {
  2010  	env := map[string]any{
  2011  		"m":     map[any]any{nil: "bar"},
  2012  		"empty": map[any]any{},
  2013  	}
  2014  	t.Run("nil key exists", func(t *testing.T) {
  2015  		p, err := expr.Compile(`m[nil]`, expr.Env(env))
  2016  		assert.NoError(t, err)
  2017  
  2018  		out, err := expr.Run(p, env)
  2019  		assert.NoError(t, err)
  2020  		assert.Equal(t, "bar", out)
  2021  	})
  2022  	t.Run("no nil key", func(t *testing.T) {
  2023  		p, err := expr.Compile(`empty[nil]`, expr.Env(env))
  2024  		assert.NoError(t, err)
  2025  
  2026  		out, err := expr.Run(p, env)
  2027  		assert.NoError(t, err)
  2028  		assert.Equal(t, nil, out)
  2029  	})
  2030  	t.Run("nil in m", func(t *testing.T) {
  2031  		p, err := expr.Compile(`nil in m`, expr.Env(env))
  2032  		assert.NoError(t, err)
  2033  
  2034  		out, err := expr.Run(p, env)
  2035  		assert.NoError(t, err)
  2036  		assert.Equal(t, true, out)
  2037  	})
  2038  	t.Run("nil in empty", func(t *testing.T) {
  2039  		p, err := expr.Compile(`nil in empty`, expr.Env(env))
  2040  		assert.NoError(t, err)
  2041  
  2042  		out, err := expr.Run(p, env)
  2043  		assert.NoError(t, err)
  2044  		assert.Equal(t, false, out)
  2045  	})
  2046  }
  2047  
  2048  // Test the use of env keyword.  Forms env[] and env[”] are valid.
  2049  // The enclosed identifier must be in the expression env.
  2050  func TestEnv_keyword(t *testing.T) {
  2051  	env := map[string]any{
  2052  		"space test":                       "ok",
  2053  		"space_test":                       "not ok", // Seems to be some underscore substituting happening, check that.
  2054  		"Section 1-2a":                     "ok",
  2055  		`c:\ndrive\2015 Information Table`: "ok",
  2056  		"%*worst function name ever!!": func() string {
  2057  			return "ok"
  2058  		}(),
  2059  		"1":      "o",
  2060  		"2":      "k",
  2061  		"num":    10,
  2062  		"mylist": []int{1, 2, 3, 4, 5},
  2063  		"MIN": func(a, b int) int {
  2064  			if a < b {
  2065  				return a
  2066  			} else {
  2067  				return b
  2068  			}
  2069  		},
  2070  		"red":   "n",
  2071  		"irect": "um",
  2072  		"String Map": map[string]string{
  2073  			"one":   "two",
  2074  			"three": "four",
  2075  		},
  2076  		"OtherMap": map[string]string{
  2077  			"a": "b",
  2078  			"c": "d",
  2079  		},
  2080  	}
  2081  
  2082  	// No error cases
  2083  	var tests = []struct {
  2084  		code string
  2085  		want any
  2086  	}{
  2087  		{"$env['space test']", "ok"},
  2088  		{"$env['Section 1-2a']", "ok"},
  2089  		{`$env["c:\\ndrive\\2015 Information Table"]`, "ok"},
  2090  		{"$env['%*worst function name ever!!']", "ok"},
  2091  		{"$env['String Map'].one", "two"},
  2092  		{"$env['1'] + $env['2']", "ok"},
  2093  		{"1 + $env['num'] + $env['num']", 21},
  2094  		{"MIN($env['num'],0)", 0},
  2095  		{"$env['nu' + 'm']", 10},
  2096  		{"$env[red + irect]", 10},
  2097  		{"$env['String Map']?.five", ""},
  2098  		{"$env.red", "n"},
  2099  		{"$env?.unknown", nil},
  2100  		{"$env.mylist[1]", 2},
  2101  		{"$env?.OtherMap?.a", "b"},
  2102  		{"$env?.OtherMap?.d", ""},
  2103  		{"'num' in $env", true},
  2104  		{"get($env, 'num')", 10},
  2105  	}
  2106  
  2107  	for _, tt := range tests {
  2108  		t.Run(tt.code, func(t *testing.T) {
  2109  
  2110  			program, err := expr.Compile(tt.code, expr.Env(env))
  2111  			require.NoError(t, err, "compile error")
  2112  
  2113  			got, err := expr.Run(program, env)
  2114  			require.NoError(t, err, "execution error")
  2115  
  2116  			assert.Equal(t, tt.want, got, tt.code)
  2117  		})
  2118  	}
  2119  
  2120  	for _, tt := range tests {
  2121  		t.Run(tt.code, func(t *testing.T) {
  2122  			got, err := expr.Eval(tt.code, env)
  2123  			require.NoError(t, err, "eval error: "+tt.code)
  2124  
  2125  			assert.Equal(t, tt.want, got, "eval: "+tt.code)
  2126  		})
  2127  	}
  2128  
  2129  	// error cases
  2130  	tests = []struct {
  2131  		code string
  2132  		want any
  2133  	}{
  2134  		{"env()", "bad"},
  2135  	}
  2136  
  2137  	for _, tt := range tests {
  2138  		t.Run(tt.code, func(t *testing.T) {
  2139  			_, err := expr.Eval(tt.code, expr.Env(env))
  2140  			require.Error(t, err, "compile error")
  2141  
  2142  		})
  2143  	}
  2144  }
  2145  
  2146  func TestEnv_keyword_with_custom_functions(t *testing.T) {
  2147  	fn := expr.Function("fn", func(params ...any) (any, error) {
  2148  		return "ok", nil
  2149  	})
  2150  
  2151  	var tests = []struct {
  2152  		code  string
  2153  		error bool
  2154  	}{
  2155  		{`fn()`, false},
  2156  		{`$env.fn()`, true},
  2157  		{`$env["fn"]`, true},
  2158  	}
  2159  
  2160  	for _, tt := range tests {
  2161  		t.Run(tt.code, func(t *testing.T) {
  2162  			_, err := expr.Compile(tt.code, expr.Env(mock.Env{}), fn)
  2163  			if tt.error {
  2164  				require.Error(t, err)
  2165  			} else {
  2166  				require.NoError(t, err)
  2167  			}
  2168  		})
  2169  	}
  2170  }
  2171  
  2172  func TestIssue401(t *testing.T) {
  2173  	program, err := expr.Compile("(a - b + c) / d", expr.AllowUndefinedVariables())
  2174  	require.NoError(t, err, "compile error")
  2175  
  2176  	output, err := expr.Run(program, map[string]any{
  2177  		"a": 1,
  2178  		"b": 2,
  2179  		"c": 3,
  2180  		"d": 4,
  2181  	})
  2182  	require.NoError(t, err, "run error")
  2183  	require.Equal(t, 0.5, output)
  2184  }
  2185  
  2186  func TestEval_slices_out_of_bound(t *testing.T) {
  2187  	tests := []struct {
  2188  		code string
  2189  		want any
  2190  	}{
  2191  		{"[1, 2, 3][:99]", []any{1, 2, 3}},
  2192  		{"[1, 2, 3][99:]", []any{}},
  2193  		{"[1, 2, 3][:-99]", []any{}},
  2194  		{"[1, 2, 3][-99:]", []any{1, 2, 3}},
  2195  	}
  2196  
  2197  	for _, tt := range tests {
  2198  		t.Run(tt.code, func(t *testing.T) {
  2199  			got, err := expr.Eval(tt.code, nil)
  2200  			require.NoError(t, err, "eval error: "+tt.code)
  2201  			assert.Equal(t, tt.want, got, "eval: "+tt.code)
  2202  		})
  2203  	}
  2204  }
  2205  
  2206  func TestMemoryBudget(t *testing.T) {
  2207  	tests := []struct {
  2208  		code string
  2209  	}{
  2210  		{`map(1..100, {map(1..100, {map(1..100, {0})})})`},
  2211  		{`len(1..10000000)`},
  2212  	}
  2213  
  2214  	for _, tt := range tests {
  2215  		t.Run(tt.code, func(t *testing.T) {
  2216  			program, err := expr.Compile(tt.code)
  2217  			require.NoError(t, err, "compile error")
  2218  
  2219  			_, err = expr.Run(program, nil)
  2220  			assert.Error(t, err, "run error")
  2221  			assert.Contains(t, err.Error(), "memory budget exceeded")
  2222  		})
  2223  	}
  2224  }
  2225  
  2226  func TestExpr_custom_tests(t *testing.T) {
  2227  	f, err := os.Open("custom_tests.json")
  2228  	if os.IsNotExist(err) {
  2229  		t.Skip("no custom tests")
  2230  		return
  2231  	}
  2232  
  2233  	require.NoError(t, err, "open file error")
  2234  	defer f.Close()
  2235  
  2236  	var tests []string
  2237  	err = json.NewDecoder(f).Decode(&tests)
  2238  	require.NoError(t, err, "decode json error")
  2239  
  2240  	for id, tt := range tests {
  2241  		t.Run(fmt.Sprintf("line %v", id+2), func(t *testing.T) {
  2242  			program, err := expr.Compile(tt)
  2243  			require.NoError(t, err)
  2244  
  2245  			timeout := make(chan bool, 1)
  2246  			go func() {
  2247  				time.Sleep(time.Second)
  2248  				timeout <- true
  2249  			}()
  2250  
  2251  			done := make(chan bool, 1)
  2252  			go func() {
  2253  				out, err := expr.Run(program, nil)
  2254  				// Make sure out is used.
  2255  				_ = fmt.Sprintf("%v", out)
  2256  				assert.Error(t, err)
  2257  				done <- true
  2258  			}()
  2259  
  2260  			select {
  2261  			case <-done:
  2262  				// Success.
  2263  			case <-timeout:
  2264  				t.Fatal("timeout")
  2265  			}
  2266  		})
  2267  	}
  2268  }
  2269  
  2270  func TestIssue432(t *testing.T) {
  2271  	env := map[string]any{
  2272  		"func": func(
  2273  			paramUint32 uint32,
  2274  			paramUint16 uint16,
  2275  			paramUint8 uint8,
  2276  			paramUint uint,
  2277  			paramInt32 int32,
  2278  			paramInt16 int16,
  2279  			paramInt8 int8,
  2280  			paramInt int,
  2281  			paramFloat64 float64,
  2282  			paramFloat32 float32,
  2283  		) float64 {
  2284  			return float64(paramUint32) + float64(paramUint16) + float64(paramUint8) + float64(paramUint) +
  2285  				float64(paramInt32) + float64(paramInt16) + float64(paramInt8) + float64(paramInt) +
  2286  				float64(paramFloat64) + float64(paramFloat32)
  2287  		},
  2288  	}
  2289  	code := `func(1,1,1,1,1,1,1,1,1,1)`
  2290  
  2291  	program, err := expr.Compile(code, expr.Env(env))
  2292  	assert.NoError(t, err)
  2293  
  2294  	out, err := expr.Run(program, env)
  2295  	assert.NoError(t, err)
  2296  	assert.Equal(t, float64(10), out)
  2297  }
  2298  
  2299  func TestIssue453(t *testing.T) {
  2300  	env := map[string]any{
  2301  		"foo": nil,
  2302  	}
  2303  	_, err := expr.Compile(`foo()`, expr.Env(env))
  2304  	require.Error(t, err)
  2305  }
  2306  
  2307  func TestIssue461(t *testing.T) {
  2308  	type EnvStr string
  2309  	type EnvField struct {
  2310  		S   EnvStr
  2311  		Str string
  2312  	}
  2313  	type Env struct {
  2314  		S        EnvStr
  2315  		Str      string
  2316  		EnvField EnvField
  2317  	}
  2318  	var tests = []struct {
  2319  		input string
  2320  		env   Env
  2321  		want  bool
  2322  	}{
  2323  		{
  2324  			input: "Str == S",
  2325  			env:   Env{S: "string", Str: "string"},
  2326  			want:  false,
  2327  		},
  2328  		{
  2329  			input: "Str == Str",
  2330  			env:   Env{Str: "string"},
  2331  			want:  true,
  2332  		},
  2333  		{
  2334  			input: "S == S",
  2335  			env:   Env{Str: "string"},
  2336  			want:  true,
  2337  		},
  2338  		{
  2339  			input: `Str == "string"`,
  2340  			env:   Env{Str: "string"},
  2341  			want:  true,
  2342  		},
  2343  		{
  2344  			input: `S == "string"`,
  2345  			env:   Env{Str: "string"},
  2346  			want:  false,
  2347  		},
  2348  		{
  2349  			input: "EnvField.Str == EnvField.S",
  2350  			env:   Env{EnvField: EnvField{S: "string", Str: "string"}},
  2351  			want:  false,
  2352  		},
  2353  		{
  2354  			input: "EnvField.Str == EnvField.Str",
  2355  			env:   Env{EnvField: EnvField{Str: "string"}},
  2356  			want:  true,
  2357  		},
  2358  		{
  2359  			input: "EnvField.S == EnvField.S",
  2360  			env:   Env{EnvField: EnvField{Str: "string"}},
  2361  			want:  true,
  2362  		},
  2363  		{
  2364  			input: `EnvField.Str == "string"`,
  2365  			env:   Env{EnvField: EnvField{Str: "string"}},
  2366  			want:  true,
  2367  		},
  2368  		{
  2369  			input: `EnvField.S == "string"`,
  2370  			env:   Env{EnvField: EnvField{Str: "string"}},
  2371  			want:  false,
  2372  		},
  2373  	}
  2374  
  2375  	for _, tt := range tests {
  2376  		t.Run(tt.input, func(t *testing.T) {
  2377  			program, err := expr.Compile(tt.input, expr.Env(tt.env), expr.AsBool())
  2378  
  2379  			out, err := expr.Run(program, tt.env)
  2380  			require.NoError(t, err)
  2381  
  2382  			require.Equal(t, tt.want, out)
  2383  		})
  2384  	}
  2385  }
  2386  
  2387  func TestIssue462(t *testing.T) {
  2388  	env := map[string]any{
  2389  		"foo": func() (string, error) {
  2390  			return "bar", nil
  2391  		},
  2392  	}
  2393  	_, err := expr.Compile(`$env.unknown(int())`, expr.Env(env))
  2394  	require.Error(t, err)
  2395  }
  2396  
  2397  func TestIssue_embedded_pointer_struct(t *testing.T) {
  2398  	var tests = []struct {
  2399  		input string
  2400  		env   mock.Env
  2401  		want  any
  2402  	}{
  2403  		{
  2404  			input: "EmbedPointerEmbedInt > 0",
  2405  			env: mock.Env{
  2406  				Embed: mock.Embed{
  2407  					EmbedPointerEmbed: &mock.EmbedPointerEmbed{
  2408  						EmbedPointerEmbedInt: 123,
  2409  					},
  2410  				},
  2411  			},
  2412  			want: true,
  2413  		},
  2414  		{
  2415  			input: "(Embed).EmbedPointerEmbedInt > 0",
  2416  			env: mock.Env{
  2417  				Embed: mock.Embed{
  2418  					EmbedPointerEmbed: &mock.EmbedPointerEmbed{
  2419  						EmbedPointerEmbedInt: 123,
  2420  					},
  2421  				},
  2422  			},
  2423  			want: true,
  2424  		},
  2425  		{
  2426  			input: "(Embed).EmbedPointerEmbedInt > 0",
  2427  			env: mock.Env{
  2428  				Embed: mock.Embed{
  2429  					EmbedPointerEmbed: &mock.EmbedPointerEmbed{
  2430  						EmbedPointerEmbedInt: 0,
  2431  					},
  2432  				},
  2433  			},
  2434  			want: false,
  2435  		},
  2436  		{
  2437  			input: "(Embed).EmbedPointerEmbedMethod(0)",
  2438  			env: mock.Env{
  2439  				Embed: mock.Embed{
  2440  					EmbedPointerEmbed: &mock.EmbedPointerEmbed{
  2441  						EmbedPointerEmbedInt: 0,
  2442  					},
  2443  				},
  2444  			},
  2445  			want: "",
  2446  		},
  2447  		{
  2448  			input: "(Embed).EmbedPointerEmbedPointerReceiverMethod(0)",
  2449  			env: mock.Env{
  2450  				Embed: mock.Embed{
  2451  					EmbedPointerEmbed: nil,
  2452  				},
  2453  			},
  2454  			want: "",
  2455  		},
  2456  	}
  2457  	for _, tt := range tests {
  2458  		t.Run(tt.input, func(t *testing.T) {
  2459  			program, err := expr.Compile(tt.input, expr.Env(tt.env))
  2460  			require.NoError(t, err)
  2461  
  2462  			out, err := expr.Run(program, tt.env)
  2463  			require.NoError(t, err)
  2464  
  2465  			require.Equal(t, tt.want, out)
  2466  		})
  2467  	}
  2468  }
  2469  
  2470  func TestIssue474(t *testing.T) {
  2471  	testCases := []struct {
  2472  		code string
  2473  		fail bool
  2474  	}{
  2475  		{
  2476  			code: `func("invalid")`,
  2477  			fail: true,
  2478  		},
  2479  		{
  2480  			code: `func(true)`,
  2481  			fail: true,
  2482  		},
  2483  		{
  2484  			code: `func([])`,
  2485  			fail: true,
  2486  		},
  2487  		{
  2488  			code: `func({})`,
  2489  			fail: true,
  2490  		},
  2491  		{
  2492  			code: `func(1)`,
  2493  			fail: false,
  2494  		},
  2495  		{
  2496  			code: `func(1.5)`,
  2497  			fail: false,
  2498  		},
  2499  	}
  2500  
  2501  	for _, tc := range testCases {
  2502  		ltc := tc
  2503  		t.Run(ltc.code, func(t *testing.T) {
  2504  			t.Parallel()
  2505  			function := expr.Function("func", func(params ...any) (any, error) {
  2506  				return true, nil
  2507  			}, new(func(float64) bool))
  2508  			_, err := expr.Compile(ltc.code, function)
  2509  			if ltc.fail {
  2510  				if err == nil {
  2511  					t.Error("expected an error, but it was nil")
  2512  					t.FailNow()
  2513  				}
  2514  			} else {
  2515  				if err != nil {
  2516  					t.Errorf("expected nil, but it was %v", err)
  2517  					t.FailNow()
  2518  				}
  2519  			}
  2520  		})
  2521  	}
  2522  }
  2523  
  2524  func TestRaceCondition_variables(t *testing.T) {
  2525  	program, err := expr.Compile(`let foo = 1; foo + 1`, expr.Env(mock.Env{}))
  2526  	require.NoError(t, err)
  2527  
  2528  	var wg sync.WaitGroup
  2529  
  2530  	for i := 0; i < 10; i++ {
  2531  		wg.Add(1)
  2532  		go func() {
  2533  			defer wg.Done()
  2534  			out, err := expr.Run(program, mock.Env{})
  2535  			require.NoError(t, err)
  2536  			require.Equal(t, 2, out)
  2537  		}()
  2538  	}
  2539  
  2540  	wg.Wait()
  2541  }
  2542  
  2543  func TestOperatorDependsOnEnv(t *testing.T) {
  2544  	env := map[string]any{
  2545  		"plus": func(a, b int) int {
  2546  			return 42
  2547  		},
  2548  	}
  2549  	program, err := expr.Compile(`1 + 2`, expr.Operator("+", "plus"), expr.Env(env))
  2550  	require.NoError(t, err)
  2551  
  2552  	out, err := expr.Run(program, env)
  2553  	require.NoError(t, err)
  2554  	assert.Equal(t, 42, out)
  2555  }
  2556  
  2557  func TestIssue624(t *testing.T) {
  2558  	type tag struct {
  2559  		Name string
  2560  	}
  2561  
  2562  	type item struct {
  2563  		Tags []tag
  2564  	}
  2565  
  2566  	i := item{
  2567  		Tags: []tag{
  2568  			{Name: "one"},
  2569  			{Name: "two"},
  2570  		},
  2571  	}
  2572  
  2573  	rule := `[
  2574  true && true, 
  2575  one(Tags, .Name in ["one"]), 
  2576  one(Tags, .Name in ["two"]), 
  2577  one(Tags, .Name in ["one"]) && one(Tags, .Name in ["two"])
  2578  ]`
  2579  	resp, err := expr.Eval(rule, i)
  2580  	require.NoError(t, err)
  2581  	require.Equal(t, []interface{}{true, true, true, true}, resp)
  2582  }
  2583  
  2584  func TestPredicateCombination(t *testing.T) {
  2585  	tests := []struct {
  2586  		code1 string
  2587  		code2 string
  2588  	}{
  2589  		{"all(1..3, {# > 0}) && all(1..3, {# < 4})", "all(1..3, {# > 0 && # < 4})"},
  2590  		{"all(1..3, {# > 1}) && all(1..3, {# < 4})", "all(1..3, {# > 1 && # < 4})"},
  2591  		{"all(1..3, {# > 0}) && all(1..3, {# < 2})", "all(1..3, {# > 0 && # < 2})"},
  2592  		{"all(1..3, {# > 1}) && all(1..3, {# < 2})", "all(1..3, {# > 1 && # < 2})"},
  2593  
  2594  		{"any(1..3, {# > 0}) || any(1..3, {# < 4})", "any(1..3, {# > 0 || # < 4})"},
  2595  		{"any(1..3, {# > 1}) || any(1..3, {# < 4})", "any(1..3, {# > 1 || # < 4})"},
  2596  		{"any(1..3, {# > 0}) || any(1..3, {# < 2})", "any(1..3, {# > 0 || # < 2})"},
  2597  		{"any(1..3, {# > 1}) || any(1..3, {# < 2})", "any(1..3, {# > 1 || # < 2})"},
  2598  
  2599  		{"none(1..3, {# > 0}) && none(1..3, {# < 4})", "none(1..3, {# > 0 || # < 4})"},
  2600  		{"none(1..3, {# > 1}) && none(1..3, {# < 4})", "none(1..3, {# > 1 || # < 4})"},
  2601  		{"none(1..3, {# > 0}) && none(1..3, {# < 2})", "none(1..3, {# > 0 || # < 2})"},
  2602  		{"none(1..3, {# > 1}) && none(1..3, {# < 2})", "none(1..3, {# > 1 || # < 2})"},
  2603  	}
  2604  	for _, tt := range tests {
  2605  		t.Run(tt.code1, func(t *testing.T) {
  2606  			out1, err := expr.Eval(tt.code1, nil)
  2607  			require.NoError(t, err)
  2608  
  2609  			out2, err := expr.Eval(tt.code2, nil)
  2610  			require.NoError(t, err)
  2611  
  2612  			require.Equal(t, out1, out2)
  2613  		})
  2614  	}
  2615  }
  2616  
  2617  func TestArrayComparison(t *testing.T) {
  2618  	tests := []struct {
  2619  		env  any
  2620  		code string
  2621  	}{
  2622  		{[]string{"A", "B"}, "foo == ['A', 'B']"},
  2623  		{[]int{1, 2}, "foo == [1, 2]"},
  2624  		{[]uint8{1, 2}, "foo == [1, 2]"},
  2625  		{[]float64{1.1, 2.2}, "foo == [1.1, 2.2]"},
  2626  		{[]any{"A", 1, 1.1, true}, "foo == ['A', 1, 1.1, true]"},
  2627  		{[]string{"A", "B"}, "foo != [1, 2]"},
  2628  	}
  2629  
  2630  	for _, tt := range tests {
  2631  		t.Run(tt.code, func(t *testing.T) {
  2632  			env := map[string]any{"foo": tt.env}
  2633  			program, err := expr.Compile(tt.code, expr.Env(env))
  2634  			require.NoError(t, err)
  2635  
  2636  			out, err := expr.Run(program, env)
  2637  			require.NoError(t, err)
  2638  			require.Equal(t, true, out)
  2639  		})
  2640  	}
  2641  }
  2642  
  2643  func TestIssue_570(t *testing.T) {
  2644  	type Student struct {
  2645  		Name string
  2646  	}
  2647  
  2648  	env := map[string]any{
  2649  		"student": (*Student)(nil),
  2650  	}
  2651  
  2652  	program, err := expr.Compile("student?.Name", expr.Env(env))
  2653  	require.NoError(t, err)
  2654  
  2655  	out, err := expr.Run(program, env)
  2656  	require.NoError(t, err)
  2657  	require.IsType(t, nil, out)
  2658  }
  2659  
  2660  func TestIssue_integer_truncated_by_compiler(t *testing.T) {
  2661  	env := map[string]any{
  2662  		"fn": func(x byte) byte {
  2663  			return x
  2664  		},
  2665  	}
  2666  
  2667  	_, err := expr.Compile("fn(255)", expr.Env(env))
  2668  	require.NoError(t, err)
  2669  
  2670  	_, err = expr.Compile("fn(256)", expr.Env(env))
  2671  	require.Error(t, err)
  2672  }
  2673  
  2674  func TestExpr_crash(t *testing.T) {
  2675  	content, err := os.ReadFile("testdata/crash.txt")
  2676  	require.NoError(t, err)
  2677  
  2678  	_, err = expr.Compile(string(content))
  2679  	require.Error(t, err)
  2680  }
  2681  
  2682  func TestExpr_nil_op_str(t *testing.T) {
  2683  	// Let's test operators, which do `.(string)` in VM, also check for nil.
  2684  
  2685  	var str *string = nil
  2686  	env := map[string]any{
  2687  		"nilString": str,
  2688  	}
  2689  
  2690  	tests := []struct{ code string }{
  2691  		{`nilString == "str"`},
  2692  		{`nilString contains "str"`},
  2693  		{`nilString matches "str"`},
  2694  		{`nilString startsWith "str"`},
  2695  		{`nilString endsWith "str"`},
  2696  
  2697  		{`"str" == nilString`},
  2698  		{`"str" contains nilString`},
  2699  		{`"str" matches nilString`},
  2700  		{`"str" startsWith nilString`},
  2701  		{`"str" endsWith nilString`},
  2702  	}
  2703  
  2704  	for _, tt := range tests {
  2705  		t.Run(tt.code, func(t *testing.T) {
  2706  			program, err := expr.Compile(tt.code)
  2707  			require.NoError(t, err)
  2708  
  2709  			output, err := expr.Run(program, env)
  2710  			require.NoError(t, err)
  2711  			require.Equal(t, false, output)
  2712  		})
  2713  	}
  2714  }