Move sample values to group instance

The goal is to construct examples with a parameterless initializer.
This doesn't quite work, since the sample values are retrieved via the
harness, which doesn't have an active example when the sample values are
created.
This commit is contained in:
Michael Miller 2019-08-30 14:46:24 -06:00
parent 4ecc2c6004
commit bfe641e07e
10 changed files with 25 additions and 39 deletions

View file

@ -41,12 +41,6 @@ module Spectator
include ::Spectator::DSL::StructureDSL # Include the DSL for creating groups, example, and more. include ::Spectator::DSL::StructureDSL # Include the DSL for creating groups, example, and more.
include ::Spectator::DSL::ExampleDSL # Mix in methods and macros specifically for example DSL. include ::Spectator::DSL::ExampleDSL # Mix in methods and macros specifically for example DSL.
# Placeholder initializer.
# This is needed because examples and groups call super in their initializer.
# Those initializers pass the sample values upward through their hierarchy.
def initialize(_sample_values : ::Spectator::Internals::SampleValues)
end
# Pass off the "what" argument and block to `DSL::StructureDSL.describe`. # Pass off the "what" argument and block to `DSL::StructureDSL.describe`.
# That method will handle creating a new group for this spec. # That method will handle creating a new group for this spec.
describe({{what}}) {{block}} describe({{what}}) {{block}}

View file

@ -7,9 +7,9 @@ module Spectator::DSL
end end
# Constructs a new example instance and returns it. # Constructs a new example instance and returns it.
# The *group* and *sample_values* are passed to `Example#initialize`. # The *group* is passed to `Example#initialize`.
def build(group : ExampleGroup, sample_values : Internals::SampleValues) : Example def build(group : ExampleGroup, _sample_values : Internals::SampleValues) : Example
@example_type.new(group, sample_values) @example_type.new(group)
end end
end end
end end

View file

@ -26,7 +26,7 @@ module Spectator::DSL
# The *parent* should be the group that contains this group. # The *parent* should be the group that contains this group.
# The *sample_values* will be given to all of the examples (and groups) nested in this group. # The *sample_values* will be given to all of the examples (and groups) nested in this group.
def build(parent : ExampleGroup, sample_values : Internals::SampleValues) : NestedExampleGroup def build(parent : ExampleGroup, sample_values : Internals::SampleValues) : NestedExampleGroup
NestedExampleGroup.new(@what, parent, hooks, conditions).tap do |group| NestedExampleGroup.new(@what, parent, hooks, conditions, sample_values).tap do |group|
# Set the group's children to built versions of the children from this instance. # Set the group's children to built versions of the children from this instance.
group.children = @children.map do |child| group.children = @children.map do |child|
# Build the child and up-cast to prevent type errors. # Build the child and up-cast to prevent type errors.

View file

@ -6,7 +6,7 @@ module Spectator::DSL
# Creates a `RootExampleGroup` which can have instances of `Example` and `ExampleGroup` nested in it. # Creates a `RootExampleGroup` which can have instances of `Example` and `ExampleGroup` nested in it.
# The *sample_values* will be given to all of the examples (and groups) nested in this group. # The *sample_values* will be given to all of the examples (and groups) nested in this group.
def build(sample_values : Internals::SampleValues) : RootExampleGroup def build(sample_values : Internals::SampleValues) : RootExampleGroup
RootExampleGroup.new(hooks, conditions).tap do |group| RootExampleGroup.new(hooks, conditions, sample_values).tap do |group|
# Set the group's children to built versions of the children from this instance. # Set the group's children to built versions of the children from this instance.
group.children = @children.map do |child| group.children = @children.map do |child|
# Build the child and up-cast to prevent type errors. # Build the child and up-cast to prevent type errors.

View file

@ -39,11 +39,11 @@ module Spectator::DSL
# The *parent* should be the group that contains this group. # The *parent* should be the group that contains this group.
# The *sample_values* will be given to all of the examples (and groups) nested in this group. # The *sample_values* will be given to all of the examples (and groups) nested in this group.
def build(parent : ExampleGroup, sample_values : Internals::SampleValues) : NestedExampleGroup def build(parent : ExampleGroup, sample_values : Internals::SampleValues) : NestedExampleGroup
collection = @collection_builder.call(@collection_type.new(sample_values)) collection = @collection_builder.call(@collection_type.new)
# This creates the container for the sub-groups. # This creates the container for the sub-groups.
# The hooks are defined here, instead of repeating for each sub-group. # The hooks are defined here, instead of repeating for each sub-group.
NestedExampleGroup.new(@what, parent, hooks, conditions).tap do |group| NestedExampleGroup.new(@what, parent, hooks, conditions, sample_values).tap do |group|
# Set the container group's children to be sub-groups for each item in the collection. # Set the container group's children to be sub-groups for each item in the collection.
group.children = collection.map do |value| group.children = collection.map do |value|
# Create a sub-group for each item in the collection. # Create a sub-group for each item in the collection.
@ -61,7 +61,7 @@ module Spectator::DSL
private def build_sub_group(parent : ExampleGroup, sample_values : Internals::SampleValues, value : T) : NestedExampleGroup private def build_sub_group(parent : ExampleGroup, sample_values : Internals::SampleValues, value : T) : NestedExampleGroup
# Add the value to sample values for this sub-group. # Add the value to sample values for this sub-group.
sub_values = sample_values.add(@symbol, @name, value) sub_values = sample_values.add(@symbol, @name, value)
NestedExampleGroup.new(value.to_s, parent, ExampleHooks.empty, ExampleConditions.empty).tap do |group| NestedExampleGroup.new(value.to_s, parent, ExampleHooks.empty, ExampleConditions.empty, sub_values).tap do |group|
# Set the sub-group's children to built versions of the children from this instance. # Set the sub-group's children to built versions of the children from this instance.
group.children = @children.map do |child| group.children = @children.map do |child|
# Build the child and up-cast to prevent type errors. # Build the child and up-cast to prevent type errors.

View file

@ -503,13 +503,6 @@ module Spectator::DSL
# The collection could reference a helper method # The collection could reference a helper method
# or anything else in the parent scope. # or anything else in the parent scope.
class Sample%sample < {{@type.id}} class Sample%sample < {{@type.id}}
# Placeholder initializer.
# This is needed because examples and groups call super in their initializer.
# Those initializers pass the sample values upward through their hierarchy.
def initialize(_sample_values : ::Spectator::Internals::SampleValues)
super
end
# Method that returns an array containing the collection. # Method that returns an array containing the collection.
# This method should be called only once. # This method should be called only once.
# The framework stores the collection as an array for a couple of reasons. # The framework stores the collection as an array for a couple of reasons.
@ -543,9 +536,9 @@ module Spectator::DSL
end end
# Initializer to extract current element of the collection from sample values. # Initializer to extract current element of the collection from sample values.
def initialize(sample_values : ::Spectator::Internals::SampleValues) def initialize
super super
@%wrapper = sample_values.get_wrapper(:%sample) @%wrapper = ::Spectator::Internals::Harness.current.group.sample_values.get_wrapper(:%sample)
end end
# Start a new example group. # Start a new example group.
@ -656,9 +649,9 @@ module Spectator::DSL
end end
# Initializer to extract current element of the collection from sample values. # Initializer to extract current element of the collection from sample values.
def initialize(sample_values : ::Spectator::Internals::SampleValues) def initialize
super super
@%wrapper = sample_values.get_wrapper(:%sample) @%wrapper = ::Spectator::Internals::Harness.current.group.sample_values.get_wrapper(:%sample)
end end
# Start a new example group. # Start a new example group.
@ -1576,13 +1569,6 @@ module Spectator::DSL
private macro _spectator_test(class_name, run_method_name) private macro _spectator_test(class_name, run_method_name)
# Wrapper class for isolating the test code. # Wrapper class for isolating the test code.
class {{class_name.id}} < {{@type.id}} class {{class_name.id}} < {{@type.id}}
# Initializer that accepts sample values.
# The sample values are passed upward to the group modules.
# Any module that adds sample values can pull their values from this instance.
def initialize(sample_values : ::Spectator::Internals::SampleValues)
super
end
# Generated method for actually running the test code. # Generated method for actually running the test code.
def {{run_method_name.id}} def {{run_method_name.id}}
{{yield}} {{yield}}
@ -1614,9 +1600,9 @@ module Spectator::DSL
# Stores the group the example belongs to # Stores the group the example belongs to
# and sample values specific to this instance of the test. # and sample values specific to this instance of the test.
# This method's signature must match the one used in `ExampleFactory#build`. # This method's signature must match the one used in `ExampleFactory#build`.
def initialize(group : ::Spectator::ExampleGroup, sample_values : ::Spectator::Internals::SampleValues) def initialize(group : ::Spectator::ExampleGroup)
super super
@instance = {{test_class_name.id}}.new(sample_values) @instance = {{test_class_name.id}}.new
end end
# Retrieves the underlying, wrapped test code. # Retrieves the underlying, wrapped test code.

View file

@ -31,8 +31,7 @@ module Spectator
# Creates the base of the example. # Creates the base of the example.
# The group should be the example group the example belongs to. # The group should be the example group the example belongs to.
# The *sample_values* are passed to the example code. def initialize(@group)
def initialize(@group, sample_values : Internals::SampleValues)
end end
# Indicates there is only one example to run. # Indicates there is only one example to run.

View file

@ -15,9 +15,11 @@ module Spectator
include Enumerable(ExampleComponent) include Enumerable(ExampleComponent)
include Iterable(ExampleComponent) include Iterable(ExampleComponent)
getter sample_values : Internals::SampleValues
# Creates the example group. # Creates the example group.
# The hooks are stored to be triggered later. # The hooks are stored to be triggered later.
def initialize(@hooks : ExampleHooks, @conditions : ExampleConditions) def initialize(@hooks : ExampleHooks, @conditions : ExampleConditions, @sample_values)
@before_all_hooks_run = false @before_all_hooks_run = false
@after_all_hooks_run = false @after_all_hooks_run = false
end end

View file

@ -34,6 +34,11 @@ module Spectator::Internals
# Retrieves the current running example. # Retrieves the current running example.
getter example : Example getter example : Example
# Retrieves the group for the current running example.
def group
example.group
end
# Reports the outcome of an expectation. # Reports the outcome of an expectation.
# An exception will be raised when a failing result is given. # An exception will be raised when a failing result is given.
def report_expectation(expectation : Expectations::Expectation) : Nil def report_expectation(expectation : Expectations::Expectation) : Nil

View file

@ -18,8 +18,8 @@ module Spectator
# The parent's children must contain this group, # The parent's children must contain this group,
# otherwise there may be unexpected behavior. # otherwise there may be unexpected behavior.
# The *hooks* are stored to be triggered later. # The *hooks* are stored to be triggered later.
def initialize(@what, @parent, hooks : ExampleHooks, conditions : ExampleConditions) def initialize(@what, @parent, hooks : ExampleHooks, conditions : ExampleConditions, sample_values)
super(hooks, conditions) super(hooks, conditions, sample_values)
end end
# Indicates wheter the group references a type. # Indicates wheter the group references a type.