(.module: [lux #* ["_" test (#+ Test)] [abstract [monad (#+ do)]] [control ["." try] [security ["!" capability]] [concurrency ["." promise (#+ Promise)]] [parser ["." environment (#+ Environment)]]] [data ["." product] ["." text ("#\." equivalence) ["%" format (#+ format)]]] [math ["." random] [number ["n" nat] ["i" int]]]] {1 ["." / [// [file (#+ Path)]]]}) (template [ ] [(def: (-> [Environment Path /.Command (List /.Argument)]) (|>> list [environment.empty "~" ]))] [echo! "echo" Text (|>)] [sleep! "sleep" Nat %.nat] ) (def: (read_test expected process) (-> Text (/.Process Promise) _.Assertion) (do promise.monad [?read (!.use (\ process read) []) ?await (!.use (\ process await) [])] ($_ _.and' (_.cover' [/.Can_Read] (case ?read (#try.Success actual) (text\= expected actual) (#try.Failure error) false)) (_.cover' [/.Can_Wait /.Exit /.normal] (case ?await (#try.Success exit) (i.= /.normal exit) (#try.Failure error) false)) ))) (def: (destroy_test process) (-> (/.Process Promise) _.Assertion) (do promise.monad [?destroy (!.use (\ process destroy) []) ?await (!.use (\ process await) [])] (_.cover' [/.Can_Destroy] (and (case ?destroy (#try.Success _) true (#try.Failure error) false) (case ?await (#try.Success _) false (#try.Failure error) true))))) (with_expansions [ (as_is [/.Can_Execute /.Command /.Argument])] (def: #export (spec shell) (-> (/.Shell Promise) Test) (<| (_.for [/.Shell /.Process]) (do {! random.monad} [message (random.ascii/alpha 10) seconds (\ ! map (|>> (n.% 5) (n.+ 5)) random.nat)] (wrap (do promise.monad [?echo (!.use (\ shell execute) (..echo! message)) ?sleep (!.use (\ shell execute) (..sleep! seconds))] (case [?echo ?sleep] [(#try.Success echo) (#try.Success sleep)] ($_ _.and' (_.cover' true) (..read_test message echo) (..destroy_test sleep)) _ (_.cover' false))))))))