builtins: test def, use, export, export*
s-ol
3 months ago
0 | import TestPilot from require 'spec.test_setup' | |
1 | import T, Constant, Scope from require 'alv' | |
2 | ||
3 | describe "def", -> | |
4 | COPILOT = TestPilot! | |
5 | ||
6 | it "returns nothing", -> | |
7 | with COPILOT\eval_once '(def _ 3)' | |
8 | assert.is.true \is_const! | |
9 | assert.is.nil .result | |
10 | ||
11 | it "passes through side-effects", -> | |
12 | with COPILOT\eval_once ' | |
13 | (import* time) | |
14 | (def nonconst (every 0.5 "bang!"))' | |
15 | assert.is.false \is_const! | |
16 | assert.is.nil .result | |
17 | assert.is.equal T.clock, (next .children[2].side_inputs).type | |
18 | ||
19 | it "validates args", -> | |
20 | err = assert.has.error -> COPILOT\eval_once '(def)' | |
21 | assert.matches "requires at least 2 arguments", err | |
22 | ||
23 | err = assert.has.error -> COPILOT\eval_once '(def a)' | |
24 | assert.matches "requires at least 2 arguments", err | |
25 | ||
26 | err = assert.has.error -> COPILOT\eval_once '(def a 1 b)' | |
27 | assert.matches "requires an even number of arguments", err | |
28 | ||
29 | err = assert.has.error -> COPILOT\eval_once '(def (+ 1 2) 3)' | |
30 | assert.matches "name is not a symbol", err | |
31 | ||
32 | it "cannot redefine symbols", -> | |
33 | err = assert.has.error -> COPILOT\eval_once ' | |
34 | (def a 1 | |
35 | a 2)' | |
36 | assert.matches "cannot redefine symbol", err | |
37 | ||
38 | it "can hide symbols", -> | |
39 | with COPILOT\eval_once ' | |
40 | (def a 1) | |
41 | (do | |
42 | (def a 2) | |
43 | a) | |
44 | a' | |
45 | assert.is.true \is_const! | |
46 | assert.is.equal (Constant.num 1), .result | |
47 | assert.is.equal (Constant.num 2), .children[2].result | |
48 | ||
49 | describe "export", -> | |
50 | COPILOT = TestPilot! | |
51 | ||
52 | it "returns a scope containing new defs", -> | |
53 | with COPILOT\eval_once '(export)' | |
54 | assert.is.true \is_const! | |
55 | assert.is.equal T.scope, .result.type | |
56 | assert.is.same {}, .result!.values | |
57 | ||
58 | with COPILOT\eval_once '(export (def a 1 b 2))' | |
59 | assert.is.true \is_const! | |
60 | assert.is.equal T.scope, .result.type | |
61 | assert.is.equal (Constant.num 1), .result!.values.a.result | |
62 | assert.is.equal (Constant.num 2), .result!.values.b.result | |
63 | ||
64 | it "passes through side-effects", -> | |
65 | with COPILOT\eval_once ' | |
66 | (import* time) | |
67 | (export | |
68 | (def hello (every 0.5 "bang!")) | |
69 | (every 0.5 42))' | |
70 | assert.is.false \is_const! | |
71 | assert.is.equal T.scope, .result.type | |
72 | a = next .children[2].children[1].side_inputs | |
73 | b = next .children[2].children[2].side_inputs | |
74 | assert.is.truthy .side_inputs[a] | |
75 | assert.is.truthy .side_inputs[b] | |
76 | ||
77 | it "doesn't mutate the current scope", -> | |
78 | with COPILOT\eval_once ' | |
79 | (def a 1) | |
80 | (export | |
81 | (def a 5) | |
82 | (def b 2)) | |
83 | (export*)' | |
84 | assert.is.true \is_const! | |
85 | assert.is.equal T.scope, .result.type | |
86 | assert.is.equal (Constant.num 1), .result!.values.a.result | |
87 | assert.is.nil .result!.values.b | |
88 | ||
89 | describe "export*", -> | |
90 | COPILOT = TestPilot! | |
91 | ||
92 | it "validates args", -> | |
93 | err = assert.has.error -> COPILOT\eval_once '(export* (+ 1 2))' | |
94 | assert.matches "arguments need to be symbols", err | |
95 | ||
96 | err = assert.has.error -> COPILOT\eval_once '(export* 3)' | |
97 | assert.matches "is not a sym", err | |
98 | ||
99 | err = assert.has.error -> COPILOT\eval_once '(export* a)' | |
100 | assert.matches "undefined symbol", err | |
101 | ||
102 | describe "without args", -> | |
103 | it "returns a scope containing all local defs", -> | |
104 | with COPILOT\eval_once '(export*)' | |
105 | assert.is.true \is_const! | |
106 | assert.is.equal T.scope, .result.type | |
107 | assert.is.same {}, .result!.values | |
108 | ||
109 | with COPILOT\eval_once ' | |
110 | (def a 1 b "hello" c 3) | |
111 | (export*)' | |
112 | assert.is.true \is_const! | |
113 | assert.is.equal T.scope, .result.type | |
114 | assert.is.equal (Constant.num 1), .result!.values.a.result | |
115 | assert.is.equal (Constant.str 'hello'), .result!.values.b.result | |
116 | assert.is.equal (Constant.num 3), .result!.values.c.result | |
117 | ||
118 | describe "with args", -> | |
119 | it "returns a scope containing those defs", -> | |
120 | with COPILOT\eval_once ' | |
121 | (def a 1 b "hello" c 3) | |
122 | (export* a b)' | |
123 | assert.is.true \is_const! | |
124 | assert.is.equal T.scope, .result.type | |
125 | assert.is.equal (Constant.num 1), .result!.values.a.result | |
126 | assert.is.equal (Constant.str 'hello'), .result!.values.b.result | |
127 | assert.is.nil .result!.values.c | |
128 | ||
129 | describe "use", -> | |
130 | COPILOT = TestPilot! | |
131 | ||
132 | it "returns nothing", -> | |
133 | with COPILOT\eval_once '(use (export))' | |
134 | assert.is.true \is_const! | |
135 | assert.is.nil .result | |
136 | ||
137 | it "updates the current scope", -> | |
138 | with COPILOT\eval_once ' | |
139 | (use (export | |
140 | (def a 2))) | |
141 | a' | |
142 | assert.is.true \is_const! | |
143 | assert.is.equal (Constant.num 2), .result | |
144 | ||
145 | it "terms and conditions apply", -> | |
146 | err = assert.has.error -> COPILOT\eval_once ' | |
147 | (def a 1) | |
148 | (use | |
149 | (export | |
150 | (def a 5) | |
151 | (def b 2)))' | |
152 | assert.matches "cannot redefine symbol", err |