Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 24 additions & 12 deletions assertions.dylan
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,15 @@ Warranty: Distributed WITHOUT WARRANTY OF ANY KIND

define constant $invalid-description = "*** invalid description ***";

// This is used to do a non-local exit to the end of a test and skip remaining assertions.
define class <assertion-failure> (<condition>) end;
// This is used to do a non-local exit to the end of a test and skip remaining
// assertions. It's a subclass of <serious-condition> so that the debugger will be
// invoked if we don't handle it, e.g., for '--debug failures'.
define class <assertion-failure> (<simple-error>)
end class;

define method condition-to-string (c :: <assertion-failure>) => (s :: <string>)
apply(format-to-string, c.condition-format-string, c.condition-format-arguments)
end method;

/// Assertion macros

Expand Down Expand Up @@ -100,6 +107,10 @@ define macro expect-equal
terminate?: #f) }
end macro;

define function handle-assertion-condition? (c :: <condition>)
~instance?(c, <assertion-failure>) & handle-condition?(*runner*, c)
end function;

define function do-check-equal
(description-thunk :: <function>, arguments-thunk :: <function>, caller :: <string>,
#key terminate? :: <boolean>)
Expand Down Expand Up @@ -128,7 +139,7 @@ define function do-check-equal
want, *indent*, $indent-step, got, detail));
terminate? & signal(make(<assertion-failure>));
end;
exception (err :: <serious-condition>, test: method (cond) ~debug?() end)
exception (err :: <serious-condition>, test: handle-assertion-condition?)
record-check(description | $invalid-description,
$crashed,
format-to-string("Error %s: %s", phase, err));
Expand Down Expand Up @@ -183,7 +194,7 @@ define function do-check-not-equal
format-to-string("%= and %= are =.", val1, val2));
terminate? & signal(make(<assertion-failure>));
end;
exception (err :: <serious-condition>, test: method (cond) ~debug?() end)
exception (err :: <serious-condition>, test: handle-assertion-condition?)
record-check(description | $invalid-description,
$crashed,
format-to-string("Error %s: %s", phase, err));
Expand Down Expand Up @@ -324,7 +335,7 @@ define function do-check-instance?
description := eval-check-description(description-thunk);
phase := format-to-string("evaluating %s expressions", caller);
let (type :: <type>, value, value-expr :: <string>) = get-arguments();
phase := format-to-string("checking if expression %s is %=an instance of %s",
phase := format-to-string("checking if expression %s is %san instance of %s",
value-expr, if (negate?) "not " else "" end, type);
if (instance?(value, type) ~= negate?)
record-check(description, $passed, #f);
Expand All @@ -334,7 +345,7 @@ define function do-check-instance?
value, value-expr, type));
terminate? & signal(make(<assertion-failure>));
end;
exception (err :: <serious-condition>, test: method (cond) ~debug?() end)
exception (err :: <serious-condition>, test: handle-assertion-condition?)
record-check(description | $invalid-description,
$crashed,
format-to-string("Error %s: %s", phase, err));
Expand Down Expand Up @@ -381,7 +392,7 @@ define function do-check-true
format-to-string("expression %s is false.", value-expr));
terminate? & signal(make(<assertion-failure>));
end;
exception (err :: <serious-condition>, test: method (cond) ~debug?() end)
exception (err :: <serious-condition>, test: handle-assertion-condition?)
record-check(description | $invalid-description,
$crashed,
format-to-string("Error %s: %s", phase, err));
Expand Down Expand Up @@ -443,7 +454,7 @@ define function do-check-false
value-expr, value));
terminate? & signal(make(<assertion-failure>));
end;
exception (err :: <serious-condition>, test: method (cond) ~debug?() end)
exception (err :: <serious-condition>, test: handle-assertion-condition?)
record-check(description | $invalid-description,
$crashed,
format-to-string("Error %s: %s", phase, err));
Expand Down Expand Up @@ -515,17 +526,18 @@ define function do-check-condition
terminate? & signal(make(<assertion-failure>));
exception (ex :: condition-class)
record-check(description, $passed, #f);
// Not really sure if this should catch something broader, like
// <condition>, but leaving it this way for compat with old code.
exception (ex :: <serious-condition>)
exception (ex :: <condition>,
test: method (c)
~instance?(c, <assertion-failure>)
end)
record-check(description, $failed,
format-to-string("condition of class %s signaled; "
"expected a condition of class %s. "
"The error was: %s",
ex.object-class, condition-class, ex));
terminate? & signal(make(<assertion-failure>));
end;
exception (err :: <serious-condition>, test: method (cond) ~debug?() end)
exception (err :: <serious-condition>, test: handle-assertion-condition?)
record-check(description | $invalid-description,
$crashed,
format-to-string("Error %s: %s", phase, err));
Expand Down
13 changes: 7 additions & 6 deletions command-line.dylan
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,11 @@ define function parse-args
add-option(parser,
make(<choice-option>,
names: "debug",
choices: #("none", "crashes", "all"),
choices: #("none", "crashes", "failures", "all"),
default: "none",
variable: "WHAT",
help: "Enter the debugger? None, crashes, or all"
" (crashes and failures). [%default%]"));
help: "Enter the debugger? none, crashes, failures, or all."
" [%default%]"));
add-option(parser,
make(<choice-option>,
names: #("progress", "p"),
Expand Down Expand Up @@ -132,9 +132,10 @@ define function make-runner-from-command-line
get-option-value(parser, "run"),
get-option-value(parser, "skip"));
let debug = select (as-lowercase(get-option-value(parser, "debug")) by \=)
"none" => $debug-none;
"crashes" => $debug-crashes;
"all" => $debug-all;
"none" => $debug-none;
"crashes" => $debug-crashes;
"failures" => $debug-failures;
"all" => $debug-all;
end;
let progress = select (as-lowercase(get-option-value(parser, "progress")) by \=)
"none" => $progress-none;
Expand Down
11 changes: 7 additions & 4 deletions library.dylan
Original file line number Diff line number Diff line change
Expand Up @@ -139,9 +139,8 @@ define module %testworks
<debug-option>,
$debug-none,
$debug-crashes,
$debug-all,
debug-failures?,
debug?;
$debug-failures,
$debug-all;

// Components
export
Expand Down Expand Up @@ -238,6 +237,10 @@ define module %testworks

// Specs accessors
export spec-name,
spec-title;
spec-title;

// Conditions
export
<assertion-failure>;

end module %testworks;
46 changes: 31 additions & 15 deletions run.dylan
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,11 @@ define constant <progress-option>
= one-of($progress-none, $progress-minimal, $progress-all);

define constant $debug-none = #"debug-none";
define constant $debug-failures = #"debug-failures";
define constant $debug-crashes = #"debug-crashes";
define constant $debug-all = #"debug-all";
define constant <debug-option>
= one-of($debug-none, $debug-crashes, $debug-all);

define inline function debug-failures?
() => (debug-failures? :: <boolean>)
runner-debug(*runner*) == $debug-all
end function;

define inline function debug?
() => (debug? :: <boolean>)
runner-debug(*runner*) ~= $debug-none
end function;
= one-of($debug-none, $debug-crashes, $debug-failures, $debug-all);

define constant $source-order = #"source"; // order they appear in the source code.
define constant $lexical-order = #"lexical";
Expand Down Expand Up @@ -167,7 +158,8 @@ define method execute-component
skip-result := $skipped;
skip-reason := reason | format-to-string("disabled by when: option");
end
exception (err :: <serious-condition>, test: method (c) ~debug?() end)
exception (err :: <serious-condition>,
test: curry(handle-condition?, runner))
skip-result := $crashed;
skip-reason := format-to-string("Error in %s for suite %s: %s",
context, suite.component-name, err);
Expand Down Expand Up @@ -267,16 +259,16 @@ define method execute-component
block ()
test.test-function();
exception (err :: <assertion-failure>,
test: method (c) ~debug?() end)
test: curry(handle-condition?, runner))
// An assertion failure causes the remainder of a test to be
// skipped (by jumping here) to prevent cascading failures.
// The failure has already been recorded so nothing to do.
#f
exception (err :: <serious-condition>,
test: method (c) ~debug?() end)
test: curry(handle-condition?, runner))
err
end;
results
results
seconds := cpu-time-seconds;
microseconds := cpu-time-microseconds;
bytes := allocation;
Expand All @@ -294,6 +286,30 @@ define method execute-component
end if
end method execute-component;

define generic handle-condition?
(runner :: <test-runner>, cond :: <condition>) => (b :: <boolean>);

define method handle-condition?
(runner :: <test-runner>, cond :: <condition>) => (b :: <boolean>)
#f
end method;

define method handle-condition?
(runner :: <test-runner>, cond :: <assertion-failure>) => (b :: <boolean>)
select (runner.runner-debug)
$debug-failures, $debug-all => #f;
otherwise => #t;
end
end method;

define method handle-condition?
(runner :: <test-runner>, cond :: <serious-condition>) => (b :: <boolean>)
select (runner.runner-debug)
$debug-crashes, $debug-all => #f;
otherwise => #t;
end
end method;

define function make-skip-result (component, reason)
make(component-result-type(component),
name: component.component-name,
Expand Down
Loading
Loading