(.module: [library [lux "*" ["_" test {"+" [Test]}] ["[0]" meta] [abstract [monad {"+" [do]}] [\\specification ["$[0]" equivalence] ["$[0]" codec]]] [control ["[0]" try ("[1]\[0]" functor)]] [data ["[0]" product] ["[0]" bit] ["[0]" text ["%" format {"+" [format]}]] [collection ["[0]" row] ["[0]" dictionary] ["[0]" set] ["[0]" list ("[1]\[0]" functor)]]] [math ["[0]" random {"+" [Random]}] [number ["n" nat] ["[0]" frac]]] ["[0]" macro ["[0]" syntax {"+" [syntax:]}] ["[0]" code]]]] [\\library ["[0]" / {"+" [JSON]} ("\[0]" equivalence)]]) (def: .public random (Random /.JSON) (random.rec (function (_ recur) (do [! random.monad] [size (\ ! each (n.% 2) random.nat)] ($_ random.or (\ ! in []) random.bit random.safe_frac (random.unicode size) (random.row size recur) (random.dictionary text.hash size (random.unicode size) recur) ))))) (syntax: (boolean []) (do meta.monad [value meta.seed] (in (list (code.bit (n.even? value)))))) (syntax: (number []) (do meta.monad [value meta.seed] (in (list (code.frac (n.frac value)))))) (syntax: (string []) (do meta.monad [value (macro.identifier "string")] (in (list (code.text (%.code value)))))) (def: .public test Test (<| (_.covering /._) (_.for [/.JSON]) (`` ($_ _.and (_.for [/.equivalence] ($equivalence.spec /.equivalence ..random)) (_.for [/.codec] ($codec.spec /.equivalence /.codec ..random)) (do random.monad [sample ..random] (_.cover [/.Null /.null?] (\ bit.equivalence = (/.null? sample) (case sample #/.Null true _ false)))) (do random.monad [expected ..random] (_.cover [/.format] (|> expected /.format (\ /.codec decoded) (try\each (\= expected)) (try.else false)))) (do random.monad [keys (random.set text.hash 3 (random.ascii/alpha 1)) values (random.set frac.hash 3 random.safe_frac) .let [expected (list.zipped/2 (set.list keys) (list\each (|>> #/.Number) (set.list values))) object (/.object expected)]] ($_ _.and (_.cover [/.object /.fields] (case (/.fields object) {#try.Success actual} (\ (list.equivalence text.equivalence) = (list\each product.left expected) actual) {#try.Failure error} false)) (_.cover [/.field] (list.every? (function (_ [key expected]) (|> (/.field key object) (try\each (\= expected)) (try.else false))) expected)) )) (do random.monad [key (random.ascii/alpha 1) unknown (random.only (|>> (\ text.equivalence = key) not) (random.ascii/alpha 1)) expected random.safe_frac] (_.cover [/.has] (<| (try.else false) (do try.monad [object (/.has key {#/.Number expected} (/.object (list))) .let [can_find_known_key! (|> object (/.field key) (try\each (\= {#/.Number expected})) (try.else false)) cannot_find_unknown_key! (case (/.field unknown object) {#try.Success _} false {#try.Failure error} true)]] (in (and can_find_known_key! cannot_find_unknown_key!)))))) (~~ (template [ ] [(do random.monad [key (random.ascii/alpha 1) value ] (_.cover [ ] (|> (/.object (list [key { value}])) ( key) (try\each (\ = value)) (try.else false))))] [/.Boolean /.boolean_field #/.Boolean random.bit bit.equivalence] [/.Number /.number_field #/.Number random.safe_frac frac.equivalence] [/.String /.string_field #/.String (random.ascii/alpha 1) text.equivalence] [/.Array /.array_field #/.Array (random.row 3 ..random) (row.equivalence /.equivalence)] [/.Object /.object_field #/.Object (random.dictionary text.hash 3 (random.ascii/alpha 1) ..random) (dictionary.equivalence /.equivalence)] )) (with_expansions [ (boolean) (number) (string) (row.row #/.Null {#/.Boolean } {#/.Number } {#/.String }) (string) (string) (string) (string) (string) (string) (string)] (_.cover [/.json] (and (\= #/.Null (/.json #null)) (~~ (template [ ] [(\= { } (/.json ))] [#/.Boolean ] [#/.Number ] [#/.String ] )) (\= {#/.Array } (/.json [#null ])) (let [object (/.json { #null [#null ] { }})] (<| (try.else false) (do try.monad [value0 (/.field object) value1 (/.field object) value2 (/.field object) value3 (/.field object) value4 (/.field object) value5 (/.field object) value6 (/.field value5)] (in (and (\= #/.Null value0) (\= {#/.Boolean } value1) (\= {#/.Number } value2) (\= {#/.String } value3) (\= {#/.Array } value4) (\= {#/.Number } value6)))))) ))) ))))