(.module: [library [lux "*" ["_" test {"+" [Test]}] [abstract [monad {"+" [do]}] [\\specification ["$[0]" functor {"+" [Injection Comparison]}] ["$[0]" apply] ["$[0]" monad]]] [control ["[0]" try] ["[0]" exception] ["[0]" io {"+" [IO io]}]] [data [collection ["[0]" list ("[1]\[0]" mix monoid)] ["[0]" row {"+" [Row]}]]] [math ["[0]" random] [number ["n" nat]]]]] [\\library ["[0]" / [// ["[0]" async {"+" [Async]} ("[1]\[0]" monad)] ["[0]" atom {"+" [Atom atom]}]]]]) (def: injection (Injection /.Channel) (|>> async.resolved /.of_async)) (def: comparison (Comparison /.Channel) (function (_ == left right) (io.run! (do io.monad [?left (async.value left) ?right (async.value right)] (in (case [?left ?right] [(#.Some (#.Some [left _])) (#.Some (#.Some [right _]))] (== left right) _ false)))))) (def: (take_amount amount_of_polls [channel sink]) (All (_ a) (-> Nat [(/.Channel a) (/.Sink a)] (Async (List a)))) (case amount_of_polls 0 (do async.monad [_ (async.future (\ sink close))] (in #.End)) _ (do [! async.monad] [event channel] (case event #.None (in #.End) (#.Some [head tail]) (\ ! each (|>> (#.Item head)) (take_amount (-- amount_of_polls) [channel sink])))))) (def: .public test Test (<| (_.covering /._) (let [(^open "list\[0]") (list.equivalence n.equivalence)] (do [! random.monad] [inputs (random.list 5 random.nat) sample random.nat distint/0 random.nat distint/1 (|> random.nat (random.only (|>> (n.= distint/0) not))) distint/2 (|> random.nat (random.only (function (_ value) (not (or (n.= distint/0 value) (n.= distint/1 value)))))) shift random.nat] ($_ _.and (_.for [/.functor] ($functor.spec ..injection ..comparison /.functor)) (_.for [/.apply] ($apply.spec ..injection ..comparison /.apply)) (_.for [/.monad] ($monad.spec ..injection ..comparison /.monad)) (_.cover [/.Channel /.Sink /.channel] (case (io.run! (do (try.with io.monad) [.let [[channel sink] (/.channel [])] _ (\ sink feed sample) _ (\ sink close)] (in channel))) (#try.Success channel) (io.run! (do io.monad [?actual (async.value channel)] (in (case ?actual (#.Some (#.Some [actual _])) (n.= sample actual) _ false)))) (#try.Failure error) false)) (_.cover [/.channel_is_already_closed] (case (io.run! (do (try.with io.monad) [.let [[channel sink] (/.channel [])] _ (\ sink close)] (\ sink feed sample))) (#try.Success _) false (#try.Failure error) (exception.match? /.channel_is_already_closed error))) (in (do async.monad [output (|> sample async.resolved /.of_async /.list)] (_.cover' [/.of_async /.list] (list\= (list sample) output)))) (in (do async.monad [output (|> inputs (/.sequential 0) /.list)] (_.cover' [/.sequential] (list\= inputs output)))) (in (do async.monad [output (|> inputs (/.sequential 0) (/.only n.even?) /.list)] (_.cover' [/.only] (list\= (list.only n.even? inputs) output)))) (in (do [! async.monad] [.let [[?signal !signal] (: [(async.Async Any) (async.Resolver Any)] (async.async [])) sink (: (Atom (Row Nat)) (atom.atom row.empty))] _ (async.future (/.subscribe! (function (_ value) (do [! io.monad] [current (atom.read! sink) _ (atom.update! (row.suffix value) sink)] (if (n.< (list.size inputs) (++ (row.size current))) (in (#.Some [])) (do ! [_ (!signal [])] (in #.None))))) (/.sequential 0 (list\composite inputs inputs)))) _ ?signal listened (|> sink atom.read! async.future (\ ! each row.list))] (_.cover' [/.Subscriber /.subscribe!] (list\= inputs listened)))) (in (do async.monad [actual (/.mix (function (_ input total) (async.resolved (n.+ input total))) 0 (/.sequential 0 inputs))] (_.cover' [/.mix] (n.= (list\mix n.+ 0 inputs) actual)))) (in (do async.monad [actual (|> inputs (/.sequential 0) (/.mixes (function (_ input total) (async.resolved (n.+ input total))) 0) /.list)] (_.cover' [/.mixes] (list\= (list.mixes n.+ 0 inputs) actual)))) (in (do async.monad [actual (|> (list distint/0 distint/0 distint/0 distint/1 distint/2 distint/2) (/.sequential 0) (/.distinct n.equivalence) /.list)] (_.cover' [/.distinct] (list\= (list distint/0 distint/1 distint/2) actual)))) (do ! [polling_delay (\ ! each (|>> (n.% 10) ++) random.nat) amount_of_polls (\ ! each (|>> (n.% 10) ++) random.nat)] ($_ _.and (in (do [! async.monad] [actual (..take_amount amount_of_polls (/.poll polling_delay (: (IO Nat) (io.io sample)))) .let [correct_values! (list.every? (n.= sample) actual) enough_polls! (n.= amount_of_polls (list.size actual))]] (_.cover' [/.poll] (and correct_values! enough_polls!)))) (in (do [! async.monad] [actual (..take_amount amount_of_polls (/.periodic polling_delay))] (_.cover' [/.periodic] (n.= amount_of_polls (list.size actual))))))) (in (do async.monad [.let [max_iterations 10] actual (|> [0 sample] (/.iterations (function (_ [iterations current]) (async.resolved (if (n.< max_iterations iterations) (#.Some [[(++ iterations) (n.+ shift current)] current]) #.None)))) /.list)] (_.cover' [/.iterations] (and (n.= max_iterations (list.size actual)) (list\= (list.mixes n.+ sample (list.repeated (-- max_iterations) shift)) actual))))) )))))