From f6a2fe158979230dcf2d271981ff34be39c7bffc Mon Sep 17 00:00:00 2001 From: Eduardo Julian Date: Mon, 20 Apr 2020 23:56:15 -0400 Subject: Added some testing machinery to measure the code coverage of tests. --- stdlib/source/lux.lux | 36 +++--- stdlib/source/lux/host.jvm.lux | 21 ++-- stdlib/source/lux/host.old.lux | 21 ++-- stdlib/source/lux/macro.lux | 65 ++++++++--- stdlib/source/lux/test.lux | 180 +++++++++++++++++++++++------- stdlib/source/lux/type/abstract.lux | 50 ++++----- stdlib/source/lux/type/implicit.lux | 30 ++--- stdlib/source/test/lux/abstract/apply.lux | 65 ++++++----- stdlib/source/test/lux/control/state.lux | 111 +++++++++--------- stdlib/source/test/lux/control/thread.lux | 75 +++++++++---- 10 files changed, 401 insertions(+), 253 deletions(-) (limited to 'stdlib') diff --git a/stdlib/source/lux.lux b/stdlib/source/lux.lux index c33f025ea..265b8e979 100644 --- a/stdlib/source/lux.lux +++ b/stdlib/source/lux.lux @@ -1456,16 +1456,6 @@ ys} xs)) -(def:''' #export (splice-helper xs ys) - #Nil - (-> ($' List Code) ($' List Code) ($' List Code)) - ({(#Cons x xs') - (#Cons x (splice-helper xs' ys)) - - #Nil - ys} - xs)) - (def:''' (_$_joiner op a1 a2) #Nil (-> Code Code Code Code) @@ -1752,6 +1742,14 @@ (#Left ($_ text@compose "Unknown module: " module " @ " (name@encode full-name)))} (get module modules)))) +(def:''' (as-code-list expression) + #Nil + (-> Code Code) + (let' [type (form$ (list (tag$ ["lux" "Apply"]) + (identifier$ ["lux" "Code"]) + (identifier$ ["lux" "List"])))] + (form$ (list (text$ "lux check") type expression)))) + (def:''' (splice replace? untemplate elems) #Nil (-> Bit (-> Code ($' Meta Code)) ($' List Code) ($' Meta Code)) @@ -1762,21 +1760,21 @@ (#Cons lastI inits) (do meta-monad [lastO ({[_ (#Form (#Cons [[_ (#Identifier ["" "~+"])] (#Cons [spliced #Nil])]))] - (let' [[[_module-name _ _] _] spliced] - (wrap spliced)) + (wrap (as-code-list spliced)) _ (do meta-monad [lastO (untemplate lastI)] - (wrap (form$ (list (tag$ ["lux" "Cons"]) (tuple$ (list lastO (tag$ ["lux" "Nil"])))))))} + (wrap (as-code-list (form$ (list (tag$ ["lux" "Cons"]) + (tuple$ (list lastO (tag$ ["lux" "Nil"]))))))))} lastI)] (monad@fold meta-monad (function' [leftI rightO] ({[_ (#Form (#Cons [[_ (#Identifier ["" "~+"])] (#Cons [spliced #Nil])]))] - (let' [[[_module-name _ _] _] spliced] - (wrap (form$ (list (identifier$ ["lux" "splice-helper"]) - spliced - rightO)))) + (let' [g!in-module (form$ (list (text$ "lux in-module") + (text$ "lux") + (identifier$ ["lux" "list@compose"])))] + (wrap (form$ (list g!in-module (as-code-list spliced) rightO)))) _ (do meta-monad @@ -1847,7 +1845,9 @@ (return (wrap-meta (form$ (list (tag$ ["lux" "Identifier"]) (tuple$ (list (text$ module) (text$ name))))))) [#1 [_ (#Form (#Cons [[_ (#Identifier ["" "~"])] (#Cons [unquoted #Nil])]))]] - (return unquoted) + (return (form$ (list (text$ "lux check") + (identifier$ ["lux" "Code"]) + unquoted))) [#1 [_ (#Form (#Cons [[_ (#Identifier ["" "~!"])] (#Cons [dependent #Nil])]))]] (do meta-monad diff --git a/stdlib/source/lux/host.jvm.lux b/stdlib/source/lux/host.jvm.lux index dad69604e..1fb112a48 100644 --- a/stdlib/source/lux/host.jvm.lux +++ b/stdlib/source/lux/host.jvm.lux @@ -405,19 +405,14 @@ (do macro.monad [current-module macro.current-module-name definitions (macro.definitions current-module)] - (wrap (list@fold (: (-> [Text Global] Context Context) - (function (_ [short-name constant] imports) - (case constant - (#.Left _) - imports - - (#.Right [_ _ meta _]) - (case (macro.get-text-ann (name-of #..jvm-class) meta) - (#.Some full-class-name) - (add-import [short-name full-class-name] imports) - - _ - imports)))) + (wrap (list@fold (: (-> [Text Definition] Context Context) + (function (_ [short-name [_ _ meta _]] imports) + (case (macro.get-text-ann (name-of #..jvm-class) meta) + (#.Some full-class-name) + (add-import [short-name full-class-name] imports) + + _ + imports))) ..fresh definitions))))) (#.Left _) (list) diff --git a/stdlib/source/lux/host.old.lux b/stdlib/source/lux/host.old.lux index e5a5b3624..2b62b01b0 100644 --- a/stdlib/source/lux/host.old.lux +++ b/stdlib/source/lux/host.old.lux @@ -369,19 +369,14 @@ (do macro.monad [current-module macro.current-module-name definitions (macro.definitions current-module)] - (wrap (list@fold (: (-> [Text Global] Class-Imports Class-Imports) - (function (_ [short-name constant] imports) - (case constant - (#.Left _) - imports - - (#.Right [_ _ meta _]) - (case (macro.get-text-ann (name-of #..jvm-class) meta) - (#.Some full-class-name) - (add-import [short-name full-class-name] imports) - - _ - imports)))) + (wrap (list@fold (: (-> [Text Definition] Class-Imports Class-Imports) + (function (_ [short-name [_ _ meta _]] imports) + (case (macro.get-text-ann (name-of #..jvm-class) meta) + (#.Some full-class-name) + (add-import [short-name full-class-name] imports) + + _ + imports))) empty-imports definitions))))) (#.Left _) diff --git a/stdlib/source/lux/macro.lux b/stdlib/source/lux/macro.lux index 4843b1fc2..bd8beac14 100644 --- a/stdlib/source/lux/macro.lux +++ b/stdlib/source/lux/macro.lux @@ -22,7 +22,9 @@ ## (type: (Meta a) ## (-> Lux (Try [Lux a]))) -(structure: #export functor (Functor Meta) +(structure: #export functor + (Functor Meta) + (def: (map f fa) (function (_ compiler) (case (fa compiler) @@ -32,7 +34,9 @@ (#try.Success [compiler' a]) (#try.Success [compiler' (f a)]))))) -(structure: #export apply (Apply Meta) +(structure: #export apply + (Apply Meta) + (def: &functor ..functor) (def: (apply ff fa) @@ -49,7 +53,9 @@ (#try.Failure msg) (#try.Failure msg))))) -(structure: #export monad (Monad Meta) +(structure: #export monad + (Monad Meta) + (def: &functor ..functor) (def: (wrap x) @@ -525,6 +531,23 @@ "") " All Known modules: " (|> compiler (get@ #.modules) (list@map product.left) (text.join-with separator)) text.new-line))))))) +(def: #export (find-export name) + {#.doc "Looks-up a definition's type in the available modules (including the current one)."} + (-> Name (Meta Definition)) + (do ..monad + [definition (..find-def name)] + (case definition + (#.Left de-aliased) + (fail ($_ text@compose + "Aliases are not considered exports: " + (name@encode name))) + + (#.Right definition) + (let [[exported? def-type def-data def-value] definition] + (if exported? + (wrap definition) + (fail ($_ text@compose "Definition is not an export: " (name@encode name)))))))) + (def: #export (find-def-type name) {#.doc "Looks-up a definition's type in the available modules (including the current one)."} (-> Name (Meta Type)) @@ -562,32 +585,40 @@ (#.Right [exported? def-type def-data def-value]) (wrap (:coerce Type def-value))))) -(def: #export (definitions module-name) - {#.doc "The entire list of definitions in a module (including the non-exported/private ones)."} +(def: #export (globals module) + {#.doc "The entire list of globals in a module (including the non-exported/private ones)."} (-> Text (Meta (List [Text Global]))) (function (_ compiler) - (case (get module-name (get@ #.modules compiler)) + (case (get module (get@ #.modules compiler)) #.None - (#try.Failure ($_ text@compose "Unknown module: " module-name)) + (#try.Failure ($_ text@compose "Unknown module: " module)) (#.Some module) (#try.Success [compiler (get@ #.definitions module)])))) +(def: #export (definitions module) + {#.doc "The entire list of definitions in a module (including the non-exported/private ones)."} + (-> Text (Meta (List [Text Definition]))) + (:: ..monad map + (list.search-all (function (_ [name global]) + (case global + (#.Left de-aliased) + #.None + + (#.Right definition) + (#.Some [name definition])))) + (..globals module))) + (def: #export (exports module-name) {#.doc "All the exported definitions in a module."} (-> Text (Meta (List [Text Definition]))) (do ..monad - [constants (definitions module-name)] + [constants (..definitions module-name)] (wrap (do list.monad - [[name definition] constants] - (case definition - (#.Left _) - (list) - - (#.Right [exported? def-type def-data def-value]) - (if exported? - (wrap [name [exported? def-type def-data def-value]]) - (list))))))) + [[name [exported? def-type def-data def-value]] constants] + (if exported? + (wrap [name [exported? def-type def-data def-value]]) + (list)))))) (def: #export modules {#.doc "All the available modules (including the current one)."} diff --git a/stdlib/source/lux/test.lux b/stdlib/source/lux/test.lux index d36ff8059..cca7205fd 100644 --- a/stdlib/source/lux/test.lux +++ b/stdlib/source/lux/test.lux @@ -3,37 +3,52 @@ [abstract ["." monad (#+ Monad do)]] [control - ["ex" exception (#+ exception:)] + ["." exception (#+ exception:)] ["." io] [concurrency - ["." promise (#+ Promise) ("#;." monad)]]] + ["." promise (#+ Promise) ("#@." monad)]] + ["<>" parser + ["" code]]] [data ["." product] + ["." name] [number ["n" nat]] ["." text ["%" format (#+ format)]] [collection - ["." list ("#;." functor)]]] + ["." list ("#@." functor)] + ["." set (#+ Set)]]] [time ["." instant] - ["." duration]] + ["." duration (#+ Duration)]] [math - ["r" random (#+ Random) ("#;." monad)]]]) + ["." random (#+ Random) ("#@." monad)]] + ["." macro + [syntax (#+ syntax:)] + ["." code]]]) (type: #export Counters {#successes Nat - #failures Nat}) + #failures Nat + #expected-coverage (Set Name) + #actual-coverage (Set Name)}) (def: (add-counters parameter subject) (-> Counters Counters Counters) {#successes (n.+ (get@ #successes parameter) (get@ #successes subject)) - #failures (n.+ (get@ #failures parameter) (get@ #failures subject))}) + #failures (n.+ (get@ #failures parameter) (get@ #failures subject)) + #expected-coverage (set.union (get@ #expected-coverage parameter) + (get@ #expected-coverage subject)) + #actual-coverage (set.union (get@ #actual-coverage parameter) + (get@ #actual-coverage subject))}) (def: start Counters {#successes 0 - #failures 0}) + #failures 0 + #expected-coverage (set.new name.hash) + #actual-coverage (set.new name.hash)}) (template [ ] [(def: Counters (update@ .inc start))] @@ -42,15 +57,18 @@ [failure #failures] ) +(type: #export Assertion + (Promise [Counters Text])) + (type: #export Test - (Random (Promise [Counters Text]))) + (Random Assertion)) (def: separator text.new-line) (def: #export (and left right) {#.doc "Sequencing combinator."} (-> Test Test Test) - (do r.monad + (do random.monad [left left right right] (wrap (do promise.monad @@ -63,12 +81,12 @@ (def: #export (context description) (-> Text Test Test) - (r;map (promise;map (function (_ [counters documentation]) - [counters (|> documentation - (text.split-all-with ..separator) - (list;map (|>> (format context-prefix))) - (text.join-with ..separator) - (format description ..separator))])))) + (random@map (promise@map (function (_ [counters documentation]) + [counters (|> documentation + (text.split-all-with ..separator) + (list@map (|>> (format context-prefix))) + (text.join-with ..separator) + (format description ..separator))])))) (def: failure-prefix "[Failure] ") (def: success-prefix "[Success] ") @@ -77,13 +95,13 @@ (-> Text Test) (|>> (format ..failure-prefix) [failure] - promise;wrap - r;wrap)) + promise@wrap + random@wrap)) (def: #export (assert message condition) {#.doc "Check that a condition is #1, and fail with the given message otherwise."} - (-> Text Bit (Promise [Counters Text])) - (<| promise;wrap + (-> Text Bit Assertion) + (<| promise@wrap (if condition [success (format ..success-prefix message)] [failure (format ..failure-prefix message)]))) @@ -91,11 +109,11 @@ (def: #export (test message condition) {#.doc "Check that a condition is #1, and fail with the given message otherwise."} (-> Text Bit Test) - (:: r.monad wrap (assert message condition))) + (:: random.monad wrap (assert message condition))) (def: #export (lift message random) (-> Text (Random Bit) Test) - (:: r.monad map (..assert message) random)) + (:: random.monad map (..assert message) random)) (def: pcg-32-magic-inc Nat 12345) @@ -106,13 +124,13 @@ (def: #export (seed value test) (-> Seed Test Test) (function (_ prng) - (let [[_ result] (r.run (r.pcg-32 [..pcg-32-magic-inc value]) - test)] + (let [[_ result] (random.run (random.pcg-32 [..pcg-32-magic-inc value]) + test)] [prng result]))) (def: failed? (-> Counters Bit) - (|>> product.right (n.> 0))) + (|>> (get@ #failures) (n.> 0))) (def: (times-failure seed documentation) (-> Seed Text Text) @@ -124,29 +142,37 @@ (def: #export (times amount test) (-> Nat Test Test) (cond (n.= 0 amount) - (fail (ex.construct must-try-test-at-least-once [])) + (fail (exception.construct must-try-test-at-least-once [])) (n.= 1 amount) test ## else - (do r.monad - [seed r.nat] + (do random.monad + [seed random.nat] (function (_ prng) - (let [[prng' instance] (r.run (r.pcg-32 [..pcg-32-magic-inc seed]) test)] + (let [[prng' instance] (random.run (random.pcg-32 [..pcg-32-magic-inc seed]) test)] [prng' (do promise.monad [[counters documentation] instance] (if (failed? counters) (wrap [counters (times-failure seed documentation)]) - (product.right (r.run prng' (times (dec amount) test)))))]))))) + (product.right (random.run prng' (times (dec amount) test)))))]))))) -(def: (tally counters) - (-> Counters Text) +(def: (tally duration counters) + (-> Duration Counters Text) (let [successes (get@ #successes counters) - failures (get@ #failures counters)] - (ex.report ["Tests" (%.nat (n.+ successes failures))] - ["Successes" (%.nat successes)] - ["Failures" (%.nat failures)]))) + failures (get@ #failures counters) + missing-coverage (set.difference (get@ #actual-coverage counters) + (get@ #expected-coverage counters)) + unexpected-coverage (set.difference (get@ #expected-coverage counters) + (get@ #actual-coverage counters))] + (exception.report + ["Duration" (%.duration duration)] + ["Tests" (%.nat (n.+ successes failures))] + ["Successes" (%.nat successes)] + ["Failures" (%.nat failures)] + ["Missing Coverage" (|> missing-coverage set.to-list (exception.enumerate %.name))] + ["Unexpected Coverage" (|> unexpected-coverage set.to-list (exception.enumerate %.name))]))) (def: failure-exit-code -1) (def: success-exit-code +0) @@ -156,13 +182,87 @@ (do promise.monad [pre (promise.future instant.now) #let [seed (instant.to-millis pre) - prng (r.pcg-32 [..pcg-32-magic-inc seed])] - [counters documentation] (|> test (r.run prng) product.right) + prng (random.pcg-32 [..pcg-32-magic-inc seed])] + [counters documentation] (|> test (random.run prng) product.right) post (promise.future instant.now) #let [duration (instant.span pre post) _ (log! (format documentation text.new-line text.new-line - "(" (%.duration duration) ")" text.new-line - (tally counters)))]] + (tally duration counters) + text.new-line))]] (promise.future (io.exit (case (get@ #failures counters) 0 ..success-exit-code _ ..failure-exit-code))))) + +(def: (cover' coverage condition) + (-> (List Name) Bit Test) + (let [message (|> coverage + (list@map %.name) + (text.join-with " & ")) + coverage (set.from-list name.hash coverage)] + (|> (..assert message condition) + (promise@map (function (_ [counters documentation]) + [(update@ #actual-coverage (set.union coverage) counters) + documentation])) + (:: random.monad wrap)))) + +(def: (with-cover' coverage test) + (-> (List Name) Test Test) + (let [context (|> coverage + (list@map %.name) + (text.join-with " & ")) + coverage (set.from-list name.hash coverage)] + (random@map (promise@map (function (_ [counters documentation]) + [(update@ #actual-coverage (set.union coverage) counters) + documentation])) + (..context context test)))) + +(def: (name-code name) + (-> Name Code) + (code.tuple (list (code.text (name.module name)) + (code.text (name.short name))))) + +(syntax: (reference {name .identifier}) + (do @ + [_ (macro.find-export name)] + (wrap (list (name-code name))))) + +(syntax: #export (cover {coverage (.tuple (<>.many .any))} + condition) + (let [coverage (list@map (function (_ definition) + (` ((~! ..reference) (~ definition)))) + coverage)] + (wrap (list (` ((~! ..cover') + (: (.List .Name) + (.list (~+ coverage))) + (~ condition))))))) + +(syntax: #export (with-cover {coverage (.tuple (<>.many .any))} + test) + (let [coverage (list@map (function (_ definition) + (` ((~! ..reference) (~ definition)))) + coverage)] + (wrap (list (` ((~! ..with-cover') + (: (.List .Name) + (.list (~+ coverage))) + (~ test))))))) + +(def: (covering' module coverage test) + (-> Text (List Name) Test Test) + (let [coverage (set.from-list name.hash coverage)] + (|> (..context module test) + (random@map (promise@map (function (_ [counters documentation]) + [(update@ #expected-coverage (set.union coverage) counters) + documentation])))))) + +(syntax: #export (covering {module .identifier} + test) + (do @ + [#let [module (name.module module)] + definitions (macro.definitions module) + #let [coverage (|> definitions + (list.filter (|>> product.right product.left)) + (list@map (|>> product.left [module] ..name-code)))]] + (wrap (list (` ((~! ..covering') + (~ (code.text module)) + (.list (~+ coverage)) + (~ test))))))) diff --git a/stdlib/source/lux/type/abstract.lux b/stdlib/source/lux/type/abstract.lux index 70b742236..aa00fa4fd 100644 --- a/stdlib/source/lux/type/abstract.lux +++ b/stdlib/source/lux/type/abstract.lux @@ -4,15 +4,15 @@ [monad (#+ Monad do)]] [control ["ex" exception (#+ exception:)] - ["p" parser ("#;." monad) - ["s" code (#+ Parser)]]] + ["<>" parser ("#@." monad) + ["" code (#+ Parser)]]] [data - ["." name ("#;." codec)] - ["." text ("#;." equivalence monoid)] + ["." name ("#@." codec)] + ["." text ("#@." equivalence monoid)] [collection - ["." list ("#;." functor monoid)] + ["." list ("#@." functor monoid)] ["." stack (#+ Stack)]]] - ["." macro ("#;." monad) + ["." macro ("#@." monad) ["." code] [syntax (#+ syntax:) ["cs" common @@ -34,7 +34,7 @@ (loop [entries ] (case entries (#.Cons [head-name head] tail) - (if (text;= head-name) + (if (text@= head-name) (recur tail)) @@ -67,7 +67,7 @@ (case (case scope (#.Some scope) (list.find (function (_ [actual _]) - (text;= scope actual)) + (text@= scope actual)) current-scopes) #.None @@ -82,7 +82,7 @@ (loop [entries ] (case entries (#.Cons [head-name head] tail) - (if (text;= head-name) + (if (text@= head-name) (#.Cons [head-name ] tail) (#.Cons [head-name head] @@ -150,8 +150,8 @@ (def: cast (Parser [(Maybe Text) Code]) - (p.either (p.and (p.maybe s.local-identifier) s.any) - (p.and (p;wrap #.None) s.any))) + (<>.either (<>.and (<>.maybe .local-identifier) .any) + (<>.and (<>@wrap #.None) .any))) (template [ ] [(syntax: #export ( {[scope value] cast}) @@ -166,33 +166,33 @@ (def: abstraction-type-name (-> Name Text) - (|>> name;encode - ($_ text;compose - (name;encode (name-of #..Abstraction)) + (|>> name@encode + ($_ text@compose + (name@encode (name-of #..Abstraction)) " "))) (def: representation-definition-name (-> Text Text) - (|>> ($_ text;compose - (name;encode (name-of #Representation)) + (|>> ($_ text@compose + (name@encode (name-of #Representation)) " "))) (def: declaration (Parser [Text (List Text)]) - (p.either (s.form (p.and s.local-identifier (p.some s.local-identifier))) - (p.and s.local-identifier (:: p.monad wrap (list))))) + (<>.either (.form (<>.and .local-identifier (<>.some .local-identifier))) + (<>.and .local-identifier (:: <>.monad wrap (list))))) ## TODO: Make sure the generated code always gets optimized away. ## (This applies to uses of ":abstraction" and ":representation") (syntax: #export (abstract: {export csr.export} {[name type-vars] declaration} - {annotations (p.default cs.empty-annotations csr.annotations)} + {annotations (<>.default cs.empty-annotations csr.annotations)} representation-type - {primitives (p.some s.any)}) + {primitives (<>.some .any)}) (do @ [current-module macro.current-module-name - #let [type-varsC (list;map code.local-identifier type-vars) + #let [type-varsC (list@map code.local-identifier type-vars) abstraction-declaration (` ((~ (code.local-identifier name)) (~+ type-varsC))) representation-declaration (` ((~ (code.local-identifier (representation-definition-name name))) (~+ type-varsC)))] @@ -204,18 +204,18 @@ (~ (csw.annotations annotations)) (primitive (~ (code.text (abstraction-type-name [current-module name]))) [(~+ type-varsC)]))) - (` (type: (~+ (csw.export export)) (~ representation-declaration) + (` (type: (~ representation-declaration) (~ representation-type))) - ($_ list;compose + ($_ list@compose primitives (list (` ((~! ..pop!))))))))) (syntax: #export (:transmutation value) (wrap (list (` (..:abstraction (..:representation (~ value))))))) -(syntax: #export (^:representation {name (s.form s.local-identifier)} +(syntax: #export (^:representation {name (.form .local-identifier)} body - {branches (p.some s.any)}) + {branches (<>.some .any)}) (let [g!var (code.local-identifier name)] (wrap (list& g!var (` (.let [(~ g!var) (..:representation (~ g!var))] diff --git a/stdlib/source/lux/type/implicit.lux b/stdlib/source/lux/type/implicit.lux index 55583e45f..1e55c2ab1 100644 --- a/stdlib/source/lux/type/implicit.lux +++ b/stdlib/source/lux/type/implicit.lux @@ -114,19 +114,14 @@ (wrap [idx sig-type]))) (def: (prepare-definitions source-module target-module constants) - (-> Text Text (List [Text Global]) (List [Name Type])) + (-> Text Text (List [Text Definition]) (List [Name Type])) (do list.monad - [[name constant] constants] - (case constant - (#.Left _) - (list) - - (#.Right [exported? def-type def-anns def-value]) - (if (and (macro.structure? def-anns) - (or (text@= target-module source-module) - exported?)) - (list [[source-module name] def-type]) - (list))))) + [[name [exported? def-type def-anns def-value]] constants] + (if (and (macro.structure? def-anns) + (or (text@= target-module source-module) + exported?)) + (list [[source-module name] def-type]) + (list)))) (def: local-env (Meta (List [Name Type])) @@ -144,9 +139,9 @@ (def: local-structs (Meta (List [Name Type])) (do macro.monad - [this-module-name macro.current-module-name - definitions (macro.definitions this-module-name)] - (wrap (prepare-definitions this-module-name this-module-name definitions)))) + [this-module-name macro.current-module-name] + (:: @ map (prepare-definitions this-module-name this-module-name) + (macro.definitions this-module-name)))) (def: import-structs (Meta (List [Name Type])) @@ -154,9 +149,8 @@ [this-module-name macro.current-module-name imp-mods (macro.imported-modules this-module-name) export-batches (monad.map @ (function (_ imp-mod) - (do @ - [exports (macro.definitions imp-mod)] - (wrap (prepare-definitions imp-mod this-module-name exports)))) + (:: @ map (prepare-definitions imp-mod this-module-name) + (macro.definitions imp-mod))) imp-mods)] (wrap (list@join export-batches)))) diff --git a/stdlib/source/test/lux/abstract/apply.lux b/stdlib/source/test/lux/abstract/apply.lux index 87c706f55..c53283233 100644 --- a/stdlib/source/test/lux/abstract/apply.lux +++ b/stdlib/source/test/lux/abstract/apply.lux @@ -3,72 +3,71 @@ [abstract/monad (#+ do)] [data [number - ["n" nat]] - [text - ["%" format (#+ format)]]] + ["n" nat]]] [control ["." function]] [math - ["r" random]] + ["." random]] ["_" test (#+ Test)]] {1 ["." / (#+ Apply)]} [// [functor (#+ Injection Comparison)]]) -(def: (identity injection comparison (^open "_;.")) +(def: (identity injection comparison (^open "_@.")) (All [f] (-> (Injection f) (Comparison f) (Apply f) Test)) - (do r.monad - [sample (:: @ map injection r.nat)] + (do random.monad + [sample (:: @ map injection random.nat)] (_.test "Identity." ((comparison n.=) - (_;apply (injection function.identity) sample) + (_@apply (injection function.identity) sample) sample)))) -(def: (homomorphism injection comparison (^open "_;.")) +(def: (homomorphism injection comparison (^open "_@.")) (All [f] (-> (Injection f) (Comparison f) (Apply f) Test)) - (do r.monad - [sample r.nat - increase (:: @ map n.+ r.nat)] + (do random.monad + [sample random.nat + increase (:: @ map n.+ random.nat)] (_.test "Homomorphism." ((comparison n.=) - (_;apply (injection increase) (injection sample)) + (_@apply (injection increase) (injection sample)) (injection (increase sample)))))) -(def: (interchange injection comparison (^open "_;.")) +(def: (interchange injection comparison (^open "_@.")) (All [f] (-> (Injection f) (Comparison f) (Apply f) Test)) - (do r.monad - [sample r.nat - increase (:: @ map n.+ r.nat)] + (do random.monad + [sample random.nat + increase (:: @ map n.+ random.nat)] (_.test "Interchange." ((comparison n.=) - (_;apply (injection increase) (injection sample)) - (_;apply (injection (function (_ f) (f sample))) (injection increase)))))) + (_@apply (injection increase) (injection sample)) + (_@apply (injection (function (_ f) (f sample))) (injection increase)))))) -(def: (composition injection comparison (^open "_;.")) +(def: (composition injection comparison (^open "_@.")) (All [f] (-> (Injection f) (Comparison f) (Apply f) Test)) - (do r.monad - [sample r.nat - increase (:: @ map n.+ r.nat) - decrease (:: @ map n.- r.nat)] + (do random.monad + [sample random.nat + increase (:: @ map n.+ random.nat) + decrease (:: @ map n.- random.nat)] (_.test "Composition." ((comparison n.=) - (_$ _;apply + (_$ _@apply (injection function.compose) (injection increase) (injection decrease) (injection sample)) - ($_ _;apply + ($_ _@apply (injection increase) (injection decrease) (injection sample)))))) (def: #export (spec injection comparison apply) (All [f] (-> (Injection f) (Comparison f) (Apply f) Test)) - (_.context (%.name (name-of /.Apply)) - ($_ _.and - (..identity injection comparison apply) - (..homomorphism injection comparison apply) - (..interchange injection comparison apply) - (..composition injection comparison apply) - ))) + (<| (_.covering /._) + (_.with-cover [/.Apply] + ($_ _.and + (..identity injection comparison apply) + (..homomorphism injection comparison apply) + (..interchange injection comparison apply) + (..composition injection comparison apply) + )))) diff --git a/stdlib/source/test/lux/control/state.lux b/stdlib/source/test/lux/control/state.lux index 1d9899539..cb7c94b83 100644 --- a/stdlib/source/test/lux/control/state.lux +++ b/stdlib/source/test/lux/control/state.lux @@ -34,26 +34,26 @@ [state r.nat value r.nat] ($_ _.and - (_.test "Can get the state as a value." - (with-conditions [state state] - /.get)) - (_.test "Can replace the state." - (with-conditions [state value] - (do /.monad - [_ (/.put value)] - /.get))) - (_.test "Can update the state." - (with-conditions [state (n.* value state)] - (do /.monad - [_ (/.update (n.* value))] - /.get))) - (_.test "Can use the state." - (with-conditions [state (inc state)] - (/.use inc))) - (_.test "Can use a temporary (local) state." - (with-conditions [state (n.* value state)] - (/.local (n.* value) - /.get))) + (_.cover [/.State /.get] + (with-conditions [state state] + /.get)) + (_.cover [/.put] + (with-conditions [state value] + (do /.monad + [_ (/.put value)] + /.get))) + (_.cover [/.update] + (with-conditions [state (n.* value state)] + (do /.monad + [_ (/.update (n.* value))] + /.get))) + (_.cover [/.use] + (with-conditions [state (inc state)] + (/.use inc))) + (_.cover [/.local] + (with-conditions [state (n.* value state)] + (/.local (n.* value) + /.get))) ))) (def: (injection value) @@ -72,9 +72,12 @@ [state r.nat value r.nat] ($_ _.and - ($functor.spec ..injection (..comparison state) /.functor) - ($apply.spec ..injection (..comparison state) /.apply) - ($monad.spec ..injection (..comparison state) /.monad) + (_.with-cover [/.functor] + ($functor.spec ..injection (..comparison state) /.functor)) + (_.with-cover [/.apply] + ($apply.spec ..injection (..comparison state) /.apply)) + (_.with-cover [/.monad] + ($monad.spec ..injection (..comparison state) /.monad)) ))) (def: loops @@ -85,18 +88,18 @@ [state /.get] (wrap (n.< limit state)))]] ($_ _.and - (_.test "'while' will only execute if the condition is #1." - (|> (/.while condition (/.update inc)) - (/.run 0) - (let> [state' output'] - (n.= limit state')))) - (_.test "'do-while' will execute at least once." - (|> (/.do-while condition (/.update inc)) - (/.run 0) - (let> [state' output'] - (or (n.= limit state') - (and (n.= 0 limit) - (n.= 1 state')))))) + (_.cover [/.while /.run] + (|> (/.while condition (/.update inc)) + (/.run 0) + (let> [state' output'] + (n.= limit state')))) + (_.cover [/.do-while] + (|> (/.do-while condition (/.update inc)) + (/.run 0) + (let> [state' output'] + (or (n.= limit state') + (and (n.= 0 limit) + (n.= 1 state')))))) ))) (def: monad-transformer @@ -105,29 +108,25 @@ [state r.nat left r.nat right r.nat] - (let [(^open "io;.") io.monad] - (_.test "Can add state functionality to any monad." - (|> (: (/.State' io.IO Nat Nat) - (do (/.with io.monad) - [a (/.lift io.monad (io;wrap left)) - b (wrap right)] - (wrap (n.+ a b)))) - (/.run' state) - io.run - (let> [state' output'] - (and (n.= state state') - (n.= (n.+ left right) output'))))) + (let [(^open "io@.") io.monad] + (_.cover [/.State' /.with /.lift /.run'] + (|> (: (/.State' io.IO Nat Nat) + (do (/.with io.monad) + [a (/.lift io.monad (io@wrap left)) + b (wrap right)] + (wrap (n.+ a b)))) + (/.run' state) + io.run + (let> [state' output'] + (and (n.= state state') + (n.= (n.+ left right) output'))))) ))) (def: #export test Test - (<| (_.context (%.name (name-of /.State))) + (<| (_.covering /._) ($_ _.and - (<| (_.context "Basics.") - ..basics) - (<| (_.context "Structures.") - ..structures) - (<| (_.context "Loops.") - ..loops) - (<| (_.context "Monad transformer.") - ..monad-transformer)))) + ..basics + ..structures + ..loops + ..monad-transformer))) diff --git a/stdlib/source/test/lux/control/thread.lux b/stdlib/source/test/lux/control/thread.lux index 7d6ed0ceb..49e397d21 100644 --- a/stdlib/source/test/lux/control/thread.lux +++ b/stdlib/source/test/lux/control/thread.lux @@ -10,13 +10,13 @@ ["$." monad]]}] [data [number - ["n" nat]] - [text - ["%" format (#+ format)]]] + ["n" nat]]] [math - ["r" random]]] + ["." random]]] {1 - ["." / (#+ Thread)]}) + ["." / (#+ Thread) + [// + ["." io]]]}) (def: (injection value) (Injection (All [a !] (Thread ! a))) @@ -29,20 +29,55 @@ (def: #export test Test - (do r.monad - [original r.nat - factor r.nat] - (<| (_.context (%.name (name-of /.Thread))) + (do random.monad + [sample random.nat + factor random.nat] + (<| (_.covering /._) ($_ _.and - ($functor.spec ..injection ..comparison /.functor) - ($apply.spec ..injection ..comparison /.apply) - ($monad.spec ..injection ..comparison /.monad) - - (_.test "Can safely do mutation." - (n.= (n.* factor original) - (/.run (: (All [!] (Thread ! Nat)) - (do /.monad - [box (/.box original) - old (/.update (n.* factor) box)] - (/.read box)))))) + (_.with-cover [/.Thread] + ($_ _.and + (_.cover [/.run] + (n.= sample + (|> sample + (:: /.monad wrap) + /.run))) + (_.cover [/.io] + (n.= sample + (|> sample + (:: /.monad wrap) + /.io + io.run))) + + (_.with-cover [/.functor] + ($functor.spec ..injection ..comparison /.functor)) + (_.with-cover [/.apply] + ($apply.spec ..injection ..comparison /.apply)) + (_.with-cover [/.monad] + ($monad.spec ..injection ..comparison /.monad)) + )) + + (_.with-cover [/.Box /.box] + ($_ _.and + (_.cover [/.read] + (n.= sample + (/.run (: (All [!] (Thread ! Nat)) + (do /.monad + [box (/.box sample)] + (/.read box)))))) + + (_.cover [/.write] + (n.= factor + (/.run (: (All [!] (Thread ! Nat)) + (do /.monad + [box (/.box sample) + _ (/.write factor box)] + (/.read box)))))) + + (_.cover [/.update] + (n.= (n.* factor sample) + (/.run (: (All [!] (Thread ! Nat)) + (do /.monad + [box (/.box sample) + old (/.update (n.* factor) box)] + (/.read box)))))))) )))) -- cgit v1.2.3