github.com/markusbkk/elvish@v0.0.0-20231204143114-91dc52438621/pkg/eval/eval_test.go (about) 1 package eval_test 2 3 import ( 4 "strconv" 5 "sync" 6 "syscall" 7 "testing" 8 9 . "github.com/markusbkk/elvish/pkg/eval" 10 "github.com/markusbkk/elvish/pkg/prog/progtest" 11 12 . "github.com/markusbkk/elvish/pkg/eval/evaltest" 13 "github.com/markusbkk/elvish/pkg/eval/vals" 14 "github.com/markusbkk/elvish/pkg/eval/vars" 15 "github.com/markusbkk/elvish/pkg/parse" 16 "github.com/markusbkk/elvish/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 progtest.SetDeprecationLevel(t, 42) 43 testutil.InTempDir(t) 44 45 TestWithSetup(t, func(ev *Evaler) { 46 ev.ExtendGlobal(BuildNs().AddGoFn("dep", func(fm *Frame) { 47 fm.Deprecate("deprecated", nil, 42) 48 })) 49 }, 50 That("dep").PrintsStderrWith("deprecated"), 51 // Deprecation message is only shown once. 52 That("dep 2> tmp.txt; dep").DoesNothing(), 53 ) 54 } 55 56 func TestMultipleEval(t *testing.T) { 57 Test(t, 58 That("var x = hello").Then("put $x").Puts("hello"), 59 60 // Shadowing with fn. Regression test for #1213. 61 That("fn f { put old }").Then("fn f { put new }").Then("f"). 62 Puts("new"), 63 // Variable deletion. Regression test for #1213. 64 That("var x = foo").Then("del x").Then("put $x").DoesNotCompile(), 65 ) 66 } 67 68 func TestEval_AlternativeGlobal(t *testing.T) { 69 ev := NewEvaler() 70 g := BuildNs().AddVar("a", vars.NewReadOnly("")).Ns() 71 err := ev.Eval(parse.Source{Code: "nop $a"}, EvalCfg{Global: g}) 72 if err != nil { 73 t.Errorf("got error %v, want nil", err) 74 } 75 // Regression test for #1223 76 if ev.Global().HasKeyString("a") { 77 t.Errorf("$a from alternative global leaked into Evaler global") 78 } 79 } 80 81 func TestEval_Concurrent(t *testing.T) { 82 ev := NewEvaler() 83 84 var wg sync.WaitGroup 85 wg.Add(2) 86 go func() { 87 ev.Eval(parse.Source{Code: "var a"}, EvalCfg{}) 88 wg.Done() 89 }() 90 go func() { 91 ev.Eval(parse.Source{Code: "var b"}, EvalCfg{}) 92 wg.Done() 93 }() 94 wg.Wait() 95 g := ev.Global() 96 if !g.HasKeyString("a") { 97 t.Errorf("variable $a not created") 98 } 99 if !g.HasKeyString("b") { 100 t.Errorf("variable $b not created") 101 } 102 } 103 104 type fooOpts struct{ Opt string } 105 106 func (*fooOpts) SetDefaultOptions() {} 107 108 func TestCall(t *testing.T) { 109 ev := NewEvaler() 110 var gotOpt, gotArg string 111 fn := NewGoFn("foo", func(fm *Frame, opts fooOpts, arg string) { 112 gotOpt = opts.Opt 113 gotArg = arg 114 }) 115 116 passedArg := "arg value" 117 passedOpt := "opt value" 118 ev.Call(fn, 119 CallCfg{ 120 Args: []interface{}{passedArg}, 121 Opts: map[string]interface{}{"opt": passedOpt}, 122 From: "[TestCall]"}, 123 EvalCfg{}) 124 125 if gotArg != passedArg { 126 t.Errorf("got arg %q, want %q", gotArg, passedArg) 127 } 128 if gotOpt != passedOpt { 129 t.Errorf("got opt %q, want %q", gotOpt, passedOpt) 130 } 131 } 132 133 var checkTests = []struct { 134 name string 135 code string 136 wantParseErr bool 137 wantCompileErr bool 138 }{ 139 {name: "no error", code: "put $nil"}, 140 {name: "parse error only", code: "put [", 141 wantParseErr: true}, 142 {name: "compile error only", code: "put $x", 143 wantCompileErr: true}, 144 {name: "both parse and compile error", code: "put [$x", 145 wantParseErr: true, wantCompileErr: true}, 146 } 147 148 func TestCheck(t *testing.T) { 149 ev := NewEvaler() 150 for _, test := range checkTests { 151 t.Run(test.name, func(t *testing.T) { 152 parseErr, compileErr := ev.Check(parse.Source{Code: test.code}, nil) 153 if (parseErr != nil) != test.wantParseErr { 154 t.Errorf("got parse error %v, when wantParseErr = %v", 155 parseErr, test.wantParseErr) 156 } 157 if (compileErr != nil) != test.wantCompileErr { 158 t.Errorf("got compile error %v, when wantCompileErr = %v", 159 compileErr, test.wantCompileErr) 160 } 161 }) 162 } 163 }