eval_test.go 3.9 KB

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