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 }