mirror of
https://gitea.invidious.io/iv-org/shard-spectator.git
synced 2024-08-15 00:53:35 +00:00
Update docs
Mostly fixes around symbols for syntax. Added some missing docs and updated incorrect or vague ones.
This commit is contained in:
parent
9c16a5a53e
commit
847cc662bd
51 changed files with 258 additions and 219 deletions
|
@ -38,7 +38,7 @@ module Spectator::DSL
|
|||
end
|
||||
|
||||
# Begins a new sample group in the spec -
|
||||
# that is, a group defined by the `sample` keyword in the DSL.
|
||||
# that is, a group defined by the `StructureDSL#sample` macro in the DSL.
|
||||
# A corresponding `#end_group` call must be made
|
||||
# when the group being started is finished.
|
||||
# See `SampleExampleGroupBuilder#initialize` for the arguments
|
||||
|
@ -91,10 +91,12 @@ module Spectator::DSL
|
|||
current_group.add_around_each_hook(block)
|
||||
end
|
||||
|
||||
# Adds a pre-condition to run at the start of every example in the current group.
|
||||
def add_pre_condition(&block : ->) : Nil
|
||||
current_group.add_pre_condition(block)
|
||||
end
|
||||
|
||||
# Adds a post-condition to run at the end of every example in the current group.
|
||||
def add_post_condition(&block : ->) : Nil
|
||||
current_group.add_post_condition(block)
|
||||
end
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
require "./matcher_dsl"
|
||||
|
||||
module Spectator::DSL
|
||||
# Methods that are available inside test code (an `it` block).
|
||||
# Methods that are available inside test code.
|
||||
# Basically, inside an `StructureDSL#it` block.
|
||||
module ExampleDSL
|
||||
include MatcherDSL
|
||||
|
||||
# Starts an expectation.
|
||||
# This should be followed up with `to` or `to_not`.
|
||||
# This should be followed up with `Spectator::Expectations::ExpectationPartial#to`
|
||||
# or `Spectator::Expectations::ExpectationPartial#to_not`.
|
||||
# The value passed in will be checked
|
||||
# to see if it satisfies the conditions specified.
|
||||
#
|
||||
|
@ -21,7 +23,8 @@ module Spectator::DSL
|
|||
end
|
||||
|
||||
# Starts an expectation on a block of code.
|
||||
# This should be followed up with `to` or `to_not`.
|
||||
# This should be followed up with `Spectator::Expectations::ExpectationPartial#to`
|
||||
# or `Spectator::Expectations::ExpectationPartial#to_not`.
|
||||
# The block passed in, or its return value, will be checked
|
||||
# to see if it satisfies the conditions specified.
|
||||
#
|
||||
|
@ -40,7 +43,7 @@ module Spectator::DSL
|
|||
# ```
|
||||
# expect(&.size).to eq(5)
|
||||
# ```
|
||||
# The method passed will always be evaluated on `#subject`.
|
||||
# The method passed will always be evaluated on the subject.
|
||||
macro expect(_source_file = __FILE__, _source_line = __LINE__, &block)
|
||||
{% if block.is_a?(Nop) %}
|
||||
{% raise "Argument or block must be provided to expect" %}
|
||||
|
@ -48,13 +51,20 @@ module Spectator::DSL
|
|||
|
||||
# Check if the short-hand method syntax is used.
|
||||
# This is a hack, since macros don't get this as a "literal" or something similar.
|
||||
# The Crystal compiler will translate `&.foo` to `{ |__arg0| __arg0.foo }`.
|
||||
# The Crystal compiler will translate:
|
||||
# ```
|
||||
# &.foo
|
||||
# ```
|
||||
# to:
|
||||
# ```
|
||||
# { |__arg0| __arg0.foo }
|
||||
# ```
|
||||
# The hack used here is to check if it looks like a compiler-generated block.
|
||||
{% if block.args == ["__arg0".id] && block.body.is_a?(Call) && block.body.id =~ /^__arg0\./ %}
|
||||
# Extract the method name to make it clear to the user what is tested.
|
||||
# The raw block can't be used because it's not clear to the user.
|
||||
{% method_name = block.body.id.split('.').last %}
|
||||
# TODO: Maybe pass the subject in as __arg0 instead of prefixing with `subject.`.
|
||||
# TODO: Maybe pass the subject in as __arg0 instead of prefixing the method name.
|
||||
::Spectator::Expectations::ValueExpectationPartial.new(subject.{{method_name}}, {{"#" + method_name}}, {{_source_file}}, {{_source_line}})
|
||||
{% else %}
|
||||
# In this case, it looks like the short-hand method syntax wasn't used.
|
||||
|
@ -64,7 +74,8 @@ module Spectator::DSL
|
|||
end
|
||||
|
||||
# Starts an expectation.
|
||||
# This should be followed up with `to` or `to_not`.
|
||||
# This should be followed up with `Spectator::Expectations::ExpectationPartial#to`
|
||||
# or `Spectator::Expectations::ExpectationPartial#to_not`.
|
||||
# The value passed in will be checked
|
||||
# to see if it satisfies the conditions specified.
|
||||
#
|
||||
|
@ -81,7 +92,8 @@ module Spectator::DSL
|
|||
end
|
||||
|
||||
# Starts an expectation on a block of code.
|
||||
# This should be followed up with `to` or `to_not`.
|
||||
# This should be followed up with `Spectator::Expectations::ExpectationPartial#to`
|
||||
# or `Spectator::Expectations::ExpectationPartial#to_not`.
|
||||
# The block passed in, or its return value, will be checked
|
||||
# to see if it satisfies the conditions specified.
|
||||
#
|
||||
|
@ -102,7 +114,7 @@ module Spectator::DSL
|
|||
# ```
|
||||
# it expects(&.size).to eq(5)
|
||||
# ```
|
||||
# The method passed will always be evaluated on `#subject`.
|
||||
# The method passed will always be evaluated on the subject.
|
||||
macro expects(&block)
|
||||
expect {{block}}
|
||||
end
|
||||
|
|
|
@ -7,7 +7,7 @@ module Spectator::DSL
|
|||
end
|
||||
|
||||
# Constructs a new example instance and returns it.
|
||||
# The `group` and `sample_valuees` are passed to `Example#initialize`.
|
||||
# The *group* and *sample_values* are passed to `Example#initialize`.
|
||||
def build(group : ExampleGroup, sample_values : Internals::SampleValues) : Example
|
||||
@example_type.new(group, sample_values)
|
||||
end
|
||||
|
|
|
@ -53,16 +53,18 @@ module Spectator::DSL
|
|||
@around_each_hooks << block
|
||||
end
|
||||
|
||||
# Adds a pre-condition to run at the start of every example in this group.
|
||||
def add_pre_condition(block : ->) : Nil
|
||||
@pre_conditions << block
|
||||
end
|
||||
|
||||
# Adds a post-condition to run at the end of every example in this group.
|
||||
def add_post_condition(block : ->) : Nil
|
||||
@post_conditions << block
|
||||
end
|
||||
|
||||
# Constructs an `ExampleHooks` instance with all the hooks defined for this group.
|
||||
# This method should be only when the group is being built,
|
||||
# This method should be called only when the group is being built,
|
||||
# otherwise some hooks may be missing.
|
||||
private def hooks
|
||||
ExampleHooks.new(
|
||||
|
@ -74,6 +76,10 @@ module Spectator::DSL
|
|||
)
|
||||
end
|
||||
|
||||
# Constructs an `ExampleConditions` instance
|
||||
# with all the pre- and post-conditions defined for this group.
|
||||
# This method should be called only when the group is being built,
|
||||
# otherwise some conditions may be missing.
|
||||
private def conditions
|
||||
ExampleConditions.new(@pre_conditions, @post_conditions)
|
||||
end
|
||||
|
|
|
@ -4,7 +4,7 @@ module Spectator::DSL
|
|||
# Methods for defining matchers for expectations.
|
||||
module MatcherDSL
|
||||
# Indicates that some value should equal another.
|
||||
# The `==` operator is used for this check.
|
||||
# The == operator is used for this check.
|
||||
# The value passed to this method is the expected value.
|
||||
#
|
||||
# Example:
|
||||
|
@ -16,7 +16,7 @@ module Spectator::DSL
|
|||
end
|
||||
|
||||
# Indicates that some value should not equal another.
|
||||
# The `!=` operator is used for this check.
|
||||
# The != operator is used for this check.
|
||||
# The value passed to this method is the unexpected value.
|
||||
#
|
||||
# Example:
|
||||
|
@ -28,7 +28,8 @@ module Spectator::DSL
|
|||
end
|
||||
|
||||
# Indicates that some value when compared to another satisfies an operator.
|
||||
# An operator can follow, such as: `<`, `<=`, `>`, or `>=`.
|
||||
# An operator can follow, such as: <, <=, >, or >=.
|
||||
# See `Spectator::Matchers::TruthyMatcher` for a full list of operators.
|
||||
#
|
||||
# Examples:
|
||||
# ```
|
||||
|
@ -47,8 +48,8 @@ module Spectator::DSL
|
|||
end
|
||||
|
||||
# Indicates that some value should semantically equal another.
|
||||
# The `===` operator is used for this check.
|
||||
# This has identical behavior as a `when` condition in a `case` block.
|
||||
# The === operator is used for this check.
|
||||
# This has identical behavior as a "when" condition in a case block.
|
||||
#
|
||||
# Examples:
|
||||
# ```
|
||||
|
@ -61,8 +62,8 @@ module Spectator::DSL
|
|||
end
|
||||
|
||||
# Indicates that some value should be of a specified type.
|
||||
# The `#is_a?` method is used for this check.
|
||||
# A type name or type union should be used for `expected`.
|
||||
# The `Object#is_a?` method is used for this check.
|
||||
# A type name or type union should be used for *expected*.
|
||||
#
|
||||
# Examples:
|
||||
# ```
|
||||
|
@ -76,8 +77,8 @@ module Spectator::DSL
|
|||
end
|
||||
|
||||
# Indicates that some value should be of a specified type.
|
||||
# The `#is_a?` method is used for this check.
|
||||
# A type name or type union should be used for `expected`.
|
||||
# The `Object#is_a?` method is used for this check.
|
||||
# A type name or type union should be used for *expected*.
|
||||
# This method is identical to `#be_a`,
|
||||
# and exists just to improve grammar.
|
||||
#
|
||||
|
@ -90,7 +91,7 @@ module Spectator::DSL
|
|||
end
|
||||
|
||||
# Indicates that some value should be less than another.
|
||||
# The `<` operator is used for this check.
|
||||
# The < operator is used for this check.
|
||||
# The value passed to this method is the value expected to be larger.
|
||||
#
|
||||
# Example:
|
||||
|
@ -102,7 +103,7 @@ module Spectator::DSL
|
|||
end
|
||||
|
||||
# Indicates that some value should be less than or equal to another.
|
||||
# The `<=` operator is used for this check.
|
||||
# The <= operator is used for this check.
|
||||
# The value passed to this method is the value expected to be larger or equal.
|
||||
#
|
||||
# Example:
|
||||
|
@ -114,7 +115,7 @@ module Spectator::DSL
|
|||
end
|
||||
|
||||
# Indicates that some value should be greater than another.
|
||||
# The `>` operator is used for this check.
|
||||
# The > operator is used for this check.
|
||||
# The value passed to this method is the value expected to be smaller.
|
||||
#
|
||||
# Example:
|
||||
|
@ -126,7 +127,7 @@ module Spectator::DSL
|
|||
end
|
||||
|
||||
# Indicates that some value should be greater than or equal to another.
|
||||
# The `>=` operator is used for this check.
|
||||
# The >= operator is used for this check.
|
||||
# The value passed to this method is the value expected to be smaller or equal.
|
||||
#
|
||||
# Example:
|
||||
|
@ -138,9 +139,9 @@ module Spectator::DSL
|
|||
end
|
||||
|
||||
# Indicates that some value should match another.
|
||||
# The `=~` operator is used for this check.
|
||||
# The =~ operator is used for this check.
|
||||
# Typically a regular expression is used,
|
||||
# but any type that has the `=~` operator will work.
|
||||
# but any type that has the =~ operator will work.
|
||||
#
|
||||
# Examples:
|
||||
# ```
|
||||
|
@ -174,7 +175,7 @@ module Spectator::DSL
|
|||
end
|
||||
|
||||
# Indicates that some value should be truthy.
|
||||
# This means that the value is not `false` and not `nil`.
|
||||
# This means that the value is not false and not nil.
|
||||
#
|
||||
# Examples:
|
||||
# ```
|
||||
|
@ -186,7 +187,7 @@ module Spectator::DSL
|
|||
end
|
||||
|
||||
# Indicates that some value should be falsey.
|
||||
# This means that the value is either `false` or `nil`.
|
||||
# This means that the value is either false or nil.
|
||||
#
|
||||
# Examples:
|
||||
# ```
|
||||
|
@ -200,7 +201,8 @@ module Spectator::DSL
|
|||
# Indicates that some value should be contained within another.
|
||||
# This checker can be used in one of two ways.
|
||||
#
|
||||
# The first: the `expected` argument can be anything that implements `#includes?`.
|
||||
# The first: the *expected* argument can be anything
|
||||
# that implements the `includes?` method.
|
||||
# This is typically a `Range`, but can also be `Enumerable`.
|
||||
#
|
||||
# Examples:
|
||||
|
@ -209,9 +211,9 @@ module Spectator::DSL
|
|||
# expect(7).to be_within(1..10)
|
||||
# ```
|
||||
#
|
||||
# The other way is to use this in conjunction with `of`.
|
||||
# The other way is to use this is with the "of" keyword.
|
||||
# This creates a lower and upper bound
|
||||
# centered around the value of the `expected` argument.
|
||||
# centered around the value of the *expected* argument.
|
||||
# This usage is helpful for comparisons on floating-point numbers.
|
||||
#
|
||||
# Examples:
|
||||
|
@ -220,13 +222,13 @@ module Spectator::DSL
|
|||
# expect(speed).to be_within(5).of(speed_limit)
|
||||
# ```
|
||||
#
|
||||
# NOTE: The `of` suffix must be used
|
||||
# if the `expected` argument does not implement `#includes?`
|
||||
# NOTE: The of suffix must be used
|
||||
# if the *expected* argument does not implement an includes? method.
|
||||
#
|
||||
# Additionally, for this second usage,
|
||||
# an `inclusive` or `exclusive` suffix can be added.
|
||||
# an "inclusive" or "exclusive" suffix can be added.
|
||||
# These modify the upper-bound on the range being checked against.
|
||||
# By default, the range is *inclusive*.
|
||||
# By default, the range is inclusive.
|
||||
#
|
||||
# Examples:
|
||||
# ```
|
||||
|
@ -247,9 +249,9 @@ module Spectator::DSL
|
|||
# expect(7).to be_within(1, 10)
|
||||
# ```
|
||||
#
|
||||
# Additionally, an `inclusive` or `exclusive` suffix can be added.
|
||||
# Additionally, an "inclusive" or "exclusive" suffix can be added.
|
||||
# These modify the upper-bound on the range being checked against.
|
||||
# By default, the range is *inclusive*.
|
||||
# By default, the range is inclusive.
|
||||
#
|
||||
# Examples:
|
||||
# ```
|
||||
|
@ -301,10 +303,10 @@ module Spectator::DSL
|
|||
|
||||
# Indicates that some value or set should start with another value.
|
||||
# This is typically used on a `String` or `Array` (any `Enumerable` works).
|
||||
# The `expected` argument can be a `String`, `Char`, or `Regex`
|
||||
# The *expected* argument can be a `String`, `Char`, or `Regex`
|
||||
# when the actual type (being comapred against) is a `String`.
|
||||
# For `Enumerable` types, only the first item is inspected.
|
||||
# It is compared with the `===` operator,
|
||||
# It is compared with the === operator,
|
||||
# so that values, types, regular expressions, and others can be tested.
|
||||
#
|
||||
# Examples:
|
||||
|
@ -323,10 +325,10 @@ module Spectator::DSL
|
|||
|
||||
# Indicates that some value or set should end with another value.
|
||||
# This is typically used on a `String` or `Array` (any `Indexable` works).
|
||||
# The `expected` argument can be a `String`, `Char`, or `Regex`
|
||||
# The *expected* argument can be a `String`, `Char`, or `Regex`
|
||||
# when the actual type (being comapred against) is a `String`.
|
||||
# For `Indexable` types, only the last item is inspected.
|
||||
# It is compared with the `===` operator,
|
||||
# It is compared with the === operator,
|
||||
# so that values, types, regular expressions, and others can be tested.
|
||||
#
|
||||
# Examples:
|
||||
|
@ -345,7 +347,7 @@ module Spectator::DSL
|
|||
|
||||
# Indicates that some value or set should contain another value.
|
||||
# This is typically used on a `String` or `Array` (any `Enumerable` works).
|
||||
# The `expected` argument can be a `String` or `Char`
|
||||
# The *expected* argument can be a `String` or `Char`
|
||||
# when the actual type (being comapred against) is a `String`.
|
||||
# For `Enumerable` types, items are compared using the underying implementation.
|
||||
# In both cases, the `includes?` method is used.
|
||||
|
@ -369,11 +371,11 @@ module Spectator::DSL
|
|||
# Indicates that some value or set should contain another value.
|
||||
# This is similar to `#contain`, but uses a different method for matching.
|
||||
# Typically a `String` or `Array` (any `Enumerable` works) is checked against.
|
||||
# The `expected` argument can be a `String` or `Char`
|
||||
# The *expected* argument can be a `String` or `Char`
|
||||
# when the actual type (being comapred against) is a `String`.
|
||||
# The `includes?` method is used for this case.
|
||||
# For `Enumerable` types, each item is inspected until one matches.
|
||||
# The `===` operator is used for this case, which allows for equality, type, regex, and other matches.
|
||||
# The === operator is used for this case, which allows for equality, type, regex, and other matches.
|
||||
#
|
||||
# Examples:
|
||||
# ```
|
||||
|
@ -432,7 +434,7 @@ module Spectator::DSL
|
|||
# Indicates that some value should have a set of attributes matching some conditions.
|
||||
# A list of named arguments are expected.
|
||||
# The names correspond to the attributes in the instance to check.
|
||||
# The values are conditions to check with the `===` operator against the attribute's value.
|
||||
# The values are conditions to check with the === operator against the attribute's value.
|
||||
#
|
||||
# Examples:
|
||||
# ```
|
||||
|
@ -444,10 +446,10 @@ module Spectator::DSL
|
|||
end
|
||||
|
||||
# Used to create predicate matchers.
|
||||
# Any missing method that starts with `be_` will be handled.
|
||||
# Any missing method that starts with 'be_' will be handled.
|
||||
# All other method names will be ignored and raise a compile-time error.
|
||||
#
|
||||
# This can be used to simply check a predicate method that ends in `?`.
|
||||
# This can be used to simply check a predicate method that ends in '?'.
|
||||
# For instance:
|
||||
# ```
|
||||
# expect("foobar").to be_ascii_only
|
||||
|
@ -456,7 +458,7 @@ module Spectator::DSL
|
|||
# ```
|
||||
macro method_missing(call)
|
||||
{% if call.name.starts_with?("be_") %}
|
||||
{% method_name = call.name[3..-1] %} # Remove `be_` prefix.
|
||||
{% method_name = call.name[3..-1] %} # Remove be_ prefix.
|
||||
::Spectator::Matchers::PredicateMatcher(NamedTuple({{method_name}}: Nil)).new
|
||||
{% else %}
|
||||
{% raise "Undefined local variable or method '#{call}'" %}
|
||||
|
|
|
@ -3,7 +3,7 @@ module Spectator::DSL
|
|||
# Creates groups of examples and nested groups.
|
||||
class NestedExampleGroupBuilder < ExampleGroupBuilder
|
||||
# Creates a new group builder.
|
||||
# The value for `what` should be the context for the group.
|
||||
# The value for *what* should be the context for the group.
|
||||
#
|
||||
# For example, in these samples:
|
||||
# ```
|
||||
|
@ -23,8 +23,8 @@ module Spectator::DSL
|
|||
# Builds the example group.
|
||||
# A new `NestedExampleGroup` will be returned
|
||||
# which can have instances of `Example` and `ExampleGroup` nested in it.
|
||||
# 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 *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.
|
||||
def build(parent : ExampleGroup, sample_values : Internals::SampleValues) : NestedExampleGroup
|
||||
NestedExampleGroup.new(@what, parent, hooks, conditions).tap do |group|
|
||||
# Set the group's children to built versions of the children from this instance.
|
||||
|
|
|
@ -4,7 +4,7 @@ module Spectator::DSL
|
|||
# and it should be at the top of the spec "tree".
|
||||
class RootExampleGroupBuilder < ExampleGroupBuilder
|
||||
# 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
|
||||
RootExampleGroup.new(hooks, conditions).tap do |group|
|
||||
# Set the group's children to built versions of the children from this instance.
|
||||
|
|
|
@ -8,9 +8,9 @@ module Spectator::DSL
|
|||
# By doing so, the hooks are defined once, are inherited, and use less memory.
|
||||
class SampleExampleGroupBuilder(T) < NestedExampleGroupBuilder
|
||||
# Creates a new group builder.
|
||||
# The value for `what` should be the text the user specified for the collection.
|
||||
# The `collection` is the actual array of items to create examples for.
|
||||
# The `name` is the variable name that the user accesses the current collection item with.
|
||||
# The value for *what* should be the text the user specified for the collection.
|
||||
# The *collection* is the actual array of items to create examples for.
|
||||
# The *name* is the variable name that the user accesses the current collection item with.
|
||||
#
|
||||
# In this code:
|
||||
# ```
|
||||
|
@ -18,11 +18,11 @@ module Spectator::DSL
|
|||
# # ...
|
||||
# end
|
||||
# ```
|
||||
# The `what` value would be "random_integers"
|
||||
# and the collection would contain the items returned by calling `random_integers`.
|
||||
# The `name` would be "integer".
|
||||
# The *what* would be "random_integers"
|
||||
# and the collection would contain the items returned by calling *random_integers*.
|
||||
# The *name* would be "integer".
|
||||
#
|
||||
# The `symbol` is passed along to the sample values
|
||||
# The *symbol* is passed along to the sample values
|
||||
# so that the example code can retrieve the current item from the collection.
|
||||
# The symbol should be unique.
|
||||
def initialize(what : String, @collection : Array(T), @name : String, @symbol : Symbol)
|
||||
|
@ -32,8 +32,8 @@ module Spectator::DSL
|
|||
# Builds the example group.
|
||||
# A new `NestedExampleGroup` will be returned
|
||||
# which can have instances of `Example` and `ExampleGroup` nested in it.
|
||||
# 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 *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.
|
||||
def build(parent : ExampleGroup, sample_values : Internals::SampleValues) : NestedExampleGroup
|
||||
# This creates the container for the sub-groups.
|
||||
# The hooks are defined here, instead of repeating for each sub-group.
|
||||
|
@ -47,9 +47,9 @@ module Spectator::DSL
|
|||
end
|
||||
|
||||
# Builds a sub-group for one item in the collection.
|
||||
# The `parent` should be the container group currently being built by the `#build` call.
|
||||
# The `sample_values` should be the same as what was passed to the `#build` call.
|
||||
# The `value` is the current item in the collection.
|
||||
# The *parent* should be the container group currently being built by the `#build` call.
|
||||
# The *sample_values* should be the same as what was passed to the `#build` call.
|
||||
# The *value* is the current item in the collection.
|
||||
# The value will be added to the sample values for the sub-group,
|
||||
# so it shouldn't be added prior to calling this method.
|
||||
private def build_sub_group(parent : ExampleGroup, sample_values : Internals::SampleValues, value : T) : NestedExampleGroup
|
||||
|
|
|
@ -20,9 +20,11 @@ module Spectator::DSL
|
|||
# it "does something" do
|
||||
# # Test code goes here...
|
||||
# end
|
||||
# ```
|
||||
#
|
||||
# # becomes...
|
||||
# becomes...
|
||||
#
|
||||
# ```
|
||||
# # Class describing the example
|
||||
# # and provides a means of running the test.
|
||||
# # Typically every class, module, and method
|
||||
|
@ -85,9 +87,11 @@ module Spectator::DSL
|
|||
# end
|
||||
# end
|
||||
# end
|
||||
# ```
|
||||
#
|
||||
# # becomes...
|
||||
# becomes...
|
||||
#
|
||||
# ```
|
||||
# # describe "#foo"
|
||||
# module Context123
|
||||
# # Start a new group.
|
||||
|
@ -148,13 +152,13 @@ module Spectator::DSL
|
|||
# For more information, see `Internals::SampleValues`.
|
||||
module StructureDSL
|
||||
# Placeholder initializer.
|
||||
# This is needed because examples and groups call `super` in their 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 : Internals::SampleValues)
|
||||
end
|
||||
|
||||
# Creates a new example group to describe a component.
|
||||
# The `what` argument describes "what" is being tested.
|
||||
# The *what* argument describes "what" is being tested.
|
||||
# Additional example groups and DSL may be nested in the block.
|
||||
#
|
||||
# Typically when testing a method,
|
||||
|
@ -168,7 +172,7 @@ module Spectator::DSL
|
|||
# ```
|
||||
#
|
||||
# When describing a class (or any other type),
|
||||
# the `what` parameter doesn't need to be quoted.
|
||||
# the *what* parameter doesn't need to be quoted.
|
||||
# ```
|
||||
# describe String do
|
||||
# it "does something" do
|
||||
|
@ -196,7 +200,7 @@ module Spectator::DSL
|
|||
end
|
||||
|
||||
# Creates a new example group to describe a situation.
|
||||
# The `what` argument describes the scenario or case being tested.
|
||||
# The *what* argument describes the scenario or case being tested.
|
||||
# Additional example groups and DSL may be nested in the block.
|
||||
#
|
||||
# The `#describe` and `#context` are identical in terms of functionality.
|
||||
|
@ -352,12 +356,12 @@ module Spectator::DSL
|
|||
#
|
||||
# given value = 5 do
|
||||
# expect(&.odd?).to be_true
|
||||
# expect(&.event?).to be_false
|
||||
# expect(&.even?).to be_false
|
||||
# end
|
||||
#
|
||||
# given value = 42 do
|
||||
# expect(&.odd?).to be_false
|
||||
# expect(&.event?).to be_true
|
||||
# expect(&.even?).to be_true
|
||||
# end
|
||||
# end
|
||||
# ```
|
||||
|
@ -438,18 +442,18 @@ module Spectator::DSL
|
|||
# Creates a new example group to test multiple values with.
|
||||
# This method takes a collection of values
|
||||
# and repeats the contents of the block with each value.
|
||||
# The `collection` argument should be a literal collection,
|
||||
# The *collection* argument should be a literal collection,
|
||||
# such as an array, or a function that returns an enumerable.
|
||||
# Additionally, a count may be specified to limit the number of values tested.
|
||||
#
|
||||
# NOTE: If an infinite enumerable is provided for the collection,
|
||||
# then a count must be specified.
|
||||
# Only the first `count` items will be used.
|
||||
# Only the first *count* items will be used.
|
||||
#
|
||||
# The block can accept an argument.
|
||||
# If it does, then the argument's name is used to reference
|
||||
# the current item in the collection.
|
||||
# If an argument isn't provided, then `#value` can be used instead.
|
||||
# If an argument isn't provided, then *value* can be used instead.
|
||||
#
|
||||
# Example with a block argument:
|
||||
# ```
|
||||
|
@ -472,8 +476,8 @@ module Spectator::DSL
|
|||
# ```
|
||||
#
|
||||
# In the examples above, the test case (`#it` block)
|
||||
# is repeated for each element in `some_integers`.
|
||||
# `some_integers` is a ficticous collection.
|
||||
# is repeated for each element in *some_integers*.
|
||||
# *some_integers* is a ficticous collection.
|
||||
# The collection will be iterated once.
|
||||
# `#sample` and `#random_sample` blocks can be nested,
|
||||
# and work similarly to loops.
|
||||
|
@ -521,7 +525,7 @@ module Spectator::DSL
|
|||
# Iterating multiple times would generate inconsistent values at runtime.
|
||||
def %to_a
|
||||
# If a count was provided,
|
||||
# only select the first `count` items from the collection.
|
||||
# only select the first *count* items from the collection.
|
||||
# Otherwise, select all of them.
|
||||
{% if count %}
|
||||
%sample.first({{count}})
|
||||
|
@ -535,7 +539,7 @@ module Spectator::DSL
|
|||
# The module uses a generated unique name.
|
||||
module Context%sample
|
||||
# Include the parent module.
|
||||
# Since `@type` resolves immediately,
|
||||
# Since @type resolves immediately,
|
||||
# this will reference the parent type.
|
||||
include {{@type.id}}
|
||||
|
||||
|
@ -545,7 +549,7 @@ module Spectator::DSL
|
|||
# Retrieves the current element from the collection.
|
||||
def {{name}}
|
||||
# Unwrap the value and return it.
|
||||
# The `#first` method has a return type that matches the element type.
|
||||
# The `Enumerable#first` method has a return type that matches the element type.
|
||||
# So it is used on the collection method proxy to resolve the type at compile-time.
|
||||
@%wrapper.as(::Spectator::Internals::TypedValueWrapper(typeof(%sample.first))).value
|
||||
end
|
||||
|
@ -576,8 +580,8 @@ module Spectator::DSL
|
|||
# Creates a new example group to test multiple random values with.
|
||||
# This method takes a collection of values and count
|
||||
# and repeats the contents of the block with each value.
|
||||
# This method randomly selects `count` items from the collection.
|
||||
# The `collection` argument should be a literal collection,
|
||||
# This method randomly selects *count* items from the collection.
|
||||
# The *collection* argument should be a literal collection,
|
||||
# such as an array, or a function that returns an enumerable.
|
||||
#
|
||||
# NOTE: If an enumerable is used, it must be finite.
|
||||
|
@ -585,7 +589,7 @@ module Spectator::DSL
|
|||
# The block can accept an argument.
|
||||
# If it does, then the argument's name is used to reference
|
||||
# the current item in the collection.
|
||||
# If an argument isn't provided, then `#value` can be used instead.
|
||||
# If an argument isn't provided, then *value* can be used instead.
|
||||
#
|
||||
# Example with a block argument:
|
||||
# ```
|
||||
|
@ -608,8 +612,8 @@ module Spectator::DSL
|
|||
# ```
|
||||
#
|
||||
# In the examples above, the test case (`#it` block)
|
||||
# is repeated for 5 random elements in `some_integers`.
|
||||
# `some_integers` is a ficticous collection.
|
||||
# is repeated for 5 random elements in *some_integers*.
|
||||
# *some_integers* is a ficticous collection.
|
||||
# The collection will be iterated once.
|
||||
# `#sample` and `#random_sample` blocks can be nested,
|
||||
# and work similarly to loops.
|
||||
|
@ -655,7 +659,7 @@ module Spectator::DSL
|
|||
# The module uses a generated unique name.
|
||||
module Context%sample
|
||||
# Include the parent module.
|
||||
# Since `@type` resolves immediately,
|
||||
# Since @type resolves immediately,
|
||||
# this will reference the parent type.
|
||||
include {{@type.id}}
|
||||
|
||||
|
@ -665,7 +669,7 @@ module Spectator::DSL
|
|||
# Retrieves the current element from the collection.
|
||||
def {{name}}
|
||||
# Unwrap the value and return it.
|
||||
# The `#first` method has a return type that matches the element type.
|
||||
# The `Enumerable#first` method has a return type that matches the element type.
|
||||
# So it is used on the collection method proxy to resolve the type at compile-time.
|
||||
@%wrapper.as(::Spectator::Internals::TypedValueWrapper(typeof(%sample.first))).value
|
||||
end
|
||||
|
@ -714,13 +718,13 @@ module Spectator::DSL
|
|||
# ```
|
||||
#
|
||||
# By using a subject, some of the DSL becomes simpler.
|
||||
# For example, `ExampleDSL#is_expected` can be used
|
||||
# as short-hand for `expect(subject)`.
|
||||
# For example, `ExampleDSL#is_expected` can be used.
|
||||
# ```
|
||||
# subject { "foobar" }
|
||||
#
|
||||
# it "isn't empty" do
|
||||
# is_expected.to_not be_empty
|
||||
# is_expected.to_not be_empty # is the same as:
|
||||
# expect(subject).to_not be_empty
|
||||
# end
|
||||
# ```
|
||||
#
|
||||
|
@ -807,18 +811,18 @@ module Spectator::DSL
|
|||
let!(%value) {{block}}
|
||||
|
||||
# Wrapper to hold the value.
|
||||
# This will be `nil` if the value hasn't been referenced yet.
|
||||
# This will be nil if the value hasn't been referenced yet.
|
||||
# After being referenced, the cached value will be stored in a wrapper.
|
||||
@%wrapper : ::Spectator::Internals::ValueWrapper?
|
||||
|
||||
# Method for returning the value.
|
||||
def {{name.id}}
|
||||
# Check if the value is cached.
|
||||
# The wrapper will be `nil` if it isn't.
|
||||
# The wrapper will be nil if it isn't.
|
||||
if (wrapper = @%wrapper)
|
||||
# It is cached, return that value.
|
||||
# Unwrap it from the wrapper variable.
|
||||
# Here we use `typeof(METHOD)` to get around the issue
|
||||
# Here we use typeof to get around the issue
|
||||
# that the macro has no idea what type the value is.
|
||||
wrapper.unsafe_as(::Spectator::Internals::TypedValueWrapper(typeof(%value))).value
|
||||
else
|
||||
|
@ -1326,7 +1330,7 @@ module Spectator::DSL
|
|||
end
|
||||
|
||||
# Creates an example, or a test case.
|
||||
# The `what` argument describes "what" is being tested or asserted.
|
||||
# The *what* argument describes "what" is being tested or asserted.
|
||||
# The block contains the code to run the test.
|
||||
# One or more expectations should be in the block.
|
||||
#
|
||||
|
@ -1386,7 +1390,7 @@ module Spectator::DSL
|
|||
|
||||
# Creates an example, or a test case, that does not run.
|
||||
# This can be used to prototype functionality that isn't ready.
|
||||
# The `what` argument describes "what" is being tested or asserted.
|
||||
# The *what* argument describes "what" is being tested or asserted.
|
||||
# The block contains the code to run the test.
|
||||
# One or more expectations should be in the block.
|
||||
#
|
||||
|
@ -1422,7 +1426,7 @@ module Spectator::DSL
|
|||
end
|
||||
|
||||
# Same as `#pending`.
|
||||
# Include for compatibility with RSpec.
|
||||
# Included for compatibility with RSpec.
|
||||
macro xit(what, &block)
|
||||
pending({{what}}) {{block}}
|
||||
end
|
||||
|
@ -1435,8 +1439,8 @@ module Spectator::DSL
|
|||
#
|
||||
# Since the names are generated, and macros can't return values,
|
||||
# the names for everything must be passed in as arguments.
|
||||
# The `class_name` argument is the name of the class to define.
|
||||
# The `run_method_name` argument is the name of the method in the wrapper class
|
||||
# The *class_name* argument is the name of the class to define.
|
||||
# The *run_method_name* argument is the name of the method in the wrapper class
|
||||
# that will actually run the test code.
|
||||
# The block passed to this macro is the actual test code.
|
||||
private macro _spectator_test(class_name, run_method_name, &block)
|
||||
|
@ -1465,12 +1469,12 @@ module Spectator::DSL
|
|||
# Creates an example class.
|
||||
# Since the names are generated, and macros can't return values,
|
||||
# the names for everything must be passed in as arguments.
|
||||
# The `example_class_name` argument is the name of the class to define.
|
||||
# The `test_class_name` argument is the name of the wrapper class to reference.
|
||||
# The *example_class_name* argument is the name of the class to define.
|
||||
# The *test_class_name* argument is the name of the wrapper class to reference.
|
||||
# This must be the same as `class_name` for `#_spectator_example_wrapper`.
|
||||
# The `base_class` argument specifies which type of example class the new class should derive from.
|
||||
# The *base_class* argument specifies which type of example class the new class should derive from.
|
||||
# This should typically be `RunnableExample` or `PendingExample`.
|
||||
# The `what` argument is the description passed to the `#it` or `#pending` block.
|
||||
# The *what* argument is the description passed to the `#it` or `#pending` block.
|
||||
# And lastly, the block specified is any additional content to put in the class.
|
||||
# For instance, to define a method in the class, do it in the block.
|
||||
# ```
|
||||
|
|
|
@ -6,7 +6,7 @@ module Spectator
|
|||
# This is different from a "failed" result
|
||||
# in that the error was not from a failed expectation.
|
||||
class ErroredResult < FailedResult
|
||||
# Calls the `error` method on `interface` and passes `self`.
|
||||
# Calls the `error` method on *interface* and passes self.
|
||||
def call(interface)
|
||||
interface.error(self)
|
||||
end
|
||||
|
|
|
@ -2,7 +2,7 @@ require "./example_component"
|
|||
|
||||
module Spectator
|
||||
# Base class for all types of examples.
|
||||
# Concrete types must implement the `#run_inner`, `#what`, and `#instance` methods.
|
||||
# Concrete types must implement the `#run_impl, `#what`, `#instance`, and `#source` methods.
|
||||
abstract class Example < ExampleComponent
|
||||
# Indicates whether the example has already been run.
|
||||
getter? finished = false
|
||||
|
@ -31,7 +31,7 @@ module Spectator
|
|||
|
||||
# Creates the base of the example.
|
||||
# The group should be the example group the example belongs to.
|
||||
# The `sample_values` are passed to the example code.
|
||||
# The *sample_values* are passed to the example code.
|
||||
def initialize(@group, sample_values : Internals::SampleValues)
|
||||
end
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ module Spectator
|
|||
# Additionally, the indexer method (`#[]`) will index into sub-groups.
|
||||
#
|
||||
# This class also stores hooks to be associated with all examples in the group.
|
||||
# The hooks can be invoked by running one of the `#run_x_hooks` methods.
|
||||
# The hooks can be invoked by running the `#run_before_hooks` and `#run_after_hooks` methods.
|
||||
abstract class ExampleGroup < ExampleComponent
|
||||
include Enumerable(ExampleComponent)
|
||||
include Iterable(ExampleComponent)
|
||||
|
@ -90,7 +90,7 @@ module Spectator
|
|||
end
|
||||
|
||||
# Finds the example with the specified index in the children.
|
||||
# The `index` must be positive and within bounds (use `#check_bounds`).
|
||||
# The *index* must be positive and within bounds (use `#check_bounds`).
|
||||
private def find_nested(index)
|
||||
offset = index
|
||||
# Loop through each child
|
||||
|
@ -112,7 +112,7 @@ module Spectator
|
|||
# The remaining offset is passed along to the child.
|
||||
# If it's an `Example`, it returns itself.
|
||||
# Otherwise, the indexer repeats the process for the next child.
|
||||
# It should be impossible to get `nil` here,
|
||||
# It should be impossible to get nil here,
|
||||
# provided the bounds check and example counts are correct.
|
||||
child.not_nil![offset]
|
||||
end
|
||||
|
@ -122,22 +122,14 @@ module Spectator
|
|||
children.all?(&.finished?)
|
||||
end
|
||||
|
||||
# Runs all of the `before_all` and `before_each` hooks.
|
||||
# Runs all of the "before-each" and "before-all" hooks.
|
||||
# This should run prior to every example in the group.
|
||||
def run_before_hooks
|
||||
run_before_all_hooks
|
||||
run_before_each_hooks
|
||||
end
|
||||
|
||||
def run_pre_conditions
|
||||
@conditions.run_pre_conditions
|
||||
end
|
||||
|
||||
def run_post_conditions
|
||||
@conditions.run_post_conditions
|
||||
end
|
||||
|
||||
# Runs all of the `before_all` hooks.
|
||||
# Runs all of the "before-all" hooks.
|
||||
# This should run prior to any examples in the group.
|
||||
# The hooks will be run only once.
|
||||
# Subsequent calls to this method will do nothing.
|
||||
|
@ -147,20 +139,20 @@ module Spectator
|
|||
@before_all_hooks_run = true
|
||||
end
|
||||
|
||||
# Runs all of the `before_each` hooks.
|
||||
# Runs all of the "before-each" hooks.
|
||||
# This method should run prior to every example in the group.
|
||||
protected def run_before_each_hooks : Nil
|
||||
@hooks.run_before_each
|
||||
end
|
||||
|
||||
# Runs all of the `after_all` and `after_each` hooks.
|
||||
# Runs all of the "after-all" and "after-each" hooks.
|
||||
# This should run following every example in the group.
|
||||
def run_after_hooks
|
||||
run_after_each_hooks
|
||||
run_after_all_hooks
|
||||
end
|
||||
|
||||
# Runs all of the `after_all` hooks.
|
||||
# Runs all of the "after-all" hooks.
|
||||
# This should run following all examples in the group.
|
||||
# The hooks will be run only once,
|
||||
# and only after all examples in the group have finished.
|
||||
|
@ -172,18 +164,28 @@ module Spectator
|
|||
@after_all_hooks_run = true
|
||||
end
|
||||
|
||||
# Runs all of the `after_each` hooks.
|
||||
# Runs all of the "after-each" hooks.
|
||||
# This method should run following every example in the group.
|
||||
protected def run_after_each_hooks : Nil
|
||||
@hooks.run_after_each
|
||||
end
|
||||
|
||||
# Creates a proc that runs the `around_each` hooks
|
||||
# Creates a proc that runs the "around-each" hooks
|
||||
# in addition to a block passed to this method.
|
||||
# To call the block and all `around_each` hooks,
|
||||
# To call the block and all "around-each" hooks,
|
||||
# just invoke `Proc#call` on the returned proc.
|
||||
def wrap_around_each_hooks(&block : ->) : ->
|
||||
@hooks.wrap_around_each(&block)
|
||||
end
|
||||
|
||||
# Runs all of the pre-conditions for an example.
|
||||
def run_pre_conditions
|
||||
@conditions.run_pre_conditions
|
||||
end
|
||||
|
||||
# Runs all of the post-conditions for an example.
|
||||
def run_post_conditions
|
||||
@conditions.run_post_conditions
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -24,33 +24,33 @@ module Spectator
|
|||
)
|
||||
end
|
||||
|
||||
# Runs all `before_all` hooks.
|
||||
# Runs all "before-all" hooks.
|
||||
# These hooks should be run once before all examples in the group start.
|
||||
def run_before_all
|
||||
@before_all.each &.call
|
||||
end
|
||||
|
||||
# Runs all `before_each` hooks.
|
||||
# Runs all "before-each" hooks.
|
||||
# These hooks should be run every time before each example in a group.
|
||||
def run_before_each
|
||||
@before_each.each &.call
|
||||
end
|
||||
|
||||
# Runs all `after_all` hooks.
|
||||
# Runs all "after-all" hooks.
|
||||
# These hooks should be run once after all examples in group finish.
|
||||
def run_after_all
|
||||
@after_all.each &.call
|
||||
end
|
||||
|
||||
# Runs all `after_each` hooks.
|
||||
# Runs all "after-all" hooks.
|
||||
# These hooks should be run every time after each example in a group.
|
||||
def run_after_each
|
||||
@after_each.each &.call
|
||||
end
|
||||
|
||||
# Creates a proc that runs the `around_each` hooks
|
||||
# Creates a proc that runs the "around-each" hooks
|
||||
# in addition to a block passed to this method.
|
||||
# To call the block and all `around_each` hooks,
|
||||
# To call the block and all "around-each" hooks,
|
||||
# just invoke `Proc#call` on the returned proc.
|
||||
def wrap_around_each(&block : ->)
|
||||
wrapper = block
|
||||
|
|
|
@ -8,7 +8,7 @@ module Spectator
|
|||
@stack : Array(Iterator(ExampleComponent))
|
||||
|
||||
# Creates a new iterator.
|
||||
# The `group` is the example group to iterate through.
|
||||
# The *group* is the example group to iterate through.
|
||||
def initialize(@group : Iterable(ExampleComponent))
|
||||
iter = @group.each.as(Iterator(ExampleComponent))
|
||||
@stack = [iter]
|
||||
|
|
|
@ -16,7 +16,7 @@ module Spectator::Expectations
|
|||
end
|
||||
|
||||
# Creates the expectation partial.
|
||||
# The label is generated by calling `#to_s` on the block.
|
||||
# The label is generated by calling to_s on the block.
|
||||
# The block is stored for later use.
|
||||
protected def initialize(@block : -> ReturnType, source_file, source_line)
|
||||
super(@block.to_s, source_file, source_line)
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
module Spectator::Expectations
|
||||
# Ties together a partial, matcher, and their outcome.
|
||||
class Expectation
|
||||
# Populates the base portiion of the expectation with values.
|
||||
# The `matched` flag should be true if the matcher is satisfied with the partial.
|
||||
# The `negated` flag should be true if the expectation is inverted.
|
||||
# The *matched* flag should be true if the matcher is satisfied with the partial.
|
||||
# The *negated* flag should be true if the expectation is inverted.
|
||||
# These options are mutually-exclusive in this context.
|
||||
# Don't flip the value of `matched` because `negated` is true.
|
||||
# The `partial` and the `matcher` arguments should reference
|
||||
# Don't flip the value of *matched* because *negated* is true.
|
||||
# The *partial* and the *matcher* arguments should reference
|
||||
# the actual and expected result respectively.
|
||||
def initialize(@matched : Bool, @negated : Bool,
|
||||
@partial : ExpectationPartial, @matcher : Matchers::Matcher)
|
||||
|
|
|
@ -4,8 +4,6 @@ module Spectator::Expectations
|
|||
# The part of the expectation this class covers is the actual value.
|
||||
# This can also cover a block's behavior.
|
||||
# Sub-types of this class are returned by the `DSL::ExampleDSL.expect` call.
|
||||
# Sub-types are expected to implement `#eval`,
|
||||
# which returns a corresponding sub-type of `Expectation`.
|
||||
abstract struct ExpectationPartial
|
||||
# User-friendly string displayed for the actual expression being tested.
|
||||
# For instance, in the expectation:
|
||||
|
@ -27,13 +25,12 @@ module Spectator::Expectations
|
|||
private def initialize(@label, @source_file, @source_line)
|
||||
end
|
||||
|
||||
# Asserts that the `#actual` value matches some criteria.
|
||||
# The criteria is defined by the matcher passed to this method.
|
||||
# Asserts that some criteria defined by the matcher is satisfied.
|
||||
def to(matcher) : Nil
|
||||
report(eval(matcher))
|
||||
end
|
||||
|
||||
# Asserts that the `#actual` value *does not* match some criteria.
|
||||
# Asserts that some criteria defined by the matcher is not satisfied.
|
||||
# This is effectively the opposite of `#to`.
|
||||
def to_not(matcher) : Nil
|
||||
report(eval(matcher, true))
|
||||
|
|
|
@ -9,7 +9,7 @@ module Spectator::Expectations
|
|||
@expectations = Array(Expectation).new(1)
|
||||
|
||||
# Creates the reporter.
|
||||
# When the `raise_on_failure` flag is set to true,
|
||||
# When the *raise_on_failure* flag is set to true,
|
||||
# which is the default, an exception will be raised
|
||||
# on the first failure that is reported.
|
||||
# To store failures and continue, set the flag to false.
|
||||
|
|
|
@ -4,7 +4,7 @@ module Spectator::Expectations
|
|||
# Expectation partial variation that operates on a value.
|
||||
struct ValueExpectationPartial(ActualType) < ExpectationPartial
|
||||
# Actual value produced by the test.
|
||||
# This is the value passed to the `#expect` call.
|
||||
# This is the value passed to the `Spectator::DSL::ExampleDSL#expect` macro.
|
||||
getter actual
|
||||
|
||||
# Creates the expectation partial.
|
||||
|
@ -15,7 +15,7 @@ module Spectator::Expectations
|
|||
end
|
||||
|
||||
# Creates the expectation partial.
|
||||
# The label is generated by calling `#to_s` on the actual value.
|
||||
# The label is generated by calling `to_s` on the actual value.
|
||||
# The actual value is stored for later use.
|
||||
protected def initialize(@actual : ActualType, source_file, source_line)
|
||||
super(@actual.to_s, source_file, source_line)
|
||||
|
|
|
@ -10,16 +10,16 @@ module Spectator
|
|||
getter expectations : Expectations::ExampleExpectations
|
||||
|
||||
# Creates a failed result.
|
||||
# The `example` should refer to the example that was run
|
||||
# The *example* should refer to the example that was run
|
||||
# and that this result is for.
|
||||
# The `elapsed` argument is the length of time it took to run the example.
|
||||
# The `expectations` references the expectations that were checked in the example.
|
||||
# The `error` is the exception that was raised to cause the failure.
|
||||
# The *elapsed* argument is the length of time it took to run the example.
|
||||
# The *expectations* references the expectations that were checked in the example.
|
||||
# The *error* is the exception that was raised to cause the failure.
|
||||
def initialize(example, elapsed, @expectations, @error)
|
||||
super(example, elapsed)
|
||||
end
|
||||
|
||||
# Calls the `failure` method on `interface` and passes `self`.
|
||||
# Calls the `failure` method on *interface* and passes self.
|
||||
def call(interface)
|
||||
interface.failure(self)
|
||||
end
|
||||
|
|
|
@ -5,9 +5,9 @@ module Spectator
|
|||
getter elapsed : Time::Span
|
||||
|
||||
# Creates a successful result.
|
||||
# The `example` should refer to the example that was run
|
||||
# The *example* should refer to the example that was run
|
||||
# and that this result is for.
|
||||
# The `elapsed` argument is the length of time it took to run the example.
|
||||
# The *elapsed* argument is the length of time it took to run the example.
|
||||
def initialize(example, @elapsed)
|
||||
super(example)
|
||||
end
|
||||
|
|
|
@ -18,7 +18,7 @@ module Spectator::Formatters
|
|||
}
|
||||
|
||||
# Creates the formatter.
|
||||
# By default, output is sent to `STDOUT`.
|
||||
# By default, output is sent to STDOUT.
|
||||
def initialize(@io : IO = STDOUT)
|
||||
end
|
||||
|
||||
|
|
|
@ -14,8 +14,8 @@ module Spectator::Formatters
|
|||
# ```
|
||||
class FailureBlock
|
||||
# Creates the failure block.
|
||||
# The `index` uniquely identifies the failure in the output.
|
||||
# The `result` is the outcome of the failed example.
|
||||
# The *index* uniquely identifies the failure in the output.
|
||||
# The *result* is the outcome of the failed example.
|
||||
def initialize(@index : Int32, @result : FailedResult)
|
||||
end
|
||||
|
||||
|
@ -28,6 +28,10 @@ module Spectator::Formatters
|
|||
end
|
||||
|
||||
# Produces the title of the failure block.
|
||||
# The line takes the form:
|
||||
# ```text
|
||||
# 1) Example name
|
||||
# ```
|
||||
private def title(io)
|
||||
io << " "
|
||||
io << @index
|
||||
|
@ -37,6 +41,12 @@ module Spectator::Formatters
|
|||
end
|
||||
|
||||
# Produces the message line of the failure block.
|
||||
# The line takes the form:
|
||||
# ```text
|
||||
# Failure: Error message
|
||||
# ```
|
||||
# The indentation of this line starts directly under
|
||||
# the example name from the title line.
|
||||
private def message(io)
|
||||
io << " Failure: "
|
||||
io << @result.error
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
module Spectator::Internals
|
||||
# Helper class that acts as a gateway between example code and the test framework.
|
||||
# Every example run must be called with `#run`.
|
||||
# Every example must be invoked by passing it to `#run`.
|
||||
# This sets up the harness so that the example code can use it.
|
||||
# The test framework does the following:
|
||||
# ```
|
||||
|
@ -22,7 +22,7 @@ module Spectator::Internals
|
|||
# Wraps an example with a harness and runs the example.
|
||||
# The `#current` harness will be set
|
||||
# prior to running the example, and reset after.
|
||||
# The `example` argument will be the example to run.
|
||||
# The *example* argument will be the example to run.
|
||||
# The result returned from `Example#run` will be returned.
|
||||
def self.run(example : Example) : Result
|
||||
@@current = new(example)
|
||||
|
|
|
@ -2,7 +2,7 @@ require "./value_matcher"
|
|||
|
||||
module Spectator::Matchers
|
||||
# Matcher that tests that multiple attributes match specified conditions.
|
||||
# The attributes are tested with the `===` operator.
|
||||
# The attributes are tested with the === operator.
|
||||
# The `ExpectedType` type param should be a `NamedTuple`.
|
||||
struct AttributesMatcher(ExpectedType) < ValueMatcher(ExpectedType)
|
||||
# Determines whether the matcher is satisfied with the value given to it.
|
||||
|
|
|
@ -2,7 +2,7 @@ require "./value_matcher"
|
|||
|
||||
module Spectator::Matchers
|
||||
# Common matcher that tests whether two values semantically equal each other.
|
||||
# The values are compared with the `===` operator.
|
||||
# The values are compared with the === operator.
|
||||
struct CaseMatcher(ExpectedType) < ValueMatcher(ExpectedType)
|
||||
# Determines whether the matcher is satisfied with the value given to it.
|
||||
# True is returned if the match was successful, false otherwise.
|
||||
|
|
|
@ -2,7 +2,7 @@ require "./value_matcher"
|
|||
|
||||
module Spectator::Matchers
|
||||
# Matcher that tests whether a value, such as a `String` or `Array`, contains one or more values.
|
||||
# The values are checked with the `includes?` operator.
|
||||
# The values are checked with the `includes?` method.
|
||||
struct ContainMatcher(ExpectedType) < ValueMatcher(ExpectedType)
|
||||
# Determines whether the matcher is satisfied with the value given to it.
|
||||
# True is returned if the match was successful, false otherwise.
|
||||
|
|
|
@ -2,7 +2,7 @@ require "./matcher"
|
|||
|
||||
module Spectator::Matchers
|
||||
# Matcher that tests whether a collection is empty.
|
||||
# The values are checked with the `#empty?` method.
|
||||
# The values are checked with the `empty?` method.
|
||||
struct EmptyMatcher < Matcher
|
||||
# Creates the matcher.
|
||||
def initialize
|
||||
|
|
|
@ -2,7 +2,7 @@ require "./value_matcher"
|
|||
|
||||
module Spectator::Matchers
|
||||
# Common matcher that tests whether two values equal each other.
|
||||
# The values are compared with the `==` operator.
|
||||
# The values are compared with the == operator.
|
||||
struct EqualityMatcher(ExpectedType) < ValueMatcher(ExpectedType)
|
||||
# Determines whether the matcher is satisfied with the value given to it.
|
||||
# True is returned if the match was successful, false otherwise.
|
||||
|
|
|
@ -2,7 +2,7 @@ require "./value_matcher"
|
|||
|
||||
module Spectator::Matchers
|
||||
# Matcher that tests whether one value is greater than or equal to another.
|
||||
# The values are compared with the `>=` operator.
|
||||
# The values are compared with the >= operator.
|
||||
struct GreaterThanEqualMatcher(ExpectedType) < ValueMatcher(ExpectedType)
|
||||
# Determines whether the matcher is satisfied with the value given to it.
|
||||
# True is returned if the match was successful, false otherwise.
|
||||
|
|
|
@ -2,7 +2,7 @@ require "./value_matcher"
|
|||
|
||||
module Spectator::Matchers
|
||||
# Matcher that tests whether one value is greater than another.
|
||||
# The values are compared with the `>` operator.
|
||||
# The values are compared with the > operator.
|
||||
struct GreaterThanMatcher(ExpectedType) < ValueMatcher(ExpectedType)
|
||||
# Determines whether the matcher is satisfied with the value given to it.
|
||||
# True is returned if the match was successful, false otherwise.
|
||||
|
|
|
@ -3,7 +3,7 @@ require "./value_matcher"
|
|||
module Spectator::Matchers
|
||||
# Matcher that tests whether a value, such as a `String` or `Array`, matches one or more values.
|
||||
# For a `String`, the `includes?` method is used.
|
||||
# Otherwise, it expects an `Enumerable` and iterates over each item until `===` is true.
|
||||
# Otherwise, it expects an `Enumerable` and iterates over each item until === is true.
|
||||
struct HaveMatcher(ExpectedType) < ValueMatcher(ExpectedType)
|
||||
# Determines whether the matcher is satisfied with the value given to it.
|
||||
# True is returned if the match was successful, false otherwise.
|
||||
|
|
|
@ -2,7 +2,7 @@ require "./value_matcher"
|
|||
|
||||
module Spectator::Matchers
|
||||
# Matcher that tests whether two values do not equal each other.
|
||||
# The values are compared with the `!=` operator.
|
||||
# The values are compared with the != operator.
|
||||
struct InequalityMatcher(ExpectedType) < ValueMatcher(ExpectedType)
|
||||
# Determines whether the matcher is satisfied with the value given to it.
|
||||
# True is returned if the match was successful, false otherwise.
|
||||
|
|
|
@ -2,7 +2,7 @@ require "./value_matcher"
|
|||
|
||||
module Spectator::Matchers
|
||||
# Matcher that tests whether one value is less than or equal to another.
|
||||
# The values are compared with the `<=` operator.
|
||||
# The values are compared with the <= operator.
|
||||
struct LessThanEqualMatcher(ExpectedType) < ValueMatcher(ExpectedType)
|
||||
# Determines whether the matcher is satisfied with the value given to it.
|
||||
# True is returned if the match was successful, false otherwise.
|
||||
|
|
|
@ -2,7 +2,7 @@ require "./value_matcher"
|
|||
|
||||
module Spectator::Matchers
|
||||
# Matcher that tests whether one value is less than another.
|
||||
# The values are compared with the `<` operator.
|
||||
# The values are compared with the < operator.
|
||||
struct LessThanMatcher(ExpectedType) < ValueMatcher(ExpectedType)
|
||||
# Determines whether the matcher is satisfied with the value given to it.
|
||||
# True is returned if the match was successful, false otherwise.
|
||||
|
|
|
@ -2,7 +2,7 @@ require "./matcher"
|
|||
|
||||
module Spectator::Matchers
|
||||
# Common matcher that tests whether a value is nil.
|
||||
# The values are compared with the `#nil?` method.
|
||||
# The `Object#nil?` method is used for this.
|
||||
struct NilMatcher < Matcher
|
||||
# Creates the matcher.
|
||||
def initialize
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
require "./value_matcher"
|
||||
|
||||
module Spectator::Matchers
|
||||
# Matcher that tests one or more predicates (methods ending in `?`).
|
||||
# Matcher that tests one or more predicates (methods ending in '?').
|
||||
# The `ExpectedType` type param should be a `NamedTuple`.
|
||||
# Each key in the tuple is a predicate (without the `?`) to test.
|
||||
# Each key in the tuple is a predicate (without the '?') to test.
|
||||
struct PredicateMatcher(ExpectedType) < Matcher
|
||||
# Creates the matcher.
|
||||
# Constructs the label from the type parameters.
|
||||
|
|
|
@ -2,9 +2,9 @@ require "./value_matcher"
|
|||
|
||||
module Spectator::Matchers
|
||||
# Matcher that tests whether a value is in a given range or set of values.
|
||||
# The `#includes?` method is used for this check.
|
||||
# The `includes?` method is used for this check.
|
||||
# Typically this matcher uses a `Range`,
|
||||
# but any type that implements the `#includes?` method is supported.
|
||||
# but any type that implements the `includes?` method is supported.
|
||||
struct RangeMatcher(ExpectedType) < ValueMatcher(ExpectedType)
|
||||
# Determines whether the matcher is satisfied with the value given to it.
|
||||
# True is returned if the match was successful, false otherwise.
|
||||
|
@ -24,18 +24,17 @@ module Spectator::Matchers
|
|||
"Expected #{partial.label} to not be in #{label}"
|
||||
end
|
||||
|
||||
# Creates a new range matcher with bounds based off of `center`.
|
||||
# Creates a new range matcher with bounds based off of *center*.
|
||||
#
|
||||
# This method expects that the original matcher was created with a "difference" value.
|
||||
# That is:
|
||||
# ```
|
||||
# RangeMatcher.new(diff).of(center)
|
||||
# ```
|
||||
# This implies that `#match?` would not work on the original matcher.
|
||||
# This implies that the `match?` method would not work on the original matcher.
|
||||
#
|
||||
# The new range will be centered at `center`
|
||||
# and have lower and upper bounds
|
||||
# equal to `center - diff` and `center + diff` respectively.
|
||||
# The new range will be centered at *center*
|
||||
# and have upper and lower bounds equal to *center* plus and minux diff.
|
||||
# The range will be inclusive.
|
||||
def of(center)
|
||||
diff = @expected
|
||||
|
|
|
@ -2,7 +2,7 @@ require "./value_matcher"
|
|||
|
||||
module Spectator::Matchers
|
||||
# Matcher that tests whether a value matches a regular expression.
|
||||
# The value is compared with the `=~` operator.
|
||||
# The value is compared with the =~ operator.
|
||||
struct RegexMatcher(ExpectedType) < ValueMatcher(ExpectedType)
|
||||
# Determines whether the matcher is satisfied with the value given to it.
|
||||
# True is returned if the match was successful, false otherwise.
|
||||
|
|
|
@ -3,14 +3,14 @@ require "./value_matcher"
|
|||
module Spectator::Matchers
|
||||
# Matcher that tests whether a value is truthy or falsey.
|
||||
# Falsey means a value is considered false by an if-statement,
|
||||
# which are `false` and `nil` in Crystal.
|
||||
# which are false and nil in Crystal.
|
||||
# Truthy is the opposite of falsey.
|
||||
#
|
||||
# Additionally, different matchers can be created
|
||||
# by using the `#<`, `#<=`, `#>`, `#>=`, `#==`, and `#!=` operators.
|
||||
struct TruthyMatcher < ValueMatcher(Bool)
|
||||
# Creates the truthy matcher.
|
||||
# The `truthy` argument should be true to match "truthy" values,
|
||||
# The *truthy* argument should be true to match "truthy" values,
|
||||
# and false to match "falsey" values.
|
||||
def initialize(truthy : Bool)
|
||||
super(truthy ? "truthy" : "falsey", truthy)
|
||||
|
|
|
@ -2,7 +2,7 @@ require "./matcher"
|
|||
|
||||
module Spectator::Matchers
|
||||
# Matcher that tests a value is of a specified type.
|
||||
# The values are compared with the `#is_a?` method.
|
||||
# The values are compared with the `Object#is_a?` method.
|
||||
struct TypeMatcher(Expected) < Matcher
|
||||
# Creates the type matcher.
|
||||
# The `Expected` type param will be used to populate the underlying label.
|
||||
|
|
|
@ -3,8 +3,7 @@ require "./matcher"
|
|||
module Spectator::Matchers
|
||||
# Category of matcher that uses a value.
|
||||
# Matchers of this type expect that a SUT applies to the value in some way.
|
||||
# Sub-types must implement `#match?`, `#message`, and `#negated_message`.
|
||||
# Those methods accept a `ValueExpectationPartial` to work with.
|
||||
# Sub-types must implement `Matcher#match?`, `Matcher#message`, and `Matcher#negated_message`.
|
||||
abstract struct ValueMatcher(ExpectedType) < Matcher
|
||||
# Expected value.
|
||||
# Sub-types may use this value to test the expectation and generate message strings.
|
||||
|
|
|
@ -12,12 +12,12 @@ module Spectator
|
|||
getter parent : ExampleGroup
|
||||
|
||||
# Creates a new example group.
|
||||
# The `what` argument is a description from the user.
|
||||
# The `parent` should contain this group.
|
||||
# The *what* argument is a description from the user.
|
||||
# The *parent* should contain this group.
|
||||
# After creating this group, the parent's children should be updated.
|
||||
# The parent's children must contain this group,
|
||||
# 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)
|
||||
super(hooks, conditions)
|
||||
end
|
||||
|
@ -27,43 +27,53 @@ module Spectator
|
|||
@what.is_a?(Symbol)
|
||||
end
|
||||
|
||||
# Runs all of the `before_all` hooks.
|
||||
# Runs all of the "before-all" hooks.
|
||||
# This should run prior to any examples in the group.
|
||||
# The hooks will be run only once.
|
||||
# Subsequent calls to this method will do nothing.
|
||||
# Parent `before_all` hooks will be run first.
|
||||
# Parent "before-all" hooks will be run first.
|
||||
protected def run_before_all_hooks : Nil
|
||||
parent.run_before_all_hooks
|
||||
super
|
||||
end
|
||||
|
||||
# Runs all of the `before_each` hooks.
|
||||
# Runs all of the "before-each" hooks.
|
||||
# This method should run prior to every example in the group.
|
||||
# Parent `before_each` hooks will be run first.
|
||||
# Parent "before-each" hooks will be run first.
|
||||
protected def run_before_each_hooks : Nil
|
||||
parent.run_before_each_hooks
|
||||
super
|
||||
end
|
||||
|
||||
# Runs all of the `after_all` hooks.
|
||||
# Runs all of the "after-all" hooks.
|
||||
# This should run following all examples in the group.
|
||||
# The hooks will be run only once,
|
||||
# and only after all examples in the group have finished.
|
||||
# Subsequent calls after the hooks have been run will do nothing.
|
||||
# Parent `after_all` hooks will be run last.
|
||||
# Parent "after-all" hooks will be run last.
|
||||
protected def run_after_all_hooks : Nil
|
||||
super
|
||||
parent.run_after_all_hooks
|
||||
end
|
||||
|
||||
# Runs all of the `after_each` hooks.
|
||||
# Runs all of the "after-each" hooks.
|
||||
# This method should run following every example in the group.
|
||||
# Parent `after_each` hooks will be run last.
|
||||
# Parent "after-each" hooks will be run last.
|
||||
protected def run_after_each_hooks : Nil
|
||||
super
|
||||
parent.run_after_each_hooks
|
||||
end
|
||||
|
||||
# Creates a proc that runs the "around-each" hooks
|
||||
# in addition to a block passed to this method.
|
||||
# To call the block and all `around_each` hooks,
|
||||
# just invoke `Proc#call` on the returned proc.
|
||||
# Parent "around-each" hooks will be in the outermost wrappings.
|
||||
def wrap_around_each_hooks(&block : ->) : ->
|
||||
wrapper = super(&block)
|
||||
parent.wrap_around_each_hooks(&wrapper)
|
||||
end
|
||||
|
||||
# Runs all of the pre-condition checks.
|
||||
# This method should run prior to every example in the group.
|
||||
# Parent pre-conditions will be checked first.
|
||||
|
@ -80,20 +90,12 @@ module Spectator
|
|||
parent.run_post_conditions
|
||||
end
|
||||
|
||||
# Creates a proc that runs the `around_each` hooks
|
||||
# in addition to a block passed to this method.
|
||||
# To call the block and all `around_each` hooks,
|
||||
# just invoke `Proc#call` on the returned proc.
|
||||
# Parent `around_each` hooks will be in the outermost wrappings.
|
||||
def wrap_around_each_hooks(&block : ->) : ->
|
||||
wrapper = super(&block)
|
||||
parent.wrap_around_each_hooks(&wrapper)
|
||||
end
|
||||
|
||||
# Creates a string representation of the group.
|
||||
# The string consists of `#what` appended to the parent.
|
||||
# This results in a string like:
|
||||
# `Foo #bar does something`
|
||||
# ```text
|
||||
# Foo#bar does something
|
||||
# ```
|
||||
# for the following structure:
|
||||
# ```
|
||||
# describe Foo do
|
||||
|
|
|
@ -5,7 +5,7 @@ module Spectator
|
|||
# A pending result means the example is not ready to run yet.
|
||||
# This can happen when the functionality to be tested is not implemented yet.
|
||||
class PendingResult < Result
|
||||
# Calls the `pending` method on `interface` and passes `self`.
|
||||
# Calls the `pending` method on *interface* and passes self.
|
||||
def call(interface)
|
||||
interface.pending(self)
|
||||
end
|
||||
|
|
|
@ -6,8 +6,8 @@ module Spectator
|
|||
getter runtime : Time::Span
|
||||
|
||||
# Creates the report.
|
||||
# The `results` are from running the examples in the test suite.
|
||||
# The `runtime` is the total time it took to execute the suite.
|
||||
# The *results* are from running the examples in the test suite.
|
||||
# The *runtime* is the total time it took to execute the suite.
|
||||
def initialize(@results : Array(Result), @runtime)
|
||||
end
|
||||
|
||||
|
|
|
@ -6,14 +6,14 @@ module Spectator
|
|||
getter example : Example
|
||||
|
||||
# Constructs the base of the result.
|
||||
# The `example` should refer to the example that was run
|
||||
# The *example* should refer to the example that was run
|
||||
# and that this result is for.
|
||||
def initialize(@example)
|
||||
end
|
||||
|
||||
# Calls the corresponding method for the type of result.
|
||||
# This is used to avoid placing if or case-statements everywhere based on type.
|
||||
# Each sub-class implements this method by calling the correct method on `interface`.
|
||||
# Each sub-class implements this method by calling the correct method on *interface*.
|
||||
abstract def call(interface)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -50,7 +50,7 @@ module Spectator
|
|||
wrapper.call
|
||||
rescue ex
|
||||
# If an error occurs calling the wrapper,
|
||||
# it means it came from the `around_each` hooks.
|
||||
# it means it came from the "around-each" hooks.
|
||||
# This is because the test code is completely wrapped with a begin/rescue block.
|
||||
raise Exception.new("Error encountered while running around hooks", ex)
|
||||
end
|
||||
|
|
|
@ -2,7 +2,7 @@ module Spectator
|
|||
# Main driver for executing tests and feeding results to formatters.
|
||||
class Runner
|
||||
# Creates the test suite runner.
|
||||
# Specify the test `suite` to run and any additonal configuration.
|
||||
# Specify the test *suite* to run and any additonal configuration.
|
||||
def initialize(@suite : TestSuite, @config : Config)
|
||||
end
|
||||
|
||||
|
|
|
@ -32,7 +32,10 @@ module Spectator
|
|||
end
|
||||
|
||||
# String representation of the source.
|
||||
# This is formatted as `FILE:LINE`.
|
||||
# This is formatted as:
|
||||
# ```text
|
||||
# FILE:LINE
|
||||
# ```
|
||||
def to_s(io)
|
||||
io << path
|
||||
io << ':'
|
||||
|
|
|
@ -7,15 +7,15 @@ module Spectator
|
|||
getter expectations : Expectations::ExampleExpectations
|
||||
|
||||
# Creates a successful result.
|
||||
# The `example` should refer to the example that was run
|
||||
# The *example* should refer to the example that was run
|
||||
# and that this result is for.
|
||||
# The `elapsed` argument is the length of time it took to run the example.
|
||||
# The `expectations` references the expectations that were checked in the example.
|
||||
# The *elapsed* argument is the length of time it took to run the example.
|
||||
# The *expectations* references the expectations that were checked in the example.
|
||||
def initialize(example, elapsed, @expectations)
|
||||
super(example, elapsed)
|
||||
end
|
||||
|
||||
# Calls the `success` method on `interface` and passes `self`.
|
||||
# Calls the `success` method on *interface* and passes self.
|
||||
def call(interface)
|
||||
interface.success(self)
|
||||
end
|
||||
|
|
|
@ -5,7 +5,7 @@ module Spectator
|
|||
include Enumerable(Example)
|
||||
|
||||
# Creates the test suite.
|
||||
# The example `group` provided will be run.
|
||||
# The example *group* provided will be run.
|
||||
def initialize(@group : ExampleGroup)
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in a new issue