From 8ae6ef478b2883ec632a46fb3053e5d3a731d97c Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Sat, 7 Nov 2020 14:43:59 -0700 Subject: [PATCH] Dynamic examples with null context --- src/spectator/example.cr | 11 +++++++++++ src/spectator/example_context_delegate.cr | 10 ++++++++++ src/spectator/example_context_method.cr | 3 +-- src/spectator/null_context.cr | 6 ++++++ 4 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 src/spectator/null_context.cr diff --git a/src/spectator/example.cr b/src/spectator/example.cr index 6cc630c..2f435e6 100644 --- a/src/spectator/example.cr +++ b/src/spectator/example.cr @@ -26,6 +26,17 @@ module Spectator super(name, source, group) end + # Creates a dynamic example. + # A block provided to this method will be called as-if it were the test code for the example. + # The block will be given this example instance as an argument. + # The *name* describes the purpose of the example. + # It can be a `Symbol` to describe a type. + # The *source* tracks where the example exists in source code. + # The example will be assigned to *group* if it is provided. + def initialize(name : String? = nil, source : Source? = nil, group : ExampleGroup? = nil, &block : Example -> _) + @delegate = ExampleContextDelegate.null(&block) + end + # Executes the test case. # Returns the result of the execution. # The result will also be stored in `#result`. diff --git a/src/spectator/example_context_delegate.cr b/src/spectator/example_context_delegate.cr index bd5aa9c..cd8f6bb 100644 --- a/src/spectator/example_context_delegate.cr +++ b/src/spectator/example_context_delegate.cr @@ -1,5 +1,6 @@ require "./context" require "./example_context_method" +require "./null_context" module Spectator # Stores a test context and a method to call within it. @@ -11,6 +12,15 @@ module Spectator def initialize(@context : Context, @method : ExampleContextMethod) end + # Creates a delegate with a null context. + # The context will be ignored and the block will be executed in its original scope. + # The example instance will be provided as an argument to the block. + def self.null(&block : Example -> _) + context = NullContext.new + method = ExampleContextMethod.new { |example| block.call(example) } + new(context, method) + end + # Invokes a method in the test context. # The *example* is the current running example. def call(example : Example) diff --git a/src/spectator/example_context_method.cr b/src/spectator/example_context_method.cr index a3e3dfc..c14d254 100644 --- a/src/spectator/example_context_method.cr +++ b/src/spectator/example_context_method.cr @@ -4,8 +4,7 @@ module Spectator # Encapsulates a method in a test context. # This could be used to invoke a test case or hook method. # The context is passed as an argument. - # The proc should downcast the context instance to the desired type - # and call a method on that context. + # The proc should downcast the context instance to the desired type and call a method on that context. # The current example is also passed as an argument. alias ExampleContextMethod = Example, Context -> end diff --git a/src/spectator/null_context.cr b/src/spectator/null_context.cr new file mode 100644 index 0000000..3597203 --- /dev/null +++ b/src/spectator/null_context.cr @@ -0,0 +1,6 @@ +module Spectator + # Empty context used to construct examples that don't have contexts. + # This is useful for dynamically creating examples outside of a spec. + class NullContext < Context + end +end