(.using [library [lux "*" ["_" test {"+" Test}] [abstract [monad {"+" do}] ["[0]" enum] [\\specification ["$[0]" equivalence] ["$[0]" hash] ["$[0]" monoid] ["$[0]" mix] ["$[0]" functor] ["$[0]" apply] ["$[0]" monad]]] [control pipe ["[0]" io] ["[0]" maybe] ["[0]" function]] [data ["[0]" bit] ["[0]" product] ["[0]" text ("[1]#[0]" equivalence)] [collection ["[0]" set]]] [math ["[0]" random {"+" Random}] [number ["n" nat] ["[0]" int]]]]] [\\library ["[0]" / ("[1]#[0]" monad)]]) (def: bounded_size (Random Nat) (# random.monad each (n.% 100) random.nat)) (def: random (Random (List Nat)) (do [! random.monad] [size ..bounded_size] (|> random.nat (random.set n.hash size) (# ! each set.list)))) (def: signatures Test ($_ _.and (_.for [/.equivalence] ($equivalence.spec (/.equivalence n.equivalence) ..random)) (_.for [/.hash] (|> random.nat (# random.monad each (|>> list)) ($hash.spec (/.hash n.hash)))) (_.for [/.monoid] ($monoid.spec (/.equivalence n.equivalence) /.monoid ..random)) (_.for [/.mix] ($mix.spec /#in /.equivalence /.mix)) (_.for [/.functor] ($functor.spec /#in /.equivalence /.functor)) (_.for [/.apply] ($apply.spec /#in /.equivalence /.apply)) (_.for [/.monad] ($monad.spec /#in /.equivalence /.monad)) (do [! random.monad] [parameter random.nat subject random.nat] (let [lifted (/.lifted io.monad) (^open "io#[0]") io.monad expected (n.+ parameter subject)] (_.cover [/.with /.lifted] (|> (io.run! (do (/.with io.monad) [a (lifted (io#in parameter)) b (in subject)] (in (n.+ a b)))) (case> (^ (list actual)) (n.= expected actual) _ false))))) )) (def: whole Test (do [! random.monad] [size ..bounded_size .let [(^open "/#[0]") (/.equivalence n.equivalence)] sample (# ! each set.list (random.set n.hash size random.nat))] ($_ _.and (_.cover [/.size] (n.= size (/.size sample))) (_.cover [/.empty?] (# bit.equivalence = (/.empty? sample) (n.= 0 (/.size sample)))) (_.cover [/.repeated] (n.= size (/.size (/.repeated size [])))) (_.cover [/.reversed] (or (n.< 2 (/.size sample)) (let [not_same! (not (/#= sample (/.reversed sample))) self_symmetry! (/#= sample (/.reversed (/.reversed sample)))] (and not_same! self_symmetry!)))) (_.cover [/.every? /.any?] (if (/.every? n.even? sample) (not (/.any? (bit.complement n.even?) sample)) (/.any? (bit.complement n.even?) sample))) (_.cover [/.sorted] (let [<<< n.< size_preservation! (n.= (/.size sample) (/.size (/.sorted <<< sample))) symmetry! (/#= (/.sorted <<< sample) (/.reversed (/.sorted (function.flipped <<<) sample)))] (and size_preservation! symmetry!))) ))) (def: indices Test (let [(^open "/#[0]") (/.equivalence n.equivalence) (^open "/#[0]") /.functor] (do [! random.monad] [sample ..random .let [size (/.size sample)]] ($_ _.and (_.cover [/.indices] (let [indices (/.indices size) expected_amount! (n.= size (/.size indices)) already_sorted! (/#= indices (/.sorted n.< indices)) expected_numbers! (/.every? (n.= (-- size)) (/.zipped_with/2 n.+ indices (/.sorted n.> indices)))] (and expected_amount! already_sorted! expected_numbers!))) (_.cover [/.enumeration] (let [enumeration (/.enumeration sample) has_correct_indices! (/#= (/.indices (/.size enumeration)) (/#each product.left enumeration)) has_correct_values! (/#= sample (/#each product.right enumeration))] (and has_correct_indices! has_correct_values!))) (_.cover [/.item] (/.every? (function (_ [index expected]) (case (/.item index sample) {.#Some actual} (n.= expected actual) {.#None} false)) (/.enumeration sample))) (do ! [index (case size 0 random.nat _ (# ! each (n.% size) random.nat)) .let [changed? (/#= sample (/.revised index ++ sample)) same? (/#= sample (/.revised size ++ sample))]] (_.cover [/.revised] (case size 0 (and changed? same?) _ (not changed?)))) )))) (def: slice Test (let [(^open "/#[0]") (/.equivalence n.equivalence) (^open "/#[0]") /.monoid] (do [! random.monad] [sample (random.only (|>> /.size (n.> 0)) ..random) .let [size (/.size sample)] idx (# ! each (n.% size) random.nat) sub_size (# ! each (|>> (n.% size) ++) random.nat)] ($_ _.and (_.cover [/.only] (let [positives (/.only n.even? sample) negatives (/.only (bit.complement n.even?) sample)] (and (/.every? n.even? positives) (not (/.any? n.even? negatives)) (n.= (/.size sample) (n.+ (/.size positives) (/.size negatives)))))) (_.cover [/.partition] (let [[positives negatives] (/.partition n.even? sample)] (and (/#= (/.only n.even? sample) positives) (/#= (/.only (bit.complement n.even?) sample) negatives)))) (_.cover [/.split_at] (let [[left right] (/.split_at idx sample)] (/#= sample (/#composite left right)))) (_.cover [/.split_when] (let [[left right] (/.split_when n.even? sample)] (/#= sample (/#composite left right)))) (_.cover [/.first /.after] (/#= sample (/#composite (/.first idx sample) (/.after idx sample)))) (_.cover [/.while /.until] (/#= sample (/#composite (/.while n.even? sample) (/.until n.even? sample)))) (_.cover [/.sub] (let [subs (/.sub sub_size sample)] (and (/.every? (|>> /.size (n.<= sub_size)) subs) (/#= sample (/.together subs))))) )))) (def: member Test (let [(^open "/#[0]") (/.equivalence n.equivalence)] (do [! random.monad] [sample ..random] (`` ($_ _.and (_.cover [/.member?] (/.every? (/.member? n.equivalence sample) sample)) (~~ (template [
]
                    [($_ _.and
                         (_.cover []
                                  (case [(
 sample) ( sample)]
                                    [{.#Item expected _} {.#Some actual}]
                                    (n.= expected actual)

                                    [{.#End} {.#None}]
                                    true

                                    _
                                    false))
                         (_.cover []
                                  (case [(
 sample) ( sample)]
                                    [{.#Item _ expected} {.#Some actual}]
                                    (/#= (
 expected) actual)

                                    [{.#End} {.#None}]
                                    true

                                    _
                                    false))
                         )]

                    [/.head /.tail |>]
                    [/.last /.inits /.reversed]
                    ))
              )))))

(def: grouping
  Test
  (let [(^open "/#[0]") (/.equivalence n.equivalence)
        (^open "/#[0]") /.functor
        (^open "/#[0]") /.monoid
        
        +/2 (: (-> Nat Nat Nat)
               (function (_ left right)
                 ($_ n.+ left right)))
        +/3 (: (-> Nat Nat Nat Nat)
               (function (_ left mid right)
                 ($_ n.+ left mid right)))]
    (do [! random.monad]
      [sample/0 ..random
       sample/1 ..random
       sample/2 ..random]
      ($_ _.and
          (_.cover [/.pairs]
                   (let [even_sized? (|> sample/0
                                         /.size
                                         (n.% 2)
                                         (n.= 0))]
                     (case (/.pairs sample/0)
                       {.#Some pairs/0}
                       (and even_sized?
                            (n.= (n./ 2 (/.size sample/0))
                                 (/.size pairs/0)))

                       {.#None}
                       (not even_sized?))))
          (_.cover [/.zipped/2]
                   (let [zipped (/.zipped/2 sample/0 sample/1)
                         zipped::size (/.size zipped)

                         size_of_smaller_list!
                         (n.= zipped::size
                              (n.min (/.size sample/0) (/.size sample/1)))

                         can_extract_values!
                         (and (/#= (/.first zipped::size sample/0)
                                   (/#each product.left zipped))
                              (/#= (/.first zipped::size sample/1)
                                   (/#each product.right zipped)))]
                     (and size_of_smaller_list!
                          can_extract_values!)))
          (_.cover [/.zipped/3]
                   (let [zipped (/.zipped/3 sample/0 sample/1 sample/2)
                         zipped::size (/.size zipped)
                         
                         size_of_smaller_list!
                         (n.= zipped::size
                              ($_ n.min
                                  (/.size sample/0)
                                  (/.size sample/1)
                                  (/.size sample/2)))

                         can_extract_values!
                         (and (/#= (/.first zipped::size sample/0)
                                   (/#each product.left zipped))
                              (/#= (/.first zipped::size sample/1)
                                   (/#each (|>> product.right product.left) zipped))
                              (/#= (/.first zipped::size sample/2)
                                   (/#each (|>> product.right product.right) zipped)))]
                     (and size_of_smaller_list!
                          can_extract_values!)))
          (_.cover [/.zipped]
                   (and (# (/.equivalence (product.equivalence n.equivalence n.equivalence)) =
                           (/.zipped/2 sample/0 sample/1)
                           ((/.zipped 2) sample/0 sample/1))
                        (# (/.equivalence ($_ product.equivalence n.equivalence n.equivalence n.equivalence)) =
                           (/.zipped/3 sample/0 sample/1 sample/2)
                           ((/.zipped 3) sample/0 sample/1 sample/2))))

          (_.cover [/.zipped_with/2]
                   (/#= (/#each (function (_ [left right])
                                  (+/2 left right))
                                (/.zipped/2 sample/0 sample/1))
                        (/.zipped_with/2 +/2 sample/0 sample/1)))
          (_.cover [/.zipped_with/3]
                   (/#= (/#each (function (_ [left mid right])
                                  (+/3 left mid right))
                                (/.zipped/3 sample/0 sample/1 sample/2))
                        (/.zipped_with/3 +/3 sample/0 sample/1 sample/2)))
          (_.cover [/.zipped_with]
                   (and (/#= (/.zipped_with/2 +/2 sample/0 sample/1)
                             ((/.zipped_with 2) +/2 sample/0 sample/1))
                        (/#= (/.zipped_with/3 +/3 sample/0 sample/1 sample/2)
                             ((/.zipped_with 3) +/3 sample/0 sample/1 sample/2))))
          (_.cover [/.together]
                   (and (/#= (/#composite sample/0 sample/1)
                             (/.together (list sample/0 sample/1)))
                        (/#= ($_ /#composite sample/0 sample/1 sample/2)
                             (/.together (list sample/0 sample/1 sample/2)))))
          ))))

(def: search
  Test
  (let [(^open "/#[0]") /.functor
        
        choice (: (-> Nat (Maybe Text))
                  (function (_ value)
                    (if (n.even? value)
                      {.#Some (# n.decimal encoded value)}
                      {.#None})))]
    (do [! random.monad]
      [sample ..random]
      ($_ _.and
          (_.cover [/.one]
                   (case [(|> sample
                              (/.only n.even?)
                              (/#each (# n.decimal encoded))
                              /.head)
                          (/.one choice sample)]
                     [{.#Some expected} {.#Some actual}]
                     (text#= expected actual)

                     [{.#None} {.#None}]
                     true

                     _
                     false))
          (_.cover [/.all]
                   (# (/.equivalence text.equivalence) =
                      (|> sample
                          (/.only n.even?)
                          (/#each (# n.decimal encoded)))
                      (/.all choice sample)))
          (_.cover [/.example]
                   (case (/.example n.even? sample)
                     {.#Some found}
                     (n.even? found)

                     {.#None}
                     (not (/.any? n.even? sample))))
          ))))

(def: .public test
  Test
  (<| (_.covering /._)
      (_.for [.List])
      (let [(^open "/#[0]") (/.equivalence n.equivalence)
            (^open "/#[0]") /.functor]
        (do [! random.monad]
          [sample ..random
           separator random.nat]
          ($_ _.and
              ..signatures
              ..whole
              ..indices
              ..slice
              ..member
              ..grouping
              ..search
              
              (_.cover [/.interposed]
                       (or (/.empty? sample)
                           (let [sample+ (/.interposed separator sample)]
                             (and (n.= (|> (/.size sample) (n.* 2) --)
                                       (/.size sample+))
                                  (|> sample+
                                      /.pairs
                                      (maybe.else (list))
                                      (/.every? (|>> product.right (n.= separator))))))))
              (_.cover [/.iterations]
                       (or (/.empty? sample)
                           (let [size (/.size sample)]
                             (/#= (/.indices size)
                                  (/.iterations (function (_ index)
                                                  (if (n.< size index)
                                                    {.#Some (++ index)}
                                                    {.#None}))
                                                0)))))
              (_.cover [/.mixes]
                       (/#= (/#each (function (_ index)
                                      (# /.mix mix n.+ 0 (/.first index sample)))
                                    (/.indices (++ (/.size sample))))
                            (/.mixes n.+ 0 sample)))
              (do random.monad
                [expected random.nat
                 .let [(^open "/#[0]") (/.equivalence n.equivalence)]]
                (_.cover [/.when]
                         (and (/#= (list expected) (/.when true (list expected)))
                              (/#= (list) (/.when false (list expected))))))
              )))))