From e457718a2b6c0a5f3fc256fce6a7b9b2428a3dcd Mon Sep 17 00:00:00 2001 From: "Quildreen \"Sorella\" Motta" Date: Sun, 21 Apr 2013 10:34:57 -0300 Subject: [PATCH] Better reporting for rejected properties. This helps with #20 and #15. As for the latter, I still don't know whether to provide special handling for assertion-based tests or not. --- src/check.ls | 53 +++++++++++++++++++------------------ src/property.ls | 70 +++++++++++++++++++++++++++++++++++-------------- 2 files changed, 78 insertions(+), 45 deletions(-) diff --git a/src/check.ls b/src/check.ls index 0ec417a..72339b0 100644 --- a/src/check.ls +++ b/src/check.ls @@ -84,11 +84,7 @@ with-defaults = (config = {}) -> ({} <<< default-config) <<< config # Retrieves a normalised Status tag for the Result. # # :: Result -> ResultStatus -status = (result) -> - | result.ok is true => \passed - | result.ok is false => \failed - | result.ok instanceof Error => \errored - | otherwise => \ignored +status = (result) -> result.kind or \rejected #### λ failed-p @@ -96,7 +92,7 @@ status = (result) -> # Checks if a Result failed. # # :: Result -> Bool -failed-p = (result) -> (status result) in <[ failed errored ]> +failed-p = (result) -> (status result) in <[ failed rejected ]> ### -- Helpers for presenting a Report --------------------------------- @@ -156,22 +152,27 @@ label-histogram = (report) -> # :: Report -> String describe-failures = (report) -> label = (as) -> - | as.length => ": The following labels were provided: #{JSON.stringify as}" + | as.length => "» The following labels were provided: #{JSON.stringify as}" | otherwise => '' - error-for = (a) -> - | a instanceof Error => ": Threw #{a.stack or a}\n" - | otherwise => '' + error-for = (kind, e) -> + | kind is \failed => "» Threw #{e?.stack or e}\n" + | otherwise => '' - arg = (a, n) -> " #n - #{a.value} (#{a.generator})" - + arg = (a, n) -> " #n - #{JSON.stringify a.value} (#{a.generator})" + + rejection-for = (kind, e) -> + if kind != \rejected => '' + else => "» Reason: #{JSON.stringify e.value}\n" + errors = report.failed.map (a, n) -> """ - : Failure \##{n + 1} -------------------- - #{label a.labels} - #{error-for a.ok} - : The following arguments were provided: - #{a.arguments.map arg .join '\n '} - """ + : Failure \##{n + 1} ----------------------------------------------------------- + #{rejection-for a.kind, a} + #{label a.labels} + #{error-for a.kind, a.value} + » The following arguments were provided: + #{a.arguments.map arg .join '\n '} + """ switch | errors.join '' .trim! => errors.join '\n---\n' | otherwise => '' @@ -225,10 +226,10 @@ Report = Base.derive { @all.push result result.labels.map (a) ~> @labels.[]"#a".push result switch status result - | \passed => @passed.push result - | \failed => @failed.push result - | \errored => @failed.push result - | \ignored => @ignored.push result + | \held => @passed.push result + | \failed => @failed.push result + | \rejected => @failed.push result + | \ignored => @ignored.push result ##### λ to-string # Provides a human-readable presentation of this Report. @@ -263,10 +264,10 @@ check = (max, property) --> report.add result switch status result - | \passed => --max - | \failed => should-run = false - | \errored => should-run = false - | \ignored => if ++ignored > 1000 => should-run = false + | \held => --max + | \rejected => should-run = false + | \failed => should-run = false + | \ignored => if ++ignored > 1000 => should-run = false report.verdict = | ignored > 1000 => \abandoned | max > 0 => \failed diff --git a/src/property.ls b/src/property.ls index 03db4e1..d4b2c81 100644 --- a/src/property.ls +++ b/src/property.ls @@ -33,6 +33,49 @@ ### -- Aliases --------------------------------------------------------- frozen = Object.freeze + +### -- Property result types ------------------------------------------- + +#### λ make-result +# Constructs a Result object. +# +# :: String -> [a] -> [String] -> Maybe Bool -> Result +make-result = (kind, value, args, labels) --> + kind : kind + value : value + labels : labels + arguments : args + + +#### λ invalidate +# Invalidates the property for the given arguments (they're not valid). +# +# :: [a] -> Result +invalidate = (args) --> + make-result \ignored, null, args, [] + + +#### λ hold +# Constructs a Result for a successful property. +# +# :: [a] -> [String] -> Result +hold = make-result \held, true + + +#### λ reject +# Rejects the property with the given reason. +# +# :: [a] -> [String] -> Result +reject = make-result \rejected + + +#### λ fail +# Constructs a Result for a failed property (one that errored out). +# +# :: [a] -> [String] -> Result +fail = make-result \failed + + ### -- Helpers --------------------------------------------------------- #### λ values @@ -57,34 +100,23 @@ classify = (args, prop) --> #### λ verify # Verifies if the property's invariant's hold for the arguments. -# :: [a] -> Property -> Bool -verify = (args, prop) --> +# :: [a] -> [String] -> Property -> Bool +verify = (args, labels, prop) --> try - !!(prop.invariant ...(values args)) + result = prop.invariant ...(values args) + if result is true => hold args, labels + else => reject result, args, labels catch e - e - -#### λ invalidate -# Invalidates the property for the given arguments (they're not valid). -# :: [a] -> Property -> Result -invalidate = (args, prop) --> - make-result args, [], null + fail e, args, labels #### λ apply-property # Applies a property to some arguments. # :: [a] -> Property -> Result apply-property = (args, prop) --> - | valid-p args, prop => make-result args, (classify args, prop), (verify args, prop) - | otherwise => invalidate args, prop + | valid-p args, prop => verify args, (classify args, prop), prop + | otherwise => invalidate args -#### λ make-result -# Constructs a Result object. -# :: [a] -> [String] -> Maybe Bool -> Result -make-result = (args, labels, ok) --> - ok : ok - labels : labels - arguments : args ### -- Core implementation ---------------------------------------------