git.m455.casa

fa

clone url: git://git.m455.casa/fa


esperbuild/espersrc/fennel-0.7.0/test/core.fnl

1 (local l (require :test.luaunit))
2 (local fennel (require :fennel))
3
4 (set _G.tbl [])
5
6 (fn test-calculations []
7 (let [cases {"(% 1 2 (- 1 2))" 0
8 "(* 1 2 (/ 1 2))" 1
9 "(*)" 1
10 "(+ 1 2 (- 1 2))" 2
11 "(+ 1 2 (^ 1 2))" 4
12 "(+)" 0
13 "(- 1)" (- 1)
14 "(/ 2)" (/ 1 2)}]
15 (each [code expected (pairs cases)]
16 (l.assertEquals (fennel.eval code {:correlate true}) expected code))))
17
18 (fn test-booleans []
19 (let [cases {"(and 43 table false)" false
20 "(and 5)" 5
21 "(and true 12 \"hey\")" "hey"
22 "(and)" true
23 "(not 39)" false
24 "(not nil)" true
25 "(not true)" false
26 "(or 11 true false)" 11
27 "(or 5)" 5
28 "(or false nil true 12 false)" true
29 "(or)" false}]
30 (each [code expected (pairs cases)]
31 (l.assertEquals (fennel.eval code {:correlate true}) expected code))))
32
33 (fn test-comparisons []
34 (let [cases {"(< -4 89)" true
35 "(<= 5 1 91)" false
36 "(<= 88 32)" false
37 "(= 1 1 2 2)" false
38 "(> -4 89)" false
39 "(> 2 0 -1)" true
40 "(> 2 0)" true
41 "(>= 22 (+ 21 1))" true
42 "(let [f (fn [] (tset tbl :dbl (+ 1 (or (. tbl :dbl) 0))) 1)]
43 (< 0 (f) 2) (. tbl :dbl))" 1
44 "(not= 33 1)" true
45 "(not= 6 6 9)" true
46 "(~= 33 1)" true ; undocumented backwards-compat alias
47 }]
48 (each [code expected (pairs cases)]
49 (l.assertEquals (fennel.eval code {:correlate true}) expected code))))
50
51 (fn test-parsing []
52 (set _G.parsedbg true)
53 (let [cases {"\"\\\\\"" "\\"
54 "\"abc\n\\240\"" "abc\n\240"
55 "\"abc\\\"def\"" "abc\"def"
56 "\"abc\\240\"" "abc\240"
57 :150_000 150000}]
58 (each [code expected (pairs cases)]
59 (l.assertEquals (fennel.eval code {:correlate true}) expected code))))
60
61 (fn test-functions []
62 (let [cases {;; regular function
63 "((fn [x] (* x 2)) 26)" 52
64 ;; basic lambda
65 "((lambda [x] (+ x 2)) 4)" 6
66 ;; vararg lambda
67 "((lambda [x ...] (+ x 2)) 4)" 6
68 ;; underscore lambda
69 "((lambda [x _ y] (+ x y)) 4 5 6)" 10
70 ;; lambdas perform arity checks
71 "(let [(ok e) (pcall (lambda [x] (+ x 2)))]
72 (string.match e \"Missing argument x\"))" "Missing argument x"
73 ;; lambda arity checks skip argument names starting with ?
74 "(let [(ok val) (pcall (λ [?x] (+ (or ?x 1) 8)))] (and ok val))" 9
75 ;; lambda with no body returns nil
76 "(if (= nil ((lambda [a]) 1)) :lambda-works)" :lambda-works
77 ;; closures can set vars they close over
78 "(var a 11) (let [f (fn [] (set a (+ a 2)))] (f) (f) a)" 15
79 ;; nested functions
80 "(let [f (fn [x y f2] (+ x (f2 y)))
81 f2 (fn [x y] (* x (+ 2 y)))
82 f3 (fn [f] (fn [x] (f 5 x)))]
83 (f 9 5 (f3 f2)))" 44
84
85 ;; pick-args
86 "((pick-args 5 (partial select :#)))" 5
87 "(let [f (fn [...] [...]) f-0 (pick-args 0 f)] (f-0 :foo))" []
88 "(let [f (fn [...] [...]) f-2 (pick-args 2 f)] (f-2 1 2 3))" [1 2]
89 ;; pick-values
90 "(select :# (pick-values 3))" 3
91 "(let [f #(values :a :b :c)] [(pick-values 0 (f))])" []
92 "[(pick-values 4 :a :b :c (values :d :e))]" ["a" "b" "c" "d"]
93
94 ;; method calls work
95 "(: :hello :find :e)" 2
96 ;; method calls work on identifiers that aren't valid lua
97 "(let [f {:+ #(+ $2 $3 $4)}] (f:+ 1 2 9))" 12
98 ;; method calls work non-native with no args
99 "(let [f {:+ #18}] (f:+))" 18
100 ;; method calls don't double up side effects
101 "(var a 0) (let [f (fn [] (set a (+ a 1)) :hi)] (: (f) :find :h)) a" 1
102
103 ;; functions with empty bodies return nil
104 "(if (= nil ((fn [a]) 1)) :pass :fail)" "pass"
105
106 ;; partial application
107 "(let [add (fn [x y z] (+ x y z)) f2 (partial add 1 2)] (f2 6))" 9
108 "(let [add (fn [x y] (+ x y)) add2 (partial add)] (add2 99 2))" 101
109 "(let [add (fn [x y] (+ x y)) inc (partial add 1)] (inc 99))" 100
110
111 ;; many args
112 "((fn f [a sin cos radC cx cy x y limit dis] sin) 8 529)" 529
113 }]
114 (each [code expected (pairs cases)]
115 (l.assertEquals (fennel.eval code {:correlate true}) expected code))))
116
117 (fn test-conditionals []
118 (let [cases {"(if _G.non-existent 1 (* 3 9))" 27
119 "(if false \"yep\" \"nope\")" "nope"
120 "(if false :y true :x :trailing :condition)" "x"
121 "(let [b :original b (if false :not-this)] (or b :nil))" "nil"
122 "(let [x 1 y 2] (if (= (* 2 x) y) \"yep\"))" "yep"
123 "(let [x 3 res (if (= x 1) :ONE (= x 2) :TWO true :???)] res)" "???"
124 "(let [x {:y 2}] (if false \"yep\" (< 1 x.y 3) \"uh-huh\" \"nope\"))" "uh-huh"
125 "(var [a z] [0 0]) (when true (set a 192) (set z 12)) (+ z a)" 204
126 "(var a 884) (when nil (set a 192)) a" 884
127 "(var i 0) (var s 0) (while (let [l 11] (< i l)) (set s (+ s i)) (set i (+ 1 i))) s" 55
128 "(var x 12) (if true (set x 22) 0) x" 22
129 "(when (= 12 88) (os.exit 1)) false" false
130 "(while (let [f false] f) (lua :break))" nil}]
131 (each [code expected (pairs cases)]
132 (l.assertEquals (fennel.eval code {:correlate true}) expected code))))
133
134 (fn test-core []
135 (let [cases {"(+ (. {:a 93 :b 4} :a) (. [1 2 3] 2))" 95
136 "(: {:foo (fn [self] (.. self.bar 2)) :bar :baz} :foo)" "baz2"
137 "(do (tset {} :a 1) 1)" 1
138 "(do (var a nil) (var b nil) (local ret (fn [] a)) (set (a b) (values 4 5)) (ret))" 4
139 "(fn b [] (each [e {}] (e))) (let [(_ e) (pcall b)] (e:match \":[1]: .*\"))" ":1: attempt to call a table value"
140 "(global a_b :global) (local a-b :local) a_b" "global"
141 "(global x 1) (global x 284) x" 284
142 "(let [k 5 t {: k}] t.k)" 5
143 "(let [my-tbl {} k :key] (tset my-tbl k :val) my-tbl.key)" "val"
144 "(let [t [[21]]] (+ (. (. t 1) 1) (. t 1 1)))" 42
145 "(let [t []] (table.insert t \"lo\") (. t 1))" "lo"
146 "(let [t []] (tset t :a (let [{: a} {:a :bcd}] a)) t.a)" "bcd"
147 "(let [t {} _ (tset t :a 84)] (. t :a))" 84
148 "(let [t {}] (set t.a :multi) (. t :a))" "multi"
149 "(let [x 17] (. 17))" 17
150 "(let [x 3 y nil z 293] z)" 293
151 "(let [xx (let [xx 1] (* xx 2))] xx)" 2
152 "(local a 3) (let [b 2] (set-forcibly! a 7) (set-forcibly! b 6) (+ a b))" 13
153 "(local x#x# 90) x#x#" 90
154 "(table.concat [\"ab\" \"cde\"] \",\")" "ab,cde"
155 "(var [x y] [3 2]) (set (x y) (do (local [x y] [(* x 3) 0]) (values x y))) (+ x y)" 9
156 "(var a 0) (for [_ 1 3] (let [] (table.concat []) (set a 33))) a" 33
157 "(var i 0) (each [_ ((fn [] (pairs [1])))] (set i 1)) i" 1
158 "(var n 0) (let [f (fn [] (set n 96))] (f) n)" 96
159 "(var x 1) (let [_ (set x 92)] x)" 92
160 "(var x 12) ;; (set x 99)\n x" 12
161 "74 ; (require \"hey.dude\")" 74}]
162 (each [code expected (pairs cases)]
163 (l.assertEquals (fennel.eval code {:correlate true}) expected code))))
164
165 (fn test-if []
166 (let [cases {"(do (fn myfn [x y z] (+ x y z)) (myfn 1 (if 1 (values 2 5) 3) 4))" 7
167 "(do (fn myfn [x y z] (+ x y z)) (myfn 1 (if 1 2 3) 4))" 7
168 "(do (fn myfn [x y z] (+ x y z)) (myfn 1 4 (if 1 2 3)))" 7
169 "(if (values 1 2) 3 4)" 3
170 "(if (values 1) 3 4)" 3
171 "(let [x (if false 3 (values 2 5))] x)" 2}]
172 (each [code expected (pairs cases)]
173 (l.assertEquals (fennel.eval code {:correlate true}) expected code))))
174
175 (fn test-destructuring []
176 (let [cases {"((fn dest [a [b c] [d]] (+ a b c d)) 5 [9 7] [2])" 23
177 "((lambda [[a & b]] (+ a (. b 2))) [90 99 4])" 94
178 "(global (a b) ((fn [] (values 4 29)))) (+ a b)" 33
179 "(global [a b c d] [4 2 43 7]) (+ (* a b) (- c d))" 44
180 "(let [(a [b [c] d]) ((fn [] (values 4 [2 [1] 9])))] (+ a b c d))" 16
181 "(let [(a [b [c] d]) (values 4 [2 [1] 9])] (+ a b c d))" 16
182 "(let [(a b) ((fn [] (values 4 2)))] (+ a b))" 6
183 "(let [[a [b c] d] [4 [2 43] 7]] (+ (* a b) (- c d)))" 44
184 "(let [[a b & c] [1 2 3 4 5]] (+ a (. c 2) (. c 3)))" 10
185 "(let [[a b c d] [4 2 43 7]] (+ (* a b) (- c d)))" 44
186 "(let [[a b c] [4 2]] (or c :missing))" "missing"
187 "(let [[a b] [9 2 49]] (+ a b))" 11
188 "(let [x 1 x (if (= x 1) 2 3)] x)" 2
189 "(let [{: a : b} {:a 3 :b 5}] (+ a b))" 8
190 "(let [{:a [x y z]} {:a [1 2 4]}] (+ x y z))" 7
191 "(let [{:a x :b y} {:a 2 :b 4}] (+ x y))" 6
192 "(local (-a -b) ((fn [] (values 4 29)))) (+ -a -b)" 33
193 "(var [a [b c]] [1 [2 3]]) (set a 2) (set c 8) (+ a b c)" 12
194 "(var x 0) (each [_ [a b] (ipairs [[1 2] [3 4]])] (set x (+ x (* a b)))) x" 14}]
195 (each [code expected (pairs cases)]
196 (l.assertEquals (fennel.eval code {:correlate true}) expected code))))
197
198 (fn test-loops []
199 (let [cases {"(for [y 0 2] nil) (each [x (pairs [])] nil)
200 (match [1 2] [x y] (+ x y))" 3
201 "(let [t {:a 1 :b 2} t2 {}]
202 (each [k v (pairs t)]
203 (tset t2 k v))
204 (+ t2.a t2.b))" 3
205 "(var t 0) (local (f s v) (pairs [1 2 3]))
206 (each [_ x (values f (doto s (table.remove 1)))] (set t (+ t x))) t" 5
207 "(var t 0) (local (f s v) (pairs [1 2 3]))
208 (each [_ x (values f s v)] (set t (+ t x))) t" 6
209 "(var x 0) (for [y 1 20 2] (set x (+ x 1))) x" 10
210 "(var x 0) (for [y 1 5] (set x (+ x 1))) x" 5
211 "(var x 0) (while (< x 7) (set x (+ x 1))) x" 7}]
212 (each [code expected (pairs cases)]
213 (l.assertEquals (fennel.eval code) expected code))))
214
215 (fn test-edge []
216 (let [cases {"(. (let [t (let [t {} k :a] (tset t k 123) t) k :b] (tset t k 321) t) :a)" 123
217 "(length [(if (= (+ 1 1) 2) (values 1 2 3 4 5) (values 1 2 3))])" 5
218 "(length [(values 1 2 3 4 5)])" 5
219 "(let [(a b c d e f g) (if (= (+ 1 1) 2) (values 1 2 3 4 5 6 7))] (+ a b c d e f g))" 28
220 "(let [(a b c d e f g) (if (= (+ 1 1) 3) nil
221 ((or _G.unpack table.unpack) [1 2 3 4 5 6 7]))]
222 (+ a b c d e f g))" 28
223 "(let [t {:st {:v 5 :f #(+ $.v $2)}} x (#(+ $ $2) 1 3)] (t.st:f x) nil)" nil
224 "(let [x (if 3 4 5)] x)" 4
225 "(select \"#\" (if (= 1 (- 3 2)) (values 1 2 3 4 5) :onevalue))" 5
226 (.. "(do (local c1 20) (local c2 40) (fn xyz [A B] (and A B)) "
227 "(xyz (if (and c1 c2) true false) 52))") 52
228 "(let [t {} _ (set t.field :let-side)] t.field)" :let-side}]
229 (each [code expected (pairs cases)]
230 (l.assertEquals (fennel.eval code {:correlate true}) expected code))))
231
232 (fn test-hashfn []
233 (let [cases {"(#$.foo {:foo :bar})" "bar"
234 "(#$2.foo.bar.baz nil {:foo {:bar {:baz :quux}}})" "quux"
235 "(#(+ $ 2) 3)" 5
236 "(#(+ $1 $2) 3 4)" 7
237 "(#(+ $1 45) 1)" 46
238 "(#(+ $3 $4) 1 1 3 4)" 7
239 "(#[(select :# $...) $...] :a :b :c)" [3 "a" "b" "c"]
240 "(+ (#$ 1) (#$2 2 3))" 4
241 "(let [f #(+ $ $1 $2)] (f 1 2))" 4
242 "(let [f #(+ $1 45)] (f 1))" 46
243 "(let [f #(do (local a 1) (local b (+ $1 $1 a)) (+ a b))] (f 1))" 4}]
244 (each [code expected (pairs cases)]
245 (l.assertEquals (fennel.eval code {:correlate true}) expected code))))
246
247 (fn test-method_calls []
248 (let [cases {"(let [x {:foo (fn [self arg1] (.. self.bar arg1)) :bar :baz}] (x:foo :quux))"
249 "bazquux"
250 "(let [x {:y {:foo (fn [self arg1] (.. self.bar arg1)) :bar :baz}}] (x.y:foo :quux))"
251 "bazquux"}]
252 (each [code expected (pairs cases)]
253 (l.assertEquals (fennel.eval code {:correlate true}) expected code))))
254
255 (fn test-with-open []
256 (let [cases {"(var (fh1 fh2) nil) [(with-open [f1 (io.tmpfile) f2 (io.tmpfile)]
257 (set [fh1 fh2] [f1 f2]) (f1:write :asdf) (f1:seek :set 0) (f1:read :*a))
258 (io.type fh1) (io.type fh2)]" ["asdf" "closed file" "closed file"]
259 "(var fh nil) (local (ok msg) (pcall #(with-open [f (io.tmpfile)] (set fh f)
260 (error :bork!)))) [(io.type fh) ok (msg:match :bork!)]" ["closed file" false "bork!"]
261 "[(with-open [proc1 (io.popen \"echo hi\") proc2 (io.popen \"echo bye\")]
262 (values (proc1:read) (proc2:read)))]" ["hi" "bye"]}]
263 (each [code expected (pairs cases)]
264 (l.assertEquals (fennel.eval code) expected code))))
265
266 (fn test-match []
267 (let [cases {"(let [_ :bar] (match :foo _ :should-match :foo :no))" "should-match"
268 "(let [k :k] (match [5 :k] :b :no [n k] n))" 5
269 "(let [s :hey] (match s :wat :no :hey :yes))" "yes"
270 "(let [x 3 res (match x 1 :ONE 2 :TWO _ :???)] res)" "???"
271 "(let [x 95] (match [52 85 95] [x y z] :nope [a b x] :yes))" "yes"
272 "(let [x {:y :z}] (match :z x.y 1 _ 0))" 1
273 "(match (+ 1 6) 7 8 8 1 9 2)" 8
274 "(match (+ 1 6) 7 8)" 8
275 "(match (io.open \"/does/not/exist\") (nil msg) :err f f)" "err"
276 "(match (values 1 [1 2]) (x [x x]) :no (x [x y]) :yes)" "yes"
277 "(match (values 5 9) 9 :no (a b) (+ a b))" 14
278 "(match (values nil :nonnil) (true _) :no (nil b) b)" "nonnil"
279 "(match [1 2 1] [x y x] :yes)" "yes"
280 "(match [1 2 3] [3 2 1] :no [2 9 1] :NO :default)" "default"
281 "(match [1 2 3] [a & b] (+ a (. b 1) (. b 2)))" 6
282 "(match [1 2 3] [x y x] :no [x y z] :yes)" "yes"
283 "(match [1 2 [[1]]] [x y [z]] (. z 1))" 1
284 "(match [1 2 [[3]]] [x y [[x]]] :no [x y z] :yes)" "yes"
285 "(match [1 2] [_ _] :wildcard)" "wildcard"
286 "(match [1] [a & b] (# b))" 0
287 "(match [1] [a & b] (length b))" 0
288 "(match [9 5] [a b ?c] :three [a b] (+ a b))" "three"
289 "(match [9 5] [a b c] :three [a b] (+ a b))" 14
290 "(match [:a :b :c] [1 t d] :no [a b :d] :NO [a b :c] b)" "b"
291 "(match [:a :b :c] [a b c] (.. b :eee))" "beee"
292 "(match [:a [:b :c]] [a b :c] :no [:a [:b c]] c)" "c"
293 "(match [:a {:b 8}] [a b :c] :no [:a {:b b}] b)" 8
294 "(match [{:sieze :him} 5]
295 ([f 4] ? f.sieze (= f.sieze :him)) 4
296 ([f 5] ? f.sieze (= f.sieze :him)) 5)" 5
297 "(match nil _ :yes nil :no)" "yes"
298 "(match {:a 1 :b 2} {:c 3} :no {:a n} n)" 1
299 "(match {:sieze :him}
300 (tbl ? (. tbl :no)) :no
301 (tbl ? (. tbl :sieze)) :siezed)" "siezed"
302 "(match {:sieze :him}
303 (tbl ? tbl.sieze tbl.no) :no
304 (tbl ? tbl.sieze (= tbl.sieze :him)) :siezed2)" "siezed2"
305 "(var x 1) (fn i [] (set x (+ x 1)) x) (match (i) 4 :N 3 :n 2 :y)" "y"}]
306 (each [code expected (pairs cases)]
307 (l.assertEquals (fennel.eval code {:correlate true}) expected code))))
308
309 (fn test-fennelview []
310 (let [cases {"((require :fennelview) (let [t {}] [t t]) {:detect-cycles? false})"
311 "[{} {}]"
312 "((require :fennelview) (let [t {}] [t t]))"
313 "[@2{} #<table @2>]"
314 "((require :fennelview) {:a 1 :b 52})"
315 "{
316 :a 1
317 :b 52
318 }"
319 "((require :fennelview) {:a 1 :b 5} {:one-line true})"
320 "{:a 1 :b 5}"
321 ;; ensure it works on lists/syms inside compiler
322 "(eval-compiler
323 (set _G.out ((require :fennelview) '(a {} [1 2]))))
324 _G.out"
325 "(a {} [1 2])"}]
326 (each [code expected (pairs cases)]
327 (l.assertEquals (fennel.eval code {:correlate true :compiler-env _G})
328 expected code))
329 (let [mt (setmetatable [] {:__fennelview (fn [] "META")})]
330 (l.assertEquals ((require "fennelview") mt) "META"))))
331
332 (fn test-comment []
333 (l.assertEquals "-- hello world\nreturn nil"
334 (fennel.compile-string "(comment hello world)")))
335
336 {: test-booleans
337 : test-calculations
338 : test-comparisons
339 : test-conditionals
340 : test-core
341 : test-destructuring
342 : test-edge
343 : test-fennelview
344 : test-functions
345 : test-hashfn
346 : test-if
347 : test-loops
348 : test-with-open
349 : test-match
350 : test-method_calls
351 : test-parsing
352 : test-comment}