(.require [library [lux (.except) [abstract [monad (.only do)]] [control ["[0]" io] ["[0]" exception] [concurrency ["[0]" async] ["[0]" atom (.only Atom)]]] [data ["[0]" text (.use "[1]#[0]" equivalence) ["%" \\format]] [collection ["[0]" list] ["[0]" set]]] [math ["[0]" random] [number ["n" nat]]]]] [\\library ["[0]" / (.only) ["[0]" unit] ["[0]" tally (.only Tally)]]]) (def (verify expected_message/0 expected_message/1 successes failures [tally message]) (-> Text Text Nat Nat [Tally Text] Bit) (and (text.contains? expected_message/0 message) (text.contains? expected_message/1 message) (n.= successes (the tally.#successes tally)) (n.= failures (the tally.#failures tally)))) (def unit_test /.Test (do [! random.monad] [expected_message/0 (random.lower_case 5) expected_message/1 (random.only (|>> (text#= expected_message/0) not) (random.lower_case 5))] (all /.and (in (do async.monad [[success_tally success_message] (unit.test expected_message/0 true) [failure_tally failure_message] (unit.test expected_message/0 false)] (unit.coverage [unit.test tally.Tally] (and (text.ends_with? expected_message/0 success_message) (text.ends_with? expected_message/0 failure_message) (and (n.= 1 (the tally.#successes success_tally)) (n.= 0 (the tally.#failures success_tally))) (and (n.= 0 (the tally.#successes failure_tally)) (n.= 1 (the tally.#failures failure_tally))))))) (in (do async.monad [tt (unit.and (unit.test expected_message/0 true) (unit.test expected_message/1 true)) ff (unit.and (unit.test expected_message/0 false) (unit.test expected_message/1 false)) tf (unit.and (unit.test expected_message/0 true) (unit.test expected_message/1 false)) ft (unit.and (unit.test expected_message/0 false) (unit.test expected_message/1 true))] (unit.coverage [unit.and] (and (..verify expected_message/0 expected_message/1 2 0 tt) (..verify expected_message/0 expected_message/1 0 2 ff) (..verify expected_message/0 expected_message/1 1 1 tf) (..verify expected_message/0 expected_message/1 1 1 ft))))) ))) (def seed /.Test (do [! random.monad] [seed random.nat .let [[read write] (is [(async.Async Nat) (async.Resolver Nat)] (async.async []))] pre (<| (/.seed seed) (do ! [sample random.nat .let [wrote? (io.run! (write sample))]] (/.test "" wrote?))) post (<| (/.seed seed) (do ! [actual random.nat] (in (do async.monad [expected read] (unit.test "" (n.= expected actual))))))] (in (do async.monad [[pre_tally pre_message] pre [post_tally post_message] post] (unit.coverage [/.seed] (and (and (n.= 1 (the tally.#successes pre_tally)) (n.= 0 (the tally.#failures pre_tally))) (and (n.= 1 (the tally.#successes post_tally)) (n.= 0 (the tally.#failures post_tally))))))))) (def times /.Test (all /.and (do [! random.monad] [times_unit_test (/.times 0 (/.test "" true))] (in (do async.monad [[tally error] times_unit_test] (unit.coverage [/.must_try_test_at_least_once] (and (text.contains? (the exception.#label /.must_try_test_at_least_once) error) (n.= 0 (the tally.#successes tally)) (n.= 1 (the tally.#failures tally))))))) (do [! random.monad] [expected (at ! each (|>> (n.% 10) ++) random.nat) .let [counter (is (Atom Nat) (atom.atom 0))] times_unit_test (<| (/.times expected) (do ! [_ (in []) .let [_ (io.run! (atom.update! ++ counter))]] (/.test "" true)))] (in (do async.monad [[tally error] times_unit_test actual (async.future (atom.read! counter))] (unit.coverage [/.times] (and (n.= expected actual) (n.= 1 (the tally.#successes tally)) (n.= 0 (the tally.#failures tally))))))) )) (def in_parallel /.Test (all /.and (do [! random.monad] [expected (at ! each (|>> (n.% 10) ++) random.nat) .let [counter (is (Atom Nat) (atom.atom 0))] unit_test (<| /.in_parallel (list.repeated expected) (is /.Test) (do ! [_ (in []) .let [_ (io.run! (atom.update! ++ counter))]] (/.test "" true)))] (in (do async.monad [[tally error] unit_test actual (async.future (atom.read! counter))] (unit.coverage [/.in_parallel] (and (n.= expected actual) (n.= expected (the tally.#successes tally)) (n.= 0 (the tally.#failures tally))))))) (do [! random.monad] [expected (at ! each (|>> (n.% 10) ++) random.nat) .let [counter (is (Atom Nat) (atom.atom 0))] unit_test (<| /.in_parallel (list.repeated expected) (is /.Test) (do ! [_ (in []) .let [_ (undefined) _ (io.run! (atom.update! ++ counter))]] (/.test "" true)))] (in (do async.monad [[tally error] unit_test actual (async.future (atom.read! counter))] (unit.coverage [/.error_during_execution] (let [correct_error! (text.contains? (the exception.#label /.error_during_execution) error) no_complete_run! (n.= 0 actual) no_successes! (n.= 0 (the tally.#successes tally)) ran_all_tests! (n.= expected (the tally.#failures tally))] (and correct_error! no_complete_run! no_successes! ran_all_tests!)))))) )) (def .public dummy_target "YOLO") (def coverage /.Test (all /.and (do random.monad [not_covering (/.test "" true) covering (/.covering .._ (/.test "" true))] (in (do async.monad [[not_covering _] not_covering [covering _] covering] (unit.coverage [/.covering] (and (and (set.empty? (the tally.#expected not_covering)) (set.empty? (the tally.#actual not_covering))) (and (not (set.empty? (the tally.#expected covering))) (set.empty? (the tally.#actual covering)))))))) (do random.monad [not_covering (/.covering .._ (/.test "" true)) covering (/.covering .._ (/.coverage [..dummy_target] true))] (in (do async.monad [[not_covering _] not_covering [covering _] covering] (unit.coverage [/.coverage] (and (and (not (set.empty? (the tally.#expected not_covering))) (not (set.member? (the tally.#actual not_covering) (symbol ..dummy_target)))) (and (not (set.empty? (the tally.#expected covering))) (set.member? (the tally.#actual covering) (symbol ..dummy_target)))))))) (do random.monad [not_covering (/.covering .._ (/.test "" true)) covering (/.covering .._ (in (unit.coverage [..dummy_target] true)))] (in (do async.monad [[not_covering _] not_covering [covering _] covering] (unit.coverage [unit.coverage] (and (and (not (set.empty? (the tally.#expected not_covering))) (not (set.member? (the tally.#actual not_covering) (symbol ..dummy_target)))) (and (not (set.empty? (the tally.#expected covering))) (set.member? (the tally.#actual covering) (symbol ..dummy_target)))))))) (do random.monad [not_covering (/.covering .._ (/.test "" true)) covering (/.covering .._ (/.for [..dummy_target] (/.test "" true)))] (in (do async.monad [[not_covering _] not_covering [covering _] covering] (unit.coverage [/.for] (and (and (not (set.empty? (the tally.#expected not_covering))) (not (set.member? (the tally.#actual not_covering) (symbol ..dummy_target)))) (and (not (set.empty? (the tally.#expected covering))) (set.member? (the tally.#actual covering) (symbol ..dummy_target)))))))) )) (def .public test /.Test (<| (/.covering /._) (/.for [/.Test]) (do [! random.monad] [expected_context (random.lower_case 5) expected_message/0 (random.only (|>> (text#= expected_context) not) (random.lower_case 5)) expected_message/1 (random.only (|>> (text#= expected_message/0) not) (random.lower_case 5))] (all /.and (/.for [unit.Test] ..unit_test) (/.for [/.Seed] seed) (do ! [success_unit_test (/.test expected_message/0 true) failure_unit_test (/.test expected_message/0 false)] (in (do async.monad [[success_tally success_message] success_unit_test [failure_tally failure_message] failure_unit_test] (unit.coverage [/.test] (and (text.ends_with? (%.text expected_message/0) success_message) (text.ends_with? (%.text expected_message/0) failure_message) (and (n.= 1 (the tally.#successes success_tally)) (n.= 0 (the tally.#failures success_tally))) (and (n.= 0 (the tally.#successes failure_tally)) (n.= 1 (the tally.#failures failure_tally)))))))) (do ! [tt (/.and (/.test expected_message/0 true) (/.test expected_message/1 true)) ff (/.and (/.test expected_message/0 false) (/.test expected_message/1 false)) tf (/.and (/.test expected_message/0 true) (/.test expected_message/1 false)) ft (/.and (/.test expected_message/0 false) (/.test expected_message/1 true))] (in (do async.monad [tt tt ff ff tf tf ft ft] (unit.coverage [/.and] (and (..verify expected_message/0 expected_message/1 2 0 tt) (..verify expected_message/0 expected_message/1 0 2 ff) (..verify expected_message/0 expected_message/1 1 1 tf) (..verify expected_message/0 expected_message/1 1 1 ft)))))) (do ! [success_unit_test (/.context expected_context (/.test expected_message/0 true)) failure_unit_test (/.context expected_context (/.test expected_message/0 false))] (in (do async.monad [[success_tally success_message] success_unit_test [failure_tally failure_message] failure_unit_test] (unit.coverage [/.context] (and (and (text.contains? expected_context success_message) (text.contains? expected_message/0 success_message)) (and (text.contains? expected_context failure_message) (text.contains? expected_message/0 failure_message)) (and (n.= 1 (the tally.#successes success_tally)) (n.= 0 (the tally.#failures success_tally))) (and (n.= 0 (the tally.#successes failure_tally)) (n.= 1 (the tally.#failures failure_tally)))))))) (do ! [failure_unit_test (/.failure expected_message/0)] (in (do async.monad [[failure_tally failure_message] failure_unit_test] (unit.coverage [/.failure] (and (text.contains? expected_message/0 failure_message) (and (n.= 0 (the tally.#successes failure_tally)) (n.= 1 (the tally.#failures failure_tally)))))))) (do ! [success_unit_test (/.lifted expected_message/0 (in true)) failure_unit_test (/.lifted expected_message/0 (in false))] (in (do async.monad [[success_tally success_message] success_unit_test [failure_tally failure_message] failure_unit_test] (unit.coverage [/.lifted] (and (text.contains? expected_message/0 success_message) (text.contains? expected_message/0 failure_message) (and (n.= 1 (the tally.#successes success_tally)) (n.= 0 (the tally.#failures success_tally))) (and (n.= 0 (the tally.#successes failure_tally)) (n.= 1 (the tally.#failures failure_tally)))))))) ..times ..in_parallel ..coverage ))))