github.com/kolbycrouch/elvish@v0.14.1-0.20210614162631-215b9ac1c423/pkg/eval/eval_test.go (about)

     1  package eval_test
     2  
     3  import (
     4  	"strconv"
     5  	"sync"
     6  	"syscall"
     7  	"testing"
     8  
     9  	. "src.elv.sh/pkg/eval"
    10  
    11  	. "src.elv.sh/pkg/eval/evaltest"
    12  	"src.elv.sh/pkg/eval/vals"
    13  	"src.elv.sh/pkg/eval/vars"
    14  	"src.elv.sh/pkg/parse"
    15  	"src.elv.sh/pkg/prog"
    16  	"src.elv.sh/pkg/testutil"
    17  )
    18  
    19  func TestPid(t *testing.T) {
    20  	pid := strconv.Itoa(syscall.Getpid())
    21  	Test(t, That("put $pid").Puts(pid))
    22  }
    23  
    24  func TestNumBgJobs(t *testing.T) {
    25  	Test(t,
    26  		That("put $num-bg-jobs").Puts("0"),
    27  		// TODO(xiaq): Test cases where $num-bg-jobs > 0. This cannot be done
    28  		// with { put $num-bg-jobs }& because the output channel may have
    29  		// already been closed when the closure is run.
    30  	)
    31  }
    32  
    33  func TestArgs(t *testing.T) {
    34  	Test(t,
    35  		That("put $args").Puts(vals.EmptyList))
    36  	TestWithSetup(t,
    37  		func(ev *Evaler) { ev.SetArgs([]string{"foo", "bar"}) },
    38  		That("put $args").Puts(vals.MakeList("foo", "bar")))
    39  }
    40  
    41  func TestEvalTimeDeprecate(t *testing.T) {
    42  	restore := prog.SetDeprecationLevel(42)
    43  	defer restore()
    44  	_, cleanup := testutil.InTestDir()
    45  	defer cleanup()
    46  
    47  	TestWithSetup(t, func(ev *Evaler) {
    48  		ev.AddGlobal(NsBuilder{}.AddGoFn("", "dep", func(fm *Frame) {
    49  			fm.Deprecate("deprecated", nil, 42)
    50  		}).Ns())
    51  	},
    52  		That("dep").PrintsStderrWith("deprecated"),
    53  		// Deprecation message is only shown once.
    54  		That("dep 2> tmp.txt; dep").DoesNothing(),
    55  	)
    56  }
    57  
    58  func TestMultipleEval(t *testing.T) {
    59  	Test(t,
    60  		That("x = hello").Then("put $x").Puts("hello"),
    61  
    62  		// Shadowing with fn. Regression test for #1213.
    63  		That("fn f { put old }").Then("fn f { put new }").Then("f").
    64  			Puts("new"),
    65  		// Variable deletion. Regression test for #1213.
    66  		That("x = foo").Then("del x").Then("put $x").DoesNotCompile(),
    67  	)
    68  }
    69  
    70  func TestEval_AlternativeGlobal(t *testing.T) {
    71  	ev := NewEvaler()
    72  	g := NsBuilder{"a": vars.NewReadOnly("")}.Ns()
    73  	err := ev.Eval(parse.Source{Code: "nop $a"}, EvalCfg{Global: g})
    74  	if err != nil {
    75  		t.Errorf("got error %v, want nil", err)
    76  	}
    77  	// Regression test for #1223
    78  	if ev.Global().HasName("a") {
    79  		t.Errorf("$a from alternative global leaked into Evaler global")
    80  	}
    81  }
    82  
    83  func TestEval_Concurrent(t *testing.T) {
    84  	ev := NewEvaler()
    85  
    86  	var wg sync.WaitGroup
    87  	wg.Add(2)
    88  	go func() {
    89  		ev.Eval(parse.Source{Code: "var a"}, EvalCfg{})
    90  		wg.Done()
    91  	}()
    92  	go func() {
    93  		ev.Eval(parse.Source{Code: "var b"}, EvalCfg{})
    94  		wg.Done()
    95  	}()
    96  	wg.Wait()
    97  	g := ev.Global()
    98  	if !g.HasName("a") {
    99  		t.Errorf("variable $a not created")
   100  	}
   101  	if !g.HasName("b") {
   102  		t.Errorf("variable $b not created")
   103  	}
   104  }
   105  
   106  type fooOpts struct{ Opt string }
   107  
   108  func (*fooOpts) SetDefaultOptions() {}
   109  
   110  func TestCall(t *testing.T) {
   111  	ev := NewEvaler()
   112  	var gotOpt, gotArg string
   113  	fn := NewGoFn("foo", func(fm *Frame, opts fooOpts, arg string) {
   114  		gotOpt = opts.Opt
   115  		gotArg = arg
   116  	})
   117  
   118  	passedArg := "arg value"
   119  	passedOpt := "opt value"
   120  	ev.Call(fn,
   121  		CallCfg{
   122  			Args: []interface{}{passedArg},
   123  			Opts: map[string]interface{}{"opt": passedOpt},
   124  			From: "[TestCall]"},
   125  		EvalCfg{})
   126  
   127  	if gotArg != passedArg {
   128  		t.Errorf("got arg %q, want %q", gotArg, passedArg)
   129  	}
   130  	if gotOpt != passedOpt {
   131  		t.Errorf("got opt %q, want %q", gotOpt, passedOpt)
   132  	}
   133  }
   134  
   135  var checkTests = []struct {
   136  	name           string
   137  	code           string
   138  	wantParseErr   bool
   139  	wantCompileErr bool
   140  }{
   141  	{name: "no error", code: "put $nil"},
   142  	{name: "parse error only", code: "put [",
   143  		wantParseErr: true},
   144  	{name: "compile error only", code: "put $x",
   145  		wantCompileErr: true},
   146  	{name: "both parse and compile error", code: "put [$x",
   147  		wantParseErr: true, wantCompileErr: true},
   148  }
   149  
   150  func TestCheck(t *testing.T) {
   151  	ev := NewEvaler()
   152  	for _, test := range checkTests {
   153  		t.Run(test.name, func(t *testing.T) {
   154  			parseErr, compileErr := ev.Check(parse.Source{Code: test.code}, nil)
   155  			if (parseErr != nil) != test.wantParseErr {
   156  				t.Errorf("got parse error %v, when wantParseErr = %v",
   157  					parseErr, test.wantParseErr)
   158  			}
   159  			if (compileErr != nil) != test.wantCompileErr {
   160  				t.Errorf("got compile error %v, when wantCompileErr = %v",
   161  					compileErr, test.wantCompileErr)
   162  			}
   163  		})
   164  	}
   165  }