diff options
| author | s-ol <s+removethis@s-ol.nu> | 2022-02-05 10:11:13 +0000 |
|---|---|---|
| committer | s-ol <s+removethis@s-ol.nu> | 2025-03-02 14:24:49 +0000 |
| commit | c484cce5ab1f6acd14ecad30adb586a6d5fa0fd1 (patch) | |
| tree | a45c702a83e150fea5b14b279e5f0cab9b65bc3e /spec/lib | |
| parent | examples: more smoothing in love example :) (diff) | |
| download | alive-c484cce5ab1f6acd14ecad30adb586a6d5fa0fd1.tar.gz alive-c484cce5ab1f6acd14ecad30adb586a6d5fa0fd1.zip | |
rearrange spec, fix for Lua 5.1
Diffstat (limited to 'spec/lib')
| -rw-r--r-- | spec/lib/array_spec.moon | 148 | ||||
| -rw-r--r-- | spec/lib/builtins/cond_spec.moon | 92 | ||||
| -rw-r--r-- | spec/lib/builtins/do_spec.moon | 27 | ||||
| -rw-r--r-- | spec/lib/builtins/fn_spec.moon | 51 | ||||
| -rw-r--r-- | spec/lib/builtins/literal_spec.moon | 33 | ||||
| -rw-r--r-- | spec/lib/builtins/thread_spec.moon | 24 | ||||
| -rw-r--r-- | spec/lib/logic_spec.moon | 264 | ||||
| -rw-r--r-- | spec/lib/math_spec.moon | 267 | ||||
| -rw-r--r-- | spec/lib/struct_spec.moon | 51 | ||||
| -rw-r--r-- | spec/lib/testing_spec.moon | 80 |
10 files changed, 1037 insertions, 0 deletions
diff --git a/spec/lib/array_spec.moon b/spec/lib/array_spec.moon new file mode 100644 index 0000000..b55cec6 --- /dev/null +++ b/spec/lib/array_spec.moon @@ -0,0 +1,148 @@ +import TestPilot from require 'spec.test_setup' +import T, Array from require 'alv' + +describe "array", -> + test = TestPilot '', '(import* array-)\n' + + svec3 = Array 3, T.str + + it "can contain any type", -> + COPILOT\eval_once '(array 1 2 3)' + COPILOT\eval_once '(array true false)' + COPILOT\eval_once '(array "a")' + COPILOT\eval_once '(array (array 1 2) (array 3 4))' + + it "cannot contain mixed types", -> + err = assert.has.error -> COPILOT\eval_once '(array 1 false)' + assert.matches "argument error: couldn't match arguments", err + + describe "(set)", -> + it "can swap values", -> + rt = COPILOT\eval_once '(set (array "f" "b" "c") 0 "a")' + assert.is.true rt\is_const! + assert.is.equal svec3\mk_const({ 'a', 'b', 'c' }), rt.result + + it "checks value type", -> + err = assert.has.error -> COPILOT\eval_once '(set (array 1) 0 "a")' + assert.matches "expected value of type num, not str", err + + it "checks index range", -> + err = assert.has.error -> COPILOT\eval_once '(set (array 1 2) -1 0)' + assert.matches "index '%-1' out of range!", err + + COPILOT\eval_once '(set (array 1 2) 0 0)' + + COPILOT\eval_once '(set (array 1 2) 1 0)' + + err = assert.has.error -> COPILOT\eval_once '(set (array 1 2) 2 0)' + assert.matches "index '2' out of range!", err + + describe "(get)", -> + it "can get a value", -> + rt = COPILOT\eval_once '(get (array 1 2) 0)' + assert.is.true rt\is_const! + assert.is.equal '<num= 1>', tostring rt.result + + it "checks index range", -> + err = assert.has.error -> COPILOT\eval_once '(get (array 1 2) -1)' + assert.matches "index '%-1' out of range!", err + + COPILOT\eval_once '(get (array 1 2) 0)' + + COPILOT\eval_once '(get (array 1 2) 1)' + + err = assert.has.error -> COPILOT\eval_once '(get (array 1 2) 2)' + assert.matches "index '2' out of range!", err + + describe '(head)', -> + it "can peek a value", -> + rt = COPILOT\eval_once '(head (array 1 2))' + assert.is.true rt\is_const! + assert.is.equal '<num= 1>', tostring rt.result + + describe '(tail)', -> + it "gets rest of an array", -> + rt = COPILOT\eval_once '(tail (array 1))' + assert.is.true rt\is_const! + assert.is.same (Array 0, T.num), rt.result.type + assert.is.same {}, rt.result! + + rt = COPILOT\eval_once '(tail (array 1 2))' + assert.is.true rt\is_const! + assert.is.same (Array 1, T.num), rt.result.type + assert.is.same { 2 }, rt.result! + + rt = COPILOT\eval_once '(tail (array 1 2 3 4))' + assert.is.true rt\is_const! + assert.is.same (Array 3, T.num), rt.result.type + assert.is.same { 2, 3, 4 }, rt.result! + + describe '(prepend)', -> + it "prepends to array", -> + rt = COPILOT\eval_once '(prepend (array 2) 1)' + assert.is.true rt\is_const! + assert.is.same (Array 2, T.num), rt.result.type + assert.is.same { 1, 2 }, rt.result! + + rt = COPILOT\eval_once '(prepend (array 2 3 4) 1)' + assert.is.true rt\is_const! + assert.is.same (Array 4, T.num), rt.result.type + assert.is.same { 1, 2, 3, 4 }, rt.result! + + describe "(insert)", -> + it "can insert a value", -> + rt = COPILOT\eval_once '(insert (array "b" "c") 0 "a")' + assert.is.true rt\is_const! + assert.is.equal svec3\mk_const({ 'a', 'b', 'c' }), rt.result + + rt = COPILOT\eval_once '(insert (array "a" "c") 1 "b")' + assert.is.true rt\is_const! + assert.is.equal svec3\mk_const({ 'a', 'b', 'c' }), rt.result + + rt = COPILOT\eval_once '(insert (array "a" "b") 2 "c")' + assert.is.true rt\is_const! + assert.is.equal svec3\mk_const({ 'a', 'b', 'c' }), rt.result + + it "checks index range", -> + err = assert.has.error -> COPILOT\eval_once '(insert (array 1 2) -1 0)' + assert.matches "index '%-1' out of range!", err + + COPILOT\eval_once '(insert (array 1 2) 0 0)' + + COPILOT\eval_once '(insert (array 1 2) 1 0)' + + COPILOT\eval_once '(insert (array 1 2) 2 0)' + + err = assert.has.error -> COPILOT\eval_once '(insert (array 1 2) 3 0)' + assert.matches "index '3' out of range!", err + + describe "(remove)", -> + it "can remove a value", -> + rt = COPILOT\eval_once '(remove (array "d" "a" "b" "c") 0)' + assert.is.true rt\is_const! + assert.is.equal svec3\mk_const({ 'a', 'b', 'c' }), rt.result + + rt = COPILOT\eval_once '(remove (array "a" "b" "c" "d") 3)' + assert.is.true rt\is_const! + assert.is.equal svec3\mk_const({ 'a', 'b', 'c' }), rt.result + + it "checks index range", -> + err = assert.has.error -> COPILOT\eval_once '(remove (array 1 2 3) -1)' + assert.matches "index '%-1' out of range!", err + + err = assert.has.error -> COPILOT\eval_once '(remove (array 1 2 3) 3)' + assert.matches "index '3' out of range!", err + + it "can be concatenated with (concat)", -> + rt = COPILOT\eval_once '(concat (array "a" "b") (array "c"))' + assert.is.true rt\is_const! + assert.is.equal svec3\mk_const({ 'a', 'b', 'c' }), rt.result + + it "size can be read using (size)", -> + rt = COPILOT\eval_once '(size (array 1))' + assert.is.true rt\is_const! + assert.is.equal '<num= 1>', tostring rt.result + + rt = COPILOT\eval_once '(size (array 1 2 3))' + assert.is.true rt\is_const! + assert.is.equal '<num= 3>', tostring rt.result diff --git a/spec/lib/builtins/cond_spec.moon b/spec/lib/builtins/cond_spec.moon new file mode 100644 index 0000000..89f7c7e --- /dev/null +++ b/spec/lib/builtins/cond_spec.moon @@ -0,0 +1,92 @@ +import TestPilot from require 'spec.test_setup' +import T, Struct, Array, Constant from require 'alv' + +describe "if", -> + COPILOT = TestPilot! + + it "checks truthiness", -> + for truthy in *{'true', '1', '-1', '1234', '(array 1 2 3)', '"test"', '""'} + with COPILOT\eval_once "(if #{truthy} 'yes' 'no')" + assert.is.true \is_const! + assert.is.equal 'yes', .result! + + for falsy in *{'false', '0'} + with COPILOT\eval_once "(if #{falsy} 'yes' 'no')" + assert.is.true \is_const! + assert.is.equal 'no', .result! + + it "can be used without else clause", -> + with COPILOT\eval_once '(if true "yes")' + assert.is.true \is_const! + assert.is.equal 'yes', .result! + + with COPILOT\eval_once '(if false "yes")' + assert.is.true \is_const! + assert.is.equal nil, .result + + it "doesn't evaluate the untaken branch", -> + with COPILOT\eval_once '(if true "yes" (error/doesnt-exist))' + assert.is.true \is_const! + assert.is.equal 'yes', .result! + + with COPILOT\eval_once '(if false (error/doesnt-exist) "no")' + assert.is.true \is_const! + assert.is.equal 'no', .result! + + it "errors on non-const choice", -> + err = assert.has.error -> + COPILOT\eval_once '(import* time) (if (ramp 1) "yes" "no")' + assert.matches "'if'%-expression needs to be constant", err + + it "forwards any result", -> + with COPILOT\eval_once ' + (import* time) + (if true (every 1 (array 1 2 3)))' + assert.is.false \is_const! + assert.is.equal '<num[3]! nil>', tostring .result + +describe "when", -> + COPILOT = TestPilot! + + it "checks truthiness", -> + for truthy in *{'true', '1', '-1', '1234', '(array 1 2 3)', '"test"', '""'} + with COPILOT\eval_once "(when #{truthy} 'yes')" + assert.is.true \is_const! + assert.is.equal 'yes', .result! + + for falsy in *{'false', '0'} + with COPILOT\eval_once "(when #{falsy} 'yes')" + assert.is.true \is_const! + assert.is.nil .result + + it "doesn't evaluate if falsy", -> + with COPILOT\eval_once '(when false (error/doesnt-exist))' + assert.is.true \is_const! + assert.is.nil, .result + + with COPILOT\eval_once ' + (when false + (error/doesnt-exist) + (error/doesnt-exist) + (error/doesnt-exist))' + assert.is.true \is_const! + assert.is.nil, .result + + it "errors on non-const choice", -> + err = assert.has.error -> + COPILOT\eval_once '(import* time) (when (ramp 1) 1 2 3)' + assert.matches "'when'%-expression needs to be constant", err + + it "forwards any result", -> + with COPILOT\eval_once ' + (import* time) + (when true + (every 1 (array 1 2 3)) + 1 2 3)' + assert.is.false \is_const! + assert.is.equal '<num~ 3>', tostring .result + + with COPILOT\eval_once '(when true (array 1 2 3))' + assert.is.true \is_const! + assert.is.equal '<num[3]= [1 2 3]>', tostring .result + diff --git a/spec/lib/builtins/do_spec.moon b/spec/lib/builtins/do_spec.moon new file mode 100644 index 0000000..fd2825b --- /dev/null +++ b/spec/lib/builtins/do_spec.moon @@ -0,0 +1,27 @@ +import TestPilot from require 'spec.test_setup' + +describe "do", -> + COPILOT = TestPilot! + + it "can be empty", -> + with COPILOT\eval_once '(do)' + assert.is.true \is_const! + assert.is.nil .result + + it "returns the last result, if any", -> + with COPILOT\eval_once '(do 1 2 3)' + assert.is.true \is_const! + assert.is.equal '<num= 3>', tostring .result + + with COPILOT\eval_once '(do 1 2 (def _ 3))' + assert.is.true \is_const! + assert.is.nil .result + + it "passes through side-effects", -> + with COPILOT\eval_once ' + (import* time) + (do + (every 0.5 "bang! side-effect") + 3)' + assert.is.false \is_const! + assert.is.equal '<num= 3>', tostring .result diff --git a/spec/lib/builtins/fn_spec.moon b/spec/lib/builtins/fn_spec.moon new file mode 100644 index 0000000..af27cf3 --- /dev/null +++ b/spec/lib/builtins/fn_spec.moon @@ -0,0 +1,51 @@ +import TestPilot from require 'spec.test_setup' +import T, Struct, Array, Constant from require 'alv' + +describe "function", -> + COPILOT = TestPilot! + + it "returns constant results when constant", -> + rt = COPILOT\eval_once ' + (import* math) + + (defn my-plus (a b) + (+ a b)) + + (my-plus 2 3)' + assert.is.true rt\is_const! + assert.is.equal (Constant.num 5), rt.result + + it "checks argument arity when invoked", -> + err = assert.has.error -> COPILOT\eval_once ' + ([1]import* math) + + ([2]defn my-plus (a b) + ([4]+ a b)) + + ([3]my-plus 2)' + assert.matches "argument error: expected 2 arguments, found 1", err + assert.matches "while invoking function 'my%-plus' at %[3%]", err + + err = assert.has.error -> COPILOT\eval_once ' + ([1]import* math) + + ([2]defn my-plus (a b) + ([4]+ a b)) + + ([3]my-plus 2 3 4)' + assert.matches "argument error: expected 2 arguments, found 3", err + assert.matches "while invoking function 'my%-plus' at %[3%]", err + + it "can be anonymously invoked", -> + rt = COPILOT\eval_once ' + ([1] + ([2]fn (a b) b) + 3 4)' + assert.is.equal (Constant.num 4), rt\const! + + err = assert.has.error -> COPILOT\eval_once ' + ([1] + ([2]fn (a b) b) + 3)' + assert.matches "argument error: expected 2 arguments, found 1", err + assert.matches "while invoking function %(unnamed%) at %[1%]", err diff --git a/spec/lib/builtins/literal_spec.moon b/spec/lib/builtins/literal_spec.moon new file mode 100644 index 0000000..3db010d --- /dev/null +++ b/spec/lib/builtins/literal_spec.moon @@ -0,0 +1,33 @@ +import TestPilot from require 'spec.test_setup' +import T, Struct, Array, Constant from require 'alv' + +describe "literal", -> + TestPilot ' + (def str "hello" + num 2 + bool true + curl ([5]struct "a" 2 "b" false) + sqre ([7]array 1 2 3 4)) + (export*)' + + assert.is.true COPILOT.active_module.root\is_const! + scope = (assert COPILOT.active_module.root.result)\unwrap T.scope + + it "string is parsed and returned correctly", -> + assert.is.equal (Constant.str 'hello'), (scope\get 'str')\const! + + it "number is parsed and returned correctly", -> + assert.is.equal (Constant.num 2), (scope\get 'num')\const! + + it "boolean is parsed and returned correctly", -> + assert.is.equal (Constant.bool true), (scope\get 'bool')\const! + + it "struct is parsed and returned correctly", -> + struct = (scope\get 'curl')\const! + assert.is.equal (Struct a: T.num, b: T.bool), struct.type + assert.is.same { a: 2, b: false }, struct! + + it "array is parsed and returned correctly", -> + array = (scope\get 'sqre')\const! + assert.is.equal (Array 4, T.num), array.type + assert.is.same {1, 2, 3, 4}, array! diff --git a/spec/lib/builtins/thread_spec.moon b/spec/lib/builtins/thread_spec.moon new file mode 100644 index 0000000..4b81119 --- /dev/null +++ b/spec/lib/builtins/thread_spec.moon @@ -0,0 +1,24 @@ +import TestPilot from require 'spec.test_setup' + +describe "thread macros", -> + COPILOT = TestPilot! + + it "thread forward (->)", -> + rt = COPILOT\eval_once ' + (import* math) + #((/ (+ 10 2) 8) = 1.5) + (-> 10 + (+ 2) + (/ 8))' + assert.is.true rt\is_const! + assert.is.equal '<num= 1.5>', tostring rt.result + + it "thread last forward (->>)", -> + rt = COPILOT\eval_once ' + (import* math) + #((/ 10 (+ 2 2)) = 2.5) + (->> 2 + (+ 2) + (/ 10))' + assert.is.true rt\is_const! + assert.is.equal '<num= 2.5>', tostring rt.result diff --git a/spec/lib/logic_spec.moon b/spec/lib/logic_spec.moon new file mode 100644 index 0000000..f3d0610 --- /dev/null +++ b/spec/lib/logic_spec.moon @@ -0,0 +1,264 @@ +import TestPilot from require 'spec.test_setup' +import T, Array, Constant from require 'alv' + +describe "logic", -> + test = TestPilot '', '(import* logic)\n' + TRUE = T.bool\mk_const true + FALSE = T.bool\mk_const false + + describe "==", -> + it "can compare any type", -> + with COPILOT\eval_once '(== 1 1)' + assert.is.true \is_const! + assert.is.equal TRUE, .result + + with COPILOT\eval_once '(== 1 2)' + assert.is.true \is_const! + assert.is.equal FALSE, .result + + with COPILOT\eval_once '(== 1 "hello")' + assert.is.true \is_const! + assert.is.equal FALSE, .result + + with COPILOT\eval_once '(== "hello" "hello")' + assert.is.true \is_const! + assert.is.equal TRUE, .result + + with COPILOT\eval_once '(== (array 1 2 3) (array 1 2 3))' + assert.is.true \is_const! + assert.is.equal TRUE, .result + + with COPILOT\eval_once '(== (array 1 2 3) (array 1 2 1))' + assert.is.true \is_const! + assert.is.equal FALSE, .result + + with COPILOT\eval_once '(== (array 1 2 3) (array 1 2))' + assert.is.true \is_const! + assert.is.equal FALSE, .result + + with COPILOT\eval_once '(== (array 1 2 3) (array 1 2 3 4))' + assert.is.true \is_const! + assert.is.equal FALSE, .result + + with COPILOT\eval_once '(== + (struct "a" 1 "b" true "c" (array "test")) + (struct "a" 1 "b" true "c" (array "test")))' + assert.is.true \is_const! + assert.is.equal TRUE, .result + + with COPILOT\eval_once '(== + (struct "a" 1 "b" false "c" (array "test")) + (struct "a" 1 "b" true "c" (array "test")))' + assert.is.true \is_const! + assert.is.equal FALSE, .result + + with COPILOT\eval_once '(== + (struct "a" 1 "b" true "c" (array "test" "toast")) + (struct "a" 1 "b" true "c" (array "test")))' + assert.is.true \is_const! + assert.is.equal FALSE, .result + + with COPILOT\eval_once '(== + (struct "a" 1 "b" true) + (struct "a" 1 "b" true "c" (array "test")))' + assert.is.true \is_const! + assert.is.equal FALSE, .result + + with COPILOT\eval_once '(== + (struct "a" 1 "b" true) + (struct "a" 1))' + assert.is.true \is_const! + assert.is.equal FALSE, .result + + with COPILOT\eval_once '(== print print)' + assert.is.true \is_const! + assert.is.equal TRUE, .result + + with COPILOT\eval_once '(== print ==)' + assert.is.true \is_const! + assert.is.equal FALSE, .result + + it "is aliased as eq", -> + with COPILOT\eval_once '(== eq ==)' + assert.is.true \is_const! + assert.is.equal TRUE, .result + + describe "!=", -> + it "can compare any type", -> + with COPILOT\eval_once '(!= 1 1)' + assert.is.true \is_const! + assert.is.equal FALSE, .result + + with COPILOT\eval_once '(!= 1 2)' + assert.is.true \is_const! + assert.is.equal TRUE, .result + + with COPILOT\eval_once '(!= 1 "hello")' + assert.is.true \is_const! + assert.is.equal TRUE, .result + + with COPILOT\eval_once '(!= "hello" "hello")' + assert.is.true \is_const! + assert.is.equal FALSE, .result + + with COPILOT\eval_once '(!= (array 1 2 3) (array 1 2 3))' + assert.is.true \is_const! + assert.is.equal FALSE, .result + + with COPILOT\eval_once '(!= (array 1 2 3) (array 1 2 1))' + assert.is.true \is_const! + assert.is.equal TRUE, .result + + with COPILOT\eval_once '(!= (array 1 2 3) (array 1 2))' + assert.is.true \is_const! + assert.is.equal TRUE, .result + + with COPILOT\eval_once '(!= (array 1 2 3) (array 1 2 3 4))' + assert.is.true \is_const! + assert.is.equal TRUE, .result + + with COPILOT\eval_once '(!= + (struct "a" 1 "b" true "c" (array "test")) + (struct "a" 1 "b" true "c" (array "test")))' + assert.is.true \is_const! + assert.is.equal FALSE, .result + + with COPILOT\eval_once '(!= + (struct "a" 1 "b" false "c" (array "test")) + (struct "a" 1 "b" true "c" (array "test")))' + assert.is.true \is_const! + assert.is.equal TRUE, .result + + with COPILOT\eval_once '(!= + (struct "a" 1 "b" true "c" (array "test" "toast")) + (struct "a" 1 "b" true "c" (array "test")))' + assert.is.true \is_const! + assert.is.equal TRUE, .result + + with COPILOT\eval_once '(!= + (struct "a" 1 "b" true) + (struct "a" 1 "b" true "c" (array "test")))' + assert.is.true \is_const! + assert.is.equal TRUE, .result + + with COPILOT\eval_once '(!= + (struct "a" 1 "b" true) + (struct "a" 1))' + assert.is.true \is_const! + assert.is.equal TRUE, .result + + with COPILOT\eval_once '(!= print print)' + assert.is.true \is_const! + assert.is.equal FALSE, .result + + with COPILOT\eval_once '(!= print ==)' + assert.is.true \is_const! + assert.is.equal TRUE, .result + + it "is aliased as note-eq", -> + with COPILOT\eval_once '(== not-eq !=)' + assert.is.true \is_const! + assert.is.equal TRUE, .result + + describe "bool", -> + it "coerces numbers", -> + with COPILOT\eval_once '(bool 0)' + assert.is.true \is_const! + assert.is.equal FALSE, .result + + with COPILOT\eval_once '(bool 1)' + assert.is.true \is_const! + assert.is.equal TRUE, .result + + with COPILOT\eval_once '(bool -1)' + assert.is.true \is_const! + assert.is.equal TRUE, .result + + with COPILOT\eval_once '(bool 1024)' + assert.is.true \is_const! + assert.is.equal TRUE, .result + + it "accepts booleans", -> + with COPILOT\eval_once '(bool false)' + assert.is.true \is_const! + assert.is.equal FALSE, .result + + with COPILOT\eval_once '(bool true)' + assert.is.true \is_const! + assert.is.equal TRUE, .result + + describe "not", -> + it "accepts booleans", -> + with COPILOT\eval_once '(not false)' + assert.is.true \is_const! + assert.is.equal TRUE, .result + + with COPILOT\eval_once '(not true)' + assert.is.true \is_const! + assert.is.equal FALSE, .result + + it "coerces numbers", -> + with COPILOT\eval_once '(not 0)' + assert.is.true \is_const! + assert.is.equal TRUE, .result + + with COPILOT\eval_once '(not 1)' + assert.is.true \is_const! + assert.is.equal FALSE, .result + + with COPILOT\eval_once '(not -1)' + assert.is.true \is_const! + assert.is.equal FALSE, .result + + with COPILOT\eval_once '(not 1024)' + assert.is.true \is_const! + assert.is.equal FALSE, .result + + + describe "or", -> + it "accepts any number of mixed arguments", -> + with COPILOT\eval_once '(or false 0)' + assert.is.true \is_const! + assert.is.equal FALSE, .result + + with COPILOT\eval_once '(or 1 0)' + assert.is.true \is_const! + assert.is.equal TRUE, .result + + with COPILOT\eval_once '(or 0 false 0 0 0 0)' + assert.is.true \is_const! + assert.is.equal FALSE, .result + + with COPILOT\eval_once '(or 0 0 0 true 0 0)' + assert.is.true \is_const! + assert.is.equal TRUE, .result + + with COPILOT\eval_once '(or 0 true 0 1 0 0)' + assert.is.true \is_const! + assert.is.equal TRUE, .result + + describe "and", -> + it "accepts any number of mixed arguments", -> + with COPILOT\eval_once '(and false 1)' + assert.is.true \is_const! + assert.is.equal FALSE, .result + + with COPILOT\eval_once '(and 1 true)' + assert.is.true \is_const! + assert.is.equal TRUE, .result + + with COPILOT\eval_once '(and false 0)' + assert.is.true \is_const! + assert.is.equal FALSE, .result + + with COPILOT\eval_once '(and 1 1 true 0)' + assert.is.true \is_const! + assert.is.equal FALSE, .result + + with COPILOT\eval_once '(and 1 1 true true 1)' + assert.is.true \is_const! + assert.is.equal TRUE, .result + + with COPILOT\eval_once '(and 1 1 1)' + assert.is.true \is_const! + assert.is.equal TRUE, .result diff --git a/spec/lib/math_spec.moon b/spec/lib/math_spec.moon new file mode 100644 index 0000000..23a353b --- /dev/null +++ b/spec/lib/math_spec.moon @@ -0,0 +1,267 @@ +import TestPilot from require 'spec.test_setup' +import T, Array, Constant from require 'alv' + +describe_both = (fn) -> + describe "math", -> + test = TestPilot '', '(import* testing math)\n' + fn! + + describe "math-simple", -> + test = TestPilot '', '(import* testing math-simple)\n' + fn! + +describe_both -> + describe "add, sub, mul, div, pow, mod", -> + it "are aliased as +-*/^%", -> + COPILOT\eval_once ' + (expect= + add) + (expect= - sub) + (expect= * mul) + (expect= / div) + (expect= ^ pow) + (expect= % mod) + ' + + it "are sane", -> + COPILOT\eval_once ' + (expect= 2 (+ 1 1)) + (expect= 6 (+ 2 3 0 1)) + + (expect= -5 (- 2 7)) + (expect= 0 (- 10 4 3 2 1 0)) + (expect= -10 (- 10)) + + (expect= 1 (* 1 1)) + (expect= -2 (* -1 2)) + (expect= 14 (* 4 0.5 7)) + + (expect= 1 (/ 4 4)) + (expect= -2 (/ -10 5)) + (expect= 3 (/ -30 -10)) + + (expect= 1024 (^ 2 10)) + (expect= 0.25 (^ 4 -1)) + (expect= 1 (^ 999 0)) + + (expect= 4 (% 10 6)) + (expect= 3 (% -2 5)) + (expect= -2 (% -2 -5)) + ' + + describe "trigonometric functions and constants", -> + COPILOT\eval_once ' + (expect= tau (* pi 2)) + + #(darn you fp accuracy! + (expect= 0.5 (asin (sin 0.5))) + (expect= 0.5 (acos (cos 0.5))) + ...) + ' + + it "min, max, clamp, huge", -> + COPILOT\eval_once ' + (expect= 0 (min 0 1 2)) + (expect= 2 (max 0 1 2)) + + (expect= -2 (clamp -2 3.5 -4)) + (expect= -1 (clamp -2 3.5 -1)) + (expect= 0 (clamp -2 3.5 0)) + (expect= 1 (clamp -2 3.5 1)) + (expect= 3.5 (clamp -2 3.5 4)) + + (expect= (- huge) (min 0 1 -123456789 (- huge))) + (expect= huge (max 0 1 123456789 huge)) + ' + + it "inc, dec", -> + COPILOT\eval_once ' + (expect= 1 (inc 0)) + (expect= -1 (dec 0)) + (expect= 3 (inc (inc 1))) + (expect= -1 (dec (dec 1))) + (expect= 0 (inc (dec 0)) (dec (inc 0))) + ' + +describe "math", -> + test = TestPilot '', '(import* testing math)\n' + + describe "add, sub, mul, div, pow, mod", -> + it "handle scalar/vector", -> + COPILOT\eval_once ' + (expect= (array 3 4 5) + (+ 1 (array 1 2 3) 1)) + + (expect= (array 0 1 2) + (- (array 1 2 3) 1)) + + (expect= (array 3 6 9) + (* 3 (array 1 2 3))) + (expect= (array 3 6 9) + (* (array 1 2 3) 3)) + + (expect= (array 12 9 4) + (/ 36 (array 3 4 9))) + + (expect= (array 9 16 25) + (^ (array 3 4 5) 2)) + (expect= (array 1 2 4 8) + (^ 2 (array 0 1 2 3))) + + (expect= (array 3 0 1) + (% (array 3 4 5) 4)) + ' + + it "handle vector/vector and matrix/matrix", -> + COPILOT\eval_once ' + (expect= (array 5 7 9) + (+ (array 1 2 3) + (array 4 5 6))) + + (expect= (array (array 11 12) + (array 13 14)) + (+ + (array (array 1 2) + (array 3 4)) + 5 + 5)) + + (expect= (array 2 0 -2) + (- (array 3 2 1) + (array 1 2 3))) + + (expect= (array 1 -2 -3) + (- (array -1 2 3))) + ' + + err = assert.has.error -> + COPILOT\eval_once ' + (+ (array 1 2 3) + (array 1 2))' + + err = assert.has.error -> + COPILOT\eval_once ' + (+ (array (array 1 2) (array 1 2)) + (array 1 2))' + + err = assert.has.error -> + COPILOT\eval_once ' + (- (array 1 2 3) + (array 1 2))' + + err = assert.has.error -> + COPILOT\eval_once ' + (- (array (array 1 2) (array 1 2)) + (array 1 2))' + + describe "mul", -> + it "handles scalars and matrices", -> + with COPILOT\eval_once ' + (* 3 + (array + (array 1 2) + (array 4 5)))' + assert.is.true \is_const! + assert.is.equal '<num[2][2]= [[3 6] [12 15]]>', tostring .result + + with COPILOT\eval_once ' + (* (array + (array 1 2) + (array 4 5)) + 3)' + assert.is.true \is_const! + assert.is.equal '<num[2][2]= [[3 6] [12 15]]>', tostring .result + + it "handles vectors and matrices", -> + with COPILOT\eval_once ' + (* + (array (array 1 0 0) + (array 0 1 0) + (array 0 0 1)) + (array 4 5 6))' + assert.is.true \is_const! + assert.is.equal '<num[3]= [4 5 6]>', tostring .result + + with COPILOT\eval_once ' + (* + (array (array 1 0 0) + (array 0 1 0) + (array 3 2 1)) + (array 4 5 1))' + assert.is.true \is_const! + assert.is.equal '<num[3]= [4 5 23]>', tostring .result + + it "handles matrices", -> + with COPILOT\eval_once ' + (* + (array (array 1 2 3) + (array 4 5 6)) + (array (array 10 11) + (array 20 21) + (array 30 31)))' + assert.is.true \is_const! + assert.is.equal '<num[2][2]= [[140 146] [320 335]]>', tostring .result + + it "handles everything mixed", -> + with COPILOT\eval_once ' + (* + (array (array 1 2 3) + (array 4 5 6)) + 2 + (array (array 10 11) + (array 20 21) + (array 30 31)))' + assert.is.true \is_const! + assert.is.equal '<num[2][2]= [[280 292] [640 670]]>', tostring .result + + with COPILOT\eval_once ' + (* + (array (array 1 2 3) + (array 4 5 6)) + 2 + (array (array 10 11) + (array 20 21) + (array 30 31)) + (array 4 7))' + assert.is.true \is_const! + assert.is.equal '<num[2]= [3164 7250]>', tostring .result + + it "errors with wrong sizes (matrix and vector)", -> + err = assert.has.error -> COPILOT\eval_once ' + (* + (array (array 1 2 3) + (array 4 5 6)) + (array 1 2))' + -- assert.matches "", err + + err = assert.has.error -> COPILOT\eval_once ' + (* + (array 1 2 3) + (array (array 1 2 3) + (array 4 5 6)))' + -- assert.matches "", err + + it "errors with wrong sizes (matrix)", -> + err = assert.has.error -> COPILOT\eval_once ' + (* + (array (array 1 2 3) + (array 4 5 6)) + (array (array 1 2) + (array 4 5)))' + -- assert.matches "", err + + it "min, max, clamp, huge", -> + COPILOT\eval_once ' + (expect= (array 3 2 1) + (min (array 3 4 1) (array 5 2 huge))) + (expect= (array 5 huge 4) + (max (array 3 huge 4) (array 5 999 2))) + + (expect= (array -2 -1 0 1 3.5) + (clamp -2 3.5 (array -4 -1 0 1 4))) + + (expect= 1 (inc 0)) + (expect= -1 (dec 0)) + (expect= 3 (inc (inc 1))) + (expect= -1 (dec (dec 1))) + (expect= 0 (inc (dec 0)) (dec (inc 0))) + ' diff --git a/spec/lib/struct_spec.moon b/spec/lib/struct_spec.moon new file mode 100644 index 0000000..9937f99 --- /dev/null +++ b/spec/lib/struct_spec.moon @@ -0,0 +1,51 @@ +import TestPilot from require 'spec.test_setup' +import T, Struct from require 'alv' + +describe "struct", -> + test = TestPilot '', '(import* struct-)\n' + + ab = Struct { a: T.num, b: T.bool } + + describe "(set)", -> + it "can update values", -> + rt = COPILOT\eval_once '(set (struct "a" 1 "b" false) "a" 2)' + assert.is.true rt\is_const! + assert.is.equal ab\mk_const({ a: 2, b: false }), rt.result + + it "cannot add members", -> + err = assert.has.error -> COPILOT\eval_once '(set (struct "a" 1) "b" 2)' + assert.matches "{a: num} has no 'b' key", err + + it "checks value type", -> + err = assert.has.error -> COPILOT\eval_once '(set (struct "a" 1) "a" "str")' + assert.matches "expected value for key 'a' to be num, not str", err + + describe "(get)", -> + it "can get values", -> + rt = COPILOT\eval_once '(get (struct "a" 1 "b" false) "a")' + assert.is.true rt\is_const! + assert.is.equal '<num= 1>', tostring rt.result + + it "checks keys", -> + err = assert.has.error -> COPILOT\eval_once '(get (struct "a" 1) "b")' + assert.matches "has no 'b' key", err + + describe "(insert)", -> + it "can add members", -> + rt = COPILOT\eval_once '(insert (struct "b" true) "a" 1)' + assert.is.true rt\is_const! + assert.is.equal ab\mk_const({ a: 1, b: true }), rt.result + + it "doesn't clobber existing members", -> + err = assert.has.error -> COPILOT\eval_once '(insert (struct "a" 1) "a" 2)' + assert.matches "key 'a' already exists in value of type {a: num}", err + + describe "(remove)", -> + it "can remove members", -> + rt = COPILOT\eval_once '(remove (struct "a" 1 "b" false "c" "abc") "c")' + assert.is.true rt\is_const! + assert.is.equal ab\mk_const({ a: 1, b: false }), rt.result + + it "checks keys", -> + err = assert.has.error -> COPILOT\eval_once '(remove (struct "a" 1) "b")' + assert.matches "has no 'b' key", err diff --git a/spec/lib/testing_spec.moon b/spec/lib/testing_spec.moon new file mode 100644 index 0000000..5be7848 --- /dev/null +++ b/spec/lib/testing_spec.moon @@ -0,0 +1,80 @@ +import TestPilot from require 'spec.test_setup' +import T, Array, Constant from require 'alv' + +describe "testing", -> + test = TestPilot '', '(import* testing logic)\n' + + describe "assert", -> + it "ignores true", -> + with COPILOT\eval_once '(assert true)' + assert.is.true \is_const! + assert.is.nil .result + + with COPILOT\eval_once '(assert true "with message")' + assert.is.true \is_const! + assert.is.nil .result + + it "throws on false", -> + assert.has.error -> COPILOT\eval_once '(assert false)' + + it "shows failing expression", -> + err = assert.has.error -> COPILOT\eval_once '(assert false)' + assert.matches "assertion failed: false", err + + err = assert.has.error -> COPILOT\eval_once '(assert (== 1 2))' + assert.matches "assertion failed: %(== 1 2%)", err + + it "supports custom error messages", -> + err = assert.has.error -> COPILOT\eval_once '(assert (== "green" "red") "duck isnt green")' + assert.matches "duck isnt green", err + + describe "expect=", -> + it "passes equal params", -> + with COPILOT\eval_once '(expect= 1 1 1)' + assert.is.true \is_const! + assert.is.nil .result + + with COPILOT\eval_once '(expect= 2 2 2)' + assert.is.true \is_const! + assert.is.nil .result + + with COPILOT\eval_once '(expect= true true)' + assert.is.true \is_const! + assert.is.nil .result + + with COPILOT\eval_once '(expect= "hello" "hello")' + assert.is.true \is_const! + assert.is.nil .result + + with COPILOT\eval_once '(expect= (array 1 2) (array 1 2))' + assert.is.true \is_const! + assert.is.nil .result + + it "fails different values", -> + assert.has.error -> COPILOT\eval_once '(expect= 1 2)' + assert.has.error -> COPILOT\eval_once '(expect= 1 1 2)' + assert.has.error -> COPILOT\eval_once '(expect= 2 1 1)' + + assert.has.error -> COPILOT\eval_once '(expect= true false)' + + assert.has.error -> COPILOT\eval_once '(expect= "asdf" "bsdf")' + assert.has.error -> COPILOT\eval_once '(expect= (array 1 2) (array 1 3))' + + it "fails different types", -> + assert.has.error -> COPILOT\eval_once '(expect= true 2)' + assert.has.error -> COPILOT\eval_once '(expect= true true 1)' + assert.has.error -> COPILOT\eval_once '(expect= true false "str")' + + it "reports first failing arguments", -> + err = assert.has.error -> COPILOT\eval_once '(expect= 1 2)' + assert.matches "assertion error: Expected 2 to equal <num= 1> %(got <num= 2>%)", err + + err = assert.has.error -> COPILOT\eval_once '(expect= 1 1 2 4)' + assert.matches "assertion error: Expected 2 to equal <num= 1> %(got <num= 2>%)", err + + err = assert.has.error -> COPILOT\eval_once '(expect= true 2 3)' + assert.matches "assertion error: Expected 2 to equal <bool= true> %(got <num= 2>%)", err + + it "reports full expressions", -> + err = assert.has.error -> COPILOT\eval_once '(import* math) (expect= 1 (+ 1 1))' + assert.matches "assertion error: Expected %(%+ 1 1%) to equal <num= 1> %(got <num= 2>%)", err |
