diff options
Diffstat (limited to 'stdlib/test')
-rw-r--r-- | stdlib/test/test/lux/data/error/exception.lux | 50 | ||||
-rw-r--r-- | stdlib/test/test/lux/data/format/json.lux | 402 | ||||
-rw-r--r-- | stdlib/test/test/lux/data/struct/vector.lux | 19 | ||||
-rw-r--r-- | stdlib/test/tests.lux | 4 |
4 files changed, 166 insertions, 309 deletions
diff --git a/stdlib/test/test/lux/data/error/exception.lux b/stdlib/test/test/lux/data/error/exception.lux new file mode 100644 index 000000000..16d09a626 --- /dev/null +++ b/stdlib/test/test/lux/data/error/exception.lux @@ -0,0 +1,50 @@ +## Copyright (c) Eduardo Julian. All rights reserved. +## This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. +## If a copy of the MPL was not distributed with this file, +## You can obtain one at http://mozilla.org/MPL/2.0/. + +(;module: + lux + (lux (codata [io]) + (control monad) + (data (error ["&" exception #+ exception:]) + [text] + [number]) + (codata function) + (math ["R" random]) + pipe) + lux/test) + +(exception: Some-Exception) + +(exception: Another-Exception) + +(exception: Unknown-Exception) + +(test: "Exceptions" + [should-throw? R;bool + which? R;bool + should-catch? R;bool + default-val R;nat + some-val R;nat + another-val R;nat + otherwise-val R;nat + #let [this-ex (if should-catch? + (if which? + Some-Exception + Another-Exception) + Unknown-Exception) + this-val (if should-throw? + (if should-catch? + (if which? + some-val + another-val) + otherwise-val) + default-val)]] + (assert "Catch and otherwhise handlers can properly handle the flow of exception-handling." + (=+ this-val (|> (if should-throw? + (&;return default-val) + (&;throw this-ex "Uh-oh...")) + (&;catch Some-Exception (lambda [ex] some-val)) + (&;catch Another-Exception (lambda [ex] another-val)) + (&;otherwise (lambda [ex] otherwise-val)))))) diff --git a/stdlib/test/test/lux/data/format/json.lux b/stdlib/test/test/lux/data/format/json.lux index 78b0b1a76..d7c622bd5 100644 --- a/stdlib/test/test/lux/data/format/json.lux +++ b/stdlib/test/test/lux/data/format/json.lux @@ -6,309 +6,121 @@ (;module: lux (lux (codata [io]) - (control monad) + (control monad + codec + eq) (data [text "Text/" Monoid<Text>] text/format error - (format [json #* "JSON/" Eq<JSON> Codec<Text,JSON>]) + [bool] + [char] + [maybe] + [number] + (format ["&" json]) (struct [vector #+ vector] - [dict])) + [dict] + [list])) [compiler #+ with-gensyms] + [macro] (macro [ast] [syntax #+ syntax:] [poly #+ derived:]) - [pipe] + (math ["R" random]) + pipe test) ) -## [Utils] -(syntax: (reads-to-itself expr) - (with-gensyms [g!json g!parsed g!message] - (wrap (list (` (: (Test Unit) - (let [(~ g!json) (~ expr)] - (case (|> (~ g!json) JSON/encode JSON/decode) - (#;Left (~ g!message)) - (fail (~ g!message)) - - (#;Right (~ g!parsed)) - (if (JSON/= (~ g!json) (~ g!parsed)) - (~ (' (:: Monad<Test> wrap []))) - (fail (format "Expression does not parse to itself: " (~ (ast;text (ast;ast-to-text expr))) - "\n\nWhich is: " (|> (~ g!json) JSON/encode) - "\n\nInstead, it parsed to: " (JSON/encode (~ g!parsed)))) - )))) - ))))) - -## [Tests] -## (derived: (Codec<JSON,?> ;Bool)) -## (derived: (Codec<JSON,?> ;Int)) -## (derived: (Codec<JSON,?> ;Real)) -## (derived: (Codec<JSON,?> ;Char)) -## (derived: (Codec<JSON,?> ;Text)) - -## (type: Int-List (List Int)) -## (derived: (Codec<JSON,?> ;;Int-List)) - -## (type: Int-Maybe (Maybe Int)) -## (derived: (Codec<JSON,?> ;;Int-Maybe)) - -## (type: Triple [Bool Int Text]) -## (derived: (Codec<JSON,?> ;;Triple)) - -## (type: User -## {#alive? Bool -## #age Int -## #name Text}) -## (derived: (Codec<JSON,?> ;;User)) - -## (type: Options -## (#One Bool) -## (#Two Int) -## (#Three Text)) -## (derived: (Codec<JSON,?> ;;Options)) - -## (test: "Auto-generated codecs" -## (let% [<tests> (do-template [<input> <output> <codec>] -## [(match <output> -## (|> <input> -## (:: <codec> encode) -## JSON/encode)) -## (match+ <input> -## (should-pass (|> (JSON/decode <output>) -## (pipe;%> Error/Monad -## [(:: <codec> decode)]))))] - -## [true "true" Codec<JSON,Bool>] -## [123 "123.0" Codec<JSON,Int>] -## [123.45 "123.45" Codec<JSON,Real>] -## [#"a" "\"a\"" Codec<JSON,Char>] -## ["yolo" "\"yolo\"" Codec<JSON,Text>] - -## [(#;Cons 1 (#;Cons 2 (#;Cons 3 #;Nil))) "[1.0,2.0,3.0]" Codec<JSON,Int-List>] -## [#;Nil "[]" Codec<JSON,Int-List>] -## [(#;Some 1) "1.0" Codec<JSON,Int-Maybe>] -## [#;None "null" Codec<JSON,Int-Maybe>] -## [[false 456 "lol"] "[false,456.0,\"lol\"]" Codec<JSON,Triple>] -## [{#alive? true #age 25 #name "Eduardo Julian"} -## "{\"alive?\":true,\"age\":25.0,\"name\":\"Eduardo Julian\"}" -## Codec<JSON,User>] -## [(#One true) "[\"One\",true]" Codec<JSON,Options>] -## [(#Two 123) "[\"Two\",123.0]" Codec<JSON,Options>] -## [(#Three "yolo") "[\"Three\",\"yolo\"]" Codec<JSON,Options>] -## )] -## (test-all <tests> -## ))) - -(test: "Basics" - (test-all (match #json;Null - null) - - (match (#json;Boolean true) - (gen-boolean true)) - - (match (#json;Boolean false) - (gen-boolean false)) - - (match (#json;Number 123.45) - (gen-number 123.45)) - - (match (#json;String "YOLO") - (gen-string "YOLO")) - - ## (match (^ (#json;Array (list (#json;Boolean true) (#json;Number 123.45) (#json;String "YOLO")))) - ## (json [(gen-boolean true) (gen-number 123.45) (gen-string "YOLO")])) - - ## (match (^ (#json;Object (list ["yolo" (#json;Boolean true)] - ## ["lol" (#json;Number 123.45)]))) - ## (json {"yolo" (gen-boolean true) - ## "lol" (gen-number 123.45)})) - - (match (#;Some (#json;Boolean true)) - (get "yolo" (json {"yolo" true - "lol" 123.45}))) - - (match (#;Left _) - (get "yolo" (json {}))) - - ## (match (^ (#;Some (#json;Object (list ["lol" (#json;Number 123.45)] - ## ["yolo" (#json;Boolean true)])))) - ## (|> (json {"yolo" (gen-boolean true)}) - ## (set "lol" (gen-number 123.45)))) - - (match (#;Right true) - (get-boolean "value" (json {"value" true}))) - - (match (#;Right 123.45) - (get-number "value" (json {"value" 123.45}))) - - (match (#;Right "YOLO") - (get-string "value" (json {"value" "YOLO"}))) - - ## (match (^ (#;Right (list (#json;Boolean true) (#json;Number 123.45) (#json;String "YOLO")))) - ## (get-array "value" (json {"value" (json [(gen-boolean true) - ## (gen-number 123.45) - ## (gen-string "YOLO")])}))) - - ## (match (^ (#;Right (list ["yolo" (#json;Boolean true)] - ## ["lol" (#json;Number 123.45)]))) - ## (get-object "value" (json {"value" (json {"yolo" (gen-boolean true) - ## "lol" (gen-number 123.45)})}))) - - (match (#;Left _) - (get-array "value" (json {}))) - - (match (#;Left _) - (get-array "value" (gen-boolean true))) - )) - -(test: "Encoding" - (test-all (match "null" - (JSON/encode (json #null))) - - (match "123.0" - (JSON/encode (json 123))) - - (match "123.46" - (JSON/encode (json 123.46))) - - (match "true" - (JSON/encode (json true))) - - (match "false" - (JSON/encode (json false))) - - (match "\"YOLO\"" - (JSON/encode (json "YOLO"))) - - (match "[null,123.46,true,\"YOLO\",[\"nyan\",\"cat\"]]" - (JSON/encode (json [#null 123.46 true "YOLO" ["nyan" "cat"]]))) - - (match "{\"foo\":\"bar\",\"baz\":null,\"quux\":[\"nyan\",{\"cat\":\"meme\"}]}" - (JSON/encode (json {"foo" "bar" - "baz" #null - "quux" ["nyan" {"cat" "meme"}]}))) - )) - -(test: "Decoding" - (test-all (reads-to-itself (json #null)) - (reads-to-itself (json 123)) - (reads-to-itself (json 123.46)) - (reads-to-itself (json true)) - (reads-to-itself (json false)) - (reads-to-itself (json "\tY\"OLO\n")) - (reads-to-itself (json [#null 123.46 true "YOLO" ["nyan" "cat"]])) - (reads-to-itself (json {"foo" "bar" - "baz" #null - "quux" ["nyan" {"cat" "meme"}]})) - )) - -(test: "Parser" - (test-all (should-pass (run unit - (json #null))) - (should-fail (run unit - (json 123))) - - (match+ 123.45 - (should-pass (run real - (json 123.45)))) - (should-fail (run real - (json #null))) - - (match+ 123 - (should-pass (run int - (json 123)))) - (should-fail (run int - (json #null))) - - (match+ true - (should-pass (run bool - (json true)))) - (should-fail (run bool - (json 123))) - - (match+ "YOLO" - (should-pass (run text - (json "YOLO")))) - (should-fail (run text - (json 123))) - - (match+ (^ (list "YOLO" "LOL" "MEME")) - (should-pass (run (array text) - (json ["YOLO" "LOL" "MEME"])))) - (should-fail (run (array text) - (json 123))) - - (match+ "LOL" - (should-pass (run (at +1 text) - (json ["YOLO" "LOL" "MEME"])))) - (should-fail (run (array text) - (json 123))) - - (match+ "MEME" - (should-pass (run (field "baz" text) - (json {"foo" "YOLO" - "bar" "LOL" - "baz" "MEME"})))) - (should-fail (run (field "baz" text) - (json 123))) - - (match+ (#json;Number 123.0) - (should-pass (run any - (json 123)))) - - (match+ ["YOLO" "MEME"] - (should-pass (run (seq (field "foo" text) - (field "baz" text)) - (json {"foo" "YOLO" - "bar" "LOL" - "baz" "MEME"})))) - (should-fail (run (seq (field "foo" text) - (field "baz" text)) - (json {"foo" "YOLO" - "bar" "LOL"}))) - - (match+ (#;Left "YOLO") - (should-pass (run (alt (field "foo" text) - (field "baz" text)) - (json {"foo" "YOLO" - "bar" "LOL" - "baz" "MEME"})))) - (match+ (#;Right "MEME") - (should-pass (run (alt (field "fool" text) - (field "baz" text)) - (json {"foo" "YOLO" - "bar" "LOL" - "baz" "MEME"})))) - (should-fail (run (alt (field "fool" text) - (field "baz" text)) - (json {"foo" "YOLO" - "bar" "LOL"}))) - - (match+ "YOLO" - (should-pass (run (either (field "foo" text) - (field "baz" text)) - (json {"foo" "YOLO" - "bar" "LOL" - "baz" "MEME"})))) - (match+ "MEME" - (should-pass (run (either (field "fool" text) - (field "baz" text)) - (json {"foo" "YOLO" - "bar" "LOL" - "baz" "MEME"})))) - (should-fail (run (either (field "fool" text) - (field "baz" text)) - (json {"foo" "YOLO" - "bar" "LOL"}))) - - (match+ (#;Some "YOLO") - (should-pass (run (opt (field "foo" text)) - (json {"foo" "YOLO" - "bar" "LOL" - "baz" "MEME"})))) - (match+ #;None - (should-pass (run (opt (field "fool" text)) - (json {"foo" "YOLO" - "bar" "LOL" - "baz" "MEME"})))) - )) +(def: gen-json + (R;Random &;JSON) + (R;rec (lambda [gen-json] + (do R;Monad<Random> + [size (:: @ map (%+ +2) R;nat)] + ($_ R;alt + (:: @ wrap []) + R;bool + R;real + (R;text size) + (R;vector size gen-json) + (R;dict text;Hash<Text> size (R;text size) gen-json) + ))))) + +(test: "JSON" + [sample gen-json + #let [(^open "&/") &;Eq<JSON> + (^open "&/") &;Codec<Text,JSON>]] + ($_ seq + (assert "Every JSON is equal to itself." + (&/= sample sample)) + + (assert "Can encode/decode JSON." + (|> sample &/encode &/decode + (case> (#;Right result) + (&/= sample result) + + (#;Left _) + false))) + )) + +(type: Variant + (#Case0 Bool) + (#Case1 Int) + (#Case2 Real)) + +(type: Record + {#unit Unit + #bool Bool + #int Int + #real Real + #char Char + #text Text + #maybe (Maybe Int) + #list (List Int) + #variant Variant + #tuple [Int Real Char]}) + +(def: gen-record + (R;Random Record) + (do R;Monad<Random> + [size (:: @ map (%+ +2) R;nat)] + ($_ R;seq + (:: @ wrap []) + R;bool + R;int + R;real + R;char + (R;text size) + (R;maybe R;int) + (R;list size R;int) + ($_ R;alt R;bool R;int R;real) + ($_ R;seq R;int R;real R;char) + ))) + +(derived: (&;Codec<JSON,?> Record)) + +(struct: _ (Eq Record) + (def: (= recL recR) + (and (:: bool;Eq<Bool> = (get@ #bool recL) (get@ #bool recR)) + (;= (get@ #int recL) (get@ #int recR)) + (=. (get@ #real recL) (get@ #real recR)) + (:: char;Eq<Char> = (get@ #char recL) (get@ #char recR)) + (:: text;Eq<Text> = (get@ #text recL) (get@ #text recR)) + (:: (maybe;Eq<Maybe> number;Eq<Int>) = (get@ #maybe recL) (get@ #maybe recR)) + (:: (list;Eq<List> number;Eq<Int>) = (get@ #list recL) (get@ #list recR)) + (let [[tL0 tL1 tL2] (get@ #tuple recL) + [tR0 tR1 tR2] (get@ #tuple recR)] + (and (;= tL0 tR0) + (=. tL1 tR1) + (:: char;Eq<Char> = tL2 tR2))) + ))) + +(test: "Polytypism" + [sample gen-record + #let [(^open "&/") Eq<Record> + (^open "&/") Codec<JSON,Record>]] + (assert "Can encode/decode arbitrary types." + (|> sample &/encode &/decode + (case> (#;Right result) + (&/= sample result) + + (#;Left _) + false)))) diff --git a/stdlib/test/test/lux/data/struct/vector.lux b/stdlib/test/test/lux/data/struct/vector.lux index 2ccfa2fc1..c3f3a706e 100644 --- a/stdlib/test/test/lux/data/struct/vector.lux +++ b/stdlib/test/test/lux/data/struct/vector.lux @@ -35,10 +35,8 @@ (=+ size (&;size sample)))) (assert "Can add and remove elements to vectors." - (and (=+ (inc+ size) - (&;size (&;add non-member sample))) - (=+ (dec+ size) - (&;size (&;pop sample))))) + (and (=+ (inc+ size) (&;size (&;add non-member sample))) + (=+ (dec+ size) (&;size (&;pop sample))))) (assert "Can put and get elements into vectors." (|> sample @@ -49,16 +47,12 @@ (assert "Can update elements of vectors." (|> sample - (&;put idx non-member) - (&;update idx inc+) - (&;at idx) - (default (undefined)) + (&;put idx non-member) (&;update idx inc+) + (&;at idx) (default (undefined)) (=+ (inc+ non-member)))) (assert "Can safely transform to/from lists." - (|> sample - &;to-list &;from-list - (&/= sample))) + (|> sample &;to-list &;from-list (&/= sample))) (assert "Can identify members of a vector." (and (not (&;member? number;Eq<Nat> sample non-member)) @@ -76,8 +70,7 @@ (assert "Applicative allows you to create singleton vectors, and apply vectors of functions to vectors of values." (and (&/= (&;vector non-member) (&/wrap non-member)) - (&/= (&/map inc+ sample) - (&/apply (&/wrap inc+) sample)))) + (&/= (&/map inc+ sample) (&/apply (&/wrap inc+) sample)))) (assert "Vector concatenation is a monad." (&/= (&/append sample other-sample) diff --git a/stdlib/test/tests.lux b/stdlib/test/tests.lux index 7b760c0f1..94148e1d7 100644 --- a/stdlib/test/tests.lux +++ b/stdlib/test/tests.lux @@ -23,7 +23,8 @@ [product] [sum] [text] - [text/format] + (error [exception]) + (format [json]) (struct [array] [dict] [list] @@ -34,6 +35,7 @@ [vector] [zipper] ) + (text [format]) ) ## (codata ["_;" io] ## [env] |