builtin_special_test.go 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578
  1. package eval_test
  2. import (
  3. "errors"
  4. "path/filepath"
  5. "testing"
  6. "src.elv.sh/pkg/diag"
  7. . "src.elv.sh/pkg/eval"
  8. "src.elv.sh/pkg/eval/errs"
  9. "src.elv.sh/pkg/eval/vals"
  10. "src.elv.sh/pkg/eval/vars"
  11. "src.elv.sh/pkg/must"
  12. "src.elv.sh/pkg/parse"
  13. "src.elv.sh/pkg/prog"
  14. "src.elv.sh/pkg/testutil"
  15. . "src.elv.sh/pkg/eval/evaltest"
  16. )
  17. func TestPragma(t *testing.T) {
  18. Test(t,
  19. That("pragma unknown-command").DoesNotCompile("need more arguments"),
  20. That("pragma unknown-command =").DoesNotCompile("need more arguments"),
  21. That("pragma unknown-command x").DoesNotCompile("must be literal ="),
  22. That("pragma bad-name = some-value").DoesNotCompile("unknown pragma bad-name"),
  23. That("pragma unknown-command = bad").DoesNotCompile("invalid value for unknown-command: bad"),
  24. )
  25. // Actual effect of the unknown-command pragma is tested in TestCommand_External
  26. }
  27. func TestVar(t *testing.T) {
  28. // NOTE: TestClosure has more tests for the interaction between assignment
  29. // and variable scoping.
  30. Test(t,
  31. // Declaring one variable
  32. That("var x", "put $x").Puts(nil),
  33. // Declaring one variable whose name needs to be quoted
  34. That("var 'a/b'", "put $'a/b'").Puts(nil),
  35. // Declaring one variable whose name ends in ":".
  36. That("var a:").DoesNothing(),
  37. // Declaring a variable whose name ends in "~" initializes it to the
  38. // builtin nop function.
  39. That("var cmd~; cmd &ignored-opt ignored-arg").DoesNothing(),
  40. That("var cmd~; is $cmd~ $nop~").Puts(true),
  41. // Declaring multiple variables
  42. That("var x y", "put $x $y").Puts(nil, nil),
  43. // Declaring one variable with initial value
  44. That("var x = foo", "put $x").Puts("foo"),
  45. // Declaring multiple variables with initial values
  46. That("var x y = foo bar", "put $x $y").Puts("foo", "bar"),
  47. // Declaring multiple variables with initial values, including a rest
  48. // variable in the assignment LHS
  49. That("var x @y z = a b c d", "put $x $y $z").
  50. Puts("a", vals.MakeList("b", "c"), "d"),
  51. // An empty RHS is technically legal although rarely useful.
  52. That("var @x =", "put $x").Puts(vals.EmptyList),
  53. // Shadowing.
  54. That("var x = old; fn f { put $x }", "var x = new; put $x; f").
  55. Puts("new", "old"),
  56. // Concurrently creating a new variable and accessing existing variable.
  57. // Run with "go test -race".
  58. That("var x = 1", "put $x | var y = (all)").DoesNothing(),
  59. That("nop (var x = 1) | nop").DoesNothing(),
  60. // Assignment errors when the RHS errors.
  61. That("var x = [][1]").Throws(ErrorWithType(errs.OutOfRange{}), "[][1]"),
  62. // Arity mismatch.
  63. That("var x = 1 2").Throws(
  64. errs.ArityMismatch{What: "assignment right-hand-side",
  65. ValidLow: 1, ValidHigh: 1, Actual: 2},
  66. "var x = 1 2"),
  67. That("var x y = 1").Throws(
  68. errs.ArityMismatch{What: "assignment right-hand-side",
  69. ValidLow: 2, ValidHigh: 2, Actual: 1},
  70. "var x y = 1"),
  71. That("var x y @z = 1").Throws(
  72. errs.ArityMismatch{What: "assignment right-hand-side",
  73. ValidLow: 2, ValidHigh: -1, Actual: 1},
  74. "var x y @z = 1"),
  75. // Variable name must not be empty
  76. That("var ''").DoesNotCompile("variable name must not be empty"),
  77. // Variable name that must be quoted after $ must be quoted
  78. That("var a/b").DoesNotCompile("lvalue must be valid literal variable names"),
  79. // Multiple @ not allowed
  80. That("var x @y @z = a b c d").DoesNotCompile("at most one rest variable is allowed"),
  81. // Non-local not allowed
  82. That("var ns:a").DoesNotCompile("cannot create variable $ns:a; new variables can only be created in the current scope"),
  83. // Index not allowed
  84. That("var a[0]").DoesNotCompile("new variable $a must not have indices"),
  85. // Composite expression not allowed
  86. That("var a'b'").DoesNotCompile("lvalue may not be composite expressions"),
  87. // Braced lists must not have any indices when used as a lvalue.
  88. That("var {a b}[0] = x y").DoesNotCompile("braced list may not have indices when used as lvalue"),
  89. )
  90. }
  91. func TestSet(t *testing.T) {
  92. Test(t,
  93. // Setting one variable
  94. That("var x; set x = foo", "put $x").Puts("foo"),
  95. // An empty RHS is technically legal although rarely useful.
  96. That("var x; set @x =", "put $x").Puts(vals.EmptyList),
  97. // Variable must already exist
  98. That("set x = foo").DoesNotCompile("cannot find variable $x"),
  99. // List element assignment
  100. That("var li = [foo bar]; set li[0] = 233; put $@li").Puts("233", "bar"),
  101. // Variable in list assignment must already be defined. Regression test
  102. // for b.elv.sh/889.
  103. That("set y[0] = a").DoesNotCompile("cannot find variable $y"),
  104. // Map element assignment
  105. That("var di = [&k=v]; set di[k] = lorem; set di[k2] = ipsum",
  106. "put $di[k] $di[k2]").Puts("lorem", "ipsum"),
  107. That("var d = [&a=[&b=v]]; put $d[a][b]; set d[a][b] = u; put $d[a][b]").
  108. Puts("v", "u"),
  109. That("var li = [foo]; set li[(fail foo)] = bar").Throws(FailError{"foo"}),
  110. That("var li = [foo]; set li[0 1] = foo bar").
  111. Throws(ErrorWithMessage("multi indexing not implemented")),
  112. That("var li = [[]]; set li[1][2] = bar").
  113. Throws(errs.OutOfRange{What: "index",
  114. ValidLow: "0", ValidHigh: "0", Actual: "1"}, "li[1][2]"),
  115. // Assignment to read-only var is a compile-time error.
  116. That("set nil = 1").DoesNotCompile("variable $nil is read-only"),
  117. That("var a b; set a true b = 1 2 3").DoesNotCompile("variable $true is read-only"),
  118. That("set @true = 1").DoesNotCompile("variable $true is read-only"),
  119. That("var r; set true @r = 1").DoesNotCompile("variable $true is read-only"),
  120. That("var r; set @r true = 1").DoesNotCompile("variable $true is read-only"),
  121. // Error conditions already covered by TestVar are not repeated.
  122. // = is required.
  123. That("var x; set x").DoesNotCompile("need = and right-hand-side"),
  124. // set a non-exist environment
  125. That("has-env X; set E:X = x; get-env X; unset-env X").
  126. Puts(false, "x"),
  127. )
  128. }
  129. func TestSet_ErrorInSetMethod(t *testing.T) {
  130. TestWithSetup(t, func(ev *Evaler) { addBadVar(ev, 0) },
  131. That("set bad = foo").Throws(errBadVar, "bad"),
  132. That("var a; set bad @a = foo").Throws(errBadVar, "bad"),
  133. That("var a; set a @bad = foo").Throws(errBadVar, "@bad"),
  134. That("var a; set @a bad = foo").Throws(errBadVar, "bad"),
  135. )
  136. }
  137. func TestTmp(t *testing.T) {
  138. testutil.Unsetenv(t, "X")
  139. Test(t,
  140. That("var x = foo; put $x; { tmp x = bar; put $x }; put $x").
  141. Puts("foo", "bar", "foo"),
  142. That("var x; tmp x = y").DoesNotCompile("tmp may only be used inside a function"),
  143. That("{ tmp x = y }").DoesNotCompile("cannot find variable $x"),
  144. That("has-env X; { tmp E:X = y; put $E:X }; has-env X; put $E:X").
  145. Puts(false, "y", false, ""),
  146. That("set-env X x; { tmp E:X = y; put $E:X }; get-env X; put $E:X; unset-env X").
  147. Puts("y", "x", "x"),
  148. )
  149. }
  150. func TestTmp_ErrorSetting(t *testing.T) {
  151. TestWithSetup(t, func(ev *Evaler) { addBadVar(ev, 0) },
  152. That("{ tmp bad = foo }").Throws(errBadVar, "bad", "{ tmp bad = foo }"),
  153. )
  154. }
  155. func TestTmp_ErrorRestoring(t *testing.T) {
  156. TestWithSetup(t, func(ev *Evaler) { addBadVar(ev, 1) },
  157. That("{ tmp bad = foo; put after }").
  158. Puts("after").
  159. Throws(ErrorWithMessage("restore variable: bad var"),
  160. "bad", "{ tmp bad = foo; put after }"),
  161. )
  162. }
  163. func addBadVar(ev *Evaler, allowedSets int) {
  164. ev.ExtendGlobal(BuildNs().AddVar("bad", &badVar{allowedSets}))
  165. }
  166. var errBadVar = errors.New("bad var")
  167. type badVar struct{ allowedSets int }
  168. func (v *badVar) Get() any { return nil }
  169. func (v *badVar) Set(any) error {
  170. if v.allowedSets == 0 {
  171. return errBadVar
  172. }
  173. v.allowedSets--
  174. return nil
  175. }
  176. func TestDel(t *testing.T) {
  177. testutil.Setenv(t, "TEST_ENV", "test value")
  178. Test(t,
  179. // Deleting variable
  180. That("var x = 1; del x").DoesNothing(),
  181. That("var x = 1; del x; echo $x").DoesNotCompile("variable $x not found"),
  182. // Deleting environment variable
  183. That("has-env TEST_ENV", "del E:TEST_ENV", "has-env TEST_ENV").Puts(true, false),
  184. // Deleting variable whose name contains special characters
  185. That("var 'a/b' = foo; del 'a/b'").DoesNothing(),
  186. // Deleting element
  187. That("var x = [&k=v &k2=v2]; del x[k2]; keys $x").Puts("k"),
  188. That("var x = [[&k=v &k2=v2]]; del x[0][k2]; keys $x[0]").Puts("k"),
  189. // Error cases
  190. // Deleting nonexistent variable
  191. That("del x").DoesNotCompile("no variable $x"),
  192. // Deleting element of nonexistent variable
  193. That("del x[0]").DoesNotCompile("no variable $x"),
  194. // Deleting variable in non-local namespace
  195. That("var a: = (ns [&b=$nil])", "del a:b").DoesNotCompile("only variables in the local scope or E: can be deleted"),
  196. // Variable name given with $
  197. That("var x = 1; del $x").DoesNotCompile("arguments to del must omit the dollar sign"),
  198. // Variable name not given as a single primary expression
  199. That("var ab = 1; del a'b'").DoesNotCompile("arguments to del must be variable or variable elements"),
  200. // Variable name not a string
  201. That("del [a]").DoesNotCompile("arguments to del must be variable or variable elements"),
  202. // Variable name has sigil
  203. That("var x = []; del @x").DoesNotCompile("arguments to del must be variable or variable elements"),
  204. // Variable name not quoted when it should be
  205. That("var 'a/b' = foo; del a/b").DoesNotCompile("arguments to del must be variable or variable elements"),
  206. // Index is multiple values
  207. That("var x = [&k1=v1 &k2=v2]", "del x[k1 k2]").Throws(
  208. ErrorWithMessage("index must evaluate to a single value in argument to del"),
  209. "k1 k2"),
  210. // Index expression throws exception
  211. That("var x = [&k]", "del x[(fail x)]").Throws(FailError{"x"}, "fail x"),
  212. // Value does not support element removal
  213. That("var x = (num 1)", "del x[k]").Throws(
  214. ErrorWithMessage("value does not support element removal"),
  215. // TODO: Fix the stack trace so that it is "x[k]"
  216. "x[k"),
  217. // Intermediate element does not exist
  218. That("var x = [&]", "del x[k][0]").Throws(
  219. ErrorWithMessage("no such key: k"),
  220. // TODO: Fix the stack trace so that it is "x[k]"
  221. "x"),
  222. )
  223. }
  224. func TestAnd(t *testing.T) {
  225. Test(t,
  226. That("and $true $false").Puts(false),
  227. That("and a b").Puts("b"),
  228. That("and $false b").Puts(false),
  229. That("and $true b").Puts("b"),
  230. // short circuit
  231. That("var x = a; and $false (x = b); put $x").Puts(false, "a"),
  232. // Exception
  233. That("and a (fail x)").Throws(FailError{"x"}, "fail x"),
  234. thatOutputErrorIsBubbled("and a"),
  235. )
  236. }
  237. func TestOr(t *testing.T) {
  238. Test(t,
  239. That("or $true $false").Puts(true),
  240. That("or a b").Puts("a"),
  241. That("or $false b").Puts("b"),
  242. That("or $true b").Puts(true),
  243. // short circuit
  244. That("var x = a; or $true (x = b); put $x").Puts(true, "a"),
  245. // Exception
  246. That("or $false (fail x)").Throws(FailError{"x"}, "fail x"),
  247. thatOutputErrorIsBubbled("or a"),
  248. )
  249. }
  250. func TestCoalesce(t *testing.T) {
  251. Test(t,
  252. That("coalesce a b").Puts("a"),
  253. That("coalesce $nil b").Puts("b"),
  254. That("coalesce $nil $nil").Puts(nil),
  255. That("coalesce").Puts(nil),
  256. // exception propagation
  257. That("coalesce $nil (fail foo)").Throws(FailError{"foo"}),
  258. // short circuit
  259. That("coalesce a (fail foo)").Puts("a"),
  260. thatOutputErrorIsBubbled("coalesce a"),
  261. )
  262. }
  263. func TestSpecialFormThunks(t *testing.T) {
  264. // Regression test for b.elv.sh/1456
  265. Test(t,
  266. That("for x [] {|arg| }").DoesNotCompile("for body must not have arguments"),
  267. That("for x [] {|&opt=val| }").DoesNotCompile("for body must not have options"),
  268. // The other special forms use the same utility under the hood and are
  269. // not repeated
  270. )
  271. }
  272. func TestIf(t *testing.T) {
  273. Test(t,
  274. That("if true { put then }").Puts("then"),
  275. That("if $false { put then } else { put else }").Puts("else"),
  276. That("if $false { put 1 } elif $false { put 2 } else { put 3 }").
  277. Puts("3"),
  278. That("if $false { put 2 } elif true { put 2 } else { put 3 }").Puts("2"),
  279. // Exception in condition expression
  280. That("if (fail x) { }").Throws(FailError{"x"}, "fail x"),
  281. )
  282. }
  283. func TestTry(t *testing.T) {
  284. Test(t,
  285. That("try { nop } catch { put bad } else { put good }").Puts("good"),
  286. That("try { fail tr } catch - { put bad } else { put good }").
  287. Puts("bad"),
  288. That("try { fail tr } finally { put final }").
  289. Puts("final").
  290. Throws(ErrorWithMessage("tr")),
  291. That("try { fail tr } catch { fail ex } finally { put final }").
  292. Puts("final").
  293. Throws(ErrorWithMessage("ex")),
  294. That("try { fail tr } catch { put ex } finally { fail final }").
  295. Puts("ex").
  296. Throws(ErrorWithMessage("final")),
  297. That("try { fail tr } catch { fail ex } finally { fail final }").
  298. Throws(ErrorWithMessage("final")),
  299. // except is a deprecated synonym for catch
  300. That("try { fail tr } except { put bad }").
  301. Puts("bad").PrintsStderrWith("deprecated"),
  302. // Must have catch or finally
  303. That("try { fail tr }").DoesNotCompile("try must be followed by a catch block or a finally block"),
  304. // Rest variable not allowed
  305. That("try { nop } catch @a { }").DoesNotCompile("rest variable not allowed"),
  306. // A readonly var as a target for the "catch" clause is a compile-time
  307. // error.
  308. That("try { fail reason } catch nil { }").DoesNotCompile("variable $nil is read-only"),
  309. That("try { fail reason } catch x { }").DoesNothing(),
  310. // A quoted var name, that would be invalid as a bareword, should be allowed as the referent
  311. // in a `try...except...` block.
  312. That("try { fail hard } catch 'x=' { put 'x= ='(to-string $'x=') }").
  313. Puts("x= =[&reason=[&content=hard &type=fail]]"),
  314. )
  315. }
  316. func TestTry_ExceptIsDeprecated(t *testing.T) {
  317. testCompileTimeDeprecation(t, "try { } except { }",
  318. `"except" is deprecated; use "catch" instead`, 18)
  319. }
  320. func TestWhile(t *testing.T) {
  321. Test(t,
  322. That("var x = (num 0)", "while (< $x 4) { put $x; set x = (+ $x 1) }").
  323. Puts(0, 1, 2, 3),
  324. // break
  325. That("var x = (num 0)", "while (< $x 4) { put $x; break }").Puts(0),
  326. // continue
  327. That("var x = (num 0)",
  328. "while (< $x 4) { put $x; set x = (+ $x 1); continue; put bad }").
  329. Puts(0, 1, 2, 3),
  330. // Exception in body
  331. That("var x = 0; while (< $x 4) { fail haha }").Throws(FailError{"haha"}),
  332. // Exception in condition
  333. That("while (fail x) { }").Throws(FailError{"x"}, "fail x"),
  334. // else branch - not taken
  335. That("var x = 0; while (< $x 4) { put $x; set x = (+ $x 1) } else { put bad }").
  336. Puts("0", 1, 2, 3),
  337. // else branch - taken
  338. That("while $false { put bad } else { put good }").Puts("good"),
  339. )
  340. }
  341. func TestFor(t *testing.T) {
  342. Test(t,
  343. // for
  344. That("for x [tempora mores] { put 'O '$x }").
  345. Puts("O tempora", "O mores"),
  346. // break
  347. That("for x [a] { break } else { put $x }").DoesNothing(),
  348. // else
  349. That("for x [a] { put $x } else { put $x }").Puts("a"),
  350. // continue
  351. That("for x [a b] { put $x; continue; put $x; }").Puts("a", "b"),
  352. // else
  353. That("for x [] { } else { put else }").Puts("else"),
  354. That("for x [a] { } else { put else }").DoesNothing(),
  355. // Propagating exception.
  356. That("for x [a] { fail foo }").Throws(FailError{"foo"}),
  357. // More than one iterator.
  358. That("for {x,y} [] { }").DoesNotCompile("must be exactly one lvalue"),
  359. // Invalid for loop lvalue. You can't use a var in a namespace other
  360. // than the local namespace as the lvalue in a for loop.
  361. That("for no-such-namespace:x [a b] { }").DoesNotCompile("cannot create variable $no-such-namespace:x; new variables can only be created in the current scope"),
  362. // Exception with the variable
  363. That("var a: = (ns [&])", "for a:b [] { }").Throws(
  364. ErrorWithMessage("no variable $a:b"),
  365. "a:b"),
  366. // Exception when evaluating iterable.
  367. That("for x [][0] { }").Throws(ErrorWithType(errs.OutOfRange{}), "[][0]"),
  368. // More than one iterable.
  369. That("for x (put a b) { }").Throws(
  370. errs.ArityMismatch{What: "value being iterated",
  371. ValidLow: 1, ValidHigh: 1, Actual: 2},
  372. "(put a b)"),
  373. // Non-iterable value
  374. That("for x (num 0) { }").Throws(ErrorWithMessage("cannot iterate number")),
  375. )
  376. }
  377. func TestFn(t *testing.T) {
  378. Test(t,
  379. That("fn f {|x| put x=$x'.' }; f lorem; f ipsum").
  380. Puts("x=lorem.", "x=ipsum."),
  381. // Recursive functions with fn. Regression test for #1206.
  382. That("fn f {|n| if (== $n 0) { num 1 } else { * $n (f (- $n 1)) } }; f 3").
  383. Puts(6),
  384. // Exception thrown by return is swallowed by a fn-defined function.
  385. That("fn f { put a; return; put b }; f").Puts("a"),
  386. // Error when evaluating the lambda
  387. That("fn f {|&opt=(fail x)| }").Throws(FailError{"x"}, "fail x"),
  388. )
  389. }
  390. // Regression test for #1225
  391. func TestUse_SetsVariableCorrectlyIfModuleCallsExtendGlobal(t *testing.T) {
  392. libdir := testutil.InTempDir(t)
  393. testutil.ApplyDir(testutil.Dir{"a.elv": "add-var"})
  394. ev := NewEvaler()
  395. ev.LibDirs = []string{libdir}
  396. addVar := func() {
  397. ev.ExtendGlobal(BuildNs().AddVar("b", vars.NewReadOnly("foo")))
  398. }
  399. ev.ExtendBuiltin(BuildNs().AddGoFn("add-var", addVar))
  400. err := ev.Eval(parse.Source{Name: "[test]", Code: "use a"}, EvalCfg{})
  401. if err != nil {
  402. t.Fatal(err)
  403. }
  404. g := ev.Global()
  405. if g.IndexString("a:").Get().(*Ns) == nil {
  406. t.Errorf("$a: is nil")
  407. }
  408. if g.IndexString("b").Get().(string) != "foo" {
  409. t.Errorf(`$b is not "foo"`)
  410. }
  411. }
  412. func TestUse_SupportsCircularDependency(t *testing.T) {
  413. libdir := testutil.InTempDir(t)
  414. testutil.ApplyDir(testutil.Dir{
  415. "a.elv": "var pre = apre; use b; put $b:pre $b:post; var post = apost",
  416. "b.elv": "var pre = bpre; use a; put $a:pre $a:post; var post = bpost",
  417. })
  418. TestWithSetup(t, func(ev *Evaler) { ev.LibDirs = []string{libdir} },
  419. That(`use a`).Puts(
  420. // When b.elv is imported from a.elv, $a:pre is set but $a:post is
  421. // not
  422. "apre", nil,
  423. // After a.elv imports b.elv, both $b:pre and $b:post are set
  424. "bpre", "bpost"),
  425. )
  426. }
  427. func TestUse(t *testing.T) {
  428. libdir1 := testutil.InTempDir(t)
  429. testutil.ApplyDir(testutil.Dir{
  430. "shadow.elv": "put lib1",
  431. "invalid-utf8.elv": "\xff",
  432. })
  433. libdir2 := testutil.InTempDir(t)
  434. testutil.ApplyDir(testutil.Dir{
  435. "has-init.elv": "put has-init",
  436. "put-x.elv": "put $x",
  437. "lorem.elv": "var name = lorem; fn put-name { put $name }",
  438. "d.elv": "var name = d",
  439. "shadow.elv": "put lib2",
  440. "a": testutil.Dir{
  441. "b": testutil.Dir{
  442. "c": testutil.Dir{
  443. "d.elv": "var name = a/b/c/d",
  444. "x.elv": "use ./d; var d = $d:name; use ../../../lorem; var lorem = $lorem:name",
  445. },
  446. },
  447. },
  448. })
  449. TestWithSetup(t, func(ev *Evaler) { ev.LibDirs = []string{libdir1, libdir2} },
  450. That(`use lorem; put $lorem:name`).Puts("lorem"),
  451. // imports are lexically scoped
  452. // TODO: Support testing for compilation error
  453. That(`{ use lorem }; put $lorem:name`).DoesNotCompile("variable $lorem:name not found"),
  454. // prefers lib dir that appear earlier
  455. That("use shadow").Puts("lib1"),
  456. // use of imported variable is captured in upvalue
  457. That(`use lorem; { put $lorem:name }`).Puts("lorem"),
  458. That(`{ use lorem; { put $lorem:name } }`).Puts("lorem"),
  459. That(`({ use lorem; put { { put $lorem:name } } })`).Puts("lorem"),
  460. // use of imported function is also captured in upvalue
  461. That(`{ use lorem; { lorem:put-name } }`).Puts("lorem"),
  462. // use of a nested module
  463. That(`use a/b/c/d; put $d:name`).Puts("a/b/c/d"),
  464. // module is cached after first use
  465. That(`use has-init; use has-init`).Puts("has-init"),
  466. // repeated uses result in the same namespace being imported
  467. That("use lorem; use lorem lorem2; put $lorem:name $lorem2:name").
  468. Puts("lorem", "lorem"),
  469. // overriding module
  470. That(`use d; put $d:name; use a/b/c/d; put $d:name`).
  471. Puts("d", "a/b/c/d"),
  472. // relative uses
  473. That(`use a/b/c/x; put $x:d $x:lorem`).Puts("a/b/c/d", "lorem"),
  474. // relative uses from top-level
  475. That(`use ./d; put $d:name`).Puts("d"),
  476. // Renaming module
  477. That(`use a/b/c/d mod; put $mod:name`).Puts("a/b/c/d"),
  478. // Variables defined in the default global scope is invisible from
  479. // modules
  480. That("var x = foo; use put-x").Throws(ErrorWithType(&diag.Error{})),
  481. // Using an unknown module spec fails.
  482. That("use unknown").Throws(ErrorWithType(NoSuchModule{})),
  483. That("use ./unknown").Throws(ErrorWithType(NoSuchModule{})),
  484. That("use ../unknown").Throws(ErrorWithType(NoSuchModule{})),
  485. // Invalid UTF-8 in module file
  486. That("use invalid-utf8").Throws(ErrorWithMessage(
  487. filepath.Join(libdir1, "invalid-utf8.elv")+": source is not valid UTF-8")),
  488. // Nonexistent module
  489. That("use non-existent").Throws(ErrorWithMessage("no such module: non-existent")),
  490. // Wrong uses of "use".
  491. That("use").DoesNotCompile("use requires a module name"),
  492. That("use a b c").DoesNotCompile("use has superfluous argument(s)"),
  493. )
  494. }
  495. // Regression test for #1072
  496. func TestUse_WarnsAboutDeprecatedFeatures(t *testing.T) {
  497. testutil.Set(t, &prog.DeprecationLevel, 18)
  498. libdir := testutil.InTempDir(t)
  499. must.WriteFile("dep.elv", "a=b nop $a")
  500. TestWithSetup(t, func(ev *Evaler) { ev.LibDirs = []string{libdir} },
  501. // Importing module triggers check for deprecated features
  502. That("use dep").PrintsStderrWith("is deprecated"),
  503. )
  504. }