diff --git a/src/spectator/formatting/formatter.cr b/src/spectator/formatting/formatter.cr index bfbbec2..22e59eb 100644 --- a/src/spectator/formatting/formatter.cr +++ b/src/spectator/formatting/formatter.cr @@ -31,11 +31,13 @@ module Spectator::Formatting # This method is the first method to be invoked # and will be called only once. # It is called before any examples run. + # The *notification* will be a `StartNotification` type of object. def start(_notification) end # Invoked just before an example runs. # This method is called once for every example. + # The *notification* will be an `ExampleNotification` type of object. def example_started(_notification) end @@ -43,22 +45,26 @@ module Spectator::Formatting # This method is called once for every example. # One of `#example_passed`, `#example_pending` or `#example_failed` # will be called immediately after this method, depending on the example's result. + # The *notification* will be an `ExampleNotification` type of object. def example_finished(_notification) end # Invoked after an example completes successfully. # This is called right after `#example_finished`. + # The *notification* will be an `ExampleNotification` type of object. def example_passed(_notification) end # Invoked after an example is skipped or marked as pending. # This is called right after `#example_finished`. + # The *notification* will be an `ExampleNotification` type of object. def example_pending(_notification) end # Invoked after an example fails. # This is called right after `#example_finished`. # Errors are considered failures and will cause this method to be called. + # The *notification* will be an `ExampleNotification` type of object. def example_failed(_notification) end diff --git a/src/spectator/formatting/notifications.cr b/src/spectator/formatting/notifications.cr new file mode 100644 index 0000000..afe57e2 --- /dev/null +++ b/src/spectator/formatting/notifications.cr @@ -0,0 +1,7 @@ +require "../example" + +module Spectator::Formatting + record StartNotification, example_count : Int32 + + record ExampleNotification, example : Example +end diff --git a/src/spectator/spec.cr b/src/spectator/spec.cr index 06ba0c4..df84a54 100644 --- a/src/spectator/spec.cr +++ b/src/spectator/spec.cr @@ -14,7 +14,7 @@ module Spectator # Runs all selected examples and returns the results. def run - Runner.new(examples, @config.run_flags).run + Runner.new(examples, @config.formatter, @config.run_flags).run end # Selects and shuffles the examples that should run. diff --git a/src/spectator/spec/events.cr b/src/spectator/spec/events.cr new file mode 100644 index 0000000..b22eee0 --- /dev/null +++ b/src/spectator/spec/events.cr @@ -0,0 +1,49 @@ +module Spectator + class Spec + # Mix-in for announcing events from a `Runner`. + # All events invoke their corresponding method on the formatter. + module Events + # Triggers the 'start' event. + # See `Formatting::Formatter#start` + private def start + notification = Formatting::StartNotification.new(example_count) + formatter.start(notification) + end + + # Triggers the 'example started' event. + # Must be passed the *example* about to run. + # See `Formatting::Formatter#example_started` + private def example_started(example) + notification = Formatting::ExampleNotification.new(example) + formatter.example_started(notification) + end + + # Triggers the 'example started' event. + # Also triggers the example result event corresponding to the example's outcome. + # Must be passed the completed *example*. + # See `Formatting::Formatter#example_finished` + private def example_finished(example) + notification = Formatting::ExampleNotification.new(example) + formatter.example_started(notification) + + case example.result + when .fail? then formatter.example_failed(notification) + when .pass? then formatter.example_passed(notification) + else formatter.example_pending(notification) + end + end + + # Triggers the 'stop' event. + # See `Formatting::Formatter#stop` + private def stop + formatter.stop(nil) + end + + # Triggers the 'close' event. + # See `Formatting::Formatter#close` + private def close + formatter.close(nil) + end + end + end +end diff --git a/src/spectator/spec/runner.cr b/src/spectator/spec/runner.cr index 4bc9d7b..850c3e0 100644 --- a/src/spectator/spec/runner.cr +++ b/src/spectator/spec/runner.cr @@ -1,10 +1,16 @@ require "../example" require "../run_flags" +require "./events" module Spectator class Spec # Logic for executing examples and collecting results. private struct Runner + include Events + + # Formatter to send events to. + private getter formatter : Formatting::Formatter + # Creates the runner. # The collection of *examples* should be pre-filtered and shuffled. # This runner will run each example in the order provided. @@ -19,12 +25,16 @@ module Spectator # True will be returned if the spec ran successfully, # or false if there was at least one failure. def run : Bool + start executed = [] of Example elapsed = Time.measure { executed = run_examples } + stop # TODO: Generate a report and pass it along to the formatter. false # TODO: Report real result + ensure + close end # Attempts to run all examples. @@ -45,11 +55,14 @@ module Spectator # Runs a single example and returns the result. # The formatter is given the example and result information. private def run_example(example) - if dry_run? + example_started(example) + result = if dry_run? dry_run_result else example.run end + example_finished(example) + result end # Creates a fake result.