... 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 https://mozilla.org/MPL/2.0/.

(.using
 [library
  [lux (.except)
   [abstract
    ["[0]" monad]]
   [data
    [collection
     ["[0]" stack]]
    [text
     ["%" \\injection]]]
   [math
    ["[0]" random]
    [number
     [/64
      ["n" natural]]]]
   ["[0]" type]
   [test
    ["_" property (.only Test)]]]]
 [\\library
  ["[0]" / (.only)
   ["/[1]" //]]])

(the .public test
  Test
  (<| (_.covering /._)
      (monad.let [! random.monad]
        [elems (random.stack 3 random.natural)

         left random.natural
         right random.natural])
      (all _.and
           (_.coverage [/.Static
                        /.reset /.context
                        /.shift /.exit]
             (and (let [(open "//#[0]") //.monad
                        (open "stack#[0]") (stack.equivalence n.equivalence)
                        visit (is (-> (Stack Natural)
                                      (//.Cont (Stack Natural) (Stack Natural)))
                                  (function (visit it)
                                    (when it
                                      {.#Empty}
                                      (//#pure {.#Empty})

                                      {.#Top head tail}
                                      (monad.let [! //.monad]
                                        [output (/.shift (function (_ after)
                                                           (pure {.#Top head (after tail)})))]
                                        (visit output)))))]
                    (//.continued (stack#= elems)
                                  (/.reset (visit elems))))
                  (same? /.reset /.context)
                  (same? /.shift /.exit)))
           (_.coverage [/.Dynamic
                        /.prompt /.control]
             (and (|> (monad.let [! //.monad]
                        [it (/.shift (function (_ after)
                                       (monad.let !
                                         [.let [it (after right)]]
                                         (pure (n.x left it)))))]
                        (/.shift (function (_ after)
                                   (pure it))))
                      (is (//.Cont Natural (/.Static Natural)))
                      /.reset
                      //.value
                      (n.= (n.x left right)))
                  (|> (monad.let [! //.monad]
                        [it (/.control (function (_ after)
                                         (monad.let !
                                           [it (after right)]
                                           (pure (n.x left it)))))]
                        (/.control (function (_ after)
                                     (pure it))))
                      (is (//.Cont Natural (/.Dynamic Natural)))
                      /.prompt
                      //.value
                      (same? right))
                  ))
           (_.coverage [/.Propagated
                        /.propagated
                        /.reset_0 /.shift_0]
             (and (|> (/.reset (is (//.Cont Natural (/.Static Natural))
                                   (monad.let [! //.monad]
                                     [it (is (//.Cont Natural (/.Static Natural))
                                             (/.reset (/.shift (function (_ after)
                                                                 (/.shift (function (_ after)
                                                                            (pure right)))))))]
                                     (pure (n.x left it)))))
                      //.value
                      (n.= (n.x left right)))
                  (|> (/.reset_0 (is (//.Cont Natural (/.Propagated Natural))
                                     (monad.let [! //.monad]
                                       [it (is (//.Cont Natural (/.Propagated Natural))
                                               (/.reset_0 (/.shift_0 (function (_ after)
                                                                       (/.shift_0 (function (_ after)
                                                                                    (pure right)))))))]
                                       (pure (n.x left it)))))
                      /.propagated
                      //.value
                      (n.= right))
                  ))
           )))
