src.elv.sh@v0.21.0-dev.0.20240515223629-06979efb9a2a/pkg/eval/eval_test.go (about)

     1  package eval_test
     2  
     3  import (
     4  	"sync"
     5  	"testing"
     6  
     7  	. "src.elv.sh/pkg/eval"
     8  
     9  	"src.elv.sh/pkg/eval/vars"
    10  	"src.elv.sh/pkg/parse"
    11  )
    12  
    13  func TestEval_AlternativeGlobal(t *testing.T) {
    14  	ev := NewEvaler()
    15  	g := BuildNs().AddVar("a", vars.NewReadOnly("")).Ns()
    16  	err := ev.Eval(parse.Source{Name: "[test]", Code: "nop $a"}, EvalCfg{Global: g})
    17  	if err != nil {
    18  		t.Errorf("got error %v, want nil", err)
    19  	}
    20  	// Regression test for #1223
    21  	if ev.Global().HasKeyString("a") {
    22  		t.Errorf("$a from alternative global leaked into Evaler global")
    23  	}
    24  }
    25  
    26  func TestEval_Concurrent(t *testing.T) {
    27  	ev := NewEvaler()
    28  
    29  	var wg sync.WaitGroup
    30  	wg.Add(2)
    31  	go func() {
    32  		ev.Eval(parse.Source{Name: "[test]", Code: "var a"}, EvalCfg{})
    33  		wg.Done()
    34  	}()
    35  	go func() {
    36  		ev.Eval(parse.Source{Name: "[test]", Code: "var b"}, EvalCfg{})
    37  		wg.Done()
    38  	}()
    39  	wg.Wait()
    40  	g := ev.Global()
    41  	if !g.HasKeyString("a") {
    42  		t.Errorf("variable $a not created")
    43  	}
    44  	if !g.HasKeyString("b") {
    45  		t.Errorf("variable $b not created")
    46  	}
    47  }
    48  
    49  type fooOpts struct{ Opt string }
    50  
    51  func (*fooOpts) SetDefaultOptions() {}
    52  
    53  func TestCall(t *testing.T) {
    54  	ev := NewEvaler()
    55  	var gotOpt, gotArg string
    56  	fn := NewGoFn("foo", func(fm *Frame, opts fooOpts, arg string) {
    57  		gotOpt = opts.Opt
    58  		gotArg = arg
    59  	})
    60  
    61  	passedArg := "arg value"
    62  	passedOpt := "opt value"
    63  	ev.Call(fn,
    64  		CallCfg{
    65  			Args: []any{passedArg},
    66  			Opts: map[string]any{"opt": passedOpt},
    67  			From: "[TestCall]"},
    68  		EvalCfg{})
    69  
    70  	if gotArg != passedArg {
    71  		t.Errorf("got arg %q, want %q", gotArg, passedArg)
    72  	}
    73  	if gotOpt != passedOpt {
    74  		t.Errorf("got opt %q, want %q", gotOpt, passedOpt)
    75  	}
    76  }
    77  
    78  var checkTests = []struct {
    79  	name           string
    80  	code           string
    81  	wantParseErr   bool
    82  	wantCompileErr bool
    83  }{
    84  	{name: "no error", code: "put $nil"},
    85  	{name: "parse error only", code: "put [",
    86  		wantParseErr: true},
    87  	{name: "compile error only", code: "put $x",
    88  		wantCompileErr: true},
    89  	{name: "both parse and compile error", code: "put [$x",
    90  		wantParseErr: true, wantCompileErr: true},
    91  }
    92  
    93  func TestCheck(t *testing.T) {
    94  	ev := NewEvaler()
    95  	for _, test := range checkTests {
    96  		t.Run(test.name, func(t *testing.T) {
    97  			parseErr, _, compileErr := ev.Check(parse.Source{Name: "[test]", Code: test.code}, nil)
    98  			if (parseErr != nil) != test.wantParseErr {
    99  				t.Errorf("got parse error %v, when wantParseErr = %v",
   100  					parseErr, test.wantParseErr)
   101  			}
   102  			if (compileErr != nil) != test.wantCompileErr {
   103  				t.Errorf("got compile error %v, when wantCompileErr = %v",
   104  					compileErr, test.wantCompileErr)
   105  			}
   106  		})
   107  	}
   108  }