aboutsummaryrefslogtreecommitdiff
path: root/stdlib/source/specification/lux/world/shell.lux
blob: f0248af56f26983358915d17c0da2f27d3087a65 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
(.require
 [library
  [lux (.except)
   [abstract
    [monad (.only do)]]
   [control
    ["[0]" try (.use "[1]#[0]" functor)]
    [concurrency
     ["[0]" async (.only Async) (.use "[1]#[0]" monad)]]]
   [data
    ["[0]" product]
    ["[0]" text (.use "[1]#[0]" equivalence)
     ["%" \\format (.only format)]]]
   [math
    ["[0]" random]
    [number
     ["n" nat]
     ["i" int]]]
   [test
    ["_" property (.only Test)]
    ["[0]" unit]]]]
 [\\library
  ["[0]" / (.only)
   [//
    [file (.only Path)]
    ["[0]" environment
     ["[1]" \\parser (.only Environment)]]]]])

(with_template [<name> <command> <type> <prep>]
  [(def <name>
     (-> <type> [Environment Path /.Command (List /.Argument)])
     (|>> <prep> list [environment.empty "~" <command>]))]

  [echo! "echo" Text (|>)]
  [sleep! "sleep" Nat %.nat]
  )

(def (can_wait! process)
  (-> (/.Process Async) unit.Test)
  (|> (of process await [])
      (async#each (|>> (try#each (i.= /.normal))
                       (try.else false)
                       (unit.coverage [/.Exit /.normal])))
      async#conjoint))

(def (can_read! expected process)
  (-> Text (/.Process Async) (Async Bit))
  (|> (of process read [])
      (async#each (|>> (try#each (text#= expected))
                       (try.else false)))))

(def (can_destroy! process)
  (-> (/.Process Async) (Async Bit))
  (do async.monad
    [?destroy (of process destroy [])
     ?await (of process await [])]
    (in (and (when ?destroy
               {try.#Success _}
               true
               
               {try.#Failure error}
               false)
             (when ?await
               {try.#Success _}
               false
               
               {try.#Failure error}
               true)))))

(with_expansions [<shell_coverage> (these [/.Command /.Argument])]
  (def .public (spec shell)
    (-> (/.Shell Async) Test)
    (<| (_.for [/.Shell
                /.execute
                
                /.Process
                /.read /.fail /.write /.destroy /.await])
        (do [! random.monad]
          [message (random.alphabetic 10)
           seconds (of ! each (|>> (n.% 5) (n.+ 5)) random.nat)]
          (in (do [! async.monad]
                [?echo (of shell execute (..echo! message))
                 ?sleep (of shell execute (..sleep! seconds))]
                (when [?echo ?sleep]
                  [{try.#Success echo} {try.#Success sleep}]
                  (do !
                    [can_read! (..can_read! message echo)
                     can_destroy! (..can_destroy! sleep)]
                    (all unit.and
                         (unit.coverage <shell_coverage>
                           (and can_read!
                                can_destroy!))
                         (..can_wait! echo)
                         ))
                  
                  _
                  (unit.coverage <shell_coverage>
                    false))))))))