From 27f844ce25c51525ad9549bdd20b7ca5ea1930ab Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Tue, 30 Jul 2019 16:08:06 -0600 Subject: [PATCH 01/78] Remove abstract base match data Switching to a single type that holds the data.Trying to reduce the number of types and generic types generated. --- src/spectator/matchers/match_data.cr | 57 +++++++++++++--------------- 1 file changed, 26 insertions(+), 31 deletions(-) diff --git a/src/spectator/matchers/match_data.cr b/src/spectator/matchers/match_data.cr index 4595e33..4555674 100644 --- a/src/spectator/matchers/match_data.cr +++ b/src/spectator/matchers/match_data.cr @@ -1,46 +1,41 @@ require "./match_data_labeled_value" -require "./match_data_value" -require "./generic_match_data_value" module Spectator::Matchers - # Information regarding a expectation parial and matcher. - # `Matcher#match` will return a sub-type of this. - abstract struct MatchData + # Result of evaluating a matcher on an expectation partial. + # + # Procs are used to "store references" to the information. + # Most of the time, the information in this struct is unused. + # To reduce unecessary overhead and memory usage, + # the values are constructed lazily, on-demand when needed. + struct MatchData # Indicates whether the matcher was satisified with the expectation partial. getter? matched : Bool - # Creates the base of the match data. + # Extra information about the match that is shown in the result output. + getter values : Array(MatchDataLabeledValue) + + # Creates the match data. + # # The *matched* argument indicates # whether the matcher was satisified with the expectation partial. - def initialize(@matched) + # The *expected* and *actual* procs are what was expected to happen + # and what actually happened. + # They should write a string to the given IO. + # The *values* are extra information about the match, + # that is shown in the result output. + def initialize(@matched, @expected : IO -> , @actual : IO -> , @values) end - # Information about the match. - # Returned elments will differ by matcher, - # but all will return a set of labeled values. - def values : Array(MatchDataLabeledValue) - named_tuple.map do |key, value| - if value.is_a?(MatchDataValue) - MatchDataLabeledValue.new(key, value) - else - wrapper = GenericMatchDataValue.new(value) - MatchDataLabeledValue.new(key, wrapper) - end - end + # Description of what should have happened and would satisfy the matcher. + # This is informational and displayed to the end-user. + def expected + @expected.call end - # Raw information about the match. - # Sub-types must implement this and return a `NamedTuple` - # containing the match data values. - # This will be transformed and returned by `#values`. - private abstract def named_tuple - - # Describes the condition that satisfies the matcher. + # Description of what actually happened. # This is informational and displayed to the end-user. - abstract def message : String - - # Describes the condition that won't satsify the matcher. - # This is informational and displayed to the end-user. - abstract def negated_message : String + def actual + @actual.call + end end end From a06247bb1e4b9cbbb620ec1c382b91b4ac7f35e6 Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Tue, 30 Jul 2019 16:11:55 -0600 Subject: [PATCH 02/78] Change MatchData to Expectation After including negation into matcher logic, these types are equivalent. --- src/spectator/expectations/expectation.cr | 68 +++++++++++------------ src/spectator/matchers/match_data.cr | 41 -------------- 2 files changed, 34 insertions(+), 75 deletions(-) delete mode 100644 src/spectator/matchers/match_data.cr diff --git a/src/spectator/expectations/expectation.cr b/src/spectator/expectations/expectation.cr index 536aff0..6b59a72 100644 --- a/src/spectator/expectations/expectation.cr +++ b/src/spectator/expectations/expectation.cr @@ -1,52 +1,52 @@ module Spectator::Expectations - # Ties together a partial, matcher, and their outcome. - class Expectation - # Populates the base portiion of the expectation with values. - # The *negated* flag should be true if the expectation is inverted. - # The *match_data* is the value returned by `Spectator::Matcher#match` - # when the expectation was evaluated. - # The *negated* flag and `MatchData#matched?` flag - # are mutually-exclusive in this context. - def initialize(@match_data : Spectator::Matchers::MatchData, @negated : Bool) - end + # Result of evaluating a matcher on an expectation partial. + # + # Procs are used to "store references" to the information. + # Most of the time, the information in this struct is unused. + # To reduce unecessary overhead and memory usage, + # the values are constructed lazily, on-demand when needed. + struct Expectation + # Indicates whether the matcher was satisified with the expectation partial. + getter? matched : Bool - # Indicates whether the expectation was satisifed. - # This is true if: - # - The matcher was satisified and the expectation is not negated. - # - The matcher wasn't satisfied and the expectation is negated. + # ditto def satisfied? - @match_data.matched? ^ @negated + matched? end - # Information about the match. - # Returned value and type will something that has key-value pairs (like a `NamedTuple`). - def values - @match_data.values.tap do |labeled_values| - if @negated - labeled_values.each do |labeled_value| - value = labeled_value.value - value.negate - end - end - end + # Extra information about the match that is shown in the result output. + getter values : Array(MatchDataLabeledValue) + + # Creates the expectation (match data). + # + # The *matched* argument indicates + # whether the matcher was satisified with the expectation partial. + # The *expected* and *actual* procs are what was expected to happen + # and what actually happened. + # They should write a string to the given IO. + # The *values* are extra information about the match, + # that is shown in the result output. + def initialize(@matched, @expected : IO -> , @actual : IO -> , @values) end - # Text that indicates the condition that must be met for the expectation to be satisifed. - def expected_message - @negated ? @match_data.negated_message : @match_data.message + # Description of what should have happened and would satisfy the matcher. + # This is informational and displayed to the end-user. + def expected + @expected.call end - # Text that indicates what the outcome was. - def actual_message - @match_data.matched? ? @match_data.message : @match_data.negated_message + # Description of what actually happened. + # This is informational and displayed to the end-user. + def actual + @actual.call end # Creates the JSON representation of the expectation. def to_json(json : ::JSON::Builder) json.object do json.field("satisfied", satisfied?) - json.field("expected", expected_message) - json.field("actual", actual_message) + json.field("expected", expected) + json.field("actual", actual) json.field("values") do json.object do values.each do |labeled_value| diff --git a/src/spectator/matchers/match_data.cr b/src/spectator/matchers/match_data.cr deleted file mode 100644 index 4555674..0000000 --- a/src/spectator/matchers/match_data.cr +++ /dev/null @@ -1,41 +0,0 @@ -require "./match_data_labeled_value" - -module Spectator::Matchers - # Result of evaluating a matcher on an expectation partial. - # - # Procs are used to "store references" to the information. - # Most of the time, the information in this struct is unused. - # To reduce unecessary overhead and memory usage, - # the values are constructed lazily, on-demand when needed. - struct MatchData - # Indicates whether the matcher was satisified with the expectation partial. - getter? matched : Bool - - # Extra information about the match that is shown in the result output. - getter values : Array(MatchDataLabeledValue) - - # Creates the match data. - # - # The *matched* argument indicates - # whether the matcher was satisified with the expectation partial. - # The *expected* and *actual* procs are what was expected to happen - # and what actually happened. - # They should write a string to the given IO. - # The *values* are extra information about the match, - # that is shown in the result output. - def initialize(@matched, @expected : IO -> , @actual : IO -> , @values) - end - - # Description of what should have happened and would satisfy the matcher. - # This is informational and displayed to the end-user. - def expected - @expected.call - end - - # Description of what actually happened. - # This is informational and displayed to the end-user. - def actual - @actual.call - end - end -end From ab1c0269e00a0c293cb773c49998adb2cca2ad08 Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Tue, 30 Jul 2019 16:13:48 -0600 Subject: [PATCH 03/78] Remove DummyMatchData No longer needed since MatchData was changed to non-abstract. --- src/spectator/matchers/dummy_match_data.cr | 32 ---------------------- 1 file changed, 32 deletions(-) delete mode 100644 src/spectator/matchers/dummy_match_data.cr diff --git a/src/spectator/matchers/dummy_match_data.cr b/src/spectator/matchers/dummy_match_data.cr deleted file mode 100644 index 4a6a693..0000000 --- a/src/spectator/matchers/dummy_match_data.cr +++ /dev/null @@ -1,32 +0,0 @@ -module Spectator::Matchers - # Match data that does nothing. - # This is to workaround a Crystal compiler bug. - # See: [Issue 4225](https://github.com/crystal-lang/crystal/issues/4225) - # If there are no concrete implementations of an abstract class, - # the compiler gives an error. - # The error indicates an abstract method is undefined. - # This class shouldn't be used, it's just to trick the compiler. - private struct DummyMatchData < MatchData - # Creates the match data. - def initialize - super(false) - end - - # Dummy values. - def named_tuple - { - you: "shouldn't be calling this.", - } - end - - # Dummy message. - def message - "You shouldn't be calling this." - end - - # Dummy message - def negated_message - "You shouldn't be calling this." - end - end -end From e95c81f46e817fad0e189bd6a61a92742ef6dd23 Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Tue, 30 Jul 2019 16:19:27 -0600 Subject: [PATCH 04/78] Pass negation flag to matcher Some matchers need to know if they're negated to work properly and can't be simply negated afterwards. --- src/spectator/expectations/expectation_partial.cr | 10 ++-------- src/spectator/matchers/array_matcher.cr | 3 +-- src/spectator/matchers/attributes_matcher.cr | 3 +-- src/spectator/matchers/case_matcher.cr | 3 +-- src/spectator/matchers/collection_matcher.cr | 3 +-- src/spectator/matchers/contain_matcher.cr | 3 +-- src/spectator/matchers/empty_matcher.cr | 3 +-- src/spectator/matchers/end_with_matcher.cr | 3 +-- src/spectator/matchers/equality_matcher.cr | 3 +-- src/spectator/matchers/exception_matcher.cr | 3 +-- src/spectator/matchers/greater_than_equal_matcher.cr | 3 +-- src/spectator/matchers/greater_than_matcher.cr | 3 +-- src/spectator/matchers/have_key_matcher.cr | 3 +-- src/spectator/matchers/have_matcher.cr | 3 +-- src/spectator/matchers/have_predicate_matcher.cr | 3 +-- src/spectator/matchers/have_value_matcher.cr | 3 +-- src/spectator/matchers/inequality_matcher.cr | 3 +-- src/spectator/matchers/less_than_equal_matcher.cr | 3 +-- src/spectator/matchers/less_than_matcher.cr | 3 +-- src/spectator/matchers/matcher.cr | 5 ++--- src/spectator/matchers/nil_matcher.cr | 3 +-- src/spectator/matchers/predicate_matcher.cr | 3 +-- src/spectator/matchers/range_matcher.cr | 3 +-- src/spectator/matchers/reference_matcher.cr | 3 +-- src/spectator/matchers/respond_matcher.cr | 3 +-- src/spectator/matchers/size_matcher.cr | 3 +-- src/spectator/matchers/size_of_matcher.cr | 3 +-- src/spectator/matchers/start_with_matcher.cr | 3 +-- src/spectator/matchers/truthy_matcher.cr | 3 +-- src/spectator/matchers/type_matcher.cr | 3 +-- src/spectator/matchers/unordered_array_matcher.cr | 3 +-- 31 files changed, 33 insertions(+), 69 deletions(-) diff --git a/src/spectator/expectations/expectation_partial.cr b/src/spectator/expectations/expectation_partial.cr index 0238a8e..bed48d8 100644 --- a/src/spectator/expectations/expectation_partial.cr +++ b/src/spectator/expectations/expectation_partial.cr @@ -27,13 +27,13 @@ module Spectator::Expectations # Asserts that some criteria defined by the matcher is satisfied. def to(matcher) : Nil - report(eval(matcher)) + report(matcher.match(self, false)) end # 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)) + report(matcher.match(self, true)) end # ditto @@ -42,12 +42,6 @@ module Spectator::Expectations to_not(matcher) end - # Evaluates the expectation and returns it. - private def eval(matcher, negated = false) - match_data = matcher.match(self) - Expectation.new(match_data, negated) - end - # Reports an expectation to the current harness. private def report(expectation : Expectation) Internals::Harness.current.report_expectation(expectation) diff --git a/src/spectator/matchers/array_matcher.cr b/src/spectator/matchers/array_matcher.cr index df29b9a..3857806 100644 --- a/src/spectator/matchers/array_matcher.cr +++ b/src/spectator/matchers/array_matcher.cr @@ -6,8 +6,7 @@ module Spectator::Matchers # has the exact same contents as another and in the same order. struct ArrayMatcher(ExpectedType) < ValueMatcher(Enumerable(ExpectedType)) # Determines whether the matcher is satisfied with the partial given to it. - # `MatchData` is returned that contains information about the match. - def match(partial) + def match(partial, negated = false) actual = partial.actual.to_a expected_elements = expected.to_a values = ExpectedActual.new(expected_elements, label, actual, partial.label) diff --git a/src/spectator/matchers/attributes_matcher.cr b/src/spectator/matchers/attributes_matcher.cr index 12e7d49..d7088ed 100644 --- a/src/spectator/matchers/attributes_matcher.cr +++ b/src/spectator/matchers/attributes_matcher.cr @@ -17,8 +17,7 @@ module Spectator::Matchers end # Determines whether the matcher is satisfied with the partial given to it. - # `MatchData` is returned that contains information about the match. - def match(partial) + def match(partial, negated = false) actual_values = snapshot_values(partial.actual) values = ExpectedActual.new(expected, label, actual_values, partial.label) MatchData.new(match?(actual_values), values) diff --git a/src/spectator/matchers/case_matcher.cr b/src/spectator/matchers/case_matcher.cr index d321468..8aa727c 100644 --- a/src/spectator/matchers/case_matcher.cr +++ b/src/spectator/matchers/case_matcher.cr @@ -10,8 +10,7 @@ module Spectator::Matchers end # Determines whether the matcher is satisfied with the partial given to it. - # `MatchData` is returned that contains information about the match. - def match(partial) + def match(partial, negated = false) values = ExpectedActual.new(partial, self) MatchData.new(match?(values.actual), values) end diff --git a/src/spectator/matchers/collection_matcher.cr b/src/spectator/matchers/collection_matcher.cr index f57d46c..47fcd2f 100644 --- a/src/spectator/matchers/collection_matcher.cr +++ b/src/spectator/matchers/collection_matcher.cr @@ -9,8 +9,7 @@ module Spectator::Matchers end # Determines whether the matcher is satisfied with the partial given to it. - # `MatchData` is returned that contains information about the match. - def match(partial) + def match(partial, negated = false) actual = partial.actual matched = match?(actual) MatchData.new(matched, ExpectedActual.new(partial, self)) diff --git a/src/spectator/matchers/contain_matcher.cr b/src/spectator/matchers/contain_matcher.cr index 739d1e9..cdcd2a9 100644 --- a/src/spectator/matchers/contain_matcher.cr +++ b/src/spectator/matchers/contain_matcher.cr @@ -12,8 +12,7 @@ module Spectator::Matchers end # Determines whether the matcher is satisfied with the partial given to it. - # `MatchData` is returned that contains information about the match. - def match(partial) + def match(partial, negated = false) values = ExpectedActual.new(partial, self) MatchData.new(match?(values.actual), values) end diff --git a/src/spectator/matchers/empty_matcher.cr b/src/spectator/matchers/empty_matcher.cr index b477ec4..0db1e3c 100644 --- a/src/spectator/matchers/empty_matcher.cr +++ b/src/spectator/matchers/empty_matcher.cr @@ -10,8 +10,7 @@ module Spectator::Matchers end # Determines whether the matcher is satisfied with the partial given to it. - # `MatchData` is returned that contains information about the match. - def match(partial) + def match(partial, negated = false) actual = partial.actual matched = actual.empty? MatchData.new(matched, actual, partial.label) diff --git a/src/spectator/matchers/end_with_matcher.cr b/src/spectator/matchers/end_with_matcher.cr index 92655d5..63d9fa4 100644 --- a/src/spectator/matchers/end_with_matcher.cr +++ b/src/spectator/matchers/end_with_matcher.cr @@ -16,8 +16,7 @@ module Spectator::Matchers end # Determines whether the matcher is satisfied with the partial given to it. - # `MatchData` is returned that contains information about the match. - def match(partial) + def match(partial, negated = false) values = ExpectedActual.new(partial, self) actual = values.actual if actual.responds_to?(:ends_with?) diff --git a/src/spectator/matchers/equality_matcher.cr b/src/spectator/matchers/equality_matcher.cr index 0e97e60..79128f0 100644 --- a/src/spectator/matchers/equality_matcher.cr +++ b/src/spectator/matchers/equality_matcher.cr @@ -10,8 +10,7 @@ module Spectator::Matchers end # Determines whether the matcher is satisfied with the partial given to it. - # `MatchData` is returned that contains information about the match. - def match(partial) + def match(partial, negated = false) values = ExpectedActual.new(partial, self) MatchData.new(match?(values.actual), values) end diff --git a/src/spectator/matchers/exception_matcher.cr b/src/spectator/matchers/exception_matcher.cr index 066922c..738281e 100644 --- a/src/spectator/matchers/exception_matcher.cr +++ b/src/spectator/matchers/exception_matcher.cr @@ -21,8 +21,7 @@ module Spectator::Matchers end # Determines whether the matcher is satisfied with the partial given to it. - # `MatchData` is returned that contains information about the match. - def match(partial) + def match(partial, negated = false) exception = capture_exception { partial.actual } matched = match?(exception) if exception.nil? diff --git a/src/spectator/matchers/greater_than_equal_matcher.cr b/src/spectator/matchers/greater_than_equal_matcher.cr index 4ac07aa..9adb4b2 100644 --- a/src/spectator/matchers/greater_than_equal_matcher.cr +++ b/src/spectator/matchers/greater_than_equal_matcher.cr @@ -10,8 +10,7 @@ module Spectator::Matchers end # Determines whether the matcher is satisfied with the partial given to it. - # `MatchData` is returned that contains information about the match. - def match(partial) + def match(partial, negated = false) values = ExpectedActual.new(partial, self) MatchData.new(match?(values.actual), values) end diff --git a/src/spectator/matchers/greater_than_matcher.cr b/src/spectator/matchers/greater_than_matcher.cr index a96947e..b382a94 100644 --- a/src/spectator/matchers/greater_than_matcher.cr +++ b/src/spectator/matchers/greater_than_matcher.cr @@ -10,8 +10,7 @@ module Spectator::Matchers end # Determines whether the matcher is satisfied with the partial given to it. - # `MatchData` is returned that contains information about the match. - def match(partial) + def match(partial, negated = false) values = ExpectedActual.new(partial, self) MatchData.new(match?(values.actual), values) end diff --git a/src/spectator/matchers/have_key_matcher.cr b/src/spectator/matchers/have_key_matcher.cr index c27743a..16b92cd 100644 --- a/src/spectator/matchers/have_key_matcher.cr +++ b/src/spectator/matchers/have_key_matcher.cr @@ -10,8 +10,7 @@ module Spectator::Matchers end # Determines whether the matcher is satisfied with the partial given to it. - # `MatchData` is returned that contains information about the match. - def match(partial) + def match(partial, negated = false) values = ExpectedActual.new(partial, self) MatchData.new(match?(values.actual), values) end diff --git a/src/spectator/matchers/have_matcher.cr b/src/spectator/matchers/have_matcher.cr index 7fb2a99..06f827d 100644 --- a/src/spectator/matchers/have_matcher.cr +++ b/src/spectator/matchers/have_matcher.cr @@ -35,8 +35,7 @@ module Spectator::Matchers end # Determines whether the matcher is satisfied with the partial given to it. - # `MatchData` is returned that contains information about the match. - def match(partial) + def match(partial, negated = false) values = ExpectedActual.new(partial, self) MatchData.new(match?(values.actual), values) end diff --git a/src/spectator/matchers/have_predicate_matcher.cr b/src/spectator/matchers/have_predicate_matcher.cr index bba32ae..45aaaf0 100644 --- a/src/spectator/matchers/have_predicate_matcher.cr +++ b/src/spectator/matchers/have_predicate_matcher.cr @@ -19,8 +19,7 @@ module Spectator::Matchers end # Determines whether the matcher is satisfied with the partial given to it. - # `MatchData` is returned that contains information about the match. - def match(partial) : MatchData + def match(partial, negated = false) values = snapshot_values(partial.actual) MatchData.new(match?(values), values, partial.label, label) end diff --git a/src/spectator/matchers/have_value_matcher.cr b/src/spectator/matchers/have_value_matcher.cr index a59d1f4..3d0cf8c 100644 --- a/src/spectator/matchers/have_value_matcher.cr +++ b/src/spectator/matchers/have_value_matcher.cr @@ -10,8 +10,7 @@ module Spectator::Matchers end # Determines whether the matcher is satisfied with the partial given to it. - # `MatchData` is returned that contains information about the match. - def match(partial) + def match(partial, negated = false) values = ExpectedActual.new(partial, self) MatchData.new(match?(values.actual), values) end diff --git a/src/spectator/matchers/inequality_matcher.cr b/src/spectator/matchers/inequality_matcher.cr index 71010fb..dad2548 100644 --- a/src/spectator/matchers/inequality_matcher.cr +++ b/src/spectator/matchers/inequality_matcher.cr @@ -10,8 +10,7 @@ module Spectator::Matchers end # Determines whether the matcher is satisfied with the partial given to it. - # `MatchData` is returned that contains information about the match. - def match(partial) + def match(partial, negated = false) values = ExpectedActual.new(partial, self) MatchData.new(match?(values.actual), values) end diff --git a/src/spectator/matchers/less_than_equal_matcher.cr b/src/spectator/matchers/less_than_equal_matcher.cr index ff3fc10..73e8ca5 100644 --- a/src/spectator/matchers/less_than_equal_matcher.cr +++ b/src/spectator/matchers/less_than_equal_matcher.cr @@ -10,8 +10,7 @@ module Spectator::Matchers end # Determines whether the matcher is satisfied with the partial given to it. - # `MatchData` is returned that contains information about the match. - def match(partial) + def match(partial, negated = false) values = ExpectedActual.new(partial, self) MatchData.new(match?(values.actual), values) end diff --git a/src/spectator/matchers/less_than_matcher.cr b/src/spectator/matchers/less_than_matcher.cr index 3cb12e6..b9663c3 100644 --- a/src/spectator/matchers/less_than_matcher.cr +++ b/src/spectator/matchers/less_than_matcher.cr @@ -10,8 +10,7 @@ module Spectator::Matchers end # Determines whether the matcher is satisfied with the partial given to it. - # `MatchData` is returned that contains information about the match. - def match(partial) + def match(partial, negated = false) values = ExpectedActual.new(partial, self) MatchData.new(match?(values.actual), values) end diff --git a/src/spectator/matchers/matcher.cr b/src/spectator/matchers/matcher.cr index 8586918..c72e409 100644 --- a/src/spectator/matchers/matcher.cr +++ b/src/spectator/matchers/matcher.cr @@ -10,8 +10,7 @@ module Spectator::Matchers # but for verbose output to help the end-user. abstract def label : String - # Determines whether the matcher is satisfied with the value given to it. - # True is returned if the match was successful, false otherwise. - abstract def match(partial) : MatchData + # Determines whether the matcher is satisfied with the partial given to it. + def match(partial, negated = false) : Expectation end end diff --git a/src/spectator/matchers/nil_matcher.cr b/src/spectator/matchers/nil_matcher.cr index fd5021b..1619143 100644 --- a/src/spectator/matchers/nil_matcher.cr +++ b/src/spectator/matchers/nil_matcher.cr @@ -10,8 +10,7 @@ module Spectator::Matchers end # Determines whether the matcher is satisfied with the partial given to it. - # `MatchData` is returned that contains information about the match. - def match(partial) + def match(partial, negated = false) actual = partial.actual matched = actual.nil? MatchData.new(matched, actual, partial.label) diff --git a/src/spectator/matchers/predicate_matcher.cr b/src/spectator/matchers/predicate_matcher.cr index 1abd791..2b0391b 100644 --- a/src/spectator/matchers/predicate_matcher.cr +++ b/src/spectator/matchers/predicate_matcher.cr @@ -18,8 +18,7 @@ module Spectator::Matchers end # Determines whether the matcher is satisfied with the partial given to it. - # `MatchData` is returned that contains information about the match. - def match(partial) : MatchData + def match(partial, negated = false) values = snapshot_values(partial.actual) MatchData.new(match?(values), values, partial.label, label) end diff --git a/src/spectator/matchers/range_matcher.cr b/src/spectator/matchers/range_matcher.cr index ad05da3..edc498c 100644 --- a/src/spectator/matchers/range_matcher.cr +++ b/src/spectator/matchers/range_matcher.cr @@ -10,8 +10,7 @@ module Spectator::Matchers end # Determines whether the matcher is satisfied with the partial given to it. - # `MatchData` is returned that contains information about the match. - def match(partial) + def match(partial, negated = false) actual = partial.actual matched = match?(actual) expected_value = @expected diff --git a/src/spectator/matchers/reference_matcher.cr b/src/spectator/matchers/reference_matcher.cr index 1463a2a..3c0b9e4 100644 --- a/src/spectator/matchers/reference_matcher.cr +++ b/src/spectator/matchers/reference_matcher.cr @@ -10,8 +10,7 @@ module Spectator::Matchers end # Determines whether the matcher is satisfied with the partial given to it. - # `MatchData` is returned that contains information about the match. - def match(partial) + def match(partial, negated = false) values = ExpectedActual.new(partial, self) MatchData.new(match?(values.actual), values) end diff --git a/src/spectator/matchers/respond_matcher.cr b/src/spectator/matchers/respond_matcher.cr index 4c0e4a0..ad0868d 100644 --- a/src/spectator/matchers/respond_matcher.cr +++ b/src/spectator/matchers/respond_matcher.cr @@ -14,8 +14,7 @@ module Spectator::Matchers end # Determines whether the matcher is satisfied with the partial given to it. - # `MatchData` is returned that contains information about the match. - def match(partial) + def match(partial, negated = false) values = snapshot_values(partial.actual) MatchData.new(match?(values), values, partial.label, label) end diff --git a/src/spectator/matchers/size_matcher.cr b/src/spectator/matchers/size_matcher.cr index 7295acf..9e2a399 100644 --- a/src/spectator/matchers/size_matcher.cr +++ b/src/spectator/matchers/size_matcher.cr @@ -5,8 +5,7 @@ module Spectator::Matchers # The set's `#size` method is used for this check. struct SizeMatcher(ExpectedType) < ValueMatcher(ExpectedType) # Determines whether the matcher is satisfied with the partial given to it. - # `MatchData` is returned that contains information about the match. - def match(partial) + def match(partial, negated = false) actual = partial.actual.size values = ExpectedActual.new(expected, label, actual, partial.label) MatchData.new(actual == expected, values) diff --git a/src/spectator/matchers/size_of_matcher.cr b/src/spectator/matchers/size_of_matcher.cr index 334a93d..d500d20 100644 --- a/src/spectator/matchers/size_of_matcher.cr +++ b/src/spectator/matchers/size_of_matcher.cr @@ -5,8 +5,7 @@ module Spectator::Matchers # The set's `#size` method is used for this check. struct SizeOfMatcher(ExpectedType) < ValueMatcher(ExpectedType) # Determines whether the matcher is satisfied with the partial given to it. - # `MatchData` is returned that contains information about the match. - def match(partial) + def match(partial, negated = false) actual = partial.actual.size size = expected.size values = ExpectedActual.new(size, label, actual, partial.label) diff --git a/src/spectator/matchers/start_with_matcher.cr b/src/spectator/matchers/start_with_matcher.cr index 6ece475..2a4eba9 100644 --- a/src/spectator/matchers/start_with_matcher.cr +++ b/src/spectator/matchers/start_with_matcher.cr @@ -16,8 +16,7 @@ module Spectator::Matchers end # Determines whether the matcher is satisfied with the partial given to it. - # `MatchData` is returned that contains information about the match. - def match(partial) + def match(partial, negated = false) values = ExpectedActual.new(partial, self) actual = values.actual if actual.responds_to?(:starts_with?) diff --git a/src/spectator/matchers/truthy_matcher.cr b/src/spectator/matchers/truthy_matcher.cr index 7eac541..4663c5e 100644 --- a/src/spectator/matchers/truthy_matcher.cr +++ b/src/spectator/matchers/truthy_matcher.cr @@ -27,8 +27,7 @@ module Spectator::Matchers end # Determines whether the matcher is satisfied with the partial given to it. - # `MatchData` is returned that contains information about the match. - def match(partial) + def match(partial, negated = false) actual = partial.actual MatchData.new(match?(actual), @truthy, actual, partial.label) end diff --git a/src/spectator/matchers/type_matcher.cr b/src/spectator/matchers/type_matcher.cr index a072b6d..0b58c2f 100644 --- a/src/spectator/matchers/type_matcher.cr +++ b/src/spectator/matchers/type_matcher.cr @@ -16,8 +16,7 @@ module Spectator::Matchers end # Determines whether the matcher is satisfied with the partial given to it. - # `MatchData` is returned that contains information about the match. - def match(partial) + def match(partial, negated = false) actual = partial.actual MatchData(Expected, typeof(actual)).new(match?(actual), actual, partial.label) end diff --git a/src/spectator/matchers/unordered_array_matcher.cr b/src/spectator/matchers/unordered_array_matcher.cr index d84adad..cb13a34 100644 --- a/src/spectator/matchers/unordered_array_matcher.cr +++ b/src/spectator/matchers/unordered_array_matcher.cr @@ -5,8 +5,7 @@ module Spectator::Matchers # has the exact same contents as another, but in any order. struct UnorderedArrayMatcher(ExpectedType) < ValueMatcher(Enumerable(ExpectedType)) # Determines whether the matcher is satisfied with the partial given to it. - # `MatchData` is returned that contains information about the match. - def match(partial) + def match(partial, negated = false) expected_elements = expected.to_a actual = partial.actual.to_a missing, extra = array_diff(expected, actual) From 42b916bdf72eb6f7420d108488879833703ff7a5 Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Wed, 31 Jul 2019 20:01:39 -0600 Subject: [PATCH 05/78] New "actual" types --- src/spectator/expectations/actual.cr | 23 +++++++++++++++++ src/spectator/expectations/block_actual.cr | 30 ++++++++++++++++++++++ src/spectator/expectations/value_actual.cr | 27 +++++++++++++++++++ 3 files changed, 80 insertions(+) create mode 100644 src/spectator/expectations/actual.cr create mode 100644 src/spectator/expectations/block_actual.cr create mode 100644 src/spectator/expectations/value_actual.cr diff --git a/src/spectator/expectations/actual.cr b/src/spectator/expectations/actual.cr new file mode 100644 index 0000000..a62a11a --- /dev/null +++ b/src/spectator/expectations/actual.cr @@ -0,0 +1,23 @@ +module Spectator::Expectations + # Base class for capturing an actual value - the thing being checked/tested. + abstract struct Actual + # User-friendly string displayed for the actual expression being tested. + # For instance, in the expectation: + # ``` + # expect(foo).to eq(bar) + # ``` + # This property will be "foo". + # It will be the literal string "foo", + # and not the actual value of the foo. + getter label : String + + # Creates the common base of the actual value. + def initialize(@label) + end + + # String representation of the actual value. + def to_s(io) + io << label + end + end +end diff --git a/src/spectator/expectations/block_actual.cr b/src/spectator/expectations/block_actual.cr new file mode 100644 index 0000000..aad9afd --- /dev/null +++ b/src/spectator/expectations/block_actual.cr @@ -0,0 +1,30 @@ +require "./actual" + +module Spectator::Expectations + # Captures an actual block and its label. + struct BlockActual(ReturnType) < Actual + # Calls the block and retrieves the value. + def value : ReturnType + @proc.call + end + + # Creates the actual with a custom label. + # Typically the label is the code in the block/proc. + def initialize(label : String, @proc : -> ReturnType) + super(label) + end + + # Creates the actual with a generic label. + # This is used for the "should" syntax and when the label doesn't matter. + def initialize(@proc : -> ReturnType) + super("") + end + + # Reports complete information about the actual value. + def inspect(io) + io << label + io << " -> " + io << value + end + end +end diff --git a/src/spectator/expectations/value_actual.cr b/src/spectator/expectations/value_actual.cr new file mode 100644 index 0000000..c5a6de4 --- /dev/null +++ b/src/spectator/expectations/value_actual.cr @@ -0,0 +1,27 @@ +require "./actual" + +module Spectator::Expectations + # Captures an actual value and its label. + struct ValueActual(T) < Actual + # Actual value. + getter value : T + + # Creates the actual with a custom label. + def initialize(label : String, @value) + super(label) + end + + # Creates the actual with a stringified value. + # This is used for the "should" syntax and when the label doesn't matter. + def initialize(@value) + super(@value.to_s) + end + + # Reports complete information about the actual value. + def inspect(io) + io << label + io << '=' + io << @value + end + end +end From 3a7dc7299aa80673857dbd6bd182d8857e5a128f Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Wed, 31 Jul 2019 20:11:30 -0600 Subject: [PATCH 06/78] Rewrite ExpectationPartial and remove sub-types The partial now contains the actual and source. It also calls the correct match method on the matcher and constructs an expectation (which needs to be updated). --- .../expectations/block_expectation_partial.cr | 25 ---------- .../expectations/expectation_partial.cr | 50 ++++++++----------- .../expectations/value_expectation_partial.cr | 24 --------- src/spectator/matchers/matcher.cr | 48 +++++++++++++++--- 4 files changed, 61 insertions(+), 86 deletions(-) delete mode 100644 src/spectator/expectations/block_expectation_partial.cr delete mode 100644 src/spectator/expectations/value_expectation_partial.cr diff --git a/src/spectator/expectations/block_expectation_partial.cr b/src/spectator/expectations/block_expectation_partial.cr deleted file mode 100644 index 3adbec7..0000000 --- a/src/spectator/expectations/block_expectation_partial.cr +++ /dev/null @@ -1,25 +0,0 @@ -require "./expectation_partial" - -module Spectator::Expectations - # Expectation partial variation that operates on a block. - struct BlockExpectationPartial(ReturnType) < ExpectationPartial - # Actual value produced by calling the block. - def actual - @block.call - end - - # Creates the expectation partial. - # The label should be a string representation of the block. - # The block is stored for later use. - def initialize(@block : Proc(ReturnType), label, source_file, source_line) - super(label, source_file, source_line) - end - - # Creates the expectation partial. - # The label is generated by calling to_s on the block. - # The block is stored for later use. - def initialize(@block : Proc(ReturnType), source_file, source_line) - super("", source_file, source_line) - end - end -end diff --git a/src/spectator/expectations/expectation_partial.cr b/src/spectator/expectations/expectation_partial.cr index 0238a8e..177bc94 100644 --- a/src/spectator/expectations/expectation_partial.cr +++ b/src/spectator/expectations/expectation_partial.cr @@ -1,39 +1,34 @@ +require "../matchers/match_data" +require "../source" +require "./actual" + module Spectator::Expectations - # Base class for all expectation partials. - # An "expectation partial" stores part of an expectation (obviously). - # The part of the expectation this class covers is the actual value. + # Stores part of an expectation (obviously). + # The part of the expectation this type covers is the actual value and source. # This can also cover a block's behavior. - # Sub-types of this class are returned by the `DSL::ExampleDSL.expect` call. - abstract struct ExpectationPartial - # User-friendly string displayed for the actual expression being tested. - # For instance, in the expectation: - # ``` - # expect(foo).to eq(bar) - # ``` - # This property will be "foo". - # It will be the literal string "foo", - # and not the actual value of the foo. - getter label : String + struct ExpectationPartial + # The actual value being tested. + # This also contains its label. + getter actual : Actual - # Source file the expectation originated from. - getter source_file : String + # Location where this expectation was defined. + getter source : Source - # Line number in the source file the expectation originated from. - getter source_line : Int32 - - # Creates the base of the partial. - private def initialize(@label, @source_file, @source_line) + # Creates the partial. + def initialize(@actual, @source) end # Asserts that some criteria defined by the matcher is satisfied. def to(matcher) : Nil - report(eval(matcher)) + match_data = matcher.match(@actual) + report(match_data) end # 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)) + match_data = matcher.negated_match(@actual) + report(match_data) end # ditto @@ -42,14 +37,9 @@ module Spectator::Expectations to_not(matcher) end - # Evaluates the expectation and returns it. - private def eval(matcher, negated = false) - match_data = matcher.match(self) - Expectation.new(match_data, negated) - end - # Reports an expectation to the current harness. - private def report(expectation : Expectation) + private def report(match_data : Matchers::MatchData) + expectation = Expectation.new(match_data, @source) Internals::Harness.current.report_expectation(expectation) end end diff --git a/src/spectator/expectations/value_expectation_partial.cr b/src/spectator/expectations/value_expectation_partial.cr deleted file mode 100644 index 791bce5..0000000 --- a/src/spectator/expectations/value_expectation_partial.cr +++ /dev/null @@ -1,24 +0,0 @@ -require "./expectation_partial" - -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 `Spectator::DSL::ExampleDSL#expect` macro. - getter actual - - # Creates the expectation partial. - # The label should be a string representation of the actual value. - # The actual value is stored for later use. - def initialize(@actual : ActualType, label, source_file, source_line) - super(label, source_file, source_line) - end - - # Creates the expectation partial. - # The label is generated by calling `to_s` on the actual value. - # The actual value is stored for later use. - def initialize(@actual : ActualType, source_file, source_line) - super(@actual.to_s, source_file, source_line) - end - end -end diff --git a/src/spectator/matchers/matcher.cr b/src/spectator/matchers/matcher.cr index 8586918..a054de1 100644 --- a/src/spectator/matchers/matcher.cr +++ b/src/spectator/matchers/matcher.cr @@ -5,13 +5,47 @@ module Spectator::Matchers # A matcher looks at something produced by the SUT # and evaluates whether it is correct or not. abstract struct Matcher - # Textual representation of what the matcher expects. - # This shouldn't be used in the conditional logic, - # but for verbose output to help the end-user. - abstract def label : String + # Short text about the matcher's purpose. + # This explains what condition satisfies the matcher. + # The description is used when the one-liner syntax is used. + # ``` + # it { is_expected.to do_something } + # ``` + # The phrasing should be such that it reads "it ___." + abstract def description : String - # Determines whether the matcher is satisfied with the value given to it. - # True is returned if the match was successful, false otherwise. - abstract def match(partial) : MatchData + # Message displayed when the matcher isn't satisifed. + # This is only called when `#matches?` returns false. + abstract def failure_message : String + + # Message displayed when the matcher isn't satisifed and is negated. + # This is only called when `#does_not_match?` returns false. + # + # A default implementation of this method is provided, + # which causes compilation to fail. + # If the matcher supports negation, it must override this method. + def failure_message_when_negated : String + {% raise "Negation with #{@type.name} is not supported."} + end + + # Checks whether the matcher is satisifed. + private abstract def match?(actual) : Bool + + # If the expectation is negated, then this method is called instead of `#match?`. + # The default implementation of this method is to invert the result of `#match?`. + # If the matcher requires custom handling of negated matches, + # then this method should be overriden. + # Remember to override `#failure_message_when_negated` as well. + private def does_not_match?(actual) : Bool + !matches?(actual) + end + + def match(actual) + matched = match?(actual) + end + + def negated_match(actual) + matched = does_not_match?(actual) + end end end From ae43c930bf9dd2f6c38ba782fa091d1154111bea Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Thu, 1 Aug 2019 13:49:08 -0600 Subject: [PATCH 07/78] Replace MatchDataValue types with a single LabeledValue --- .../matchers/alternative_match_data_value.cr | 32 --------------- .../matchers/generic_match_data_value.cr | 23 ----------- src/spectator/matchers/labeled_value.cr | 10 +++++ src/spectator/matchers/match_data_value.cr | 10 ----- .../matchers/negatable_match_data_value.cr | 34 ---------------- .../negatable_prefixed_match_data_value.cr | 39 ------------------- .../matchers/prefixed_match_data_value.cr | 27 ------------- 7 files changed, 10 insertions(+), 165 deletions(-) delete mode 100644 src/spectator/matchers/alternative_match_data_value.cr delete mode 100644 src/spectator/matchers/generic_match_data_value.cr create mode 100644 src/spectator/matchers/labeled_value.cr delete mode 100644 src/spectator/matchers/match_data_value.cr delete mode 100644 src/spectator/matchers/negatable_match_data_value.cr delete mode 100644 src/spectator/matchers/negatable_prefixed_match_data_value.cr delete mode 100644 src/spectator/matchers/prefixed_match_data_value.cr diff --git a/src/spectator/matchers/alternative_match_data_value.cr b/src/spectator/matchers/alternative_match_data_value.cr deleted file mode 100644 index b600312..0000000 --- a/src/spectator/matchers/alternative_match_data_value.cr +++ /dev/null @@ -1,32 +0,0 @@ -require "./match_data_value" - -module Spectator::Matchers - # Selects a value based on whether the value is negated. - # This is used when a matcher is negated. - private class AlternativeMatchDataValue(T1, T2) < MatchDataValue - # Creates the wrapper. - def initialize(@value1 : T1, @value2 : T2) - @negated = false - end - - # Negates (toggles) the value. - def negate - @negated = !@negated - end - - # Returns the correct value based on the negated status. - def value - @negated ? @value2 : @value1 - end - - # Produces a stringified value. - def to_s(io) - io << value - end - - # Produces a stringified value with additional information. - def inspect(io) - io << value - end - end -end diff --git a/src/spectator/matchers/generic_match_data_value.cr b/src/spectator/matchers/generic_match_data_value.cr deleted file mode 100644 index 9069489..0000000 --- a/src/spectator/matchers/generic_match_data_value.cr +++ /dev/null @@ -1,23 +0,0 @@ -require "./match_data_value" - -module Spectator::Matchers - # Wraps a value for used in match data. - private class GenericMatchDataValue(T) < MatchDataValue - # Underlying value. - getter value - - # Creates the wrapper. - def initialize(@value : T) - end - - # Stringifies the value. - def to_s(io) - @value.inspect(io) - end - - # Inspects the value. - def inspect(io) - @value.inspect(io) - end - end -end diff --git a/src/spectator/matchers/labeled_value.cr b/src/spectator/matchers/labeled_value.cr new file mode 100644 index 0000000..3a8c6be --- /dev/null +++ b/src/spectator/matchers/labeled_value.cr @@ -0,0 +1,10 @@ +module Spectator::Matchers + struct LabeledValue + getter label : Symbol + + getter value : String + + def initialize(@label, @value) + end + end +end diff --git a/src/spectator/matchers/match_data_value.cr b/src/spectator/matchers/match_data_value.cr deleted file mode 100644 index 21629fd..0000000 --- a/src/spectator/matchers/match_data_value.cr +++ /dev/null @@ -1,10 +0,0 @@ -module Spectator::Matchers - # Abstract base for all match data values. - # All sub-classes are expected to implement their own `#to_s`. - private abstract class MatchDataValue - # Placeholder for negating the value. - def negate - # ... - end - end -end diff --git a/src/spectator/matchers/negatable_match_data_value.cr b/src/spectator/matchers/negatable_match_data_value.cr deleted file mode 100644 index 62abf49..0000000 --- a/src/spectator/matchers/negatable_match_data_value.cr +++ /dev/null @@ -1,34 +0,0 @@ -require "./match_data_value" - -module Spectator::Matchers - # Wraps an expected value that can be negated. - # This is used when a matcher is negated. - private class NegatableMatchDataValue(T) < MatchDataValue - # Negatable value. - getter value - - # Creates the wrapper. - def initialize(@value : T) - @negated = false - end - - # Negates (toggles) the value. - def negate - @negated = !@negated - end - - # Produces a stringified value. - # The string will be prefixed with "Not" when negated. - def to_s(io) - io << "Not " if @negated - @value.inspect(io) - end - - # Produces a stringified value with additional information. - # The string will be prefixed with "Not" when negated. - def inspect(io) - io << "Not " if @negated - @value.inspect(io) - end - end -end diff --git a/src/spectator/matchers/negatable_prefixed_match_data_value.cr b/src/spectator/matchers/negatable_prefixed_match_data_value.cr deleted file mode 100644 index 9cc6138..0000000 --- a/src/spectator/matchers/negatable_prefixed_match_data_value.cr +++ /dev/null @@ -1,39 +0,0 @@ -require "./match_data_value" - -module Spectator::Matchers - # Wraps a prefixed value that can be negated. - # This is used when a matcher is negated. - private class NegatablePrefixedMatchDataValue(T) < MatchDataValue - # Negatable value. - getter value - - # Creates the wrapper. - def initialize(@positive_prefix : String, @negative_prefix : String, @value : T) - @negated = false - end - - # Negates (toggles) the value. - def negate - @negated = !@negated - end - - # Returns the correct prefix based on the negated status. - private def prefix - @negated ? @negative_prefix : @positive_prefix - end - - # Produces a stringified value. - def to_s(io) - io << prefix - io << ' ' - @value.inspect(io) - end - - # Produces a stringified value with additional information. - def inspect(io) - io << prefix - io << ' ' - @value.inspect(io) - end - end -end diff --git a/src/spectator/matchers/prefixed_match_data_value.cr b/src/spectator/matchers/prefixed_match_data_value.cr deleted file mode 100644 index feea8cc..0000000 --- a/src/spectator/matchers/prefixed_match_data_value.cr +++ /dev/null @@ -1,27 +0,0 @@ -require "./match_data_value" - -module Spectator::Matchers - # Prefixes (for output formatting) an actual or expected value. - private class PrefixedMatchDataValue(T) < MatchDataValue - # Value being prefixed. - getter value : T - - # Creates the prefixed value. - def initialize(@prefix : String, @value : T) - end - - # Outputs the formatted value with a prefix. - def to_s(io) - io << @prefix - io << ' ' - @value.inspect(io) - end - - # Outputs details of the formatted value with a prefix. - def inspect(io) - io << @prefix - io << ' ' - @prefix.inspect(io) - end - end -end From acd01a23e6825b264132df89dc069274d27a4640 Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Thu, 1 Aug 2019 14:04:00 -0600 Subject: [PATCH 08/78] Re-add MatchData and variants --- src/spectator/matchers/failed_match_data.cr | 17 +++++++++++++++++ src/spectator/matchers/match_data.cr | 5 +++++ src/spectator/matchers/successful_match_data.cr | 9 +++++++++ 3 files changed, 31 insertions(+) create mode 100644 src/spectator/matchers/failed_match_data.cr create mode 100644 src/spectator/matchers/match_data.cr create mode 100644 src/spectator/matchers/successful_match_data.cr diff --git a/src/spectator/matchers/failed_match_data.cr b/src/spectator/matchers/failed_match_data.cr new file mode 100644 index 0000000..5855de5 --- /dev/null +++ b/src/spectator/matchers/failed_match_data.cr @@ -0,0 +1,17 @@ +require "./labeled_value" +require "./match_data" + +module Spectator::Matchers + struct FailedMatchData < MatchData + def matched? + false + end + + getter failure_message : String + + getter values : Array(LabeledValue) + + def initialize(@failure_message, @values = [] of LabeledValue) + end + end +end diff --git a/src/spectator/matchers/match_data.cr b/src/spectator/matchers/match_data.cr new file mode 100644 index 0000000..321e27a --- /dev/null +++ b/src/spectator/matchers/match_data.cr @@ -0,0 +1,5 @@ +module Spectator::Matchers + abstract struct MatchData + abstract def matched? : Bool + end +end diff --git a/src/spectator/matchers/successful_match_data.cr b/src/spectator/matchers/successful_match_data.cr new file mode 100644 index 0000000..b4cdb5a --- /dev/null +++ b/src/spectator/matchers/successful_match_data.cr @@ -0,0 +1,9 @@ +require "./match_data" + +module Spectator::Matchers + struct SuccessfulMatchData < MatchData + def matched? + true + end + end +end From 96f2888b88ac57e46616074902892b48c7d1ff6e Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Thu, 1 Aug 2019 14:05:05 -0600 Subject: [PATCH 09/78] Fully implement match methods Add placeholders for matcher values. --- src/spectator/matchers/matcher.cr | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/spectator/matchers/matcher.cr b/src/spectator/matchers/matcher.cr index a054de1..ef0c457 100644 --- a/src/spectator/matchers/matcher.cr +++ b/src/spectator/matchers/matcher.cr @@ -1,4 +1,5 @@ -require "./match_data" +require "./failed_matched_data" +require "./successful_match_data" module Spectator::Matchers # Common base class for all expectation conditions. @@ -40,12 +41,28 @@ module Spectator::Matchers !matches?(actual) end + private def values(actual) : Array(LabeledValue) + [LabeledValue.new(:actual, actual.value)] + end + + private def negated_values(actual) : Array(LabeledValue) + values + end + def match(actual) - matched = match?(actual) + if match?(actual) + SuccessfulMatchData.new + else + FailedMatchData.new(failure_message, values) + end end def negated_match(actual) - matched = does_not_match?(actual) + if does_not_match?(actual) + SuccessfulMatchData.new + else + FailedMatchData.new(failure_message_when_negated, negated_values) + end end end end From 10cf7bbb776a613a1ed4c04180430fc6e682695c Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Thu, 1 Aug 2019 14:05:27 -0600 Subject: [PATCH 10/78] Update Expectation to use new MatchData --- src/spectator/expectations/expectation.cr | 75 ++++++++++++----------- 1 file changed, 38 insertions(+), 37 deletions(-) diff --git a/src/spectator/expectations/expectation.cr b/src/spectator/expectations/expectation.cr index 6b59a72..1f787dc 100644 --- a/src/spectator/expectations/expectation.cr +++ b/src/spectator/expectations/expectation.cr @@ -1,57 +1,58 @@ +require "../matchers/failed_matched_data" +require "../matchers/match_data" +require "../source" + module Spectator::Expectations # Result of evaluating a matcher on an expectation partial. - # - # Procs are used to "store references" to the information. - # Most of the time, the information in this struct is unused. - # To reduce unecessary overhead and memory usage, - # the values are constructed lazily, on-demand when needed. struct Expectation - # Indicates whether the matcher was satisified with the expectation partial. - getter? matched : Bool + # Location where this expectation was defined. + getter source : Source + + # Creates the expectation. + def initialize(@match_data : MatchData, @source : Source) + end - # ditto def satisfied? - matched? + @match_data.matched? end - # Extra information about the match that is shown in the result output. - getter values : Array(MatchDataLabeledValue) - - # Creates the expectation (match data). - # - # The *matched* argument indicates - # whether the matcher was satisified with the expectation partial. - # The *expected* and *actual* procs are what was expected to happen - # and what actually happened. - # They should write a string to the given IO. - # The *values* are extra information about the match, - # that is shown in the result output. - def initialize(@matched, @expected : IO -> , @actual : IO -> , @values) + def failure? + !satisfied? end - # Description of what should have happened and would satisfy the matcher. - # This is informational and displayed to the end-user. - def expected - @expected.call + def failure_message? + @match_data.as?(FailedMatchData).try(&.failure_message) end - # Description of what actually happened. - # This is informational and displayed to the end-user. - def actual - @actual.call + def failure_message + @match_data.as(FailedMatchData).failure_message + end + + def values? + @match_data.as?(FailedMatchData).try(&.values) + end + + def values + @match_data.as(FailedMatchData).values end # Creates the JSON representation of the expectation. def to_json(json : ::JSON::Builder) json.object do + json.field("source") { @source.to_json(json) } json.field("satisfied", satisfied?) - json.field("expected", expected) - json.field("actual", actual) - json.field("values") do - json.object do - values.each do |labeled_value| - json.field(labeled_value.label, labeled_value.value.to_s) - end + if (failed = @match_data.as?(FailedMatchData)) + failed_to_json(failed, json) + end + end + end + + private def failed_to_json(failed : FailedMatchData, json : ::JSON::Builder) + json.field("failure", failed.failure_message) + json.field("values") do + json.object do + failed.values.each do |pair| + json.field(pair.label, pair.value) end end end From ba1c37b142f3567418a05f67a98b3c11da96bb71 Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Thu, 1 Aug 2019 14:46:13 -0600 Subject: [PATCH 11/78] Fix macro --- src/spectator/matchers/matcher.cr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/spectator/matchers/matcher.cr b/src/spectator/matchers/matcher.cr index ef0c457..bd1e4af 100644 --- a/src/spectator/matchers/matcher.cr +++ b/src/spectator/matchers/matcher.cr @@ -26,7 +26,7 @@ module Spectator::Matchers # which causes compilation to fail. # If the matcher supports negation, it must override this method. def failure_message_when_negated : String - {% raise "Negation with #{@type.name} is not supported."} + {% raise "Negation with #{@type.name} is not supported." %} end # Checks whether the matcher is satisifed. From 96c271cf33326fed5d2c749f53634e24ad5eacc1 Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Thu, 1 Aug 2019 14:46:47 -0600 Subject: [PATCH 12/78] No need to shout --- src/spectator/expectations/block_actual.cr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/spectator/expectations/block_actual.cr b/src/spectator/expectations/block_actual.cr index aad9afd..512ce3e 100644 --- a/src/spectator/expectations/block_actual.cr +++ b/src/spectator/expectations/block_actual.cr @@ -17,7 +17,7 @@ module Spectator::Expectations # Creates the actual with a generic label. # This is used for the "should" syntax and when the label doesn't matter. def initialize(@proc : -> ReturnType) - super("") + super("") end # Reports complete information about the actual value. From 79a095bb3106bec2eb2c174d5a1d918c2a0afad8 Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Thu, 1 Aug 2019 15:00:56 -0600 Subject: [PATCH 13/78] Use new style expectations and actuals in DSL --- src/spectator/dsl/example_dsl.cr | 11 ++++++++--- src/spectator/should.cr | 16 ++++++++++++---- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/spectator/dsl/example_dsl.cr b/src/spectator/dsl/example_dsl.cr index f518b53..87261c6 100644 --- a/src/spectator/dsl/example_dsl.cr +++ b/src/spectator/dsl/example_dsl.cr @@ -19,7 +19,9 @@ module Spectator::DSL # Where the actual value is returned by the system-under-test, # and the expected value is what the actual value should be to satisfy the condition. macro expect(actual, _source_file = __FILE__, _source_line = __LINE__) - ::Spectator::Expectations::ValueExpectationPartial.new({{actual}}, {{actual.stringify}}, {{_source_file}}, {{_source_line}}) + value_actual = ::Spectator::Expectations::ValueActual.new({{actual.stringify}}, {{actual}}) + source = ::Spectator::Source.new({{_source_file}}, {{_source_line}}) + ::Spectator::Expectations::ExpectationPartial.new(value_actual, source) end # Starts an expectation on a block of code. @@ -68,12 +70,15 @@ module Spectator::DSL # The raw block can't be used because it's not clear to the user. {% method_name = block.body.id.split('.')[1..-1].join('.') %} %partial = %proc.partial(subject) - ::Spectator::Expectations::BlockExpectationPartial.new(%partial, {{"#" + method_name}}, {{_source_file}}, {{_source_line}}) + block_actual = ::Spectator::Expectations::ValueActual.new({{"#" + method_name}}, %partial) {% else %} # In this case, it looks like the short-hand method syntax wasn't used. # Just drop in the proc as-is. - ::Spectator::Expectations::BlockExpectationPartial.new(%proc, "`" + {{block.body.stringify}} + "`", {{_source_file}}, {{_source_line}}) + block_actual = ::Spectator::Expectations::ValueActual.new({{"`" + block.body.stringify + "`"}}, %proc) {% end %} + + source = ::Spectator::Source.new({{_source_file}}, {{_source_line}}) + ::Spectator::Expectations::ExpectationPartial.new(block_actual, source) end # Starts an expectation. diff --git a/src/spectator/should.cr b/src/spectator/should.cr index 2cfcf2d..0653a0e 100644 --- a/src/spectator/should.cr +++ b/src/spectator/should.cr @@ -21,13 +21,17 @@ class Object # However, since this isn't a macro and we can't "look behind" this method call # to see what it was invoked on, the argument is an empty string. # Additionally, the source file and line can't be obtained. - ::Spectator::Expectations::ValueExpectationPartial.new(self, __FILE__, __LINE__).to(matcher) + actual = ::Spectator::Expectations::ValueActual.new(self) + source = ::Spectator::Source.new(__FILE__, __LINE__) + ::Spectator::Expectations::ExpectationPartial.new(actual, source).to(matcher) end # Works the same as `#should` except the condition is inverted. # When `#should` succeeds, this method will fail, and vice-versa. def should_not(matcher : ::Spectator::Matchers::Matcher) - ::Spectator::Expectations::ValueExpectationPartial.new(self, __FILE__, __LINE__).to_not(matcher) + actual = ::Spectator::Expectations::ValueActual.new(self) + source = ::Spectator::Source.new(__FILE__, __LINE__) + ::Spectator::Expectations::ExpectationPartial.new(actual, source).to_not(matcher) end end @@ -35,12 +39,16 @@ struct Proc(*T, R) # Extension method to create an expectation for a block of code (proc). # Depending on the matcher, the proc may be executed multiple times. def should(matcher : ::Spectator::Matchers::Matcher) - ::Spectator::Expectations::BlockExpectationPartial.new(self, __FILE__, __LINE__).to(matcher) + actual = ::Spectator::Expectations::BlockActual.new(self) + source = ::Spectator::Source.new(__FILE__, __LINE__) + ::Spectator::Expectations::ExpectationPartial.new(actual, source).to(matcher) end # Works the same as `#should` except the condition is inverted. # When `#should` succeeds, this method will fail, and vice-versa. def should_not(matcher : ::Spectator::Matchers::Matcher) - ::Spectator::Expectations::BlockExpectationPartial.new(self, __FILE__, __LINE__).to_not(matcher) + actual = ::Spectator::Expectations::BlockActual.new(self) + source = ::Spectator::Source.new(__FILE__, __LINE__) + ::Spectator::Expectations::BlockExpectationPartial.new(actual, source).to_not(matcher) end end From 28680fa8491855933461a36e4a70a9bd03451d0a Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Thu, 1 Aug 2019 15:22:18 -0600 Subject: [PATCH 14/78] Rename Actual types to be more "human" sounding --- src/spectator/dsl/example_dsl.cr | 6 +++--- .../expectations/{block_actual.cr => actual_block.cr} | 2 +- .../expectations/{value_actual.cr => actual_value.cr} | 2 +- src/spectator/should.cr | 8 ++++---- 4 files changed, 9 insertions(+), 9 deletions(-) rename src/spectator/expectations/{block_actual.cr => actual_block.cr} (94%) rename src/spectator/expectations/{value_actual.cr => actual_value.cr} (94%) diff --git a/src/spectator/dsl/example_dsl.cr b/src/spectator/dsl/example_dsl.cr index 87261c6..611c3fb 100644 --- a/src/spectator/dsl/example_dsl.cr +++ b/src/spectator/dsl/example_dsl.cr @@ -19,7 +19,7 @@ module Spectator::DSL # Where the actual value is returned by the system-under-test, # and the expected value is what the actual value should be to satisfy the condition. macro expect(actual, _source_file = __FILE__, _source_line = __LINE__) - value_actual = ::Spectator::Expectations::ValueActual.new({{actual.stringify}}, {{actual}}) + value_actual = ::Spectator::Expectations::ActualValue.new({{actual.stringify}}, {{actual}}) source = ::Spectator::Source.new({{_source_file}}, {{_source_line}}) ::Spectator::Expectations::ExpectationPartial.new(value_actual, source) end @@ -70,11 +70,11 @@ module Spectator::DSL # The raw block can't be used because it's not clear to the user. {% method_name = block.body.id.split('.')[1..-1].join('.') %} %partial = %proc.partial(subject) - block_actual = ::Spectator::Expectations::ValueActual.new({{"#" + method_name}}, %partial) + block_actual = ::Spectator::Expectations::ActualValue.new({{"#" + method_name}}, %partial) {% else %} # In this case, it looks like the short-hand method syntax wasn't used. # Just drop in the proc as-is. - block_actual = ::Spectator::Expectations::ValueActual.new({{"`" + block.body.stringify + "`"}}, %proc) + block_actual = ::Spectator::Expectations::ActualValue.new({{"`" + block.body.stringify + "`"}}, %proc) {% end %} source = ::Spectator::Source.new({{_source_file}}, {{_source_line}}) diff --git a/src/spectator/expectations/block_actual.cr b/src/spectator/expectations/actual_block.cr similarity index 94% rename from src/spectator/expectations/block_actual.cr rename to src/spectator/expectations/actual_block.cr index 512ce3e..b1b77d6 100644 --- a/src/spectator/expectations/block_actual.cr +++ b/src/spectator/expectations/actual_block.cr @@ -2,7 +2,7 @@ require "./actual" module Spectator::Expectations # Captures an actual block and its label. - struct BlockActual(ReturnType) < Actual + struct ActualBlock(ReturnType) < Actual # Calls the block and retrieves the value. def value : ReturnType @proc.call diff --git a/src/spectator/expectations/value_actual.cr b/src/spectator/expectations/actual_value.cr similarity index 94% rename from src/spectator/expectations/value_actual.cr rename to src/spectator/expectations/actual_value.cr index c5a6de4..eaa542f 100644 --- a/src/spectator/expectations/value_actual.cr +++ b/src/spectator/expectations/actual_value.cr @@ -2,7 +2,7 @@ require "./actual" module Spectator::Expectations # Captures an actual value and its label. - struct ValueActual(T) < Actual + struct ActualValue(T) < Actual # Actual value. getter value : T diff --git a/src/spectator/should.cr b/src/spectator/should.cr index 0653a0e..d8f0316 100644 --- a/src/spectator/should.cr +++ b/src/spectator/should.cr @@ -21,7 +21,7 @@ class Object # However, since this isn't a macro and we can't "look behind" this method call # to see what it was invoked on, the argument is an empty string. # Additionally, the source file and line can't be obtained. - actual = ::Spectator::Expectations::ValueActual.new(self) + actual = ::Spectator::Expectations::ActualValue.new(self) source = ::Spectator::Source.new(__FILE__, __LINE__) ::Spectator::Expectations::ExpectationPartial.new(actual, source).to(matcher) end @@ -29,7 +29,7 @@ class Object # Works the same as `#should` except the condition is inverted. # When `#should` succeeds, this method will fail, and vice-versa. def should_not(matcher : ::Spectator::Matchers::Matcher) - actual = ::Spectator::Expectations::ValueActual.new(self) + actual = ::Spectator::Expectations::ActualValue.new(self) source = ::Spectator::Source.new(__FILE__, __LINE__) ::Spectator::Expectations::ExpectationPartial.new(actual, source).to_not(matcher) end @@ -39,7 +39,7 @@ struct Proc(*T, R) # Extension method to create an expectation for a block of code (proc). # Depending on the matcher, the proc may be executed multiple times. def should(matcher : ::Spectator::Matchers::Matcher) - actual = ::Spectator::Expectations::BlockActual.new(self) + actual = ::Spectator::Expectations::ActualBlock.new(self) source = ::Spectator::Source.new(__FILE__, __LINE__) ::Spectator::Expectations::ExpectationPartial.new(actual, source).to(matcher) end @@ -47,7 +47,7 @@ struct Proc(*T, R) # Works the same as `#should` except the condition is inverted. # When `#should` succeeds, this method will fail, and vice-versa. def should_not(matcher : ::Spectator::Matchers::Matcher) - actual = ::Spectator::Expectations::BlockActual.new(self) + actual = ::Spectator::Expectations::ActualBlock.new(self) source = ::Spectator::Source.new(__FILE__, __LINE__) ::Spectator::Expectations::BlockExpectationPartial.new(actual, source).to_not(matcher) end From dd69cec53679095325018fdddc442080b63f8912 Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Thu, 1 Aug 2019 15:22:45 -0600 Subject: [PATCH 15/78] Should capture a block instead of a value --- src/spectator/dsl/example_dsl.cr | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/spectator/dsl/example_dsl.cr b/src/spectator/dsl/example_dsl.cr index 611c3fb..945c209 100644 --- a/src/spectator/dsl/example_dsl.cr +++ b/src/spectator/dsl/example_dsl.cr @@ -70,11 +70,11 @@ module Spectator::DSL # The raw block can't be used because it's not clear to the user. {% method_name = block.body.id.split('.')[1..-1].join('.') %} %partial = %proc.partial(subject) - block_actual = ::Spectator::Expectations::ActualValue.new({{"#" + method_name}}, %partial) + block_actual = ::Spectator::Expectations::ActualBlock.new({{"#" + method_name}}, %partial) {% else %} # In this case, it looks like the short-hand method syntax wasn't used. # Just drop in the proc as-is. - block_actual = ::Spectator::Expectations::ActualValue.new({{"`" + block.body.stringify + "`"}}, %proc) + block_actual = ::Spectator::Expectations::ActualBlock.new({{"`" + block.body.stringify + "`"}}, %proc) {% end %} source = ::Spectator::Source.new({{_source_file}}, {{_source_line}}) From 763a65beacf17f1802b684375e793ee1215184e8 Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Thu, 1 Aug 2019 15:38:20 -0600 Subject: [PATCH 16/78] Rename again This naming is more appropriate since these types can be used for expected and actual values. --- src/spectator/dsl/example_dsl.cr | 6 +++--- .../expectations/expectation_partial.cr | 4 ++-- src/spectator/should.cr | 8 ++++---- .../actual_block.cr => test_block.cr} | 14 +++++++------- .../actual.cr => test_expression.cr} | 8 ++++---- .../actual_value.cr => test_value.cr} | 16 +++++++++------- 6 files changed, 29 insertions(+), 27 deletions(-) rename src/spectator/{expectations/actual_block.cr => test_block.cr} (61%) rename src/spectator/{expectations/actual.cr => test_expression.cr} (68%) rename src/spectator/{expectations/actual_value.cr => test_value.cr} (50%) diff --git a/src/spectator/dsl/example_dsl.cr b/src/spectator/dsl/example_dsl.cr index 945c209..ede6ec1 100644 --- a/src/spectator/dsl/example_dsl.cr +++ b/src/spectator/dsl/example_dsl.cr @@ -19,7 +19,7 @@ module Spectator::DSL # Where the actual value is returned by the system-under-test, # and the expected value is what the actual value should be to satisfy the condition. macro expect(actual, _source_file = __FILE__, _source_line = __LINE__) - value_actual = ::Spectator::Expectations::ActualValue.new({{actual.stringify}}, {{actual}}) + test_value = ::Spectator::TestValue.new({{actual.stringify}}, {{actual}}) source = ::Spectator::Source.new({{_source_file}}, {{_source_line}}) ::Spectator::Expectations::ExpectationPartial.new(value_actual, source) end @@ -70,11 +70,11 @@ module Spectator::DSL # The raw block can't be used because it's not clear to the user. {% method_name = block.body.id.split('.')[1..-1].join('.') %} %partial = %proc.partial(subject) - block_actual = ::Spectator::Expectations::ActualBlock.new({{"#" + method_name}}, %partial) + test_block = ::Spectator::Expectations::TestBlock.new({{"#" + method_name}}, %partial) {% else %} # In this case, it looks like the short-hand method syntax wasn't used. # Just drop in the proc as-is. - block_actual = ::Spectator::Expectations::ActualBlock.new({{"`" + block.body.stringify + "`"}}, %proc) + test_block = ::Spectator::Expectations::TestBlock.new({{"`" + block.body.stringify + "`"}}, %proc) {% end %} source = ::Spectator::Source.new({{_source_file}}, {{_source_line}}) diff --git a/src/spectator/expectations/expectation_partial.cr b/src/spectator/expectations/expectation_partial.cr index 177bc94..2be1475 100644 --- a/src/spectator/expectations/expectation_partial.cr +++ b/src/spectator/expectations/expectation_partial.cr @@ -1,6 +1,6 @@ require "../matchers/match_data" require "../source" -require "./actual" +require "../test_expression" module Spectator::Expectations # Stores part of an expectation (obviously). @@ -9,7 +9,7 @@ module Spectator::Expectations struct ExpectationPartial # The actual value being tested. # This also contains its label. - getter actual : Actual + getter actual : TestExpression # Location where this expectation was defined. getter source : Source diff --git a/src/spectator/should.cr b/src/spectator/should.cr index d8f0316..06b11b1 100644 --- a/src/spectator/should.cr +++ b/src/spectator/should.cr @@ -21,7 +21,7 @@ class Object # However, since this isn't a macro and we can't "look behind" this method call # to see what it was invoked on, the argument is an empty string. # Additionally, the source file and line can't be obtained. - actual = ::Spectator::Expectations::ActualValue.new(self) + actual = ::Spectator::Expectations::TestValue.new(self) source = ::Spectator::Source.new(__FILE__, __LINE__) ::Spectator::Expectations::ExpectationPartial.new(actual, source).to(matcher) end @@ -29,7 +29,7 @@ class Object # Works the same as `#should` except the condition is inverted. # When `#should` succeeds, this method will fail, and vice-versa. def should_not(matcher : ::Spectator::Matchers::Matcher) - actual = ::Spectator::Expectations::ActualValue.new(self) + actual = ::Spectator::Expectations::TestValue.new(self) source = ::Spectator::Source.new(__FILE__, __LINE__) ::Spectator::Expectations::ExpectationPartial.new(actual, source).to_not(matcher) end @@ -39,7 +39,7 @@ struct Proc(*T, R) # Extension method to create an expectation for a block of code (proc). # Depending on the matcher, the proc may be executed multiple times. def should(matcher : ::Spectator::Matchers::Matcher) - actual = ::Spectator::Expectations::ActualBlock.new(self) + actual = ::Spectator::Expectations::TestBlock.new(self) source = ::Spectator::Source.new(__FILE__, __LINE__) ::Spectator::Expectations::ExpectationPartial.new(actual, source).to(matcher) end @@ -47,7 +47,7 @@ struct Proc(*T, R) # Works the same as `#should` except the condition is inverted. # When `#should` succeeds, this method will fail, and vice-versa. def should_not(matcher : ::Spectator::Matchers::Matcher) - actual = ::Spectator::Expectations::ActualBlock.new(self) + actual = ::Spectator::Expectations::TestBlock.new(self) source = ::Spectator::Source.new(__FILE__, __LINE__) ::Spectator::Expectations::BlockExpectationPartial.new(actual, source).to_not(matcher) end diff --git a/src/spectator/expectations/actual_block.cr b/src/spectator/test_block.cr similarity index 61% rename from src/spectator/expectations/actual_block.cr rename to src/spectator/test_block.cr index b1b77d6..a6a9735 100644 --- a/src/spectator/expectations/actual_block.cr +++ b/src/spectator/test_block.cr @@ -1,26 +1,26 @@ -require "./actual" +require "./test_expression" -module Spectator::Expectations - # Captures an actual block and its label. - struct ActualBlock(ReturnType) < Actual +module Spectator + # Captures an block from a test and its label. + struct TestBlock(ReturnType) < TestExpression # Calls the block and retrieves the value. def value : ReturnType @proc.call end - # Creates the actual with a custom label. + # Creates the block expression with a custom label. # Typically the label is the code in the block/proc. def initialize(label : String, @proc : -> ReturnType) super(label) end - # Creates the actual with a generic label. + # Creates the block expression with a generic label. # This is used for the "should" syntax and when the label doesn't matter. def initialize(@proc : -> ReturnType) super("") end - # Reports complete information about the actual value. + # Reports complete information about the expression. def inspect(io) io << label io << " -> " diff --git a/src/spectator/expectations/actual.cr b/src/spectator/test_expression.cr similarity index 68% rename from src/spectator/expectations/actual.cr rename to src/spectator/test_expression.cr index a62a11a..1ebbf8a 100644 --- a/src/spectator/expectations/actual.cr +++ b/src/spectator/test_expression.cr @@ -1,6 +1,6 @@ module Spectator::Expectations - # Base class for capturing an actual value - the thing being checked/tested. - abstract struct Actual + # Base type for capturing an expression from a test. + abstract struct TestExpression # User-friendly string displayed for the actual expression being tested. # For instance, in the expectation: # ``` @@ -11,11 +11,11 @@ module Spectator::Expectations # and not the actual value of the foo. getter label : String - # Creates the common base of the actual value. + # Creates the common base of the expression. def initialize(@label) end - # String representation of the actual value. + # String representation of the expression. def to_s(io) io << label end diff --git a/src/spectator/expectations/actual_value.cr b/src/spectator/test_value.cr similarity index 50% rename from src/spectator/expectations/actual_value.cr rename to src/spectator/test_value.cr index eaa542f..12ed328 100644 --- a/src/spectator/expectations/actual_value.cr +++ b/src/spectator/test_value.cr @@ -1,27 +1,29 @@ -require "./actual" +require "./test_expression" -module Spectator::Expectations - # Captures an actual value and its label. - struct ActualValue(T) < Actual +module Spectator + # Captures a value from a test and its label. + struct TestValue(T) < TestExpression # Actual value. getter value : T - # Creates the actual with a custom label. + # Creates the expression value with a custom label. def initialize(label : String, @value) super(label) end - # Creates the actual with a stringified value. + # Creates the expression with a stringified value. # This is used for the "should" syntax and when the label doesn't matter. def initialize(@value) super(@value.to_s) end - # Reports complete information about the actual value. + # Reports complete information about the expression. def inspect(io) io << label io << '=' io << @value end end + + alias LabeledValue = TestValue(String) end From 99d8f2a8451ea7573d3bffa5e1c86acc5e43702d Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Thu, 1 Aug 2019 15:40:46 -0600 Subject: [PATCH 17/78] Use TestValue instead of custom LabeledValue --- src/spectator/matchers/labeled_value.cr | 10 ---------- src/spectator/matchers/matcher.cr | 1 + 2 files changed, 1 insertion(+), 10 deletions(-) delete mode 100644 src/spectator/matchers/labeled_value.cr diff --git a/src/spectator/matchers/labeled_value.cr b/src/spectator/matchers/labeled_value.cr deleted file mode 100644 index 3a8c6be..0000000 --- a/src/spectator/matchers/labeled_value.cr +++ /dev/null @@ -1,10 +0,0 @@ -module Spectator::Matchers - struct LabeledValue - getter label : Symbol - - getter value : String - - def initialize(@label, @value) - end - end -end diff --git a/src/spectator/matchers/matcher.cr b/src/spectator/matchers/matcher.cr index bd1e4af..6123969 100644 --- a/src/spectator/matchers/matcher.cr +++ b/src/spectator/matchers/matcher.cr @@ -1,5 +1,6 @@ require "./failed_matched_data" require "./successful_match_data" +require "./test_value" module Spectator::Matchers # Common base class for all expectation conditions. From 7e3b3cd9997fc0642e30e37ac07a523a43d606c2 Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Thu, 1 Aug 2019 15:44:04 -0600 Subject: [PATCH 18/78] Fix namespaces --- src/spectator/dsl/example_dsl.cr | 4 ++-- src/spectator/should.cr | 8 ++++---- src/spectator/test_expression.cr | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/spectator/dsl/example_dsl.cr b/src/spectator/dsl/example_dsl.cr index ede6ec1..328c657 100644 --- a/src/spectator/dsl/example_dsl.cr +++ b/src/spectator/dsl/example_dsl.cr @@ -70,11 +70,11 @@ module Spectator::DSL # The raw block can't be used because it's not clear to the user. {% method_name = block.body.id.split('.')[1..-1].join('.') %} %partial = %proc.partial(subject) - test_block = ::Spectator::Expectations::TestBlock.new({{"#" + method_name}}, %partial) + test_block = ::Spectator::TestBlock.new({{"#" + method_name}}, %partial) {% else %} # In this case, it looks like the short-hand method syntax wasn't used. # Just drop in the proc as-is. - test_block = ::Spectator::Expectations::TestBlock.new({{"`" + block.body.stringify + "`"}}, %proc) + test_block = ::Spectator::TestBlock.new({{"`" + block.body.stringify + "`"}}, %proc) {% end %} source = ::Spectator::Source.new({{_source_file}}, {{_source_line}}) diff --git a/src/spectator/should.cr b/src/spectator/should.cr index 06b11b1..de75c85 100644 --- a/src/spectator/should.cr +++ b/src/spectator/should.cr @@ -21,7 +21,7 @@ class Object # However, since this isn't a macro and we can't "look behind" this method call # to see what it was invoked on, the argument is an empty string. # Additionally, the source file and line can't be obtained. - actual = ::Spectator::Expectations::TestValue.new(self) + actual = ::Spectator::TestValue.new(self) source = ::Spectator::Source.new(__FILE__, __LINE__) ::Spectator::Expectations::ExpectationPartial.new(actual, source).to(matcher) end @@ -29,7 +29,7 @@ class Object # Works the same as `#should` except the condition is inverted. # When `#should` succeeds, this method will fail, and vice-versa. def should_not(matcher : ::Spectator::Matchers::Matcher) - actual = ::Spectator::Expectations::TestValue.new(self) + actual = ::Spectator::TestValue.new(self) source = ::Spectator::Source.new(__FILE__, __LINE__) ::Spectator::Expectations::ExpectationPartial.new(actual, source).to_not(matcher) end @@ -39,7 +39,7 @@ struct Proc(*T, R) # Extension method to create an expectation for a block of code (proc). # Depending on the matcher, the proc may be executed multiple times. def should(matcher : ::Spectator::Matchers::Matcher) - actual = ::Spectator::Expectations::TestBlock.new(self) + actual = ::Spectator::TestBlock.new(self) source = ::Spectator::Source.new(__FILE__, __LINE__) ::Spectator::Expectations::ExpectationPartial.new(actual, source).to(matcher) end @@ -47,7 +47,7 @@ struct Proc(*T, R) # Works the same as `#should` except the condition is inverted. # When `#should` succeeds, this method will fail, and vice-versa. def should_not(matcher : ::Spectator::Matchers::Matcher) - actual = ::Spectator::Expectations::TestBlock.new(self) + actual = ::Spectator::TestBlock.new(self) source = ::Spectator::Source.new(__FILE__, __LINE__) ::Spectator::Expectations::BlockExpectationPartial.new(actual, source).to_not(matcher) end diff --git a/src/spectator/test_expression.cr b/src/spectator/test_expression.cr index 1ebbf8a..6ec4f27 100644 --- a/src/spectator/test_expression.cr +++ b/src/spectator/test_expression.cr @@ -1,4 +1,4 @@ -module Spectator::Expectations +module Spectator # Base type for capturing an expression from a test. abstract struct TestExpression # User-friendly string displayed for the actual expression being tested. From f004912fc186ca86536ba0384521e0fbe7c7832b Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Thu, 1 Aug 2019 15:48:39 -0600 Subject: [PATCH 19/78] Value first, then label --- src/spectator/dsl/example_dsl.cr | 6 +++--- src/spectator/test_block.cr | 2 +- src/spectator/test_value.cr | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/spectator/dsl/example_dsl.cr b/src/spectator/dsl/example_dsl.cr index 328c657..df30978 100644 --- a/src/spectator/dsl/example_dsl.cr +++ b/src/spectator/dsl/example_dsl.cr @@ -19,7 +19,7 @@ module Spectator::DSL # Where the actual value is returned by the system-under-test, # and the expected value is what the actual value should be to satisfy the condition. macro expect(actual, _source_file = __FILE__, _source_line = __LINE__) - test_value = ::Spectator::TestValue.new({{actual.stringify}}, {{actual}}) + test_value = ::Spectator::TestValue.new({{actual}}, {{actual.stringify}}) source = ::Spectator::Source.new({{_source_file}}, {{_source_line}}) ::Spectator::Expectations::ExpectationPartial.new(value_actual, source) end @@ -70,11 +70,11 @@ module Spectator::DSL # The raw block can't be used because it's not clear to the user. {% method_name = block.body.id.split('.')[1..-1].join('.') %} %partial = %proc.partial(subject) - test_block = ::Spectator::TestBlock.new({{"#" + method_name}}, %partial) + test_block = ::Spectator::TestBlock.new(%partial, {{"#" + method_name}}) {% else %} # In this case, it looks like the short-hand method syntax wasn't used. # Just drop in the proc as-is. - test_block = ::Spectator::TestBlock.new({{"`" + block.body.stringify + "`"}}, %proc) + test_block = ::Spectator::TestBlock.new(%proc, {{"`" + block.body.stringify + "`"}}) {% end %} source = ::Spectator::Source.new({{_source_file}}, {{_source_line}}) diff --git a/src/spectator/test_block.cr b/src/spectator/test_block.cr index a6a9735..1b6d4d5 100644 --- a/src/spectator/test_block.cr +++ b/src/spectator/test_block.cr @@ -10,7 +10,7 @@ module Spectator # Creates the block expression with a custom label. # Typically the label is the code in the block/proc. - def initialize(label : String, @proc : -> ReturnType) + def initialize(@proc : -> ReturnType, label : String) super(label) end diff --git a/src/spectator/test_value.cr b/src/spectator/test_value.cr index 12ed328..dcee9a2 100644 --- a/src/spectator/test_value.cr +++ b/src/spectator/test_value.cr @@ -7,7 +7,7 @@ module Spectator getter value : T # Creates the expression value with a custom label. - def initialize(label : String, @value) + def initialize(@value, label : String) super(label) end From 114a4077f3ca3d1e2987d419b114b712c4868fa6 Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Thu, 1 Aug 2019 15:58:48 -0600 Subject: [PATCH 20/78] Fix parameters on LabeledValue --- src/spectator/matchers/matcher.cr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/spectator/matchers/matcher.cr b/src/spectator/matchers/matcher.cr index 6123969..798c525 100644 --- a/src/spectator/matchers/matcher.cr +++ b/src/spectator/matchers/matcher.cr @@ -43,7 +43,7 @@ module Spectator::Matchers end private def values(actual) : Array(LabeledValue) - [LabeledValue.new(:actual, actual.value)] + [LabeledValue.new(actual.value.to_s, "actual")] end private def negated_values(actual) : Array(LabeledValue) From f63697b0199880d457af83f1c9a5c39f7eaf11bf Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Thu, 1 Aug 2019 15:59:29 -0600 Subject: [PATCH 21/78] Update ValueMatcher to use Matcher's methods --- src/spectator/matchers/value_matcher.cr | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/src/spectator/matchers/value_matcher.cr b/src/spectator/matchers/value_matcher.cr index 9ffa6d8..9e821ef 100644 --- a/src/spectator/matchers/value_matcher.cr +++ b/src/spectator/matchers/value_matcher.cr @@ -3,28 +3,22 @@ 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 `Matcher#match?`, `Matcher#message`, and `Matcher#negated_message`. abstract struct ValueMatcher(ExpectedType) < Matcher - # Textual representation of what the matcher expects. - # This shouldn't be used in the conditional logic, - # but for verbose output to help the end-user. - getter label - # Expected value. # Sub-types may use this value to test the expectation and generate message strings. - getter expected + getter expected : TestValue(ExpectedType) # Creates the value matcher. - # The label should be a string representation of the expectation. # The expected value is stored for later use. - def initialize(@expected : ExpectedType, @label : String) + def initialize(@expected) end - # Creates the value matcher. - # The label is generated by calling `#to_s` on the expected value. - # The expected value is stored for later use. - def initialize(expected : ExpectedType) - initialize(expected, expected.to_s) + private def values(actual) : Array(LabeledValue) + super(actual) << LabeledValue.new(expected.value.to_s, "expected") + end + + private def negated_values(actual) : Array(LabeledValue) + super(actual) << LabeledValue.new("Not #{expected.value}", "expected") end end end From 4b59dcf1428a3421efdf7459807eb17e61c0337a Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Thu, 1 Aug 2019 16:02:28 -0600 Subject: [PATCH 22/78] Pass actual value to failure message methods and values --- src/spectator/matchers/matcher.cr | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/spectator/matchers/matcher.cr b/src/spectator/matchers/matcher.cr index 798c525..c022d52 100644 --- a/src/spectator/matchers/matcher.cr +++ b/src/spectator/matchers/matcher.cr @@ -18,7 +18,7 @@ module Spectator::Matchers # Message displayed when the matcher isn't satisifed. # This is only called when `#matches?` returns false. - abstract def failure_message : String + abstract def failure_message(actual) : String # Message displayed when the matcher isn't satisifed and is negated. # This is only called when `#does_not_match?` returns false. @@ -26,7 +26,7 @@ module Spectator::Matchers # A default implementation of this method is provided, # which causes compilation to fail. # If the matcher supports negation, it must override this method. - def failure_message_when_negated : String + def failure_message_when_negated(actual) : String {% raise "Negation with #{@type.name} is not supported." %} end @@ -54,7 +54,7 @@ module Spectator::Matchers if match?(actual) SuccessfulMatchData.new else - FailedMatchData.new(failure_message, values) + FailedMatchData.new(failure_message(actual), values(actual)) end end @@ -62,7 +62,7 @@ module Spectator::Matchers if does_not_match?(actual) SuccessfulMatchData.new else - FailedMatchData.new(failure_message_when_negated, negated_values) + FailedMatchData.new(failure_message_when_negated(actual), negated_values(actual)) end end end From c75fba80766943ea96148beb2223cdce8ca69934 Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Thu, 1 Aug 2019 16:17:12 -0600 Subject: [PATCH 23/78] Change visibility to private --- src/spectator/matchers/matcher.cr | 4 ++-- src/spectator/matchers/value_matcher.cr | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/spectator/matchers/matcher.cr b/src/spectator/matchers/matcher.cr index c022d52..e9d57bc 100644 --- a/src/spectator/matchers/matcher.cr +++ b/src/spectator/matchers/matcher.cr @@ -18,7 +18,7 @@ module Spectator::Matchers # Message displayed when the matcher isn't satisifed. # This is only called when `#matches?` returns false. - abstract def failure_message(actual) : String + private abstract def failure_message(actual) : String # Message displayed when the matcher isn't satisifed and is negated. # This is only called when `#does_not_match?` returns false. @@ -26,7 +26,7 @@ module Spectator::Matchers # A default implementation of this method is provided, # which causes compilation to fail. # If the matcher supports negation, it must override this method. - def failure_message_when_negated(actual) : String + private def failure_message_when_negated(actual) : String {% raise "Negation with #{@type.name} is not supported." %} end diff --git a/src/spectator/matchers/value_matcher.cr b/src/spectator/matchers/value_matcher.cr index 9e821ef..27d51e0 100644 --- a/src/spectator/matchers/value_matcher.cr +++ b/src/spectator/matchers/value_matcher.cr @@ -6,7 +6,7 @@ module Spectator::Matchers abstract struct ValueMatcher(ExpectedType) < Matcher # Expected value. # Sub-types may use this value to test the expectation and generate message strings. - getter expected : TestValue(ExpectedType) + private getter expected : TestValue(ExpectedType) # Creates the value matcher. # The expected value is stored for later use. From 16a2204a2d4482ae876afcbc6deb00d3040af616 Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Thu, 1 Aug 2019 16:17:39 -0600 Subject: [PATCH 24/78] Simplify CaseMatcher by using new matcher refactoring --- src/spectator/matchers/case_matcher.cr | 41 ++++++-------------------- 1 file changed, 9 insertions(+), 32 deletions(-) diff --git a/src/spectator/matchers/case_matcher.cr b/src/spectator/matchers/case_matcher.cr index 8aa727c..b24d9df 100644 --- a/src/spectator/matchers/case_matcher.cr +++ b/src/spectator/matchers/case_matcher.cr @@ -4,43 +4,20 @@ module Spectator::Matchers # Common matcher that tests whether two values semantically equal each other. # The values are compared with the === operator. struct CaseMatcher(ExpectedType) < ValueMatcher(ExpectedType) - # Determines whether the matcher is satisfied with the value given to it. private def match?(actual) - expected === actual + expected.value === actual.value + end + + def description + "matches #{expected.label}" end - # Determines whether the matcher is satisfied with the partial given to it. - def match(partial, negated = false) - values = ExpectedActual.new(partial, self) - MatchData.new(match?(values.actual), values) + def failure_message(actual) + "#{actual.label} did not match #{expected.label}" end - # Match data specific to this matcher. - private struct MatchData(ExpectedType, ActualType) < MatchData - # Creates the match data. - def initialize(matched, @values : ExpectedActual(ExpectedType, ActualType)) - super(matched) - end - - # Information about the match. - def named_tuple - { - expected: NegatableMatchDataValue.new(@values.expected), - actual: @values.actual, - } - end - - # Describes the condition that satisfies the matcher. - # This is informational and displayed to the end-user. - def message - "#{@values.actual_label} matches #{@values.expected_label}" - end - - # Describes the condition that won't satsify the matcher. - # This is informational and displayed to the end-user. - def negated_message - "#{@values.actual_label} does not match #{@values.expected_label}" - end + def failure_message_when_negated(actual) + "#{actual.label} matched #{expected.label}" end end end From 11600a2f8d186f4ad74e5c1c91386ac11323d335 Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Thu, 1 Aug 2019 16:35:02 -0600 Subject: [PATCH 25/78] Simplify more matchers that are easy targets --- src/spectator/matchers/case_matcher.cr | 8 ++-- src/spectator/matchers/contain_matcher.cr | 46 +++++++--------------- src/spectator/matchers/empty_matcher.cr | 44 ++++++--------------- src/spectator/matchers/equality_matcher.cr | 39 ++++-------------- 4 files changed, 39 insertions(+), 98 deletions(-) diff --git a/src/spectator/matchers/case_matcher.cr b/src/spectator/matchers/case_matcher.cr index b24d9df..c4283f6 100644 --- a/src/spectator/matchers/case_matcher.cr +++ b/src/spectator/matchers/case_matcher.cr @@ -7,16 +7,16 @@ module Spectator::Matchers private def match?(actual) expected.value === actual.value end - + def description "matches #{expected.label}" end - def failure_message(actual) - "#{actual.label} did not match #{expected.label}" + private def failure_message(actual) + "#{actual.label} does not match #{expected.label}" end - def failure_message_when_negated(actual) + private def failure_message_when_negated(actual) "#{actual.label} matched #{expected.label}" end end diff --git a/src/spectator/matchers/contain_matcher.cr b/src/spectator/matchers/contain_matcher.cr index cdcd2a9..f733701 100644 --- a/src/spectator/matchers/contain_matcher.cr +++ b/src/spectator/matchers/contain_matcher.cr @@ -4,45 +4,29 @@ 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?` method. struct ContainMatcher(ExpectedType) < ValueMatcher(ExpectedType) - # Determines whether the matcher is satisfied with the value given to it. private def match?(actual) - expected.all? do |item| - actual.includes?(item) + expected.value.all? do |item| + actual.value.includes?(item) end end - # Determines whether the matcher is satisfied with the partial given to it. - def match(partial, negated = false) - values = ExpectedActual.new(partial, self) - MatchData.new(match?(values.actual), values) + def description + "contains #{expected.label}" end - # Match data specific to this matcher. - private struct MatchData(ExpectedType, ActualType) < MatchData - # Creates the match data. - def initialize(matched, @values : ExpectedActual(ExpectedType, ActualType)) - super(matched) - end + private def failure_message(actual) + "#{actual.label} does not match #{expected.label}" + end - # Information about the match. - def named_tuple - { - subset: NegatableMatchDataValue.new(@values.expected), - superset: @values.actual, - } - end + private def failure_message_when_negated(actual) + "#{actual.label} contains #{expected.label}" + end - # Describes the condition that satisfies the matcher. - # This is informational and displayed to the end-user. - def message - "#{@values.actual_label} contains #{@values.expected_label}" - end - - # Describes the condition that won't satsify the matcher. - # This is informational and displayed to the end-user. - def negated_message - "#{@values.actual_label} does not contain #{@values.expected_label}" - end + private def values(actual) : Array(LabeledValue) + [ + LabeledValue.new(expected.value.to_s, "subset"), + LabeledValue.new(actual.value.to_s, "superset"), + ] end end end diff --git a/src/spectator/matchers/empty_matcher.cr b/src/spectator/matchers/empty_matcher.cr index 0db1e3c..1433082 100644 --- a/src/spectator/matchers/empty_matcher.cr +++ b/src/spectator/matchers/empty_matcher.cr @@ -4,44 +4,24 @@ module Spectator::Matchers # Matcher that tests whether a collection is empty. # The values are checked with the `empty?` method. struct EmptyMatcher < Matcher - # Textual representation of what the matcher expects. - def label - "empty?" + private def match?(actual) + actual.value.empty? end - # Determines whether the matcher is satisfied with the partial given to it. - def match(partial, negated = false) - actual = partial.actual - matched = actual.empty? - MatchData.new(matched, actual, partial.label) + def description + "is empty" end - # Match data specific to this matcher. - private struct MatchData(T) < MatchData - # Creates the match data. - def initialize(matched, @actual : T, @actual_label : String) - super(matched) - end + private def failure_message(actual) + "#{actual.label} is not empty" + end - # Information about the match. - def named_tuple - { - expected: NegatableMatchDataValue.new([] of Nil), - actual: @actual, - } - end + private def failure_message_when_negated(actual) + "#{actual.label} is empty" + end - # Describes the condition that satisfies the matcher. - # This is informational and displayed to the end-user. - def message - "#{@actual_label} is empty" - end - - # Describes the condition that won't satsify the matcher. - # This is informational and displayed to the end-user. - def negated_message - "#{@actual_label} is not empty" - end + private def values(actual) : Array(LabeledValue) + [LabeledValue.new(actual.value.to_s, "actual")] end end end diff --git a/src/spectator/matchers/equality_matcher.cr b/src/spectator/matchers/equality_matcher.cr index 79128f0..ce95be1 100644 --- a/src/spectator/matchers/equality_matcher.cr +++ b/src/spectator/matchers/equality_matcher.cr @@ -4,43 +4,20 @@ module Spectator::Matchers # Common matcher that tests whether two values equal each other. # The values are compared with the == operator. struct EqualityMatcher(ExpectedType) < ValueMatcher(ExpectedType) - # Determines whether the matcher is satisfied with the value given to it. private def match?(actual) - actual == expected + expected.value == actual.value end - # Determines whether the matcher is satisfied with the partial given to it. - def match(partial, negated = false) - values = ExpectedActual.new(partial, self) - MatchData.new(match?(values.actual), values) + def description + "equals #{expected.label}" end - # Match data specific to this matcher. - private struct MatchData(ExpectedType, ActualType) < MatchData - # Creates the match data. - def initialize(matched, @values : ExpectedActual(ExpectedType, ActualType)) - super(matched) - end + private def failure_message(actual) + "#{actual.label} does not equal #{expected.label}" + end - # Information about the match. - def named_tuple - { - expected: NegatableMatchDataValue.new(@values.expected), - actual: @values.actual, - } - end - - # Describes the condition that satisfies the matcher. - # This is informational and displayed to the end-user. - def message - "#{@values.actual_label} is #{@values.expected_label} (using ==)" - end - - # Describes the condition that won't satsify the matcher. - # This is informational and displayed to the end-user. - def negated_message - "#{@values.actual_label} is not #{@values.expected_label} (using ==)" - end + private def failure_message_when_negated(actual) + "#{actual.label} equals #{expected.label}" end end end From 42b8fe471f9305de591fe834af1be554265a388a Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Thu, 1 Aug 2019 16:37:19 -0600 Subject: [PATCH 26/78] Fix some includes and a dangling old file --- src/spectator/expectations/expectation.cr | 2 +- src/spectator/matchers/failed_match_data.cr | 2 +- .../matchers/match_data_labeled_value.cr | 15 --------------- src/spectator/matchers/matcher.cr | 4 ++-- 4 files changed, 4 insertions(+), 19 deletions(-) delete mode 100644 src/spectator/matchers/match_data_labeled_value.cr diff --git a/src/spectator/expectations/expectation.cr b/src/spectator/expectations/expectation.cr index 1f787dc..63e48cb 100644 --- a/src/spectator/expectations/expectation.cr +++ b/src/spectator/expectations/expectation.cr @@ -1,4 +1,4 @@ -require "../matchers/failed_matched_data" +require "../matchers/failed_match_data" require "../matchers/match_data" require "../source" diff --git a/src/spectator/matchers/failed_match_data.cr b/src/spectator/matchers/failed_match_data.cr index 5855de5..250cf64 100644 --- a/src/spectator/matchers/failed_match_data.cr +++ b/src/spectator/matchers/failed_match_data.cr @@ -1,4 +1,4 @@ -require "./labeled_value" +require "../test_value" require "./match_data" module Spectator::Matchers diff --git a/src/spectator/matchers/match_data_labeled_value.cr b/src/spectator/matchers/match_data_labeled_value.cr deleted file mode 100644 index 2a39095..0000000 --- a/src/spectator/matchers/match_data_labeled_value.cr +++ /dev/null @@ -1,15 +0,0 @@ -module Spectator::Matchers - # A value from match data with a label. - struct MatchDataLabeledValue - # Label tied to the value. - # This annotates what the value is. - getter label : Symbol - - # The actual value from the match data. - getter value : MatchDataValue - - # Creates a new labeled value. - def initialize(@label, @value) - end - end -end diff --git a/src/spectator/matchers/matcher.cr b/src/spectator/matchers/matcher.cr index e9d57bc..d87d8ca 100644 --- a/src/spectator/matchers/matcher.cr +++ b/src/spectator/matchers/matcher.cr @@ -1,6 +1,6 @@ -require "./failed_matched_data" +require "../test_value" +require "./failed_match_data" require "./successful_match_data" -require "./test_value" module Spectator::Matchers # Common base class for all expectation conditions. From 5cc735368cfedfbe8c68bde2d82be9ea73e84848 Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Thu, 1 Aug 2019 21:17:24 -0600 Subject: [PATCH 27/78] Update comparison matchers --- .../matchers/greater_than_equal_matcher.cr | 49 ++++++++----------- .../matchers/greater_than_matcher.cr | 49 ++++++++----------- .../matchers/less_than_equal_matcher.cr | 49 ++++++++----------- src/spectator/matchers/less_than_matcher.cr | 49 ++++++++----------- 4 files changed, 80 insertions(+), 116 deletions(-) diff --git a/src/spectator/matchers/greater_than_equal_matcher.cr b/src/spectator/matchers/greater_than_equal_matcher.cr index 9adb4b2..f2ee6fd 100644 --- a/src/spectator/matchers/greater_than_equal_matcher.cr +++ b/src/spectator/matchers/greater_than_equal_matcher.cr @@ -4,43 +4,34 @@ module Spectator::Matchers # Matcher that tests whether one value is greater than or equal to another. # The values are compared with the >= operator. struct GreaterThanEqualMatcher(ExpectedType) < ValueMatcher(ExpectedType) - # Determines whether the matcher is satisfied with the value given to it. private def match?(actual) - actual >= expected + actual.value >= expected.value end - # Determines whether the matcher is satisfied with the partial given to it. - def match(partial, negated = false) - values = ExpectedActual.new(partial, self) - MatchData.new(match?(values.actual), values) + def description + "greater than or equal to #{expected.label}" end - # Match data specific to this matcher. - private struct MatchData(ExpectedType, ActualType) < MatchData - # Creates the match data. - def initialize(matched, @values : ExpectedActual(ExpectedType, ActualType)) - super(matched) - end + private def failure_message(actual) + "#{actual.label} is less than #{expected.label}" + end - # Information about the match. - def named_tuple - { - expected: NegatablePrefixedMatchDataValue.new(">=", "<", @values.expected), - actual: @values.actual, - } - end + private def failure_message_when_negated(actual) + "#{actual.label} is greater than or equal to #{expected.label}" + end - # Describes the condition that satisfies the matcher. - # This is informational and displayed to the end-user. - def message - "#{@values.actual_label} is greater than or equal to #{@values.expected_label} (using >=)" - end + private def values(actual) + [ + LabeledValue.new(">= #{expected.value}", "expected"), + LabeledValue.new(actual.value.to_s, "actual") + ] + end - # Describes the condition that won't satsify the matcher. - # This is informational and displayed to the end-user. - def negated_message - "#{@values.actual_label} is less than #{@values.expected_label} (using >=)" - end + private def negated_values(actual) + [ + LabeledValue.new("< #{expected.value}", "expected"), + LabeledValue.new(actual.value.to_s, "actual") + ] end end end diff --git a/src/spectator/matchers/greater_than_matcher.cr b/src/spectator/matchers/greater_than_matcher.cr index b382a94..d9ce293 100644 --- a/src/spectator/matchers/greater_than_matcher.cr +++ b/src/spectator/matchers/greater_than_matcher.cr @@ -4,43 +4,34 @@ module Spectator::Matchers # Matcher that tests whether one value is greater than another. # The values are compared with the > operator. struct GreaterThanMatcher(ExpectedType) < ValueMatcher(ExpectedType) - # Determines whether the matcher is satisfied with the value given to it. private def match?(actual) - actual > expected + actual.value > expected.value end - # Determines whether the matcher is satisfied with the partial given to it. - def match(partial, negated = false) - values = ExpectedActual.new(partial, self) - MatchData.new(match?(values.actual), values) + def description + "greater than #{expected.label}" end - # Match data specific to this matcher. - private struct MatchData(ExpectedType, ActualType) < MatchData - # Creates the match data. - def initialize(matched, @values : ExpectedActual(ExpectedType, ActualType)) - super(matched) - end + private def failure_message(actual) + "#{actual.label} is less than or equal to #{expected.label}" + end - # Information about the match. - def named_tuple - { - expected: NegatablePrefixedMatchDataValue.new(">", "<=", @values.expected), - actual: @values.actual, - } - end + private def failure_message_when_negated(actual) + "#{actual.label} is greater than #{expected.label}" + end - # Describes the condition that satisfies the matcher. - # This is informational and displayed to the end-user. - def message - "#{@values.actual_label} is greater than #{@values.expected_label} (using >)" - end + private def values(actual) + [ + LabeledValue.new("> #{expected.value}", "expected"), + LabeledValue.new(actual.value.to_s, "actual") + ] + end - # Describes the condition that won't satsify the matcher. - # This is informational and displayed to the end-user. - def negated_message - "#{@values.actual_label} is less than or equal to #{@values.expected_label} (using >)" - end + private def negated_values(actual) + [ + LabeledValue.new("<= #{expected.value}", "expected"), + LabeledValue.new(actual.value.to_s, "actual") + ] end end end diff --git a/src/spectator/matchers/less_than_equal_matcher.cr b/src/spectator/matchers/less_than_equal_matcher.cr index 73e8ca5..aa5d3aa 100644 --- a/src/spectator/matchers/less_than_equal_matcher.cr +++ b/src/spectator/matchers/less_than_equal_matcher.cr @@ -4,43 +4,34 @@ module Spectator::Matchers # Matcher that tests whether one value is less than or equal to another. # The values are compared with the <= operator. struct LessThanEqualMatcher(ExpectedType) < ValueMatcher(ExpectedType) - # Determines whether the matcher is satisfied with the value given to it. private def match?(actual) - actual <= expected + actual.value <= expected.value end - # Determines whether the matcher is satisfied with the partial given to it. - def match(partial, negated = false) - values = ExpectedActual.new(partial, self) - MatchData.new(match?(values.actual), values) + def description + "less than or equal to #{expected.label}" end - # Match data specific to this matcher. - private struct MatchData(ExpectedType, ActualType) < MatchData - # Creates the match data. - def initialize(matched, @values : ExpectedActual(ExpectedType, ActualType)) - super(matched) - end + private def failure_message(actual) + "#{actual.label} is greater than #{expected.label}" + end - # Information about the match. - def named_tuple - { - expected: NegatablePrefixedMatchDataValue.new("<=", ">", @values.expected), - actual: @values.actual, - } - end + private def failure_message_when_negated(actual) + "#{actual.label} is less than or equal to #{expected.label}" + end - # Describes the condition that satisfies the matcher. - # This is informational and displayed to the end-user. - def message - "#{@values.actual_label} is less than or equal to #{@values.expected_label} (using <=)" - end + private def values(actual) + [ + LabeledValue.new("<= #{expected.value}", "expected"), + LabeledValue.new(actual.value.to_s, "actual") + ] + end - # Describes the condition that won't satsify the matcher. - # This is informational and displayed to the end-user. - def negated_message - "#{@values.actual_label} is greater than #{@values.expected_label} (using <=)" - end + private def negated_values(actual) + [ + LabeledValue.new("> #{expected.value}", "expected"), + LabeledValue.new(actual.value.to_s, "actual") + ] end end end diff --git a/src/spectator/matchers/less_than_matcher.cr b/src/spectator/matchers/less_than_matcher.cr index b9663c3..5c63732 100644 --- a/src/spectator/matchers/less_than_matcher.cr +++ b/src/spectator/matchers/less_than_matcher.cr @@ -4,43 +4,34 @@ module Spectator::Matchers # Matcher that tests whether one value is less than another. # The values are compared with the < operator. struct LessThanMatcher(ExpectedType) < ValueMatcher(ExpectedType) - # Determines whether the matcher is satisfied with the value given to it. private def match?(actual) - actual < expected + actual.value < expected.value end - # Determines whether the matcher is satisfied with the partial given to it. - def match(partial, negated = false) - values = ExpectedActual.new(partial, self) - MatchData.new(match?(values.actual), values) + def description + "less than #{expected.label}" end - # Match data specific to this matcher. - private struct MatchData(ExpectedType, ActualType) < MatchData - # Creates the match data. - def initialize(matched, @values : ExpectedActual(ExpectedType, ActualType)) - super(matched) - end + private def failure_message(actual) + "#{actual.label} is greater than or equal to #{expected.label}" + end - # Information about the match. - def named_tuple - { - expected: NegatablePrefixedMatchDataValue.new("<", ">=", @values.expected), - actual: @values.actual, - } - end + private def failure_message_when_negated(actual) + "#{actual.label} is less than #{expected.label}" + end - # Describes the condition that satisfies the matcher. - # This is informational and displayed to the end-user. - def message - "#{@values.actual_label} is less than #{@values.expected_label} (using <)" - end + private def values(actual) + [ + LabeledValue.new("< #{expected.value}", "expected"), + LabeledValue.new(actual.value.to_s, "actual") + ] + end - # Describes the condition that won't satsify the matcher. - # This is informational and displayed to the end-user. - def negated_message - "#{@values.actual_label} is greater than or equal to #{@values.expected_label} (using <)" - end + private def negated_values(actual) + [ + LabeledValue.new(">= #{expected.value}", "expected"), + LabeledValue.new(actual.value.to_s, "actual") + ] end end end From 044202e606e1ad9f1e76f4295d7fca8d3d22748f Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Tue, 6 Aug 2019 21:55:22 -0600 Subject: [PATCH 28/78] Use inspect instead of to_s for value reporting --- src/spectator/matchers/contain_matcher.cr | 4 ++-- src/spectator/matchers/empty_matcher.cr | 2 +- src/spectator/matchers/greater_than_equal_matcher.cr | 8 ++++---- src/spectator/matchers/greater_than_matcher.cr | 8 ++++---- src/spectator/matchers/less_than_equal_matcher.cr | 8 ++++---- src/spectator/matchers/less_than_matcher.cr | 8 ++++---- src/spectator/matchers/matcher.cr | 2 +- src/spectator/matchers/value_matcher.cr | 4 ++-- 8 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/spectator/matchers/contain_matcher.cr b/src/spectator/matchers/contain_matcher.cr index f733701..f707486 100644 --- a/src/spectator/matchers/contain_matcher.cr +++ b/src/spectator/matchers/contain_matcher.cr @@ -24,8 +24,8 @@ module Spectator::Matchers private def values(actual) : Array(LabeledValue) [ - LabeledValue.new(expected.value.to_s, "subset"), - LabeledValue.new(actual.value.to_s, "superset"), + LabeledValue.new(expected.value.inspect, "subset"), + LabeledValue.new(actual.value.inspect, "superset"), ] end end diff --git a/src/spectator/matchers/empty_matcher.cr b/src/spectator/matchers/empty_matcher.cr index 1433082..dcd5582 100644 --- a/src/spectator/matchers/empty_matcher.cr +++ b/src/spectator/matchers/empty_matcher.cr @@ -21,7 +21,7 @@ module Spectator::Matchers end private def values(actual) : Array(LabeledValue) - [LabeledValue.new(actual.value.to_s, "actual")] + [LabeledValue.new(actual.value.inspect, "actual")] end end end diff --git a/src/spectator/matchers/greater_than_equal_matcher.cr b/src/spectator/matchers/greater_than_equal_matcher.cr index f2ee6fd..9228a98 100644 --- a/src/spectator/matchers/greater_than_equal_matcher.cr +++ b/src/spectator/matchers/greater_than_equal_matcher.cr @@ -22,15 +22,15 @@ module Spectator::Matchers private def values(actual) [ - LabeledValue.new(">= #{expected.value}", "expected"), - LabeledValue.new(actual.value.to_s, "actual") + LabeledValue.new(">= #{expected.value.inspect}", "expected"), + LabeledValue.new(actual.value.inspect, "actual"), ] end private def negated_values(actual) [ - LabeledValue.new("< #{expected.value}", "expected"), - LabeledValue.new(actual.value.to_s, "actual") + LabeledValue.new("< #{expected.value.inspect}", "expected"), + LabeledValue.new(actual.value.inspect, "actual"), ] end end diff --git a/src/spectator/matchers/greater_than_matcher.cr b/src/spectator/matchers/greater_than_matcher.cr index d9ce293..c65a038 100644 --- a/src/spectator/matchers/greater_than_matcher.cr +++ b/src/spectator/matchers/greater_than_matcher.cr @@ -22,15 +22,15 @@ module Spectator::Matchers private def values(actual) [ - LabeledValue.new("> #{expected.value}", "expected"), - LabeledValue.new(actual.value.to_s, "actual") + LabeledValue.new("> #{expected.value.inspect}", "expected"), + LabeledValue.new(actual.value.inspect, "actual"), ] end private def negated_values(actual) [ - LabeledValue.new("<= #{expected.value}", "expected"), - LabeledValue.new(actual.value.to_s, "actual") + LabeledValue.new("<= #{expected.value.inspect}", "expected"), + LabeledValue.new(actual.value.inspect, "actual"), ] end end diff --git a/src/spectator/matchers/less_than_equal_matcher.cr b/src/spectator/matchers/less_than_equal_matcher.cr index aa5d3aa..2146257 100644 --- a/src/spectator/matchers/less_than_equal_matcher.cr +++ b/src/spectator/matchers/less_than_equal_matcher.cr @@ -22,15 +22,15 @@ module Spectator::Matchers private def values(actual) [ - LabeledValue.new("<= #{expected.value}", "expected"), - LabeledValue.new(actual.value.to_s, "actual") + LabeledValue.new("<= #{expected.value.inspect}", "expected"), + LabeledValue.new(actual.value.inspect, "actual"), ] end private def negated_values(actual) [ - LabeledValue.new("> #{expected.value}", "expected"), - LabeledValue.new(actual.value.to_s, "actual") + LabeledValue.new("> #{expected.value.inspect}", "expected"), + LabeledValue.new(actual.value.inspect, "actual"), ] end end diff --git a/src/spectator/matchers/less_than_matcher.cr b/src/spectator/matchers/less_than_matcher.cr index 5c63732..e45f3d6 100644 --- a/src/spectator/matchers/less_than_matcher.cr +++ b/src/spectator/matchers/less_than_matcher.cr @@ -22,15 +22,15 @@ module Spectator::Matchers private def values(actual) [ - LabeledValue.new("< #{expected.value}", "expected"), - LabeledValue.new(actual.value.to_s, "actual") + LabeledValue.new("< #{expected.value.inspect}", "expected"), + LabeledValue.new(actual.value.inspect, "actual"), ] end private def negated_values(actual) [ - LabeledValue.new(">= #{expected.value}", "expected"), - LabeledValue.new(actual.value.to_s, "actual") + LabeledValue.new(">= #{expected.value.inspect}", "expected"), + LabeledValue.new(actual.value.inspect, "actual"), ] end end diff --git a/src/spectator/matchers/matcher.cr b/src/spectator/matchers/matcher.cr index d87d8ca..0d4e1dd 100644 --- a/src/spectator/matchers/matcher.cr +++ b/src/spectator/matchers/matcher.cr @@ -43,7 +43,7 @@ module Spectator::Matchers end private def values(actual) : Array(LabeledValue) - [LabeledValue.new(actual.value.to_s, "actual")] + [LabeledValue.new(actual.value.inspect, "actual")] end private def negated_values(actual) : Array(LabeledValue) diff --git a/src/spectator/matchers/value_matcher.cr b/src/spectator/matchers/value_matcher.cr index 27d51e0..7e09a08 100644 --- a/src/spectator/matchers/value_matcher.cr +++ b/src/spectator/matchers/value_matcher.cr @@ -14,11 +14,11 @@ module Spectator::Matchers end private def values(actual) : Array(LabeledValue) - super(actual) << LabeledValue.new(expected.value.to_s, "expected") + super(actual) << LabeledValue.new(expected.value.inspect, "expected") end private def negated_values(actual) : Array(LabeledValue) - super(actual) << LabeledValue.new("Not #{expected.value}", "expected") + super(actual) << LabeledValue.new("Not #{expected.value.inspect}", "expected") end end end From 13fad5081b44a09d58afbb22205379e096648902 Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Tue, 6 Aug 2019 21:56:33 -0600 Subject: [PATCH 29/78] Initial refactor of ArrayMatcher --- src/spectator/matchers/array_matcher.cr | 175 ++++++++---------------- 1 file changed, 59 insertions(+), 116 deletions(-) diff --git a/src/spectator/matchers/array_matcher.cr b/src/spectator/matchers/array_matcher.cr index 3857806..1efef4d 100644 --- a/src/spectator/matchers/array_matcher.cr +++ b/src/spectator/matchers/array_matcher.cr @@ -5,129 +5,72 @@ module Spectator::Matchers # Matcher for checking that the contents of one array (or similar type) # has the exact same contents as another and in the same order. struct ArrayMatcher(ExpectedType) < ValueMatcher(Enumerable(ExpectedType)) - # Determines whether the matcher is satisfied with the partial given to it. - def match(partial, negated = false) - actual = partial.actual.to_a - expected_elements = expected.to_a - values = ExpectedActual.new(expected_elements, label, actual, partial.label) - if values.expected.size == values.actual.size + def description + "contains exactly #{expected.label}" + end + + private def failure_message(actual) + {% raise "This method should never be called" %} + end + + private def failure_message_when_negated(actual) + {% raise "This method should never be called" %} + end + + private def match?(actual) + {% raise "This method should never be called" %} + end + + private def does_not_match?(actual) + {% raise "This method should never be called" %} + end + + def match(actual) + actual_elements = actual.value.to_a + expected_elements = expected.value.to_a + if expected_elements.size == actual_elements.size index = 0 - values.expected.zip(values.actual) do |expected, element| - return ContentMatchData.new(index, values) unless expected == element + expected_elements.zip(actual_elements) do |expected_element, actual_element| + unless expected_element == actual_element + return FailedMatchData.new("#{actual.label} does not contain exactly #{expected.label} (element mismatch)", + [ + LabeledValue.new(expected_element.inspect, "expected"), + LabeledValue.new(actual_element.inspect, "actual"), + LabeledValue.new(index.to_s, "index"), + ]) + end index += 1 end - IdenticalMatchData.new(values) + # Success. + SuccessfulMatchData.new else - SizeMatchData.new(values) + # Size mismatch. + FailedMatchData.new("#{actual.label} does not contain exactly #{expected.label} (size mismatch)", + [ + LabeledValue.new(expected_elements.inspect, "expected"), + LabeledValue.new(actual_elements.inspect, "actual"), + LabeledValue.new(expected_elements.size, "expected size"), + LabeledValue.new(actual_elements.size, "actual size"), + ]) end end - # Creates the value matcher. - # The label should be a string representation of the expectation. - # The expected value is stored for later use. - def initialize(expected : Enumerable(ExpectedType), label : String) - super - end - - # Creates the value matcher. - # The label is generated by calling `#to_s` on the expected value. - # The expected value is stored for later use. - def initialize(expected : Enumerable(ExpectedType)) - super - end - - # Returns a matcher that uses the same expected array, but allows unordered items. - def in_any_order - UnorderedArrayMatcher.new(@expected, @label) - end - - # Returns self. - # Exists for syntax to ensure in-order matching is performed. - def in_order - self - end - - # Common functionality for all match data for this matcher. - private abstract struct CommonMatchData(ExpectedType, ActualType) < MatchData - # Creates the match data. - def initialize(matched, @values : ExpectedActual(Array(ExpectedType), Array(ActualType))) - super(matched) - end - - # Basic information about the match. - def named_tuple - { - expected: NegatableMatchDataValue.new(@values.expected), - actual: @values.actual, - } - end - - # Describes the condition that satisfies the matcher. - # This is informational and displayed to the end-user. - def message - "#{@values.actual_label} contains exactly #{@values.expected_label}" - end - end - - # Match data specific to this matcher. - # This type is used when the actual value matches the expected value. - private struct IdenticalMatchData(ExpectedType, ActualType) < CommonMatchData(ExpectedType, ActualType) - # Creates the match data. - def initialize(values : ExpectedActual(Array(ExpectedType), Array(ActualType))) - super(true, values) - end - - # Describes the condition that won't satsify the matcher. - # This is informational and displayed to the end-user. - def negated_message - "#{@values.actual_label} does not contain exactly #{@values.expected_label}" - end - end - - # Match data specific to this matcher. - # This type is used when the actual size differs from the expected size. - private struct SizeMatchData(ExpectedType, ActualType) < CommonMatchData(ExpectedType, ActualType) - # Creates the match data. - def initialize(values : ExpectedActual(Array(ExpectedType), Array(ActualType))) - super(false, values) - end - - # Information about the match. - def named_tuple - super.merge({ - "expected size": NegatableMatchDataValue.new(@values.expected.size), - "actual size": @values.actual.size, - }) - end - - # Describes the condition that won't satsify the matcher. - # This is informational and displayed to the end-user. - def negated_message - "#{@values.actual_label} does not contain exactly #{@values.expected_label} (size differs)" - end - end - - # Match data specific to this matcher. - # This type is used when the actual contents differs from the expected contents. - private struct ContentMatchData(ExpectedType, ActualType) < CommonMatchData(ExpectedType, ActualType) - # Creates the match data. - def initialize(@index : Int32, values : ExpectedActual(Array(ExpectedType), Array(ActualType))) - super(false, values) - end - - # Information about the match. - def named_tuple - super.merge({ - index: @index, - "expected element": NegatableMatchDataValue.new(@values.expected[@index]), - "actual element": @values.actual[@index], - }) - end - - # Describes the condition that won't satsify the matcher. - # This is informational and displayed to the end-user. - def negated_message - "#{@values.actual_label} does not contain exactly #{@values.expected_label} (content differs)" + def negated_match(actual) + actual_elements = actual.value.to_a + expected_elements = expected.value.to_a + if expected_elements.size == actual_elements.size + index = 0 + expected_elements.zip(actual_elements) do |expected_element, actual_element| + return SuccessfulMatchData.new unless expected_element == actual_element + index += 1 + end + FailedMatchData.new("#{actual.label} contains exactly #{expected.label}", + [ + LabeledValue.new("Not #{expected_elements.inspect}", "expected"), + LabeledValue.new(actual_elements.inspect, "actual"), + ]) + else + SuccessfulMatchData.new end end end From ab147d00fbadf31c1748ae5e05f0800e7ed6a837 Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Tue, 6 Aug 2019 22:18:05 -0600 Subject: [PATCH 30/78] Cleanup match methods --- src/spectator/matchers/array_matcher.cr | 90 +++++++++++++++---------- 1 file changed, 55 insertions(+), 35 deletions(-) diff --git a/src/spectator/matchers/array_matcher.cr b/src/spectator/matchers/array_matcher.cr index 1efef4d..f8178bb 100644 --- a/src/spectator/matchers/array_matcher.cr +++ b/src/spectator/matchers/array_matcher.cr @@ -28,50 +28,70 @@ module Spectator::Matchers def match(actual) actual_elements = actual.value.to_a expected_elements = expected.value.to_a - if expected_elements.size == actual_elements.size - index = 0 - expected_elements.zip(actual_elements) do |expected_element, actual_element| - unless expected_element == actual_element - return FailedMatchData.new("#{actual.label} does not contain exactly #{expected.label} (element mismatch)", - [ - LabeledValue.new(expected_element.inspect, "expected"), - LabeledValue.new(actual_element.inspect, "actual"), - LabeledValue.new(index.to_s, "index"), - ]) - end - index += 1 - end - # Success. + index = compare_arrays(expected_elements, actual_elements) + + case index + when true # Contents are identical. SuccessfulMatchData.new - else - # Size mismatch. - FailedMatchData.new("#{actual.label} does not contain exactly #{expected.label} (size mismatch)", - [ - LabeledValue.new(expected_elements.inspect, "expected"), - LabeledValue.new(actual_elements.inspect, "actual"), - LabeledValue.new(expected_elements.size, "expected size"), - LabeledValue.new(actual_elements.size, "actual size"), - ]) + when false # Size differs. + failed_size_mismatch(expected_elements, actual_elements, actual.label) + else # Content differs. + failed_content_mismatch(expected_elements, actual_elements, index, actual.label) end end def negated_match(actual) actual_elements = actual.value.to_a expected_elements = expected.value.to_a - if expected_elements.size == actual_elements.size - index = 0 - expected_elements.zip(actual_elements) do |expected_element, actual_element| - return SuccessfulMatchData.new unless expected_element == actual_element - index += 1 - end - FailedMatchData.new("#{actual.label} contains exactly #{expected.label}", - [ - LabeledValue.new("Not #{expected_elements.inspect}", "expected"), - LabeledValue.new(actual_elements.inspect, "actual"), - ]) - else + + case compare_arrays(expected_elements, actual_elements) + when true # Contents are identical. + failed_content_identical(expected_elements, actual_elements, actual.label) + when false # Size differs. + SuccessfulMatchData.new + else # Contents differ. SuccessfulMatchData.new end end + + private def compare_arrays(expected_elements, actual_elements) + if expected_elements.size == actual_elements.size + index = 0 + expected_elements.zip(actual_elements) do |expected_element, actual_element| + return index unless expected_element == actual_element + index += 1 + end + true + else + false + end + end + + def failed_size_mismatch(expected_elements, actual_elements, actual_label) + FailedMatchData.new("#{actual_label} does not contain exactly #{expected.label} (size mismatch)", + [ + LabeledValue.new(expected_elements.inspect, "expected"), + LabeledValue.new(actual_elements.inspect, "actual"), + LabeledValue.new(expected_elements.size, "expected size"), + LabeledValue.new(actual_elements.size, "actual size"), + ]) + end + + def failed_content_mismatch(expected_elements, actual_elements, index, actual_label) + FailedMatchData.new("#{actual_label} does not contain exactly #{expected.label} (element mismatch)", + [ + LabeledValue.new(expected_elements[index].inspect, "expected"), + LabeledValue.new(actual_elements[index].inspect, "actual"), + LabeledValue.new(index.to_s, "index"), + ]) + end + + def failed_content_identical(expected_elements, actual_elements, actual_label) + FailedMatchData.new("#{actual.label} contains exactly #{expected.label}", + [ + LabeledValue.new("Not #{expected_elements.inspect}", "expected"), + LabeledValue.new(actual_elements.inspect, "actual"), + ]) + end end end From e7b19ee5917ddb4e052ee8d3b0a1ca85e9c08b35 Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Tue, 6 Aug 2019 22:33:13 -0600 Subject: [PATCH 31/78] Insert StandardMatcher into Matcher hierarchy This is to remove all the unused abstract methods. --- src/spectator/matchers/array_matcher.cr | 34 +++++-------- src/spectator/matchers/matcher.cr | 54 ++------------------ src/spectator/matchers/standard_matcher.cr | 59 ++++++++++++++++++++++ src/spectator/matchers/value_matcher.cr | 4 +- 4 files changed, 77 insertions(+), 74 deletions(-) create mode 100644 src/spectator/matchers/standard_matcher.cr diff --git a/src/spectator/matchers/array_matcher.cr b/src/spectator/matchers/array_matcher.cr index f8178bb..268d0fe 100644 --- a/src/spectator/matchers/array_matcher.cr +++ b/src/spectator/matchers/array_matcher.cr @@ -1,30 +1,22 @@ -require "./value_matcher" +require "../test_value" +require "./failed_match_data" +require "./matcher" +require "./successful_match_data" require "./unordered_array_matcher" module Spectator::Matchers # Matcher for checking that the contents of one array (or similar type) # has the exact same contents as another and in the same order. - struct ArrayMatcher(ExpectedType) < ValueMatcher(Enumerable(ExpectedType)) + struct ArrayMatcher(ExpectedType) < Matcher + private getter expected : TestValue(ExpectedType) + + def initialize(@expected) + end + def description "contains exactly #{expected.label}" end - private def failure_message(actual) - {% raise "This method should never be called" %} - end - - private def failure_message_when_negated(actual) - {% raise "This method should never be called" %} - end - - private def match?(actual) - {% raise "This method should never be called" %} - end - - private def does_not_match?(actual) - {% raise "This method should never be called" %} - end - def match(actual) actual_elements = actual.value.to_a expected_elements = expected.value.to_a @@ -67,7 +59,7 @@ module Spectator::Matchers end end - def failed_size_mismatch(expected_elements, actual_elements, actual_label) + private def failed_size_mismatch(expected_elements, actual_elements, actual_label) FailedMatchData.new("#{actual_label} does not contain exactly #{expected.label} (size mismatch)", [ LabeledValue.new(expected_elements.inspect, "expected"), @@ -77,7 +69,7 @@ module Spectator::Matchers ]) end - def failed_content_mismatch(expected_elements, actual_elements, index, actual_label) + private def failed_content_mismatch(expected_elements, actual_elements, index, actual_label) FailedMatchData.new("#{actual_label} does not contain exactly #{expected.label} (element mismatch)", [ LabeledValue.new(expected_elements[index].inspect, "expected"), @@ -86,7 +78,7 @@ module Spectator::Matchers ]) end - def failed_content_identical(expected_elements, actual_elements, actual_label) + private def failed_content_identical(expected_elements, actual_elements, actual_label) FailedMatchData.new("#{actual.label} contains exactly #{expected.label}", [ LabeledValue.new("Not #{expected_elements.inspect}", "expected"), diff --git a/src/spectator/matchers/matcher.cr b/src/spectator/matchers/matcher.cr index 0d4e1dd..9120909 100644 --- a/src/spectator/matchers/matcher.cr +++ b/src/spectator/matchers/matcher.cr @@ -1,6 +1,4 @@ -require "../test_value" -require "./failed_match_data" -require "./successful_match_data" +require "./match_data" module Spectator::Matchers # Common base class for all expectation conditions. @@ -16,54 +14,8 @@ module Spectator::Matchers # The phrasing should be such that it reads "it ___." abstract def description : String - # Message displayed when the matcher isn't satisifed. - # This is only called when `#matches?` returns false. - private abstract def failure_message(actual) : String + abstract def match(actual) : MatchData - # Message displayed when the matcher isn't satisifed and is negated. - # This is only called when `#does_not_match?` returns false. - # - # A default implementation of this method is provided, - # which causes compilation to fail. - # If the matcher supports negation, it must override this method. - private def failure_message_when_negated(actual) : String - {% raise "Negation with #{@type.name} is not supported." %} - end - - # Checks whether the matcher is satisifed. - private abstract def match?(actual) : Bool - - # If the expectation is negated, then this method is called instead of `#match?`. - # The default implementation of this method is to invert the result of `#match?`. - # If the matcher requires custom handling of negated matches, - # then this method should be overriden. - # Remember to override `#failure_message_when_negated` as well. - private def does_not_match?(actual) : Bool - !matches?(actual) - end - - private def values(actual) : Array(LabeledValue) - [LabeledValue.new(actual.value.inspect, "actual")] - end - - private def negated_values(actual) : Array(LabeledValue) - values - end - - def match(actual) - if match?(actual) - SuccessfulMatchData.new - else - FailedMatchData.new(failure_message(actual), values(actual)) - end - end - - def negated_match(actual) - if does_not_match?(actual) - SuccessfulMatchData.new - else - FailedMatchData.new(failure_message_when_negated(actual), negated_values(actual)) - end - end + abstract def negated_match(actual) : MatchData end end diff --git a/src/spectator/matchers/standard_matcher.cr b/src/spectator/matchers/standard_matcher.cr new file mode 100644 index 0000000..491e21d --- /dev/null +++ b/src/spectator/matchers/standard_matcher.cr @@ -0,0 +1,59 @@ +require "../test_value" +require "./failed_match_data" +require "./matcher" +require "./successful_match_data" + +module Spectator::Matchers + # Provides common methods for matchers. + abstract struct StandardMatcher < Matcher + # Message displayed when the matcher isn't satisifed. + # This is only called when `#matches?` returns false. + private abstract def failure_message(actual) : String + + # Message displayed when the matcher isn't satisifed and is negated. + # This is only called when `#does_not_match?` returns false. + # + # A default implementation of this method is provided, + # which causes compilation to fail. + # If the matcher supports negation, it must override this method. + private def failure_message_when_negated(actual) : String + {% raise "Negation with #{@type.name} is not supported." %} + end + + # Checks whether the matcher is satisifed. + private abstract def match?(actual) : Bool + + # If the expectation is negated, then this method is called instead of `#match?`. + # The default implementation of this method is to invert the result of `#match?`. + # If the matcher requires custom handling of negated matches, + # then this method should be overriden. + # Remember to override `#failure_message_when_negated` as well. + private def does_not_match?(actual) : Bool + !matches?(actual) + end + + private def values(actual) : Array(LabeledValue) + [LabeledValue.new(actual.value.inspect, "actual")] + end + + private def negated_values(actual) : Array(LabeledValue) + values + end + + def match(actual) + if match?(actual) + SuccessfulMatchData.new + else + FailedMatchData.new(failure_message(actual), values(actual)) + end + end + + def negated_match(actual) + if does_not_match?(actual) + SuccessfulMatchData.new + else + FailedMatchData.new(failure_message_when_negated(actual), negated_values(actual)) + end + end + end +end diff --git a/src/spectator/matchers/value_matcher.cr b/src/spectator/matchers/value_matcher.cr index 7e09a08..7c5e0ca 100644 --- a/src/spectator/matchers/value_matcher.cr +++ b/src/spectator/matchers/value_matcher.cr @@ -1,9 +1,9 @@ -require "./matcher" +require "./standard_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. - abstract struct ValueMatcher(ExpectedType) < Matcher + abstract struct ValueMatcher(ExpectedType) < StandardMatcher # Expected value. # Sub-types may use this value to test the expectation and generate message strings. private getter expected : TestValue(ExpectedType) From 436c10cad6df184805b6205731a8a04ec4da6b94 Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Tue, 6 Aug 2019 23:13:33 -0600 Subject: [PATCH 32/78] Simplify match data values by using named tuples --- src/spectator/matchers/array_matcher.cr | 28 ++++++++----------- src/spectator/matchers/contain_matcher.cr | 10 +++---- src/spectator/matchers/empty_matcher.cr | 4 +-- src/spectator/matchers/failed_match_data.cr | 6 ++-- .../matchers/greater_than_equal_matcher.cr | 16 +++++------ .../matchers/greater_than_matcher.cr | 16 +++++------ .../matchers/less_than_equal_matcher.cr | 16 +++++------ src/spectator/matchers/less_than_matcher.cr | 16 +++++------ src/spectator/matchers/standard_matcher.cr | 8 +++--- src/spectator/matchers/value_matcher.cr | 8 +++--- 10 files changed, 62 insertions(+), 66 deletions(-) diff --git a/src/spectator/matchers/array_matcher.cr b/src/spectator/matchers/array_matcher.cr index 268d0fe..acbf26d 100644 --- a/src/spectator/matchers/array_matcher.cr +++ b/src/spectator/matchers/array_matcher.cr @@ -1,4 +1,3 @@ -require "../test_value" require "./failed_match_data" require "./matcher" require "./successful_match_data" @@ -61,29 +60,26 @@ module Spectator::Matchers private def failed_size_mismatch(expected_elements, actual_elements, actual_label) FailedMatchData.new("#{actual_label} does not contain exactly #{expected.label} (size mismatch)", - [ - LabeledValue.new(expected_elements.inspect, "expected"), - LabeledValue.new(actual_elements.inspect, "actual"), - LabeledValue.new(expected_elements.size, "expected size"), - LabeledValue.new(actual_elements.size, "actual size"), - ]) + expected: expected_elements.inspect, + actual: actual_elements.inspect, + "expected size": expected_elements.size.to_s, + "actual size": actual_elements.size.to_s + ) end private def failed_content_mismatch(expected_elements, actual_elements, index, actual_label) FailedMatchData.new("#{actual_label} does not contain exactly #{expected.label} (element mismatch)", - [ - LabeledValue.new(expected_elements[index].inspect, "expected"), - LabeledValue.new(actual_elements[index].inspect, "actual"), - LabeledValue.new(index.to_s, "index"), - ]) + expected: expected_elements[index].inspect, + actual: actual_elements[index].inspect, + index: index.to_s + ) end private def failed_content_identical(expected_elements, actual_elements, actual_label) FailedMatchData.new("#{actual.label} contains exactly #{expected.label}", - [ - LabeledValue.new("Not #{expected_elements.inspect}", "expected"), - LabeledValue.new(actual_elements.inspect, "actual"), - ]) + expected: "Not #{expected_elements.inspect}", + actual: actual_elements.inspect + ) end end end diff --git a/src/spectator/matchers/contain_matcher.cr b/src/spectator/matchers/contain_matcher.cr index f707486..fa6d65a 100644 --- a/src/spectator/matchers/contain_matcher.cr +++ b/src/spectator/matchers/contain_matcher.cr @@ -22,11 +22,11 @@ module Spectator::Matchers "#{actual.label} contains #{expected.label}" end - private def values(actual) : Array(LabeledValue) - [ - LabeledValue.new(expected.value.inspect, "subset"), - LabeledValue.new(actual.value.inspect, "superset"), - ] + private def values(actual) + { + subset: expected.value.inspect, + superset: actual.value.inspect, + } end end end diff --git a/src/spectator/matchers/empty_matcher.cr b/src/spectator/matchers/empty_matcher.cr index dcd5582..658cd17 100644 --- a/src/spectator/matchers/empty_matcher.cr +++ b/src/spectator/matchers/empty_matcher.cr @@ -20,8 +20,8 @@ module Spectator::Matchers "#{actual.label} is empty" end - private def values(actual) : Array(LabeledValue) - [LabeledValue.new(actual.value.inspect, "actual")] + private def values(actual) + {actual: actual.value.inspect} end end end diff --git a/src/spectator/matchers/failed_match_data.cr b/src/spectator/matchers/failed_match_data.cr index 250cf64..eef1cb2 100644 --- a/src/spectator/matchers/failed_match_data.cr +++ b/src/spectator/matchers/failed_match_data.cr @@ -1,4 +1,3 @@ -require "../test_value" require "./match_data" module Spectator::Matchers @@ -9,9 +8,10 @@ module Spectator::Matchers getter failure_message : String - getter values : Array(LabeledValue) + getter values : Array(Tuple(Symbol, String)) - def initialize(@failure_message, @values = [] of LabeledValue) + def initialize(@failure_message, **values) + @values = values.to_a end end end diff --git a/src/spectator/matchers/greater_than_equal_matcher.cr b/src/spectator/matchers/greater_than_equal_matcher.cr index 9228a98..1a2ef80 100644 --- a/src/spectator/matchers/greater_than_equal_matcher.cr +++ b/src/spectator/matchers/greater_than_equal_matcher.cr @@ -21,17 +21,17 @@ module Spectator::Matchers end private def values(actual) - [ - LabeledValue.new(">= #{expected.value.inspect}", "expected"), - LabeledValue.new(actual.value.inspect, "actual"), - ] + { + expected: ">= #{expected.value.inspect}", + actual: actual.value.inspect, + } end private def negated_values(actual) - [ - LabeledValue.new("< #{expected.value.inspect}", "expected"), - LabeledValue.new(actual.value.inspect, "actual"), - ] + { + expected: "< #{expected.value.inspect}", + actual: actual.value.inspect, + } end end end diff --git a/src/spectator/matchers/greater_than_matcher.cr b/src/spectator/matchers/greater_than_matcher.cr index c65a038..12ec50f 100644 --- a/src/spectator/matchers/greater_than_matcher.cr +++ b/src/spectator/matchers/greater_than_matcher.cr @@ -21,17 +21,17 @@ module Spectator::Matchers end private def values(actual) - [ - LabeledValue.new("> #{expected.value.inspect}", "expected"), - LabeledValue.new(actual.value.inspect, "actual"), - ] + { + expected: "> #{expected.value.inspect}", + actual: actual.value.inspect, + } end private def negated_values(actual) - [ - LabeledValue.new("<= #{expected.value.inspect}", "expected"), - LabeledValue.new(actual.value.inspect, "actual"), - ] + { + expected: "<= #{expected.value.inspect}", + actual: actual.value.inspect, + } end end end diff --git a/src/spectator/matchers/less_than_equal_matcher.cr b/src/spectator/matchers/less_than_equal_matcher.cr index 2146257..da43df1 100644 --- a/src/spectator/matchers/less_than_equal_matcher.cr +++ b/src/spectator/matchers/less_than_equal_matcher.cr @@ -21,17 +21,17 @@ module Spectator::Matchers end private def values(actual) - [ - LabeledValue.new("<= #{expected.value.inspect}", "expected"), - LabeledValue.new(actual.value.inspect, "actual"), - ] + { + expected: "<= #{expected.value.inspect}", + actual: actual.value.inspect, + } end private def negated_values(actual) - [ - LabeledValue.new("> #{expected.value.inspect}", "expected"), - LabeledValue.new(actual.value.inspect, "actual"), - ] + { + expected: "> #{expected.value.inspect}", + actual: actual.value.inspect, + } end end end diff --git a/src/spectator/matchers/less_than_matcher.cr b/src/spectator/matchers/less_than_matcher.cr index e45f3d6..0c37302 100644 --- a/src/spectator/matchers/less_than_matcher.cr +++ b/src/spectator/matchers/less_than_matcher.cr @@ -21,17 +21,17 @@ module Spectator::Matchers end private def values(actual) - [ - LabeledValue.new("< #{expected.value.inspect}", "expected"), - LabeledValue.new(actual.value.inspect, "actual"), - ] + { + expected: "< #{expected.value.inspect}", + actual: actual.value.inspect, + } end private def negated_values(actual) - [ - LabeledValue.new(">= #{expected.value.inspect}", "expected"), - LabeledValue.new(actual.value.inspect, "actual"), - ] + { + expected: ">= #{expected.value.inspect}", + actual: actual.value.inspect, + } end end end diff --git a/src/spectator/matchers/standard_matcher.cr b/src/spectator/matchers/standard_matcher.cr index 491e21d..63ba640 100644 --- a/src/spectator/matchers/standard_matcher.cr +++ b/src/spectator/matchers/standard_matcher.cr @@ -32,12 +32,12 @@ module Spectator::Matchers !matches?(actual) end - private def values(actual) : Array(LabeledValue) - [LabeledValue.new(actual.value.inspect, "actual")] + private def values(actual) + {actual: actual.value.inspect} end - private def negated_values(actual) : Array(LabeledValue) - values + private def negated_values(actual) + values(actual) end def match(actual) diff --git a/src/spectator/matchers/value_matcher.cr b/src/spectator/matchers/value_matcher.cr index 7c5e0ca..fc00c42 100644 --- a/src/spectator/matchers/value_matcher.cr +++ b/src/spectator/matchers/value_matcher.cr @@ -13,12 +13,12 @@ module Spectator::Matchers def initialize(@expected) end - private def values(actual) : Array(LabeledValue) - super(actual) << LabeledValue.new(expected.value.inspect, "expected") + private def values(actual) + super.merge(expected: expected.value.inspect) end - private def negated_values(actual) : Array(LabeledValue) - super(actual) << LabeledValue.new("Not #{expected.value.inspect}", "expected") + private def negated_values(actual) + super.merge(expected: "Not #{expected.value.inspect}") end end end From 98b2cbc9cbba35da2691f861ef555b45e7ddccc4 Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Tue, 6 Aug 2019 23:20:23 -0600 Subject: [PATCH 33/78] Fix type inference --- src/spectator/matchers/array_matcher.cr | 4 ++-- src/spectator/matchers/value_matcher.cr | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/spectator/matchers/array_matcher.cr b/src/spectator/matchers/array_matcher.cr index acbf26d..e19153e 100644 --- a/src/spectator/matchers/array_matcher.cr +++ b/src/spectator/matchers/array_matcher.cr @@ -7,9 +7,9 @@ module Spectator::Matchers # Matcher for checking that the contents of one array (or similar type) # has the exact same contents as another and in the same order. struct ArrayMatcher(ExpectedType) < Matcher - private getter expected : TestValue(ExpectedType) + private getter expected - def initialize(@expected) + def initialize(@expected : TestValue(Enumerable(ExpectedType))) end def description diff --git a/src/spectator/matchers/value_matcher.cr b/src/spectator/matchers/value_matcher.cr index fc00c42..0710918 100644 --- a/src/spectator/matchers/value_matcher.cr +++ b/src/spectator/matchers/value_matcher.cr @@ -6,11 +6,11 @@ module Spectator::Matchers abstract struct ValueMatcher(ExpectedType) < StandardMatcher # Expected value. # Sub-types may use this value to test the expectation and generate message strings. - private getter expected : TestValue(ExpectedType) + private getter expected # Creates the value matcher. # The expected value is stored for later use. - def initialize(@expected) + def initialize(@expected : TestValue(ExpectedType)) end private def values(actual) From 3314ce85797d48d95fbbce8a0e1cf6fd34de0c1b Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Tue, 6 Aug 2019 23:21:08 -0600 Subject: [PATCH 34/78] Remove ExpectedActual utility class Don't think this is needed anymore. --- src/spectator/matchers/expected_actual.cr | 30 ----------------------- 1 file changed, 30 deletions(-) delete mode 100644 src/spectator/matchers/expected_actual.cr diff --git a/src/spectator/matchers/expected_actual.cr b/src/spectator/matchers/expected_actual.cr deleted file mode 100644 index d4efe63..0000000 --- a/src/spectator/matchers/expected_actual.cr +++ /dev/null @@ -1,30 +0,0 @@ -module Spectator::Matchers - # Stores values and labels for expected and actual values. - private struct ExpectedActual(ExpectedType, ActualType) - # The expected value. - getter expected : ExpectedType - - # The user label for the expected value. - getter expected_label : String - - # The actual value. - getter actual : ActualType - - # The user label for the actual value. - getter actual_label : String - - # Creates the value and label store. - def initialize(@expected : ExpectedType, @expected_label, @actual : ActualType, @actual_label) - end - - # Creates the value and label store. - # Attributes are pulled from an expectation partial and matcher. - def initialize( - partial : Spectator::Expectations::ValueExpectationPartial(ActualType) | - Spectator::Expectations::BlockExpectationPartial(ActualType), - matcher : ValueMatcher(ExpectedType) - ) - initialize(matcher.expected, matcher.label, partial.actual, partial.label) - end - end -end From 6a317b7a21b9c9e6f259c0e2aaec88f6d318f739 Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Tue, 6 Aug 2019 23:22:50 -0600 Subject: [PATCH 35/78] Re-add ordering methods --- src/spectator/matchers/array_matcher.cr | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/spectator/matchers/array_matcher.cr b/src/spectator/matchers/array_matcher.cr index e19153e..b994278 100644 --- a/src/spectator/matchers/array_matcher.cr +++ b/src/spectator/matchers/array_matcher.cr @@ -45,6 +45,14 @@ module Spectator::Matchers end end + def in_order + self + end + + def in_any_order + UnorderedArrayMatcher.new(expected) + end + private def compare_arrays(expected_elements, actual_elements) if expected_elements.size == actual_elements.size index = 0 From ec96bf2de2ceb15ba5bcd29dbac7dfcabd9da334 Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Tue, 6 Aug 2019 23:35:36 -0600 Subject: [PATCH 36/78] Refactor AttributesMatcher to use new style --- src/spectator/matchers/attributes_matcher.cr | 88 +++++++++----------- 1 file changed, 40 insertions(+), 48 deletions(-) diff --git a/src/spectator/matchers/attributes_matcher.cr b/src/spectator/matchers/attributes_matcher.cr index d7088ed..1061e99 100644 --- a/src/spectator/matchers/attributes_matcher.cr +++ b/src/spectator/matchers/attributes_matcher.cr @@ -1,71 +1,63 @@ -require "./value_matcher" +require "../test_value" +require "./failed_match_data" +require "./matcher" +require "./successful_match_data" module Spectator::Matchers # Matcher that tests that multiple attributes match specified conditions. # 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. - private def match?(actual) - # Test each attribute and immediately return false if a comparison fails. - {% for attribute in ExpectedType.keys %} - return false unless expected[{{attribute.symbolize}}] === actual[{{attribute.symbolize}}] - {% end %} + # Each key in the tuple is the attribute/method name, + # and the corresponding value is the expected value to match against. + struct AttributesMatcher(ExpectedType) < Matcher + private getter expected - # All checks passed if this point is reached. - true + def initialize(@expected : TestValue(ExpectedType)) end - # Determines whether the matcher is satisfied with the partial given to it. - def match(partial, negated = false) - actual_values = snapshot_values(partial.actual) - values = ExpectedActual.new(expected, label, actual_values, partial.label) - MatchData.new(match?(actual_values), values) + def description + "has attributes #{expected.label}" + end + + def match(actual) + snapshot = snapshot_values(actual.value) + if matched?(snapshot) + SuccessfulMatchData.new + else + FailedMatchData.new("#{actual.label} does not have attributes #{expected.label}", **values(snapshot)) + end + end + + def negated_match(actual) + snapshot = snapshot_values(actual.value) + if matched?(snapshot) + FailedMatchData.new("#{actual.label} has attributes #{expected.label}", **values(snapshot)) + else + SuccessfulMatchData.new + end end # Captures all of the actual values. - # A `NamedTuple` is returned, - # with each key being the attribute. - private def snapshot_values(actual) + # A `NamedTuple` is returned, with each key being the attribute. + private def snapshot_values(object) {% begin %} { {% for attribute in ExpectedType.keys %} - {{attribute}}: actual.{{attribute}}, + {{attribute}}: object.{{attribute}}, {% end %} } {% end %} end - # Match data specific to this matcher. - private struct MatchData(ExpectedType, ActualType) < MatchData - # Creates the match data. - def initialize(matched, @values : ExpectedActual(ExpectedType, ActualType)) - super(matched) - end - - # Information about the match. - def named_tuple - {% begin %} - { - {% for attribute in ExpectedType.keys %} - {{"expected " + attribute.stringify}}: NegatableMatchDataValue.new(@values.expected[{{attribute.symbolize}}]), - {{"actual " + attribute.stringify}}: @values.actual[{{attribute.symbolize}}], - {% end %} - } + private def values(snapshot) + {% begin %} + { + {% for attribute in ExpectedType.keys %} + {{"expected " + attribute.stringify}}: expected.value[{{attribute.symbolize}}]), + {{"actual " + attribute.stringify}}: snapshot[{{attribute.symbolize}}], {% end %} - end - - # Describes the condition that satisfies the matcher. - # This is informational and displayed to the end-user. - def message - "#{@values.actual_label} has attributes #{@values.expected_label}" - end - - # Describes the condition that won't satsify the matcher. - # This is informational and displayed to the end-user. - def negated_message - "#{@values.actual_label} does not have attributes #{@values.expected_label}" - end + } + {% end %} end end end From f2f46418a3a2c71e7cf343a1cc58a4f24f4697bb Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Wed, 7 Aug 2019 00:07:39 -0600 Subject: [PATCH 37/78] Refactor collection matcher --- src/spectator/matchers/collection_matcher.cr | 55 ++++++-------------- 1 file changed, 17 insertions(+), 38 deletions(-) diff --git a/src/spectator/matchers/collection_matcher.cr b/src/spectator/matchers/collection_matcher.cr index 47fcd2f..2a16822 100644 --- a/src/spectator/matchers/collection_matcher.cr +++ b/src/spectator/matchers/collection_matcher.cr @@ -1,18 +1,24 @@ +require "../test_value" +require "./range_matcher" require "./value_matcher" module Spectator::Matchers # Matcher for checking that a value is in a collection of other values. struct CollectionMatcher(ExpectedType) < ValueMatcher(ExpectedType) - # Determines whether the matcher is satisfied with the value given to it. private def match?(actual) - expected.includes?(actual) + expected.value.includes?(actual.value) end - # Determines whether the matcher is satisfied with the partial given to it. - def match(partial, negated = false) - actual = partial.actual - matched = match?(actual) - MatchData.new(matched, ExpectedActual.new(partial, self)) + def description + "is in #{expected.label}" + end + + private def failure_message(actual) + "#{actual.label} is not in #{expected.label}" + end + + private def failure_message_when_negated(actual) + "#{actual.label} is in #{expected.label}" end # Creates a new range matcher with bounds based off of *center*. @@ -20,7 +26,7 @@ module Spectator::Matchers # This method expects that the original matcher was created with a "difference" value. # That is: # ``` - # RangeMatcher.new(diff).of(center) + # CollectionMatcher.new(diff).of(center) # ``` # This implies that the `#match` method would not work on the original matcher. # @@ -28,39 +34,12 @@ module Spectator::Matchers # and have upper and lower bounds equal to *center* plus and minus diff. # The range will be inclusive. def of(center) - diff = @expected + diff = @expected.value lower = center - diff upper = center + diff range = Range.new(lower, upper) - RangeMatcher.new(range, "#{center} +/- #{label}") - end - - # Match data specific to this matcher. - private struct MatchData(ExpectedType, ActualType) < MatchData - # Creates the match data. - def initialize(matched, @values : ExpectedActual(ExpectedType, ActualType)) - super(matched) - end - - # Information about the match. - def named_tuple - { - collection: NegatableMatchDataValue.new(@values.expected), - actual: @values.actual, - } - end - - # Describes the condition that satisfies the matcher. - # This is informational and displayed to the end-user. - def message - "#{@values.actual_label} is in #{@values.expected_label}" - end - - # Describes the condition that won't satsify the matcher. - # This is informational and displayed to the end-user. - def negated_message - "#{@values.actual_label} is not in #{@values.expected_label}" - end + test_value = TestValue.new(range, "#{center} +/- #{expected.label}") + RangeMatcher.new(test_value) end end end From 72e5735106676272a826325f224f18fc56d6be7d Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Wed, 7 Aug 2019 00:08:32 -0600 Subject: [PATCH 38/78] Refactor EndWithMatcher --- src/spectator/matchers/end_with_matcher.cr | 126 ++++++++++----------- 1 file changed, 62 insertions(+), 64 deletions(-) diff --git a/src/spectator/matchers/end_with_matcher.cr b/src/spectator/matchers/end_with_matcher.cr index 63d9fa4..986fbf2 100644 --- a/src/spectator/matchers/end_with_matcher.cr +++ b/src/spectator/matchers/end_with_matcher.cr @@ -1,88 +1,86 @@ -require "./value_matcher" +require "./failed_match_data" +require "./matcher" +require "./successful_match_data" module Spectator::Matchers # Matcher that tests whether a value, such as a `String` or `Array`, ends with a value. # The `ends_with?` method is used if it's defined on the actual type. # Otherwise, it is treated as an `Indexable` and the `last` value is compared against. - struct EndWithMatcher(ExpectedType) < ValueMatcher(ExpectedType) - # Determines whether the matcher is satisfied with the value given to it. - private def match_ends_with?(actual) - actual.ends_with?(expected) + struct EndWithMatcher(ExpectedType) < Matcher + private getter expected + + def initialize(@expected : TestValue(ExpectedType)) end - # Determines whether the matcher is satisfied with the value given to it. - private def match_last?(actual) - expected === actual + def description + "ends with #{expected.label}" end - # Determines whether the matcher is satisfied with the partial given to it. - def match(partial, negated = false) - values = ExpectedActual.new(partial, self) - actual = values.actual - if actual.responds_to?(:ends_with?) - EndsWithMatchData.new(match_ends_with?(actual), values) + def match(actual) + if actual.value.responds_to?(:ends_with?) + match_ends_with(actual) else - last = actual.last - LastMatchData.new(match_last?(last), values, last) + match_last(actual) end end - # Match data specific to this matcher. - # This type is used when the actual value responds to `ends_with?`. - private struct EndsWithMatchData(ExpectedType, ActualType) < MatchData - # Creates the match data. - def initialize(matched, @values : ExpectedActual(ExpectedType, ActualType)) - super(matched) - end - - # Information about the match. - def named_tuple - { - expected: NegatableMatchDataValue.new(@values.expected), - actual: @values.actual, - } - end - - # Describes the condition that satisfies the matcher. - # This is informational and displayed to the end-user. - def message - "#{@values.actual_label} ends with #{@values.expected_label} (using #ends_with?)" - end - - # Describes the condition that won't satsify the matcher. - # This is informational and displayed to the end-user. - def negated_message - "#{@values.actual_label} does not end with #{@values.expected_label} (using #ends_with?)" + private def match_ends_with(actual) + if actual.value.ends_with?(expected.value) + SuccessfulMatchData.new + else + FailedMatchData.new("#{actual.label} does not end with #{expected.label} (using #ends_with?)", + expected: expected.value.inspect, + actual: actual.value.inspect + ) end end - # Match data specific to this matcher. - # This type is used when the actual value does not respond to `ends_with?`. - private struct LastMatchData(ExpectedType, ActualType, LastType) < MatchData - # Creates the match data. - def initialize(matched, @values : ExpectedActual(ExpectedType, ActualType), @last : LastType) - super(matched) - end + private def match_last(actual) + list = actual.value.to_a + last = list.last - # Information about the match. - def named_tuple - { - expected: @values.expected, - actual: @last, - list: @values.actual, - } + if expected.value === last + SuccessfulMatchData.new + else + FailedMatchData.new("#{actual.label} does not end with #{expected.label} (using expected === last)", + expected: expected.value, + actual: last, + list: list + ) end + end - # Describes the condition that satisfies the matcher. - # This is informational and displayed to the end-user. - def message - "#{@values.actual_label} ends with #{@values.expected_label} (using expected === actual.last)" + def negated_match(actual) + if actual.value.responds_to?(:ends_with?) + negated_match_ends_with(actual) + else + negated_match_last(actual) end + end - # Describes the condition that won't satsify the matcher. - # This is informational and displayed to the end-user. - def negated_message - "#{@values.actual_label} does not end with #{@values.expected_label} (using expected === actual.last)" + private def negated_match_ends_with(actual) + if actual.value.ends_with?(expected.value) + FailedMatchData.new("#{actual.label} ends with #{expected.label} (using #ends_with?)", + expected: expected.value.inspect, + actual: actual.value.inspect + ) + else + SuccessfulMatchData.new + end + end + + private def negated_match_last(actual) + list = actual.value.to_a + last = list.last + + if expected.value === last + FailedMatchData.new("#{actual.label} ends with #{expected.label} (using expected === last)", + expected: expected.value, + actual: last, + list: list + ) + else + SuccessfulMatchData.new end end end From 7cca43029eef3efe70b2ce9316796168b35fb7b8 Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Thu, 8 Aug 2019 14:20:21 -0600 Subject: [PATCH 39/78] Refactor ExceptionMatcher --- src/spectator/matchers/exception_matcher.cr | 158 ++++++++------------ 1 file changed, 65 insertions(+), 93 deletions(-) diff --git a/src/spectator/matchers/exception_matcher.cr b/src/spectator/matchers/exception_matcher.cr index 738281e..c4b9197 100644 --- a/src/spectator/matchers/exception_matcher.cr +++ b/src/spectator/matchers/exception_matcher.cr @@ -1,11 +1,65 @@ -require "./value_matcher" +require "../test_value" +require "./failed_match_data" +require "./matcher" +require "./successful_match_data" module Spectator::Matchers # Matcher that tests whether an exception is raised. - struct ExceptionMatcher(ExceptionType, ExpectedType) < ValueMatcher(ExpectedType) - # Determines whether the matcher is satisfied with the value given to it. - private def match?(exception) - exception.is_a?(ExceptionType) && (expected.nil? || expected === exception.message) + struct ExceptionMatcher(ExceptionType, ExpectedType) < Matcher + private getter expected + + def initialize + @expected = TestValue.new(nil, ExceptionType.to_s) + end + + def initialize(@expected : TestValue(ExpectedType)) + end + + def match(actual) + exception = capture_exception { actual.value } + case exception + when Nil + FailedMatchData.new("#{actual.label} did not raise", expected: ExpectedType.inspect) + when ExceptionType + if expected.value.nil? || expected.value === exception.message + SuccessfulMatchData.new + else + FailedMatchData.new("#{actual.label} raised #{ExpectedType}, but the message is not #{expected.label}", + "expected type": ExceptionType.inspect, + "actual type": exception.class.inspect, + "expected message": expected.value.inspect, + "actual message": exception.message + ) + end + else + FailedMatchData.new("#{actual.label} did not raise #{ExpectedType}", + expected: ExpectedType.inspect, + actual: exception.class.inspect + ) + end + end + + def negated_match(actual) + exception = capture_exception { actual.value } + case exception + when Nil + SuccessfulMatchData.new + when ExceptionType + if expected.value.nil? + FailedMatchData.new("#{actual.label} raised #{ExpectedType}") + elsif expected.value === exception.message + FailedMatchData.new("#{actual.label} raised #{ExpectedType} with message matching #{expected.label}", + "expected type": ExceptionType.inspect, + "actual type": exception.class.inspect, + "expected message": expected.value.inspect, + "actual message": exception.message + ) + else + SuccessfulMatchData.new + end + else + SuccessfulMatchData.new + end end # Runs a block of code and returns the exception it threw. @@ -20,103 +74,21 @@ module Spectator::Matchers exception end - # Determines whether the matcher is satisfied with the partial given to it. - def match(partial, negated = false) - exception = capture_exception { partial.actual } - matched = match?(exception) - if exception.nil? - MatchData.new(ExceptionType, matched, ExpectedActual.new(expected, label, exception, partial.label)) - else - values = ExpectedActual.new(expected, label, exception, partial.label) - if expected.nil? - MatchData.new(ExceptionType, matched, values) - else - MessageMatchData.new(ExceptionType, matched, values) - end - end - end - - # Creates a new exception matcher with no message check. - def initialize - super(nil, ExceptionType.to_s) - end - - # Creates a new exception matcher with a message check. - def initialize(expected : ExpectedType, label : String) - super(expected, label) - end - # Creates a new exception matcher with no message check. def self.create(exception_type : T.class, label : String) forall T ExceptionMatcher(T, Nil).new end # Creates a new exception matcher with a message check. - def self.create(expected, label : String) - ExceptionMatcher(Exception, typeof(expected)).new(expected, label) + def self.create(value, label : String) + expected = TestValue.new(value, label) + ExceptionMatcher(Exception, typeof(value)).new(expected) end # Creates a new exception matcher with a type and message check. - def self.create(exception_type : T.class, expected, label : String) forall T - ExceptionMatcher(T, typeof(expected)).new(expected, label) - end - - # Match data specific to this matcher. - private struct MatchData(ExceptionType, ExpectedType, ActualType) < MatchData - # Creates the match data. - def initialize(t : ExceptionType.class, matched, @values : ExpectedActual(ExpectedType, ActualType)) - super(matched) - end - - # Information about the match. - def named_tuple - { - "expected type": NegatableMatchDataValue.new(ExceptionType), - "actual type": @values.actual.class, - } - end - - # Describes the condition that satisfies the matcher. - # This is informational and displayed to the end-user. - def message - "#{@values.actual_label} raises #{ExceptionType}" - end - - # Describes the condition that won't satsify the matcher. - # This is informational and displayed to the end-user. - def negated_message - "#{@values.actual_label} does not raise #{ExceptionType}" - end - end - - # Match data specific to this matcher with an expected message. - private struct MessageMatchData(ExceptionType, ExpectedType) < ::Spectator::Matchers::MatchData - # Creates the match data. - def initialize(t : ExceptionType.class, matched, @values : ExpectedActual(ExpectedType, Exception)) - super(matched) - end - - # Information about the match. - def named_tuple - { - "expected type": NegatableMatchDataValue.new(ExceptionType), - "actual type": @values.actual.class, - "expected message": NegatableMatchDataValue.new(@values.expected), - "actual message": @values.actual.message, - } - end - - # Describes the condition that satisfies the matcher. - # This is informational and displayed to the end-user. - def message - "#{@values.actual_label} raises #{ExceptionType} with message #{@values.expected_label}" - end - - # Describes the condition that won't satsify the matcher. - # This is informational and displayed to the end-user. - def negated_message - "#{@values.actual_label} does not raise #{ExceptionType} with message #{@values.expected_label}" - end + def self.create(exception_type : T.class, value, label : String) forall T + expected = TestValue.new(value, label) + ExceptionMatcher(T, typeof(value)).new(expected) end end end From f1ebce7739577378a6186724b1c67bf8360dd7e6 Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Thu, 8 Aug 2019 15:25:32 -0600 Subject: [PATCH 40/78] Refactor HaveKeyMatcher and HaveValueMatcher --- src/spectator/matchers/have_key_matcher.cr | 47 +++++++------------- src/spectator/matchers/have_value_matcher.cr | 47 +++++++------------- 2 files changed, 32 insertions(+), 62 deletions(-) diff --git a/src/spectator/matchers/have_key_matcher.cr b/src/spectator/matchers/have_key_matcher.cr index 16b92cd..771f5ab 100644 --- a/src/spectator/matchers/have_key_matcher.cr +++ b/src/spectator/matchers/have_key_matcher.cr @@ -4,44 +4,29 @@ module Spectator::Matchers # Matcher that tests whether a `Hash` (or similar type) has a given key. # The set is checked with the `has_key?` method. struct HaveKeyMatcher(ExpectedType) < ValueMatcher(ExpectedType) - # Determines whether the matcher is satisfied with the value given to it. private def match?(actual) - actual.has_key?(expected) + actual.value.has_key?(expected.value) end - # Determines whether the matcher is satisfied with the partial given to it. - def match(partial, negated = false) - values = ExpectedActual.new(partial, self) - MatchData.new(match?(values.actual), values) + def description + "has key #{expected.label}" end - # Match data specific to this matcher. - private struct MatchData(ExpectedType, ActualType) < MatchData - # Creates the match data. - def initialize(matched, @values : ExpectedActual(ExpectedType, ActualType)) - super(matched) - end + private def failure_message(actual) + "#{actual.label} does not have key #{expected.label}" + end - # Information about the match. - def named_tuple - actual = @values.actual - { - key: NegatableMatchDataValue.new(@values.expected), - actual: actual.responds_to?(:keys) ? actual.keys : actual, - } - end + private def failure_message_when_negated(actual) + "#{actual.label} has key #{expected.label}" + end - # Describes the condition that satisfies the matcher. - # This is informational and displayed to the end-user. - def message - "#{@values.actual_label} has key #{@values.expected_label}" - end - - # Describes the condition that won't satsify the matcher. - # This is informational and displayed to the end-user. - def negated_message - "#{@values.actual_label} does not have key #{@values.expected_label}" - end + private def values(actual) + actual_value = actual.value + set = actual_value.responds_to?(:keys) ? actual_value.keys : actual_value + { + key: expected.value.inspect, + actual: set.inspect, + } end end end diff --git a/src/spectator/matchers/have_value_matcher.cr b/src/spectator/matchers/have_value_matcher.cr index 3d0cf8c..7a44f14 100644 --- a/src/spectator/matchers/have_value_matcher.cr +++ b/src/spectator/matchers/have_value_matcher.cr @@ -4,44 +4,29 @@ module Spectator::Matchers # Matcher that tests whether a `Hash` (or similar type) has a given value. # The set is checked with the `has_value?` method. struct HaveValueMatcher(ExpectedType) < ValueMatcher(ExpectedType) - # Determines whether the matcher is satisfied with the value given to it. private def match?(actual) - actual.has_value?(expected) + actual.value.has_value?(expected.value) end - # Determines whether the matcher is satisfied with the partial given to it. - def match(partial, negated = false) - values = ExpectedActual.new(partial, self) - MatchData.new(match?(values.actual), values) + def description + "has value #{expected.label}" end - # Match data specific to this matcher. - private struct MatchData(ExpectedType, ActualType) < MatchData - # Creates the match data. - def initialize(matched, @values : ExpectedActual(ExpectedType, ActualType)) - super(matched) - end + private def failure_message(actual) + "#{actual.label} does not have value #{expected.label}" + end - # Information about the match. - def named_tuple - actual = @values.actual - { - value: NegatableMatchDataValue.new(@values.expected), - actual: actual.responds_to?(:values) ? actual.values : actual, - } - end + private def failure_message_when_negated(actual) + "#{actual.label} has value #{expected.label}" + end - # Describes the condition that satisfies the matcher. - # This is informational and displayed to the end-user. - def message - "#{@values.actual_label} has value #{@values.expected_label}" - end - - # Describes the condition that won't satsify the matcher. - # This is informational and displayed to the end-user. - def negated_message - "#{@values.actual_label} does not have value #{@values.expected_label}" - end + private def values(actual) + actual_value = actual.value + set = actual_value.responds_to?(:values) ? actual_value.values : actual_value + { + value: expected.value.inspect, + actual: set.inspect, + } end end end From 17aa472d92becf2bae82419e8afb7cec0492f1d2 Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Thu, 8 Aug 2019 15:26:30 -0600 Subject: [PATCH 41/78] Refactor HaveMatcher --- src/spectator/matchers/have_matcher.cr | 66 ++++++++++---------------- 1 file changed, 25 insertions(+), 41 deletions(-) diff --git a/src/spectator/matchers/have_matcher.cr b/src/spectator/matchers/have_matcher.cr index 06f827d..6ac12bc 100644 --- a/src/spectator/matchers/have_matcher.cr +++ b/src/spectator/matchers/have_matcher.cr @@ -5,67 +5,51 @@ module Spectator::Matchers # For a `String`, the `includes?` method is used. # 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. private def match?(actual) - if actual.is_a?(String) - match_string?(actual) + actual_value = actual.value + if actual_value.is_a?(String) + match_string(actual_value) else - match_enumerable?(actual) + match_enumerable(actual_value) end end # Checks if a `String` matches the expected values. # The `includes?` method is used for this check. - private def match_string?(actual) - expected.all? do |item| - actual.includes?(item) + private def match_string?(actual_value) + expected.value.all? do |item| + actual_value.includes?(item) end end # Checks if an `Enumerable` matches the expected values. # The `===` operator is used on every item. - private def match_enumerable?(actual) - array = actual.to_a - expected.all? do |item| - array.any? do |elem| - item === elem + private def match_enumerable?(actual_value) + array = actual_value.to_a + expected.value.all? do |item| + array.any? do |element| + item === element end end end - # Determines whether the matcher is satisfied with the partial given to it. - def match(partial, negated = false) - values = ExpectedActual.new(partial, self) - MatchData.new(match?(values.actual), values) + def description + "includes #{expected.label}" end - # Match data specific to this matcher. - private struct MatchData(ExpectedType, ActualType) < MatchData - # Creates the match data. - def initialize(matched, @values : ExpectedActual(ExpectedType, ActualType)) - super(matched) - end + private def failure_message(actual) + "#{actual.label} does not include #{expected.label}" + end - # Information about the match. - def named_tuple - { - subset: NegatableMatchDataValue.new(@values.expected), - superset: @values.actual, - } - end + private def failure_message_when_negated(actual) + "#{actual.label} includes #{expected.label}" + end - # Describes the condition that satisfies the matcher. - # This is informational and displayed to the end-user. - def message - "#{@values.actual_label} includes #{@values.expected_label}" - end - - # Describes the condition that won't satsify the matcher. - # This is informational and displayed to the end-user. - def negated_message - "#{@values.actual_label} does not include #{@values.expected_label}" - end + private def values(actual) + { + subset: expected.value.inspect, + superset: actual.value.inspect, + } end end end From badccad2faa31b652f3f150ea25a3e188bfb2f1b Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Thu, 8 Aug 2019 15:45:34 -0600 Subject: [PATCH 42/78] Some more easy target refactors EmptyMatcher should extend StandardMatcher. --- src/spectator/matchers/empty_matcher.cr | 6 +-- src/spectator/matchers/inequality_matcher.cr | 49 +++++++---------- src/spectator/matchers/nil_matcher.cr | 44 ++++----------- src/spectator/matchers/reference_matcher.cr | 39 +++----------- src/spectator/matchers/size_matcher.cr | 51 ++++++++---------- src/spectator/matchers/size_of_matcher.cr | 52 ++++++++---------- src/spectator/matchers/type_matcher.cr | 57 ++++++++------------ 7 files changed, 106 insertions(+), 192 deletions(-) diff --git a/src/spectator/matchers/empty_matcher.cr b/src/spectator/matchers/empty_matcher.cr index 658cd17..4db31f9 100644 --- a/src/spectator/matchers/empty_matcher.cr +++ b/src/spectator/matchers/empty_matcher.cr @@ -3,7 +3,7 @@ require "./matcher" module Spectator::Matchers # Matcher that tests whether a collection is empty. # The values are checked with the `empty?` method. - struct EmptyMatcher < Matcher + struct EmptyMatcher < StandardMatcher private def match?(actual) actual.value.empty? end @@ -19,9 +19,5 @@ module Spectator::Matchers private def failure_message_when_negated(actual) "#{actual.label} is empty" end - - private def values(actual) - {actual: actual.value.inspect} - end end end diff --git a/src/spectator/matchers/inequality_matcher.cr b/src/spectator/matchers/inequality_matcher.cr index dad2548..c1bd6cd 100644 --- a/src/spectator/matchers/inequality_matcher.cr +++ b/src/spectator/matchers/inequality_matcher.cr @@ -4,43 +4,34 @@ module Spectator::Matchers # Matcher that tests whether two values do not equal each other. # The values are compared with the != operator. struct InequalityMatcher(ExpectedType) < ValueMatcher(ExpectedType) - # Determines whether the matcher is satisfied with the value given to it. private def match?(actual) - actual != expected + expected.value != actual.value end - # Determines whether the matcher is satisfied with the partial given to it. - def match(partial, negated = false) - values = ExpectedActual.new(partial, self) - MatchData.new(match?(values.actual), values) + def description + "is not equal to #{expected.label}" end - # Match data specific to this matcher. - private struct MatchData(ExpectedType, ActualType) < MatchData - # Creates the match data. - def initialize(matched, @values : ExpectedActual(ExpectedType, ActualType)) - super(matched) - end + private def failure_message(actual) + "#{actual.label} is equal to #{expected.label}" + end - # Information about the match. - def named_tuple - { - expected: NegatablePrefixedMatchDataValue.new("Not", "", @values.expected), - actual: @values.actual, - } - end + private def failure_message_when_negated(actual) + "#{actual.label} is not equal to #{expected.label}" + end - # Describes the condition that satisfies the matcher. - # This is informational and displayed to the end-user. - def message - "#{@values.actual_label} is not #{@values.expected_label} (using !=)" - end + private def values(actual) + { + expected: "Not #{expected.value.inspect}", + actual: actual.value.inspect, + } + end - # Describes the condition that won't satsify the matcher. - # This is informational and displayed to the end-user. - def negated_message - "#{@values.actual_label} is #{@values.expected_label} (using !=)" - end + private def negated_values(actual) + { + expected: expected.value.inspect, + actual: actual.value.inspect, + } end end end diff --git a/src/spectator/matchers/nil_matcher.cr b/src/spectator/matchers/nil_matcher.cr index 1619143..c97a663 100644 --- a/src/spectator/matchers/nil_matcher.cr +++ b/src/spectator/matchers/nil_matcher.cr @@ -3,45 +3,21 @@ require "./matcher" module Spectator::Matchers # Common matcher that tests whether a value is nil. # The `Object#nil?` method is used for this. - struct NilMatcher < Matcher - # Textual representation of what the matcher expects. - def label - "nil?" + struct NilMatcher < StandardMatcher + private def match?(actual) + actual.value.nil? end - # Determines whether the matcher is satisfied with the partial given to it. - def match(partial, negated = false) - actual = partial.actual - matched = actual.nil? - MatchData.new(matched, actual, partial.label) + def description + "is nil" end - # Match data specific to this matcher. - private struct MatchData(T) < MatchData - # Creates the match data. - def initialize(matched, @actual : T, @actual_label : String) - super(matched) - end + private def failure_message(actual) + "#{actual.label} is not nil" + end - # Information about the match. - def named_tuple - { - expected: NegatableMatchDataValue.new(nil), - actual: @actual, - } - end - - # Describes the condition that satisfies the matcher. - # This is informational and displayed to the end-user. - def message - "#{@actual_label} is nil" - end - - # Describes the condition that won't satsify the matcher. - # This is informational and displayed to the end-user. - def negated_message - "#{@actual_label} is not nil" - end + private def failure_message_when_negated(actual) + "#{actual.label} is nil" end end end diff --git a/src/spectator/matchers/reference_matcher.cr b/src/spectator/matchers/reference_matcher.cr index 3c0b9e4..42d84d3 100644 --- a/src/spectator/matchers/reference_matcher.cr +++ b/src/spectator/matchers/reference_matcher.cr @@ -4,43 +4,20 @@ module Spectator::Matchers # Matcher that tests whether two references are the same. # The values are compared with the `Reference#same?` method. struct ReferenceMatcher(ExpectedType) < ValueMatcher(ExpectedType) - # Determines whether the matcher is satisfied with the value given to it. private def match?(actual) - actual.same?(expected) + expected.value.same?(actual.value) end - # Determines whether the matcher is satisfied with the partial given to it. - def match(partial, negated = false) - values = ExpectedActual.new(partial, self) - MatchData.new(match?(values.actual), values) + def description + "is #{expected.label}" end - # Match data specific to this matcher. - private struct MatchData(ExpectedType, ActualType) < MatchData - # Creates the match data. - def initialize(matched, @values : ExpectedActual(ExpectedType, ActualType)) - super(matched) - end + private def failure_message(actual) + "#{actual.label} is not #{expected.label}" + end - # Information about the match. - def named_tuple - { - expected: NegatableMatchDataValue.new(@values.expected), - actual: @values.actual, - } - end - - # Describes the condition that satisfies the matcher. - # This is informational and displayed to the end-user. - def message - "#{@values.actual_label} is #{@values.expected_label}" - end - - # Describes the condition that won't satsify the matcher. - # This is informational and displayed to the end-user. - def negated_message - "#{@values.actual_label} is not #{@values.expected_label}" - end + private def failure_message_when_negated(actual) + "#{actual.label} is #{expected.label}" end end end diff --git a/src/spectator/matchers/size_matcher.cr b/src/spectator/matchers/size_matcher.cr index 9e2a399..f4d37c9 100644 --- a/src/spectator/matchers/size_matcher.cr +++ b/src/spectator/matchers/size_matcher.cr @@ -4,39 +4,34 @@ module Spectator::Matchers # Matcher that tests whether a set has a specified number of elements. # The set's `#size` method is used for this check. struct SizeMatcher(ExpectedType) < ValueMatcher(ExpectedType) - # Determines whether the matcher is satisfied with the partial given to it. - def match(partial, negated = false) - actual = partial.actual.size - values = ExpectedActual.new(expected, label, actual, partial.label) - MatchData.new(actual == expected, values) + private def match?(actual) + expected.value == actual.value.size end - # Match data specific to this matcher. - private struct MatchData(ExpectedType, ActualType) < MatchData - # Creates the match data. - def initialize(matched, @values : ExpectedActual(ExpectedType, ActualType)) - super(matched) - end + def description + "has size #{expected.label}" + end - # Information about the match. - def named_tuple - { - expected: NegatableMatchDataValue.new(@values.expected), - actual: @values.actual, - } - end + private def failure_message(actual) + "#{actual.label} does not have #{expected.label} elements" + end - # Describes the condition that satisfies the matcher. - # This is informational and displayed to the end-user. - def message - "#{@values.actual_label} has #{@values.expected_label} elements" - end + private def failure_message_when_negated(actual) + "#{actual.label} has #{expected.label} elements" + end - # Describes the condition that won't satsify the matcher. - # This is informational and displayed to the end-user. - def negated_message - "#{@values.actual_label} does not have #{@values.expected_label} elements" - end + private def values(actual) + { + expected: expected.value.inspect, + actual: actual.value.size.inspect, + } + end + + private def negated_values(actual) + { + expected: "Not #{expected.value.inspect}", + actual: actual.value.size.inspect, + } end end end diff --git a/src/spectator/matchers/size_of_matcher.cr b/src/spectator/matchers/size_of_matcher.cr index d500d20..fefd10a 100644 --- a/src/spectator/matchers/size_of_matcher.cr +++ b/src/spectator/matchers/size_of_matcher.cr @@ -4,40 +4,34 @@ module Spectator::Matchers # Matcher that tests whether a set has the same number of elements as another set. # The set's `#size` method is used for this check. struct SizeOfMatcher(ExpectedType) < ValueMatcher(ExpectedType) - # Determines whether the matcher is satisfied with the partial given to it. - def match(partial, negated = false) - actual = partial.actual.size - size = expected.size - values = ExpectedActual.new(size, label, actual, partial.label) - MatchData.new(actual == size, values) + private def match?(actual) + expected.value.size == actual.value.size end - # Match data specific to this matcher. - private struct MatchData(ExpectedType, ActualType) < MatchData - # Creates the match data. - def initialize(matched, @values : ExpectedActual(ExpectedType, ActualType)) - super(matched) - end + def description + "is the same size as #{expected.label}" + end - # Information about the match. - def named_tuple - { - expected: NegatableMatchDataValue.new(@values.expected), - actual: @values.actual, - } - end + private def failure_message(actual) + "#{actual.label} is not the same size as #{expected.label}" + end - # Describes the condition that satisfies the matcher. - # This is informational and displayed to the end-user. - def message - "#{@values.actual_label} has the same number of elements as #{@values.expected_label}" - end + private def failure_message_when_negated(actual) + "#{actual.label} is the same size as #{expected.label}" + end - # Describes the condition that won't satsify the matcher. - # This is informational and displayed to the end-user. - def negated_message - "#{@values.actual_label} has a different number of elements than #{@values.expected_label}" - end + private def values(actual) + { + expected: expected.value.size.inspect, + actual: actual.value.size.inspect, + } + end + + private def negated_values(actual) + { + expected: "Not #{expected.value.size.inspect}", + actual: actual.value.size.inspect, + } end end end diff --git a/src/spectator/matchers/type_matcher.cr b/src/spectator/matchers/type_matcher.cr index 0b58c2f..16ee14c 100644 --- a/src/spectator/matchers/type_matcher.cr +++ b/src/spectator/matchers/type_matcher.cr @@ -3,50 +3,35 @@ require "./matcher" module Spectator::Matchers # Matcher that tests a value is of a specified type. # The values are compared with the `Object#is_a?` method. - struct TypeMatcher(Expected) < Matcher - # Textual representation of what the matcher expects. - # The `Expected` type param will be used to populate the label. - def label - Expected.to_s - end - - # Determines whether the matcher is satisfied with the value given to it. + struct TypeMatcher(Expected) < StandardMatcher private def match?(actual) - actual.is_a?(Expected) + actual.value.is_a?(Expected) end - # Determines whether the matcher is satisfied with the partial given to it. - def match(partial, negated = false) - actual = partial.actual - MatchData(Expected, typeof(actual)).new(match?(actual), actual, partial.label) + def description + "is as #{Expected}" end - # Match data specific to this matcher. - private struct MatchData(ExpectedType, ActualType) < MatchData - # Creates the match data. - def initialize(matched, @actual : ActualType, @actual_label : String) - super(matched) - end + private def failure_message(actual) + "#{actual.label} is not a #{Expected}" + end - # Information about the match. - def named_tuple - { - expected: NegatableMatchDataValue.new(ExpectedType), - actual: @actual.class, - } - end + private def failure_message_when_negated(actual) + "#{actual.label} is a #{Expected}" + end - # Describes the condition that satisfies the matcher. - # This is informational and displayed to the end-user. - def message - "#{@actual_label} is a #{ExpectedType}" - end + private def values(actual) + { + expected: Expected.to_s, + actual: actual.value.class.inspect, + } + end - # Describes the condition that won't satsify the matcher. - # This is informational and displayed to the end-user. - def negated_message - "#{@actual_label} is not a #{ExpectedType}" - end + private def negated_values(actual) + { + expected: "Not #{Expected}", + actual: actual.value.class.inspect, + } end end end From a3fa522bd4aa78901207daf3cff02492f451d836 Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Thu, 8 Aug 2019 15:59:31 -0600 Subject: [PATCH 43/78] Refactor TruthyMatcher --- src/spectator/matchers/truthy_matcher.cr | 103 +++++++++++------------ 1 file changed, 48 insertions(+), 55 deletions(-) diff --git a/src/spectator/matchers/truthy_matcher.cr b/src/spectator/matchers/truthy_matcher.cr index 4663c5e..3629a31 100644 --- a/src/spectator/matchers/truthy_matcher.cr +++ b/src/spectator/matchers/truthy_matcher.cr @@ -1,4 +1,4 @@ -require "./value_matcher" +require "./standard_matcher" module Spectator::Matchers # Matcher that tests whether a value is truthy or falsey. @@ -8,28 +8,51 @@ module Spectator::Matchers # # Additionally, different matchers can be created # by using the `#<`, `#<=`, `#>`, `#>=`, `#==`, and `#!=` operators. - struct TruthyMatcher < Matcher + struct TruthyMatcher < StandardMatcher # Creates the truthy matcher. # The *truthy* argument should be true to match "truthy" values, # and false to match "falsey" values. - def initialize(@truthy : Bool) + def initialize(@truthy : Bool = true) end - # Textual representation of what the matcher expects. - def label + private def label @truthy ? "truthy" : "falsey" end - # Determines whether the matcher is satisfied with the value given to it. - private def match?(actual) - # Cast value to truthy value and compare. - @truthy == !!actual + private def negated_label + @truthy ? "falsey" : "truthy" end - # Determines whether the matcher is satisfied with the partial given to it. - def match(partial, negated = false) - actual = partial.actual - MatchData.new(match?(actual), @truthy, actual, partial.label) + private def match?(actual) + @truthy == !!actual.value + end + + def description + "is #{label}" + end + + private def failure_message(actual) + "#{actual.label} is #{negated_label}" + end + + private def failure_message_when_negated(actual) + "#{actual.label} is #{label}" + end + + private def values(actual) + { + expected: @truthy ? "Not false or nil" : "false or nil", + actual: actual.value.inspect, + truthy: !!actual.value.inspect, + } + end + + private def negated_values(actual) + { + expected: @truthy ? "false or nil" : "Not false or nil", + actual: actual.value.inspect, + truthy: !!actual.value.inspect, + } end # Creates a matcher that checks if a value is less than an expected value. @@ -37,7 +60,8 @@ module Spectator::Matchers # ``` # expect(0).to be < 1 # ``` - def <(expected : ExpectedType) forall ExpectedType + def <(value : ExpectedType) forall ExpectedType + expected = TestValue.new(value) LessThanMatcher.new(expected) end @@ -46,7 +70,8 @@ module Spectator::Matchers # ``` # expect(0).to be <= 1 # ``` - def <=(expected : ExpectedType) forall ExpectedType + def <=(value : ExpectedType) forall ExpectedType + expected = TestValue.new(value) LessThanEqualMatcher.new(expected) end @@ -55,7 +80,8 @@ module Spectator::Matchers # ``` # expect(2).to be > 1 # ``` - def >(expected : ExpectedType) forall ExpectedType + def >(value : ExpectedType) forall ExpectedType + expected = TestValue.new(value) GreaterThanMatcher.new(expected) end @@ -64,7 +90,8 @@ module Spectator::Matchers # ``` # expect(2).to be >= 1 # ``` - def >=(expected : ExpectedType) forall ExpectedType + def >=(value : ExpectedType) forall ExpectedType + expected = TestValue.new(value) GreaterThanEqualMatcher.new(expected) end @@ -73,7 +100,8 @@ module Spectator::Matchers # ``` # expect(0).to be == 0 # ``` - def ==(expected : ExpectedType) forall ExpectedType + def ==(value : ExpectedType) forall ExpectedType + expected = TestValue.new(value) EqualityMatcher.new(expected) end @@ -82,44 +110,9 @@ module Spectator::Matchers # ``` # expect(0).to be != 1 # ``` - def !=(expected : ExpectedType) forall ExpectedType + def !=(value : ExpectedType) forall ExpectedType + expected = TestValue.new(value) InequalityMatcher.new(expected) end - - # Match data specific to this matcher. - private struct MatchData(ActualType) < MatchData - # Creates the match data. - def initialize(matched, @truthy : Bool, @actual : ActualType, @actual_label : String) - super(matched) - end - - # Information about the match. - def named_tuple - truthy = "Not false or nil" - falsey = "false or nil" - { - expected: AlternativeMatchDataValue.new(@truthy ? truthy : falsey, @truthy ? falsey : truthy), - actual: @actual, - truthy: !!@actual, - } - end - - # Describes the condition that satisfies the matcher. - # This is informational and displayed to the end-user. - def message - "#{@actual_label} is #{expected_label}" - end - - # Describes the condition that won't satsify the matcher. - # This is informational and displayed to the end-user. - def negated_message - "#{@actual_label} is not #{expected_label}" - end - - # Textual representation of what the matcher expects. - private def expected_label - @truthy ? "truthy" : "falsey" - end - end end end From cbaa9a4c43998d3868aa46b21ee7b5ffbad43b0f Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Thu, 8 Aug 2019 16:04:09 -0600 Subject: [PATCH 44/78] Refactor StartWithMatcher --- src/spectator/matchers/start_with_matcher.cr | 122 +++++++++---------- 1 file changed, 59 insertions(+), 63 deletions(-) diff --git a/src/spectator/matchers/start_with_matcher.cr b/src/spectator/matchers/start_with_matcher.cr index 2a4eba9..4de8700 100644 --- a/src/spectator/matchers/start_with_matcher.cr +++ b/src/spectator/matchers/start_with_matcher.cr @@ -4,85 +4,81 @@ module Spectator::Matchers # Matcher that tests whether a value, such as a `String` or `Array`, starts with a value. # The `starts_with?` method is used if it's defined on the actual type. # Otherwise, it is treated as an `Enumerable` and the `first` value is compared against. - struct StartWithMatcher(ExpectedType) < ValueMatcher(ExpectedType) - # Determines whether the matcher is satisfied with the value given to it. - private def match_starts_with?(actual) - actual.starts_with?(expected) + struct StartWithMatcher(ExpectedType) < Matcher + private getter expected + + def initialize(@expected : TestValue(ExpectedType)) end - # Determines whether the matcher is satisfied with the value given to it. - private def match_first?(actual) - expected === actual + def description + "starts with #{expected.label}" end - # Determines whether the matcher is satisfied with the partial given to it. - def match(partial, negated = false) - values = ExpectedActual.new(partial, self) - actual = values.actual - if actual.responds_to?(:starts_with?) - StartsWithMatchData.new(match_starts_with?(actual), values) + def match(actual) + if actual.value.responds_to?(:starts_with?) + match_starts_with(actual) else - first = actual.first - FirstMatchData.new(match_first?(first), values, first) + match_first(actual) end end - # Match data specific to this matcher. - # This type is used when the actual value responds to `starts_with?`. - private struct StartsWithMatchData(ExpectedType, ActualType) < MatchData - # Creates the match data. - def initialize(matched, @values : ExpectedActual(ExpectedType, ActualType)) - super(matched) - end - - # Information about the match. - def named_tuple - { - expected: NegatableMatchDataValue.new(@values.expected), - actual: @values.actual, - } - end - - # Describes the condition that satisfies the matcher. - # This is informational and displayed to the end-user. - def message - "#{@values.actual_label} starts with #{@values.expected_label} (using #starts_with?)" - end - - # Describes the condition that won't satsify the matcher. - # This is informational and displayed to the end-user. - def negated_message - "#{@values.actual_label} does not start with #{@values.expected_label} (using #starts_with?)" + private def match_starts_with(actual) + if actual.value.starts_with?(expected.value) + SuccessfulMatchData.new + else + FailedMatchData.new("#{actual.label} does not start with #{expected.label} (using #starts_with?)", + expected: expected.value.inspect, + actual: actual.value.inspect + ) end end - # Match data specific to this matcher. - # This type is used when the actual value does not respond to `ends_with?`. - private struct FirstMatchData(ExpectedType, ActualType, FirstType) < MatchData - # Creates the match data. - def initialize(matched, @values : ExpectedActual(ExpectedType, ActualType), @first : FirstType) - super(matched) - end + private def match_last(actual) + list = actual.value.to_a + first = list.first - # Information about the match. - def named_tuple - { - expected: @values.expected, - actual: @first, - list: @values.actual, - } + if expected.value === first + SuccessfulMatchData.new + else + FailedMatchData.new("#{actual.label} does not start with #{expected.label} (using expected === first)", + expected: expected.value, + actual: first, + list: list + ) end + end - # Describes the condition that satisfies the matcher. - # This is informational and displayed to the end-user. - def message - "#{@values.actual_label} starts with #{@values.expected_label} (using expected === actual.first)" + def negated_match(actual) + if actual.value.responds_to?(:starts_with?) + negated_match_starts_with(actual) + else + negated_match_first(actual) end + end - # Describes the condition that won't satsify the matcher. - # This is informational and displayed to the end-user. - def negated_message - "#{@values.actual_label} does not start with #{@values.expected_label} (using expected === actual.first)" + private def negated_match_starts_with(actual) + if actual.value.starts_with?(expected.value) + FailedMatchData.new("#{actual.label} starts with #{expected.label} (using #starts_with?)", + expected: expected.value.inspect, + actual: actual.value.inspect + ) + else + SuccessfulMatchData.new + end + end + + private def negated_match_first(actual) + list = actual.value.to_a + first = list.first + + if expected.value === first + FailedMatchData.new("#{actual.label} starts with #{expected.label} (using expected === first)", + expected: expected.value, + actual: first, + list: list + ) + else + SuccessfulMatchData.new end end end From 520c738f6a4688fd3d63c5b547f70db950bd408b Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Thu, 8 Aug 2019 16:47:17 -0600 Subject: [PATCH 45/78] Refactor RangeMatcher --- src/spectator/matchers/range_matcher.cr | 97 +++++++++++-------------- 1 file changed, 44 insertions(+), 53 deletions(-) diff --git a/src/spectator/matchers/range_matcher.cr b/src/spectator/matchers/range_matcher.cr index edc498c..7ec238e 100644 --- a/src/spectator/matchers/range_matcher.cr +++ b/src/spectator/matchers/range_matcher.cr @@ -4,74 +4,65 @@ module Spectator::Matchers # Matcher that tests whether a value is in a given range. # The `Range#includes?` method is used for this check. struct RangeMatcher(ExpectedType) < ValueMatcher(ExpectedType) - # Determines whether the matcher is satisfied with the value given to it. private def match?(actual) - expected.includes?(actual) + expected.value.includes?(actual.value) end - # Determines whether the matcher is satisfied with the partial given to it. - def match(partial, negated = false) - actual = partial.actual - matched = match?(actual) - expected_value = @expected - MatchData.new(matched, ExpectedActual.new(expected_value, label, actual, partial.label)) + def description + "is in #{expected.label}" + end + + private def failure_message(actual) + "#{actual.label} is not in #{expected.label} (#{exclusivity})" + end + + private def failure_message_when_negated(actual) + "#{actual.label} is in #{expected.label} (#{exclusivity})" + end + + private def values(actual) + { + lower: ">= #{range.begin.inspect}", + upper: "#{exclusive? ? "<" : "<="} #{range.end.inspect}", + actual: actual.value.inspect, + } + end + + private def negated_values(actual) + { + lower: "< #{range.begin.inspect}", + upper: "#{exclusive? ? ">=" : ">"} #{range.end.inspect}", + actual: actual.value.inspect, + } end # Returns a new matcher, with the same bounds, but uses an inclusive range. def inclusive - range = Range.new(@expected.begin, @expected.end, exclusive: false) - RangeMatcher.new(range, label) + new_range = Range.new(range.begin, range.end, exclusive: false) + expected = TestValue.new(new_range, label) + RangeMatcher.new(expected) end # Returns a new matcher, with the same bounds, but uses an exclusive range. def exclusive - range = Range.new(@expected.begin, @expected.end, exclusive: true) - RangeMatcher.new(range, label) + new_range = Range.new(range.begin, range.end, exclusive: true) + expected = TestValue.new(new_range, label) + RangeMatcher.new(expected) end - # Match data specific to this matcher. - # This is used when the expected type is a `Range`. - private struct MatchData(B, E, ActualType) < MatchData - # Creates the match data. - def initialize(matched, @values : ExpectedActual(Range(B, E), ActualType)) - super(matched) - end + # Gets the expected range. + private def range + expected.value + end - # Information about the match. - def named_tuple - { - lower: NegatablePrefixedMatchDataValue.new(">=", "<", range.begin), - upper: NegatablePrefixedMatchDataValue.new(exclusive? ? "<" : "<=", exclusive? ? ">=" : ">", range.end), - actual: @values.actual, - } - end + # Indicates whether the range is inclusive or exclusive. + private def exclusive? + range.exclusive? + end - # Describes the condition that satisfies the matcher. - # This is informational and displayed to the end-user. - def message - "#{@values.actual_label} is in #{@values.expected_label} (#{exclusivity})" - end - - # Describes the condition that won't satsify the matcher. - # This is informational and displayed to the end-user. - def negated_message - "#{@values.actual_label} is not in #{@values.expected_label} (#{exclusivity})" - end - - # Gets the expected range. - private def range - @values.expected - end - - # Indicates whether the range is inclusive or exclusive. - private def exclusive? - range.exclusive? - end - - # Produces a string "inclusive" or "exclusive" based on the range. - private def exclusivity - exclusive? ? "exclusive" : "inclusive" - end + # Produces a string "inclusive" or "exclusive" based on the range. + private def exclusivity + exclusive? ? "exclusive" : "inclusive" end end end From 3ae16c6ec1c38c2d615b1ba359b55923075149b6 Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Thu, 8 Aug 2019 16:47:27 -0600 Subject: [PATCH 46/78] Refactor predicate and respond matchers Add missing match? method to AttributesMatcher. --- src/spectator/matchers/attributes_matcher.cr | 14 +++- .../matchers/have_predicate_matcher.cr | 68 ++++++++-------- src/spectator/matchers/predicate_matcher.cr | 70 ++++++++-------- src/spectator/matchers/respond_matcher.cr | 80 +++++++------------ 4 files changed, 108 insertions(+), 124 deletions(-) diff --git a/src/spectator/matchers/attributes_matcher.cr b/src/spectator/matchers/attributes_matcher.cr index 1061e99..8bb6757 100644 --- a/src/spectator/matchers/attributes_matcher.cr +++ b/src/spectator/matchers/attributes_matcher.cr @@ -21,7 +21,7 @@ module Spectator::Matchers def match(actual) snapshot = snapshot_values(actual.value) - if matched?(snapshot) + if match?(snapshot) SuccessfulMatchData.new else FailedMatchData.new("#{actual.label} does not have attributes #{expected.label}", **values(snapshot)) @@ -30,7 +30,7 @@ module Spectator::Matchers def negated_match(actual) snapshot = snapshot_values(actual.value) - if matched?(snapshot) + if match?(snapshot) FailedMatchData.new("#{actual.label} has attributes #{expected.label}", **values(snapshot)) else SuccessfulMatchData.new @@ -49,6 +49,16 @@ module Spectator::Matchers {% end %} end + private def match?(snapshot) + # Test that every attribute has the expected value. + {% for attribute in ExpectedType.keys %} + return false unless expected.value[{{attribute.symbolize}}] === snapshot[{{attribute.symbolize}}] + {% end %} + + # At this point, none of the checks failed, so the match was successful. + true + end + private def values(snapshot) {% begin %} { diff --git a/src/spectator/matchers/have_predicate_matcher.cr b/src/spectator/matchers/have_predicate_matcher.cr index 45aaaf0..eef56f7 100644 --- a/src/spectator/matchers/have_predicate_matcher.cr +++ b/src/spectator/matchers/have_predicate_matcher.cr @@ -7,57 +7,53 @@ module Spectator::Matchers # Each key in the tuple is a predicate (without the '?' and 'has_' prefix) to test. # Each value is a a `Tuple` of arguments to pass to the predicate method. struct HavePredicateMatcher(ExpectedType) < ValueMatcher(ExpectedType) - # Determines whether the matcher is satisfied with the value given to it. - private def match?(values) - # Test each predicate and immediately return false if one is false. - {% for attribute in ExpectedType.keys %} - return false unless values[{{attribute.symbolize}}] - {% end %} + private getter expected - # All checks passed if this point is reached. - true + def initialize(@expected : TestValue(ExpectedType)) end - # Determines whether the matcher is satisfied with the partial given to it. - def match(partial, negated = false) - values = snapshot_values(partial.actual) - MatchData.new(match?(values), values, partial.label, label) + def description + "has #{expected.label}" + end + + def match(actual) + snapshot = snapshot_values(actual.value) + if match?(snapshot) + SuccessfulMatchData.new + else + FailedMatchData.new("#{actual.label} does not have #{expected.label}", **snapshot) + end + end + + def negated_match(actual) + snapshot = snapshot_values(actual.value) + if match?(snapshot) + FailedMatchData.new("#{actual.label} has #{expected.label}", **snapshot) + else + SuccessfulMatchData.new + end end # Captures all of the actual values. - # A `NamedTuple` is returned, - # with each key being the attribute. - private def snapshot_values(actual) + # A `NamedTuple` is returned, with each key being the attribute. + private def snapshot_values(object) {% begin %} { {% for attribute in ExpectedType.keys %} - {{attribute}}: actual.has_{{attribute}}?(*@expected[{{attribute.symbolize}}]), + {{attribute}}: object.has_{{attribute}}?(*@expected[{{attribute.symbolize}}]), {% end %} } {% end %} end - # Match data specific to this matcher. - private struct MatchData(ActualType) < MatchData - # Creates the match data. - def initialize(matched, @named_tuple : ActualType, @actual_label : String, @expected_label : String) - super(matched) - end + private def match?(snapshot) + # Test each predicate and immediately return false if one is false. + {% for attribute in ExpectedType.keys %} + return false unless snapshot[{{attribute.symbolize}}] + {% end %} - # Information about the match. - getter named_tuple - - # Describes the condition that satisfies the matcher. - # This is informational and displayed to the end-user. - def message - "#{@actual_label} has #{@expected_label}" - end - - # Describes the condition that won't satsify the matcher. - # This is informational and displayed to the end-user. - def negated_message - "#{@actual_label} does not have #{@expected_label}" - end + # All checks passed if this point is reached. + true end end end diff --git a/src/spectator/matchers/predicate_matcher.cr b/src/spectator/matchers/predicate_matcher.cr index 2b0391b..507049c 100644 --- a/src/spectator/matchers/predicate_matcher.cr +++ b/src/spectator/matchers/predicate_matcher.cr @@ -5,58 +5,54 @@ module Spectator::Matchers # The `ExpectedType` type param should be a `NamedTuple`. # Each key in the tuple is a predicate (without the '?') to test. # Each value is a a `Tuple` of arguments to pass to the predicate method. - struct PredicateMatcher(ExpectedType) < ValueMatcher(ExpectedType) - # Determines whether the matcher is satisfied with the value given to it. - private def match?(values) - # Test each predicate and immediately return false if one is false. - {% for attribute in ExpectedType.keys %} - return false unless values[{{attribute.symbolize}}] - {% end %} + struct PredicateMatcher(ExpectedType) < Matcher(ExpectedType) + private getter expected - # All checks passed if this point is reached. - true + def initialize(@expected : TestValue(ExpectedType)) end - # Determines whether the matcher is satisfied with the partial given to it. - def match(partial, negated = false) - values = snapshot_values(partial.actual) - MatchData.new(match?(values), values, partial.label, label) + def description + "is #{expected.label}" + end + + def match(actual) + snapshot = snapshot_values(actual.value) + if match?(snapshot) + SuccessfulMatchData.new + else + FailedMatchData.new("#{actual.label} is not #{expected.label}", **snapshot) + end + end + + def negated_match(actual) + snapshot = snapshot_values(actual.value) + if match?(snapshot) + FailedMatchData.new("#{actual.label} is #{expected.label}", **snapshot) + else + SuccessfulMatchData.new + end end # Captures all of the actual values. - # A `NamedTuple` is returned, - # with each key being the attribute. - private def snapshot_values(actual) + # A `NamedTuple` is returned, with each key being the attribute. + private def snapshot_values(object) {% begin %} { {% for attribute in ExpectedType.keys %} - {{attribute}}: actual.{{attribute}}?(*@expected[{{attribute.symbolize}}]), + {{attribute}}: object.{{attribute}}?(*@expected[{{attribute.symbolize}}]), {% end %} } {% end %} end - # Match data specific to this matcher. - private struct MatchData(ActualType) < MatchData - # Creates the match data. - def initialize(matched, @named_tuple : ActualType, @actual_label : String, @expected_label : String) - super(matched) - end + private def match?(snapshot) + # Test each predicate and immediately return false if one is false. + {% for attribute in ExpectedType.keys %} + return false unless snapshot[{{attribute.symbolize}}] + {% end %} - # Information about the match. - getter named_tuple - - # Describes the condition that satisfies the matcher. - # This is informational and displayed to the end-user. - def message - "#{@actual_label} is #{@expected_label}" - end - - # Describes the condition that won't satsify the matcher. - # This is informational and displayed to the end-user. - def negated_message - "#{@actual_label} is not #{@expected_label}" - end + # All checks passed if this point is reached. + true end end end diff --git a/src/spectator/matchers/respond_matcher.cr b/src/spectator/matchers/respond_matcher.cr index ad0868d..99a728f 100644 --- a/src/spectator/matchers/respond_matcher.cr +++ b/src/spectator/matchers/respond_matcher.cr @@ -6,67 +6,49 @@ module Spectator::Matchers # The `ExpectedType` type param should be a `NamedTuple`, # with each key being the method to check and the value is ignored. struct RespondMatcher(ExpectedType) < Matcher - # Determines whether the matcher is satisfied with the value given to it. - private def match?(actual) - # The snapshot did the hard work. - # Here just check if all values are true. - actual.values.all? + def description + "responds to #{label}" end - # Determines whether the matcher is satisfied with the partial given to it. - def match(partial, negated = false) - values = snapshot_values(partial.actual) - MatchData.new(match?(values), values, partial.label, label) + private def label + # Prefix every method name with # and join them with commas. + {{ExpectedType.keys.map { |e| "##{e}".id }.splat.stringify}} + end + + def match(actual) + snapshot = snapshot_values(actual.value) + if match?(snapshot) + SuccessfulMatchData.new + else + FailedMatchData.new("#{actual.label} does not respond to #{label}", **snapshot) + end + end + + def negated_match(actual) + snapshot = snapshot_values(actual.value) + if match?(snapshot) + FailedMatchData.new("#{actual.label} responds to #{label}", **snapshot) + else + SuccessfulMatchData.new + end end # Captures all of the actual values. - # A `NamedTuple` is returned, - # with each key being the attribute. - private def snapshot_values(actual) + # A `NamedTuple` is returned, with each key being the attribute. + private def snapshot_values(object) {% begin %} { - {% for method in ExpectedType.keys %} - {{method.stringify}}: actual.responds_to?({{method.symbolize}}), + {% for attribute in ExpectedType.keys %} + {{attribute}}: object.responds_to?({{attribute.symbolize}}), {% end %} } {% end %} end - # Textual representation of what the matcher expects. - def label - # Prefix every method name with # and join them with commas. - {{ExpectedType.keys.map { |e| "##{e}".id }.splat.stringify}} - end - - # Match data specific to this matcher. - private struct MatchData(ActualType) < MatchData - # Creates the match data. - def initialize(matched, @actual : ActualType, @actual_label : String, @expected_label : String) - super(matched) - end - - # Information about the match. - def named_tuple - {% begin %} - { - {% for method in ActualType.keys %} - {{"responds to #" + method.stringify}}: @actual[{{method.symbolize}}], - {% end %} - } - {% end %} - end - - # Describes the condition that satisfies the matcher. - # This is informational and displayed to the end-user. - def message - "#{@actual_label} responds to #{@expected_label}" - end - - # Describes the condition that won't satsify the matcher. - # This is informational and displayed to the end-user. - def negated_message - "#{@actual_label} does not respond to #{@expected_label}" - end + private def match?(snapshot) + # The snapshot did the hard work. + # Here just check if all values are true. + snapshot.values.all? end end end From 9bffb300419cef28e33b7a3380675fabb65cc85e Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Thu, 8 Aug 2019 16:59:29 -0600 Subject: [PATCH 47/78] Refactor UnorderedArrayMatcher --- .../matchers/unordered_array_matcher.cr | 121 ++++++------------ 1 file changed, 37 insertions(+), 84 deletions(-) diff --git a/src/spectator/matchers/unordered_array_matcher.cr b/src/spectator/matchers/unordered_array_matcher.cr index cb13a34..8c5ed49 100644 --- a/src/spectator/matchers/unordered_array_matcher.cr +++ b/src/spectator/matchers/unordered_array_matcher.cr @@ -3,18 +3,45 @@ require "./value_matcher" module Spectator::Matchers # Matcher for checking that the contents of one array (or similar type) # has the exact same contents as another, but in any order. - struct UnorderedArrayMatcher(ExpectedType) < ValueMatcher(Enumerable(ExpectedType)) - # Determines whether the matcher is satisfied with the partial given to it. - def match(partial, negated = false) - expected_elements = expected.to_a - actual = partial.actual.to_a - missing, extra = array_diff(expected, actual) + struct UnorderedArrayMatcher(ExpectedType) < Matcher + private getter expected + + def initialize(@expected : TestValue(Enumerable(ExpectedType))) + end + + def description + "contains #{expected.label} in any order" + end + + def match(actual) + actual_elements = actual.value.to_a + expected_elements = expected.value.to_a + missing, extra = array_diff(expected_elements, actual_elements) - values = ExpectedActual.new(expected_elements, label, actual, partial.label) if missing.empty? && extra.empty? - IdenticalMatchData.new(values) + SuccessfulMatchData.new else - ContentMatchData.new(values, missing, extra) + FailedMatchData.new("#{actual_label} does not contain #{expected.label} (unordered)", + expected: expected_elements.inspect, + actual: actual_elements.inspect, + missing: missing.inspect, + extra: extra.inspect, + ) + end + end + + def negated_match(actual) + actual_elements = actual.value.to_a + expected_elements = expected.value.to_a + missing, extra = array_diff(expected_elements, actual_elements) + + if missing.empty? && extra.empty? + FailedMatchData.new("#{actual_label} contains #{expected.label} (unordered)", + expected: "Not #{expected_elements.inspect}", + actual: actual_elements.inspect, + ) + else + SuccessfulMatchData.new end end @@ -24,7 +51,7 @@ module Spectator::Matchers extra = actual.dup missing = [] of ExpectedType - # TODO: OPTIMIZE + # OPTIMIZE: Not very efficient at finding the difference. expected.each do |item| index = extra.index(item) if index @@ -36,79 +63,5 @@ module Spectator::Matchers {missing, extra} end - - # Creates the value matcher. - # The label should be a string representation of the expectation. - # The expected value is stored for later use. - def initialize(expected : Enumerable(ExpectedType), label : String) - super - end - - # Creates the value matcher. - # The label is generated by calling `#to_s` on the expected value. - # The expected value is stored for later use. - def initialize(expected : Enumerable(ExpectedType)) - super - end - - # Common functionality for all match data for this matcher. - private abstract struct CommonMatchData(ExpectedType, ActualType) < MatchData - # Creates the match data. - def initialize(matched, @values : ExpectedActual(Array(ExpectedType), Array(ActualType))) - super(matched) - end - - # Basic information about the match. - def named_tuple - { - expected: NegatableMatchDataValue.new(@values.expected), - actual: @values.actual, - } - end - - # Describes the condition that satisfies the matcher. - # This is informational and displayed to the end-user. - def message - "#{@values.actual_label} contains #{@values.expected_label} (unordered)" - end - end - - # Match data specific to this matcher. - # This type is used when the actual value matches the expected value. - private struct IdenticalMatchData(ExpectedType, ActualType) < CommonMatchData(ExpectedType, ActualType) - # Creates the match data. - def initialize(values : ExpectedActual(Array(ExpectedType), Array(ActualType))) - super(true, values) - end - - # Describes the condition that won't satsify the matcher. - # This is informational and displayed to the end-user. - def negated_message - "#{@values.actual_label} does not contain #{@values.expected_label} (unordered)" - end - end - - # Match data specific to this matcher. - # This type is used when the actual contents differs from the expected contents. - private struct ContentMatchData(ExpectedType, ActualType) < CommonMatchData(ExpectedType, ActualType) - # Creates the match data. - def initialize(values : ExpectedActual(Array(ExpectedType), Array(ActualType)), @missing : Array(ExpectedType), @extra : Array(ActualType)) - super(false, values) - end - - # Information about the match. - def named_tuple - super.merge({ - missing: @missing, - extra: @extra, - }) - end - - # Describes the condition that won't satsify the matcher. - # This is informational and displayed to the end-user. - def negated_message - "#{@values.actual_label} does not contain #{@values.expected_label} (content differs)" - end - end end end From 1222e24836a0d02681fc989c6a83e2f021fa6d9a Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Thu, 8 Aug 2019 17:03:47 -0600 Subject: [PATCH 48/78] Add missing methods to matchers Fix matcher inheritance. --- src/spectator/matchers/exception_matcher.cr | 8 ++++++++ src/spectator/matchers/have_predicate_matcher.cr | 8 ++++++++ src/spectator/matchers/predicate_matcher.cr | 10 +++++++++- 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/spectator/matchers/exception_matcher.cr b/src/spectator/matchers/exception_matcher.cr index c4b9197..d1a289e 100644 --- a/src/spectator/matchers/exception_matcher.cr +++ b/src/spectator/matchers/exception_matcher.cr @@ -15,6 +15,14 @@ module Spectator::Matchers def initialize(@expected : TestValue(ExpectedType)) end + def description + if (message = @expected) + "raises #{ExceptionType} with message #{message}" + else + "raises #{ExceptionType}" + end + end + def match(actual) exception = capture_exception { actual.value } case exception diff --git a/src/spectator/matchers/have_predicate_matcher.cr b/src/spectator/matchers/have_predicate_matcher.cr index eef56f7..ccd4451 100644 --- a/src/spectator/matchers/have_predicate_matcher.cr +++ b/src/spectator/matchers/have_predicate_matcher.cr @@ -34,6 +34,14 @@ module Spectator::Matchers end end + private def failure_message(actual) + "#{actual.label} does not have #{expected.label}" + end + + private def failure_message_when_negated(actual) + "#{actual.label} has #{expected.label}" + end + # Captures all of the actual values. # A `NamedTuple` is returned, with each key being the attribute. private def snapshot_values(object) diff --git a/src/spectator/matchers/predicate_matcher.cr b/src/spectator/matchers/predicate_matcher.cr index 507049c..6cbbb88 100644 --- a/src/spectator/matchers/predicate_matcher.cr +++ b/src/spectator/matchers/predicate_matcher.cr @@ -5,7 +5,7 @@ module Spectator::Matchers # The `ExpectedType` type param should be a `NamedTuple`. # Each key in the tuple is a predicate (without the '?') to test. # Each value is a a `Tuple` of arguments to pass to the predicate method. - struct PredicateMatcher(ExpectedType) < Matcher(ExpectedType) + struct PredicateMatcher(ExpectedType) < Matcher private getter expected def initialize(@expected : TestValue(ExpectedType)) @@ -33,6 +33,14 @@ module Spectator::Matchers end end + private def failure_message(actual) + "#{actual.label} is not #{expected.label}" + end + + private def failure_message_when_negated(actual) + "#{actual.label} is #{expected.label}" + end + # Captures all of the actual values. # A `NamedTuple` is returned, with each key being the attribute. private def snapshot_values(object) From 2eb51b9c41ea5e9bf4564a6a6d5a738d8c61dd40 Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Thu, 8 Aug 2019 17:05:44 -0600 Subject: [PATCH 49/78] Fix type inference in TestValue --- src/spectator/test_value.cr | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/spectator/test_value.cr b/src/spectator/test_value.cr index dcee9a2..3071a92 100644 --- a/src/spectator/test_value.cr +++ b/src/spectator/test_value.cr @@ -7,13 +7,13 @@ module Spectator getter value : T # Creates the expression value with a custom label. - def initialize(@value, label : String) + def initialize(@value : T, label : String) super(label) end # Creates the expression with a stringified value. # This is used for the "should" syntax and when the label doesn't matter. - def initialize(@value) + def initialize(@value : T) super(@value.to_s) end From 4665d5f68d8d6686d2e128e78b331a89db512c3d Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Thu, 8 Aug 2019 17:08:38 -0600 Subject: [PATCH 50/78] Fix inconsistent naming for test expressions --- src/spectator/dsl/example_dsl.cr | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/spectator/dsl/example_dsl.cr b/src/spectator/dsl/example_dsl.cr index df30978..60b8785 100644 --- a/src/spectator/dsl/example_dsl.cr +++ b/src/spectator/dsl/example_dsl.cr @@ -21,7 +21,7 @@ module Spectator::DSL macro expect(actual, _source_file = __FILE__, _source_line = __LINE__) test_value = ::Spectator::TestValue.new({{actual}}, {{actual.stringify}}) source = ::Spectator::Source.new({{_source_file}}, {{_source_line}}) - ::Spectator::Expectations::ExpectationPartial.new(value_actual, source) + ::Spectator::Expectations::ExpectationPartial.new(test_value, source) end # Starts an expectation on a block of code. @@ -78,7 +78,7 @@ module Spectator::DSL {% end %} source = ::Spectator::Source.new({{_source_file}}, {{_source_line}}) - ::Spectator::Expectations::ExpectationPartial.new(block_actual, source) + ::Spectator::Expectations::ExpectationPartial.new(test_block, source) end # Starts an expectation. From eef7e9ce3c0b23dc3b66eb394898e5e6d1ccc18a Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Thu, 8 Aug 2019 17:15:13 -0600 Subject: [PATCH 51/78] Wrap expression and label in TestValue --- src/spectator/dsl/matcher_dsl.cr | 48 ++++++++++++++++---------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/src/spectator/dsl/matcher_dsl.cr b/src/spectator/dsl/matcher_dsl.cr index 18feb87..408b4f2 100644 --- a/src/spectator/dsl/matcher_dsl.cr +++ b/src/spectator/dsl/matcher_dsl.cr @@ -12,7 +12,7 @@ module Spectator::DSL # expect(1 + 2).to eq(3) # ``` macro eq(expected) - ::Spectator::Matchers::EqualityMatcher.new({{expected}}, {{expected.stringify}}) + ::Spectator::Matchers::EqualityMatcher.new(::Spectator::TestValue.new({{expected}}, {{expected.stringify}}))) end # Indicates that some value should not equal another. @@ -24,7 +24,7 @@ module Spectator::DSL # expect(1 + 2).to ne(5) # ``` macro ne(expected) - ::Spectator::Matchers::InequalityMatcher.new({{expected}}, {{expected.stringify}}) + ::Spectator::Matchers::InequalityMatcher.new(::Spectator::TestValue.new({{expected}}, {{expected.stringify}})) end # Indicates that some value when compared to another satisfies an operator. @@ -44,7 +44,7 @@ module Spectator::DSL # expect("foo").to be_truthy # ``` macro be - ::Spectator::Matchers::TruthyMatcher.new(true) + ::Spectator::Matchers::TruthyMatcher.new end # Indicates that some object should be the same as another. @@ -58,7 +58,7 @@ module Spectator::DSL # expect(obj.dup).to_not be(obj) # ``` macro be(expected) - ::Spectator::Matchers::ReferenceMatcher.new({{expected}}, {{expected.stringify}}) + ::Spectator::Matchers::ReferenceMatcher.new(::Spectator::TestValue.new({{expected}}, {{expected.stringify}})) end # Indicates that some value should be of a specified type. @@ -115,7 +115,7 @@ module Spectator::DSL # expect(3 - 1).to be_lt(3) # ``` macro be_lt(expected) - ::Spectator::Matchers::LessThanMatcher.new({{expected}}, {{expected.stringify}}) + ::Spectator::Matchers::LessThanMatcher.new(::Spectator::TestValue.new({{expected}}, {{expected.stringify}})) end # Indicates that some value should be less than or equal to another. @@ -127,7 +127,7 @@ module Spectator::DSL # expect(3 - 1).to be_le(3) # ``` macro be_le(expected) - ::Spectator::Matchers::LessThanEqualMatcher.new({{expected}}, {{expected.stringify}}) + ::Spectator::Matchers::LessThanEqualMatcher.new(::Spectator::TestValue.new({{expected}}, {{expected.stringify}})) end # Indicates that some value should be greater than another. @@ -139,7 +139,7 @@ module Spectator::DSL # expect(3 + 1).to be_gt(3) # ``` macro be_gt(expected) - ::Spectator::Matchers::GreaterThanMatcher.new({{expected}}, {{expected.stringify}}) + ::Spectator::Matchers::GreaterThanMatcher.new(::Spectator::TestValue.new({{expected}}, {{expected.stringify}})) end # Indicates that some value should be greater than or equal to another. @@ -151,7 +151,7 @@ module Spectator::DSL # expect(3 + 1).to be_ge(3) # ``` macro be_ge(expected) - ::Spectator::Matchers::GreaterThanEqualMatcher.new({{expected}}, {{expected.stringify}}) + ::Spectator::Matchers::GreaterThanEqualMatcher.new(::Spectator::TestValue.new({{expected}}, {{expected.stringify}})) end # Indicates that some value should match another. @@ -168,7 +168,7 @@ module Spectator::DSL # expect({:foo, 5}).to match({Symbol, Int32}) # ``` macro match(expected) - ::Spectator::Matchers::CaseMatcher.new({{expected}}, {{expected.stringify}}) + ::Spectator::Matchers::CaseMatcher.new(::Spectator::TestValue.new({{expected}}, {{expected.stringify}})) end # Indicates that some value should be true. @@ -202,7 +202,7 @@ module Spectator::DSL # expect(true).to be_truthy # ``` macro be_truthy - ::Spectator::Matchers::TruthyMatcher.new(true) + ::Spectator::Matchers::TruthyMatcher.new end # Indicates that some value should be falsey. @@ -258,7 +258,7 @@ module Spectator::DSL # NOTE: Do not attempt to mix the two use cases. # It likely won't work and will result in a compilation error. macro be_within(expected) - ::Spectator::Matchers::CollectionMatcher.new({{expected}}, {{expected.stringify}}) + ::Spectator::Matchers::CollectionMatcher.new(::Spectator::TestValue.new({{expected}}, {{expected.stringify}})) end # Indicates that some value should be between a lower and upper-bound. @@ -279,7 +279,7 @@ module Spectator::DSL # ``` macro be_between(min, max) :Spectator::Matchers::RangeMatcher.new( - Range.new({{min}}, {{max}}), + ::Spectator::TestValue.new(Range.new({{min}}, {{max}})), [{{min.stringify}}, {{max.stringify}}].join(" to ") ) end @@ -339,7 +339,7 @@ module Spectator::DSL # expect(%w[foo bar]).to start_with(/foo/) # ``` macro start_with(expected) - ::Spectator::Matchers::StartWithMatcher.new({{expected}}, {{expected.stringify}}) + ::Spectator::Matchers::StartWithMatcher.new(::Spectator::TestValue.new({{expected}}, {{expected.stringify}})) end # Indicates that some value or set should end with another value. @@ -361,7 +361,7 @@ module Spectator::DSL # expect(%w[foo bar]).to end_with(/bar/) # ``` macro end_with(expected) - ::Spectator::Matchers::EndWithMatcher.new({{expected}}, {{expected.stringify}}) + ::Spectator::Matchers::EndWithMatcher.new(::Spectator::TestValue.new({{expected}}, {{expected.stringify}})) end # Indicates that some value or set should contain another value. @@ -384,7 +384,7 @@ module Spectator::DSL # expect(%i[a b c]).to contain(:a, :b) # ``` macro contain(*expected) - ::Spectator::Matchers::ContainMatcher.new({{expected}}, {{expected.splat.stringify}}) + ::Spectator::Matchers::ContainMatcher.new(::Spectator::TestValue.new({{expected}}, {{expected.splat.stringify}})) end # Indicates that some value or set should contain another value. @@ -413,7 +413,7 @@ module Spectator::DSL # expect(%w[FOO BAR BAZ]).to have(/foo/i, String) # ``` macro have(*expected) - ::Spectator::Matchers::HaveMatcher.new({{expected}}, {{expected.splat.stringify}}) + ::Spectator::Matchers::HaveMatcher.new(::Spectator::TestValue.new({{expected}}, {{expected.splat.stringify}})) end # Indicates that some set, such as a `Hash`, has a given key. @@ -425,7 +425,7 @@ module Spectator::DSL # expect({"lucky" => 7}).to have_key("lucky") # ``` macro have_key(expected) - ::Spectator::Matchers::HaveKeyMatcher.new({{expected}}, {{expected.stringify}}) + ::Spectator::Matchers::HaveKeyMatcher.new(::Spectator::TestValue.new({{expected}}, {{expected.stringify}})) end # ditto @@ -442,7 +442,7 @@ module Spectator::DSL # expect({"lucky" => 7}).to have_value(7) # ``` macro have_value(expected) - ::Spectator::Matchers::HaveValueMatcher.new({{expected}}, {{expected.stringify}}) + ::Spectator::Matchers::HaveValueMatcher.new(::Spectator::TestValue.new({{expected}}, {{expected.stringify}})) end # ditto @@ -457,7 +457,7 @@ module Spectator::DSL # expect([1, 2, 3]).to contain_exactly(1, 2, 3) # ``` macro contain_exactly(*expected) - ::Spectator::Matchers::ArrayMatcher.new({{expected}}, {{expected.stringify}}) + ::Spectator::Matchers::ArrayMatcher.new(::Spectator::TestValue.new({{expected}}, {{expected.stringify}})) end # Indicates that some set should contain the same values in exact order as another set. @@ -467,7 +467,7 @@ module Spectator::DSL # expect([1, 2, 3]).to match_array([1, 2, 3]) # ``` macro match_array(expected) - ::Spectator::Matchers::ArrayMatcher.new({{expected}}, {{expected.stringify}}) + ::Spectator::Matchers::ArrayMatcher.new(::Spectator::TestValue.new({{expected}}, {{expected.stringify}})) end # Indicates that some set should have a specified size. @@ -477,7 +477,7 @@ module Spectator::DSL # expect([1, 2, 3]).to have_size(3) # ``` macro have_size(expected) - ::Spectator::Matchers::SizeMatcher.new({{expected}}, {{expected.stringify}}) + ::Spectator::Matchers::SizeMatcher.new(::Spectator::TestValue.new({{expected}}, {{expected.stringify}})) end # Indicates that some set should have the same size (number of elements) as another set. @@ -487,7 +487,7 @@ module Spectator::DSL # expect([1, 2, 3]).to have_size_of(%i[x y z]) # ``` macro have_size_of(expected) - ::Spectator::Matchers::SizeOfMatcher.new(({{expected}}), {{expected.stringify}}) + ::Spectator::Matchers::SizeOfMatcher.new(::Spectator::TestValue.new(({{expected}}), {{expected.stringify}})) end # Indicates that some value should have a set of attributes matching some conditions. @@ -501,7 +501,7 @@ module Spectator::DSL # expect(%i[a b c]).to have_attributes(size: 1..5, first: Symbol) # ``` macro have_attributes(**expected) - ::Spectator::Matchers::AttributesMatcher.new({{expected}}, {{expected.double_splat.stringify}}) + ::Spectator::Matchers::AttributesMatcher.new(::Spectator::TestValue.new({{expected}}, {{expected.double_splat.stringify}})) end # Indicates that some block should raise an error. @@ -620,7 +620,7 @@ module Spectator::DSL {% end %} label << ')' {% end %} - ::Spectator::Matchers::{{matcher.id}}.new(descriptor, label.to_s) + ::Spectator::Matchers::{{matcher.id}}.new(::Spectator::TestValue.new(descriptor, label.to_s)) end end end From 955311bb959a58246e3dc3f5cf597b1d98948c0f Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Thu, 8 Aug 2019 21:38:49 -0600 Subject: [PATCH 52/78] Don't force Enumerable expected type Should duck type anyway. --- src/spectator/matchers/array_matcher.cr | 2 +- src/spectator/matchers/unordered_array_matcher.cr | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/spectator/matchers/array_matcher.cr b/src/spectator/matchers/array_matcher.cr index b994278..66594a9 100644 --- a/src/spectator/matchers/array_matcher.cr +++ b/src/spectator/matchers/array_matcher.cr @@ -9,7 +9,7 @@ module Spectator::Matchers struct ArrayMatcher(ExpectedType) < Matcher private getter expected - def initialize(@expected : TestValue(Enumerable(ExpectedType))) + def initialize(@expected : TestValue(ExpectedType)) end def description diff --git a/src/spectator/matchers/unordered_array_matcher.cr b/src/spectator/matchers/unordered_array_matcher.cr index 8c5ed49..9014aa1 100644 --- a/src/spectator/matchers/unordered_array_matcher.cr +++ b/src/spectator/matchers/unordered_array_matcher.cr @@ -6,7 +6,7 @@ module Spectator::Matchers struct UnorderedArrayMatcher(ExpectedType) < Matcher private getter expected - def initialize(@expected : TestValue(Enumerable(ExpectedType))) + def initialize(@expected : TestValue(ExpectedType)) end def description From 21e10c1ef22d610e45bb5ea8c2f521c4bf3fbbdc Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Thu, 8 Aug 2019 21:39:30 -0600 Subject: [PATCH 53/78] Fix expected value snapshot --- src/spectator/matchers/have_predicate_matcher.cr | 2 +- src/spectator/matchers/predicate_matcher.cr | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/spectator/matchers/have_predicate_matcher.cr b/src/spectator/matchers/have_predicate_matcher.cr index ccd4451..96145d5 100644 --- a/src/spectator/matchers/have_predicate_matcher.cr +++ b/src/spectator/matchers/have_predicate_matcher.cr @@ -48,7 +48,7 @@ module Spectator::Matchers {% begin %} { {% for attribute in ExpectedType.keys %} - {{attribute}}: object.has_{{attribute}}?(*@expected[{{attribute.symbolize}}]), + {{attribute}}: object.has_{{attribute}}?(*@expected.value[{{attribute.symbolize}}]), {% end %} } {% end %} diff --git a/src/spectator/matchers/predicate_matcher.cr b/src/spectator/matchers/predicate_matcher.cr index 6cbbb88..93ce33b 100644 --- a/src/spectator/matchers/predicate_matcher.cr +++ b/src/spectator/matchers/predicate_matcher.cr @@ -47,7 +47,7 @@ module Spectator::Matchers {% begin %} { {% for attribute in ExpectedType.keys %} - {{attribute}}: object.{{attribute}}?(*@expected[{{attribute.symbolize}}]), + {{attribute}}: object.{{attribute}}?(*@expected.value[{{attribute.symbolize}}]), {% end %} } {% end %} From 3b1a5a1121903297b380af711248b3fa6506a135 Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Thu, 8 Aug 2019 21:52:05 -0600 Subject: [PATCH 54/78] Fix various expectation type code --- src/spectator/expectation_failed.cr | 2 +- src/spectator/expectations/expectation.cr | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/spectator/expectation_failed.cr b/src/spectator/expectation_failed.cr index 35d7d5f..05246da 100644 --- a/src/spectator/expectation_failed.cr +++ b/src/spectator/expectation_failed.cr @@ -9,7 +9,7 @@ module Spectator # Creates the exception. # The exception string is generated from the expecation message. def initialize(@expectation) - super(@expectation.actual_message) + super(@expectation.failure_message) end end end diff --git a/src/spectator/expectations/expectation.cr b/src/spectator/expectations/expectation.cr index 63e48cb..f7bd03b 100644 --- a/src/spectator/expectations/expectation.cr +++ b/src/spectator/expectations/expectation.cr @@ -9,7 +9,7 @@ module Spectator::Expectations getter source : Source # Creates the expectation. - def initialize(@match_data : MatchData, @source : Source) + def initialize(@match_data : Matchers::MatchData, @source : Source) end def satisfied? @@ -21,19 +21,19 @@ module Spectator::Expectations end def failure_message? - @match_data.as?(FailedMatchData).try(&.failure_message) + @match_data.as?(Matchers::FailedMatchData).try(&.failure_message) end def failure_message - @match_data.as(FailedMatchData).failure_message + @match_data.as(Matchers::FailedMatchData).failure_message end def values? - @match_data.as?(FailedMatchData).try(&.values) + @match_data.as?(Matchers::FailedMatchData).try(&.values) end def values - @match_data.as(FailedMatchData).values + @match_data.as(Matchers::FailedMatchData).values end # Creates the JSON representation of the expectation. @@ -41,18 +41,18 @@ module Spectator::Expectations json.object do json.field("source") { @source.to_json(json) } json.field("satisfied", satisfied?) - if (failed = @match_data.as?(FailedMatchData)) + if (failed = @match_data.as?(Matchers::FailedMatchData)) failed_to_json(failed, json) end end end - private def failed_to_json(failed : FailedMatchData, json : ::JSON::Builder) + private def failed_to_json(failed : Matchers::FailedMatchData, json : ::JSON::Builder) json.field("failure", failed.failure_message) json.field("values") do json.object do failed.values.each do |pair| - json.field(pair.label, pair.value) + json.field(pair.first, pair.last) end end end From 9dc5a999d1473b973fa1e59a776bb3c70e3f1c28 Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Thu, 8 Aug 2019 21:52:33 -0600 Subject: [PATCH 55/78] Fix method name (copy/paste fail) --- src/spectator/matchers/start_with_matcher.cr | 1 + 1 file changed, 1 insertion(+) diff --git a/src/spectator/matchers/start_with_matcher.cr b/src/spectator/matchers/start_with_matcher.cr index 4de8700..5e0a16a 100644 --- a/src/spectator/matchers/start_with_matcher.cr +++ b/src/spectator/matchers/start_with_matcher.cr @@ -35,6 +35,7 @@ module Spectator::Matchers private def match_last(actual) list = actual.value.to_a + private def match_first(value, actual) first = list.first if expected.value === first From 353e5f688668048570ff9d164136e35352e890bd Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Thu, 8 Aug 2019 21:57:02 -0600 Subject: [PATCH 56/78] Update formatting to use Tuple --- src/spectator/formatting/failure_block.cr | 2 +- src/spectator/formatting/failure_junit_test_case.cr | 6 +++--- src/spectator/formatting/match_data_values.cr | 10 +++++----- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/spectator/formatting/failure_block.cr b/src/spectator/formatting/failure_block.cr index 4b7276e..b542775 100644 --- a/src/spectator/formatting/failure_block.cr +++ b/src/spectator/formatting/failure_block.cr @@ -53,7 +53,7 @@ module Spectator::Formatting # Produces a list of unsatisfied expectations and their values. private def unsatisfied_expectations(indent) @result.expectations.each_unsatisfied do |expectation| - indent.line(Color.failure(LabeledText.new("Failure", expectation.actual_message))) + indent.line(Color.failure(LabeledText.new("Failure", expectation.failure_message))) indent.line indent.increase do matcher_values(indent, expectation) diff --git a/src/spectator/formatting/failure_junit_test_case.cr b/src/spectator/formatting/failure_junit_test_case.cr index d2f9d2d..964e673 100644 --- a/src/spectator/formatting/failure_junit_test_case.cr +++ b/src/spectator/formatting/failure_junit_test_case.cr @@ -19,7 +19,7 @@ module Spectator::Formatting private def content(xml) super @result.expectations.each_unsatisfied do |expectation| - xml.element("failure", message: expectation.actual_message) do + xml.element("failure", message: expectation.failure_message) do expectation_values(expectation.values, xml) end end @@ -28,8 +28,8 @@ module Spectator::Formatting # Adds the expectation values to the failure block. private def expectation_values(labeled_values, xml) labeled_values.each do |entry| - label = entry.label - value = entry.value + label = entry.first + value = entry.last xml.text("#{label}: #{value}\n") end end diff --git a/src/spectator/formatting/match_data_values.cr b/src/spectator/formatting/match_data_values.cr index 51b5f1e..bf194a9 100644 --- a/src/spectator/formatting/match_data_values.cr +++ b/src/spectator/formatting/match_data_values.cr @@ -2,22 +2,22 @@ module Spectator::Formatting # Produces a `MatchDataValuePair` for each key-value pair # from `Spectator::Matchers::MatchData#values`. private struct MatchDataValues - include Enumerable(MatchDataValuePair) + include Enumerable(Tuple(Symbol, String)) @max_key_length : Int32 # Creates the values mapper. - def initialize(@values : Array(Spectator::Matchers::MatchDataLabeledValue)) - @max_key_length = @values.map(&.label.to_s.size).max + def initialize(@values : Array(Tuple(Symbol, String))) + @max_key_length = @values.map(&.first.to_s.size).max end # Yields pairs that can be printed to output. def each @values.each do |labeled_value| - key = labeled_value.label + key = labeled_value.first key_length = key.to_s.size padding = @max_key_length - key_length - yield MatchDataValuePair.new(key, labeled_value.value, padding) + yield MatchDataValuePair.new(key, labeled_value.last, padding) end end end From 8b718f0bd07c5a8859228ab33102172197e6b2d1 Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Fri, 9 Aug 2019 00:32:45 -0600 Subject: [PATCH 57/78] Handle union case for expected value When using both forms of the HaveMatcher - expected can be a Char, String, or Regex. Regex is invalid for String#includes?. I believe this might be a generics issue that was fixed recently in Crystal. --- src/spectator/matchers/have_matcher.cr | 1 + 1 file changed, 1 insertion(+) diff --git a/src/spectator/matchers/have_matcher.cr b/src/spectator/matchers/have_matcher.cr index 6ac12bc..f8cd097 100644 --- a/src/spectator/matchers/have_matcher.cr +++ b/src/spectator/matchers/have_matcher.cr @@ -19,6 +19,7 @@ module Spectator::Matchers private def match_string?(actual_value) expected.value.all? do |item| actual_value.includes?(item) + actual_value.includes?(item) if item.is_a?(Char | String) end end From 569faa0a2b225d57dfdff1f32488f20643529848 Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Fri, 9 Aug 2019 00:42:39 -0600 Subject: [PATCH 58/78] Various other fixes --- src/spectator/matchers/have_matcher.cr | 16 +++++++--------- src/spectator/matchers/standard_matcher.cr | 4 ++-- src/spectator/matchers/start_with_matcher.cr | 2 -- 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/src/spectator/matchers/have_matcher.cr b/src/spectator/matchers/have_matcher.cr index f8cd097..31405d1 100644 --- a/src/spectator/matchers/have_matcher.cr +++ b/src/spectator/matchers/have_matcher.cr @@ -6,27 +6,25 @@ module Spectator::Matchers # Otherwise, it expects an `Enumerable` and iterates over each item until === is true. struct HaveMatcher(ExpectedType) < ValueMatcher(ExpectedType) private def match?(actual) - actual_value = actual.value - if actual_value.is_a?(String) - match_string(actual_value) + if (value = actual.value).is_a?(String) + match_string?(value) else - match_enumerable(actual_value) + match_enumerable?(value) end end # Checks if a `String` matches the expected values. # The `includes?` method is used for this check. - private def match_string?(actual_value) + private def match_string?(value) expected.value.all? do |item| - actual_value.includes?(item) - actual_value.includes?(item) if item.is_a?(Char | String) + value.includes?(item) if item.is_a?(Char | String) end end # Checks if an `Enumerable` matches the expected values. # The `===` operator is used on every item. - private def match_enumerable?(actual_value) - array = actual_value.to_a + private def match_enumerable?(value) + array = value.to_a expected.value.all? do |item| array.any? do |element| item === element diff --git a/src/spectator/matchers/standard_matcher.cr b/src/spectator/matchers/standard_matcher.cr index 63ba640..f33d910 100644 --- a/src/spectator/matchers/standard_matcher.cr +++ b/src/spectator/matchers/standard_matcher.cr @@ -44,7 +44,7 @@ module Spectator::Matchers if match?(actual) SuccessfulMatchData.new else - FailedMatchData.new(failure_message(actual), values(actual)) + FailedMatchData.new(failure_message(actual), **values(actual)) end end @@ -52,7 +52,7 @@ module Spectator::Matchers if does_not_match?(actual) SuccessfulMatchData.new else - FailedMatchData.new(failure_message_when_negated(actual), negated_values(actual)) + FailedMatchData.new(failure_message_when_negated(actual), **negated_values(actual)) end end end diff --git a/src/spectator/matchers/start_with_matcher.cr b/src/spectator/matchers/start_with_matcher.cr index 5e0a16a..754944f 100644 --- a/src/spectator/matchers/start_with_matcher.cr +++ b/src/spectator/matchers/start_with_matcher.cr @@ -33,8 +33,6 @@ module Spectator::Matchers end end - private def match_last(actual) - list = actual.value.to_a private def match_first(value, actual) first = list.first From 114bfa47c2d7b5f0e7b45fd8652c1c723fb6d206 Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Fri, 9 Aug 2019 11:12:15 -0600 Subject: [PATCH 59/78] Genericize TestExpression and make value abstract This seems to resolve issues with the compiler making unions of unrelated test case types. --- src/spectator/expectations/expectation_partial.cr | 6 +++--- src/spectator/test_block.cr | 2 +- src/spectator/test_expression.cr | 4 +++- src/spectator/test_value.cr | 2 +- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/spectator/expectations/expectation_partial.cr b/src/spectator/expectations/expectation_partial.cr index 2be1475..1cc8831 100644 --- a/src/spectator/expectations/expectation_partial.cr +++ b/src/spectator/expectations/expectation_partial.cr @@ -6,16 +6,16 @@ module Spectator::Expectations # Stores part of an expectation (obviously). # The part of the expectation this type covers is the actual value and source. # This can also cover a block's behavior. - struct ExpectationPartial + struct ExpectationPartial(T) # The actual value being tested. # This also contains its label. - getter actual : TestExpression + getter actual : TestExpression(T) # Location where this expectation was defined. getter source : Source # Creates the partial. - def initialize(@actual, @source) + def initialize(@actual : TestExpression(T), @source : Source) end # Asserts that some criteria defined by the matcher is satisfied. diff --git a/src/spectator/test_block.cr b/src/spectator/test_block.cr index 1b6d4d5..b1f1c4f 100644 --- a/src/spectator/test_block.cr +++ b/src/spectator/test_block.cr @@ -2,7 +2,7 @@ require "./test_expression" module Spectator # Captures an block from a test and its label. - struct TestBlock(ReturnType) < TestExpression + struct TestBlock(ReturnType) < TestExpression(ReturnType) # Calls the block and retrieves the value. def value : ReturnType @proc.call diff --git a/src/spectator/test_expression.cr b/src/spectator/test_expression.cr index 6ec4f27..d5e3cdd 100644 --- a/src/spectator/test_expression.cr +++ b/src/spectator/test_expression.cr @@ -1,6 +1,6 @@ module Spectator # Base type for capturing an expression from a test. - abstract struct TestExpression + abstract struct TestExpression(T) # User-friendly string displayed for the actual expression being tested. # For instance, in the expectation: # ``` @@ -15,6 +15,8 @@ module Spectator def initialize(@label) end + abstract def value : T + # String representation of the expression. def to_s(io) io << label diff --git a/src/spectator/test_value.cr b/src/spectator/test_value.cr index 3071a92..b621562 100644 --- a/src/spectator/test_value.cr +++ b/src/spectator/test_value.cr @@ -2,7 +2,7 @@ require "./test_expression" module Spectator # Captures a value from a test and its label. - struct TestValue(T) < TestExpression + struct TestValue(T) < TestExpression(T) # Actual value. getter value : T From 3d86893f445c4d576698301390576eaccfa5c0c3 Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Fri, 9 Aug 2019 11:13:13 -0600 Subject: [PATCH 60/78] Resolve various duck-typing issues --- src/spectator/matchers/end_with_matcher.cr | 32 ++++++------ src/spectator/matchers/have_matcher.cr | 2 +- src/spectator/matchers/start_with_matcher.cr | 51 ++++++++++---------- 3 files changed, 43 insertions(+), 42 deletions(-) diff --git a/src/spectator/matchers/end_with_matcher.cr b/src/spectator/matchers/end_with_matcher.cr index 986fbf2..516e411 100644 --- a/src/spectator/matchers/end_with_matcher.cr +++ b/src/spectator/matchers/end_with_matcher.cr @@ -17,35 +17,35 @@ module Spectator::Matchers end def match(actual) - if actual.value.responds_to?(:ends_with?) - match_ends_with(actual) + if (value = actual.value).responds_to?(:ends_with?) + match_ends_with(value, actual.label) else - match_last(actual) + match_last(value, actual.label) end end - private def match_ends_with(actual) - if actual.value.ends_with?(expected.value) + private def match_ends_with(actual_value, actual_label) + if actual_value.ends_with?(expected.value) SuccessfulMatchData.new else - FailedMatchData.new("#{actual.label} does not end with #{expected.label} (using #ends_with?)", + FailedMatchData.new("#{actual_label} does not end with #{expected.label} (using #ends_with?)", expected: expected.value.inspect, - actual: actual.value.inspect + actual: actual_value.inspect ) end end - private def match_last(actual) - list = actual.value.to_a + private def match_last(actual_value, actual_label) + list = actual_value.to_a last = list.last if expected.value === last SuccessfulMatchData.new else - FailedMatchData.new("#{actual.label} does not end with #{expected.label} (using expected === last)", - expected: expected.value, - actual: last, - list: list + FailedMatchData.new("#{actual_label} does not end with #{expected.label} (using expected === last)", + expected: expected.value.inspect, + actual: last.inspect, + list: list.inspect ) end end @@ -75,9 +75,9 @@ module Spectator::Matchers if expected.value === last FailedMatchData.new("#{actual.label} ends with #{expected.label} (using expected === last)", - expected: expected.value, - actual: last, - list: list + expected: expected.value.inspect, + actual: last.inspect, + list: list.inspect ) else SuccessfulMatchData.new diff --git a/src/spectator/matchers/have_matcher.cr b/src/spectator/matchers/have_matcher.cr index 31405d1..3886e51 100644 --- a/src/spectator/matchers/have_matcher.cr +++ b/src/spectator/matchers/have_matcher.cr @@ -17,7 +17,7 @@ module Spectator::Matchers # The `includes?` method is used for this check. private def match_string?(value) expected.value.all? do |item| - value.includes?(item) if item.is_a?(Char | String) + value.includes?(item) end end diff --git a/src/spectator/matchers/start_with_matcher.cr b/src/spectator/matchers/start_with_matcher.cr index 754944f..539c73d 100644 --- a/src/spectator/matchers/start_with_matcher.cr +++ b/src/spectator/matchers/start_with_matcher.cr @@ -15,66 +15,67 @@ module Spectator::Matchers end def match(actual) - if actual.value.responds_to?(:starts_with?) - match_starts_with(actual) + if (value = actual.value).responds_to?(:starts_with?) + match_starts_with(value, actual.label) else - match_first(actual) + match_first(value, actual.label) end end - private def match_starts_with(actual) - if actual.value.starts_with?(expected.value) + private def match_starts_with(actual_value, actual_label) + if actual_value.starts_with?(expected.value) SuccessfulMatchData.new else - FailedMatchData.new("#{actual.label} does not start with #{expected.label} (using #starts_with?)", + FailedMatchData.new("#{actual_label} does not start with #{expected.label} (using #starts_with?)", expected: expected.value.inspect, - actual: actual.value.inspect + actual: actual_value.inspect ) end end - private def match_first(value, actual) + private def match_first(actual_value, actual_label) + list = actual_value.to_a first = list.first if expected.value === first SuccessfulMatchData.new else - FailedMatchData.new("#{actual.label} does not start with #{expected.label} (using expected === first)", - expected: expected.value, - actual: first, - list: list + FailedMatchData.new("#{actual_label} does not start with #{expected.label} (using expected === first)", + expected: expected.value.inspect, + actual: first.inspect, + list: list.inspect ) end end def negated_match(actual) - if actual.value.responds_to?(:starts_with?) - negated_match_starts_with(actual) + if (value = actual.value).responds_to?(:starts_with?) + negated_match_starts_with(value, actual.label) else - negated_match_first(actual) + negated_match_first(value, actual.label) end end - private def negated_match_starts_with(actual) - if actual.value.starts_with?(expected.value) - FailedMatchData.new("#{actual.label} starts with #{expected.label} (using #starts_with?)", + private def negated_match_starts_with(actual_value, actual_label) + if actual_value.starts_with?(expected.value) + FailedMatchData.new("#{actual_label} starts with #{expected.label} (using #starts_with?)", expected: expected.value.inspect, - actual: actual.value.inspect + actual: actual_value.inspect ) else SuccessfulMatchData.new end end - private def negated_match_first(actual) - list = actual.value.to_a + private def negated_match_first(actual_value, actual_label) + list = actual_value.to_a first = list.first if expected.value === first - FailedMatchData.new("#{actual.label} starts with #{expected.label} (using expected === first)", - expected: expected.value, - actual: first, - list: list + FailedMatchData.new("#{actual_label} starts with #{expected.label} (using expected === first)", + expected: expected.value.inspect, + actual: first.inspect, + list: list.inspect ) else SuccessfulMatchData.new From 5a1dea8f728d95c740203b8510f62d7fcc8c9729 Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Fri, 9 Aug 2019 11:20:29 -0600 Subject: [PATCH 61/78] Convert bools to strings for output --- src/spectator/matchers/predicate_matcher.cr | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/spectator/matchers/predicate_matcher.cr b/src/spectator/matchers/predicate_matcher.cr index 93ce33b..f8cb737 100644 --- a/src/spectator/matchers/predicate_matcher.cr +++ b/src/spectator/matchers/predicate_matcher.cr @@ -20,14 +20,14 @@ module Spectator::Matchers if match?(snapshot) SuccessfulMatchData.new else - FailedMatchData.new("#{actual.label} is not #{expected.label}", **snapshot) + FailedMatchData.new("#{actual.label} is not #{expected.label}", **values(snapshot)) end end def negated_match(actual) snapshot = snapshot_values(actual.value) if match?(snapshot) - FailedMatchData.new("#{actual.label} is #{expected.label}", **snapshot) + FailedMatchData.new("#{actual.label} is #{expected.label}", **values(snapshot)) else SuccessfulMatchData.new end @@ -53,6 +53,16 @@ module Spectator::Matchers {% end %} end + private def values(snapshot) + {% begin %} + { + {% for attribute in ExpectedType.keys %} + {{attribute}}: snapshot[{{attribute.symbolize}}].inspect, + {% end %} + } + {% end %} + end + private def match?(snapshot) # Test each predicate and immediately return false if one is false. {% for attribute in ExpectedType.keys %} From 0dfde618078765bfe075f097ac21c6866dd41b0b Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Fri, 9 Aug 2019 11:20:41 -0600 Subject: [PATCH 62/78] Fix method name matches? -> match? --- src/spectator/matchers/standard_matcher.cr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/spectator/matchers/standard_matcher.cr b/src/spectator/matchers/standard_matcher.cr index f33d910..0e99e38 100644 --- a/src/spectator/matchers/standard_matcher.cr +++ b/src/spectator/matchers/standard_matcher.cr @@ -29,7 +29,7 @@ module Spectator::Matchers # then this method should be overriden. # Remember to override `#failure_message_when_negated` as well. private def does_not_match?(actual) : Bool - !matches?(actual) + !match?(actual) end private def values(actual) From e763296c2627ff72ce462f375ea559f12f760a8a Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Fri, 9 Aug 2019 11:23:10 -0600 Subject: [PATCH 63/78] Remove inspection quotes from around output values --- src/spectator/formatting/match_data_value_pair.cr | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/spectator/formatting/match_data_value_pair.cr b/src/spectator/formatting/match_data_value_pair.cr index 95fa57f..dd7f255 100644 --- a/src/spectator/formatting/match_data_value_pair.cr +++ b/src/spectator/formatting/match_data_value_pair.cr @@ -1,8 +1,8 @@ module Spectator::Formatting # A single labeled value from the `Spectator::Matchers::MatchData#value` method. - private struct MatchDataValuePair(T) + private struct MatchDataValuePair # Creates the pair formatter. - def initialize(@key : Symbol, @value : T, @padding : Int32) + def initialize(@key : Symbol, @value : String, @padding : Int32) end # Appends the pair to the output. @@ -10,7 +10,7 @@ module Spectator::Formatting @padding.times { io << ' ' } io << @key io << ": " - @value.inspect(io) + io << @value end end end From 751c15434b35f90c226f0982b52aa82166a44fef Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Fri, 9 Aug 2019 11:29:53 -0600 Subject: [PATCH 64/78] Help infer the block's return type --- src/spectator/dsl/example_dsl.cr | 8 ++++++-- src/spectator/dsl/matcher_dsl.cr | 2 ++ src/spectator/test_block.cr | 8 ++++++++ 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/spectator/dsl/example_dsl.cr b/src/spectator/dsl/example_dsl.cr index 60b8785..dfc3b2b 100644 --- a/src/spectator/dsl/example_dsl.cr +++ b/src/spectator/dsl/example_dsl.cr @@ -1,3 +1,7 @@ +require "../expectations/expectation_partial" +require "../source" +require "../test_block" +require "../test_value" require "./matcher_dsl" module Spectator::DSL @@ -70,11 +74,11 @@ module Spectator::DSL # The raw block can't be used because it's not clear to the user. {% method_name = block.body.id.split('.')[1..-1].join('.') %} %partial = %proc.partial(subject) - test_block = ::Spectator::TestBlock.new(%partial, {{"#" + method_name}}) + test_block = ::Spectator::TestBlock.create(%partial, {{"#" + method_name}}) {% else %} # In this case, it looks like the short-hand method syntax wasn't used. # Just drop in the proc as-is. - test_block = ::Spectator::TestBlock.new(%proc, {{"`" + block.body.stringify + "`"}}) + test_block = ::Spectator::TestBlock.create(%proc, {{"`" + block.body.stringify + "`"}}) {% end %} source = ::Spectator::Source.new({{_source_file}}, {{_source_line}}) diff --git a/src/spectator/dsl/matcher_dsl.cr b/src/spectator/dsl/matcher_dsl.cr index 408b4f2..30fc916 100644 --- a/src/spectator/dsl/matcher_dsl.cr +++ b/src/spectator/dsl/matcher_dsl.cr @@ -1,4 +1,6 @@ require "../matchers" +require "../test_block" +require "../test_value" module Spectator::DSL # Methods for defining matchers for expectations. diff --git a/src/spectator/test_block.cr b/src/spectator/test_block.cr index b1f1c4f..a955594 100644 --- a/src/spectator/test_block.cr +++ b/src/spectator/test_block.cr @@ -14,12 +14,20 @@ module Spectator super(label) end + def self.create(proc : -> T, label : String) forall T + TestBlock(T).new(proc, label) + end + # Creates the block expression with a generic label. # This is used for the "should" syntax and when the label doesn't matter. def initialize(@proc : -> ReturnType) super("") end + def self.create(proc : -> T) forall T + TestBlock(T).new(proc) + end + # Reports complete information about the expression. def inspect(io) io << label From 22511686315de295ccdfe0ba6351a5f0d14eace1 Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Fri, 9 Aug 2019 14:01:10 -0600 Subject: [PATCH 65/78] Get inspection string of attribute values --- src/spectator/matchers/attributes_matcher.cr | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/spectator/matchers/attributes_matcher.cr b/src/spectator/matchers/attributes_matcher.cr index 8bb6757..be5cbbc 100644 --- a/src/spectator/matchers/attributes_matcher.cr +++ b/src/spectator/matchers/attributes_matcher.cr @@ -63,8 +63,8 @@ module Spectator::Matchers {% begin %} { {% for attribute in ExpectedType.keys %} - {{"expected " + attribute.stringify}}: expected.value[{{attribute.symbolize}}]), - {{"actual " + attribute.stringify}}: snapshot[{{attribute.symbolize}}], + {{"expected " + attribute.stringify}}: expected.value[{{attribute.symbolize}}].inspect, + {{"actual " + attribute.stringify}}: snapshot[{{attribute.symbolize}}].inspect, {% end %} } {% end %} From c47b47ade901e36eeb43af5b46e950c284b9af8e Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Fri, 9 Aug 2019 14:18:59 -0600 Subject: [PATCH 66/78] Fix most problems (hopefully) with ExceptionMatcher --- src/spectator/matchers/exception_matcher.cr | 71 ++++++++++++--------- 1 file changed, 41 insertions(+), 30 deletions(-) diff --git a/src/spectator/matchers/exception_matcher.cr b/src/spectator/matchers/exception_matcher.cr index d1a289e..b39ceb9 100644 --- a/src/spectator/matchers/exception_matcher.cr +++ b/src/spectator/matchers/exception_matcher.cr @@ -25,48 +25,59 @@ module Spectator::Matchers def match(actual) exception = capture_exception { actual.value } - case exception - when Nil - FailedMatchData.new("#{actual.label} did not raise", expected: ExpectedType.inspect) - when ExceptionType - if expected.value.nil? || expected.value === exception.message - SuccessfulMatchData.new + if exception.nil? + FailedMatchData.new("#{actual.label} did not raise", expected: ExceptionType.inspect) + else + if exception.is_a?(ExceptionType) + if (value = expected.value).nil? + SuccessfulMatchData.new + else + if value === exception.message + SuccessfulMatchData.new + else + FailedMatchData.new("#{actual.label} raised #{exception.class}, but the message is not #{expected.label}", + "expected type": ExceptionType.inspect, + "actual type": exception.class.inspect, + "expected message": value.inspect, + "actual message": exception.message.to_s + ) + end + end else - FailedMatchData.new("#{actual.label} raised #{ExpectedType}, but the message is not #{expected.label}", - "expected type": ExceptionType.inspect, - "actual type": exception.class.inspect, - "expected message": expected.value.inspect, - "actual message": exception.message + FailedMatchData.new("#{actual.label} did not raise #{ExceptionType}", + expected: ExceptionType.inspect, + actual: exception.class.inspect ) end - else - FailedMatchData.new("#{actual.label} did not raise #{ExpectedType}", - expected: ExpectedType.inspect, - actual: exception.class.inspect - ) end end def negated_match(actual) exception = capture_exception { actual.value } - case exception - when Nil + if exception.nil? SuccessfulMatchData.new - when ExceptionType - if expected.value.nil? - FailedMatchData.new("#{actual.label} raised #{ExpectedType}") - elsif expected.value === exception.message - FailedMatchData.new("#{actual.label} raised #{ExpectedType} with message matching #{expected.label}", - "expected type": ExceptionType.inspect, - "actual type": exception.class.inspect, - "expected message": expected.value.inspect, - "actual message": exception.message - ) + else + if exception.is_a?(ExceptionType) + if (value = expected.value).nil? + FailedMatchData.new("#{actual.label} raised #{exception.class}", + expected: "Not #{ExceptionType}", + actual: exception.class.inspect + ) + else + if value === exception.message + FailedMatchData.new("#{actual.label} raised #{exception.class} with message matching #{expected.label}", + "expected type": ExceptionType.inspect, + "actual type": exception.class.inspect, + "expected message": value.inspect, + "actual message": exception.message.to_s + ) + else + SuccessfulMatchData.new + end + end else SuccessfulMatchData.new end - else - SuccessfulMatchData.new end end From 8fc3af075c875bb23fb66441298053b3b17274a5 Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Fri, 9 Aug 2019 15:06:22 -0600 Subject: [PATCH 67/78] Workaround for NoReturn type for block Not sure if this will work for everything. It seems that NoReturn shows up as ReturnType (generic) when the compiler detects the block will raise. --- src/spectator/test_block.cr | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/spectator/test_block.cr b/src/spectator/test_block.cr index a955594..b0dc53d 100644 --- a/src/spectator/test_block.cr +++ b/src/spectator/test_block.cr @@ -15,7 +15,12 @@ module Spectator end def self.create(proc : -> T, label : String) forall T - TestBlock(T).new(proc, label) + {% if T.id == "ReturnType".id %} + wrapper = -> { proc.call; nil } + TestBlock(Nil).new(wrapper, label) + {% else %} + TestBlock(T).new(proc, label) + {% end %} end # Creates the block expression with a generic label. @@ -25,7 +30,12 @@ module Spectator end def self.create(proc : -> T) forall T - TestBlock(T).new(proc) + {% if T.id == "ReturnType".id %} + wrapper = -> { proc.call; nil } + TestBlock(Nil).new(wrapper) + {% else %} + TestBlock(T).new(proc) + {% end %} end # Reports complete information about the expression. From 85b741243634ee1318e8c4184f72dfe3a1a3d0cc Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Fri, 9 Aug 2019 15:14:00 -0600 Subject: [PATCH 68/78] Fix some more matcher errors --- src/spectator/dsl/matcher_dsl.cr | 2 +- src/spectator/matchers/array_matcher.cr | 14 +++++++------- src/spectator/matchers/have_predicate_matcher.cr | 14 ++++++++++++-- 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/src/spectator/dsl/matcher_dsl.cr b/src/spectator/dsl/matcher_dsl.cr index 30fc916..18b30ab 100644 --- a/src/spectator/dsl/matcher_dsl.cr +++ b/src/spectator/dsl/matcher_dsl.cr @@ -14,7 +14,7 @@ module Spectator::DSL # expect(1 + 2).to eq(3) # ``` macro eq(expected) - ::Spectator::Matchers::EqualityMatcher.new(::Spectator::TestValue.new({{expected}}, {{expected.stringify}}))) + ::Spectator::Matchers::EqualityMatcher.new(::Spectator::TestValue.new({{expected}}, {{expected.stringify}})) end # Indicates that some value should not equal another. diff --git a/src/spectator/matchers/array_matcher.cr b/src/spectator/matchers/array_matcher.cr index 66594a9..28080ea 100644 --- a/src/spectator/matchers/array_matcher.cr +++ b/src/spectator/matchers/array_matcher.cr @@ -22,12 +22,12 @@ module Spectator::Matchers index = compare_arrays(expected_elements, actual_elements) case index + when Int # Content differs. + failed_content_mismatch(expected_elements, actual_elements, index, actual.label) when true # Contents are identical. SuccessfulMatchData.new - when false # Size differs. + else # Size differs. failed_size_mismatch(expected_elements, actual_elements, actual.label) - else # Content differs. - failed_content_mismatch(expected_elements, actual_elements, index, actual.label) end end @@ -36,11 +36,11 @@ module Spectator::Matchers expected_elements = expected.value.to_a case compare_arrays(expected_elements, actual_elements) + when Int # Contents differ. + SuccessfulMatchData.new when true # Contents are identical. failed_content_identical(expected_elements, actual_elements, actual.label) - when false # Size differs. - SuccessfulMatchData.new - else # Contents differ. + else # Size differs. SuccessfulMatchData.new end end @@ -84,7 +84,7 @@ module Spectator::Matchers end private def failed_content_identical(expected_elements, actual_elements, actual_label) - FailedMatchData.new("#{actual.label} contains exactly #{expected.label}", + FailedMatchData.new("#{actual_label} contains exactly #{expected.label}", expected: "Not #{expected_elements.inspect}", actual: actual_elements.inspect ) diff --git a/src/spectator/matchers/have_predicate_matcher.cr b/src/spectator/matchers/have_predicate_matcher.cr index 96145d5..3bb881a 100644 --- a/src/spectator/matchers/have_predicate_matcher.cr +++ b/src/spectator/matchers/have_predicate_matcher.cr @@ -21,14 +21,14 @@ module Spectator::Matchers if match?(snapshot) SuccessfulMatchData.new else - FailedMatchData.new("#{actual.label} does not have #{expected.label}", **snapshot) + FailedMatchData.new("#{actual.label} does not have #{expected.label}", **values(snapshot)) end end def negated_match(actual) snapshot = snapshot_values(actual.value) if match?(snapshot) - FailedMatchData.new("#{actual.label} has #{expected.label}", **snapshot) + FailedMatchData.new("#{actual.label} has #{expected.label}", **values(snapshot)) else SuccessfulMatchData.new end @@ -54,6 +54,16 @@ module Spectator::Matchers {% end %} end + private def values(snapshot) + {% begin %} + { + {% for attribute in ExpectedType.keys %} + {{attribute}}: snapshot[{{attribute.symbolize}}].inspect, + {% end %} + } + {% end %} + end + private def match?(snapshot) # Test each predicate and immediately return false if one is false. {% for attribute in ExpectedType.keys %} From 251e3b87749f136d985185821b373920fd7405a0 Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Fri, 9 Aug 2019 15:16:01 -0600 Subject: [PATCH 69/78] Remove specs for matchers Will replace with Spectator-based tests later. --- spec/matchers/array_matcher_spec.cr | 405 ----------- spec/matchers/attributes_matcher_spec.cr | 358 --------- spec/matchers/case_matcher_spec.cr | 203 ------ spec/matchers/collection_matcher_spec.cr | 391 ---------- spec/matchers/contain_matcher_spec.cr | 386 ---------- spec/matchers/empty_matcher_spec.cr | 73 -- spec/matchers/end_with_matcher_spec.cr | 393 ---------- spec/matchers/equality_matcher_spec.cr | 173 ----- spec/matchers/exception_matcher_spec.cr | 205 ------ .../greater_than_equal_matcher_spec.cr | 160 ---- spec/matchers/greater_than_matcher_spec.cr | 160 ---- spec/matchers/have_key_matcher_spec.cr | 166 ----- spec/matchers/have_matcher_spec.cr | 604 --------------- spec/matchers/have_predicate_matcher_spec.cr | 87 --- spec/matchers/have_value_matcher_spec.cr | 140 ---- spec/matchers/inequality_matcher_spec.cr | 181 ----- spec/matchers/less_than_equal_matcher_spec.cr | 160 ---- spec/matchers/less_than_matcher_spec.cr | 160 ---- spec/matchers/nil_matcher_spec.cr | 86 --- spec/matchers/predicate_matcher_spec.cr | 89 --- spec/matchers/range_matcher_spec.cr | 686 ------------------ spec/matchers/reference_matcher_spec.cr | 152 ---- spec/matchers/respond_matcher_spec.cr | 123 ---- spec/matchers/size_matcher_spec.cr | 121 --- spec/matchers/size_of_matcher_spec.cr | 121 --- spec/matchers/start_with_matcher_spec.cr | 393 ---------- spec/matchers/truthy_matcher_spec.cr | 374 ---------- spec/matchers/type_matcher_spec.cr | 125 ---- spec/matchers/unordered_array_matcher_spec.cr | 474 ------------ 29 files changed, 7149 deletions(-) delete mode 100644 spec/matchers/array_matcher_spec.cr delete mode 100644 spec/matchers/attributes_matcher_spec.cr delete mode 100644 spec/matchers/case_matcher_spec.cr delete mode 100644 spec/matchers/collection_matcher_spec.cr delete mode 100644 spec/matchers/contain_matcher_spec.cr delete mode 100644 spec/matchers/empty_matcher_spec.cr delete mode 100644 spec/matchers/end_with_matcher_spec.cr delete mode 100644 spec/matchers/equality_matcher_spec.cr delete mode 100644 spec/matchers/exception_matcher_spec.cr delete mode 100644 spec/matchers/greater_than_equal_matcher_spec.cr delete mode 100644 spec/matchers/greater_than_matcher_spec.cr delete mode 100644 spec/matchers/have_key_matcher_spec.cr delete mode 100644 spec/matchers/have_matcher_spec.cr delete mode 100644 spec/matchers/have_predicate_matcher_spec.cr delete mode 100644 spec/matchers/have_value_matcher_spec.cr delete mode 100644 spec/matchers/inequality_matcher_spec.cr delete mode 100644 spec/matchers/less_than_equal_matcher_spec.cr delete mode 100644 spec/matchers/less_than_matcher_spec.cr delete mode 100644 spec/matchers/nil_matcher_spec.cr delete mode 100644 spec/matchers/predicate_matcher_spec.cr delete mode 100644 spec/matchers/range_matcher_spec.cr delete mode 100644 spec/matchers/reference_matcher_spec.cr delete mode 100644 spec/matchers/respond_matcher_spec.cr delete mode 100644 spec/matchers/size_matcher_spec.cr delete mode 100644 spec/matchers/size_of_matcher_spec.cr delete mode 100644 spec/matchers/start_with_matcher_spec.cr delete mode 100644 spec/matchers/truthy_matcher_spec.cr delete mode 100644 spec/matchers/type_matcher_spec.cr delete mode 100644 spec/matchers/unordered_array_matcher_spec.cr diff --git a/spec/matchers/array_matcher_spec.cr b/spec/matchers/array_matcher_spec.cr deleted file mode 100644 index 9376ccf..0000000 --- a/spec/matchers/array_matcher_spec.cr +++ /dev/null @@ -1,405 +0,0 @@ -require "../spec_helper" - -describe Spectator::Matchers::ArrayMatcher do - describe "#in_any_order" do - it "returns an unordered matcher" do - array = %i[x y z] - matcher = Spectator::Matchers::ArrayMatcher.new(array) - matcher.in_any_order.should be_a(Spectator::Matchers::UnorderedArrayMatcher(Symbol)) - end - - it "maintains the expected array" do - array = %i[x y z] - matcher = Spectator::Matchers::ArrayMatcher.new(array) - unordered_matcher = matcher.in_any_order - unordered_matcher.expected.should eq(array) - end - - it "maintains the expected label" do - array = %i[x y z] - label = "some_array" - matcher = Spectator::Matchers::ArrayMatcher.new(array, label) - unordered_matcher = matcher.in_any_order - unordered_matcher.label.should eq(label) - end - end - - describe "#match" do - context "returned MatchData" do - context "with identical arrays" do - describe "#matched?" do - it "is true" do - array = %i[a b c] - partial = new_partial(array) - matcher = Spectator::Matchers::ArrayMatcher.new(array) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - - describe "#values" do - context "expected" do - it "is the expected array" do - array = %i[a b c] - partial = new_partial(array) - matcher = Spectator::Matchers::ArrayMatcher.new(array) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :expected)[:value].should eq(array) - end - end - - context "actual" do - it "is the actual array" do - array = %i[a b c] - partial = new_partial(array) - matcher = Spectator::Matchers::ArrayMatcher.new(array) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :actual)[:value].should eq(array) - end - end - end - - describe "#message" do - it "contains the actual label" do - array = %i[a b c] - label = "everything" - partial = new_partial(array, label) - matcher = Spectator::Matchers::ArrayMatcher.new(array) - match_data = matcher.match(partial) - match_data.message.should contain(label) - end - - it "contains the expected label" do - array = %i[a b c] - label = "everything" - partial = new_partial(array) - matcher = Spectator::Matchers::ArrayMatcher.new(array, label) - match_data = matcher.match(partial) - match_data.message.should contain(label) - end - - context "when expected label is omitted" do - it "contains stringified form of expected array" do - array1 = %i[a b c] - array2 = [1, 2, 3] - partial = new_partial(array1) - matcher = Spectator::Matchers::ArrayMatcher.new(array2) - match_data = matcher.match(partial) - match_data.message.should contain(array2.to_s) - end - end - end - - describe "#negated_message" do - it "contains the actual label" do - array = %i[a b c] - label = "everything" - partial = new_partial(array, label) - matcher = Spectator::Matchers::ArrayMatcher.new(array) - match_data = matcher.match(partial) - match_data.negated_message.should contain(label) - end - - it "contains the expected label" do - array = %i[a b c] - label = "everything" - partial = new_partial(array) - matcher = Spectator::Matchers::ArrayMatcher.new(array, label) - match_data = matcher.match(partial) - match_data.negated_message.should contain(label) - end - - context "when expected label is omitted" do - it "contains stringified form of expected array" do - array1 = %i[a b c] - array2 = [1, 2, 3] - partial = new_partial(array1) - matcher = Spectator::Matchers::ArrayMatcher.new(array2) - match_data = matcher.match(partial) - match_data.negated_message.should contain(array2.to_s) - end - end - end - end - - context "with arrays differing in size" do - describe "#matched?" do - it "is false" do - array1 = %i[a b c d e] - array2 = %i[x y z] - partial = new_partial(array1) - matcher = Spectator::Matchers::ArrayMatcher.new(array2) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - - describe "#values" do - context "expected" do - it "is the expected array" do - array1 = %i[a b c d e] - array2 = %i[x y z] - partial = new_partial(array1) - matcher = Spectator::Matchers::ArrayMatcher.new(array2) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :expected)[:value].should eq(array2) - end - end - - context "actual" do - it "is the actual array" do - array1 = %i[a b c d e] - array2 = %i[x y z] - partial = new_partial(array1) - matcher = Spectator::Matchers::ArrayMatcher.new(array2) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :actual)[:value].should eq(array1) - end - end - - context "expected size" do - it "is the expected size" do - array1 = %i[a b c d e] - array2 = %i[x y z] - partial = new_partial(array1) - matcher = Spectator::Matchers::ArrayMatcher.new(array2) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :"expected size")[:value].should eq(array2.size) - end - end - - context "actual size" do - it "is the actual size" do - array1 = %i[a b c d e] - array2 = %i[x y z] - partial = new_partial(array1) - matcher = Spectator::Matchers::ArrayMatcher.new(array2) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :"actual size")[:value].should eq(array1.size) - end - end - end - - describe "#message" do - it "contains the actual label" do - array1 = %i[a b c d e] - array2 = %i[x y z] - label = "everything" - partial = new_partial(array1, label) - matcher = Spectator::Matchers::ArrayMatcher.new(array2) - match_data = matcher.match(partial) - match_data.message.should contain(label) - end - - it "contains the expected label" do - array1 = %i[a b c d e] - array2 = %i[x y z] - label = "everything" - partial = new_partial(array1) - matcher = Spectator::Matchers::ArrayMatcher.new(array2, label) - match_data = matcher.match(partial) - match_data.message.should contain(label) - end - - context "when expected label is omitted" do - it "contains stringified form of expected array" do - array1 = %i[a b c d e] - array2 = %i[x y z] - partial = new_partial(array1) - matcher = Spectator::Matchers::ArrayMatcher.new(array2) - match_data = matcher.match(partial) - match_data.message.should contain(array2.to_s) - end - end - end - - describe "#negated_message" do - it "mentions size" do - array1 = %i[a b c d e] - array2 = %i[x y z] - partial = new_partial(array1) - matcher = Spectator::Matchers::ArrayMatcher.new(array2) - match_data = matcher.match(partial) - match_data.negated_message.should contain("size") - end - - it "contains the actual label" do - array1 = %i[a b c d e] - array2 = %i[x y z] - label = "everything" - partial = new_partial(array1, label) - matcher = Spectator::Matchers::ArrayMatcher.new(array2) - match_data = matcher.match(partial) - match_data.negated_message.should contain(label) - end - - it "contains the expected label" do - array1 = %i[a b c d e] - array2 = %i[x y z] - label = "everything" - partial = new_partial(array1) - matcher = Spectator::Matchers::ArrayMatcher.new(array2, label) - match_data = matcher.match(partial) - match_data.negated_message.should contain(label) - end - - context "when expected label is omitted" do - it "contains stringified form of expected array" do - array1 = %i[a b c d e] - array2 = %i[x y z] - partial = new_partial(array1) - matcher = Spectator::Matchers::ArrayMatcher.new(array2) - match_data = matcher.match(partial) - match_data.negated_message.should contain(array2.to_s) - end - end - end - end - - context "with arrays differing in content" do - describe "#matched?" do - it "is false" do - array1 = %i[a b c] - array2 = %i[x y z] - partial = new_partial(array1) - matcher = Spectator::Matchers::ArrayMatcher.new(array2) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - - describe "#values" do - context "expected" do - it "is the expected array" do - array1 = %i[a b c] - array2 = %i[x y z] - partial = new_partial(array1) - matcher = Spectator::Matchers::ArrayMatcher.new(array2) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :expected)[:value].should eq(array2) - end - end - - context "actual" do - it "is the actual array" do - array1 = %i[a b c] - array2 = %i[x y z] - partial = new_partial(array1) - matcher = Spectator::Matchers::ArrayMatcher.new(array2) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :actual)[:value].should eq(array1) - end - end - - context "expected element" do - it "is the first mismatch" do - array1 = %i[a b c] - array2 = %i[x y z] - partial = new_partial(array1) - matcher = Spectator::Matchers::ArrayMatcher.new(array2) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :"expected element")[:value].should eq(array2.first) - end - end - - context "actual element" do - it "is the first mismatch" do - array1 = %i[a b c] - array2 = %i[x y z] - partial = new_partial(array1) - matcher = Spectator::Matchers::ArrayMatcher.new(array2) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :"actual element")[:value].should eq(array1.first) - end - end - - context "index" do - it "is the mismatched index" do - array1 = %i[a b c] - array2 = %i[x y z] - partial = new_partial(array1) - matcher = Spectator::Matchers::ArrayMatcher.new(array2) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :index)[:value].should eq(0) - end - end - end - - describe "#message" do - it "contains the actual label" do - array1 = %i[a b c] - array2 = %i[x y z] - label = "everything" - partial = new_partial(array1, label) - matcher = Spectator::Matchers::ArrayMatcher.new(array2) - match_data = matcher.match(partial) - match_data.message.should contain(label) - end - - it "contains the expected label" do - array1 = %i[a b c] - array2 = %i[x y z] - label = "everything" - partial = new_partial(array1) - matcher = Spectator::Matchers::ArrayMatcher.new(array2, label) - match_data = matcher.match(partial) - match_data.message.should contain(label) - end - - context "when expected label is omitted" do - it "contains stringified form of expected array" do - array1 = %i[a b c] - array2 = %i[x y z] - partial = new_partial(array1) - matcher = Spectator::Matchers::ArrayMatcher.new(array2) - match_data = matcher.match(partial) - match_data.message.should contain(array2.to_s) - end - end - end - - describe "#negated_message" do - it "mentions content" do - array1 = %i[a b c] - array2 = %i[x y z] - partial = new_partial(array1) - matcher = Spectator::Matchers::ArrayMatcher.new(array2) - match_data = matcher.match(partial) - match_data.negated_message.should contain("content") - end - - it "contains the actual label" do - array1 = %i[a b c] - array2 = %i[x y z] - label = "everything" - partial = new_partial(array1, label) - matcher = Spectator::Matchers::ArrayMatcher.new(array2) - match_data = matcher.match(partial) - match_data.negated_message.should contain(label) - end - - it "contains the expected label" do - array1 = %i[a b c] - array2 = %i[x y z] - label = "everything" - partial = new_partial(array1) - matcher = Spectator::Matchers::ArrayMatcher.new(array2, label) - match_data = matcher.match(partial) - match_data.negated_message.should contain(label) - end - - context "when expected label is omitted" do - it "contains stringified form of expected array" do - array1 = %i[a b c] - array2 = %i[x y z] - partial = new_partial(array1) - matcher = Spectator::Matchers::ArrayMatcher.new(array2) - match_data = matcher.match(partial) - match_data.negated_message.should contain(array2.to_s) - end - end - end - end - end - end -end diff --git a/spec/matchers/attributes_matcher_spec.cr b/spec/matchers/attributes_matcher_spec.cr deleted file mode 100644 index 36bedc5..0000000 --- a/spec/matchers/attributes_matcher_spec.cr +++ /dev/null @@ -1,358 +0,0 @@ -require "../spec_helper" - -describe Spectator::Matchers::AttributesMatcher do - describe "#match" do - it "uses ===" do - array = %i[a b c] - spy = SpySUT.new - partial = new_partial(array) - matcher = Spectator::Matchers::AttributesMatcher.new({first: spy}) - matcher.match(partial) - spy.case_eq_call_count.should be > 0 - end - - context "returned MatchData" do - describe "#matched?" do - context "one argument" do - context "against an equal value" do - it "is true" do - array = %i[a b c] - attributes = {first: :a} - partial = new_partial(array) - matcher = Spectator::Matchers::AttributesMatcher.new(attributes) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - - context "against a different value" do - it "is false" do - array = %i[a b c] - attributes = {first: :z} - partial = new_partial(array) - matcher = Spectator::Matchers::AttributesMatcher.new(attributes) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - - context "against a matching type" do - it "is true" do - array = %i[a b c] - attributes = {first: Symbol} - partial = new_partial(array) - matcher = Spectator::Matchers::AttributesMatcher.new(attributes) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - - context "against a non-matching type" do - it "is false" do - array = %i[a b c] - attributes = {first: Int32} - partial = new_partial(array) - matcher = Spectator::Matchers::AttributesMatcher.new(attributes) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - - context "against a matching regex" do - it "is true" do - array = %w[FOO BAR BAZ] - attributes = {first: /foo/i} - partial = new_partial(array) - matcher = Spectator::Matchers::AttributesMatcher.new(attributes) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - - context "against a non-matching regex" do - it "is false" do - array = %w[FOO BAR BAZ] - attributes = {first: /qux/i} - partial = new_partial(array) - matcher = Spectator::Matchers::AttributesMatcher.new(attributes) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - end - - context "multiple attributes" do - context "against equal values" do - it "is true" do - array = %i[a b c] - attributes = {first: :a, last: :c} - partial = new_partial(array) - matcher = Spectator::Matchers::AttributesMatcher.new(attributes) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - - context "matching type" do - context "matching regex" do - it "is true" do - array = [:a, 42, "FOO"] - attributes = {first: Symbol, last: /foo/i} - partial = new_partial(array) - matcher = Spectator::Matchers::AttributesMatcher.new(attributes) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - - context "non-matching regex" do - it "is false" do - array = [:a, 42, "FOO"] - attributes = {first: Symbol, last: /bar/i} - partial = new_partial(array) - matcher = Spectator::Matchers::AttributesMatcher.new(attributes) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - end - - context "non-matching type" do - context "matching regex" do - it "is false" do - array = [:a, 42, "FOO"] - attributes = {first: Float32, last: /foo/i} - partial = new_partial(array) - matcher = Spectator::Matchers::AttributesMatcher.new(attributes) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - - context "non-matching regex" do - it "is false" do - array = [:a, 42, "FOO"] - attributes = {first: Float32, last: /bar/i} - partial = new_partial(array) - matcher = Spectator::Matchers::AttributesMatcher.new(attributes) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - end - end - - context "against one equal value" do - it "is false" do - array = %i[a b c] - attributes = {first: :a, last: :d} - partial = new_partial(array) - matcher = Spectator::Matchers::AttributesMatcher.new(attributes) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - - context "against no equal values" do - it "is false" do - array = %i[a b c] - attributes = {first: :d, last: :e} - partial = new_partial(array) - matcher = Spectator::Matchers::AttributesMatcher.new(attributes) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - - context "against matching types" do - it "is true" do - array = [:a, 42, "FOO"] - attributes = {first: Symbol, last: String} - partial = new_partial(array) - matcher = Spectator::Matchers::AttributesMatcher.new(attributes) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - - context "against one matching type" do - it "is false" do - array = [:a, 42, "FOO"] - attributes = {first: Symbol, last: Float32} - partial = new_partial(array) - matcher = Spectator::Matchers::AttributesMatcher.new(attributes) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - - context "against no matching types" do - it "is false" do - array = [:a, 42, "FOO"] - attributes = {first: Float32, last: Bytes} - partial = new_partial(array) - matcher = Spectator::Matchers::AttributesMatcher.new(attributes) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - - context "against matching regexes" do - it "is true" do - array = %w[FOO BAR BAZ] - attributes = {first: /foo/i, last: /baz/i} - partial = new_partial(array) - matcher = Spectator::Matchers::AttributesMatcher.new(attributes) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - - context "against one matching regex" do - it "is false" do - array = %w[FOO BAR BAZ] - attributes = {first: /foo/i, last: /qux/i} - partial = new_partial(array) - matcher = Spectator::Matchers::AttributesMatcher.new(attributes) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - - context "against no matching regexes" do - it "is false" do - array = %w[FOO BAR] - attributes = {first: /baz/i, last: /qux/i} - partial = new_partial(array) - matcher = Spectator::Matchers::AttributesMatcher.new(attributes) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - - context "against equal and matching type and regex" do - it "is true" do - array = [:a, 42, "FOO"] - attributes = {first: Symbol, last: /foo/i, size: 3} - partial = new_partial(array) - matcher = Spectator::Matchers::AttributesMatcher.new(attributes) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - end - end - - describe "#values" do - it "contains a key for each expected attribute" do - array = [:a, 42, "FOO"] - attributes = {first: Symbol, last: /foo/i, size: 3} - partial = new_partial(array) - matcher = Spectator::Matchers::AttributesMatcher.new(attributes) - match_data = matcher.match(partial) - match_data_has_key?(match_data.values, :"expected first").should be_true - match_data_has_key?(match_data.values, :"expected last").should be_true - match_data_has_key?(match_data.values, :"expected size").should be_true - end - - it "contains a key for each actual value" do - array = [:a, 42, "FOO"] - attributes = {first: Symbol, last: /foo/i, size: 3} - partial = new_partial(array) - matcher = Spectator::Matchers::AttributesMatcher.new(attributes) - match_data = matcher.match(partial) - match_data_has_key?(match_data.values, :"actual first").should be_true - match_data_has_key?(match_data.values, :"actual last").should be_true - match_data_has_key?(match_data.values, :"actual size").should be_true - end - - it "has the expected values" do - array = [:a, 42, "FOO"] - attributes = {first: Symbol, last: /foo/i, size: 3} - partial = new_partial(array) - matcher = Spectator::Matchers::AttributesMatcher.new(attributes) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :"expected first")[:value].should eq(attributes[:first]) - match_data_value_sans_prefix(match_data.values, :"expected last")[:value].should eq(attributes[:last]) - match_data_value_sans_prefix(match_data.values, :"expected size")[:value].should eq(attributes[:size]) - end - - it "has the actual values" do - array = [:a, 42, "FOO"] - attributes = {first: Symbol, last: /foo/i, size: 3} - partial = new_partial(array) - matcher = Spectator::Matchers::AttributesMatcher.new(attributes) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :"actual first")[:value].should eq(array.first) - match_data_value_sans_prefix(match_data.values, :"actual last")[:value].should eq(array.last) - match_data_value_sans_prefix(match_data.values, :"actual size")[:value].should eq(array.size) - end - end - - describe "#message" do - it "contains the actual label" do - value = "foobar" - attributes = {size: 6} - label = "everything" - partial = new_partial(value, label) - matcher = Spectator::Matchers::AttributesMatcher.new(attributes) - match_data = matcher.match(partial) - match_data.message.should contain(label) - end - - it "contains the expected label" do - value = "foobar" - attributes = {size: 6} - label = "everything" - partial = new_partial(value) - matcher = Spectator::Matchers::AttributesMatcher.new(attributes, label) - match_data = matcher.match(partial) - match_data.message.should contain(label) - end - - context "when expected label is omitted" do - it "contains stringified form of expected value" do - value = "foobar" - attributes = {size: 6} - partial = new_partial(value) - matcher = Spectator::Matchers::AttributesMatcher.new(attributes) - match_data = matcher.match(partial) - match_data.message.should contain(attributes.to_s) - end - end - end - - describe "#negated_message" do - it "contains the actual label" do - value = "foobar" - attributes = {size: 6} - label = "everything" - partial = new_partial(value, label) - matcher = Spectator::Matchers::AttributesMatcher.new(attributes) - match_data = matcher.match(partial) - match_data.negated_message.should contain(label) - end - - it "contains the expected label" do - value = "foobar" - attributes = {size: 6} - label = "everything" - partial = new_partial(value) - matcher = Spectator::Matchers::AttributesMatcher.new(attributes, label) - match_data = matcher.match(partial) - match_data.negated_message.should contain(label) - end - - context "when expected label is omitted" do - it "contains stringified form of expected value" do - value = "foobar" - attributes = {size: 6} - partial = new_partial(value) - matcher = Spectator::Matchers::AttributesMatcher.new(attributes) - match_data = matcher.match(partial) - match_data.negated_message.should contain(attributes.to_s) - end - end - end - end - end -end diff --git a/spec/matchers/case_matcher_spec.cr b/spec/matchers/case_matcher_spec.cr deleted file mode 100644 index 573a30b..0000000 --- a/spec/matchers/case_matcher_spec.cr +++ /dev/null @@ -1,203 +0,0 @@ -require "../spec_helper" - -describe Spectator::Matchers::CaseMatcher do - describe "#match" do - it "compares using #===" do - spy = SpySUT.new - partial = new_partial(42) - matcher = Spectator::Matchers::CaseMatcher.new(spy) - matcher.match(partial) - spy.case_eq_call_count.should be > 0 - end - - context "returned MatchData" do - describe "#matched?" do - context "with identical values" do - it "is true" do - value = 42 - partial = new_partial(value) - matcher = Spectator::Matchers::CaseMatcher.new(value) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - - context "with different values" do - it "is false" do - value1 = 42 - value2 = 777 - partial = new_partial(value1) - matcher = Spectator::Matchers::CaseMatcher.new(value2) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - - context "with the same instance" do - it "is true" do - # Box is used because it is a reference type and doesn't override the == method. - ref = Box.new([] of Int32) - partial = new_partial(ref) - matcher = Spectator::Matchers::CaseMatcher.new(ref) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - - context "with different instances" do - context "with same contents" do - it "is true" do - array1 = [1, 2, 3] - array2 = [1, 2, 3] - partial = new_partial(array1) - matcher = Spectator::Matchers::CaseMatcher.new(array2) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - - context "with different contents" do - it "is false" do - array1 = [1, 2, 3] - array2 = [4, 5, 6] - partial = new_partial(array1) - matcher = Spectator::Matchers::CaseMatcher.new(array2) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - - context "with the same type" do - it "is true" do - value1 = "foobar" - value2 = String - partial = new_partial(value1) - matcher = Spectator::Matchers::CaseMatcher.new(value2) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - - context "with a different type" do - it "is false" do - value1 = "foobar" - value2 = Array - partial = new_partial(value1) - matcher = Spectator::Matchers::CaseMatcher.new(value2) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - - context "with a matching regex" do - it "is true" do - value = "foobar" - pattern = /foo/ - partial = new_partial(value) - matcher = Spectator::Matchers::CaseMatcher.new(pattern) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - - context "with a non-matching regex" do - it "is false" do - value = "foo" - pattern = /bar/ - partial = new_partial(value) - matcher = Spectator::Matchers::CaseMatcher.new(pattern) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - end - end - - describe "#values" do - context "expected" do - it "is the expected value" do - actual = "foobar" - expected = /foo/ - partial = new_partial(actual) - matcher = Spectator::Matchers::CaseMatcher.new(expected) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :expected)[:value].should eq(expected) - end - end - - context "actual" do - it "is the actual value" do - actual = "foobar" - expected = /foo/ - partial = new_partial(actual) - matcher = Spectator::Matchers::CaseMatcher.new(expected) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :actual)[:value].should eq(actual) - end - end - end - - describe "#message" do - it "contains the actual label" do - value = 42 - label = "everything" - partial = new_partial(value, label) - matcher = Spectator::Matchers::CaseMatcher.new(value) - match_data = matcher.match(partial) - match_data.message.should contain(label) - end - - it "contains the expected label" do - value = 42 - label = "everything" - partial = new_partial(value) - matcher = Spectator::Matchers::CaseMatcher.new(value, label) - match_data = matcher.match(partial) - match_data.message.should contain(label) - end - - context "when expected label is omitted" do - it "contains stringified form of expected value" do - value1 = 42 - value2 = 777 - partial = new_partial(value1) - matcher = Spectator::Matchers::CaseMatcher.new(value2) - match_data = matcher.match(partial) - match_data.message.should contain(value2.to_s) - end - end - end - - describe "#negated_message" do - it "contains the actual label" do - value = 42 - label = "everything" - partial = new_partial(value, label) - matcher = Spectator::Matchers::CaseMatcher.new(value) - match_data = matcher.match(partial) - match_data.negated_message.should contain(label) - end - - it "contains the expected label" do - value = 42 - label = "everything" - partial = new_partial(value) - matcher = Spectator::Matchers::CaseMatcher.new(value, label) - match_data = matcher.match(partial) - match_data.negated_message.should contain(label) - end - - context "when expected label is omitted" do - it "contains stringified form of expected value" do - value1 = 42 - value2 = 777 - partial = new_partial(value1) - matcher = Spectator::Matchers::CaseMatcher.new(value2) - match_data = matcher.match(partial) - match_data.negated_message.should contain(value2.to_s) - end - end - end - end - end -end diff --git a/spec/matchers/collection_matcher_spec.cr b/spec/matchers/collection_matcher_spec.cr deleted file mode 100644 index f848792..0000000 --- a/spec/matchers/collection_matcher_spec.cr +++ /dev/null @@ -1,391 +0,0 @@ -require "../spec_helper" - -describe Spectator::Matchers::CollectionMatcher do - describe "#match" do - it "compares using #includes?" do - spy = SpySUT.new - partial = new_partial(5) - matcher = Spectator::Matchers::CollectionMatcher.new(spy) - matcher.match(partial) - spy.includes_call_count.should be > 0 - end - - context "returned MatchData" do - describe "#matched?" do - context "given a Range" do - context "inclusive" do - it "is true for lower-bound" do - lower = 3 - upper = 9 - value = lower - range = Range.new(lower, upper, exclusive: false) - partial = new_partial(value) - matcher = Spectator::Matchers::CollectionMatcher.new(range) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - - it "is false for lower-bound minus 1" do - lower = 3 - upper = 9 - value = lower - 1 - range = Range.new(lower, upper, exclusive: false) - partial = new_partial(value) - matcher = Spectator::Matchers::CollectionMatcher.new(range) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - - it "is true for mid-range" do - lower = 3 - upper = 9 - value = 5 - range = Range.new(lower, upper, exclusive: false) - partial = new_partial(value) - matcher = Spectator::Matchers::CollectionMatcher.new(range) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - - it "is true for upper-bound" do - lower = 3 - upper = 9 - value = upper - range = Range.new(lower, upper, exclusive: false) - partial = new_partial(value) - matcher = Spectator::Matchers::CollectionMatcher.new(range) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - - it "is false for upper-bound plus 1" do - lower = 3 - upper = 9 - value = upper + 1 - range = Range.new(lower, upper, exclusive: false) - partial = new_partial(value) - matcher = Spectator::Matchers::CollectionMatcher.new(range) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - - context "exclusive" do - it "is true for lower-bound" do - lower = 3 - upper = 9 - value = lower - range = Range.new(lower, upper, exclusive: true) - partial = new_partial(value) - matcher = Spectator::Matchers::CollectionMatcher.new(range) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - - it "is false for lower-bound minus 1" do - lower = 3 - upper = 9 - value = lower - 1 - range = Range.new(lower, upper, exclusive: true) - partial = new_partial(value) - matcher = Spectator::Matchers::CollectionMatcher.new(range) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - - it "is true for mid-range" do - lower = 3 - upper = 9 - value = 5 - range = Range.new(lower, upper, exclusive: true) - partial = new_partial(value) - matcher = Spectator::Matchers::CollectionMatcher.new(range) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - - it "is false for upper-bound" do - lower = 3 - upper = 9 - value = upper - range = Range.new(lower, upper, exclusive: true) - partial = new_partial(value) - matcher = Spectator::Matchers::CollectionMatcher.new(range) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - - it "is false for upper-bound plus 1" do - lower = 3 - upper = 9 - value = upper + 1 - range = Range.new(lower, upper, exclusive: true) - partial = new_partial(value) - matcher = Spectator::Matchers::CollectionMatcher.new(range) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - end - - context "given an Enumerable" do - it "is true for an existing item" do - array = %i[a b c] - value = :b - partial = new_partial(value) - matcher = Spectator::Matchers::CollectionMatcher.new(array) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - - it "is false for a non-existing item" do - array = %i[a b c] - value = :z - partial = new_partial(value) - matcher = Spectator::Matchers::CollectionMatcher.new(array) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - end - - describe "#values" do - context "given a Range" do - context "collection" do - it "is the expected value" do - value = 5 - range = Range.new(3, 9) - partial = new_partial(value) - matcher = Spectator::Matchers::CollectionMatcher.new(range) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :collection)[:value].should eq(range) - end - end - - context "actual" do - it "is the actual value" do - value = 5 - range = Range.new(3, 9) - partial = new_partial(value) - matcher = Spectator::Matchers::CollectionMatcher.new(range) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :actual)[:value].should eq(value) - end - end - end - - context "given an Enumerable" do - context "collection" do - it "is the expected value" do - array = %i[a b c] - value = :z - partial = new_partial(value) - matcher = Spectator::Matchers::CollectionMatcher.new(array) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :collection)[:value].should eq(array) - end - end - - context "actual" do - it "is the actual value" do - array = %i[a b c] - value = :z - partial = new_partial(value) - matcher = Spectator::Matchers::CollectionMatcher.new(array) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :actual)[:value].should eq(value) - end - end - end - end - - describe "#message" do - it "contains the actual label" do - range = 1..10 - value = 5 - label = "everything" - partial = new_partial(value, label) - matcher = Spectator::Matchers::CollectionMatcher.new(range) - match_data = matcher.match(partial) - match_data.message.should contain(label) - end - - it "contains the expected label" do - range = 1..10 - value = 5 - label = "everything" - partial = new_partial(value) - matcher = Spectator::Matchers::CollectionMatcher.new(range, label) - match_data = matcher.match(partial) - match_data.message.should contain(label) - end - - context "when expected label is omitted" do - it "contains stringified form of expected value" do - range = 1..10 - value = 5 - partial = new_partial(value) - matcher = Spectator::Matchers::CollectionMatcher.new(range) - match_data = matcher.match(partial) - match_data.message.should contain(range.to_s) - end - end - end - - describe "#negated_message" do - it "contains the actual label" do - range = 1..10 - value = 5 - label = "everything" - partial = new_partial(value, label) - matcher = Spectator::Matchers::CollectionMatcher.new(range) - match_data = matcher.match(partial) - match_data.negated_message.should contain(label) - end - - it "contains the expected label" do - range = 1..10 - value = 5 - label = "everything" - partial = new_partial(value) - matcher = Spectator::Matchers::CollectionMatcher.new(range, label) - match_data = matcher.match(partial) - match_data.negated_message.should contain(label) - end - - context "when expected label is omitted" do - it "contains stringified form of expected value" do - range = 1..10 - value = 5 - partial = new_partial(value) - matcher = Spectator::Matchers::CollectionMatcher.new(range) - match_data = matcher.match(partial) - match_data.negated_message.should contain(range.to_s) - end - end - end - end - end - - describe "#of" do - it "is true for lower-bound" do - center = 5 - diff = 4 - lower = center - diff - value = lower - partial = new_partial(value) - matcher = Spectator::Matchers::CollectionMatcher.new(diff).of(center) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - - it "is false for lower-bound minus 1" do - center = 5 - diff = 4 - lower = center - diff - value = lower - 1 - partial = new_partial(value) - matcher = Spectator::Matchers::CollectionMatcher.new(diff).of(center) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - - it "is true for mid-range" do - center = 5 - diff = 4 - value = center - partial = new_partial(value) - matcher = Spectator::Matchers::CollectionMatcher.new(diff).of(center) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - - it "is true for upper-bound" do - center = 5 - diff = 4 - upper = center + diff - value = upper - partial = new_partial(value) - matcher = Spectator::Matchers::CollectionMatcher.new(diff).of(center) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - - it "is false for upper-bound plus 1" do - center = 5 - diff = 4 - upper = center + diff - value = upper + 1 - partial = new_partial(value) - matcher = Spectator::Matchers::CollectionMatcher.new(diff).of(center) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - - describe "#message" do - it "contains the original label" do - center = 5 - diff = 4 - value = 3 - label = "foobar" - partial = new_partial(value) - matcher = Spectator::Matchers::CollectionMatcher.new(diff, label).of(center) - match_data = matcher.match(partial) - match_data.message.should contain(label) - end - - it "contains the center" do - center = 5 - diff = 4 - value = 3 - partial = new_partial(value) - matcher = Spectator::Matchers::CollectionMatcher.new(diff).of(center) - match_data = matcher.match(partial) - match_data.message.should contain(center.to_s) - end - - it "contains the diff" do - center = 5 - diff = 4 - value = 3 - partial = new_partial(value) - matcher = Spectator::Matchers::CollectionMatcher.new(diff).of(center) - match_data = matcher.match(partial) - match_data.message.should contain(diff.to_s) - end - end - - describe "#negated_message" do - it "contains the original label" do - center = 5 - diff = 4 - value = 3 - label = "foobar" - partial = new_partial(value) - matcher = Spectator::Matchers::CollectionMatcher.new(diff, label).of(center) - match_data = matcher.match(partial) - match_data.negated_message.should contain(label) - end - - it "contains the center" do - center = 5 - diff = 4 - value = 3 - partial = new_partial(value) - matcher = Spectator::Matchers::CollectionMatcher.new(diff).of(center) - match_data = matcher.match(partial) - match_data.negated_message.should contain(center.to_s) - end - - it "contains the diff" do - center = 5 - diff = 4 - value = 3 - partial = new_partial(value) - matcher = Spectator::Matchers::CollectionMatcher.new(diff).of(center) - match_data = matcher.match(partial) - match_data.negated_message.should contain(diff.to_s) - end - end - end -end diff --git a/spec/matchers/contain_matcher_spec.cr b/spec/matchers/contain_matcher_spec.cr deleted file mode 100644 index a10af48..0000000 --- a/spec/matchers/contain_matcher_spec.cr +++ /dev/null @@ -1,386 +0,0 @@ -require "../spec_helper" - -describe Spectator::Matchers::ContainMatcher do - describe "#match" do - context "returned MatchData" do - describe "#matched?" do - context "with a String" do - context "one argument" do - context "against a matching string" do - it "is true" do - value = "foobarbaz" - search = "bar" - partial = new_partial(value) - matcher = Spectator::Matchers::ContainMatcher.new({search}) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - - context "at the beginning" do - it "is true" do - value = "foobar" - search = "foo" - partial = new_partial(value) - matcher = Spectator::Matchers::ContainMatcher.new({search}) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - - context "at the end" do - it "is true" do - value = "foobar" - search = "bar" - partial = new_partial(value) - matcher = Spectator::Matchers::ContainMatcher.new({search}) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - end - - context "against a different string" do - it "is false" do - value = "foobar" - search = "baz" - partial = new_partial(value) - matcher = Spectator::Matchers::ContainMatcher.new({search}) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - - context "against a matching character" do - it "is true" do - value = "foobar" - search = 'o' - partial = new_partial(value) - matcher = Spectator::Matchers::ContainMatcher.new({search}) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - - context "at the beginning" do - it "is true" do - value = "foobar" - search = 'f' - partial = new_partial(value) - matcher = Spectator::Matchers::ContainMatcher.new({search}) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - - context "at the end" do - it "is true" do - value = "foobar" - search = 'r' - partial = new_partial(value) - matcher = Spectator::Matchers::ContainMatcher.new({search}) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - end - - context "against a different character" do - it "is false" do - value = "foobar" - search = 'z' - partial = new_partial(value) - matcher = Spectator::Matchers::ContainMatcher.new({search}) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - end - - context "multiple arguments" do - context "against matching strings" do - it "is true" do - value = "foobarbaz" - search = {"foo", "bar", "baz"} - partial = new_partial(value) - matcher = Spectator::Matchers::ContainMatcher.new(search) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - - context "against one matching string" do - it "is false" do - value = "foobarbaz" - search = {"foo", "qux"} - partial = new_partial(value) - matcher = Spectator::Matchers::ContainMatcher.new(search) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - - context "against no matching strings" do - it "is false" do - value = "foobar" - search = {"baz", "qux"} - partial = new_partial(value) - matcher = Spectator::Matchers::ContainMatcher.new(search) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - - context "against matching characters" do - it "is true" do - value = "foobarbaz" - search = {'f', 'b', 'z'} - partial = new_partial(value) - matcher = Spectator::Matchers::ContainMatcher.new(search) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - - context "against one matching character" do - it "is false" do - value = "foobarbaz" - search = {'f', 'c', 'd'} - partial = new_partial(value) - matcher = Spectator::Matchers::ContainMatcher.new(search) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - - context "against no matching characters" do - it "is false" do - value = "foobarbaz" - search = {'c', 'd', 'e'} - partial = new_partial(value) - matcher = Spectator::Matchers::ContainMatcher.new(search) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - - context "against a matching string and character" do - it "is true" do - value = "foobarbaz" - search = {"foo", 'z'} - partial = new_partial(value) - matcher = Spectator::Matchers::ContainMatcher.new(search) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - - context "against a matching string and non-matching character" do - it "is false" do - value = "foobarbaz" - search = {"foo", 'c'} - partial = new_partial(value) - matcher = Spectator::Matchers::ContainMatcher.new(search) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - - context "against a non-matching string and matching character" do - it "is false" do - value = "foobarbaz" - search = {"qux", 'f'} - partial = new_partial(value) - matcher = Spectator::Matchers::ContainMatcher.new(search) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - - context "against a non-matching string and character" do - it "is false" do - value = "foobarbaz" - search = {"qux", 'c'} - partial = new_partial(value) - matcher = Spectator::Matchers::ContainMatcher.new(search) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - end - end - - context "with an Enumberable" do - context "one argument" do - context "against an equal value" do - it "is true" do - array = %i[a b c] - search = :b - partial = new_partial(array) - matcher = Spectator::Matchers::ContainMatcher.new({search}) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - - context "at the beginning" do - it "is true" do - array = %i[a b c] - search = :a - partial = new_partial(array) - matcher = Spectator::Matchers::ContainMatcher.new({search}) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - - context "at the end" do - it "is true" do - array = %i[a b c] - search = :c - partial = new_partial(array) - matcher = Spectator::Matchers::ContainMatcher.new({search}) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - end - - context "against a different value" do - it "is false" do - array = %i[a b c] - search = :z - partial = new_partial(array) - matcher = Spectator::Matchers::ContainMatcher.new({search}) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - end - - context "multiple arguments" do - context "against equal values" do - it "is true" do - array = %i[a b c] - search = {:a, :b} - partial = new_partial(array) - matcher = Spectator::Matchers::ContainMatcher.new(search) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - - context "against one equal value" do - it "is false" do - array = %i[a b c] - search = {:a, :d} - partial = new_partial(array) - matcher = Spectator::Matchers::ContainMatcher.new(search) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - - context "against no equal values" do - it "is false" do - array = %i[a b c] - search = {:d, :e} - partial = new_partial(array) - matcher = Spectator::Matchers::ContainMatcher.new(search) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - end - end - end - - describe "#values" do - describe "subset" do - it "is the expected set" do - array = %i[a b c] - search = {:d, :e} - partial = new_partial(array) - matcher = Spectator::Matchers::ContainMatcher.new(search) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :subset)[:value].should eq(search) - end - end - - describe "superset" do - it "is the actual set" do - array = %i[a b c] - search = {:d, :e} - partial = new_partial(array) - matcher = Spectator::Matchers::ContainMatcher.new(search) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :superset)[:value].should eq(array) - end - end - end - - describe "#message" do - it "contains the actual label" do - value = "foobar" - search = "baz" - label = "everything" - partial = new_partial(value, label) - matcher = Spectator::Matchers::ContainMatcher.new({search}) - match_data = matcher.match(partial) - match_data.message.should contain(label) - end - - it "contains the expected label" do - value = "foobar" - search = "baz" - label = "everything" - partial = new_partial(value) - matcher = Spectator::Matchers::ContainMatcher.new({search}, label) - match_data = matcher.match(partial) - match_data.message.should contain(label) - end - - context "when expected label is omitted" do - it "contains stringified form of expected value" do - value = "foobar" - search = "baz" - partial = new_partial(value) - matcher = Spectator::Matchers::ContainMatcher.new({search}) - match_data = matcher.match(partial) - match_data.message.should contain(search) - end - end - end - - describe "#negated_message" do - it "contains the actual label" do - value = "foobar" - search = "baz" - label = "everything" - partial = new_partial(value, label) - matcher = Spectator::Matchers::ContainMatcher.new({search}) - match_data = matcher.match(partial) - match_data.negated_message.should contain(label) - end - - it "contains the expected label" do - value = "foobar" - search = "baz" - label = "everything" - partial = new_partial(value) - matcher = Spectator::Matchers::ContainMatcher.new({search}, label) - match_data = matcher.match(partial) - match_data.negated_message.should contain(label) - end - - context "when expected label is omitted" do - it "contains stringified form of expected value" do - value = "foobar" - search = "baz" - partial = new_partial(value) - matcher = Spectator::Matchers::ContainMatcher.new({search}) - match_data = matcher.match(partial) - match_data.negated_message.should contain(search) - end - end - end - end - end -end diff --git a/spec/matchers/empty_matcher_spec.cr b/spec/matchers/empty_matcher_spec.cr deleted file mode 100644 index eea43bc..0000000 --- a/spec/matchers/empty_matcher_spec.cr +++ /dev/null @@ -1,73 +0,0 @@ -require "../spec_helper" - -describe Spectator::Matchers::EmptyMatcher do - describe "#match" do - context "returned MatchData" do - describe "#matched?" do - context "with an empty set" do - it "is true" do - array = [] of Symbol - partial = new_partial(array) - matcher = Spectator::Matchers::EmptyMatcher.new - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - - context "with a filled set" do - it "is false" do - array = %i[a b c] - partial = new_partial(array) - matcher = Spectator::Matchers::EmptyMatcher.new - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - end - - describe "#values" do - context "expected" do - it "is an empty set" do - array = %i[a b c] - partial = new_partial(array) - matcher = Spectator::Matchers::EmptyMatcher.new - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :expected)[:to_s].should eq("[]") - end - end - - context "actual" do - it "is the actual set" do - array = %i[a b c] - partial = new_partial(array) - matcher = Spectator::Matchers::EmptyMatcher.new - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :actual)[:value].should eq(array) - end - end - end - - describe "#message" do - it "contains the actual label" do - array = %i[a b c] - label = "everything" - partial = new_partial(array, label) - matcher = Spectator::Matchers::EmptyMatcher.new - match_data = matcher.match(partial) - match_data.message.should contain(label) - end - end - - describe "#negated_message" do - it "contains the actual label" do - array = %i[a b c] - label = "everything" - partial = new_partial(array, label) - matcher = Spectator::Matchers::EmptyMatcher.new - match_data = matcher.match(partial) - match_data.negated_message.should contain(label) - end - end - end - end -end diff --git a/spec/matchers/end_with_matcher_spec.cr b/spec/matchers/end_with_matcher_spec.cr deleted file mode 100644 index d9894d5..0000000 --- a/spec/matchers/end_with_matcher_spec.cr +++ /dev/null @@ -1,393 +0,0 @@ -require "../spec_helper" - -describe Spectator::Matchers::EndWithMatcher do - describe "#match" do - context "returned MatchData" do - describe "#matched?" do - context "with a String" do - context "against a matching string" do - it "is true" do - value = "foobar" - last = "bar" - partial = new_partial(value) - matcher = Spectator::Matchers::EndWithMatcher.new(last) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - - context "not at end" do - it "is false" do - value = "foobar" - last = "foo" - partial = new_partial(value) - matcher = Spectator::Matchers::EndWithMatcher.new(last) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - end - - context "against a different string" do - it "is false" do - value = "foobar" - last = "baz" - partial = new_partial(value) - matcher = Spectator::Matchers::EndWithMatcher.new(last) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - - context "against a matching character" do - it "is true" do - value = "foobar" - last = 'r' - partial = new_partial(value) - matcher = Spectator::Matchers::EndWithMatcher.new(last) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - - context "not at end" do - it "is false" do - value = "foobar" - last = 'b' - partial = new_partial(value) - matcher = Spectator::Matchers::EndWithMatcher.new(last) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - end - - context "against a different character" do - it "is false" do - value = "foobar" - last = 'z' - partial = new_partial(value) - matcher = Spectator::Matchers::EndWithMatcher.new(last) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - - context "against a matching regex" do - it "is true" do - value = "FOOBAR" - last = /bar/i - partial = new_partial(value) - matcher = Spectator::Matchers::EndWithMatcher.new(last) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - - context "not at end" do - it "is false" do - value = "FOOBAR" - last = /foo/i - partial = new_partial(value) - matcher = Spectator::Matchers::EndWithMatcher.new(last) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - end - - context "against a non-matching regex" do - it "is false" do - value = "FOOBAR" - last = /baz/i - partial = new_partial(value) - matcher = Spectator::Matchers::EndWithMatcher.new(last) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - end - - context "with an Enumberable" do - context "against an equal value" do - it "is true" do - array = %i[a b c] - last = :c - partial = new_partial(array) - matcher = Spectator::Matchers::EndWithMatcher.new(last) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - - context "not at end" do - it "is false" do - array = %i[a b c] - last = :b - partial = new_partial(array) - matcher = Spectator::Matchers::EndWithMatcher.new(last) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - end - - context "against a different value" do - it "is false" do - array = %i[a b c] - last = :z - partial = new_partial(array) - matcher = Spectator::Matchers::EndWithMatcher.new(last) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - - context "against matching element type" do - it "is true" do - array = %i[a b c] - partial = new_partial(array) - matcher = Spectator::Matchers::EndWithMatcher.new(Symbol) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - - context "not at end" do - it "is false" do - array = [1, 2, 3, :a, :b, :c] - partial = new_partial(array) - matcher = Spectator::Matchers::EndWithMatcher.new(Int32) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - end - - context "against different element type" do - it "is false" do - array = %i[a b c] - partial = new_partial(array) - matcher = Spectator::Matchers::EndWithMatcher.new(Int32) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - - context "against a matching regex" do - it "is true" do - array = %w[FOO BAR BAZ] - last = /baz/i - partial = new_partial(array) - matcher = Spectator::Matchers::EndWithMatcher.new(last) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - - context "not at end" do - it "is false" do - array = %w[FOO BAR BAZ] - last = /bar/i - partial = new_partial(array) - matcher = Spectator::Matchers::EndWithMatcher.new(last) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - end - - context "against a non-matching regex" do - it "is false" do - array = %w[FOO BAR BAZ] - last = /qux/i - partial = new_partial(array) - matcher = Spectator::Matchers::EndWithMatcher.new(last) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - end - end - - describe "#values" do - context "with a String" do - context "expected" do - it "is the expected value" do - value = "FOOBAR" - last = /baz/i - partial = new_partial(value) - matcher = Spectator::Matchers::EndWithMatcher.new(last) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :expected)[:value].should eq(last) - end - end - - context "actual" do - it "is the actual value" do - value = "FOOBAR" - last = /baz/i - partial = new_partial(value) - matcher = Spectator::Matchers::EndWithMatcher.new(last) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :actual)[:value].should eq(value) - end - end - end - - context "with an Indexable" do - context "expected" do - it "is the expected value" do - array = %w[FOO BAR BAZ] - last = /qux/i - partial = new_partial(array) - matcher = Spectator::Matchers::EndWithMatcher.new(last) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :expected)[:value].should eq(last) - end - end - - context "actual" do - it "is the last element" do - array = %w[FOO BAR BAZ] - last = /qux/i - partial = new_partial(array) - matcher = Spectator::Matchers::EndWithMatcher.new(last) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :actual)[:value].should eq(array.last) - end - end - - context "list" do - it "is the full actual list" do - array = %w[FOO BAR BAZ] - last = /qux/i - partial = new_partial(array) - matcher = Spectator::Matchers::EndWithMatcher.new(last) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :list)[:value].should eq(array) - end - end - end - end - - describe "#message" do - context "with a String" do - it "mentions #ends_with?" do - value = "foobar" - last = "baz" - partial = new_partial(value) - matcher = Spectator::Matchers::EndWithMatcher.new(last) - match_data = matcher.match(partial) - match_data.message.should contain("#ends_with?") - end - end - - context "with an Indexable" do - it "mentions ===" do - array = %i[a b c] - partial = new_partial(array) - matcher = Spectator::Matchers::EndWithMatcher.new(array.last) - match_data = matcher.match(partial) - match_data.message.should contain("===") - end - - it "mentions last" do - array = %i[a b c] - partial = new_partial(array) - matcher = Spectator::Matchers::EndWithMatcher.new(array.last) - match_data = matcher.match(partial) - match_data.message.should contain("last") - end - end - - it "contains the actual label" do - value = "foobar" - last = "baz" - label = "everything" - partial = new_partial(value, label) - matcher = Spectator::Matchers::EndWithMatcher.new(last) - match_data = matcher.match(partial) - match_data.message.should contain(label) - end - - it "contains the expected label" do - value = "foobar" - last = "baz" - label = "everything" - partial = new_partial(value) - matcher = Spectator::Matchers::EndWithMatcher.new(last, label) - match_data = matcher.match(partial) - match_data.message.should contain(label) - end - - context "when expected label is omitted" do - it "contains stringified form of expected value" do - value = "foobar" - last = "baz" - partial = new_partial(value) - matcher = Spectator::Matchers::EndWithMatcher.new(last) - match_data = matcher.match(partial) - match_data.message.should contain(last) - end - end - end - - describe "#negated_message" do - context "with a String" do - it "mentions #starts_with?" do - value = "foobar" - last = "baz" - partial = new_partial(value) - matcher = Spectator::Matchers::EndWithMatcher.new(last) - match_data = matcher.match(partial) - match_data.negated_message.should contain("#ends_with?") - end - end - - context "with an Indexable" do - it "mentions ===" do - array = %i[a b c] - partial = new_partial(array) - matcher = Spectator::Matchers::EndWithMatcher.new(array.last) - match_data = matcher.match(partial) - match_data.negated_message.should contain("===") - end - - it "mentions last" do - array = %i[a b c] - partial = new_partial(array) - matcher = Spectator::Matchers::EndWithMatcher.new(array.last) - match_data = matcher.match(partial) - match_data.negated_message.should contain("last") - end - end - - it "contains the actual label" do - value = "foobar" - last = "baz" - label = "everything" - partial = new_partial(value, label) - matcher = Spectator::Matchers::EndWithMatcher.new(last) - match_data = matcher.match(partial) - match_data.negated_message.should contain(label) - end - - it "contains the expected label" do - value = "foobar" - last = "baz" - label = "everything" - partial = new_partial(value) - matcher = Spectator::Matchers::EndWithMatcher.new(last, label) - match_data = matcher.match(partial) - match_data.negated_message.should contain(label) - end - - context "when expected label is omitted" do - it "contains stringified form of expected value" do - value = "foobar" - last = "baz" - partial = new_partial(value) - matcher = Spectator::Matchers::EndWithMatcher.new(last) - match_data = matcher.match(partial) - match_data.negated_message.should contain(last) - end - end - end - end - end -end diff --git a/spec/matchers/equality_matcher_spec.cr b/spec/matchers/equality_matcher_spec.cr deleted file mode 100644 index b997a0f..0000000 --- a/spec/matchers/equality_matcher_spec.cr +++ /dev/null @@ -1,173 +0,0 @@ -require "../spec_helper" - -describe Spectator::Matchers::EqualityMatcher do - describe "#match" do - it "compares using #==" do - spy = SpySUT.new - partial = new_partial(spy) - matcher = Spectator::Matchers::EqualityMatcher.new(42) - matcher.match(partial) - spy.eq_call_count.should be > 0 - end - - context "returned MatchData" do - describe "#matched?" do - context "with identical values" do - it "is true" do - value = 42 - partial = new_partial(value) - matcher = Spectator::Matchers::EqualityMatcher.new(value) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - - context "with different values" do - it "is false" do - value1 = 42 - value2 = 777 - partial = new_partial(value1) - matcher = Spectator::Matchers::EqualityMatcher.new(value2) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - - context "with the same instance" do - it "is true" do - # Box is used because it is a reference type and doesn't override the == method. - ref = Box.new([] of Int32) - partial = new_partial(ref) - matcher = Spectator::Matchers::EqualityMatcher.new(ref) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - - context "with different instances" do - context "with same contents" do - it "is true" do - array1 = [1, 2, 3] - array2 = [1, 2, 3] - partial = new_partial(array1) - matcher = Spectator::Matchers::EqualityMatcher.new(array2) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - - context "with different contents" do - it "is false" do - array1 = [1, 2, 3] - array2 = [4, 5, 6] - partial = new_partial(array1) - matcher = Spectator::Matchers::EqualityMatcher.new(array2) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - end - end - - describe "#values" do - context "expected" do - it "is the expected value" do - expected, actual = 42, 777 - partial = new_partial(actual) - matcher = Spectator::Matchers::EqualityMatcher.new(expected) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :expected)[:value].should eq(expected) - end - end - - context "actual" do - it "is the actual value" do - expected, actual = 42, 777 - partial = new_partial(actual) - matcher = Spectator::Matchers::EqualityMatcher.new(expected) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :actual)[:value].should eq(actual) - end - end - end - - describe "#message" do - it "mentions ==" do - value = 42 - partial = new_partial(value) - matcher = Spectator::Matchers::EqualityMatcher.new(value) - match_data = matcher.match(partial) - match_data.message.should contain("==") - end - - it "contains the actual label" do - value = 42 - label = "everything" - partial = new_partial(value, label) - matcher = Spectator::Matchers::EqualityMatcher.new(value) - match_data = matcher.match(partial) - match_data.message.should contain(label) - end - - it "contains the expected label" do - value = 42 - label = "everything" - partial = new_partial(value) - matcher = Spectator::Matchers::EqualityMatcher.new(value, label) - match_data = matcher.match(partial) - match_data.message.should contain(label) - end - - context "when expected label is omitted" do - it "contains stringified form of expected value" do - value1 = 42 - value2 = 777 - partial = new_partial(value1) - matcher = Spectator::Matchers::EqualityMatcher.new(value2) - match_data = matcher.match(partial) - match_data.message.should contain(value2.to_s) - end - end - end - - describe "#negated_message" do - it "mentions ==" do - value = 42 - partial = new_partial(value) - matcher = Spectator::Matchers::EqualityMatcher.new(value) - match_data = matcher.match(partial) - match_data.negated_message.should contain("==") - end - - it "contains the actual label" do - value = 42 - label = "everything" - partial = new_partial(value, label) - matcher = Spectator::Matchers::EqualityMatcher.new(value) - match_data = matcher.match(partial) - match_data.negated_message.should contain(label) - end - - it "contains the expected label" do - value = 42 - label = "everything" - partial = new_partial(value) - matcher = Spectator::Matchers::EqualityMatcher.new(value, label) - match_data = matcher.match(partial) - match_data.negated_message.should contain(label) - end - - context "when expected label is omitted" do - it "contains stringified form of expected value" do - value1 = 42 - value2 = 777 - partial = new_partial(value1) - matcher = Spectator::Matchers::EqualityMatcher.new(value2) - match_data = matcher.match(partial) - match_data.negated_message.should contain(value2.to_s) - end - end - end - end - end -end diff --git a/spec/matchers/exception_matcher_spec.cr b/spec/matchers/exception_matcher_spec.cr deleted file mode 100644 index b5c31b4..0000000 --- a/spec/matchers/exception_matcher_spec.cr +++ /dev/null @@ -1,205 +0,0 @@ -require "../spec_helper" - -describe Spectator::Matchers::ExceptionMatcher do - describe "#match" do - it "compares the message using #===" do - spy = SpySUT.new - partial = new_block_partial { raise "foobar" } - matcher = Spectator::Matchers::ExceptionMatcher(Exception, SpySUT).new(spy, "foo") - matcher.match(partial) - spy.case_eq_call_count.should be > 0 - end - - context "returned MatchData" do - describe "#matched?" do - context "with no exception" do - it "is false" do - partial = new_block_partial { 42 } - matcher = Spectator::Matchers::ExceptionMatcher(Exception, Nil).new - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - - context "with an exception" do - context "of the same type" do - it "is true" do - partial = new_block_partial { raise ArgumentError.new } - matcher = Spectator::Matchers::ExceptionMatcher(ArgumentError, Nil).new - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - - context "of a different type" do - it "is false" do - partial = new_block_partial { raise ArgumentError.new } - matcher = Spectator::Matchers::ExceptionMatcher(KeyError, Nil).new - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - - context "of a sub-type" do - it "is true" do - partial = new_block_partial { raise ArgumentError.new } - matcher = Spectator::Matchers::ExceptionMatcher(Exception, Nil).new - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - - context "and an equal message" do - it "is true" do - message = "foobar" - partial = new_block_partial { raise ArgumentError.new(message) } - matcher = Spectator::Matchers::ExceptionMatcher(ArgumentError, String).new(message, "label") - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - - context "and a different message" do - it "is false" do - partial = new_block_partial { raise ArgumentError.new("foobar") } - matcher = Spectator::Matchers::ExceptionMatcher(ArgumentError, String).new("different", "label") - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - - context "and a matching regex" do - it "is true" do - partial = new_block_partial { raise ArgumentError.new("foobar") } - matcher = Spectator::Matchers::ExceptionMatcher(ArgumentError, Regex).new(/foo/, "label") - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - - context "and a non-matching regex" do - it "is false" do - partial = new_block_partial { raise ArgumentError.new("foobar") } - matcher = Spectator::Matchers::ExceptionMatcher(ArgumentError, Regex).new(/baz/, "label") - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - end - end - - describe "#values" do - describe "expected type" do - it "is the exception type" do - partial = new_block_partial { raise ArgumentError.new } - matcher = Spectator::Matchers::ExceptionMatcher(KeyError, Nil).new - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :"expected type")[:value].should eq(KeyError) - end - end - - describe "actual type" do - it "is the raised type" do - partial = new_block_partial { raise ArgumentError.new } - matcher = Spectator::Matchers::ExceptionMatcher(KeyError, Nil).new - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :"actual type")[:value].should eq(ArgumentError) - end - - context "when nothing is raised" do - it "is Nil" do - partial = new_block_partial { 42 } - matcher = Spectator::Matchers::ExceptionMatcher(KeyError, Nil).new - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :"actual type")[:value].should eq(Nil) - end - end - end - - describe "expected message" do - it "is the expected value" do - regex = /baz/ - partial = new_block_partial { raise ArgumentError.new("foobar") } - matcher = Spectator::Matchers::ExceptionMatcher(KeyError, Regex).new(regex, "label") - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :"expected message")[:value].should eq(regex) - end - end - - describe "actual message" do - it "is the raised exception's message" do - message = "foobar" - partial = new_block_partial { raise ArgumentError.new(message) } - matcher = Spectator::Matchers::ExceptionMatcher(KeyError, Regex).new(/baz/, "label") - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :"actual message")[:value].should eq(message) - end - end - end - - describe "#message" do - it "mentions raise" do - partial = new_block_partial { raise "foobar" } - matcher = Spectator::Matchers::ExceptionMatcher(Exception, Nil).new - match_data = matcher.match(partial) - match_data.message.should contain("raise") - end - - it "contains the actual label" do - label = "everything" - partial = new_block_partial(label) { raise "foobar" } - matcher = Spectator::Matchers::ExceptionMatcher(Exception, Nil).new - match_data = matcher.match(partial) - match_data.message.should contain(label) - end - - it "contains the expected label" do - label = "everything" - partial = new_block_partial { raise "foobar" } - matcher = Spectator::Matchers::ExceptionMatcher(Exception, Regex).new(/foobar/, label) - match_data = matcher.match(partial) - match_data.message.should contain(label) - end - - it "contains the exception type" do - partial = new_block_partial { raise "foobar" } - matcher = Spectator::Matchers::ExceptionMatcher(ArgumentError, Nil).new - match_data = matcher.match(partial) - match_data.message.should contain("ArgumentError") - end - end - - describe "#negated_message" do - it "mentions raise" do - partial = new_block_partial { raise "foobar" } - matcher = Spectator::Matchers::ExceptionMatcher(Exception, Nil).new - match_data = matcher.match(partial) - match_data.negated_message.should contain("raise") - end - - it "contains the actual label" do - label = "everything" - partial = new_block_partial(label) { raise "foobar" } - matcher = Spectator::Matchers::ExceptionMatcher(Exception, Nil).new - match_data = matcher.match(partial) - match_data.negated_message.should contain(label) - end - - it "contains the expected label" do - label = "everything" - partial = new_block_partial { raise "foobar" } - matcher = Spectator::Matchers::ExceptionMatcher(Exception, Regex).new(/foobar/, label) - match_data = matcher.match(partial) - match_data.negated_message.should contain(label) - end - - it "contains the exception type" do - partial = new_block_partial { raise "foobar" } - matcher = Spectator::Matchers::ExceptionMatcher(ArgumentError, Nil).new - match_data = matcher.match(partial) - match_data.negated_message.should contain("ArgumentError") - end - end - end - end -end diff --git a/spec/matchers/greater_than_equal_matcher_spec.cr b/spec/matchers/greater_than_equal_matcher_spec.cr deleted file mode 100644 index c76641d..0000000 --- a/spec/matchers/greater_than_equal_matcher_spec.cr +++ /dev/null @@ -1,160 +0,0 @@ -require "../spec_helper" - -describe Spectator::Matchers::GreaterThanEqualMatcher do - describe "#match" do - it "compares using #>=" do - spy = SpySUT.new - partial = new_partial(spy) - matcher = Spectator::Matchers::GreaterThanEqualMatcher.new(42) - matcher.match(partial) - spy.ge_call_count.should be > 0 - end - - context "returned MatchData" do - describe "#matched?" do - context "with a larger value" do - it "is false" do - actual = 42 - expected = 777 - partial = new_partial(actual) - matcher = Spectator::Matchers::GreaterThanEqualMatcher.new(expected) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - - context "with a smaller value" do - it "is true" do - actual = 777 - expected = 42 - partial = new_partial(actual) - matcher = Spectator::Matchers::GreaterThanEqualMatcher.new(expected) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - - context "with an equal value" do - it "is true" do - value = 42 - partial = new_partial(value) - matcher = Spectator::Matchers::GreaterThanEqualMatcher.new(value) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - end - - describe "#values" do - context "expected" do - it "is the expected value" do - actual = 777 - expected = 42 - partial = new_partial(actual) - matcher = Spectator::Matchers::GreaterThanEqualMatcher.new(expected) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :expected)[:value].should eq(expected) - end - - it "is prefixed with >=" do - actual = 777 - expected = 42 - partial = new_partial(actual) - matcher = Spectator::Matchers::GreaterThanEqualMatcher.new(expected) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :expected)[:to_s].should start_with(">=") - end - end - - context "actual" do - it "is the actual value" do - actual = 777 - expected = 42 - partial = new_partial(actual) - matcher = Spectator::Matchers::GreaterThanEqualMatcher.new(expected) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :actual)[:value].should eq(actual) - end - end - end - - describe "#message" do - it "mentions >=" do - value = 42 - partial = new_partial(value) - matcher = Spectator::Matchers::GreaterThanEqualMatcher.new(value) - match_data = matcher.match(partial) - match_data.message.should contain(">=") - end - - it "contains the actual label" do - value = 42 - label = "everything" - partial = new_partial(value, label) - matcher = Spectator::Matchers::GreaterThanEqualMatcher.new(value) - match_data = matcher.match(partial) - match_data.message.should contain(label) - end - - it "contains the expected label" do - value = 42 - label = "everything" - partial = new_partial(value) - matcher = Spectator::Matchers::GreaterThanEqualMatcher.new(value, label) - match_data = matcher.match(partial) - match_data.message.should contain(label) - end - - context "when expected label is omitted" do - it "contains stringified form of expected value" do - value1 = 42 - value2 = 777 - partial = new_partial(value1) - matcher = Spectator::Matchers::GreaterThanEqualMatcher.new(value2) - match_data = matcher.match(partial) - match_data.message.should contain(value2.to_s) - end - end - end - - describe "#negated_message" do - it "mentions >=" do - value = 42 - partial = new_partial(value) - matcher = Spectator::Matchers::GreaterThanEqualMatcher.new(value) - match_data = matcher.match(partial) - match_data.negated_message.should contain(">=") - end - - it "contains the actual label" do - value = 42 - label = "everything" - partial = new_partial(value, label) - matcher = Spectator::Matchers::GreaterThanEqualMatcher.new(value) - match_data = matcher.match(partial) - match_data.negated_message.should contain(label) - end - - it "contains the expected label" do - value = 42 - label = "everything" - partial = new_partial(value) - matcher = Spectator::Matchers::GreaterThanEqualMatcher.new(value, label) - match_data = matcher.match(partial) - match_data.negated_message.should contain(label) - end - - context "when expected label is omitted" do - it "contains stringified form of expected value" do - value1 = 42 - value2 = 777 - partial = new_partial(value1) - matcher = Spectator::Matchers::GreaterThanEqualMatcher.new(value2) - match_data = matcher.match(partial) - match_data.negated_message.should contain(value2.to_s) - end - end - end - end - end -end diff --git a/spec/matchers/greater_than_matcher_spec.cr b/spec/matchers/greater_than_matcher_spec.cr deleted file mode 100644 index 1375cff..0000000 --- a/spec/matchers/greater_than_matcher_spec.cr +++ /dev/null @@ -1,160 +0,0 @@ -require "../spec_helper" - -describe Spectator::Matchers::GreaterThanMatcher do - describe "#match" do - it "compares using #>" do - spy = SpySUT.new - partial = new_partial(spy) - matcher = Spectator::Matchers::GreaterThanMatcher.new(42) - matcher.match(partial) - spy.gt_call_count.should be > 0 - end - - context "returned MatchData" do - describe "#matched?" do - context "with a larger value" do - it "is false" do - actual = 42 - expected = 777 - partial = new_partial(actual) - matcher = Spectator::Matchers::GreaterThanMatcher.new(expected) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - - context "with a smaller value" do - it "is true" do - actual = 777 - expected = 42 - partial = new_partial(actual) - matcher = Spectator::Matchers::GreaterThanMatcher.new(expected) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - - context "with an equal value" do - it "is false" do - value = 42 - partial = new_partial(value) - matcher = Spectator::Matchers::GreaterThanMatcher.new(value) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - end - - describe "#values" do - context "expected" do - it "is the expected value" do - actual = 777 - expected = 42 - partial = new_partial(actual) - matcher = Spectator::Matchers::GreaterThanMatcher.new(expected) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :expected)[:value].should eq(expected) - end - - it "is prefixed with >" do - actual = 777 - expected = 42 - partial = new_partial(actual) - matcher = Spectator::Matchers::GreaterThanMatcher.new(expected) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :expected)[:to_s].should start_with(">") - end - end - - context "actual" do - it "is the actual value" do - actual = 777 - expected = 42 - partial = new_partial(actual) - matcher = Spectator::Matchers::GreaterThanMatcher.new(expected) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :actual)[:value].should eq(actual) - end - end - end - - describe "#message" do - it "mentions >" do - value = 42 - partial = new_partial(value) - matcher = Spectator::Matchers::GreaterThanMatcher.new(value) - match_data = matcher.match(partial) - match_data.message.should contain(">") - end - - it "contains the actual label" do - value = 42 - label = "everything" - partial = new_partial(value, label) - matcher = Spectator::Matchers::GreaterThanMatcher.new(value) - match_data = matcher.match(partial) - match_data.message.should contain(label) - end - - it "contains the expected label" do - value = 42 - label = "everything" - partial = new_partial(value) - matcher = Spectator::Matchers::GreaterThanMatcher.new(value, label) - match_data = matcher.match(partial) - match_data.message.should contain(label) - end - - context "when expected label is omitted" do - it "contains stringified form of expected value" do - value1 = 42 - value2 = 777 - partial = new_partial(value1) - matcher = Spectator::Matchers::GreaterThanMatcher.new(value2) - match_data = matcher.match(partial) - match_data.message.should contain(value2.to_s) - end - end - end - - describe "#negated_message" do - it "mentions >" do - value = 42 - partial = new_partial(value) - matcher = Spectator::Matchers::GreaterThanMatcher.new(value) - match_data = matcher.match(partial) - match_data.negated_message.should contain(">") - end - - it "contains the actual label" do - value = 42 - label = "everything" - partial = new_partial(value, label) - matcher = Spectator::Matchers::GreaterThanMatcher.new(value) - match_data = matcher.match(partial) - match_data.negated_message.should contain(label) - end - - it "contains the expected label" do - value = 42 - label = "everything" - partial = new_partial(value) - matcher = Spectator::Matchers::GreaterThanMatcher.new(value, label) - match_data = matcher.match(partial) - match_data.negated_message.should contain(label) - end - - context "when expected label is omitted" do - it "contains stringified form of expected value" do - value1 = 42 - value2 = 777 - partial = new_partial(value1) - matcher = Spectator::Matchers::GreaterThanMatcher.new(value2) - match_data = matcher.match(partial) - match_data.negated_message.should contain(value2.to_s) - end - end - end - end - end -end diff --git a/spec/matchers/have_key_matcher_spec.cr b/spec/matchers/have_key_matcher_spec.cr deleted file mode 100644 index cbcf6f6..0000000 --- a/spec/matchers/have_key_matcher_spec.cr +++ /dev/null @@ -1,166 +0,0 @@ -require "../spec_helper" - -private struct FakeKeySet - def has_key?(key) - true - end -end - -describe Spectator::Matchers::HaveKeyMatcher do - describe "#match" do - context "returned MatchData" do - describe "#matched?" do - context "against a Hash" do - context "with an existing key" do - it "is true" do - hash = Hash{"foo" => "bar"} - key = "foo" - partial = new_partial(hash) - matcher = Spectator::Matchers::HaveKeyMatcher.new(key) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - - context "with a non-existent key" do - it "is false" do - hash = Hash{"foo" => "bar"} - key = "baz" - partial = new_partial(hash) - matcher = Spectator::Matchers::HaveKeyMatcher.new(key) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - end - - context "against a NamedTuple" do - context "with an existing key" do - it "is true" do - tuple = {foo: "bar"} - key = :foo - partial = new_partial(tuple) - matcher = Spectator::Matchers::HaveKeyMatcher.new(key) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - - context "with a non-existent key" do - it "is false" do - tuple = {foo: "bar"} - key = :baz - partial = new_partial(tuple) - matcher = Spectator::Matchers::HaveKeyMatcher.new(key) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - end - end - - describe "#values" do - context "key" do - it "is the expected key" do - tuple = {foo: "bar"} - key = :baz - partial = new_partial(tuple) - matcher = Spectator::Matchers::HaveKeyMatcher.new(key) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :key)[:value].should eq(key) - end - end - - context "actual" do - context "when #keys is available" do - it "is the list of keys" do - tuple = {foo: "bar"} - key = :baz - partial = new_partial(tuple) - matcher = Spectator::Matchers::HaveKeyMatcher.new(key) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :actual)[:value].should eq(tuple.keys) - end - end - - context "when #keys isn't available" do - it "is the actual value" do - actual = FakeKeySet.new - key = :baz - partial = new_partial(actual) - matcher = Spectator::Matchers::HaveKeyMatcher.new(key) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :actual)[:value].should eq(actual) - end - end - end - end - - describe "#message" do - it "contains the actual label" do - tuple = {foo: "bar"} - key = :foo - label = "blah" - partial = new_partial(tuple, label) - matcher = Spectator::Matchers::HaveKeyMatcher.new(key) - match_data = matcher.match(partial) - match_data.message.should contain(label) - end - - it "contains the expected label" do - tuple = {foo: "bar"} - key = :foo - label = "blah" - partial = new_partial(tuple) - matcher = Spectator::Matchers::HaveKeyMatcher.new(key, label) - match_data = matcher.match(partial) - match_data.message.should contain(label) - end - - context "when the expected label is omitted" do - it "contains the stringified key" do - tuple = {foo: "bar"} - key = :foo - partial = new_partial(tuple) - matcher = Spectator::Matchers::HaveKeyMatcher.new(key) - match_data = matcher.match(partial) - match_data.message.should contain(key.to_s) - end - end - end - - describe "#negated_message" do - it "contains the actual label" do - tuple = {foo: "bar"} - key = :foo - label = "blah" - partial = new_partial(tuple, label) - matcher = Spectator::Matchers::HaveKeyMatcher.new(key) - match_data = matcher.match(partial) - match_data.negated_message.should contain(label) - end - - it "contains the expected label" do - tuple = {foo: "bar"} - key = :foo - label = "blah" - partial = new_partial(tuple) - matcher = Spectator::Matchers::HaveKeyMatcher.new(key, label) - match_data = matcher.match(partial) - match_data.negated_message.should contain(label) - end - - context "when the expected label is omitted" do - it "contains the stringified key" do - tuple = {foo: "bar"} - key = :foo - partial = new_partial(tuple) - matcher = Spectator::Matchers::HaveKeyMatcher.new(key) - match_data = matcher.match(partial) - match_data.negated_message.should contain(key.to_s) - end - end - end - end - end -end diff --git a/spec/matchers/have_matcher_spec.cr b/spec/matchers/have_matcher_spec.cr deleted file mode 100644 index f4e917f..0000000 --- a/spec/matchers/have_matcher_spec.cr +++ /dev/null @@ -1,604 +0,0 @@ -require "../spec_helper" - -describe Spectator::Matchers::HaveMatcher do - describe "#match" do - it "uses ===" do - array = %i[a b c] - spy = SpySUT.new - partial = new_partial(array) - matcher = Spectator::Matchers::HaveMatcher.new({spy}) - matcher.match(partial) - spy.case_eq_call_count.should be > 0 - end - - context "returned MatchData" do - describe "#matched?" do - context "with a String" do - context "one argument" do - context "against a matching string" do - it "is true" do - value = "foobarbaz" - search = "bar" - partial = new_partial(value) - matcher = Spectator::Matchers::HaveMatcher.new({search}) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - - context "at the beginning" do - it "is true" do - value = "foobar" - search = "foo" - partial = new_partial(value) - matcher = Spectator::Matchers::HaveMatcher.new({search}) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - - context "at the end" do - it "is true" do - value = "foobar" - search = "bar" - partial = new_partial(value) - matcher = Spectator::Matchers::HaveMatcher.new({search}) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - end - - context "against a different string" do - it "is false" do - value = "foobar" - search = "baz" - partial = new_partial(value) - matcher = Spectator::Matchers::HaveMatcher.new({search}) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - - context "against a matching character" do - it "is true" do - value = "foobar" - search = 'o' - partial = new_partial(value) - matcher = Spectator::Matchers::HaveMatcher.new({search}) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - - context "at the beginning" do - it "is true" do - value = "foobar" - search = 'f' - partial = new_partial(value) - matcher = Spectator::Matchers::HaveMatcher.new({search}) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - - context "at the end" do - it "is true" do - value = "foobar" - search = 'r' - partial = new_partial(value) - matcher = Spectator::Matchers::HaveMatcher.new({search}) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - end - - context "against a different character" do - it "is false" do - value = "foobar" - search = 'z' - partial = new_partial(value) - matcher = Spectator::Matchers::HaveMatcher.new({search}) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - end - - context "multiple arguments" do - context "against matching strings" do - it "is true" do - value = "foobarbaz" - search = {"foo", "bar", "baz"} - partial = new_partial(value) - matcher = Spectator::Matchers::HaveMatcher.new(search) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - - context "against one matching string" do - it "is false" do - value = "foobarbaz" - search = {"foo", "qux"} - partial = new_partial(value) - matcher = Spectator::Matchers::HaveMatcher.new(search) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - - context "against no matching strings" do - it "is false" do - value = "foobar" - search = {"baz", "qux"} - partial = new_partial(value) - matcher = Spectator::Matchers::HaveMatcher.new(search) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - - context "against matching characters" do - it "is true" do - value = "foobarbaz" - search = {'f', 'b', 'z'} - partial = new_partial(value) - matcher = Spectator::Matchers::HaveMatcher.new(search) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - - context "against one matching character" do - it "is false" do - value = "foobarbaz" - search = {'f', 'c', 'd'} - partial = new_partial(value) - matcher = Spectator::Matchers::HaveMatcher.new(search) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - - context "against no matching characters" do - it "is false" do - value = "foobarbaz" - search = {'c', 'd', 'e'} - partial = new_partial(value) - matcher = Spectator::Matchers::HaveMatcher.new(search) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - - context "against a matching string and character" do - it "is true" do - value = "foobarbaz" - search = {"foo", 'z'} - partial = new_partial(value) - matcher = Spectator::Matchers::HaveMatcher.new(search) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - - context "against a matching string and non-matching character" do - it "is false" do - value = "foobarbaz" - search = {"foo", 'c'} - partial = new_partial(value) - matcher = Spectator::Matchers::HaveMatcher.new(search) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - - context "against a non-matching string and matching character" do - it "is false" do - value = "foobarbaz" - search = {"qux", 'f'} - partial = new_partial(value) - matcher = Spectator::Matchers::HaveMatcher.new(search) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - - context "against a non-matching string and character" do - it "is false" do - value = "foobarbaz" - search = {"qux", 'c'} - partial = new_partial(value) - matcher = Spectator::Matchers::HaveMatcher.new(search) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - end - end - - context "with an Enumberable" do - context "one argument" do - context "against an equal value" do - it "is true" do - array = %i[a b c] - search = :b - partial = new_partial(array) - matcher = Spectator::Matchers::HaveMatcher.new({search}) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - - context "at the beginning" do - it "is true" do - array = %i[a b c] - search = :a - partial = new_partial(array) - matcher = Spectator::Matchers::HaveMatcher.new({search}) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - - context "at the end" do - it "is true" do - array = %i[a b c] - search = :c - partial = new_partial(array) - matcher = Spectator::Matchers::HaveMatcher.new({search}) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - end - - context "against a different value" do - it "is false" do - array = %i[a b c] - search = :z - partial = new_partial(array) - matcher = Spectator::Matchers::HaveMatcher.new({search}) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - - context "against a matching type" do - it "is true" do - array = %i[a b c] - partial = new_partial(array) - matcher = Spectator::Matchers::HaveMatcher.new({Symbol}) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - - context "at the beginning" do - it "is true" do - array = [:a, 1, 2] - partial = new_partial(array) - matcher = Spectator::Matchers::HaveMatcher.new({Symbol}) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - - context "at the end" do - it "is true" do - array = [0, 1, :c] - partial = new_partial(array) - matcher = Spectator::Matchers::HaveMatcher.new({Symbol}) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - end - - context "against a non-matching type" do - it "is false" do - array = %i[a b c] - partial = new_partial(array) - matcher = Spectator::Matchers::HaveMatcher.new({Int32}) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - - context "against a matching regex" do - it "is true" do - array = %w[FOO BAR BAZ] - search = /bar/i - partial = new_partial(array) - matcher = Spectator::Matchers::HaveMatcher.new({search}) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - - context "at the beginning" do - it "is true" do - array = %w[FOO BAR BAZ] - search = /foo/i - partial = new_partial(array) - matcher = Spectator::Matchers::HaveMatcher.new({search}) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - - context "at the end" do - it "is true" do - array = %w[FOO BAR BAZ] - search = /baz/i - partial = new_partial(array) - matcher = Spectator::Matchers::HaveMatcher.new({search}) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - end - - context "against a non-matching regex" do - it "is false" do - array = %w[FOO BAR BAZ] - search = /qux/i - partial = new_partial(array) - matcher = Spectator::Matchers::HaveMatcher.new({search}) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - end - - context "multiple arguments" do - context "against equal values" do - it "is true" do - array = %i[a b c] - search = {:a, :b} - partial = new_partial(array) - matcher = Spectator::Matchers::HaveMatcher.new(search) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - - context "matching type" do - context "matching regex" do - it "is true" do - array = [:a, 42, "FOO"] - search = {:a, Int32, /foo/i} - partial = new_partial(array) - matcher = Spectator::Matchers::HaveMatcher.new(search) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - - context "non-matching regex" do - it "is false" do - array = [:a, 42, "FOO"] - search = {:a, Int32, /bar/i} - partial = new_partial(array) - matcher = Spectator::Matchers::HaveMatcher.new(search) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - end - - context "non-matching type" do - context "matching regex" do - it "is false" do - array = [:a, 42, "FOO"] - search = {:a, Float32, /foo/i} - partial = new_partial(array) - matcher = Spectator::Matchers::HaveMatcher.new(search) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - - context "non-matching regex" do - it "is false" do - array = [:a, 42, "FOO"] - search = {:a, Float32, /bar/i} - partial = new_partial(array) - matcher = Spectator::Matchers::HaveMatcher.new(search) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - end - end - - context "against one equal value" do - it "is false" do - array = %i[a b c] - search = {:a, :d} - partial = new_partial(array) - matcher = Spectator::Matchers::HaveMatcher.new(search) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - - context "against no equal values" do - it "is false" do - array = %i[a b c] - search = {:d, :e} - partial = new_partial(array) - matcher = Spectator::Matchers::HaveMatcher.new(search) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - - context "against matching types" do - it "is true" do - array = [:a, 42, "FOO"] - search = {Symbol, String} - partial = new_partial(array) - matcher = Spectator::Matchers::HaveMatcher.new(search) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - - context "against one matching type" do - it "is false" do - array = [:a, 42, "FOO"] - search = {Symbol, Float32} - partial = new_partial(array) - matcher = Spectator::Matchers::HaveMatcher.new(search) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - - context "against no matching types" do - it "is false" do - array = [:a, 42, "FOO"] - search = {Float32, Bytes} - partial = new_partial(array) - matcher = Spectator::Matchers::HaveMatcher.new(search) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - - context "against matching regexes" do - it "is true" do - array = %w[FOO BAR BAZ] - search = {/foo/i, /bar/i} - partial = new_partial(array) - matcher = Spectator::Matchers::HaveMatcher.new(search) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - - context "against one matching regex" do - it "is false" do - array = %w[FOO BAR BAZ] - search = {/foo/i, /qux/i} - partial = new_partial(array) - matcher = Spectator::Matchers::HaveMatcher.new(search) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - - context "against no matching regexes" do - it "is false" do - array = %w[FOO BAR] - search = {/baz/i, /qux/i} - partial = new_partial(array) - matcher = Spectator::Matchers::HaveMatcher.new(search) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - - context "against equal and matching type and regex" do - it "is true" do - array = [:a, 42, "FOO"] - search = {:a, Int32, /foo/i} - partial = new_partial(array) - matcher = Spectator::Matchers::HaveMatcher.new(search) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - end - end - end - - describe "#values" do - context "subset" do - it "has the expected value" do - array = [:a, 42, "FOO"] - search = {:a, Int32, /foo/i} - partial = new_partial(array) - matcher = Spectator::Matchers::HaveMatcher.new(search) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :subset)[:value].should eq(search) - end - end - - context "superset" do - it "has the actual value" do - array = [:a, 42, "FOO"] - search = {:a, Int32, /foo/i} - partial = new_partial(array) - matcher = Spectator::Matchers::HaveMatcher.new(search) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :superset)[:value].should eq(array) - end - end - end - - describe "#message" do - it "contains the actual label" do - value = "foobar" - search = "baz" - label = "everything" - partial = new_partial(value, label) - matcher = Spectator::Matchers::HaveMatcher.new({search}) - match_data = matcher.match(partial) - match_data.message.should contain(label) - end - - it "contains the expected label" do - value = "foobar" - search = "baz" - label = "everything" - partial = new_partial(value) - matcher = Spectator::Matchers::HaveMatcher.new({search}, label) - match_data = matcher.match(partial) - match_data.message.should contain(label) - end - - context "when expected label is omitted" do - it "contains stringified form of expected value" do - value = "foobar" - search = "baz" - partial = new_partial(value) - matcher = Spectator::Matchers::HaveMatcher.new({search}) - match_data = matcher.match(partial) - match_data.message.should contain(search) - end - end - end - - describe "#negated_message" do - it "contains the actual label" do - value = "foobar" - search = "baz" - label = "everything" - partial = new_partial(value, label) - matcher = Spectator::Matchers::HaveMatcher.new({search}) - match_data = matcher.match(partial) - match_data.negated_message.should contain(label) - end - - it "contains the expected label" do - value = "foobar" - search = "baz" - label = "everything" - partial = new_partial(value) - matcher = Spectator::Matchers::HaveMatcher.new({search}, label) - match_data = matcher.match(partial) - match_data.negated_message.should contain(label) - end - - context "when expected label is omitted" do - it "contains stringified form of expected value" do - value = "foobar" - search = "baz" - partial = new_partial(value) - matcher = Spectator::Matchers::HaveMatcher.new({search}) - match_data = matcher.match(partial) - match_data.negated_message.should contain(search) - end - end - end - end - end -end diff --git a/spec/matchers/have_predicate_matcher_spec.cr b/spec/matchers/have_predicate_matcher_spec.cr deleted file mode 100644 index 5b49382..0000000 --- a/spec/matchers/have_predicate_matcher_spec.cr +++ /dev/null @@ -1,87 +0,0 @@ -require "../spec_helper" - -describe Spectator::Matchers::HavePredicateMatcher do - describe "#match" do - context "returned MatchData" do - describe "#match?" do - context "with a true predicate" do - it "is true" do - value = "foo\\bar" - partial = new_partial(value) - matcher = Spectator::Matchers::HavePredicateMatcher.new({back_references: Tuple.new}, "back_references") - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - - context "with a false predicate" do - it "is false" do - value = "foobar" - partial = new_partial(value) - matcher = Spectator::Matchers::HavePredicateMatcher.new({back_references: Tuple.new}, "back_references") - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - end - - describe "#values" do - it "contains a key for each expected attribute" do - value = "foobar" - partial = new_partial(value) - matcher = Spectator::Matchers::HavePredicateMatcher.new({back_references: Tuple.new}, "back_references") - match_data = matcher.match(partial) - match_data_has_key?(match_data.values, :back_references).should be_true - end - - it "has the actual values" do - value = "foobar" - partial = new_partial(value) - matcher = Spectator::Matchers::HavePredicateMatcher.new({back_references: Tuple.new}, "back_references") - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :back_references)[:value].should eq(value.has_back_references?) - end - end - - describe "#message" do - it "contains the actual label" do - value = "foobar" - label = "blah" - partial = new_partial(value, label) - matcher = Spectator::Matchers::HavePredicateMatcher.new({back_references: Tuple.new}, "back_references") - match_data = matcher.match(partial) - match_data.message.should contain(label) - end - - it "contains the expected label" do - value = "foobar" - label = "blah" - partial = new_partial(value) - matcher = Spectator::Matchers::HavePredicateMatcher.new({back_references: Tuple.new}, label) - match_data = matcher.match(partial) - match_data.message.should contain(label) - end - end - - describe "#negated_message" do - it "contains the actual label" do - value = "foobar" - label = "blah" - partial = new_partial(value, label) - matcher = Spectator::Matchers::HavePredicateMatcher.new({back_references: Tuple.new}, "back_references") - match_data = matcher.match(partial) - match_data.negated_message.should contain(label) - end - - it "contains the expected label" do - value = "foobar" - label = "blah" - partial = new_partial(value) - matcher = Spectator::Matchers::HavePredicateMatcher.new({back_references: Tuple.new}, label) - match_data = matcher.match(partial) - match_data.negated_message.should contain(label) - end - end - end - end -end diff --git a/spec/matchers/have_value_matcher_spec.cr b/spec/matchers/have_value_matcher_spec.cr deleted file mode 100644 index 78ba281..0000000 --- a/spec/matchers/have_value_matcher_spec.cr +++ /dev/null @@ -1,140 +0,0 @@ -require "../spec_helper" - -private struct FakeValueSet - def has_value?(value) - true - end -end - -describe Spectator::Matchers::HaveValueMatcher do - describe "#match" do - context "returned MatchData" do - describe "#matched?" do - context "with an existing value" do - it "is true" do - hash = Hash{"foo" => "bar"} - value = "bar" - partial = new_partial(hash) - matcher = Spectator::Matchers::HaveValueMatcher.new(value) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - - context "with a non-existent value" do - it "is false" do - hash = Hash{"foo" => "bar"} - value = "baz" - partial = new_partial(hash) - matcher = Spectator::Matchers::HaveValueMatcher.new(value) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - end - - describe "#values" do - context "value" do - it "is the expected value" do - hash = {"foo" => "bar"} - value = "baz" - partial = new_partial(hash) - matcher = Spectator::Matchers::HaveValueMatcher.new(value) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :value)[:value].should eq(value) - end - end - - context "actual" do - context "when #values is available" do - it "is the list of values" do - hash = Hash{"foo" => "bar"} - value = "baz" - partial = new_partial(hash) - matcher = Spectator::Matchers::HaveValueMatcher.new(value) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :actual)[:value].should eq(hash.values) - end - end - - context "when #values isn't available" do - it "is the actual value" do - actual = FakeValueSet.new - value = "baz" - partial = new_partial(actual) - matcher = Spectator::Matchers::HaveValueMatcher.new(value) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :actual)[:value].should eq(actual) - end - end - end - end - - describe "#message" do - it "contains the actual label" do - hash = Hash{"foo" => "bar"} - value = "bar" - label = "blah" - partial = new_partial(hash, label) - matcher = Spectator::Matchers::HaveValueMatcher.new(value) - match_data = matcher.match(partial) - match_data.message.should contain(label) - end - - it "contains the expected label" do - hash = Hash{"foo" => "bar"} - value = "bar" - label = "blah" - partial = new_partial(hash) - matcher = Spectator::Matchers::HaveValueMatcher.new(value, label) - match_data = matcher.match(partial) - match_data.message.should contain(label) - end - - context "when the expected label is omitted" do - it "contains the stringified key" do - hash = Hash{"foo" => "bar"} - value = "bar" - partial = new_partial(hash) - matcher = Spectator::Matchers::HaveValueMatcher.new(value) - match_data = matcher.match(partial) - match_data.message.should contain(value.to_s) - end - end - end - - describe "#negated_message" do - it "contains the actual label" do - hash = Hash{"foo" => "bar"} - value = "bar" - label = "blah" - partial = new_partial(hash, label) - matcher = Spectator::Matchers::HaveValueMatcher.new(value) - match_data = matcher.match(partial) - match_data.negated_message.should contain(label) - end - - it "contains the expected label" do - hash = Hash{"foo" => "bar"} - value = "bar" - label = "blah" - partial = new_partial(hash) - matcher = Spectator::Matchers::HaveValueMatcher.new(value, label) - match_data = matcher.match(partial) - match_data.negated_message.should contain(label) - end - - context "when the expected label is omitted" do - it "contains the stringified key" do - hash = Hash{"foo" => "bar"} - value = "bar" - partial = new_partial(hash) - matcher = Spectator::Matchers::HaveValueMatcher.new(value) - match_data = matcher.match(partial) - match_data.negated_message.should contain(value.to_s) - end - end - end - end - end -end diff --git a/spec/matchers/inequality_matcher_spec.cr b/spec/matchers/inequality_matcher_spec.cr deleted file mode 100644 index 1dcdcfc..0000000 --- a/spec/matchers/inequality_matcher_spec.cr +++ /dev/null @@ -1,181 +0,0 @@ -require "../spec_helper" - -describe Spectator::Matchers::InequalityMatcher do - describe "#match" do - it "compares using #!=" do - spy = SpySUT.new - partial = new_partial(spy) - matcher = Spectator::Matchers::InequalityMatcher.new(42) - matcher.match(partial) - spy.ne_call_count.should be > 0 - end - - context "returned MatchData" do - describe "#matched?" do - context "with identical values" do - it "is false" do - value = 42 - partial = new_partial(value) - matcher = Spectator::Matchers::InequalityMatcher.new(value) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - - context "with different values" do - it "is true" do - value1 = 42 - value2 = 777 - partial = new_partial(value1) - matcher = Spectator::Matchers::InequalityMatcher.new(value2) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - - context "with the same instance" do - it "is false" do - # Box is used because it is a reference type and doesn't override the == method. - ref = Box.new([] of Int32) - partial = new_partial(ref) - matcher = Spectator::Matchers::InequalityMatcher.new(ref) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - - context "with different instances" do - context "with same contents" do - it "is false" do - array1 = [1, 2, 3] - array2 = [1, 2, 3] - partial = new_partial(array1) - matcher = Spectator::Matchers::InequalityMatcher.new(array2) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - - context "with different contents" do - it "is true" do - array1 = [1, 2, 3] - array2 = [4, 5, 6] - partial = new_partial(array1) - matcher = Spectator::Matchers::InequalityMatcher.new(array2) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - end - end - - describe "#values" do - context "expected" do - it "is the expected value" do - expected, actual = 42, 777 - partial = new_partial(actual) - matcher = Spectator::Matchers::InequalityMatcher.new(expected) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :expected)[:value].should eq(expected) - end - - it "is prefixed with 'Not'" do - expected, actual = 42, 777 - partial = new_partial(actual) - matcher = Spectator::Matchers::InequalityMatcher.new(expected) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :expected)[:to_s].should start_with("Not") - end - end - - context "actual" do - it "is the actual value" do - expected, actual = 42, 777 - partial = new_partial(actual) - matcher = Spectator::Matchers::InequalityMatcher.new(expected) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :actual)[:value].should eq(actual) - end - end - end - - describe "#message" do - it "mentions !=" do - value = 42 - partial = new_partial(value) - matcher = Spectator::Matchers::InequalityMatcher.new(value) - match_data = matcher.match(partial) - match_data.message.should contain("!=") - end - - it "contains the actual label" do - value = 42 - label = "everything" - partial = new_partial(value, label) - matcher = Spectator::Matchers::InequalityMatcher.new(value) - match_data = matcher.match(partial) - match_data.message.should contain(label) - end - - it "contains the expected label" do - value = 42 - label = "everything" - partial = new_partial(value) - matcher = Spectator::Matchers::InequalityMatcher.new(value, label) - match_data = matcher.match(partial) - match_data.message.should contain(label) - end - - context "when expected label is omitted" do - it "contains stringified form of expected value" do - value1 = 42 - value2 = 777 - partial = new_partial(value1) - matcher = Spectator::Matchers::InequalityMatcher.new(value2) - match_data = matcher.match(partial) - match_data.message.should contain(value2.to_s) - end - end - end - - describe "#negated_message" do - it "mentions !=" do - value = 42 - partial = new_partial(value) - matcher = Spectator::Matchers::InequalityMatcher.new(value) - match_data = matcher.match(partial) - match_data.negated_message.should contain("!=") - end - - it "contains the actual label" do - value = 42 - label = "everything" - partial = new_partial(value, label) - matcher = Spectator::Matchers::InequalityMatcher.new(value) - match_data = matcher.match(partial) - match_data.negated_message.should contain(label) - end - - it "contains the expected label" do - value = 42 - label = "everything" - partial = new_partial(value) - matcher = Spectator::Matchers::InequalityMatcher.new(value, label) - match_data = matcher.match(partial) - match_data.negated_message.should contain(label) - end - - context "when expected label is omitted" do - it "contains stringified form of expected value" do - value1 = 42 - value2 = 777 - partial = new_partial(value1) - matcher = Spectator::Matchers::InequalityMatcher.new(value2) - match_data = matcher.match(partial) - match_data.negated_message.should contain(value2.to_s) - end - end - end - end - end -end diff --git a/spec/matchers/less_than_equal_matcher_spec.cr b/spec/matchers/less_than_equal_matcher_spec.cr deleted file mode 100644 index 75d648f..0000000 --- a/spec/matchers/less_than_equal_matcher_spec.cr +++ /dev/null @@ -1,160 +0,0 @@ -require "../spec_helper" - -describe Spectator::Matchers::LessThanEqualMatcher do - describe "#match" do - it "compares using #<=" do - spy = SpySUT.new - partial = new_partial(spy) - matcher = Spectator::Matchers::LessThanEqualMatcher.new(42) - matcher.match(partial) - spy.le_call_count.should be > 0 - end - - context "returned MatchData" do - describe "#matched?" do - context "with a larger value" do - it "is true" do - actual = 42 - expected = 777 - partial = new_partial(actual) - matcher = Spectator::Matchers::LessThanEqualMatcher.new(expected) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - - context "with a smaller value" do - it "is false" do - actual = 777 - expected = 42 - partial = new_partial(actual) - matcher = Spectator::Matchers::LessThanEqualMatcher.new(expected) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - - context "with an equal value" do - it "is true" do - value = 42 - partial = new_partial(value) - matcher = Spectator::Matchers::LessThanEqualMatcher.new(value) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - end - - describe "#values" do - context "expected" do - it "is the expected value" do - actual = 42 - expected = 777 - partial = new_partial(actual) - matcher = Spectator::Matchers::LessThanEqualMatcher.new(expected) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :expected)[:value].should eq(expected) - end - - it "is prefixed with <=" do - actual = 42 - expected = 777 - partial = new_partial(actual) - matcher = Spectator::Matchers::LessThanEqualMatcher.new(expected) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :expected)[:to_s].should start_with("<=") - end - end - - context "actual" do - it "is the actual value" do - actual = 42 - expected = 777 - partial = new_partial(actual) - matcher = Spectator::Matchers::LessThanEqualMatcher.new(expected) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :actual)[:value].should eq(actual) - end - end - end - - describe "#message" do - it "mentions <=" do - value = 42 - partial = new_partial(value) - matcher = Spectator::Matchers::LessThanEqualMatcher.new(value) - match_data = matcher.match(partial) - match_data.message.should contain("<=") - end - - it "contains the actual label" do - value = 42 - label = "everything" - partial = new_partial(value, label) - matcher = Spectator::Matchers::LessThanEqualMatcher.new(value) - match_data = matcher.match(partial) - match_data.message.should contain(label) - end - - it "contains the expected label" do - value = 42 - label = "everything" - partial = new_partial(value) - matcher = Spectator::Matchers::LessThanEqualMatcher.new(value, label) - match_data = matcher.match(partial) - match_data.message.should contain(label) - end - - context "when expected label is omitted" do - it "contains stringified form of expected value" do - value1 = 42 - value2 = 777 - partial = new_partial(value1) - matcher = Spectator::Matchers::LessThanEqualMatcher.new(value2) - match_data = matcher.match(partial) - match_data.message.should contain(value2.to_s) - end - end - end - - describe "#negated_message" do - it "mentions <=" do - value = 42 - partial = new_partial(value) - matcher = Spectator::Matchers::LessThanEqualMatcher.new(value) - match_data = matcher.match(partial) - match_data.negated_message.should contain("<=") - end - - it "contains the actual label" do - value = 42 - label = "everything" - partial = new_partial(value, label) - matcher = Spectator::Matchers::LessThanEqualMatcher.new(value) - match_data = matcher.match(partial) - match_data.negated_message.should contain(label) - end - - it "contains the expected label" do - value = 42 - label = "everything" - partial = new_partial(value) - matcher = Spectator::Matchers::LessThanEqualMatcher.new(value, label) - match_data = matcher.match(partial) - match_data.negated_message.should contain(label) - end - - context "when expected label is omitted" do - it "contains stringified form of expected value" do - value1 = 42 - value2 = 777 - partial = new_partial(value1) - matcher = Spectator::Matchers::LessThanEqualMatcher.new(value2) - match_data = matcher.match(partial) - match_data.negated_message.should contain(value2.to_s) - end - end - end - end - end -end diff --git a/spec/matchers/less_than_matcher_spec.cr b/spec/matchers/less_than_matcher_spec.cr deleted file mode 100644 index df5acaf..0000000 --- a/spec/matchers/less_than_matcher_spec.cr +++ /dev/null @@ -1,160 +0,0 @@ -require "../spec_helper" - -describe Spectator::Matchers::LessThanMatcher do - describe "#match" do - it "compares using #<" do - spy = SpySUT.new - partial = new_partial(spy) - matcher = Spectator::Matchers::LessThanMatcher.new(42) - matcher.match(partial) - spy.lt_call_count.should be > 0 - end - - context "returned MatchData" do - describe "#matched?" do - context "with a larger value" do - it "is true" do - actual = 42 - expected = 777 - partial = new_partial(actual) - matcher = Spectator::Matchers::LessThanMatcher.new(expected) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - - context "with a smaller value" do - it "is false" do - actual = 777 - expected = 42 - partial = new_partial(actual) - matcher = Spectator::Matchers::LessThanMatcher.new(expected) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - - context "with an equal value" do - it "is false" do - value = 42 - partial = new_partial(value) - matcher = Spectator::Matchers::LessThanMatcher.new(value) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - end - - describe "#values" do - context "expected" do - it "is the expected value" do - actual = 42 - expected = 777 - partial = new_partial(actual) - matcher = Spectator::Matchers::LessThanMatcher.new(expected) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :expected)[:value].should eq(expected) - end - - it "is prefixed with <" do - actual = 42 - expected = 777 - partial = new_partial(actual) - matcher = Spectator::Matchers::LessThanMatcher.new(expected) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :expected)[:to_s].should start_with("<") - end - end - - context "actual" do - it "is the actual value" do - actual = 42 - expected = 777 - partial = new_partial(actual) - matcher = Spectator::Matchers::LessThanMatcher.new(expected) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :actual)[:value].should eq(actual) - end - end - end - - describe "#message" do - it "mentions <" do - value = 42 - partial = new_partial(value) - matcher = Spectator::Matchers::LessThanMatcher.new(value) - match_data = matcher.match(partial) - match_data.message.should contain("<") - end - - it "contains the actual label" do - value = 42 - label = "everything" - partial = new_partial(value, label) - matcher = Spectator::Matchers::LessThanMatcher.new(value) - match_data = matcher.match(partial) - match_data.message.should contain(label) - end - - it "contains the expected label" do - value = 42 - label = "everything" - partial = new_partial(value) - matcher = Spectator::Matchers::LessThanMatcher.new(value, label) - match_data = matcher.match(partial) - match_data.message.should contain(label) - end - - context "when expected label is omitted" do - it "contains stringified form of expected value" do - value1 = 42 - value2 = 777 - partial = new_partial(value1) - matcher = Spectator::Matchers::LessThanMatcher.new(value2) - match_data = matcher.match(partial) - match_data.message.should contain(value2.to_s) - end - end - end - - describe "#negated_message" do - it "mentions <" do - value = 42 - partial = new_partial(value) - matcher = Spectator::Matchers::LessThanMatcher.new(value) - match_data = matcher.match(partial) - match_data.negated_message.should contain("<") - end - - it "contains the actual label" do - value = 42 - label = "everything" - partial = new_partial(value, label) - matcher = Spectator::Matchers::LessThanMatcher.new(value) - match_data = matcher.match(partial) - match_data.negated_message.should contain(label) - end - - it "contains the expected label" do - value = 42 - label = "everything" - partial = new_partial(value) - matcher = Spectator::Matchers::LessThanMatcher.new(value, label) - match_data = matcher.match(partial) - match_data.negated_message.should contain(label) - end - - context "when expected label is omitted" do - it "contains stringified form of expected value" do - value1 = 42 - value2 = 777 - partial = new_partial(value1) - matcher = Spectator::Matchers::LessThanMatcher.new(value2) - match_data = matcher.match(partial) - match_data.negated_message.should contain(value2.to_s) - end - end - end - end - end -end diff --git a/spec/matchers/nil_matcher_spec.cr b/spec/matchers/nil_matcher_spec.cr deleted file mode 100644 index 3250d02..0000000 --- a/spec/matchers/nil_matcher_spec.cr +++ /dev/null @@ -1,86 +0,0 @@ -require "../spec_helper" - -describe Spectator::Matchers::NilMatcher do - describe "#match" do - context "returned MatchData" do - describe "#matched?" do - context "with nil" do - it "is true" do - value = nil.as(Bool?) - partial = new_partial(value) - matcher = Spectator::Matchers::NilMatcher.new - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - - context "with not nil" do - it "is false" do - value = true.as(Bool?) - partial = new_partial(value) - matcher = Spectator::Matchers::NilMatcher.new - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - end - - describe "#values" do - context "expected" do - it "is nil" do - partial = new_partial(42) - matcher = Spectator::Matchers::NilMatcher.new - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :expected)[:value].should eq(nil) - end - end - - context "actual" do - it "is the actual value" do - value = 42 - partial = new_partial(value) - matcher = Spectator::Matchers::NilMatcher.new - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :actual)[:value].should eq(value) - end - end - end - - describe "#message" do - it "mentions nil" do - partial = new_partial(42) - matcher = Spectator::Matchers::NilMatcher.new - match_data = matcher.match(partial) - match_data.message.should contain("nil") - end - - it "contains the actual label" do - value = 42 - label = "everything" - partial = new_partial(value, label) - matcher = Spectator::Matchers::NilMatcher.new - match_data = matcher.match(partial) - match_data.message.should contain(label) - end - end - - describe "#negated_message" do - it "mentions nil" do - partial = new_partial(42) - matcher = Spectator::Matchers::NilMatcher.new - match_data = matcher.match(partial) - match_data.negated_message.should contain("nil") - end - - it "contains the actual label" do - value = 42 - label = "everything" - partial = new_partial(value, label) - matcher = Spectator::Matchers::NilMatcher.new - match_data = matcher.match(partial) - match_data.negated_message.should contain(label) - end - end - end - end -end diff --git a/spec/matchers/predicate_matcher_spec.cr b/spec/matchers/predicate_matcher_spec.cr deleted file mode 100644 index 031556b..0000000 --- a/spec/matchers/predicate_matcher_spec.cr +++ /dev/null @@ -1,89 +0,0 @@ -require "../spec_helper" - -describe Spectator::Matchers::PredicateMatcher do - describe "#match" do - context "returned MatchData" do - describe "#match?" do - context "with a true predicate" do - it "is true" do - value = "foobar" - partial = new_partial(value) - matcher = Spectator::Matchers::PredicateMatcher.new({ascii_only: Tuple.new}, "ascii_only") - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - - context "with a false predicate" do - it "is false" do - value = "foobar" - partial = new_partial(value) - matcher = Spectator::Matchers::PredicateMatcher.new({empty: Tuple.new}, "empty") - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - end - - describe "#values" do - it "contains a key for each expected attribute" do - value = "foobar" - partial = new_partial(value) - matcher = Spectator::Matchers::PredicateMatcher.new({empty: Tuple.new, ascii_only: Tuple.new}, "empty, ascii_only") - match_data = matcher.match(partial) - match_data_has_key?(match_data.values, :empty).should be_true - match_data_has_key?(match_data.values, :ascii_only).should be_true - end - - it "has the actual values" do - value = "foobar" - partial = new_partial(value) - matcher = Spectator::Matchers::PredicateMatcher.new({empty: Tuple.new, ascii_only: Tuple.new}, "empty, ascii_only") - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :empty)[:value].should eq(value.empty?) - match_data_value_sans_prefix(match_data.values, :ascii_only)[:value].should eq(value.ascii_only?) - end - end - - describe "#message" do - it "contains the actual label" do - value = "foobar" - label = "blah" - partial = new_partial(value, label) - matcher = Spectator::Matchers::PredicateMatcher.new({ascii_only: Tuple.new}, "ascii_only") - match_data = matcher.match(partial) - match_data.message.should contain(label) - end - - it "contains the expected label" do - value = "foobar" - label = "blah" - partial = new_partial(value) - matcher = Spectator::Matchers::PredicateMatcher.new({ascii_only: Tuple.new}, label) - match_data = matcher.match(partial) - match_data.message.should contain(label) - end - end - - describe "#negated_message" do - it "contains the actual label" do - value = "foobar" - label = "blah" - partial = new_partial(value, label) - matcher = Spectator::Matchers::PredicateMatcher.new({ascii_only: Tuple.new}, "ascii_only") - match_data = matcher.match(partial) - match_data.negated_message.should contain(label) - end - - it "contains the expected label" do - value = "foobar" - label = "blah" - partial = new_partial(value) - matcher = Spectator::Matchers::PredicateMatcher.new({ascii_only: Tuple.new}, label) - match_data = matcher.match(partial) - match_data.negated_message.should contain(label) - end - end - end - end -end diff --git a/spec/matchers/range_matcher_spec.cr b/spec/matchers/range_matcher_spec.cr deleted file mode 100644 index 5f473a5..0000000 --- a/spec/matchers/range_matcher_spec.cr +++ /dev/null @@ -1,686 +0,0 @@ -require "../spec_helper" - -describe Spectator::Matchers::RangeMatcher do - describe "#match" do - context "returned MatchData" do - describe "#matched?" do - context "inclusive" do - it "is true for lower-bound" do - lower = 3 - upper = 9 - value = lower - range = Range.new(lower, upper, exclusive: false) - partial = new_partial(value) - matcher = Spectator::Matchers::RangeMatcher.new(range) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - - it "is false for lower-bound minus 1" do - lower = 3 - upper = 9 - value = lower - 1 - range = Range.new(lower, upper, exclusive: false) - partial = new_partial(value) - matcher = Spectator::Matchers::RangeMatcher.new(range) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - - it "is true for mid-range" do - lower = 3 - upper = 9 - value = 5 - range = Range.new(lower, upper, exclusive: false) - partial = new_partial(value) - matcher = Spectator::Matchers::RangeMatcher.new(range) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - - it "is true for upper-bound" do - lower = 3 - upper = 9 - value = upper - range = Range.new(lower, upper, exclusive: false) - partial = new_partial(value) - matcher = Spectator::Matchers::RangeMatcher.new(range) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - - it "is false for upper-bound plus 1" do - lower = 3 - upper = 9 - value = upper + 1 - range = Range.new(lower, upper, exclusive: false) - partial = new_partial(value) - matcher = Spectator::Matchers::RangeMatcher.new(range) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - - context "exclusive" do - it "is true for lower-bound" do - lower = 3 - upper = 9 - value = lower - range = Range.new(lower, upper, exclusive: true) - partial = new_partial(value) - matcher = Spectator::Matchers::RangeMatcher.new(range) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - - it "is false for lower-bound minus 1" do - lower = 3 - upper = 9 - value = lower - 1 - range = Range.new(lower, upper, exclusive: true) - partial = new_partial(value) - matcher = Spectator::Matchers::RangeMatcher.new(range) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - - it "is true for mid-range" do - lower = 3 - upper = 9 - value = 5 - range = Range.new(lower, upper, exclusive: true) - partial = new_partial(value) - matcher = Spectator::Matchers::RangeMatcher.new(range) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - - it "is false for upper-bound" do - lower = 3 - upper = 9 - value = upper - range = Range.new(lower, upper, exclusive: true) - partial = new_partial(value) - matcher = Spectator::Matchers::RangeMatcher.new(range) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - - it "is false for upper-bound plus 1" do - lower = 3 - upper = 9 - value = upper + 1 - range = Range.new(lower, upper, exclusive: true) - partial = new_partial(value) - matcher = Spectator::Matchers::RangeMatcher.new(range) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - end - - describe "#values" do - context "lower" do - it "is #begin from the expected range" do - range = Range.new(3, 9) - partial = new_partial(5) - matcher = Spectator::Matchers::RangeMatcher.new(range) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :lower)[:value].should eq(range.begin) - end - - it "is prefixed with >=" do - range = Range.new(3, 9) - partial = new_partial(5) - matcher = Spectator::Matchers::RangeMatcher.new(range) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :lower)[:to_s].should start_with(">=") - end - end - - context "upper" do - it "is #end from the expected range" do - range = Range.new(3, 9) - partial = new_partial(5) - matcher = Spectator::Matchers::RangeMatcher.new(range) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :upper)[:value].should eq(range.end) - end - - context "when inclusive" do - it "is prefixed with <=" do - range = Range.new(3, 9, exclusive: false) - partial = new_partial(5) - matcher = Spectator::Matchers::RangeMatcher.new(range) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :upper)[:to_s].should start_with("<=") - end - end - - context "when exclusive" do - it "is prefixed with <" do - range = Range.new(3, 9, exclusive: false) - partial = new_partial(5) - matcher = Spectator::Matchers::RangeMatcher.new(range) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :upper)[:to_s].should start_with("<") - end - end - end - - context "actual" do - it "is the actual value" do - value = 5 - range = Range.new(3, 9) - partial = new_partial(value) - matcher = Spectator::Matchers::RangeMatcher.new(range) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :actual)[:value].should eq(value) - end - end - end - - describe "#message" do - it "contains the actual label" do - range = 1..10 - value = 5 - label = "everything" - partial = new_partial(value, label) - matcher = Spectator::Matchers::RangeMatcher.new(range) - match_data = matcher.match(partial) - match_data.message.should contain(label) - end - - it "contains the expected label" do - range = 1..10 - value = 5 - label = "everything" - partial = new_partial(value) - matcher = Spectator::Matchers::RangeMatcher.new(range, label) - match_data = matcher.match(partial) - match_data.message.should contain(label) - end - - context "when expected label is omitted" do - it "contains stringified form of expected value" do - range = 1..10 - value = 5 - partial = new_partial(value) - matcher = Spectator::Matchers::RangeMatcher.new(range) - match_data = matcher.match(partial) - match_data.message.should contain(range.to_s) - end - end - end - - describe "#negated_message" do - it "contains the actual label" do - range = 1..10 - value = 5 - label = "everything" - partial = new_partial(value, label) - matcher = Spectator::Matchers::RangeMatcher.new(range) - match_data = matcher.match(partial) - match_data.negated_message.should contain(label) - end - - it "contains the expected label" do - range = 1..10 - value = 5 - label = "everything" - partial = new_partial(value) - matcher = Spectator::Matchers::RangeMatcher.new(range, label) - match_data = matcher.match(partial) - match_data.negated_message.should contain(label) - end - - context "when expected label is omitted" do - it "contains stringified form of expected value" do - range = 1..10 - value = 5 - partial = new_partial(value) - matcher = Spectator::Matchers::RangeMatcher.new(range) - match_data = matcher.match(partial) - match_data.negated_message.should contain(range.to_s) - end - end - end - end - end - - describe "#inclusive" do - context "initially exclusive" do - it "is true for lower-bound" do - lower = 3 - upper = 9 - value = lower - range = Range.new(lower, upper, exclusive: true) - partial = new_partial(value) - matcher = Spectator::Matchers::RangeMatcher.new(range).inclusive - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - - it "is false for lower-bound minus 1" do - lower = 3 - upper = 9 - value = lower - 1 - range = Range.new(lower, upper, exclusive: true) - partial = new_partial(value) - matcher = Spectator::Matchers::RangeMatcher.new(range).inclusive - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - - it "is true for mid-range" do - lower = 3 - upper = 9 - value = 5 - range = Range.new(lower, upper, exclusive: true) - partial = new_partial(value) - matcher = Spectator::Matchers::RangeMatcher.new(range).inclusive - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - - it "is true for upper-bound" do - lower = 3 - upper = 9 - value = upper - range = Range.new(lower, upper, exclusive: true) - partial = new_partial(value) - matcher = Spectator::Matchers::RangeMatcher.new(range).inclusive - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - - it "is false for upper-bound plus 1" do - lower = 3 - upper = 9 - value = upper + 1 - range = Range.new(lower, upper, exclusive: true) - partial = new_partial(value) - matcher = Spectator::Matchers::RangeMatcher.new(range).inclusive - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - - describe "#message" do - it "mentions inclusive" do - range = 1...10 - value = 5 - partial = new_partial(value) - matcher = Spectator::Matchers::RangeMatcher.new(range).inclusive - match_data = matcher.match(partial) - match_data.message.should contain("inclusive") - end - - it "does not mention exclusive" do - range = 1...10 - value = 5 - partial = new_partial(value) - matcher = Spectator::Matchers::RangeMatcher.new(range).inclusive - match_data = matcher.match(partial) - match_data.message.should_not contain("exclusive") - end - - it "contains the original label" do - range = 1...10 - value = 5 - label = "foobar" - partial = new_partial(value) - matcher = Spectator::Matchers::RangeMatcher.new(range, label).inclusive - match_data = matcher.match(partial) - match_data.message.should contain(label) - end - end - - describe "#negated_message" do - it "mentions inclusive" do - range = 1...10 - value = 5 - partial = new_partial(value) - matcher = Spectator::Matchers::RangeMatcher.new(range).inclusive - match_data = matcher.match(partial) - match_data.negated_message.should contain("inclusive") - end - - it "does not mention exclusive" do - range = 1...10 - value = 5 - partial = new_partial(value) - matcher = Spectator::Matchers::RangeMatcher.new(range).inclusive - match_data = matcher.match(partial) - match_data.negated_message.should_not contain("exclusive") - end - - it "contains the original label" do - range = 1...10 - value = 5 - label = "foobar" - partial = new_partial(value) - matcher = Spectator::Matchers::RangeMatcher.new(range, label).inclusive - match_data = matcher.match(partial) - match_data.negated_message.should contain(label) - end - end - end - - context "initially inclusive" do - it "is true for lower-bound" do - lower = 3 - upper = 9 - value = lower - range = Range.new(lower, upper, exclusive: false) - partial = new_partial(value) - matcher = Spectator::Matchers::RangeMatcher.new(range).inclusive - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - - it "is false for lower-bound minus 1" do - lower = 3 - upper = 9 - value = lower - 1 - range = Range.new(lower, upper, exclusive: false) - partial = new_partial(value) - matcher = Spectator::Matchers::RangeMatcher.new(range).inclusive - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - - it "is true for mid-range" do - lower = 3 - upper = 9 - value = 5 - range = Range.new(lower, upper, exclusive: false) - partial = new_partial(value) - matcher = Spectator::Matchers::RangeMatcher.new(range).inclusive - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - - it "is true for upper-bound" do - lower = 3 - upper = 9 - value = upper - range = Range.new(lower, upper, exclusive: false) - partial = new_partial(value) - matcher = Spectator::Matchers::RangeMatcher.new(range).inclusive - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - - it "is false for upper-bound plus 1" do - lower = 3 - upper = 9 - value = upper + 1 - range = Range.new(lower, upper, exclusive: false) - partial = new_partial(value) - matcher = Spectator::Matchers::RangeMatcher.new(range).inclusive - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - - describe "#message" do - it "mentions inclusive" do - range = 1...10 - value = 5 - partial = new_partial(value) - matcher = Spectator::Matchers::RangeMatcher.new(range).inclusive - match_data = matcher.match(partial) - match_data.message.should contain("inclusive") - end - - it "contains the original label" do - range = 1..10 - value = 5 - label = "foobar" - partial = new_partial(value) - matcher = Spectator::Matchers::RangeMatcher.new(range, label).inclusive - match_data = matcher.match(partial) - match_data.message.should contain(label) - end - end - - describe "#negated_message" do - it "mentions inclusive" do - range = 1..10 - value = 5 - partial = new_partial(value) - matcher = Spectator::Matchers::RangeMatcher.new(range).inclusive - match_data = matcher.match(partial) - match_data.negated_message.should contain("inclusive") - end - - it "contains the original label" do - range = 1...10 - value = 5 - label = "foobar" - partial = new_partial(value) - matcher = Spectator::Matchers::RangeMatcher.new(range, label).inclusive - match_data = matcher.match(partial) - match_data.negated_message.should contain(label) - end - end - end - end - - describe "#exclusive" do - context "initially inclusive" do - it "is true for lower-bound" do - lower = 3 - upper = 9 - value = lower - range = Range.new(lower, upper, exclusive: false) - partial = new_partial(value) - matcher = Spectator::Matchers::RangeMatcher.new(range).exclusive - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - - it "is false for lower-bound minus 1" do - lower = 3 - upper = 9 - value = lower - 1 - range = Range.new(lower, upper, exclusive: false) - partial = new_partial(value) - matcher = Spectator::Matchers::RangeMatcher.new(range).exclusive - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - - it "is true for mid-range" do - lower = 3 - upper = 9 - value = 5 - range = Range.new(lower, upper, exclusive: false) - partial = new_partial(value) - matcher = Spectator::Matchers::RangeMatcher.new(range).exclusive - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - - it "is false for upper-bound" do - lower = 3 - upper = 9 - value = upper - range = Range.new(lower, upper, exclusive: false) - partial = new_partial(value) - matcher = Spectator::Matchers::RangeMatcher.new(range).exclusive - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - - it "is false for upper-bound plus 1" do - lower = 3 - upper = 9 - value = upper + 1 - range = Range.new(lower, upper, exclusive: false) - partial = new_partial(value) - matcher = Spectator::Matchers::RangeMatcher.new(range).exclusive - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - - describe "#message" do - it "mentions exclusive" do - range = 1..10 - value = 5 - partial = new_partial(value) - matcher = Spectator::Matchers::RangeMatcher.new(range).exclusive - match_data = matcher.match(partial) - match_data.message.should contain("exclusive") - end - - it "does not mention inclusive" do - range = 1..10 - value = 5 - partial = new_partial(value) - matcher = Spectator::Matchers::RangeMatcher.new(range).exclusive - match_data = matcher.match(partial) - match_data.message.should_not contain("inclusive") - end - - it "contains the original label" do - range = 1..10 - value = 5 - label = "foobar" - partial = new_partial(value) - matcher = Spectator::Matchers::RangeMatcher.new(range, label).exclusive - match_data = matcher.match(partial) - match_data.message.should contain(label) - end - end - - describe "#negated_message" do - it "mentions exclusive" do - range = 1..10 - value = 5 - partial = new_partial(value) - matcher = Spectator::Matchers::RangeMatcher.new(range).exclusive - match_data = matcher.match(partial) - match_data.negated_message.should contain("exclusive") - end - - it "does not mention inclusive" do - range = 1..10 - value = 5 - partial = new_partial(value) - matcher = Spectator::Matchers::RangeMatcher.new(range).exclusive - match_data = matcher.match(partial) - match_data.negated_message.should_not contain("inclusive") - end - - it "contains the original label" do - range = 1..10 - value = 5 - label = "foobar" - partial = new_partial(value) - matcher = Spectator::Matchers::RangeMatcher.new(range, label).exclusive - match_data = matcher.match(partial) - match_data.negated_message.should contain(label) - end - end - end - - context "initially exclusive" do - it "is true for lower-bound" do - lower = 3 - upper = 9 - value = lower - range = Range.new(lower, upper, exclusive: true) - partial = new_partial(value) - matcher = Spectator::Matchers::RangeMatcher.new(range).exclusive - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - - it "is false for lower-bound minus 1" do - lower = 3 - upper = 9 - value = lower - 1 - range = Range.new(lower, upper, exclusive: true) - partial = new_partial(value) - matcher = Spectator::Matchers::RangeMatcher.new(range).exclusive - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - - it "is true for mid-range" do - lower = 3 - upper = 9 - value = 5 - range = Range.new(lower, upper, exclusive: true) - partial = new_partial(value) - matcher = Spectator::Matchers::RangeMatcher.new(range).exclusive - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - - it "is false for upper-bound" do - lower = 3 - upper = 9 - value = upper - range = Range.new(lower, upper, exclusive: true) - partial = new_partial(value) - matcher = Spectator::Matchers::RangeMatcher.new(range).exclusive - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - - it "is false for upper-bound plus 1" do - lower = 3 - upper = 9 - value = upper + 1 - range = Range.new(lower, upper, exclusive: true) - partial = new_partial(value) - matcher = Spectator::Matchers::RangeMatcher.new(range).exclusive - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - - describe "#message" do - it "mentions exclusive" do - range = 1...10 - value = 5 - partial = new_partial(value) - matcher = Spectator::Matchers::RangeMatcher.new(range).exclusive - match_data = matcher.match(partial) - match_data.message.should contain("exclusive") - end - - it "contains the original label" do - range = 1...10 - value = 5 - label = "foobar" - partial = new_partial(value) - matcher = Spectator::Matchers::RangeMatcher.new(range, label).exclusive - match_data = matcher.match(partial) - match_data.message.should contain(label) - end - end - - describe "#negated_message" do - it "mentions exclusive" do - range = 1...10 - value = 5 - partial = new_partial(value) - matcher = Spectator::Matchers::RangeMatcher.new(range).exclusive - match_data = matcher.match(partial) - match_data.negated_message.should contain("exclusive") - end - - it "contains the original label" do - range = 1...10 - value = 5 - label = "foobar" - partial = new_partial(value) - matcher = Spectator::Matchers::RangeMatcher.new(range, label).exclusive - match_data = matcher.match(partial) - match_data.negated_message.should contain(label) - end - end - end - end -end diff --git a/spec/matchers/reference_matcher_spec.cr b/spec/matchers/reference_matcher_spec.cr deleted file mode 100644 index b029090..0000000 --- a/spec/matchers/reference_matcher_spec.cr +++ /dev/null @@ -1,152 +0,0 @@ -require "../spec_helper" - -describe Spectator::Matchers::ReferenceMatcher do - describe "#match" do - context "returned MatchData" do - describe "#matched?" do - context "with the same instance" do - it "is true" do - # Box is used because it is a reference type and doesn't override the == method. - ref = Box.new([] of Int32) - partial = new_partial(ref) - matcher = Spectator::Matchers::ReferenceMatcher.new(ref) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - - context "with different instances" do - context "with same contents" do - it "is false" do - array1 = [1, 2, 3] - array2 = [1, 2, 3] - partial = new_partial(array1) - matcher = Spectator::Matchers::ReferenceMatcher.new(array2) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - - context "with a duplicated instance" do - it "is false" do - array1 = [1, 2, 3] - array2 = array1.dup - partial = new_partial(array1) - matcher = Spectator::Matchers::ReferenceMatcher.new(array2) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - - context "with the same type" do - it "is false" do - obj1 = "foo" - obj2 = "bar" - partial = new_partial(obj1) - matcher = Spectator::Matchers::ReferenceMatcher.new(obj2) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - - context "with a different type" do - it "is false" do - obj1 = "foobar" - obj2 = [1, 2, 3] - partial = new_partial(obj1) - matcher = Spectator::Matchers::ReferenceMatcher.new(obj2) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - end - end - - describe "#values" do - context "expected" do - it "is the expected value" do - actual = "foobar" - expected = /foo/ - partial = new_partial(actual) - matcher = Spectator::Matchers::ReferenceMatcher.new(expected) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :expected)[:value].should eq(expected) - end - end - - context "actual" do - it "is the actual value" do - actual = "foobar" - expected = /foo/ - partial = new_partial(actual) - matcher = Spectator::Matchers::ReferenceMatcher.new(expected) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :actual)[:value].should eq(actual) - end - end - end - - describe "#message" do - it "contains the actual label" do - value = "foobar" - label = "everything" - partial = new_partial(value, label) - matcher = Spectator::Matchers::ReferenceMatcher.new(value) - match_data = matcher.match(partial) - match_data.message.should contain(label) - end - - it "contains the expected label" do - value = "foobar" - label = "everything" - partial = new_partial(value) - matcher = Spectator::Matchers::ReferenceMatcher.new(value, label) - match_data = matcher.match(partial) - match_data.message.should contain(label) - end - - context "when expected label is omitted" do - it "contains stringified form of expected value" do - obj1 = "foo" - obj2 = "bar" - partial = new_partial(obj1) - matcher = Spectator::Matchers::ReferenceMatcher.new(obj2) - match_data = matcher.match(partial) - match_data.message.should contain(obj2.to_s) - end - end - end - - describe "#negated_message" do - it "contains the actual label" do - value = "foobar" - label = "everything" - partial = new_partial(value, label) - matcher = Spectator::Matchers::ReferenceMatcher.new(value) - match_data = matcher.match(partial) - match_data.negated_message.should contain(label) - end - - it "contains the expected label" do - value = "foobar" - label = "everything" - partial = new_partial(value) - matcher = Spectator::Matchers::ReferenceMatcher.new(value, label) - match_data = matcher.match(partial) - match_data.negated_message.should contain(label) - end - - context "when expected label is omitted" do - it "contains stringified form of expected value" do - obj1 = "foo" - obj2 = "bar" - partial = new_partial(obj1) - matcher = Spectator::Matchers::ReferenceMatcher.new(obj2) - match_data = matcher.match(partial) - match_data.negated_message.should contain(obj2.to_s) - end - end - end - end - end -end diff --git a/spec/matchers/respond_matcher_spec.cr b/spec/matchers/respond_matcher_spec.cr deleted file mode 100644 index 3685464..0000000 --- a/spec/matchers/respond_matcher_spec.cr +++ /dev/null @@ -1,123 +0,0 @@ -require "../spec_helper" - -describe Spectator::Matchers::RespondMatcher do - describe "#match" do - context "returned MatchData" do - describe "#matched?" do - context "one method" do - context "with a responding method" do - it "is true" do - array = %i[a b c] - partial = new_partial(array) - matcher = Spectator::Matchers::RespondMatcher(NamedTuple(size: Nil)).new - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - - context "against a non-responding method" do - it "is false" do - array = %i[a b c] - partial = new_partial(array) - matcher = Spectator::Matchers::RespondMatcher(NamedTuple(downcase: Nil)).new - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - end - - context "multiple methods" do - context "with one responding method" do - it "is false" do - array = %i[a b c] - partial = new_partial(array) - matcher = Spectator::Matchers::RespondMatcher(NamedTuple(size: Nil, downcase: Nil)).new - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - - context "with all responding methods" do - it "is true" do - array = %i[a b c] - partial = new_partial(array) - matcher = Spectator::Matchers::RespondMatcher(NamedTuple(size: Nil, to_a: Nil)).new - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - - context "with no responding methods" do - it "is false" do - array = %i[a b c] - partial = new_partial(array) - matcher = Spectator::Matchers::RespondMatcher(NamedTuple(downcase: Nil, upcase: Nil)).new - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - end - end - - describe "#values" do - it "contains a key for each expected method" do - array = %i[a b c] - partial = new_partial(array) - matcher = Spectator::Matchers::RespondMatcher(NamedTuple(size: Nil, downcase: Nil)).new - match_data = matcher.match(partial) - match_data_has_key?(match_data.values, :"responds to #size").should be_true - match_data_has_key?(match_data.values, :"responds to #downcase").should be_true - end - - it "has the actual values" do - array = %i[a b c] - partial = new_partial(array) - matcher = Spectator::Matchers::RespondMatcher(NamedTuple(size: Nil, downcase: Nil)).new - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :"responds to #size")[:value].should be_true - match_data_value_sans_prefix(match_data.values, :"responds to #downcase")[:value].should be_false - end - end - - describe "#message" do - it "contains the actual label" do - value = "foobar" - label = "everything" - partial = new_partial(value, label) - matcher = Spectator::Matchers::RespondMatcher(NamedTuple(size: Nil, downcase: Nil)).new - match_data = matcher.match(partial) - match_data.message.should contain(label) - end - - it "contains the method names" do - value = "foobar" - partial = new_partial(value) - matcher = Spectator::Matchers::RespondMatcher(NamedTuple(size: Nil, downcase: Nil)).new - match_data = matcher.match(partial) - match_data.message.should contain("#size") - match_data.message.should contain("#downcase") - end - end - - describe "#negated_message" do - it "contains the actual label" do - value = "foobar" - label = "everything" - partial = new_partial(value, label) - matcher = Spectator::Matchers::RespondMatcher(NamedTuple(size: Nil, downcase: Nil)).new - match_data = matcher.match(partial) - match_data.negated_message.should contain(label) - end - - it "contains the method names" do - value = "foobar" - partial = new_partial(value) - matcher = Spectator::Matchers::RespondMatcher(NamedTuple(size: Nil, downcase: Nil)).new - match_data = matcher.match(partial) - match_data.message.should contain("#size") - match_data.negated_message.should contain("#downcase") - end - end - end - end -end diff --git a/spec/matchers/size_matcher_spec.cr b/spec/matchers/size_matcher_spec.cr deleted file mode 100644 index e50432d..0000000 --- a/spec/matchers/size_matcher_spec.cr +++ /dev/null @@ -1,121 +0,0 @@ -require "../spec_helper" - -describe Spectator::Matchers::SizeMatcher do - describe "#match" do - context "returned MatchData" do - describe "#matched?" do - context "with a matching number of items" do - it "is true" do - array = %i[a b c] - size = array.size - partial = new_partial(array) - matcher = Spectator::Matchers::SizeMatcher.new(size) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - - context "with a different number of items" do - it "is false" do - array = %i[a b c] - size = array.size + 1 - partial = new_partial(array) - matcher = Spectator::Matchers::SizeMatcher.new(size) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - end - - describe "#values" do - context "expected" do - it "is the size given" do - array = %i[a b c] - size = array.size + 1 - partial = new_partial(array) - matcher = Spectator::Matchers::SizeMatcher.new(size) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :expected)[:value].should eq(size) - end - end - - context "actual" do - it "is the size of the set" do - array = %i[a b c] - size = array.size + 1 - partial = new_partial(array) - matcher = Spectator::Matchers::SizeMatcher.new(size) - match_data = matcher.match(partial) - match_data_value_with_key(match_data.values, :actual).value.should eq(array.size) - end - end - end - - describe "#message" do - it "contains the actual label" do - array = %i[a b c] - size = array.size + 1 - label = "foobar" - partial = new_partial(array, label) - matcher = Spectator::Matchers::SizeMatcher.new(size) - match_data = matcher.match(partial) - match_data.message.should contain(label) - end - - it "contains the expected label" do - array = %i[a b c] - size = array.size + 1 - label = "foobar" - partial = new_partial(array) - matcher = Spectator::Matchers::SizeMatcher.new(size, label) - match_data = matcher.match(partial) - match_data.message.should contain(label) - end - - context "when expected label is omitted" do - it "contains stringified form of expected value" do - array = %i[a b c] - size = array.size + 1 - partial = new_partial(array) - matcher = Spectator::Matchers::SizeMatcher.new(size) - match_data = matcher.match(partial) - match_data.message.should contain(size.to_s) - end - end - end - - describe "#negated_message" do - it "contains the actual label" do - array = %i[a b c] - size = array.size + 1 - label = "foobar" - partial = new_partial(array, label) - matcher = Spectator::Matchers::SizeMatcher.new(size) - match_data = matcher.match(partial) - match_data.negated_message.should contain(label) - end - - it "contains the expected label" do - array = %i[a b c] - size = array.size + 1 - label = "foobar" - partial = new_partial(array) - matcher = Spectator::Matchers::SizeMatcher.new(size, label) - match_data = matcher.match(partial) - match_data.negated_message.should contain(label) - end - - context "when expected label is omitted" do - it "contains stringified form of expected value" do - array = %i[a b c] - size = array.size + 1 - partial = new_partial(array) - matcher = Spectator::Matchers::SizeMatcher.new(size) - match_data = matcher.match(partial) - match_data.negated_message.should contain(size.to_s) - end - end - end - end - end -end diff --git a/spec/matchers/size_of_matcher_spec.cr b/spec/matchers/size_of_matcher_spec.cr deleted file mode 100644 index eb1cbb0..0000000 --- a/spec/matchers/size_of_matcher_spec.cr +++ /dev/null @@ -1,121 +0,0 @@ -require "../spec_helper" - -describe Spectator::Matchers::SizeOfMatcher do - describe "#match" do - context "returned MatchData" do - describe "#matched?" do - context "with a matching number of items" do - it "is true" do - array = %i[a b c] - other = [1, 2, 3] - partial = new_partial(array) - matcher = Spectator::Matchers::SizeOfMatcher.new(other) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - - context "with a different number of items" do - it "is false" do - array = %i[a b c] - other = [1, 2, 3, 4] - partial = new_partial(array) - matcher = Spectator::Matchers::SizeOfMatcher.new(other) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - end - - describe "#values" do - context "expected" do - it "is the size given" do - array = %i[a b c] - other = [1, 2, 3, 4] - partial = new_partial(array) - matcher = Spectator::Matchers::SizeOfMatcher.new(other) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :expected)[:value].should eq(other.size) - end - end - - context "actual" do - it "is the size of the set" do - array = %i[a b c] - other = [1, 2, 3, 4] - partial = new_partial(array) - matcher = Spectator::Matchers::SizeOfMatcher.new(other) - match_data = matcher.match(partial) - match_data_value_with_key(match_data.values, :actual).value.should eq(array.size) - end - end - end - - describe "#message" do - it "contains the actual label" do - array = %i[a b c] - other = [1, 2, 3, 4] - label = "foobar" - partial = new_partial(array, label) - matcher = Spectator::Matchers::SizeOfMatcher.new(other) - match_data = matcher.match(partial) - match_data.message.should contain(label) - end - - it "contains the expected label" do - array = %i[a b c] - other = [1, 2, 3, 4] - label = "foobar" - partial = new_partial(array) - matcher = Spectator::Matchers::SizeOfMatcher.new(other, label) - match_data = matcher.match(partial) - match_data.message.should contain(label) - end - - context "when expected label is omitted" do - it "contains stringified form of expected value" do - array = %i[a b c] - other = [1, 2, 3, 4] - partial = new_partial(array) - matcher = Spectator::Matchers::SizeOfMatcher.new(other) - match_data = matcher.match(partial) - match_data.message.should contain(other.to_s) - end - end - end - - describe "#negated_message" do - it "contains the actual label" do - array = %i[a b c] - other = [1, 2, 3, 4] - label = "foobar" - partial = new_partial(array, label) - matcher = Spectator::Matchers::SizeOfMatcher.new(other) - match_data = matcher.match(partial) - match_data.negated_message.should contain(label) - end - - it "contains the expected label" do - array = %i[a b c] - other = [1, 2, 3, 4] - label = "foobar" - partial = new_partial(array) - matcher = Spectator::Matchers::SizeOfMatcher.new(other, label) - match_data = matcher.match(partial) - match_data.negated_message.should contain(label) - end - - context "when expected label is omitted" do - it "contains stringified form of expected value" do - array = %i[a b c] - other = [1, 2, 3, 4] - partial = new_partial(array) - matcher = Spectator::Matchers::SizeOfMatcher.new(other) - match_data = matcher.match(partial) - match_data.negated_message.should contain(other.to_s) - end - end - end - end - end -end diff --git a/spec/matchers/start_with_matcher_spec.cr b/spec/matchers/start_with_matcher_spec.cr deleted file mode 100644 index de626a5..0000000 --- a/spec/matchers/start_with_matcher_spec.cr +++ /dev/null @@ -1,393 +0,0 @@ -require "../spec_helper" - -describe Spectator::Matchers::StartWithMatcher do - describe "#match" do - context "returned MatchData" do - describe "#matched?" do - context "with a String" do - context "against a matching string" do - it "is true" do - value = "foobar" - start = "foo" - partial = new_partial(value) - matcher = Spectator::Matchers::StartWithMatcher.new(start) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - - context "not at start" do - it "is false" do - value = "foobar" - start = "bar" - partial = new_partial(value) - matcher = Spectator::Matchers::StartWithMatcher.new(start) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - end - - context "against a different string" do - it "is false" do - value = "foobar" - start = "baz" - partial = new_partial(value) - matcher = Spectator::Matchers::StartWithMatcher.new(start) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - - context "against a matching character" do - it "is true" do - value = "foobar" - start = 'f' - partial = new_partial(value) - matcher = Spectator::Matchers::StartWithMatcher.new(start) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - - context "not at start" do - it "is false" do - value = "foobar" - start = 'b' - partial = new_partial(value) - matcher = Spectator::Matchers::StartWithMatcher.new(start) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - end - - context "against a different character" do - it "is false" do - value = "foobar" - start = 'z' - partial = new_partial(value) - matcher = Spectator::Matchers::StartWithMatcher.new(start) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - - context "against a matching regex" do - it "is true" do - value = "FOOBAR" - start = /foo/i - partial = new_partial(value) - matcher = Spectator::Matchers::StartWithMatcher.new(start) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - - context "not at start" do - it "is false" do - value = "FOOBAR" - start = /bar/i - partial = new_partial(value) - matcher = Spectator::Matchers::StartWithMatcher.new(start) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - end - - context "against a non-matching regex" do - it "is false" do - value = "FOOBAR" - start = /baz/i - partial = new_partial(value) - matcher = Spectator::Matchers::StartWithMatcher.new(start) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - end - - context "with an Enumberable" do - context "against an equal value" do - it "is true" do - array = %i[a b c] - start = :a - partial = new_partial(array) - matcher = Spectator::Matchers::StartWithMatcher.new(start) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - - context "not at start" do - it "is false" do - array = %i[a b c] - start = :b - partial = new_partial(array) - matcher = Spectator::Matchers::StartWithMatcher.new(start) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - end - - context "against a different value" do - it "is false" do - array = %i[a b c] - start = :z - partial = new_partial(array) - matcher = Spectator::Matchers::StartWithMatcher.new(start) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - - context "against matching element type" do - it "is true" do - array = %i[a b c] - partial = new_partial(array) - matcher = Spectator::Matchers::StartWithMatcher.new(Symbol) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - - context "not at start" do - it "is false" do - array = [1, 2, 3, :a, :b, :c] - partial = new_partial(array) - matcher = Spectator::Matchers::StartWithMatcher.new(Symbol) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - end - - context "against different element type" do - it "is false" do - array = %i[a b c] - partial = new_partial(array) - matcher = Spectator::Matchers::StartWithMatcher.new(Int32) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - - context "against a matching regex" do - it "is true" do - array = %w[FOO BAR BAZ] - start = /foo/i - partial = new_partial(array) - matcher = Spectator::Matchers::StartWithMatcher.new(start) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - - context "not at start" do - it "is false" do - array = %w[FOO BAR BAZ] - start = /bar/i - partial = new_partial(array) - matcher = Spectator::Matchers::StartWithMatcher.new(start) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - end - - context "against a non-matching regex" do - it "is false" do - array = %w[FOO BAR BAZ] - start = /qux/i - partial = new_partial(array) - matcher = Spectator::Matchers::StartWithMatcher.new(start) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - end - end - - describe "#values" do - context "with a String" do - context "expected" do - it "is the expected value" do - value = "FOOBAR" - first = /baz/i - partial = new_partial(value) - matcher = Spectator::Matchers::StartWithMatcher.new(first) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :expected)[:value].should eq(first) - end - end - - context "actual" do - it "is the actual value" do - value = "FOOBAR" - first = /baz/i - partial = new_partial(value) - matcher = Spectator::Matchers::StartWithMatcher.new(first) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :actual)[:value].should eq(value) - end - end - end - - context "with an Indexable" do - context "expected" do - it "is the expected value" do - array = %w[FOO BAR BAZ] - first = /qux/i - partial = new_partial(array) - matcher = Spectator::Matchers::StartWithMatcher.new(first) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :expected)[:value].should eq(first) - end - end - - context "actual" do - it "is the first element" do - array = %w[FOO BAR BAZ] - first = /qux/i - partial = new_partial(array) - matcher = Spectator::Matchers::StartWithMatcher.new(first) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :actual)[:value].should eq(array.first) - end - end - - context "list" do - it "is the full actual list" do - array = %w[FOO BAR BAZ] - first = /qux/i - partial = new_partial(array) - matcher = Spectator::Matchers::StartWithMatcher.new(first) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :list)[:value].should eq(array) - end - end - end - end - - describe "#message" do - context "with a String" do - it "mentions #starts_with?" do - value = "foobar" - start = "baz" - partial = new_partial(value) - matcher = Spectator::Matchers::StartWithMatcher.new(start) - match_data = matcher.match(partial) - match_data.message.should contain("#starts_with?") - end - end - - context "with an Enumerable" do - it "mentions ===" do - array = %i[a b c] - partial = new_partial(array) - matcher = Spectator::Matchers::StartWithMatcher.new(array.first) - match_data = matcher.match(partial) - match_data.message.should contain("===") - end - - it "mentions first" do - array = %i[a b c] - partial = new_partial(array) - matcher = Spectator::Matchers::StartWithMatcher.new(array.first) - match_data = matcher.match(partial) - match_data.message.should contain("first") - end - end - - it "contains the actual label" do - value = "foobar" - start = "baz" - label = "everything" - partial = new_partial(value, label) - matcher = Spectator::Matchers::StartWithMatcher.new(start) - match_data = matcher.match(partial) - match_data.message.should contain(label) - end - - it "contains the expected label" do - value = "foobar" - start = "baz" - label = "everything" - partial = new_partial(value) - matcher = Spectator::Matchers::StartWithMatcher.new(start, label) - match_data = matcher.match(partial) - match_data.message.should contain(label) - end - - context "when expected label is omitted" do - it "contains stringified form of expected value" do - value = "foobar" - start = "baz" - partial = new_partial(value) - matcher = Spectator::Matchers::StartWithMatcher.new(start) - match_data = matcher.match(partial) - match_data.message.should contain(start) - end - end - end - - describe "#negated_message" do - context "with a String" do - it "mentions #starts_with?" do - value = "foobar" - start = "baz" - partial = new_partial(value) - matcher = Spectator::Matchers::StartWithMatcher.new(start) - match_data = matcher.match(partial) - match_data.negated_message.should contain("#starts_with?") - end - end - - context "with an Enumerable" do - it "mentions ===" do - array = %i[a b c] - partial = new_partial(array) - matcher = Spectator::Matchers::StartWithMatcher.new(array.first) - match_data = matcher.match(partial) - match_data.negated_message.should contain("===") - end - - it "mentions first" do - array = %i[a b c] - partial = new_partial(array) - matcher = Spectator::Matchers::StartWithMatcher.new(array.first) - match_data = matcher.match(partial) - match_data.negated_message.should contain("first") - end - end - - it "contains the actual label" do - value = "foobar" - start = "baz" - label = "everything" - partial = new_partial(value, label) - matcher = Spectator::Matchers::StartWithMatcher.new(start) - match_data = matcher.match(partial) - match_data.negated_message.should contain(label) - end - - it "contains the expected label" do - value = "foobar" - start = "baz" - label = "everything" - partial = new_partial(value) - matcher = Spectator::Matchers::StartWithMatcher.new(start, label) - match_data = matcher.match(partial) - match_data.negated_message.should contain(label) - end - - context "when expected label is omitted" do - it "contains stringified form of expected value" do - value = "foobar" - start = "baz" - partial = new_partial(value) - matcher = Spectator::Matchers::StartWithMatcher.new(start) - match_data = matcher.match(partial) - match_data.negated_message.should contain(start) - end - end - end - end - end -end diff --git a/spec/matchers/truthy_matcher_spec.cr b/spec/matchers/truthy_matcher_spec.cr deleted file mode 100644 index 7ef3970..0000000 --- a/spec/matchers/truthy_matcher_spec.cr +++ /dev/null @@ -1,374 +0,0 @@ -require "../spec_helper" - -# This is a terrible hack, -# but I don't want to expose `ValueMatcher#expected` publicly -# just for this spec. -module Spectator::Matchers - struct ValueMatcher(ExpectedType) - def expected_value - expected - end - end -end - -def be_comparison - Spectator::Matchers::TruthyMatcher.new(true) -end - -describe Spectator::Matchers::TruthyMatcher do - describe "#match" do - context "returned MatchData" do - context "truthy" do - describe "#matched?" do - context "with a truthy value" do - it "is true" do - value = 42 - partial = new_partial(value) - matcher = Spectator::Matchers::TruthyMatcher.new(true) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - - context "with false" do - it "is false" do - value = false - partial = new_partial(value) - matcher = Spectator::Matchers::TruthyMatcher.new(true) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - - context "with nil" do - it "is false" do - value = nil - partial = new_partial(value) - matcher = Spectator::Matchers::TruthyMatcher.new(true) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - end - - describe "#values" do - context "expected" do - it "contains the definition of falsey" do - value = 42 - partial = new_partial(value) - matcher = Spectator::Matchers::TruthyMatcher.new(true) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :expected)[:to_s].should match(/false or nil/i) - end - - it "is prefixed with \"Not\"" do - value = 42 - partial = new_partial(value) - matcher = Spectator::Matchers::TruthyMatcher.new(true) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :expected)[:to_s].should start_with(/not/i) - end - end - - context "actual" do - it "is the actual value" do - value = 42 - partial = new_partial(value) - matcher = Spectator::Matchers::TruthyMatcher.new(true) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :actual)[:value].should eq(value) - end - end - - context "truthy" do - context "when the actual value is truthy" do - it "is true" do - value = 42 - partial = new_partial(value) - matcher = Spectator::Matchers::TruthyMatcher.new(true) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :truthy)[:value].should be_true - end - end - - context "when the actual value is false" do - it "is false" do - value = false - partial = new_partial(value) - matcher = Spectator::Matchers::TruthyMatcher.new(true) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :truthy)[:value].should be_false - end - end - - context "when the actual value is nil" do - it "is false" do - value = nil - partial = new_partial(value) - matcher = Spectator::Matchers::TruthyMatcher.new(true) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :truthy)[:value].should be_false - end - end - end - end - - describe "#message" do - it "contains the actual label" do - value = 42 - label = "everything" - partial = new_partial(value, label) - matcher = Spectator::Matchers::TruthyMatcher.new(true) - match_data = matcher.match(partial) - match_data.message.should contain(label) - end - - it "contains the \"truthy\"" do - value = 42 - partial = new_partial(value) - matcher = Spectator::Matchers::TruthyMatcher.new(true) - match_data = matcher.match(partial) - match_data.message.should contain("truthy") - end - end - - describe "#negated_message" do - it "contains the actual label" do - value = 42 - label = "everything" - partial = new_partial(value, label) - matcher = Spectator::Matchers::TruthyMatcher.new(true) - match_data = matcher.match(partial) - match_data.negated_message.should contain(label) - end - - it "contains the \"truthy\"" do - value = 42 - partial = new_partial(value) - matcher = Spectator::Matchers::TruthyMatcher.new(true) - match_data = matcher.match(partial) - match_data.negated_message.should contain("truthy") - end - end - end - - context "falsey" do - describe "#matched?" do - context "with a truthy value" do - it "is false" do - value = 42 - partial = new_partial(value) - matcher = Spectator::Matchers::TruthyMatcher.new(false) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - - context "with false" do - it "is true" do - value = false - partial = new_partial(value) - matcher = Spectator::Matchers::TruthyMatcher.new(false) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - - context "with nil" do - it "is true" do - value = nil - partial = new_partial(value) - matcher = Spectator::Matchers::TruthyMatcher.new(false) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - end - - describe "#values" do - context "expected" do - it "contains the definition of falsey" do - value = 42 - partial = new_partial(value) - matcher = Spectator::Matchers::TruthyMatcher.new(false) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :expected)[:to_s].should match(/false or nil/i) - end - - it "is not prefixed with \"Not\"" do - value = 42 - partial = new_partial(value) - matcher = Spectator::Matchers::TruthyMatcher.new(false) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :expected)[:to_s].should_not start_with(/not/i) - end - end - - context "actual" do - it "is the actual value" do - value = 42 - partial = new_partial(value) - matcher = Spectator::Matchers::TruthyMatcher.new(false) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :actual)[:value].should eq(value) - end - end - - context "truthy" do - context "when the actual value is truthy" do - it "is true" do - value = 42 - partial = new_partial(value) - matcher = Spectator::Matchers::TruthyMatcher.new(false) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :truthy)[:value].should be_true - end - end - - context "when the actual value is false" do - it "is false" do - value = false - partial = new_partial(value) - matcher = Spectator::Matchers::TruthyMatcher.new(false) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :truthy)[:value].should be_false - end - end - - context "when the actual value is nil" do - it "is false" do - value = nil - partial = new_partial(value) - matcher = Spectator::Matchers::TruthyMatcher.new(false) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :truthy)[:value].should be_false - end - end - end - end - - describe "#message" do - it "contains the actual label" do - value = 42 - label = "everything" - partial = new_partial(value, label) - matcher = Spectator::Matchers::TruthyMatcher.new(false) - match_data = matcher.match(partial) - match_data.message.should contain(label) - end - - it "contains the \"falsey\"" do - value = 42 - partial = new_partial(value) - matcher = Spectator::Matchers::TruthyMatcher.new(false) - match_data = matcher.match(partial) - match_data.message.should contain("falsey") - end - end - - describe "#negated_message" do - it "contains the actual label" do - value = 42 - label = "everything" - partial = new_partial(value, label) - matcher = Spectator::Matchers::TruthyMatcher.new(false) - match_data = matcher.match(partial) - match_data.negated_message.should contain(label) - end - - it "contains the \"falsey\"" do - value = 42 - partial = new_partial(value) - matcher = Spectator::Matchers::TruthyMatcher.new(false) - match_data = matcher.match(partial) - match_data.negated_message.should contain("falsey") - end - end - end - end - end - - describe "#<" do - it "returns a LessThanMatcher" do - value = 0 - matcher = be_comparison < value - matcher.should be_a(Spectator::Matchers::LessThanMatcher(typeof(value))) - end - - it "passes along the expected value" do - value = 42 - matcher = be_comparison < value - matcher.expected_value.should eq(value) - end - end - - describe "#<=" do - it "returns a LessThanEqualMatcher" do - value = 0 - matcher = be_comparison <= value - matcher.should be_a(Spectator::Matchers::LessThanEqualMatcher(typeof(value))) - end - - it "passes along the expected value" do - value = 42 - matcher = be_comparison <= value - matcher.expected_value.should eq(value) - end - end - - describe "#>" do - it "returns a GreaterThanMatcher" do - value = 0 - matcher = be_comparison > value - matcher.should be_a(Spectator::Matchers::GreaterThanMatcher(typeof(value))) - end - - it "passes along the expected value" do - value = 42 - matcher = be_comparison > value - matcher.expected_value.should eq(value) - end - end - - describe "#>=" do - it "returns a GreaterThanEqualMatcher" do - value = 0 - matcher = be_comparison >= value - matcher.should be_a(Spectator::Matchers::GreaterThanEqualMatcher(typeof(value))) - end - - it "passes along the expected value" do - value = 42 - matcher = be_comparison >= value - matcher.expected_value.should eq(value) - end - end - - describe "#==" do - it "returns an EqualityMatcher" do - value = 0 - matcher = be_comparison == value - matcher.should be_a(Spectator::Matchers::EqualityMatcher(typeof(value))) - end - - it "passes along the expected value" do - value = 42 - matcher = be_comparison == value - matcher.expected_value.should eq(value) - end - end - - describe "#!=" do - it "returns an InequalityMatcher" do - value = 0 - matcher = be_comparison != value - matcher.should be_a(Spectator::Matchers::InequalityMatcher(typeof(value))) - end - - it "passes along the expected value" do - value = 42 - matcher = be_comparison != value - matcher.expected_value.should eq(value) - end - end -end diff --git a/spec/matchers/type_matcher_spec.cr b/spec/matchers/type_matcher_spec.cr deleted file mode 100644 index 7489b28..0000000 --- a/spec/matchers/type_matcher_spec.cr +++ /dev/null @@ -1,125 +0,0 @@ -require "../spec_helper" - -describe Spectator::Matchers::TypeMatcher do - describe "#match" do - context "returned MatchData" do - describe "#matched?" do - context "with the same type" do - it "is true" do - value = "foobar" - partial = new_partial(value) - matcher = Spectator::Matchers::TypeMatcher(String).new - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - - context "with a different type" do - it "is false" do - value = "foobar" - partial = new_partial(value) - matcher = Spectator::Matchers::TypeMatcher(Int32).new - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - - context "with a parent type" do - it "is true" do - value = IO::Memory.new - partial = new_partial(value) - matcher = Spectator::Matchers::TypeMatcher(IO).new - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - - context "with a child type" do - it "is false" do - value = Exception.new("foobar") - partial = new_partial(value) - matcher = Spectator::Matchers::TypeMatcher(ArgumentError).new - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - - context "with a mix-in" do - it "is true" do - value = %i[a b c] - partial = new_partial(value) - matcher = Spectator::Matchers::TypeMatcher(Enumerable(Symbol)).new - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - end - - describe "#values" do - context "expected" do - it "is the expected type name" do - value = %i[a b c] - partial = new_partial(value) - matcher = Spectator::Matchers::TypeMatcher(String).new - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :expected)[:value].should eq(String) - end - end - - context "actual" do - it "is the actual type name" do - value = %i[a b c] - partial = new_partial(value) - matcher = Spectator::Matchers::TypeMatcher(String).new - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :actual)[:value].should eq(typeof(value)) - end - - it "is the runtime type name" do - value = 42.as(Int32?) - partial = new_partial(value) - matcher = Spectator::Matchers::TypeMatcher(String).new - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :actual)[:value].should eq(value.class) - end - end - end - - describe "#message" do - it "contains the actual label" do - value = 42 - label = "everything" - partial = new_partial(value, label) - matcher = Spectator::Matchers::TypeMatcher(String).new - match_data = matcher.match(partial) - match_data.message.should contain(label) - end - - it "contains the expected type" do - partial = new_partial(42) - matcher = Spectator::Matchers::TypeMatcher(String).new - match_data = matcher.match(partial) - match_data.message.should contain("String") - end - end - - describe "#negated_message" do - it "contains the actual label" do - value = 42 - label = "everything" - partial = new_partial(value, label) - matcher = Spectator::Matchers::TypeMatcher(String).new - match_data = matcher.match(partial) - match_data.negated_message.should contain(label) - end - - it "contains the expected type" do - partial = new_partial(42) - matcher = Spectator::Matchers::TypeMatcher(String).new - match_data = matcher.match(partial) - match_data.negated_message.should contain("String") - end - end - end - end -end diff --git a/spec/matchers/unordered_array_matcher_spec.cr b/spec/matchers/unordered_array_matcher_spec.cr deleted file mode 100644 index 5cea6f6..0000000 --- a/spec/matchers/unordered_array_matcher_spec.cr +++ /dev/null @@ -1,474 +0,0 @@ -require "../spec_helper" - -describe Spectator::Matchers::UnorderedArrayMatcher do - describe "#match" do - context "returned MatchData" do - context "with identical arrays" do - describe "#matched?" do - it "is true" do - array = %i[a b c] - partial = new_partial(array) - matcher = Spectator::Matchers::UnorderedArrayMatcher.new(array) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - - describe "#values" do - context "expected" do - it "is the expected array" do - array = %i[a b c] - partial = new_partial(array) - matcher = Spectator::Matchers::UnorderedArrayMatcher.new(array) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :expected)[:value].should eq(array) - end - end - - context "actual" do - it "is the actual array" do - array = %i[a b c] - partial = new_partial(array) - matcher = Spectator::Matchers::UnorderedArrayMatcher.new(array) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :actual)[:value].should eq(array) - end - end - end - - describe "#message" do - it "contains the actual label" do - array = %i[a b c] - label = "everything" - partial = new_partial(array, label) - matcher = Spectator::Matchers::UnorderedArrayMatcher.new(array) - match_data = matcher.match(partial) - match_data.message.should contain(label) - end - - it "contains the expected label" do - array = %i[a b c] - label = "everything" - partial = new_partial(array) - matcher = Spectator::Matchers::UnorderedArrayMatcher.new(array, label) - match_data = matcher.match(partial) - match_data.message.should contain(label) - end - - context "when expected label is omitted" do - it "contains stringified form of expected array" do - array1 = %i[a b c] - array2 = [1, 2, 3] - partial = new_partial(array1) - matcher = Spectator::Matchers::UnorderedArrayMatcher.new(array2) - match_data = matcher.match(partial) - match_data.message.should contain(array2.to_s) - end - end - end - - describe "#negated_message" do - it "contains the actual label" do - array = %i[a b c] - label = "everything" - partial = new_partial(array, label) - matcher = Spectator::Matchers::UnorderedArrayMatcher.new(array) - match_data = matcher.match(partial) - match_data.negated_message.should contain(label) - end - - it "contains the expected label" do - array = %i[a b c] - label = "everything" - partial = new_partial(array) - matcher = Spectator::Matchers::UnorderedArrayMatcher.new(array, label) - match_data = matcher.match(partial) - match_data.negated_message.should contain(label) - end - - context "when expected label is omitted" do - it "contains stringified form of expected array" do - array1 = %i[a b c] - array2 = [1, 2, 3] - partial = new_partial(array1) - matcher = Spectator::Matchers::UnorderedArrayMatcher.new(array2) - match_data = matcher.match(partial) - match_data.negated_message.should contain(array2.to_s) - end - end - end - end - - context "with identical unordered arrays" do - describe "#matched?" do - it "is true" do - array1 = %i[a b c] - array2 = %i[c a b] - partial = new_partial(array1) - matcher = Spectator::Matchers::UnorderedArrayMatcher.new(array2) - match_data = matcher.match(partial) - match_data.matched?.should be_true - end - end - - describe "#values" do - context "expected" do - it "is the expected array" do - array1 = %i[a b c] - array2 = %i[c a b] - partial = new_partial(array1) - matcher = Spectator::Matchers::UnorderedArrayMatcher.new(array2) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :expected)[:value].should eq(array2) - end - end - - context "actual" do - it "is the actual array" do - array1 = %i[a b c] - array2 = %i[c a b] - partial = new_partial(array1) - matcher = Spectator::Matchers::UnorderedArrayMatcher.new(array2) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :actual)[:value].should eq(array1) - end - end - end - - describe "#message" do - it "contains the actual label" do - array1 = %i[a b c] - array2 = %i[c a b] - label = "everything" - partial = new_partial(array1, label) - matcher = Spectator::Matchers::UnorderedArrayMatcher.new(array2) - match_data = matcher.match(partial) - match_data.message.should contain(label) - end - - it "contains the expected label" do - array1 = %i[a b c] - array2 = %i[c a b] - label = "everything" - partial = new_partial(array1) - matcher = Spectator::Matchers::UnorderedArrayMatcher.new(array2, label) - match_data = matcher.match(partial) - match_data.message.should contain(label) - end - - context "when expected label is omitted" do - it "contains stringified form of expected array" do - array1 = %i[a b c] - array2 = %i[c a b] - partial = new_partial(array1) - matcher = Spectator::Matchers::UnorderedArrayMatcher.new(array2) - match_data = matcher.match(partial) - match_data.message.should contain(array2.to_s) - end - end - end - - describe "#negated_message" do - it "contains the actual label" do - array1 = %i[a b c] - array2 = %i[c a b] - label = "everything" - partial = new_partial(array1, label) - matcher = Spectator::Matchers::UnorderedArrayMatcher.new(array2) - match_data = matcher.match(partial) - match_data.negated_message.should contain(label) - end - - it "contains the expected label" do - array1 = %i[a b c] - array2 = %i[c a b] - label = "everything" - partial = new_partial(array1) - matcher = Spectator::Matchers::UnorderedArrayMatcher.new(array2, label) - match_data = matcher.match(partial) - match_data.negated_message.should contain(label) - end - - context "when expected label is omitted" do - it "contains stringified form of expected array" do - array1 = %i[a b c] - array2 = %i[c a b] - partial = new_partial(array1) - matcher = Spectator::Matchers::UnorderedArrayMatcher.new(array2) - match_data = matcher.match(partial) - match_data.negated_message.should contain(array2.to_s) - end - end - end - end - - context "with arrays differing in size" do - describe "#matched?" do - it "is false" do - array1 = %i[a b c d e] - array2 = %i[a c e f] - partial = new_partial(array1) - matcher = Spectator::Matchers::UnorderedArrayMatcher.new(array2) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - - describe "#values" do - context "expected" do - it "is the expected array" do - array1 = %i[a b c d e] - array2 = %i[a c e f] - partial = new_partial(array1) - matcher = Spectator::Matchers::UnorderedArrayMatcher.new(array2) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :expected)[:value].should eq(array2) - end - end - - context "actual" do - it "is the actual array" do - array1 = %i[a b c d e] - array2 = %i[a c e f] - partial = new_partial(array1) - matcher = Spectator::Matchers::UnorderedArrayMatcher.new(array2) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :actual)[:value].should eq(array1) - end - end - - context "missing" do - it "is the missing items" do - array1 = %i[a b c d e] - array2 = %i[a c e f] - partial = new_partial(array1) - matcher = Spectator::Matchers::UnorderedArrayMatcher.new(array2) - match_data = matcher.match(partial) - missing = match_data_value_sans_prefix(match_data.values, :missing)[:value].as(typeof(array2)) - missing.should contain(:f) - end - end - - context "extra" do - it "is the extra items" do - array1 = %i[a b c d e] - array2 = %i[a c e f] - partial = new_partial(array1) - matcher = Spectator::Matchers::UnorderedArrayMatcher.new(array2) - match_data = matcher.match(partial) - extra = match_data_value_sans_prefix(match_data.values, :extra)[:value].as(typeof(array1)) - extra.should contain(:b) - extra.should contain(:d) - end - end - end - - describe "#message" do - it "contains the actual label" do - array1 = %i[a b c d e] - array2 = %i[a c e f] - label = "everything" - partial = new_partial(array1, label) - matcher = Spectator::Matchers::UnorderedArrayMatcher.new(array2) - match_data = matcher.match(partial) - match_data.message.should contain(label) - end - - it "contains the expected label" do - array1 = %i[a b c d e] - array2 = %i[a c e f] - label = "everything" - partial = new_partial(array1) - matcher = Spectator::Matchers::UnorderedArrayMatcher.new(array2, label) - match_data = matcher.match(partial) - match_data.message.should contain(label) - end - - context "when expected label is omitted" do - it "contains stringified form of expected array" do - array1 = %i[a b c d e] - array2 = %i[a c e f] - partial = new_partial(array1) - matcher = Spectator::Matchers::UnorderedArrayMatcher.new(array2) - match_data = matcher.match(partial) - match_data.message.should contain(array2.to_s) - end - end - end - - describe "#negated_message" do - it "contains the actual label" do - array1 = %i[a b c d e] - array2 = %i[a c e f] - label = "everything" - partial = new_partial(array1, label) - matcher = Spectator::Matchers::UnorderedArrayMatcher.new(array2) - match_data = matcher.match(partial) - match_data.negated_message.should contain(label) - end - - it "contains the expected label" do - array1 = %i[a b c d e] - array2 = %i[a c e f] - label = "everything" - partial = new_partial(array1) - matcher = Spectator::Matchers::UnorderedArrayMatcher.new(array2, label) - match_data = matcher.match(partial) - match_data.negated_message.should contain(label) - end - - context "when expected label is omitted" do - it "contains stringified form of expected array" do - array1 = %i[a b c d e] - array2 = %i[a c e f] - partial = new_partial(array1) - matcher = Spectator::Matchers::UnorderedArrayMatcher.new(array2) - match_data = matcher.match(partial) - match_data.negated_message.should contain(array2.to_s) - end - end - end - end - - context "with arrays differing in content" do - describe "#matched?" do - it "is false" do - array1 = %i[a b c] - array2 = %i[x y z] - partial = new_partial(array1) - matcher = Spectator::Matchers::UnorderedArrayMatcher.new(array2) - match_data = matcher.match(partial) - match_data.matched?.should be_false - end - end - - describe "#values" do - context "expected" do - it "is the expected array" do - array1 = %i[a b c] - array2 = %i[x y z] - partial = new_partial(array1) - matcher = Spectator::Matchers::UnorderedArrayMatcher.new(array2) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :expected)[:value].should eq(array2) - end - end - - context "actual" do - it "is the actual array" do - array1 = %i[a b c] - array2 = %i[x y z] - partial = new_partial(array1) - matcher = Spectator::Matchers::UnorderedArrayMatcher.new(array2) - match_data = matcher.match(partial) - match_data_value_sans_prefix(match_data.values, :actual)[:value].should eq(array1) - end - end - - context "missing" do - it "is the missing items" do - array1 = %i[a b c] - array2 = %i[x y z] - partial = new_partial(array1) - matcher = Spectator::Matchers::UnorderedArrayMatcher.new(array2) - match_data = matcher.match(partial) - missing = match_data_value_sans_prefix(match_data.values, :missing)[:value].as(typeof(array2)) - missing.should contain(:x) - missing.should contain(:y) - missing.should contain(:z) - end - end - - context "extra" do - it "is the extra items" do - array1 = %i[a b c] - array2 = %i[x y z] - partial = new_partial(array1) - matcher = Spectator::Matchers::UnorderedArrayMatcher.new(array2) - match_data = matcher.match(partial) - extra = match_data_value_sans_prefix(match_data.values, :extra)[:value].as(typeof(array1)) - extra.should contain(:a) - extra.should contain(:b) - extra.should contain(:c) - end - end - end - - describe "#message" do - it "contains the actual label" do - array1 = %i[a b c] - array2 = %i[x y z] - label = "everything" - partial = new_partial(array1, label) - matcher = Spectator::Matchers::UnorderedArrayMatcher.new(array2) - match_data = matcher.match(partial) - match_data.message.should contain(label) - end - - it "contains the expected label" do - array1 = %i[a b c] - array2 = %i[x y z] - label = "everything" - partial = new_partial(array1) - matcher = Spectator::Matchers::UnorderedArrayMatcher.new(array2, label) - match_data = matcher.match(partial) - match_data.message.should contain(label) - end - - context "when expected label is omitted" do - it "contains stringified form of expected array" do - array1 = %i[a b c] - array2 = %i[x y z] - partial = new_partial(array1) - matcher = Spectator::Matchers::UnorderedArrayMatcher.new(array2) - match_data = matcher.match(partial) - match_data.message.should contain(array2.to_s) - end - end - end - - describe "#negated_message" do - it "mentions content" do - array1 = %i[a b c] - array2 = %i[x y z] - partial = new_partial(array1) - matcher = Spectator::Matchers::UnorderedArrayMatcher.new(array2) - match_data = matcher.match(partial) - match_data.negated_message.should contain("content") - end - - it "contains the actual label" do - array1 = %i[a b c] - array2 = %i[x y z] - label = "everything" - partial = new_partial(array1, label) - matcher = Spectator::Matchers::UnorderedArrayMatcher.new(array2) - match_data = matcher.match(partial) - match_data.negated_message.should contain(label) - end - - it "contains the expected label" do - array1 = %i[a b c] - array2 = %i[x y z] - label = "everything" - partial = new_partial(array1) - matcher = Spectator::Matchers::UnorderedArrayMatcher.new(array2, label) - match_data = matcher.match(partial) - match_data.negated_message.should contain(label) - end - - context "when expected label is omitted" do - it "contains stringified form of expected array" do - array1 = %i[a b c] - array2 = %i[x y z] - partial = new_partial(array1) - matcher = Spectator::Matchers::UnorderedArrayMatcher.new(array2) - match_data = matcher.match(partial) - match_data.negated_message.should contain(array2.to_s) - end - end - end - end - end - end -end From a54e406fecb6542341604e5f838022912e1e5e6f Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Fri, 9 Aug 2019 15:32:22 -0600 Subject: [PATCH 70/78] Clean up expectation specs Removed tests that are no longer valid or non-trivial to update. --- spec/expectation_failed_spec.cr | 2 +- .../block_expectation_partial_spec.cr | 168 ------------------ spec/expectations/expectation_spec.cr | 134 ++------------ .../value_expectation_partial_spec.cr | 166 ----------------- spec/helpers/expectations_helper.cr | 22 ++- 5 files changed, 34 insertions(+), 458 deletions(-) delete mode 100644 spec/expectations/block_expectation_partial_spec.cr delete mode 100644 spec/expectations/value_expectation_partial_spec.cr diff --git a/spec/expectation_failed_spec.cr b/spec/expectation_failed_spec.cr index 152967e..54c5d1d 100644 --- a/spec/expectation_failed_spec.cr +++ b/spec/expectation_failed_spec.cr @@ -13,7 +13,7 @@ describe Spectator::ExpectationFailed do it "is the same as the expectation's #actual_message" do expectation = new_unsatisfied_expectation error = Spectator::ExpectationFailed.new(expectation) - error.message.should eq(expectation.actual_message) + error.message.should eq(expectation.failure_message) end end end diff --git a/spec/expectations/block_expectation_partial_spec.cr b/spec/expectations/block_expectation_partial_spec.cr deleted file mode 100644 index ea54f3a..0000000 --- a/spec/expectations/block_expectation_partial_spec.cr +++ /dev/null @@ -1,168 +0,0 @@ -require "../spec_helper" - -describe Spectator::Expectations::BlockExpectationPartial do - describe "#actual" do - context "with a label" do - it "contains the value passed to the constructor" do - actual = ->{ 777 } - partial = Spectator::Expectations::BlockExpectationPartial.new(actual, actual.to_s, __FILE__, __LINE__) - partial.actual.should eq(actual.call) - end - end - - context "without a label" do - it "contains the value passed to the constructor" do - actual = ->{ 777 } - partial = Spectator::Expectations::BlockExpectationPartial.new(actual, __FILE__, __LINE__) - partial.actual.should eq(actual.call) - end - end - end - - describe "#label" do - context "when provided" do - it "contains the value passed to the constructor" do - actual = ->{ 777 } - label = "lucky" - partial = Spectator::Expectations::BlockExpectationPartial.new(actual, label, __FILE__, __LINE__) - partial.label.should eq(label) - end - end - - context "when omitted" do - it "contains \"proc\"" do - actual = ->{ 777 } - partial = Spectator::Expectations::BlockExpectationPartial.new(actual, __FILE__, __LINE__) - partial.label.should match(/proc/i) - end - end - end - - describe "#source_file" do - it "is the expected value" do - block = ->{ 42 } - file = __FILE__ - partial = Spectator::Expectations::BlockExpectationPartial.new(block, file, __LINE__) - partial.source_file.should eq(file) - end - end - - describe "#source_line" do - it "is the expected value" do - block = ->{ 42 } - line = __LINE__ - partial = Spectator::Expectations::BlockExpectationPartial.new(block, __FILE__, line) - partial.source_line.should eq(line) - end - end - - describe "#to" do - it "reports an expectation" do - spy = SpyExample.create do - actual = ->{ 777 } - expected = 777 - partial = Spectator::Expectations::BlockExpectationPartial.new(actual, __FILE__, __LINE__) - matcher = Spectator::Matchers::EqualityMatcher.new(expected) - partial.to(matcher) - end - Spectator::Internals::Harness.run(spy) - spy.harness.expectations.size.should eq(1) - end - - it "reports multiple expectations" do - spy = SpyExample.create do - actual = ->{ 777 } - expected = 777 - partial = Spectator::Expectations::BlockExpectationPartial.new(actual, __FILE__, __LINE__) - matcher = Spectator::Matchers::EqualityMatcher.new(expected) - 5.times { partial.to(matcher) } - end - Spectator::Internals::Harness.run(spy) - spy.harness.expectations.size.should eq(5) - end - - context "with a met condition" do - it "reports a satisifed expectation" do - spy = SpyExample.create do - actual = ->{ 777 } - expected = 777 - partial = Spectator::Expectations::BlockExpectationPartial.new(actual, __FILE__, __LINE__) - matcher = Spectator::Matchers::EqualityMatcher.new(expected) - partial.to(matcher) - end - Spectator::Internals::Harness.run(spy) - spy.harness.expectations.first.satisfied?.should be_true - end - end - - context "with an unmet condition" do - it "reports an unsatisfied expectation" do - spy = SpyExample.create do - actual = ->{ 777 } - expected = 42 - partial = Spectator::Expectations::BlockExpectationPartial.new(actual, __FILE__, __LINE__) - matcher = Spectator::Matchers::EqualityMatcher.new(expected) - partial.to(matcher) - end - Spectator::Internals::Harness.run(spy) - spy.harness.expectations.first.satisfied?.should be_false - end - end - end - - {% for method in %i[to_not not_to] %} - describe "#" + {{method.id.stringify}} do - it "reports an expectation" do - spy = SpyExample.create do - actual = ->{ 777 } - expected = 777 - partial = Spectator::Expectations::BlockExpectationPartial.new(actual, __FILE__, __LINE__) - matcher = Spectator::Matchers::EqualityMatcher.new(expected) - partial.{{method.id}}(matcher) - end - Spectator::Internals::Harness.run(spy) - spy.harness.expectations.size.should eq(1) - end - - it "reports multiple expectations" do - spy = SpyExample.create do - actual = ->{ 777 } - expected = 42 - partial = Spectator::Expectations::BlockExpectationPartial.new(actual, __FILE__, __LINE__) - matcher = Spectator::Matchers::EqualityMatcher.new(expected) - 5.times { partial.{{method.id}}(matcher) } - end - Spectator::Internals::Harness.run(spy) - spy.harness.expectations.size.should eq(5) - end - - context "with a met condition" do - it "reports an unsatisifed expectation" do - spy = SpyExample.create do - actual = ->{ 777 } - expected = 777 - partial = Spectator::Expectations::BlockExpectationPartial.new(actual, __FILE__, __LINE__) - matcher = Spectator::Matchers::EqualityMatcher.new(expected) - partial.{{method.id}}(matcher) - end - Spectator::Internals::Harness.run(spy) - spy.harness.expectations.first.satisfied?.should be_false - end - end - - context "with an unmet condition" do - it "reports an satisfied expectation" do - spy = SpyExample.create do - actual = ->{ 777 } - expected = 42 - partial = Spectator::Expectations::BlockExpectationPartial.new(actual, __FILE__, __LINE__) - matcher = Spectator::Matchers::EqualityMatcher.new(expected) - partial.{{method.id}}(matcher) - end - Spectator::Internals::Harness.run(spy) - spy.harness.expectations.first.satisfied?.should be_true - end - end - end - {% end %} -end diff --git a/spec/expectations/expectation_spec.cr b/spec/expectations/expectation_spec.cr index 176fd72..06540fc 100644 --- a/spec/expectations/expectation_spec.cr +++ b/spec/expectations/expectation_spec.cr @@ -5,18 +5,22 @@ describe Spectator::Expectations::Expectation do context "with a successful match" do it "is true" do value = 42 - match_data = new_matcher(value).match(new_partial(value)) + matcher = new_matcher(value) + partial = new_partial(value) + match_data = matcher.match(partial.actual) match_data.matched?.should be_true # Sanity check. - expectation = Spectator::Expectations::Expectation.new(match_data, false) + expectation = Spectator::Expectations::Expectation.new(match_data, partial.source) expectation.satisfied?.should be_true end context "when negated" do it "is false" do value = 42 - match_data = new_matcher(value).match(new_partial(value)) - match_data.matched?.should be_true # Sanity check. - expectation = Spectator::Expectations::Expectation.new(match_data, true) + matcher = new_matcher(value) + partial = new_partial(value) + match_data = matcher.negated_match(partial.actual) + match_data.matched?.should be_false # Sanity check. + expectation = Spectator::Expectations::Expectation.new(match_data, partial.source) expectation.satisfied?.should be_false end end @@ -24,126 +28,24 @@ describe Spectator::Expectations::Expectation do context "with an unsuccessful match" do it "is false" do - match_data = new_matcher(42).match(new_partial(777)) + matcher = new_matcher(42) + partial = new_partial(777) + match_data = matcher.match(partial.actual) match_data.matched?.should be_false # Sanity check. - expectation = Spectator::Expectations::Expectation.new(match_data, false) + expectation = Spectator::Expectations::Expectation.new(match_data, partial.source) expectation.satisfied?.should be_false end context "when negated" do it "is true" do - match_data = new_matcher(42).match(new_partial(777)) - match_data.matched?.should be_false # Sanity check. - expectation = Spectator::Expectations::Expectation.new(match_data, true) + matcher = new_matcher(42) + partial = new_partial(777) + match_data = matcher.negated_match(partial.actual) + match_data.matched?.should be_true # Sanity check. + expectation = Spectator::Expectations::Expectation.new(match_data, partial.source) expectation.satisfied?.should be_true end end end end - - describe "#values" do - it "is the same as the match data values" do - value = 42 - match_data = new_matcher(value).match(new_partial(value)) - expectation = Spectator::Expectations::Expectation.new(match_data, false) - expectation_values = expectation.values - match_data.values.zip(expectation_values).each do |m, e| - m.label.should eq(e.label) - m.value.value.should eq(e.value.value) - end - end - - context "when negated" do - it "negates all negatable values" do - value = 42 - match_data = new_matcher(value).match(new_partial(value)) - expectation = Spectator::Expectations::Expectation.new(match_data, true) - expectation.values.each do |labeled_value| - label = labeled_value.label - value = labeled_value.value - value.to_s.should start_with(/not/i) if label == :expected - end - end - end - end - - describe "#actual_message" do - context "with a successful match" do - it "equals the matcher's #message" do - value = 42 - match_data = new_matcher(value).match(new_partial(value)) - match_data.matched?.should be_true # Sanity check. - expectation = Spectator::Expectations::Expectation.new(match_data, false) - expectation.actual_message.should eq(match_data.message) - end - - context "when negated" do - it "equals the matcher's #message" do - value = 42 - match_data = new_matcher(value).match(new_partial(value)) - match_data.matched?.should be_true # Sanity check. - expectation = Spectator::Expectations::Expectation.new(match_data, true) - expectation.actual_message.should eq(match_data.message) - end - end - end - - context "with an unsuccessful match" do - it "equals the matcher's #negated_message" do - match_data = new_matcher(42).match(new_partial(777)) - match_data.matched?.should be_false # Sanity check. - expectation = Spectator::Expectations::Expectation.new(match_data, false) - expectation.actual_message.should eq(match_data.negated_message) - end - - context "when negated" do - it "equals the matcher's #negated_message" do - match_data = new_matcher(42).match(new_partial(777)) - match_data.matched?.should be_false # Sanity check. - expectation = Spectator::Expectations::Expectation.new(match_data, true) - expectation.actual_message.should eq(match_data.negated_message) - end - end - end - end - - describe "#expected_message" do - context "with a successful match" do - it "equals the matcher's #message" do - value = 42 - match_data = new_matcher(value).match(new_partial(value)) - match_data.matched?.should be_true # Sanity check. - expectation = Spectator::Expectations::Expectation.new(match_data, false) - expectation.expected_message.should eq(match_data.message) - end - - context "when negated" do - it "equals the matcher's #negated_message" do - value = 42 - match_data = new_matcher(value).match(new_partial(value)) - match_data.matched?.should be_true # Sanity check. - expectation = Spectator::Expectations::Expectation.new(match_data, true) - expectation.expected_message.should eq(match_data.negated_message) - end - end - end - - context "with an unsuccessful match" do - it "equals the matcher's #message" do - match_data = new_matcher(42).match(new_partial(777)) - match_data.matched?.should be_false # Sanity check. - expectation = Spectator::Expectations::Expectation.new(match_data, false) - expectation.expected_message.should eq(match_data.message) - end - - context "when negated" do - it "equals the matcher's #negated_message" do - match_data = new_matcher(42).match(new_partial(777)) - match_data.matched?.should be_false # Sanity check. - expectation = Spectator::Expectations::Expectation.new(match_data, true) - expectation.expected_message.should eq(match_data.negated_message) - end - end - end - end end diff --git a/spec/expectations/value_expectation_partial_spec.cr b/spec/expectations/value_expectation_partial_spec.cr deleted file mode 100644 index b7422fb..0000000 --- a/spec/expectations/value_expectation_partial_spec.cr +++ /dev/null @@ -1,166 +0,0 @@ -require "../spec_helper" - -describe Spectator::Expectations::ValueExpectationPartial do - describe "#actual" do - context "with a label" do - it "contains the value passed to the constructor" do - actual = 777 - partial = Spectator::Expectations::ValueExpectationPartial.new(actual, actual.to_s, __FILE__, __LINE__) - partial.actual.should eq(actual) - end - end - - context "without a label" do - it "contains the value passed to the constructor" do - actual = 777 - partial = Spectator::Expectations::ValueExpectationPartial.new(actual, __FILE__, __LINE__) - partial.actual.should eq(actual) - end - end - end - - describe "#label" do - context "when provided" do - it "contains the value passed to the constructor" do - actual = 777 - label = "lucky" - partial = Spectator::Expectations::ValueExpectationPartial.new(actual, label, __FILE__, __LINE__) - partial.label.should eq(label) - end - end - - context "when omitted" do - it "contains a stringified version of #actual" do - actual = 777 - partial = Spectator::Expectations::ValueExpectationPartial.new(actual, __FILE__, __LINE__) - partial.label.should eq(actual.to_s) - end - end - end - - describe "#source_file" do - it "is the expected value" do - file = __FILE__ - partial = Spectator::Expectations::ValueExpectationPartial.new(42, file, __LINE__) - partial.source_file.should eq(file) - end - end - - describe "#source_line" do - it "is the expected value" do - line = __LINE__ - partial = Spectator::Expectations::ValueExpectationPartial.new(42, __FILE__, line) - partial.source_line.should eq(line) - end - end - - describe "#to" do - it "reports an expectation" do - spy = SpyExample.create do - actual = 777 - expected = 777 - partial = Spectator::Expectations::ValueExpectationPartial.new(actual, __FILE__, __LINE__) - matcher = Spectator::Matchers::EqualityMatcher.new(expected) - partial.to(matcher) - end - Spectator::Internals::Harness.run(spy) - spy.harness.expectations.size.should eq(1) - end - - it "reports multiple expectations" do - spy = SpyExample.create do - actual = 777 - expected = 777 - partial = Spectator::Expectations::ValueExpectationPartial.new(actual, __FILE__, __LINE__) - matcher = Spectator::Matchers::EqualityMatcher.new(expected) - 5.times { partial.to(matcher) } - end - Spectator::Internals::Harness.run(spy) - spy.harness.expectations.size.should eq(5) - end - - context "with a met condition" do - it "reports a satisifed expectation" do - spy = SpyExample.create do - actual = 777 - expected = 777 - partial = Spectator::Expectations::ValueExpectationPartial.new(actual, __FILE__, __LINE__) - matcher = Spectator::Matchers::EqualityMatcher.new(expected) - partial.to(matcher) - end - Spectator::Internals::Harness.run(spy) - spy.harness.expectations.first.satisfied?.should be_true - end - end - - context "with an unmet condition" do - it "reports an unsatisfied expectation" do - spy = SpyExample.create do - actual = 777 - expected = 42 - partial = Spectator::Expectations::ValueExpectationPartial.new(actual, __FILE__, __LINE__) - matcher = Spectator::Matchers::EqualityMatcher.new(expected) - partial.to(matcher) - end - Spectator::Internals::Harness.run(spy) - spy.harness.expectations.first.satisfied?.should be_false - end - end - end - - {% for method in %i[to_not not_to] %} - describe "#" + {{method.id.stringify}} do - it "reports an expectation" do - spy = SpyExample.create do - actual = 777 - expected = 777 - partial = Spectator::Expectations::ValueExpectationPartial.new(actual, __FILE__, __LINE__) - matcher = Spectator::Matchers::EqualityMatcher.new(expected) - partial.{{method.id}}(matcher) - end - Spectator::Internals::Harness.run(spy) - spy.harness.expectations.size.should eq(1) - end - - it "reports multiple expectations" do - spy = SpyExample.create do - actual = 777 - expected = 42 - partial = Spectator::Expectations::ValueExpectationPartial.new(actual, __FILE__, __LINE__) - matcher = Spectator::Matchers::EqualityMatcher.new(expected) - 5.times { partial.{{method.id}}(matcher) } - end - Spectator::Internals::Harness.run(spy) - spy.harness.expectations.size.should eq(5) - end - - context "with a met condition" do - it "reports an unsatisifed expectation" do - spy = SpyExample.create do - actual = 777 - expected = 777 - partial = Spectator::Expectations::ValueExpectationPartial.new(actual, __FILE__, __LINE__) - matcher = Spectator::Matchers::EqualityMatcher.new(expected) - partial.{{method.id}}(matcher) - end - Spectator::Internals::Harness.run(spy) - spy.harness.expectations.first.satisfied?.should be_false - end - end - - context "with an unmet condition" do - it "reports an satisfied expectation" do - spy = SpyExample.create do - actual = 777 - expected = 42 - partial = Spectator::Expectations::ValueExpectationPartial.new(actual, __FILE__, __LINE__) - matcher = Spectator::Matchers::EqualityMatcher.new(expected) - partial.{{method.id}}(matcher) - end - Spectator::Internals::Harness.run(spy) - spy.harness.expectations.first.satisfied?.should be_true - end - end - end - {% end %} -end diff --git a/spec/helpers/expectations_helper.cr b/spec/helpers/expectations_helper.cr index ff7c339..0096f84 100644 --- a/spec/helpers/expectations_helper.cr +++ b/spec/helpers/expectations_helper.cr @@ -1,30 +1,38 @@ # Utility methods for creating expectations, partials, and matchers. def new_partial(actual : T, label : String) forall T - Spectator::Expectations::ValueExpectationPartial.new(actual, label, __FILE__, __LINE__) + test_value = Spectator::TestValue.new(actual, label) + source = Spectator::Source.new(__FILE__, __LINE__) + Spectator::Expectations::ExpectationPartial.new(test_value, source) end def new_partial(actual : T = 123) forall T - Spectator::Expectations::ValueExpectationPartial.new(actual, __FILE__, __LINE__) + test_value = Spectator::TestValue.new(actual) + source = Spectator::Source.new(__FILE__, __LINE__) + Spectator::Expectations::ExpectationPartial.new(test_value, source) end def new_block_partial(label = "BLOCK", &block) - Spectator::Expectations::BlockExpectationPartial.new(block, label, __FILE__, __LINE__) + test_block = Spectator::TestBlock.new(block, label) + source = Spectator::Source.new(__FILE__, __LINE__) + Spectator::Expectations::ExpectationPartial.new(test_block, source) end def new_matcher(expected : T, label : String) forall T - Spectator::Matchers::EqualityMatcher.new(expected, label) + test_value = Spectator::TestValue.new(expected, label) + Spectator::Matchers::EqualityMatcher.new(test_value) end def new_matcher(expected : T = 123) forall T - Spectator::Matchers::EqualityMatcher.new(expected) + test_value = Spectator::TestValue.new(expected) + Spectator::Matchers::EqualityMatcher.new(test_value) end def new_expectation(expected : ExpectedType = 123, actual : ActualType = 123) forall ExpectedType, ActualType partial = new_partial(actual, "foo") matcher = new_matcher(expected, "bar") - match_data = matcher.match(partial) - Spectator::Expectations::Expectation.new(match_data, false) + match_data = matcher.match(partial.actual) + Spectator::Expectations::Expectation.new(match_data, partial.source) end def new_satisfied_expectation(value : T = 123) forall T From efd0ab089d693e8d261772c468fecf3d21b1cfb3 Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Fri, 9 Aug 2019 16:58:35 -0600 Subject: [PATCH 71/78] Define type annotations for match methods Hopefully this speeds up some compilation. --- src/spectator/matchers/array_matcher.cr | 4 ++-- src/spectator/matchers/attributes_matcher.cr | 4 ++-- src/spectator/matchers/end_with_matcher.cr | 4 ++-- src/spectator/matchers/exception_matcher.cr | 4 ++-- src/spectator/matchers/have_predicate_matcher.cr | 4 ++-- src/spectator/matchers/matcher.cr | 4 ++-- src/spectator/matchers/predicate_matcher.cr | 4 ++-- src/spectator/matchers/respond_matcher.cr | 4 ++-- src/spectator/matchers/standard_matcher.cr | 4 ++-- src/spectator/matchers/start_with_matcher.cr | 4 ++-- src/spectator/matchers/unordered_array_matcher.cr | 4 ++-- 11 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/spectator/matchers/array_matcher.cr b/src/spectator/matchers/array_matcher.cr index 28080ea..e03f584 100644 --- a/src/spectator/matchers/array_matcher.cr +++ b/src/spectator/matchers/array_matcher.cr @@ -16,7 +16,7 @@ module Spectator::Matchers "contains exactly #{expected.label}" end - def match(actual) + def match(actual : TestExpression(T)) : MatchData forall T actual_elements = actual.value.to_a expected_elements = expected.value.to_a index = compare_arrays(expected_elements, actual_elements) @@ -31,7 +31,7 @@ module Spectator::Matchers end end - def negated_match(actual) + def negated_match(actual : TestExpression(T)) : MatchData forall T actual_elements = actual.value.to_a expected_elements = expected.value.to_a diff --git a/src/spectator/matchers/attributes_matcher.cr b/src/spectator/matchers/attributes_matcher.cr index be5cbbc..437b80f 100644 --- a/src/spectator/matchers/attributes_matcher.cr +++ b/src/spectator/matchers/attributes_matcher.cr @@ -19,7 +19,7 @@ module Spectator::Matchers "has attributes #{expected.label}" end - def match(actual) + def match(actual : TestExpression(T)) : MatchData forall T snapshot = snapshot_values(actual.value) if match?(snapshot) SuccessfulMatchData.new @@ -28,7 +28,7 @@ module Spectator::Matchers end end - def negated_match(actual) + def negated_match(actual : TestExpression(T)) : MatchData forall T snapshot = snapshot_values(actual.value) if match?(snapshot) FailedMatchData.new("#{actual.label} has attributes #{expected.label}", **values(snapshot)) diff --git a/src/spectator/matchers/end_with_matcher.cr b/src/spectator/matchers/end_with_matcher.cr index 516e411..3dbd9e6 100644 --- a/src/spectator/matchers/end_with_matcher.cr +++ b/src/spectator/matchers/end_with_matcher.cr @@ -16,7 +16,7 @@ module Spectator::Matchers "ends with #{expected.label}" end - def match(actual) + def match(actual : TestExpression(T)) : MatchData forall T if (value = actual.value).responds_to?(:ends_with?) match_ends_with(value, actual.label) else @@ -50,7 +50,7 @@ module Spectator::Matchers end end - def negated_match(actual) + def negated_match(actual : TestExpression(T)) : MatchData forall T if actual.value.responds_to?(:ends_with?) negated_match_ends_with(actual) else diff --git a/src/spectator/matchers/exception_matcher.cr b/src/spectator/matchers/exception_matcher.cr index b39ceb9..3641c15 100644 --- a/src/spectator/matchers/exception_matcher.cr +++ b/src/spectator/matchers/exception_matcher.cr @@ -23,7 +23,7 @@ module Spectator::Matchers end end - def match(actual) + def match(actual : TestExpression(T)) : MatchData forall T exception = capture_exception { actual.value } if exception.nil? FailedMatchData.new("#{actual.label} did not raise", expected: ExceptionType.inspect) @@ -52,7 +52,7 @@ module Spectator::Matchers end end - def negated_match(actual) + def negated_match(actual : TestExpression(T)) : MatchData forall T exception = capture_exception { actual.value } if exception.nil? SuccessfulMatchData.new diff --git a/src/spectator/matchers/have_predicate_matcher.cr b/src/spectator/matchers/have_predicate_matcher.cr index 3bb881a..525f157 100644 --- a/src/spectator/matchers/have_predicate_matcher.cr +++ b/src/spectator/matchers/have_predicate_matcher.cr @@ -16,7 +16,7 @@ module Spectator::Matchers "has #{expected.label}" end - def match(actual) + def match(actual : TestExpression(T)) : MatchData forall T snapshot = snapshot_values(actual.value) if match?(snapshot) SuccessfulMatchData.new @@ -25,7 +25,7 @@ module Spectator::Matchers end end - def negated_match(actual) + def negated_match(actual : TestExpression(T)) : MatchData forall T snapshot = snapshot_values(actual.value) if match?(snapshot) FailedMatchData.new("#{actual.label} has #{expected.label}", **values(snapshot)) diff --git a/src/spectator/matchers/matcher.cr b/src/spectator/matchers/matcher.cr index 9120909..7845700 100644 --- a/src/spectator/matchers/matcher.cr +++ b/src/spectator/matchers/matcher.cr @@ -14,8 +14,8 @@ module Spectator::Matchers # The phrasing should be such that it reads "it ___." abstract def description : String - abstract def match(actual) : MatchData + abstract def match(actual : TestExpression(T)) : MatchData forall T - abstract def negated_match(actual) : MatchData + abstract def negated_match(actual : TestExpression(T)) : MatchData forall T end end diff --git a/src/spectator/matchers/predicate_matcher.cr b/src/spectator/matchers/predicate_matcher.cr index f8cb737..5ab5582 100644 --- a/src/spectator/matchers/predicate_matcher.cr +++ b/src/spectator/matchers/predicate_matcher.cr @@ -15,7 +15,7 @@ module Spectator::Matchers "is #{expected.label}" end - def match(actual) + def match(actual : TestExpression(T)) : MatchData forall T snapshot = snapshot_values(actual.value) if match?(snapshot) SuccessfulMatchData.new @@ -24,7 +24,7 @@ module Spectator::Matchers end end - def negated_match(actual) + def negated_match(actual : TestExpression(T)) : MatchData forall T snapshot = snapshot_values(actual.value) if match?(snapshot) FailedMatchData.new("#{actual.label} is #{expected.label}", **values(snapshot)) diff --git a/src/spectator/matchers/respond_matcher.cr b/src/spectator/matchers/respond_matcher.cr index 99a728f..dbecaa0 100644 --- a/src/spectator/matchers/respond_matcher.cr +++ b/src/spectator/matchers/respond_matcher.cr @@ -15,7 +15,7 @@ module Spectator::Matchers {{ExpectedType.keys.map { |e| "##{e}".id }.splat.stringify}} end - def match(actual) + def match(actual : TestExpression(T)) : MatchData forall T snapshot = snapshot_values(actual.value) if match?(snapshot) SuccessfulMatchData.new @@ -24,7 +24,7 @@ module Spectator::Matchers end end - def negated_match(actual) + def negated_match(actual : TestExpression(T)) : MatchData forall T snapshot = snapshot_values(actual.value) if match?(snapshot) FailedMatchData.new("#{actual.label} responds to #{label}", **snapshot) diff --git a/src/spectator/matchers/standard_matcher.cr b/src/spectator/matchers/standard_matcher.cr index 0e99e38..3c1d109 100644 --- a/src/spectator/matchers/standard_matcher.cr +++ b/src/spectator/matchers/standard_matcher.cr @@ -40,7 +40,7 @@ module Spectator::Matchers values(actual) end - def match(actual) + def match(actual : TestExpression(T)) : MatchData forall T if match?(actual) SuccessfulMatchData.new else @@ -48,7 +48,7 @@ module Spectator::Matchers end end - def negated_match(actual) + def negated_match(actual : TestExpression(T)) : MatchData forall T if does_not_match?(actual) SuccessfulMatchData.new else diff --git a/src/spectator/matchers/start_with_matcher.cr b/src/spectator/matchers/start_with_matcher.cr index 539c73d..2e7961f 100644 --- a/src/spectator/matchers/start_with_matcher.cr +++ b/src/spectator/matchers/start_with_matcher.cr @@ -14,7 +14,7 @@ module Spectator::Matchers "starts with #{expected.label}" end - def match(actual) + def match(actual : TestExpression(T)) : MatchData forall T if (value = actual.value).responds_to?(:starts_with?) match_starts_with(value, actual.label) else @@ -48,7 +48,7 @@ module Spectator::Matchers end end - def negated_match(actual) + def negated_match(actual : TestExpression(T)) : MatchData forall T if (value = actual.value).responds_to?(:starts_with?) negated_match_starts_with(value, actual.label) else diff --git a/src/spectator/matchers/unordered_array_matcher.cr b/src/spectator/matchers/unordered_array_matcher.cr index 9014aa1..acef92f 100644 --- a/src/spectator/matchers/unordered_array_matcher.cr +++ b/src/spectator/matchers/unordered_array_matcher.cr @@ -13,7 +13,7 @@ module Spectator::Matchers "contains #{expected.label} in any order" end - def match(actual) + def match(actual : TestExpression(T)) : MatchData forall T actual_elements = actual.value.to_a expected_elements = expected.value.to_a missing, extra = array_diff(expected_elements, actual_elements) @@ -30,7 +30,7 @@ module Spectator::Matchers end end - def negated_match(actual) + def negated_match(actual : TestExpression(T)) : MatchData forall T actual_elements = actual.value.to_a expected_elements = expected.value.to_a missing, extra = array_diff(expected_elements, actual_elements) From db4eaca29169e2aa250b9674092f5ddb1053e33c Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Fri, 9 Aug 2019 17:21:12 -0600 Subject: [PATCH 72/78] Just assert the return value isn't nil --- src/spectator/expectations/expectation.cr | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/spectator/expectations/expectation.cr b/src/spectator/expectations/expectation.cr index f7bd03b..d073a5a 100644 --- a/src/spectator/expectations/expectation.cr +++ b/src/spectator/expectations/expectation.cr @@ -25,7 +25,7 @@ module Spectator::Expectations end def failure_message - @match_data.as(Matchers::FailedMatchData).failure_message + failure_message?.not_nil! end def values? @@ -33,7 +33,7 @@ module Spectator::Expectations end def values - @match_data.as(Matchers::FailedMatchData).values + values?.not_nil! end # Creates the JSON representation of the expectation. From 39f253952d6324248361a399676b549e806746f1 Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Fri, 9 Aug 2019 17:26:53 -0600 Subject: [PATCH 73/78] Add docs and some more type annotations --- src/spectator/expectations/expectation.cr | 9 +++ src/spectator/matchers/matcher.cr | 4 ++ src/spectator/matchers/standard_matcher.cr | 83 ++++++++++++++++++++-- src/spectator/matchers/value_matcher.cr | 47 +++++++++++- 4 files changed, 134 insertions(+), 9 deletions(-) diff --git a/src/spectator/expectations/expectation.cr b/src/spectator/expectations/expectation.cr index d073a5a..300f134 100644 --- a/src/spectator/expectations/expectation.cr +++ b/src/spectator/expectations/expectation.cr @@ -12,26 +12,34 @@ module Spectator::Expectations def initialize(@match_data : Matchers::MatchData, @source : Source) end + # Indicates whether the matcher was satisified. def satisfied? @match_data.matched? end + # Indicates that the expectation was not satisified. def failure? !satisfied? end + # Description of why the match failed. + # If nil, then the match was successful. def failure_message? @match_data.as?(Matchers::FailedMatchData).try(&.failure_message) end + # Description of why the match failed. def failure_message failure_message?.not_nil! end + # Additional information about the match, useful for debug. + # If nil, then the match was successful. def values? @match_data.as?(Matchers::FailedMatchData).try(&.values) end + # Additional information about the match, useful for debug. def values values?.not_nil! end @@ -47,6 +55,7 @@ module Spectator::Expectations end end + # Adds failure information to a JSON structure. private def failed_to_json(failed : Matchers::FailedMatchData, json : ::JSON::Builder) json.field("failure", failed.failure_message) json.field("values") do diff --git a/src/spectator/matchers/matcher.cr b/src/spectator/matchers/matcher.cr index 7845700..f5d0d4c 100644 --- a/src/spectator/matchers/matcher.cr +++ b/src/spectator/matchers/matcher.cr @@ -12,10 +12,14 @@ module Spectator::Matchers # it { is_expected.to do_something } # ``` # The phrasing should be such that it reads "it ___." + # where the blank is what is returned by this method. abstract def description : String + # Actually performs the test against the expression (value or block). abstract def match(actual : TestExpression(T)) : MatchData forall T + # Performs the test against the expression (value or block), but inverted. + # A successful match with `#match` should normally fail for this method, and vice-versa. abstract def negated_match(actual : TestExpression(T)) : MatchData forall T end end diff --git a/src/spectator/matchers/standard_matcher.cr b/src/spectator/matchers/standard_matcher.cr index 3c1d109..afb688b 100644 --- a/src/spectator/matchers/standard_matcher.cr +++ b/src/spectator/matchers/standard_matcher.cr @@ -5,41 +5,103 @@ require "./successful_match_data" module Spectator::Matchers # Provides common methods for matchers. + # + # The `#match` and `#negated_match` methods have an implementation + # that is suitable for most matchers. + # Matchers based on this class need to define `#match?` and `#failure_message`. + # If the matcher can be negated, + # the `#failure_message_when_negated` method needs to be overriden. + # Additionally, the `#does_not_match?` method can be specified + # if there's custom behavior for negated matches. + # If the matcher operates on or has extra data that is useful for debug, + # then the `#values` and `#negated_values` methods can be overriden. + # Finally, define a `#description` message that can be used for the one-liner "it" syntax. abstract struct StandardMatcher < Matcher # Message displayed when the matcher isn't satisifed. - # This is only called when `#matches?` returns false. - private abstract def failure_message(actual) : String + # + # This is only called when `#match?` returns false. + # + # The message should typically only contain the test expression labels. + # Actual values should be returned by `#values`. + private abstract def failure_message(actual : TestExpression(T)) : String forall T # Message displayed when the matcher isn't satisifed and is negated. + # # This is only called when `#does_not_match?` returns false. # # A default implementation of this method is provided, # which causes compilation to fail. # If the matcher supports negation, it must override this method. - private def failure_message_when_negated(actual) : String + # + # The message should typically only contain the test expression labels. + # Actual values should be returned by `#values`. + private def failure_message_when_negated(actual : TestExpression(T)) : String forall T {% raise "Negation with #{@type.name} is not supported." %} end # Checks whether the matcher is satisifed. - private abstract def match?(actual) : Bool + private abstract def match?(actual : TestExpression(T)) : Bool forall T # If the expectation is negated, then this method is called instead of `#match?`. + # # The default implementation of this method is to invert the result of `#match?`. # If the matcher requires custom handling of negated matches, # then this method should be overriden. # Remember to override `#failure_message_when_negated` as well. - private def does_not_match?(actual) : Bool + private def does_not_match?(actual : TestExpression(T)) : Bool forall T !match?(actual) end - private def values(actual) + # Additional information about the match failure. + # + # By default, just the actual value is produced. + # The return value must be a NamedTuple with Strings for each value. + # The tuple can be of any size, + # but the keys must be known at compile-time (as Symbols), + # and the values must be strings. + # Generally, the string values are produced by calling `#inspect` on the relevant object. + # It should look like this: + # ``` + # { + # expected: "foo", + # actual: "bar", + # } + # ``` + # + # The values should typically only contain the test expression values, not the labels. + # Labeled should be returned by `#failure_message`. + private def values(actual : TestExpression(T)) forall T {actual: actual.value.inspect} end - private def negated_values(actual) + # Additional information about the match failure when negated. + # + # By default, just the actual value is produced (same as `#values`). + # The return value must be a NamedTuple with Strings for each value. + # The tuple can be of any size, + # but the keys must be known at compile-time (as Symbols), + # and the values must be strings. + # Generally, the string values are produced by calling `#inspect` on the relevant object. + # It should look like this: + # ``` + # { + # expected: "Not foo", + # actual: "bar", + # } + # ``` + # + # The values should typically only contain the test expression values, not the labels. + # Labeled should be returned by `#failure_message_when_negated`. + private def negated_values(actual : TestExpression(T)) forall T values(actual) end + # Actually performs the test against the expression (value or block). + # + # This method calls the abstract `#match?` method. + # If it returns true, then a `SuccessfulMatchData` instance is returned. + # Otherwise, a `FailedMatchData` instance is returned. + # Additionally, `#failure_message` and `#values` are called for a failed match. def match(actual : TestExpression(T)) : MatchData forall T if match?(actual) SuccessfulMatchData.new @@ -48,6 +110,13 @@ module Spectator::Matchers end end + # Performs the test against the expression (value or block), but inverted. + # A successful match with `#match` should normally fail for this method, and vice-versa. + # + # This method calls the abstract `#does_not_match?` method. + # If it returns true, then a `SuccessfulMatchData` instance is returned. + # Otherwise, a `FailedMatchData` instance is returned. + # Additionally, `#failure_message_when_negated` and `#negated_values` are called for a failed match. def negated_match(actual : TestExpression(T)) : MatchData forall T if does_not_match?(actual) SuccessfulMatchData.new diff --git a/src/spectator/matchers/value_matcher.cr b/src/spectator/matchers/value_matcher.cr index 0710918..5049320 100644 --- a/src/spectator/matchers/value_matcher.cr +++ b/src/spectator/matchers/value_matcher.cr @@ -3,6 +3,18 @@ require "./standard_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. + # + # Matchers based on this class need to define `#match?` and `#failure_message`. + # If the matcher can be negated, + # the `#failure_message_when_negated` method needs to be overriden. + # Additionally, the `#does_not_match?` method can be specified + # if there's custom behavior for negated matches. + # If the matcher operates on or has extra data that is useful for debug, + # then the `#values` and `#negated_values` methods can be overriden. + # Finally, define a `#description` message that can be used for the one-liner "it" syntax. + # + # The failure messages should typically only contain the test expression labels. + # Actual values should be returned by `#values` and `#negated_values`. abstract struct ValueMatcher(ExpectedType) < StandardMatcher # Expected value. # Sub-types may use this value to test the expectation and generate message strings. @@ -13,11 +25,42 @@ module Spectator::Matchers def initialize(@expected : TestValue(ExpectedType)) end - private def values(actual) + # Additional information about the match failure. + # + # By default, just the actual and expected values are produced. + # The return value must be a NamedTuple with Strings for each value. + # The tuple can be of any size, + # but the keys must be known at compile-time (as Symbols), + # and the values must be strings. + # Generally, the string values are produced by calling `#inspect` on the relevant object. + # It should look like this: + # ``` + # { + # expected: "foo", + # actual: "bar", + # } + # ``` + private def values(actual : TestExpression(T)) forall T super.merge(expected: expected.value.inspect) end - private def negated_values(actual) + # Additional information about the match failure when negated. + # + # By default, just the actual and expected values are produced (same as `#values`). + # However, the expected value is prefixed with the word "Not". + # The return value must be a NamedTuple with Strings for each value. + # The tuple can be of any size, + # but the keys must be known at compile-time (as Symbols), + # and the values must be strings. + # Generally, the string values are produced by calling `#inspect` on the relevant object. + # It should look like this: + # ``` + # { + # expected: "Not foo", + # actual: "bar", + # } + # ``` + private def negated_values(actual : TestExpression(T)) forall T super.merge(expected: "Not #{expected.value.inspect}") end end From 37c8dd086500e0fcb4802b529e14ae8fee287509 Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Sat, 10 Aug 2019 09:55:26 -0600 Subject: [PATCH 74/78] Stringify respond_to bools --- src/spectator/matchers/respond_matcher.cr | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/spectator/matchers/respond_matcher.cr b/src/spectator/matchers/respond_matcher.cr index dbecaa0..00d63bb 100644 --- a/src/spectator/matchers/respond_matcher.cr +++ b/src/spectator/matchers/respond_matcher.cr @@ -20,14 +20,14 @@ module Spectator::Matchers if match?(snapshot) SuccessfulMatchData.new else - FailedMatchData.new("#{actual.label} does not respond to #{label}", **snapshot) + FailedMatchData.new("#{actual.label} does not respond to #{label}", **values(snapshot)) end end def negated_match(actual : TestExpression(T)) : MatchData forall T snapshot = snapshot_values(actual.value) if match?(snapshot) - FailedMatchData.new("#{actual.label} responds to #{label}", **snapshot) + FailedMatchData.new("#{actual.label} responds to #{label}", **values(snapshot)) else SuccessfulMatchData.new end @@ -45,6 +45,16 @@ module Spectator::Matchers {% end %} end + private def values(snapshot) + {% begin %} + { + {% for attribute in ExpectedType.keys %} + {{attribute}}: snapshot[{{attribute.symbolize}}].inspect, + {% end %} + } + {% end %} + end + private def match?(snapshot) # The snapshot did the hard work. # Here just check if all values are true. From d5fd21702a6890c7824e0234680a753cdc76ddec Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Sat, 10 Aug 2019 10:50:48 -0600 Subject: [PATCH 75/78] Add matcher docs --- src/spectator/matchers/array_matcher.cr | 20 ++++++++++++++++ src/spectator/matchers/attributes_matcher.cr | 10 ++++++++ src/spectator/matchers/case_matcher.cr | 17 ++++++++++++++ src/spectator/matchers/collection_matcher.cr | 17 ++++++++++++++ src/spectator/matchers/contain_matcher.cr | 21 ++++++++++++++++- src/spectator/matchers/empty_matcher.cr | 17 ++++++++++++++ src/spectator/matchers/end_with_matcher.cr | 16 +++++++++++++ src/spectator/matchers/equality_matcher.cr | 17 ++++++++++++++ src/spectator/matchers/exception_matcher.cr | 9 ++++++++ .../matchers/greater_than_equal_matcher.cr | 21 +++++++++++++++++ .../matchers/greater_than_matcher.cr | 23 ++++++++++++++++++- src/spectator/matchers/have_key_matcher.cr | 19 +++++++++++++++ src/spectator/matchers/have_matcher.cr | 19 +++++++++++++++ .../matchers/have_predicate_matcher.cr | 23 +++++++++++++++++++ src/spectator/matchers/have_value_matcher.cr | 19 +++++++++++++++ src/spectator/matchers/inequality_matcher.cr | 21 +++++++++++++++++ .../matchers/less_than_equal_matcher.cr | 21 +++++++++++++++++ src/spectator/matchers/less_than_matcher.cr | 21 +++++++++++++++++ src/spectator/matchers/nil_matcher.cr | 17 ++++++++++++++ src/spectator/matchers/predicate_matcher.cr | 23 +++++++++++++++++++ src/spectator/matchers/range_matcher.cr | 21 +++++++++++++++++ src/spectator/matchers/reference_matcher.cr | 17 ++++++++++++++ src/spectator/matchers/respond_matcher.cr | 9 ++++++++ src/spectator/matchers/size_matcher.cr | 21 +++++++++++++++++ src/spectator/matchers/size_of_matcher.cr | 21 +++++++++++++++++ src/spectator/matchers/standard_matcher.cr | 3 ++- src/spectator/matchers/start_with_matcher.cr | 20 +++++++++++++++- src/spectator/matchers/truthy_matcher.cr | 23 +++++++++++++++++++ src/spectator/matchers/type_matcher.cr | 21 +++++++++++++++++ .../matchers/unordered_array_matcher.cr | 8 +++++++ 30 files changed, 531 insertions(+), 4 deletions(-) diff --git a/src/spectator/matchers/array_matcher.cr b/src/spectator/matchers/array_matcher.cr index e03f584..f3c3940 100644 --- a/src/spectator/matchers/array_matcher.cr +++ b/src/spectator/matchers/array_matcher.cr @@ -7,15 +7,21 @@ module Spectator::Matchers # Matcher for checking that the contents of one array (or similar type) # has the exact same contents as another and in the same order. struct ArrayMatcher(ExpectedType) < Matcher + # Expected value and label. private getter expected + # Creates the matcher with an expected value. def initialize(@expected : TestValue(ExpectedType)) end + # Short text about the matcher's purpose. + # This explains what condition satisfies the matcher. + # The description is used when the one-liner syntax is used. def description "contains exactly #{expected.label}" end + # Actually performs the test against the expression. def match(actual : TestExpression(T)) : MatchData forall T actual_elements = actual.value.to_a expected_elements = expected.value.to_a @@ -31,6 +37,8 @@ module Spectator::Matchers end end + # Performs the test against the expression, but inverted. + # A successful match with `#match` should normally fail for this method, and vice-versa. def negated_match(actual : TestExpression(T)) : MatchData forall T actual_elements = actual.value.to_a expected_elements = expected.value.to_a @@ -45,14 +53,23 @@ module Spectator::Matchers end end + # Ensures the arrays elements are compared in order. + # This is the default behavior for the matcher. def in_order self end + # Specifies that the arrays elements can be compared in any order. + # The elements can be in a different order, but both arrays must have the same elements. def in_any_order UnorderedArrayMatcher.new(expected) end + # Compares two arrays to determine whether they contain the same elements, and in the same order. + # If the arrays are the same, then `true` is returned. + # If they are different, `false` or an integer is returned. + # `false` is returned when the sizes of the arrays don't match. + # An integer is returned, that is the index of the mismatched elements in the arrays. private def compare_arrays(expected_elements, actual_elements) if expected_elements.size == actual_elements.size index = 0 @@ -66,6 +83,7 @@ module Spectator::Matchers end end + # Produces match data for a failure when the array sizes differ. private def failed_size_mismatch(expected_elements, actual_elements, actual_label) FailedMatchData.new("#{actual_label} does not contain exactly #{expected.label} (size mismatch)", expected: expected_elements.inspect, @@ -75,6 +93,7 @@ module Spectator::Matchers ) end + # Produces match data for a failure when the array content is mismatched. private def failed_content_mismatch(expected_elements, actual_elements, index, actual_label) FailedMatchData.new("#{actual_label} does not contain exactly #{expected.label} (element mismatch)", expected: expected_elements[index].inspect, @@ -83,6 +102,7 @@ module Spectator::Matchers ) end + # Produces match data for a failure when the arrays are identical, but they shouldn't be (negation). private def failed_content_identical(expected_elements, actual_elements, actual_label) FailedMatchData.new("#{actual_label} contains exactly #{expected.label}", expected: "Not #{expected_elements.inspect}", diff --git a/src/spectator/matchers/attributes_matcher.cr b/src/spectator/matchers/attributes_matcher.cr index 437b80f..a447d4a 100644 --- a/src/spectator/matchers/attributes_matcher.cr +++ b/src/spectator/matchers/attributes_matcher.cr @@ -10,15 +10,21 @@ module Spectator::Matchers # Each key in the tuple is the attribute/method name, # and the corresponding value is the expected value to match against. struct AttributesMatcher(ExpectedType) < Matcher + # Expected value and label. private getter expected + # Creates the matcher with an expected value. def initialize(@expected : TestValue(ExpectedType)) end + # Short text about the matcher's purpose. + # This explains what condition satisfies the matcher. + # The description is used when the one-liner syntax is used. def description "has attributes #{expected.label}" end + # Actually performs the test against the expression. def match(actual : TestExpression(T)) : MatchData forall T snapshot = snapshot_values(actual.value) if match?(snapshot) @@ -28,6 +34,8 @@ module Spectator::Matchers end end + # Performs the test against the expression, but inverted. + # A successful match with `#match` should normally fail for this method, and vice-versa. def negated_match(actual : TestExpression(T)) : MatchData forall T snapshot = snapshot_values(actual.value) if match?(snapshot) @@ -49,6 +57,7 @@ module Spectator::Matchers {% end %} end + # Checks if all attributes from the snapshot of them are satisified. private def match?(snapshot) # Test that every attribute has the expected value. {% for attribute in ExpectedType.keys %} @@ -59,6 +68,7 @@ module Spectator::Matchers true end + # Produces the tuple for the failed match data from a snapshot of the attributes. private def values(snapshot) {% begin %} { diff --git a/src/spectator/matchers/case_matcher.cr b/src/spectator/matchers/case_matcher.cr index c4283f6..332212d 100644 --- a/src/spectator/matchers/case_matcher.cr +++ b/src/spectator/matchers/case_matcher.cr @@ -4,18 +4,35 @@ module Spectator::Matchers # Common matcher that tests whether two values semantically equal each other. # The values are compared with the === operator. struct CaseMatcher(ExpectedType) < ValueMatcher(ExpectedType) + # Checks whether the matcher is satisifed with the expression given to it. private def match?(actual) expected.value === actual.value end + # Short text about the matcher's purpose. + # This explains what condition satisfies the matcher. + # The description is used when the one-liner syntax is used. def description "matches #{expected.label}" end + # Message displayed when the matcher isn't satisifed. + # + # This is only called when `#match?` returns false. + # + # The message should typically only contain the test expression labels. + # Actual values should be returned by `#values`. private def failure_message(actual) "#{actual.label} does not match #{expected.label}" end + # Message displayed when the matcher isn't satisifed and is negated. + # This is essentially what would satisfy the matcher if it wasn't negated. + # + # This is only called when `#does_not_match?` returns false. + # + # The message should typically only contain the test expression labels. + # Actual values should be returned by `#values`. private def failure_message_when_negated(actual) "#{actual.label} matched #{expected.label}" end diff --git a/src/spectator/matchers/collection_matcher.cr b/src/spectator/matchers/collection_matcher.cr index 2a16822..ba533da 100644 --- a/src/spectator/matchers/collection_matcher.cr +++ b/src/spectator/matchers/collection_matcher.cr @@ -5,18 +5,35 @@ require "./value_matcher" module Spectator::Matchers # Matcher for checking that a value is in a collection of other values. struct CollectionMatcher(ExpectedType) < ValueMatcher(ExpectedType) + # Checks whether the matcher is satisifed with the expression given to it. private def match?(actual) expected.value.includes?(actual.value) end + # Short text about the matcher's purpose. + # This explains what condition satisfies the matcher. + # The description is used when the one-liner syntax is used. def description "is in #{expected.label}" end + # Message displayed when the matcher isn't satisifed. + # + # This is only called when `#match?` returns false. + # + # The message should typically only contain the test expression labels. + # Actual values should be returned by `#values`. private def failure_message(actual) "#{actual.label} is not in #{expected.label}" end + # Message displayed when the matcher isn't satisifed and is negated. + # This is essentially what would satisfy the matcher if it wasn't negated. + # + # This is only called when `#does_not_match?` returns false. + # + # The message should typically only contain the test expression labels. + # Actual values should be returned by `#values`. private def failure_message_when_negated(actual) "#{actual.label} is in #{expected.label}" end diff --git a/src/spectator/matchers/contain_matcher.cr b/src/spectator/matchers/contain_matcher.cr index fa6d65a..4b31fc6 100644 --- a/src/spectator/matchers/contain_matcher.cr +++ b/src/spectator/matchers/contain_matcher.cr @@ -4,24 +4,43 @@ 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?` method. struct ContainMatcher(ExpectedType) < ValueMatcher(ExpectedType) + # Checks whether the matcher is satisifed with the expression given to it. private def match?(actual) expected.value.all? do |item| actual.value.includes?(item) end end + # Short text about the matcher's purpose. + # This explains what condition satisfies the matcher. + # The description is used when the one-liner syntax is used. def description "contains #{expected.label}" end + # Message displayed when the matcher isn't satisifed. + # + # This is only called when `#match?` returns false. + # + # The message should typically only contain the test expression labels. + # Actual values should be returned by `#values`. private def failure_message(actual) "#{actual.label} does not match #{expected.label}" end + # Message displayed when the matcher isn't satisifed and is negated. + # This is essentially what would satisfy the matcher if it wasn't negated. + # + # This is only called when `#does_not_match?` returns false. + # + # The message should typically only contain the test expression labels. + # Actual values should be returned by `#values`. private def failure_message_when_negated(actual) "#{actual.label} contains #{expected.label}" end - + + # Additional information about the match failure. + # The return value is a NamedTuple with Strings for each value. private def values(actual) { subset: expected.value.inspect, diff --git a/src/spectator/matchers/empty_matcher.cr b/src/spectator/matchers/empty_matcher.cr index 4db31f9..16171b0 100644 --- a/src/spectator/matchers/empty_matcher.cr +++ b/src/spectator/matchers/empty_matcher.cr @@ -4,18 +4,35 @@ module Spectator::Matchers # Matcher that tests whether a collection is empty. # The values are checked with the `empty?` method. struct EmptyMatcher < StandardMatcher + # Checks whether the matcher is satisifed with the expression given to it. private def match?(actual) actual.value.empty? end + # Short text about the matcher's purpose. + # This explains what condition satisfies the matcher. + # The description is used when the one-liner syntax is used. def description "is empty" end + # Message displayed when the matcher isn't satisifed. + # + # This is only called when `#match?` returns false. + # + # The message should typically only contain the test expression labels. + # Actual values should be returned by `#values`. private def failure_message(actual) "#{actual.label} is not empty" end + # Message displayed when the matcher isn't satisifed and is negated. + # This is essentially what would satisfy the matcher if it wasn't negated. + # + # This is only called when `#does_not_match?` returns false. + # + # The message should typically only contain the test expression labels. + # Actual values should be returned by `#values`. private def failure_message_when_negated(actual) "#{actual.label} is empty" end diff --git a/src/spectator/matchers/end_with_matcher.cr b/src/spectator/matchers/end_with_matcher.cr index 3dbd9e6..448d1e6 100644 --- a/src/spectator/matchers/end_with_matcher.cr +++ b/src/spectator/matchers/end_with_matcher.cr @@ -7,15 +7,21 @@ module Spectator::Matchers # The `ends_with?` method is used if it's defined on the actual type. # Otherwise, it is treated as an `Indexable` and the `last` value is compared against. struct EndWithMatcher(ExpectedType) < Matcher + # Expected value and label. private getter expected + # Creates the matcher with an expected value. def initialize(@expected : TestValue(ExpectedType)) end + # Short text about the matcher's purpose. + # This explains what condition satisfies the matcher. + # The description is used when the one-liner syntax is used. def description "ends with #{expected.label}" end + # Actually performs the test against the expression. def match(actual : TestExpression(T)) : MatchData forall T if (value = actual.value).responds_to?(:ends_with?) match_ends_with(value, actual.label) @@ -24,6 +30,8 @@ module Spectator::Matchers end end + # Checks whether the actual value ends with the expected value. + # This method expects (and uses) the `#ends_with?` method on the value. private def match_ends_with(actual_value, actual_label) if actual_value.ends_with?(expected.value) SuccessfulMatchData.new @@ -35,6 +43,8 @@ module Spectator::Matchers end end + # Checks whether the last element of the value is the expected value. + # This method expects that the actual value is a set (enumerable). private def match_last(actual_value, actual_label) list = actual_value.to_a last = list.last @@ -50,6 +60,8 @@ module Spectator::Matchers end end + # Performs the test against the expression, but inverted. + # A successful match with `#match` should normally fail for this method, and vice-versa. def negated_match(actual : TestExpression(T)) : MatchData forall T if actual.value.responds_to?(:ends_with?) negated_match_ends_with(actual) @@ -58,6 +70,8 @@ module Spectator::Matchers end end + # Checks whether the actual value does not end with the expected value. + # This method expects (and uses) the `#ends_with?` method on the value. private def negated_match_ends_with(actual) if actual.value.ends_with?(expected.value) FailedMatchData.new("#{actual.label} ends with #{expected.label} (using #ends_with?)", @@ -69,6 +83,8 @@ module Spectator::Matchers end end + # Checks whether the last element of the value is not the expected value. + # This method expects that the actual value is a set (enumerable). private def negated_match_last(actual) list = actual.value.to_a last = list.last diff --git a/src/spectator/matchers/equality_matcher.cr b/src/spectator/matchers/equality_matcher.cr index ce95be1..81f0cbb 100644 --- a/src/spectator/matchers/equality_matcher.cr +++ b/src/spectator/matchers/equality_matcher.cr @@ -4,18 +4,35 @@ module Spectator::Matchers # Common matcher that tests whether two values equal each other. # The values are compared with the == operator. struct EqualityMatcher(ExpectedType) < ValueMatcher(ExpectedType) + # Checks whether the matcher is satisifed with the expression given to it. private def match?(actual) expected.value == actual.value end + # Short text about the matcher's purpose. + # This explains what condition satisfies the matcher. + # The description is used when the one-liner syntax is used. def description "equals #{expected.label}" end + # Message displayed when the matcher isn't satisifed. + # + # This is only called when `#match?` returns false. + # + # The message should typically only contain the test expression labels. + # Actual values should be returned by `#values`. private def failure_message(actual) "#{actual.label} does not equal #{expected.label}" end + # Message displayed when the matcher isn't satisifed and is negated. + # This is essentially what would satisfy the matcher if it wasn't negated. + # + # This is only called when `#does_not_match?` returns false. + # + # The message should typically only contain the test expression labels. + # Actual values should be returned by `#values`. private def failure_message_when_negated(actual) "#{actual.label} equals #{expected.label}" end diff --git a/src/spectator/matchers/exception_matcher.cr b/src/spectator/matchers/exception_matcher.cr index 3641c15..981845c 100644 --- a/src/spectator/matchers/exception_matcher.cr +++ b/src/spectator/matchers/exception_matcher.cr @@ -6,15 +6,21 @@ require "./successful_match_data" module Spectator::Matchers # Matcher that tests whether an exception is raised. struct ExceptionMatcher(ExceptionType, ExpectedType) < Matcher + # Expected value and label. private getter expected + # Creates the matcher with no expectation of the message. def initialize @expected = TestValue.new(nil, ExceptionType.to_s) end + # Creates the matcher with an expected message. def initialize(@expected : TestValue(ExpectedType)) end + # Short text about the matcher's purpose. + # This explains what condition satisfies the matcher. + # The description is used when the one-liner syntax is used. def description if (message = @expected) "raises #{ExceptionType} with message #{message}" @@ -23,6 +29,7 @@ module Spectator::Matchers end end + # Actually performs the test against the expression. def match(actual : TestExpression(T)) : MatchData forall T exception = capture_exception { actual.value } if exception.nil? @@ -52,6 +59,8 @@ module Spectator::Matchers end end + # Performs the test against the expression, but inverted. + # A successful match with `#match` should normally fail for this method, and vice-versa. def negated_match(actual : TestExpression(T)) : MatchData forall T exception = capture_exception { actual.value } if exception.nil? diff --git a/src/spectator/matchers/greater_than_equal_matcher.cr b/src/spectator/matchers/greater_than_equal_matcher.cr index 1a2ef80..7d6d7f8 100644 --- a/src/spectator/matchers/greater_than_equal_matcher.cr +++ b/src/spectator/matchers/greater_than_equal_matcher.cr @@ -4,22 +4,41 @@ module Spectator::Matchers # Matcher that tests whether one value is greater than or equal to another. # The values are compared with the >= operator. struct GreaterThanEqualMatcher(ExpectedType) < ValueMatcher(ExpectedType) + # Checks whether the matcher is satisifed with the expression given to it. private def match?(actual) actual.value >= expected.value end + # Short text about the matcher's purpose. + # This explains what condition satisfies the matcher. + # The description is used when the one-liner syntax is used. def description "greater than or equal to #{expected.label}" end + # Message displayed when the matcher isn't satisifed. + # + # This is only called when `#match?` returns false. + # + # The message should typically only contain the test expression labels. + # Actual values should be returned by `#values`. private def failure_message(actual) "#{actual.label} is less than #{expected.label}" end + # Message displayed when the matcher isn't satisifed and is negated. + # This is essentially what would satisfy the matcher if it wasn't negated. + # + # This is only called when `#does_not_match?` returns false. + # + # The message should typically only contain the test expression labels. + # Actual values should be returned by `#values`. private def failure_message_when_negated(actual) "#{actual.label} is greater than or equal to #{expected.label}" end + # Additional information about the match failure. + # The return value is a NamedTuple with Strings for each value. private def values(actual) { expected: ">= #{expected.value.inspect}", @@ -27,6 +46,8 @@ module Spectator::Matchers } end + # Additional information about the match failure when negated. + # The return value is a NamedTuple with Strings for each value. private def negated_values(actual) { expected: "< #{expected.value.inspect}", diff --git a/src/spectator/matchers/greater_than_matcher.cr b/src/spectator/matchers/greater_than_matcher.cr index 12ec50f..81d988d 100644 --- a/src/spectator/matchers/greater_than_matcher.cr +++ b/src/spectator/matchers/greater_than_matcher.cr @@ -4,29 +4,50 @@ module Spectator::Matchers # Matcher that tests whether one value is greater than another. # The values are compared with the > operator. struct GreaterThanMatcher(ExpectedType) < ValueMatcher(ExpectedType) + # Checks whether the matcher is satisifed with the expression given to it. private def match?(actual) actual.value > expected.value end + # Short text about the matcher's purpose. + # This explains what condition satisfies the matcher. + # The description is used when the one-liner syntax is used. def description "greater than #{expected.label}" end + # Message displayed when the matcher isn't satisifed. + # + # This is only called when `#match?` returns false. + # + # The message should typically only contain the test expression labels. + # Actual values should be returned by `#values`. private def failure_message(actual) "#{actual.label} is less than or equal to #{expected.label}" end + # Message displayed when the matcher isn't satisifed and is negated. + # This is essentially what would satisfy the matcher if it wasn't negated. + # + # This is only called when `#does_not_match?` returns false. + # + # The message should typically only contain the test expression labels. + # Actual values should be returned by `#values`. private def failure_message_when_negated(actual) "#{actual.label} is greater than #{expected.label}" end + # Additional information about the match failure. + # The return value is a NamedTuple with Strings for each value. private def values(actual) { expected: "> #{expected.value.inspect}", actual: actual.value.inspect, } end - + + # Additional information about the match failure when negated. + # The return value is a NamedTuple with Strings for each value. private def negated_values(actual) { expected: "<= #{expected.value.inspect}", diff --git a/src/spectator/matchers/have_key_matcher.cr b/src/spectator/matchers/have_key_matcher.cr index 771f5ab..1021827 100644 --- a/src/spectator/matchers/have_key_matcher.cr +++ b/src/spectator/matchers/have_key_matcher.cr @@ -4,22 +4,41 @@ module Spectator::Matchers # Matcher that tests whether a `Hash` (or similar type) has a given key. # The set is checked with the `has_key?` method. struct HaveKeyMatcher(ExpectedType) < ValueMatcher(ExpectedType) + # Checks whether the matcher is satisifed with the expression given to it. private def match?(actual) actual.value.has_key?(expected.value) end + # Short text about the matcher's purpose. + # This explains what condition satisfies the matcher. + # The description is used when the one-liner syntax is used. def description "has key #{expected.label}" end + # Message displayed when the matcher isn't satisifed. + # + # This is only called when `#match?` returns false. + # + # The message should typically only contain the test expression labels. + # Actual values should be returned by `#values`. private def failure_message(actual) "#{actual.label} does not have key #{expected.label}" end + # Message displayed when the matcher isn't satisifed and is negated. + # This is essentially what would satisfy the matcher if it wasn't negated. + # + # This is only called when `#does_not_match?` returns false. + # + # The message should typically only contain the test expression labels. + # Actual values should be returned by `#values`. private def failure_message_when_negated(actual) "#{actual.label} has key #{expected.label}" end + # Additional information about the match failure. + # The return value is a NamedTuple with Strings for each value. private def values(actual) actual_value = actual.value set = actual_value.responds_to?(:keys) ? actual_value.keys : actual_value diff --git a/src/spectator/matchers/have_matcher.cr b/src/spectator/matchers/have_matcher.cr index 3886e51..c2d6af9 100644 --- a/src/spectator/matchers/have_matcher.cr +++ b/src/spectator/matchers/have_matcher.cr @@ -5,6 +5,7 @@ module Spectator::Matchers # For a `String`, the `includes?` method is used. # Otherwise, it expects an `Enumerable` and iterates over each item until === is true. struct HaveMatcher(ExpectedType) < ValueMatcher(ExpectedType) + # Checks whether the matcher is satisifed with the expression given to it. private def match?(actual) if (value = actual.value).is_a?(String) match_string?(value) @@ -32,18 +33,36 @@ module Spectator::Matchers end end + # Short text about the matcher's purpose. + # This explains what condition satisfies the matcher. + # The description is used when the one-liner syntax is used. def description "includes #{expected.label}" end + # Message displayed when the matcher isn't satisifed. + # + # This is only called when `#match?` returns false. + # + # The message should typically only contain the test expression labels. + # Actual values should be returned by `#values`. private def failure_message(actual) "#{actual.label} does not include #{expected.label}" end + # Message displayed when the matcher isn't satisifed and is negated. + # This is essentially what would satisfy the matcher if it wasn't negated. + # + # This is only called when `#does_not_match?` returns false. + # + # The message should typically only contain the test expression labels. + # Actual values should be returned by `#values`. private def failure_message_when_negated(actual) "#{actual.label} includes #{expected.label}" end + # Additional information about the match failure. + # The return value is a NamedTuple with Strings for each value. private def values(actual) { subset: expected.value.inspect, diff --git a/src/spectator/matchers/have_predicate_matcher.cr b/src/spectator/matchers/have_predicate_matcher.cr index 525f157..8b9ff1f 100644 --- a/src/spectator/matchers/have_predicate_matcher.cr +++ b/src/spectator/matchers/have_predicate_matcher.cr @@ -7,15 +7,21 @@ module Spectator::Matchers # Each key in the tuple is a predicate (without the '?' and 'has_' prefix) to test. # Each value is a a `Tuple` of arguments to pass to the predicate method. struct HavePredicateMatcher(ExpectedType) < ValueMatcher(ExpectedType) + # Expected value and label. private getter expected + # Creates the matcher with a expected values. def initialize(@expected : TestValue(ExpectedType)) end + # Short text about the matcher's purpose. + # This explains what condition satisfies the matcher. + # The description is used when the one-liner syntax is used. def description "has #{expected.label}" end + # Actually performs the test against the expression. def match(actual : TestExpression(T)) : MatchData forall T snapshot = snapshot_values(actual.value) if match?(snapshot) @@ -25,6 +31,8 @@ module Spectator::Matchers end end + # Performs the test against the expression, but inverted. + # A successful match with `#match` should normally fail for this method, and vice-versa. def negated_match(actual : TestExpression(T)) : MatchData forall T snapshot = snapshot_values(actual.value) if match?(snapshot) @@ -34,10 +42,23 @@ module Spectator::Matchers end end + # Message displayed when the matcher isn't satisifed. + # + # This is only called when `#match?` returns false. + # + # The message should typically only contain the test expression labels. + # Actual values should be returned by `#values`. private def failure_message(actual) "#{actual.label} does not have #{expected.label}" end + # Message displayed when the matcher isn't satisifed and is negated. + # This is essentially what would satisfy the matcher if it wasn't negated. + # + # This is only called when `#does_not_match?` returns false. + # + # The message should typically only contain the test expression labels. + # Actual values should be returned by `#values`. private def failure_message_when_negated(actual) "#{actual.label} has #{expected.label}" end @@ -54,6 +75,7 @@ module Spectator::Matchers {% end %} end + # Produces the tuple for the failed match data from a snapshot of the predicate methods. private def values(snapshot) {% begin %} { @@ -64,6 +86,7 @@ module Spectator::Matchers {% end %} end + # Checks if all predicate methods from the snapshot of them are satisified. private def match?(snapshot) # Test each predicate and immediately return false if one is false. {% for attribute in ExpectedType.keys %} diff --git a/src/spectator/matchers/have_value_matcher.cr b/src/spectator/matchers/have_value_matcher.cr index 7a44f14..429e481 100644 --- a/src/spectator/matchers/have_value_matcher.cr +++ b/src/spectator/matchers/have_value_matcher.cr @@ -4,22 +4,41 @@ module Spectator::Matchers # Matcher that tests whether a `Hash` (or similar type) has a given value. # The set is checked with the `has_value?` method. struct HaveValueMatcher(ExpectedType) < ValueMatcher(ExpectedType) + # Checks whether the matcher is satisifed with the expression given to it. private def match?(actual) actual.value.has_value?(expected.value) end + # Short text about the matcher's purpose. + # This explains what condition satisfies the matcher. + # The description is used when the one-liner syntax is used. def description "has value #{expected.label}" end + # Message displayed when the matcher isn't satisifed. + # + # This is only called when `#match?` returns false. + # + # The message should typically only contain the test expression labels. + # Actual values should be returned by `#values`. private def failure_message(actual) "#{actual.label} does not have value #{expected.label}" end + # Message displayed when the matcher isn't satisifed and is negated. + # This is essentially what would satisfy the matcher if it wasn't negated. + # + # This is only called when `#does_not_match?` returns false. + # + # The message should typically only contain the test expression labels. + # Actual values should be returned by `#values`. private def failure_message_when_negated(actual) "#{actual.label} has value #{expected.label}" end + # Additional information about the match failure. + # The return value is a NamedTuple with Strings for each value. private def values(actual) actual_value = actual.value set = actual_value.responds_to?(:values) ? actual_value.values : actual_value diff --git a/src/spectator/matchers/inequality_matcher.cr b/src/spectator/matchers/inequality_matcher.cr index c1bd6cd..caa4d90 100644 --- a/src/spectator/matchers/inequality_matcher.cr +++ b/src/spectator/matchers/inequality_matcher.cr @@ -4,22 +4,41 @@ module Spectator::Matchers # Matcher that tests whether two values do not equal each other. # The values are compared with the != operator. struct InequalityMatcher(ExpectedType) < ValueMatcher(ExpectedType) + # Checks whether the matcher is satisifed with the expression given to it. private def match?(actual) expected.value != actual.value end + # Short text about the matcher's purpose. + # This explains what condition satisfies the matcher. + # The description is used when the one-liner syntax is used. def description "is not equal to #{expected.label}" end + # Message displayed when the matcher isn't satisifed. + # + # This is only called when `#match?` returns false. + # + # The message should typically only contain the test expression labels. + # Actual values should be returned by `#values`. private def failure_message(actual) "#{actual.label} is equal to #{expected.label}" end + # Message displayed when the matcher isn't satisifed and is negated. + # This is essentially what would satisfy the matcher if it wasn't negated. + # + # This is only called when `#does_not_match?` returns false. + # + # The message should typically only contain the test expression labels. + # Actual values should be returned by `#values`. private def failure_message_when_negated(actual) "#{actual.label} is not equal to #{expected.label}" end + # Additional information about the match failure. + # The return value is a NamedTuple with Strings for each value. private def values(actual) { expected: "Not #{expected.value.inspect}", @@ -27,6 +46,8 @@ module Spectator::Matchers } end + # Additional information about the match failure when negated. + # The return value is a NamedTuple with Strings for each value. private def negated_values(actual) { expected: expected.value.inspect, diff --git a/src/spectator/matchers/less_than_equal_matcher.cr b/src/spectator/matchers/less_than_equal_matcher.cr index da43df1..c3c413a 100644 --- a/src/spectator/matchers/less_than_equal_matcher.cr +++ b/src/spectator/matchers/less_than_equal_matcher.cr @@ -4,22 +4,41 @@ module Spectator::Matchers # Matcher that tests whether one value is less than or equal to another. # The values are compared with the <= operator. struct LessThanEqualMatcher(ExpectedType) < ValueMatcher(ExpectedType) + # Checks whether the matcher is satisifed with the expression given to it. private def match?(actual) actual.value <= expected.value end + # Short text about the matcher's purpose. + # This explains what condition satisfies the matcher. + # The description is used when the one-liner syntax is used. def description "less than or equal to #{expected.label}" end + # Message displayed when the matcher isn't satisifed. + # + # This is only called when `#match?` returns false. + # + # The message should typically only contain the test expression labels. + # Actual values should be returned by `#values`. private def failure_message(actual) "#{actual.label} is greater than #{expected.label}" end + # Message displayed when the matcher isn't satisifed and is negated. + # This is essentially what would satisfy the matcher if it wasn't negated. + # + # This is only called when `#does_not_match?` returns false. + # + # The message should typically only contain the test expression labels. + # Actual values should be returned by `#values`. private def failure_message_when_negated(actual) "#{actual.label} is less than or equal to #{expected.label}" end + # Additional information about the match failure. + # The return value is a NamedTuple with Strings for each value. private def values(actual) { expected: "<= #{expected.value.inspect}", @@ -27,6 +46,8 @@ module Spectator::Matchers } end + # Additional information about the match failure when negated. + # The return value is a NamedTuple with Strings for each value. private def negated_values(actual) { expected: "> #{expected.value.inspect}", diff --git a/src/spectator/matchers/less_than_matcher.cr b/src/spectator/matchers/less_than_matcher.cr index 0c37302..185532d 100644 --- a/src/spectator/matchers/less_than_matcher.cr +++ b/src/spectator/matchers/less_than_matcher.cr @@ -4,22 +4,41 @@ module Spectator::Matchers # Matcher that tests whether one value is less than another. # The values are compared with the < operator. struct LessThanMatcher(ExpectedType) < ValueMatcher(ExpectedType) + # Checks whether the matcher is satisifed with the expression given to it. private def match?(actual) actual.value < expected.value end + # Short text about the matcher's purpose. + # This explains what condition satisfies the matcher. + # The description is used when the one-liner syntax is used. def description "less than #{expected.label}" end + # Message displayed when the matcher isn't satisifed. + # + # This is only called when `#match?` returns false. + # + # The message should typically only contain the test expression labels. + # Actual values should be returned by `#values`. private def failure_message(actual) "#{actual.label} is greater than or equal to #{expected.label}" end + # Message displayed when the matcher isn't satisifed and is negated. + # This is essentially what would satisfy the matcher if it wasn't negated. + # + # This is only called when `#does_not_match?` returns false. + # + # The message should typically only contain the test expression labels. + # Actual values should be returned by `#values`. private def failure_message_when_negated(actual) "#{actual.label} is less than #{expected.label}" end + # Additional information about the match failure. + # The return value is a NamedTuple with Strings for each value. private def values(actual) { expected: "< #{expected.value.inspect}", @@ -27,6 +46,8 @@ module Spectator::Matchers } end + # Additional information about the match failure when negated. + # The return value is a NamedTuple with Strings for each value. private def negated_values(actual) { expected: ">= #{expected.value.inspect}", diff --git a/src/spectator/matchers/nil_matcher.cr b/src/spectator/matchers/nil_matcher.cr index c97a663..6fc109b 100644 --- a/src/spectator/matchers/nil_matcher.cr +++ b/src/spectator/matchers/nil_matcher.cr @@ -4,18 +4,35 @@ module Spectator::Matchers # Common matcher that tests whether a value is nil. # The `Object#nil?` method is used for this. struct NilMatcher < StandardMatcher + # Checks whether the matcher is satisifed with the expression given to it. private def match?(actual) actual.value.nil? end + # Short text about the matcher's purpose. + # This explains what condition satisfies the matcher. + # The description is used when the one-liner syntax is used. def description "is nil" end + # Message displayed when the matcher isn't satisifed. + # + # This is only called when `#match?` returns false. + # + # The message should typically only contain the test expression labels. + # Actual values should be returned by `#values`. private def failure_message(actual) "#{actual.label} is not nil" end + # Message displayed when the matcher isn't satisifed and is negated. + # This is essentially what would satisfy the matcher if it wasn't negated. + # + # This is only called when `#does_not_match?` returns false. + # + # The message should typically only contain the test expression labels. + # Actual values should be returned by `#values`. private def failure_message_when_negated(actual) "#{actual.label} is nil" end diff --git a/src/spectator/matchers/predicate_matcher.cr b/src/spectator/matchers/predicate_matcher.cr index 5ab5582..9d58073 100644 --- a/src/spectator/matchers/predicate_matcher.cr +++ b/src/spectator/matchers/predicate_matcher.cr @@ -6,15 +6,21 @@ module Spectator::Matchers # Each key in the tuple is a predicate (without the '?') to test. # Each value is a a `Tuple` of arguments to pass to the predicate method. struct PredicateMatcher(ExpectedType) < Matcher + # Expected value and label. private getter expected + # Creates the matcher with a expected values. def initialize(@expected : TestValue(ExpectedType)) end + # Short text about the matcher's purpose. + # This explains what condition satisfies the matcher. + # The description is used when the one-liner syntax is used. def description "is #{expected.label}" end + # Actually performs the test against the expression. def match(actual : TestExpression(T)) : MatchData forall T snapshot = snapshot_values(actual.value) if match?(snapshot) @@ -24,6 +30,8 @@ module Spectator::Matchers end end + # Performs the test against the expression, but inverted. + # A successful match with `#match` should normally fail for this method, and vice-versa. def negated_match(actual : TestExpression(T)) : MatchData forall T snapshot = snapshot_values(actual.value) if match?(snapshot) @@ -33,10 +41,23 @@ module Spectator::Matchers end end + # Message displayed when the matcher isn't satisifed. + # + # This is only called when `#match?` returns false. + # + # The message should typically only contain the test expression labels. + # Actual values should be returned by `#values`. private def failure_message(actual) "#{actual.label} is not #{expected.label}" end + # Message displayed when the matcher isn't satisifed and is negated. + # This is essentially what would satisfy the matcher if it wasn't negated. + # + # This is only called when `#does_not_match?` returns false. + # + # The message should typically only contain the test expression labels. + # Actual values should be returned by `#values`. private def failure_message_when_negated(actual) "#{actual.label} is #{expected.label}" end @@ -53,6 +74,7 @@ module Spectator::Matchers {% end %} end + # Produces the tuple for the failed match data from a snapshot of the predicate methods. private def values(snapshot) {% begin %} { @@ -63,6 +85,7 @@ module Spectator::Matchers {% end %} end + # Checks if all predicate methods from the snapshot of them are satisified. private def match?(snapshot) # Test each predicate and immediately return false if one is false. {% for attribute in ExpectedType.keys %} diff --git a/src/spectator/matchers/range_matcher.cr b/src/spectator/matchers/range_matcher.cr index 7ec238e..98a0bee 100644 --- a/src/spectator/matchers/range_matcher.cr +++ b/src/spectator/matchers/range_matcher.cr @@ -4,22 +4,41 @@ module Spectator::Matchers # Matcher that tests whether a value is in a given range. # The `Range#includes?` method is used for this check. struct RangeMatcher(ExpectedType) < ValueMatcher(ExpectedType) + # Checks whether the matcher is satisifed with the expression given to it. private def match?(actual) expected.value.includes?(actual.value) end + # Short text about the matcher's purpose. + # This explains what condition satisfies the matcher. + # The description is used when the one-liner syntax is used. def description "is in #{expected.label}" end + # Message displayed when the matcher isn't satisifed. + # + # This is only called when `#match?` returns false. + # + # The message should typically only contain the test expression labels. + # Actual values should be returned by `#values`. private def failure_message(actual) "#{actual.label} is not in #{expected.label} (#{exclusivity})" end + # Message displayed when the matcher isn't satisifed and is negated. + # This is essentially what would satisfy the matcher if it wasn't negated. + # + # This is only called when `#does_not_match?` returns false. + # + # The message should typically only contain the test expression labels. + # Actual values should be returned by `#values`. private def failure_message_when_negated(actual) "#{actual.label} is in #{expected.label} (#{exclusivity})" end + # Additional information about the match failure. + # The return value is a NamedTuple with Strings for each value. private def values(actual) { lower: ">= #{range.begin.inspect}", @@ -28,6 +47,8 @@ module Spectator::Matchers } end + # Additional information about the match failure when negated. + # The return value is a NamedTuple with Strings for each value. private def negated_values(actual) { lower: "< #{range.begin.inspect}", diff --git a/src/spectator/matchers/reference_matcher.cr b/src/spectator/matchers/reference_matcher.cr index 42d84d3..bc9d709 100644 --- a/src/spectator/matchers/reference_matcher.cr +++ b/src/spectator/matchers/reference_matcher.cr @@ -4,18 +4,35 @@ module Spectator::Matchers # Matcher that tests whether two references are the same. # The values are compared with the `Reference#same?` method. struct ReferenceMatcher(ExpectedType) < ValueMatcher(ExpectedType) + # Checks whether the matcher is satisifed with the expression given to it. private def match?(actual) expected.value.same?(actual.value) end + # Short text about the matcher's purpose. + # This explains what condition satisfies the matcher. + # The description is used when the one-liner syntax is used. def description "is #{expected.label}" end + # Message displayed when the matcher isn't satisifed. + # + # This is only called when `#match?` returns false. + # + # The message should typically only contain the test expression labels. + # Actual values should be returned by `#values`. private def failure_message(actual) "#{actual.label} is not #{expected.label}" end + # Message displayed when the matcher isn't satisifed and is negated. + # This is essentially what would satisfy the matcher if it wasn't negated. + # + # This is only called when `#does_not_match?` returns false. + # + # The message should typically only contain the test expression labels. + # Actual values should be returned by `#values`. private def failure_message_when_negated(actual) "#{actual.label} is #{expected.label}" end diff --git a/src/spectator/matchers/respond_matcher.cr b/src/spectator/matchers/respond_matcher.cr index 00d63bb..a3869b4 100644 --- a/src/spectator/matchers/respond_matcher.cr +++ b/src/spectator/matchers/respond_matcher.cr @@ -6,15 +6,20 @@ module Spectator::Matchers # The `ExpectedType` type param should be a `NamedTuple`, # with each key being the method to check and the value is ignored. struct RespondMatcher(ExpectedType) < Matcher + # Short text about the matcher's purpose. + # This explains what condition satisfies the matcher. + # The description is used when the one-liner syntax is used. def description "responds to #{label}" end + # Generated, user-friendly, string for the expected value. private def label # Prefix every method name with # and join them with commas. {{ExpectedType.keys.map { |e| "##{e}".id }.splat.stringify}} end + # Actually performs the test against the expression. def match(actual : TestExpression(T)) : MatchData forall T snapshot = snapshot_values(actual.value) if match?(snapshot) @@ -24,6 +29,8 @@ module Spectator::Matchers end end + # Performs the test against the expression, but inverted. + # A successful match with `#match` should normally fail for this method, and vice-versa. def negated_match(actual : TestExpression(T)) : MatchData forall T snapshot = snapshot_values(actual.value) if match?(snapshot) @@ -45,6 +52,7 @@ module Spectator::Matchers {% end %} end + # Produces the tuple for the failed match data from a snapshot of the results. private def values(snapshot) {% begin %} { @@ -55,6 +63,7 @@ module Spectator::Matchers {% end %} end + # Checks if all results from the snapshot are satisified. private def match?(snapshot) # The snapshot did the hard work. # Here just check if all values are true. diff --git a/src/spectator/matchers/size_matcher.cr b/src/spectator/matchers/size_matcher.cr index f4d37c9..f72b3e2 100644 --- a/src/spectator/matchers/size_matcher.cr +++ b/src/spectator/matchers/size_matcher.cr @@ -4,22 +4,41 @@ module Spectator::Matchers # Matcher that tests whether a set has a specified number of elements. # The set's `#size` method is used for this check. struct SizeMatcher(ExpectedType) < ValueMatcher(ExpectedType) + # Checks whether the matcher is satisifed with the expression given to it. private def match?(actual) expected.value == actual.value.size end + # Short text about the matcher's purpose. + # This explains what condition satisfies the matcher. + # The description is used when the one-liner syntax is used. def description "has size #{expected.label}" end + # Message displayed when the matcher isn't satisifed. + # + # This is only called when `#match?` returns false. + # + # The message should typically only contain the test expression labels. + # Actual values should be returned by `#values`. private def failure_message(actual) "#{actual.label} does not have #{expected.label} elements" end + # Message displayed when the matcher isn't satisifed and is negated. + # This is essentially what would satisfy the matcher if it wasn't negated. + # + # This is only called when `#does_not_match?` returns false. + # + # The message should typically only contain the test expression labels. + # Actual values should be returned by `#values`. private def failure_message_when_negated(actual) "#{actual.label} has #{expected.label} elements" end + # Additional information about the match failure. + # The return value is a NamedTuple with Strings for each value. private def values(actual) { expected: expected.value.inspect, @@ -27,6 +46,8 @@ module Spectator::Matchers } end + # Additional information about the match failure when negated. + # The return value is a NamedTuple with Strings for each value. private def negated_values(actual) { expected: "Not #{expected.value.inspect}", diff --git a/src/spectator/matchers/size_of_matcher.cr b/src/spectator/matchers/size_of_matcher.cr index fefd10a..4339791 100644 --- a/src/spectator/matchers/size_of_matcher.cr +++ b/src/spectator/matchers/size_of_matcher.cr @@ -4,22 +4,41 @@ module Spectator::Matchers # Matcher that tests whether a set has the same number of elements as another set. # The set's `#size` method is used for this check. struct SizeOfMatcher(ExpectedType) < ValueMatcher(ExpectedType) + # Checks whether the matcher is satisifed with the expression given to it. private def match?(actual) expected.value.size == actual.value.size end + # Short text about the matcher's purpose. + # This explains what condition satisfies the matcher. + # The description is used when the one-liner syntax is used. def description "is the same size as #{expected.label}" end + # Message displayed when the matcher isn't satisifed. + # + # This is only called when `#match?` returns false. + # + # The message should typically only contain the test expression labels. + # Actual values should be returned by `#values`. private def failure_message(actual) "#{actual.label} is not the same size as #{expected.label}" end + # Message displayed when the matcher isn't satisifed and is negated. + # This is essentially what would satisfy the matcher if it wasn't negated. + # + # This is only called when `#does_not_match?` returns false. + # + # The message should typically only contain the test expression labels. + # Actual values should be returned by `#values`. private def failure_message_when_negated(actual) "#{actual.label} is the same size as #{expected.label}" end + # Additional information about the match failure. + # The return value is a NamedTuple with Strings for each value. private def values(actual) { expected: expected.value.size.inspect, @@ -27,6 +46,8 @@ module Spectator::Matchers } end + # Additional information about the match failure when negated. + # The return value is a NamedTuple with Strings for each value. private def negated_values(actual) { expected: "Not #{expected.value.size.inspect}", diff --git a/src/spectator/matchers/standard_matcher.cr b/src/spectator/matchers/standard_matcher.cr index afb688b..18753bb 100644 --- a/src/spectator/matchers/standard_matcher.cr +++ b/src/spectator/matchers/standard_matcher.cr @@ -26,6 +26,7 @@ module Spectator::Matchers private abstract def failure_message(actual : TestExpression(T)) : String forall T # Message displayed when the matcher isn't satisifed and is negated. + # This is essentially what would satisfy the matcher if it wasn't negated. # # This is only called when `#does_not_match?` returns false. # @@ -39,7 +40,7 @@ module Spectator::Matchers {% raise "Negation with #{@type.name} is not supported." %} end - # Checks whether the matcher is satisifed. + # Checks whether the matcher is satisifed with the expression given to it. private abstract def match?(actual : TestExpression(T)) : Bool forall T # If the expectation is negated, then this method is called instead of `#match?`. diff --git a/src/spectator/matchers/start_with_matcher.cr b/src/spectator/matchers/start_with_matcher.cr index 2e7961f..15219c7 100644 --- a/src/spectator/matchers/start_with_matcher.cr +++ b/src/spectator/matchers/start_with_matcher.cr @@ -1,19 +1,27 @@ -require "./value_matcher" + + # Checks whether the last element of the value is the expected value. +# This method expects that the actual value is a set (enumerable).require "./value_matcher" module Spectator::Matchers # Matcher that tests whether a value, such as a `String` or `Array`, starts with a value. # The `starts_with?` method is used if it's defined on the actual type. # Otherwise, it is treated as an `Enumerable` and the `first` value is compared against. struct StartWithMatcher(ExpectedType) < Matcher + # Expected value and label. private getter expected + # Creates the matcher with an expected value. def initialize(@expected : TestValue(ExpectedType)) end + # Short text about the matcher's purpose. + # This explains what condition satisfies the matcher. + # The description is used when the one-liner syntax is used. def description "starts with #{expected.label}" end + # Actually performs the test against the expression. def match(actual : TestExpression(T)) : MatchData forall T if (value = actual.value).responds_to?(:starts_with?) match_starts_with(value, actual.label) @@ -22,6 +30,8 @@ module Spectator::Matchers end end + # Checks whether the actual value starts with the expected value. + # This method expects (and uses) the `#starts_with?` method on the value. private def match_starts_with(actual_value, actual_label) if actual_value.starts_with?(expected.value) SuccessfulMatchData.new @@ -33,6 +43,8 @@ module Spectator::Matchers end end + # Checks whether the first element of the value is the expected value. + # This method expects that the actual value is a set (enumerable). private def match_first(actual_value, actual_label) list = actual_value.to_a first = list.first @@ -48,6 +60,8 @@ module Spectator::Matchers end end + # Performs the test against the expression, but inverted. + # A successful match with `#match` should normally fail for this method, and vice-versa. def negated_match(actual : TestExpression(T)) : MatchData forall T if (value = actual.value).responds_to?(:starts_with?) negated_match_starts_with(value, actual.label) @@ -56,6 +70,8 @@ module Spectator::Matchers end end + # Checks whether the actual value does not start with the expected value. + # This method expects (and uses) the `#starts_with?` method on the value. private def negated_match_starts_with(actual_value, actual_label) if actual_value.starts_with?(expected.value) FailedMatchData.new("#{actual_label} starts with #{expected.label} (using #starts_with?)", @@ -67,6 +83,8 @@ module Spectator::Matchers end end + # Checks whether the first element of the value is not the expected value. + # This method expects that the actual value is a set (enumerable). private def negated_match_first(actual_value, actual_label) list = actual_value.to_a first = list.first diff --git a/src/spectator/matchers/truthy_matcher.cr b/src/spectator/matchers/truthy_matcher.cr index 3629a31..46387c5 100644 --- a/src/spectator/matchers/truthy_matcher.cr +++ b/src/spectator/matchers/truthy_matcher.cr @@ -15,30 +15,51 @@ module Spectator::Matchers def initialize(@truthy : Bool = true) end + # Generated, user-friendly, string for the expected value. private def label @truthy ? "truthy" : "falsey" end + # Generated, user-friendly, string for the unexpected value. private def negated_label @truthy ? "falsey" : "truthy" end + # Checks whether the matcher is satisifed with the expression given to it. private def match?(actual) @truthy == !!actual.value end + # Short text about the matcher's purpose. + # This explains what condition satisfies the matcher. + # The description is used when the one-liner syntax is used. def description "is #{label}" end + # Message displayed when the matcher isn't satisifed. + # + # This is only called when `#match?` returns false. + # + # The message should typically only contain the test expression labels. + # Actual values should be returned by `#values`. private def failure_message(actual) "#{actual.label} is #{negated_label}" end + # Message displayed when the matcher isn't satisifed and is negated. + # This is essentially what would satisfy the matcher if it wasn't negated. + # + # This is only called when `#does_not_match?` returns false. + # + # The message should typically only contain the test expression labels. + # Actual values should be returned by `#values`. private def failure_message_when_negated(actual) "#{actual.label} is #{label}" end + # Additional information about the match failure. + # The return value is a NamedTuple with Strings for each value. private def values(actual) { expected: @truthy ? "Not false or nil" : "false or nil", @@ -47,6 +68,8 @@ module Spectator::Matchers } end + # Additional information about the match failure when negated. + # The return value is a NamedTuple with Strings for each value. private def negated_values(actual) { expected: @truthy ? "false or nil" : "Not false or nil", diff --git a/src/spectator/matchers/type_matcher.cr b/src/spectator/matchers/type_matcher.cr index 16ee14c..928e07b 100644 --- a/src/spectator/matchers/type_matcher.cr +++ b/src/spectator/matchers/type_matcher.cr @@ -4,22 +4,41 @@ module Spectator::Matchers # Matcher that tests a value is of a specified type. # The values are compared with the `Object#is_a?` method. struct TypeMatcher(Expected) < StandardMatcher + # Checks whether the matcher is satisifed with the expression given to it. private def match?(actual) actual.value.is_a?(Expected) end + # Short text about the matcher's purpose. + # This explains what condition satisfies the matcher. + # The description is used when the one-liner syntax is used. def description "is as #{Expected}" end + # Message displayed when the matcher isn't satisifed. + # + # This is only called when `#match?` returns false. + # + # The message should typically only contain the test expression labels. + # Actual values should be returned by `#values`. private def failure_message(actual) "#{actual.label} is not a #{Expected}" end + # Message displayed when the matcher isn't satisifed and is negated. + # This is essentially what would satisfy the matcher if it wasn't negated. + # + # This is only called when `#does_not_match?` returns false. + # + # The message should typically only contain the test expression labels. + # Actual values should be returned by `#values`. private def failure_message_when_negated(actual) "#{actual.label} is a #{Expected}" end + # Additional information about the match failure. + # The return value is a NamedTuple with Strings for each value. private def values(actual) { expected: Expected.to_s, @@ -27,6 +46,8 @@ module Spectator::Matchers } end + # Additional information about the match failure when negated. + # The return value is a NamedTuple with Strings for each value. private def negated_values(actual) { expected: "Not #{Expected}", diff --git a/src/spectator/matchers/unordered_array_matcher.cr b/src/spectator/matchers/unordered_array_matcher.cr index acef92f..823ee16 100644 --- a/src/spectator/matchers/unordered_array_matcher.cr +++ b/src/spectator/matchers/unordered_array_matcher.cr @@ -4,15 +4,21 @@ module Spectator::Matchers # Matcher for checking that the contents of one array (or similar type) # has the exact same contents as another, but in any order. struct UnorderedArrayMatcher(ExpectedType) < Matcher + # Expected value and label. private getter expected + # Creates the matcher with an expected value. def initialize(@expected : TestValue(ExpectedType)) end + # Short text about the matcher's purpose. + # This explains what condition satisfies the matcher. + # The description is used when the one-liner syntax is used. def description "contains #{expected.label} in any order" end + # Actually performs the test against the expression. def match(actual : TestExpression(T)) : MatchData forall T actual_elements = actual.value.to_a expected_elements = expected.value.to_a @@ -30,6 +36,8 @@ module Spectator::Matchers end end + # Performs the test against the expression, but inverted. + # A successful match with `#match` should normally fail for this method, and vice-versa. def negated_match(actual : TestExpression(T)) : MatchData forall T actual_elements = actual.value.to_a expected_elements = expected.value.to_a From c4b886cad2a0f44b838998092b60fcae3745beba Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Sat, 10 Aug 2019 10:53:00 -0600 Subject: [PATCH 76/78] Add match data docs --- src/spectator/matchers/failed_match_data.cr | 5 +++++ src/spectator/matchers/match_data.cr | 2 ++ src/spectator/matchers/successful_match_data.cr | 2 ++ 3 files changed, 9 insertions(+) diff --git a/src/spectator/matchers/failed_match_data.cr b/src/spectator/matchers/failed_match_data.cr index eef1cb2..f1925ce 100644 --- a/src/spectator/matchers/failed_match_data.cr +++ b/src/spectator/matchers/failed_match_data.cr @@ -1,15 +1,20 @@ require "./match_data" module Spectator::Matchers + # Information about a failed match. struct FailedMatchData < MatchData + # Indicates that the match failed. def matched? false end + # Description from the matcher as to why it failed. getter failure_message : String + # Additional information from the match that can be used to debug the problem. getter values : Array(Tuple(Symbol, String)) + # Creates the match data. def initialize(@failure_message, **values) @values = values.to_a end diff --git a/src/spectator/matchers/match_data.cr b/src/spectator/matchers/match_data.cr index 321e27a..47b444c 100644 --- a/src/spectator/matchers/match_data.cr +++ b/src/spectator/matchers/match_data.cr @@ -1,5 +1,7 @@ module Spectator::Matchers + # Information about the outcome of a match. abstract struct MatchData + # Indicates whether the match as successful or not. abstract def matched? : Bool end end diff --git a/src/spectator/matchers/successful_match_data.cr b/src/spectator/matchers/successful_match_data.cr index b4cdb5a..25a94ce 100644 --- a/src/spectator/matchers/successful_match_data.cr +++ b/src/spectator/matchers/successful_match_data.cr @@ -1,7 +1,9 @@ require "./match_data" module Spectator::Matchers + # Information about a successful match. struct SuccessfulMatchData < MatchData + # Indicates that the match succeeded. def matched? true end From 898ddcb61603806fd590520397e68d94471a253f Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Sat, 10 Aug 2019 10:55:22 -0600 Subject: [PATCH 77/78] Type annotations for #match? --- src/spectator/matchers/case_matcher.cr | 2 +- src/spectator/matchers/collection_matcher.cr | 2 +- src/spectator/matchers/contain_matcher.cr | 2 +- src/spectator/matchers/empty_matcher.cr | 2 +- src/spectator/matchers/equality_matcher.cr | 2 +- src/spectator/matchers/greater_than_equal_matcher.cr | 2 +- src/spectator/matchers/greater_than_matcher.cr | 2 +- src/spectator/matchers/have_key_matcher.cr | 2 +- src/spectator/matchers/have_matcher.cr | 2 +- src/spectator/matchers/have_value_matcher.cr | 2 +- src/spectator/matchers/inequality_matcher.cr | 2 +- src/spectator/matchers/less_than_equal_matcher.cr | 2 +- src/spectator/matchers/less_than_matcher.cr | 2 +- src/spectator/matchers/nil_matcher.cr | 2 +- src/spectator/matchers/range_matcher.cr | 2 +- src/spectator/matchers/reference_matcher.cr | 2 +- src/spectator/matchers/size_matcher.cr | 2 +- src/spectator/matchers/size_of_matcher.cr | 2 +- src/spectator/matchers/truthy_matcher.cr | 2 +- src/spectator/matchers/type_matcher.cr | 2 +- 20 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/spectator/matchers/case_matcher.cr b/src/spectator/matchers/case_matcher.cr index 332212d..278431f 100644 --- a/src/spectator/matchers/case_matcher.cr +++ b/src/spectator/matchers/case_matcher.cr @@ -5,7 +5,7 @@ module Spectator::Matchers # The values are compared with the === operator. struct CaseMatcher(ExpectedType) < ValueMatcher(ExpectedType) # Checks whether the matcher is satisifed with the expression given to it. - private def match?(actual) + private def match?(actual : TestExpression(T)) forall T expected.value === actual.value end diff --git a/src/spectator/matchers/collection_matcher.cr b/src/spectator/matchers/collection_matcher.cr index ba533da..dd84b4e 100644 --- a/src/spectator/matchers/collection_matcher.cr +++ b/src/spectator/matchers/collection_matcher.cr @@ -6,7 +6,7 @@ module Spectator::Matchers # Matcher for checking that a value is in a collection of other values. struct CollectionMatcher(ExpectedType) < ValueMatcher(ExpectedType) # Checks whether the matcher is satisifed with the expression given to it. - private def match?(actual) + private def match?(actual : TestExpression(T)) forall T expected.value.includes?(actual.value) end diff --git a/src/spectator/matchers/contain_matcher.cr b/src/spectator/matchers/contain_matcher.cr index 4b31fc6..5b4da9e 100644 --- a/src/spectator/matchers/contain_matcher.cr +++ b/src/spectator/matchers/contain_matcher.cr @@ -5,7 +5,7 @@ module Spectator::Matchers # The values are checked with the `includes?` method. struct ContainMatcher(ExpectedType) < ValueMatcher(ExpectedType) # Checks whether the matcher is satisifed with the expression given to it. - private def match?(actual) + private def match?(actual : TestExpression(T)) forall T expected.value.all? do |item| actual.value.includes?(item) end diff --git a/src/spectator/matchers/empty_matcher.cr b/src/spectator/matchers/empty_matcher.cr index 16171b0..897f5d1 100644 --- a/src/spectator/matchers/empty_matcher.cr +++ b/src/spectator/matchers/empty_matcher.cr @@ -5,7 +5,7 @@ module Spectator::Matchers # The values are checked with the `empty?` method. struct EmptyMatcher < StandardMatcher # Checks whether the matcher is satisifed with the expression given to it. - private def match?(actual) + private def match?(actual : TestExpression(T)) forall T actual.value.empty? end diff --git a/src/spectator/matchers/equality_matcher.cr b/src/spectator/matchers/equality_matcher.cr index 81f0cbb..76e39ce 100644 --- a/src/spectator/matchers/equality_matcher.cr +++ b/src/spectator/matchers/equality_matcher.cr @@ -5,7 +5,7 @@ module Spectator::Matchers # The values are compared with the == operator. struct EqualityMatcher(ExpectedType) < ValueMatcher(ExpectedType) # Checks whether the matcher is satisifed with the expression given to it. - private def match?(actual) + private def match?(actual : TestExpression(T)) forall T expected.value == actual.value end diff --git a/src/spectator/matchers/greater_than_equal_matcher.cr b/src/spectator/matchers/greater_than_equal_matcher.cr index 7d6d7f8..39e8a41 100644 --- a/src/spectator/matchers/greater_than_equal_matcher.cr +++ b/src/spectator/matchers/greater_than_equal_matcher.cr @@ -5,7 +5,7 @@ module Spectator::Matchers # The values are compared with the >= operator. struct GreaterThanEqualMatcher(ExpectedType) < ValueMatcher(ExpectedType) # Checks whether the matcher is satisifed with the expression given to it. - private def match?(actual) + private def match?(actual : TestExpression(T)) forall T actual.value >= expected.value end diff --git a/src/spectator/matchers/greater_than_matcher.cr b/src/spectator/matchers/greater_than_matcher.cr index 81d988d..555ffbf 100644 --- a/src/spectator/matchers/greater_than_matcher.cr +++ b/src/spectator/matchers/greater_than_matcher.cr @@ -5,7 +5,7 @@ module Spectator::Matchers # The values are compared with the > operator. struct GreaterThanMatcher(ExpectedType) < ValueMatcher(ExpectedType) # Checks whether the matcher is satisifed with the expression given to it. - private def match?(actual) + private def match?(actual : TestExpression(T)) forall T actual.value > expected.value end diff --git a/src/spectator/matchers/have_key_matcher.cr b/src/spectator/matchers/have_key_matcher.cr index 1021827..3ac5168 100644 --- a/src/spectator/matchers/have_key_matcher.cr +++ b/src/spectator/matchers/have_key_matcher.cr @@ -5,7 +5,7 @@ module Spectator::Matchers # The set is checked with the `has_key?` method. struct HaveKeyMatcher(ExpectedType) < ValueMatcher(ExpectedType) # Checks whether the matcher is satisifed with the expression given to it. - private def match?(actual) + private def match?(actual : TestExpression(T)) forall T actual.value.has_key?(expected.value) end diff --git a/src/spectator/matchers/have_matcher.cr b/src/spectator/matchers/have_matcher.cr index c2d6af9..3aafe98 100644 --- a/src/spectator/matchers/have_matcher.cr +++ b/src/spectator/matchers/have_matcher.cr @@ -6,7 +6,7 @@ module Spectator::Matchers # Otherwise, it expects an `Enumerable` and iterates over each item until === is true. struct HaveMatcher(ExpectedType) < ValueMatcher(ExpectedType) # Checks whether the matcher is satisifed with the expression given to it. - private def match?(actual) + private def match?(actual : TestExpression(T)) forall T if (value = actual.value).is_a?(String) match_string?(value) else diff --git a/src/spectator/matchers/have_value_matcher.cr b/src/spectator/matchers/have_value_matcher.cr index 429e481..1e8a83c 100644 --- a/src/spectator/matchers/have_value_matcher.cr +++ b/src/spectator/matchers/have_value_matcher.cr @@ -5,7 +5,7 @@ module Spectator::Matchers # The set is checked with the `has_value?` method. struct HaveValueMatcher(ExpectedType) < ValueMatcher(ExpectedType) # Checks whether the matcher is satisifed with the expression given to it. - private def match?(actual) + private def match?(actual : TestExpression(T)) forall T actual.value.has_value?(expected.value) end diff --git a/src/spectator/matchers/inequality_matcher.cr b/src/spectator/matchers/inequality_matcher.cr index caa4d90..b793510 100644 --- a/src/spectator/matchers/inequality_matcher.cr +++ b/src/spectator/matchers/inequality_matcher.cr @@ -5,7 +5,7 @@ module Spectator::Matchers # The values are compared with the != operator. struct InequalityMatcher(ExpectedType) < ValueMatcher(ExpectedType) # Checks whether the matcher is satisifed with the expression given to it. - private def match?(actual) + private def match?(actual : TestExpression(T)) forall T expected.value != actual.value end diff --git a/src/spectator/matchers/less_than_equal_matcher.cr b/src/spectator/matchers/less_than_equal_matcher.cr index c3c413a..0369031 100644 --- a/src/spectator/matchers/less_than_equal_matcher.cr +++ b/src/spectator/matchers/less_than_equal_matcher.cr @@ -5,7 +5,7 @@ module Spectator::Matchers # The values are compared with the <= operator. struct LessThanEqualMatcher(ExpectedType) < ValueMatcher(ExpectedType) # Checks whether the matcher is satisifed with the expression given to it. - private def match?(actual) + private def match?(actual : TestExpression(T)) forall T actual.value <= expected.value end diff --git a/src/spectator/matchers/less_than_matcher.cr b/src/spectator/matchers/less_than_matcher.cr index 185532d..1824d63 100644 --- a/src/spectator/matchers/less_than_matcher.cr +++ b/src/spectator/matchers/less_than_matcher.cr @@ -5,7 +5,7 @@ module Spectator::Matchers # The values are compared with the < operator. struct LessThanMatcher(ExpectedType) < ValueMatcher(ExpectedType) # Checks whether the matcher is satisifed with the expression given to it. - private def match?(actual) + private def match?(actual : TestExpression(T)) forall T actual.value < expected.value end diff --git a/src/spectator/matchers/nil_matcher.cr b/src/spectator/matchers/nil_matcher.cr index 6fc109b..bd4234b 100644 --- a/src/spectator/matchers/nil_matcher.cr +++ b/src/spectator/matchers/nil_matcher.cr @@ -5,7 +5,7 @@ module Spectator::Matchers # The `Object#nil?` method is used for this. struct NilMatcher < StandardMatcher # Checks whether the matcher is satisifed with the expression given to it. - private def match?(actual) + private def match?(actual : TestExpression(T)) forall T actual.value.nil? end diff --git a/src/spectator/matchers/range_matcher.cr b/src/spectator/matchers/range_matcher.cr index 98a0bee..d03482a 100644 --- a/src/spectator/matchers/range_matcher.cr +++ b/src/spectator/matchers/range_matcher.cr @@ -5,7 +5,7 @@ module Spectator::Matchers # The `Range#includes?` method is used for this check. struct RangeMatcher(ExpectedType) < ValueMatcher(ExpectedType) # Checks whether the matcher is satisifed with the expression given to it. - private def match?(actual) + private def match?(actual : TestExpression(T)) forall T expected.value.includes?(actual.value) end diff --git a/src/spectator/matchers/reference_matcher.cr b/src/spectator/matchers/reference_matcher.cr index bc9d709..06898af 100644 --- a/src/spectator/matchers/reference_matcher.cr +++ b/src/spectator/matchers/reference_matcher.cr @@ -5,7 +5,7 @@ module Spectator::Matchers # The values are compared with the `Reference#same?` method. struct ReferenceMatcher(ExpectedType) < ValueMatcher(ExpectedType) # Checks whether the matcher is satisifed with the expression given to it. - private def match?(actual) + private def match?(actual : TestExpression(T)) forall T expected.value.same?(actual.value) end diff --git a/src/spectator/matchers/size_matcher.cr b/src/spectator/matchers/size_matcher.cr index f72b3e2..f02a2d8 100644 --- a/src/spectator/matchers/size_matcher.cr +++ b/src/spectator/matchers/size_matcher.cr @@ -5,7 +5,7 @@ module Spectator::Matchers # The set's `#size` method is used for this check. struct SizeMatcher(ExpectedType) < ValueMatcher(ExpectedType) # Checks whether the matcher is satisifed with the expression given to it. - private def match?(actual) + private def match?(actual : TestExpression(T)) forall T expected.value == actual.value.size end diff --git a/src/spectator/matchers/size_of_matcher.cr b/src/spectator/matchers/size_of_matcher.cr index 4339791..244528d 100644 --- a/src/spectator/matchers/size_of_matcher.cr +++ b/src/spectator/matchers/size_of_matcher.cr @@ -5,7 +5,7 @@ module Spectator::Matchers # The set's `#size` method is used for this check. struct SizeOfMatcher(ExpectedType) < ValueMatcher(ExpectedType) # Checks whether the matcher is satisifed with the expression given to it. - private def match?(actual) + private def match?(actual : TestExpression(T)) forall T expected.value.size == actual.value.size end diff --git a/src/spectator/matchers/truthy_matcher.cr b/src/spectator/matchers/truthy_matcher.cr index 46387c5..9eda876 100644 --- a/src/spectator/matchers/truthy_matcher.cr +++ b/src/spectator/matchers/truthy_matcher.cr @@ -26,7 +26,7 @@ module Spectator::Matchers end # Checks whether the matcher is satisifed with the expression given to it. - private def match?(actual) + private def match?(actual : TestExpression(T)) forall T @truthy == !!actual.value end diff --git a/src/spectator/matchers/type_matcher.cr b/src/spectator/matchers/type_matcher.cr index 928e07b..09af7ed 100644 --- a/src/spectator/matchers/type_matcher.cr +++ b/src/spectator/matchers/type_matcher.cr @@ -5,7 +5,7 @@ module Spectator::Matchers # The values are compared with the `Object#is_a?` method. struct TypeMatcher(Expected) < StandardMatcher # Checks whether the matcher is satisifed with the expression given to it. - private def match?(actual) + private def match?(actual : TestExpression(T)) forall T actual.value.is_a?(Expected) end From ede691dd6a51cfbfa417196376cf35dd2c14b221 Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Sat, 10 Aug 2019 11:10:48 -0600 Subject: [PATCH 78/78] Reorder methods to be in a more standard layout --- src/spectator/matchers/case_matcher.cr | 10 +- src/spectator/matchers/collection_matcher.cr | 10 +- src/spectator/matchers/contain_matcher.cr | 16 +-- src/spectator/matchers/empty_matcher.cr | 10 +- src/spectator/matchers/end_with_matcher.cr | 20 ++-- src/spectator/matchers/equality_matcher.cr | 10 +- .../matchers/greater_than_equal_matcher.cr | 10 +- .../matchers/greater_than_matcher.cr | 12 +- src/spectator/matchers/have_key_matcher.cr | 10 +- src/spectator/matchers/have_matcher.cr | 14 +-- .../matchers/have_predicate_matcher.cr | 22 ++-- src/spectator/matchers/have_value_matcher.cr | 10 +- src/spectator/matchers/inequality_matcher.cr | 10 +- .../matchers/less_than_equal_matcher.cr | 10 +- src/spectator/matchers/less_than_matcher.cr | 10 +- src/spectator/matchers/nil_matcher.cr | 10 +- src/spectator/matchers/predicate_matcher.cr | 22 ++-- src/spectator/matchers/range_matcher.cr | 38 +++--- src/spectator/matchers/reference_matcher.cr | 10 +- src/spectator/matchers/respond_matcher.cr | 22 ++-- src/spectator/matchers/size_matcher.cr | 10 +- src/spectator/matchers/size_of_matcher.cr | 10 +- src/spectator/matchers/standard_matcher.cr | 58 ++++----- src/spectator/matchers/start_with_matcher.cr | 23 ++-- src/spectator/matchers/truthy_matcher.cr | 112 +++++++++--------- src/spectator/matchers/type_matcher.cr | 10 +- 26 files changed, 254 insertions(+), 255 deletions(-) diff --git a/src/spectator/matchers/case_matcher.cr b/src/spectator/matchers/case_matcher.cr index 278431f..3ba55f3 100644 --- a/src/spectator/matchers/case_matcher.cr +++ b/src/spectator/matchers/case_matcher.cr @@ -4,11 +4,6 @@ module Spectator::Matchers # Common matcher that tests whether two values semantically equal each other. # The values are compared with the === operator. struct CaseMatcher(ExpectedType) < ValueMatcher(ExpectedType) - # Checks whether the matcher is satisifed with the expression given to it. - private def match?(actual : TestExpression(T)) forall T - expected.value === actual.value - end - # Short text about the matcher's purpose. # This explains what condition satisfies the matcher. # The description is used when the one-liner syntax is used. @@ -16,6 +11,11 @@ module Spectator::Matchers "matches #{expected.label}" end + # Checks whether the matcher is satisifed with the expression given to it. + private def match?(actual : TestExpression(T)) forall T + expected.value === actual.value + end + # Message displayed when the matcher isn't satisifed. # # This is only called when `#match?` returns false. diff --git a/src/spectator/matchers/collection_matcher.cr b/src/spectator/matchers/collection_matcher.cr index dd84b4e..bfa88f2 100644 --- a/src/spectator/matchers/collection_matcher.cr +++ b/src/spectator/matchers/collection_matcher.cr @@ -5,11 +5,6 @@ require "./value_matcher" module Spectator::Matchers # Matcher for checking that a value is in a collection of other values. struct CollectionMatcher(ExpectedType) < ValueMatcher(ExpectedType) - # Checks whether the matcher is satisifed with the expression given to it. - private def match?(actual : TestExpression(T)) forall T - expected.value.includes?(actual.value) - end - # Short text about the matcher's purpose. # This explains what condition satisfies the matcher. # The description is used when the one-liner syntax is used. @@ -17,6 +12,11 @@ module Spectator::Matchers "is in #{expected.label}" end + # Checks whether the matcher is satisifed with the expression given to it. + private def match?(actual : TestExpression(T)) forall T + expected.value.includes?(actual.value) + end + # Message displayed when the matcher isn't satisifed. # # This is only called when `#match?` returns false. diff --git a/src/spectator/matchers/contain_matcher.cr b/src/spectator/matchers/contain_matcher.cr index 5b4da9e..53389fc 100644 --- a/src/spectator/matchers/contain_matcher.cr +++ b/src/spectator/matchers/contain_matcher.cr @@ -4,13 +4,6 @@ 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?` method. struct ContainMatcher(ExpectedType) < ValueMatcher(ExpectedType) - # Checks whether the matcher is satisifed with the expression given to it. - private def match?(actual : TestExpression(T)) forall T - expected.value.all? do |item| - actual.value.includes?(item) - end - end - # Short text about the matcher's purpose. # This explains what condition satisfies the matcher. # The description is used when the one-liner syntax is used. @@ -18,6 +11,13 @@ module Spectator::Matchers "contains #{expected.label}" end + # Checks whether the matcher is satisifed with the expression given to it. + private def match?(actual : TestExpression(T)) forall T + expected.value.all? do |item| + actual.value.includes?(item) + end + end + # Message displayed when the matcher isn't satisifed. # # This is only called when `#match?` returns false. @@ -38,7 +38,7 @@ module Spectator::Matchers private def failure_message_when_negated(actual) "#{actual.label} contains #{expected.label}" end - + # Additional information about the match failure. # The return value is a NamedTuple with Strings for each value. private def values(actual) diff --git a/src/spectator/matchers/empty_matcher.cr b/src/spectator/matchers/empty_matcher.cr index 897f5d1..a8ccfe9 100644 --- a/src/spectator/matchers/empty_matcher.cr +++ b/src/spectator/matchers/empty_matcher.cr @@ -4,11 +4,6 @@ module Spectator::Matchers # Matcher that tests whether a collection is empty. # The values are checked with the `empty?` method. struct EmptyMatcher < StandardMatcher - # Checks whether the matcher is satisifed with the expression given to it. - private def match?(actual : TestExpression(T)) forall T - actual.value.empty? - end - # Short text about the matcher's purpose. # This explains what condition satisfies the matcher. # The description is used when the one-liner syntax is used. @@ -16,6 +11,11 @@ module Spectator::Matchers "is empty" end + # Checks whether the matcher is satisifed with the expression given to it. + private def match?(actual : TestExpression(T)) forall T + actual.value.empty? + end + # Message displayed when the matcher isn't satisifed. # # This is only called when `#match?` returns false. diff --git a/src/spectator/matchers/end_with_matcher.cr b/src/spectator/matchers/end_with_matcher.cr index 448d1e6..ed76381 100644 --- a/src/spectator/matchers/end_with_matcher.cr +++ b/src/spectator/matchers/end_with_matcher.cr @@ -30,6 +30,16 @@ module Spectator::Matchers end end + # Performs the test against the expression, but inverted. + # A successful match with `#match` should normally fail for this method, and vice-versa. + def negated_match(actual : TestExpression(T)) : MatchData forall T + if actual.value.responds_to?(:ends_with?) + negated_match_ends_with(actual) + else + negated_match_last(actual) + end + end + # Checks whether the actual value ends with the expected value. # This method expects (and uses) the `#ends_with?` method on the value. private def match_ends_with(actual_value, actual_label) @@ -60,16 +70,6 @@ module Spectator::Matchers end end - # Performs the test against the expression, but inverted. - # A successful match with `#match` should normally fail for this method, and vice-versa. - def negated_match(actual : TestExpression(T)) : MatchData forall T - if actual.value.responds_to?(:ends_with?) - negated_match_ends_with(actual) - else - negated_match_last(actual) - end - end - # Checks whether the actual value does not end with the expected value. # This method expects (and uses) the `#ends_with?` method on the value. private def negated_match_ends_with(actual) diff --git a/src/spectator/matchers/equality_matcher.cr b/src/spectator/matchers/equality_matcher.cr index 76e39ce..5d58454 100644 --- a/src/spectator/matchers/equality_matcher.cr +++ b/src/spectator/matchers/equality_matcher.cr @@ -4,11 +4,6 @@ module Spectator::Matchers # Common matcher that tests whether two values equal each other. # The values are compared with the == operator. struct EqualityMatcher(ExpectedType) < ValueMatcher(ExpectedType) - # Checks whether the matcher is satisifed with the expression given to it. - private def match?(actual : TestExpression(T)) forall T - expected.value == actual.value - end - # Short text about the matcher's purpose. # This explains what condition satisfies the matcher. # The description is used when the one-liner syntax is used. @@ -16,6 +11,11 @@ module Spectator::Matchers "equals #{expected.label}" end + # Checks whether the matcher is satisifed with the expression given to it. + private def match?(actual : TestExpression(T)) forall T + expected.value == actual.value + end + # Message displayed when the matcher isn't satisifed. # # This is only called when `#match?` returns false. diff --git a/src/spectator/matchers/greater_than_equal_matcher.cr b/src/spectator/matchers/greater_than_equal_matcher.cr index 39e8a41..5f4e20b 100644 --- a/src/spectator/matchers/greater_than_equal_matcher.cr +++ b/src/spectator/matchers/greater_than_equal_matcher.cr @@ -4,11 +4,6 @@ module Spectator::Matchers # Matcher that tests whether one value is greater than or equal to another. # The values are compared with the >= operator. struct GreaterThanEqualMatcher(ExpectedType) < ValueMatcher(ExpectedType) - # Checks whether the matcher is satisifed with the expression given to it. - private def match?(actual : TestExpression(T)) forall T - actual.value >= expected.value - end - # Short text about the matcher's purpose. # This explains what condition satisfies the matcher. # The description is used when the one-liner syntax is used. @@ -16,6 +11,11 @@ module Spectator::Matchers "greater than or equal to #{expected.label}" end + # Checks whether the matcher is satisifed with the expression given to it. + private def match?(actual : TestExpression(T)) forall T + actual.value >= expected.value + end + # Message displayed when the matcher isn't satisifed. # # This is only called when `#match?` returns false. diff --git a/src/spectator/matchers/greater_than_matcher.cr b/src/spectator/matchers/greater_than_matcher.cr index 555ffbf..c51303b 100644 --- a/src/spectator/matchers/greater_than_matcher.cr +++ b/src/spectator/matchers/greater_than_matcher.cr @@ -4,11 +4,6 @@ module Spectator::Matchers # Matcher that tests whether one value is greater than another. # The values are compared with the > operator. struct GreaterThanMatcher(ExpectedType) < ValueMatcher(ExpectedType) - # Checks whether the matcher is satisifed with the expression given to it. - private def match?(actual : TestExpression(T)) forall T - actual.value > expected.value - end - # Short text about the matcher's purpose. # This explains what condition satisfies the matcher. # The description is used when the one-liner syntax is used. @@ -16,6 +11,11 @@ module Spectator::Matchers "greater than #{expected.label}" end + # Checks whether the matcher is satisifed with the expression given to it. + private def match?(actual : TestExpression(T)) forall T + actual.value > expected.value + end + # Message displayed when the matcher isn't satisifed. # # This is only called when `#match?` returns false. @@ -45,7 +45,7 @@ module Spectator::Matchers actual: actual.value.inspect, } end - + # Additional information about the match failure when negated. # The return value is a NamedTuple with Strings for each value. private def negated_values(actual) diff --git a/src/spectator/matchers/have_key_matcher.cr b/src/spectator/matchers/have_key_matcher.cr index 3ac5168..e3f2560 100644 --- a/src/spectator/matchers/have_key_matcher.cr +++ b/src/spectator/matchers/have_key_matcher.cr @@ -4,11 +4,6 @@ module Spectator::Matchers # Matcher that tests whether a `Hash` (or similar type) has a given key. # The set is checked with the `has_key?` method. struct HaveKeyMatcher(ExpectedType) < ValueMatcher(ExpectedType) - # Checks whether the matcher is satisifed with the expression given to it. - private def match?(actual : TestExpression(T)) forall T - actual.value.has_key?(expected.value) - end - # Short text about the matcher's purpose. # This explains what condition satisfies the matcher. # The description is used when the one-liner syntax is used. @@ -16,6 +11,11 @@ module Spectator::Matchers "has key #{expected.label}" end + # Checks whether the matcher is satisifed with the expression given to it. + private def match?(actual : TestExpression(T)) forall T + actual.value.has_key?(expected.value) + end + # Message displayed when the matcher isn't satisifed. # # This is only called when `#match?` returns false. diff --git a/src/spectator/matchers/have_matcher.cr b/src/spectator/matchers/have_matcher.cr index 3aafe98..5dd0151 100644 --- a/src/spectator/matchers/have_matcher.cr +++ b/src/spectator/matchers/have_matcher.cr @@ -5,6 +5,13 @@ module Spectator::Matchers # For a `String`, the `includes?` method is used. # Otherwise, it expects an `Enumerable` and iterates over each item until === is true. struct HaveMatcher(ExpectedType) < ValueMatcher(ExpectedType) + # Short text about the matcher's purpose. + # This explains what condition satisfies the matcher. + # The description is used when the one-liner syntax is used. + def description + "includes #{expected.label}" + end + # Checks whether the matcher is satisifed with the expression given to it. private def match?(actual : TestExpression(T)) forall T if (value = actual.value).is_a?(String) @@ -33,13 +40,6 @@ module Spectator::Matchers end end - # Short text about the matcher's purpose. - # This explains what condition satisfies the matcher. - # The description is used when the one-liner syntax is used. - def description - "includes #{expected.label}" - end - # Message displayed when the matcher isn't satisifed. # # This is only called when `#match?` returns false. diff --git a/src/spectator/matchers/have_predicate_matcher.cr b/src/spectator/matchers/have_predicate_matcher.cr index 8b9ff1f..dedc70e 100644 --- a/src/spectator/matchers/have_predicate_matcher.cr +++ b/src/spectator/matchers/have_predicate_matcher.cr @@ -75,17 +75,6 @@ module Spectator::Matchers {% end %} end - # Produces the tuple for the failed match data from a snapshot of the predicate methods. - private def values(snapshot) - {% begin %} - { - {% for attribute in ExpectedType.keys %} - {{attribute}}: snapshot[{{attribute.symbolize}}].inspect, - {% end %} - } - {% end %} - end - # Checks if all predicate methods from the snapshot of them are satisified. private def match?(snapshot) # Test each predicate and immediately return false if one is false. @@ -96,5 +85,16 @@ module Spectator::Matchers # All checks passed if this point is reached. true end + + # Produces the tuple for the failed match data from a snapshot of the predicate methods. + private def values(snapshot) + {% begin %} + { + {% for attribute in ExpectedType.keys %} + {{attribute}}: snapshot[{{attribute.symbolize}}].inspect, + {% end %} + } + {% end %} + end end end diff --git a/src/spectator/matchers/have_value_matcher.cr b/src/spectator/matchers/have_value_matcher.cr index 1e8a83c..9c722f5 100644 --- a/src/spectator/matchers/have_value_matcher.cr +++ b/src/spectator/matchers/have_value_matcher.cr @@ -4,11 +4,6 @@ module Spectator::Matchers # Matcher that tests whether a `Hash` (or similar type) has a given value. # The set is checked with the `has_value?` method. struct HaveValueMatcher(ExpectedType) < ValueMatcher(ExpectedType) - # Checks whether the matcher is satisifed with the expression given to it. - private def match?(actual : TestExpression(T)) forall T - actual.value.has_value?(expected.value) - end - # Short text about the matcher's purpose. # This explains what condition satisfies the matcher. # The description is used when the one-liner syntax is used. @@ -16,6 +11,11 @@ module Spectator::Matchers "has value #{expected.label}" end + # Checks whether the matcher is satisifed with the expression given to it. + private def match?(actual : TestExpression(T)) forall T + actual.value.has_value?(expected.value) + end + # Message displayed when the matcher isn't satisifed. # # This is only called when `#match?` returns false. diff --git a/src/spectator/matchers/inequality_matcher.cr b/src/spectator/matchers/inequality_matcher.cr index b793510..7f175f1 100644 --- a/src/spectator/matchers/inequality_matcher.cr +++ b/src/spectator/matchers/inequality_matcher.cr @@ -4,11 +4,6 @@ module Spectator::Matchers # Matcher that tests whether two values do not equal each other. # The values are compared with the != operator. struct InequalityMatcher(ExpectedType) < ValueMatcher(ExpectedType) - # Checks whether the matcher is satisifed with the expression given to it. - private def match?(actual : TestExpression(T)) forall T - expected.value != actual.value - end - # Short text about the matcher's purpose. # This explains what condition satisfies the matcher. # The description is used when the one-liner syntax is used. @@ -16,6 +11,11 @@ module Spectator::Matchers "is not equal to #{expected.label}" end + # Checks whether the matcher is satisifed with the expression given to it. + private def match?(actual : TestExpression(T)) forall T + expected.value != actual.value + end + # Message displayed when the matcher isn't satisifed. # # This is only called when `#match?` returns false. diff --git a/src/spectator/matchers/less_than_equal_matcher.cr b/src/spectator/matchers/less_than_equal_matcher.cr index 0369031..900c7a4 100644 --- a/src/spectator/matchers/less_than_equal_matcher.cr +++ b/src/spectator/matchers/less_than_equal_matcher.cr @@ -4,11 +4,6 @@ module Spectator::Matchers # Matcher that tests whether one value is less than or equal to another. # The values are compared with the <= operator. struct LessThanEqualMatcher(ExpectedType) < ValueMatcher(ExpectedType) - # Checks whether the matcher is satisifed with the expression given to it. - private def match?(actual : TestExpression(T)) forall T - actual.value <= expected.value - end - # Short text about the matcher's purpose. # This explains what condition satisfies the matcher. # The description is used when the one-liner syntax is used. @@ -16,6 +11,11 @@ module Spectator::Matchers "less than or equal to #{expected.label}" end + # Checks whether the matcher is satisifed with the expression given to it. + private def match?(actual : TestExpression(T)) forall T + actual.value <= expected.value + end + # Message displayed when the matcher isn't satisifed. # # This is only called when `#match?` returns false. diff --git a/src/spectator/matchers/less_than_matcher.cr b/src/spectator/matchers/less_than_matcher.cr index 1824d63..5f2ec2c 100644 --- a/src/spectator/matchers/less_than_matcher.cr +++ b/src/spectator/matchers/less_than_matcher.cr @@ -4,11 +4,6 @@ module Spectator::Matchers # Matcher that tests whether one value is less than another. # The values are compared with the < operator. struct LessThanMatcher(ExpectedType) < ValueMatcher(ExpectedType) - # Checks whether the matcher is satisifed with the expression given to it. - private def match?(actual : TestExpression(T)) forall T - actual.value < expected.value - end - # Short text about the matcher's purpose. # This explains what condition satisfies the matcher. # The description is used when the one-liner syntax is used. @@ -16,6 +11,11 @@ module Spectator::Matchers "less than #{expected.label}" end + # Checks whether the matcher is satisifed with the expression given to it. + private def match?(actual : TestExpression(T)) forall T + actual.value < expected.value + end + # Message displayed when the matcher isn't satisifed. # # This is only called when `#match?` returns false. diff --git a/src/spectator/matchers/nil_matcher.cr b/src/spectator/matchers/nil_matcher.cr index bd4234b..343fe79 100644 --- a/src/spectator/matchers/nil_matcher.cr +++ b/src/spectator/matchers/nil_matcher.cr @@ -4,11 +4,6 @@ module Spectator::Matchers # Common matcher that tests whether a value is nil. # The `Object#nil?` method is used for this. struct NilMatcher < StandardMatcher - # Checks whether the matcher is satisifed with the expression given to it. - private def match?(actual : TestExpression(T)) forall T - actual.value.nil? - end - # Short text about the matcher's purpose. # This explains what condition satisfies the matcher. # The description is used when the one-liner syntax is used. @@ -16,6 +11,11 @@ module Spectator::Matchers "is nil" end + # Checks whether the matcher is satisifed with the expression given to it. + private def match?(actual : TestExpression(T)) forall T + actual.value.nil? + end + # Message displayed when the matcher isn't satisifed. # # This is only called when `#match?` returns false. diff --git a/src/spectator/matchers/predicate_matcher.cr b/src/spectator/matchers/predicate_matcher.cr index 9d58073..46d3d94 100644 --- a/src/spectator/matchers/predicate_matcher.cr +++ b/src/spectator/matchers/predicate_matcher.cr @@ -74,17 +74,6 @@ module Spectator::Matchers {% end %} end - # Produces the tuple for the failed match data from a snapshot of the predicate methods. - private def values(snapshot) - {% begin %} - { - {% for attribute in ExpectedType.keys %} - {{attribute}}: snapshot[{{attribute.symbolize}}].inspect, - {% end %} - } - {% end %} - end - # Checks if all predicate methods from the snapshot of them are satisified. private def match?(snapshot) # Test each predicate and immediately return false if one is false. @@ -95,5 +84,16 @@ module Spectator::Matchers # All checks passed if this point is reached. true end + + # Produces the tuple for the failed match data from a snapshot of the predicate methods. + private def values(snapshot) + {% begin %} + { + {% for attribute in ExpectedType.keys %} + {{attribute}}: snapshot[{{attribute.symbolize}}].inspect, + {% end %} + } + {% end %} + end end end diff --git a/src/spectator/matchers/range_matcher.cr b/src/spectator/matchers/range_matcher.cr index d03482a..6eba568 100644 --- a/src/spectator/matchers/range_matcher.cr +++ b/src/spectator/matchers/range_matcher.cr @@ -4,11 +4,6 @@ module Spectator::Matchers # Matcher that tests whether a value is in a given range. # The `Range#includes?` method is used for this check. struct RangeMatcher(ExpectedType) < ValueMatcher(ExpectedType) - # Checks whether the matcher is satisifed with the expression given to it. - private def match?(actual : TestExpression(T)) forall T - expected.value.includes?(actual.value) - end - # Short text about the matcher's purpose. # This explains what condition satisfies the matcher. # The description is used when the one-liner syntax is used. @@ -16,6 +11,25 @@ module Spectator::Matchers "is in #{expected.label}" end + # Returns a new matcher, with the same bounds, but uses an inclusive range. + def inclusive + new_range = Range.new(range.begin, range.end, exclusive: false) + expected = TestValue.new(new_range, label) + RangeMatcher.new(expected) + end + + # Returns a new matcher, with the same bounds, but uses an exclusive range. + def exclusive + new_range = Range.new(range.begin, range.end, exclusive: true) + expected = TestValue.new(new_range, label) + RangeMatcher.new(expected) + end + + # Checks whether the matcher is satisifed with the expression given to it. + private def match?(actual : TestExpression(T)) forall T + expected.value.includes?(actual.value) + end + # Message displayed when the matcher isn't satisifed. # # This is only called when `#match?` returns false. @@ -57,20 +71,6 @@ module Spectator::Matchers } end - # Returns a new matcher, with the same bounds, but uses an inclusive range. - def inclusive - new_range = Range.new(range.begin, range.end, exclusive: false) - expected = TestValue.new(new_range, label) - RangeMatcher.new(expected) - end - - # Returns a new matcher, with the same bounds, but uses an exclusive range. - def exclusive - new_range = Range.new(range.begin, range.end, exclusive: true) - expected = TestValue.new(new_range, label) - RangeMatcher.new(expected) - end - # Gets the expected range. private def range expected.value diff --git a/src/spectator/matchers/reference_matcher.cr b/src/spectator/matchers/reference_matcher.cr index 06898af..633e619 100644 --- a/src/spectator/matchers/reference_matcher.cr +++ b/src/spectator/matchers/reference_matcher.cr @@ -4,11 +4,6 @@ module Spectator::Matchers # Matcher that tests whether two references are the same. # The values are compared with the `Reference#same?` method. struct ReferenceMatcher(ExpectedType) < ValueMatcher(ExpectedType) - # Checks whether the matcher is satisifed with the expression given to it. - private def match?(actual : TestExpression(T)) forall T - expected.value.same?(actual.value) - end - # Short text about the matcher's purpose. # This explains what condition satisfies the matcher. # The description is used when the one-liner syntax is used. @@ -16,6 +11,11 @@ module Spectator::Matchers "is #{expected.label}" end + # Checks whether the matcher is satisifed with the expression given to it. + private def match?(actual : TestExpression(T)) forall T + expected.value.same?(actual.value) + end + # Message displayed when the matcher isn't satisifed. # # This is only called when `#match?` returns false. diff --git a/src/spectator/matchers/respond_matcher.cr b/src/spectator/matchers/respond_matcher.cr index a3869b4..d842167 100644 --- a/src/spectator/matchers/respond_matcher.cr +++ b/src/spectator/matchers/respond_matcher.cr @@ -13,12 +13,6 @@ module Spectator::Matchers "responds to #{label}" end - # Generated, user-friendly, string for the expected value. - private def label - # Prefix every method name with # and join them with commas. - {{ExpectedType.keys.map { |e| "##{e}".id }.splat.stringify}} - end - # Actually performs the test against the expression. def match(actual : TestExpression(T)) : MatchData forall T snapshot = snapshot_values(actual.value) @@ -52,6 +46,13 @@ module Spectator::Matchers {% end %} end + # Checks if all results from the snapshot are satisified. + private def match?(snapshot) + # The snapshot did the hard work. + # Here just check if all values are true. + snapshot.values.all? + end + # Produces the tuple for the failed match data from a snapshot of the results. private def values(snapshot) {% begin %} @@ -63,11 +64,10 @@ module Spectator::Matchers {% end %} end - # Checks if all results from the snapshot are satisified. - private def match?(snapshot) - # The snapshot did the hard work. - # Here just check if all values are true. - snapshot.values.all? + # Generated, user-friendly, string for the expected value. + private def label + # Prefix every method name with # and join them with commas. + {{ExpectedType.keys.map { |e| "##{e}".id }.splat.stringify}} end end end diff --git a/src/spectator/matchers/size_matcher.cr b/src/spectator/matchers/size_matcher.cr index f02a2d8..1ab6e3d 100644 --- a/src/spectator/matchers/size_matcher.cr +++ b/src/spectator/matchers/size_matcher.cr @@ -4,11 +4,6 @@ module Spectator::Matchers # Matcher that tests whether a set has a specified number of elements. # The set's `#size` method is used for this check. struct SizeMatcher(ExpectedType) < ValueMatcher(ExpectedType) - # Checks whether the matcher is satisifed with the expression given to it. - private def match?(actual : TestExpression(T)) forall T - expected.value == actual.value.size - end - # Short text about the matcher's purpose. # This explains what condition satisfies the matcher. # The description is used when the one-liner syntax is used. @@ -16,6 +11,11 @@ module Spectator::Matchers "has size #{expected.label}" end + # Checks whether the matcher is satisifed with the expression given to it. + private def match?(actual : TestExpression(T)) forall T + expected.value == actual.value.size + end + # Message displayed when the matcher isn't satisifed. # # This is only called when `#match?` returns false. diff --git a/src/spectator/matchers/size_of_matcher.cr b/src/spectator/matchers/size_of_matcher.cr index 244528d..3e9f1cf 100644 --- a/src/spectator/matchers/size_of_matcher.cr +++ b/src/spectator/matchers/size_of_matcher.cr @@ -4,11 +4,6 @@ module Spectator::Matchers # Matcher that tests whether a set has the same number of elements as another set. # The set's `#size` method is used for this check. struct SizeOfMatcher(ExpectedType) < ValueMatcher(ExpectedType) - # Checks whether the matcher is satisifed with the expression given to it. - private def match?(actual : TestExpression(T)) forall T - expected.value.size == actual.value.size - end - # Short text about the matcher's purpose. # This explains what condition satisfies the matcher. # The description is used when the one-liner syntax is used. @@ -16,6 +11,11 @@ module Spectator::Matchers "is the same size as #{expected.label}" end + # Checks whether the matcher is satisifed with the expression given to it. + private def match?(actual : TestExpression(T)) forall T + expected.value.size == actual.value.size + end + # Message displayed when the matcher isn't satisifed. # # This is only called when `#match?` returns false. diff --git a/src/spectator/matchers/standard_matcher.cr b/src/spectator/matchers/standard_matcher.cr index 18753bb..414e491 100644 --- a/src/spectator/matchers/standard_matcher.cr +++ b/src/spectator/matchers/standard_matcher.cr @@ -17,6 +17,35 @@ module Spectator::Matchers # then the `#values` and `#negated_values` methods can be overriden. # Finally, define a `#description` message that can be used for the one-liner "it" syntax. abstract struct StandardMatcher < Matcher + # Actually performs the test against the expression (value or block). + # + # This method calls the abstract `#match?` method. + # If it returns true, then a `SuccessfulMatchData` instance is returned. + # Otherwise, a `FailedMatchData` instance is returned. + # Additionally, `#failure_message` and `#values` are called for a failed match. + def match(actual : TestExpression(T)) : MatchData forall T + if match?(actual) + SuccessfulMatchData.new + else + FailedMatchData.new(failure_message(actual), **values(actual)) + end + end + + # Performs the test against the expression (value or block), but inverted. + # A successful match with `#match` should normally fail for this method, and vice-versa. + # + # This method calls the abstract `#does_not_match?` method. + # If it returns true, then a `SuccessfulMatchData` instance is returned. + # Otherwise, a `FailedMatchData` instance is returned. + # Additionally, `#failure_message_when_negated` and `#negated_values` are called for a failed match. + def negated_match(actual : TestExpression(T)) : MatchData forall T + if does_not_match?(actual) + SuccessfulMatchData.new + else + FailedMatchData.new(failure_message_when_negated(actual), **negated_values(actual)) + end + end + # Message displayed when the matcher isn't satisifed. # # This is only called when `#match?` returns false. @@ -96,34 +125,5 @@ module Spectator::Matchers private def negated_values(actual : TestExpression(T)) forall T values(actual) end - - # Actually performs the test against the expression (value or block). - # - # This method calls the abstract `#match?` method. - # If it returns true, then a `SuccessfulMatchData` instance is returned. - # Otherwise, a `FailedMatchData` instance is returned. - # Additionally, `#failure_message` and `#values` are called for a failed match. - def match(actual : TestExpression(T)) : MatchData forall T - if match?(actual) - SuccessfulMatchData.new - else - FailedMatchData.new(failure_message(actual), **values(actual)) - end - end - - # Performs the test against the expression (value or block), but inverted. - # A successful match with `#match` should normally fail for this method, and vice-versa. - # - # This method calls the abstract `#does_not_match?` method. - # If it returns true, then a `SuccessfulMatchData` instance is returned. - # Otherwise, a `FailedMatchData` instance is returned. - # Additionally, `#failure_message_when_negated` and `#negated_values` are called for a failed match. - def negated_match(actual : TestExpression(T)) : MatchData forall T - if does_not_match?(actual) - SuccessfulMatchData.new - else - FailedMatchData.new(failure_message_when_negated(actual), **negated_values(actual)) - end - end end end diff --git a/src/spectator/matchers/start_with_matcher.cr b/src/spectator/matchers/start_with_matcher.cr index 15219c7..067f52a 100644 --- a/src/spectator/matchers/start_with_matcher.cr +++ b/src/spectator/matchers/start_with_matcher.cr @@ -1,5 +1,4 @@ - - # Checks whether the last element of the value is the expected value. +# Checks whether the last element of the value is the expected value. # This method expects that the actual value is a set (enumerable).require "./value_matcher" module Spectator::Matchers @@ -30,6 +29,16 @@ module Spectator::Matchers end end + # Performs the test against the expression, but inverted. + # A successful match with `#match` should normally fail for this method, and vice-versa. + def negated_match(actual : TestExpression(T)) : MatchData forall T + if (value = actual.value).responds_to?(:starts_with?) + negated_match_starts_with(value, actual.label) + else + negated_match_first(value, actual.label) + end + end + # Checks whether the actual value starts with the expected value. # This method expects (and uses) the `#starts_with?` method on the value. private def match_starts_with(actual_value, actual_label) @@ -60,16 +69,6 @@ module Spectator::Matchers end end - # Performs the test against the expression, but inverted. - # A successful match with `#match` should normally fail for this method, and vice-versa. - def negated_match(actual : TestExpression(T)) : MatchData forall T - if (value = actual.value).responds_to?(:starts_with?) - negated_match_starts_with(value, actual.label) - else - negated_match_first(value, actual.label) - end - end - # Checks whether the actual value does not start with the expected value. # This method expects (and uses) the `#starts_with?` method on the value. private def negated_match_starts_with(actual_value, actual_label) diff --git a/src/spectator/matchers/truthy_matcher.cr b/src/spectator/matchers/truthy_matcher.cr index 9eda876..34aea3b 100644 --- a/src/spectator/matchers/truthy_matcher.cr +++ b/src/spectator/matchers/truthy_matcher.cr @@ -15,21 +15,6 @@ module Spectator::Matchers def initialize(@truthy : Bool = true) end - # Generated, user-friendly, string for the expected value. - private def label - @truthy ? "truthy" : "falsey" - end - - # Generated, user-friendly, string for the unexpected value. - private def negated_label - @truthy ? "falsey" : "truthy" - end - - # Checks whether the matcher is satisifed with the expression given to it. - private def match?(actual : TestExpression(T)) forall T - @truthy == !!actual.value - end - # Short text about the matcher's purpose. # This explains what condition satisfies the matcher. # The description is used when the one-liner syntax is used. @@ -37,47 +22,6 @@ module Spectator::Matchers "is #{label}" end - # Message displayed when the matcher isn't satisifed. - # - # This is only called when `#match?` returns false. - # - # The message should typically only contain the test expression labels. - # Actual values should be returned by `#values`. - private def failure_message(actual) - "#{actual.label} is #{negated_label}" - end - - # Message displayed when the matcher isn't satisifed and is negated. - # This is essentially what would satisfy the matcher if it wasn't negated. - # - # This is only called when `#does_not_match?` returns false. - # - # The message should typically only contain the test expression labels. - # Actual values should be returned by `#values`. - private def failure_message_when_negated(actual) - "#{actual.label} is #{label}" - end - - # Additional information about the match failure. - # The return value is a NamedTuple with Strings for each value. - private def values(actual) - { - expected: @truthy ? "Not false or nil" : "false or nil", - actual: actual.value.inspect, - truthy: !!actual.value.inspect, - } - end - - # Additional information about the match failure when negated. - # The return value is a NamedTuple with Strings for each value. - private def negated_values(actual) - { - expected: @truthy ? "false or nil" : "Not false or nil", - actual: actual.value.inspect, - truthy: !!actual.value.inspect, - } - end - # Creates a matcher that checks if a value is less than an expected value. # The spec would look like: # ``` @@ -137,5 +81,61 @@ module Spectator::Matchers expected = TestValue.new(value) InequalityMatcher.new(expected) end + + # Checks whether the matcher is satisifed with the expression given to it. + private def match?(actual : TestExpression(T)) forall T + @truthy == !!actual.value + end + + # Message displayed when the matcher isn't satisifed. + # + # This is only called when `#match?` returns false. + # + # The message should typically only contain the test expression labels. + # Actual values should be returned by `#values`. + private def failure_message(actual) + "#{actual.label} is #{negated_label}" + end + + # Message displayed when the matcher isn't satisifed and is negated. + # This is essentially what would satisfy the matcher if it wasn't negated. + # + # This is only called when `#does_not_match?` returns false. + # + # The message should typically only contain the test expression labels. + # Actual values should be returned by `#values`. + private def failure_message_when_negated(actual) + "#{actual.label} is #{label}" + end + + # Additional information about the match failure. + # The return value is a NamedTuple with Strings for each value. + private def values(actual) + { + expected: @truthy ? "Not false or nil" : "false or nil", + actual: actual.value.inspect, + truthy: !!actual.value.inspect, + } + end + + # Additional information about the match failure when negated. + # The return value is a NamedTuple with Strings for each value. + private def negated_values(actual) + { + expected: @truthy ? "false or nil" : "Not false or nil", + actual: actual.value.inspect, + truthy: !!actual.value.inspect, + } + end + + # Generated, user-friendly, string for the expected value. + private def label + @truthy ? "truthy" : "falsey" + end + + # Generated, user-friendly, string for the unexpected value. + private def negated_label + @truthy ? "falsey" : "truthy" + end end end diff --git a/src/spectator/matchers/type_matcher.cr b/src/spectator/matchers/type_matcher.cr index 09af7ed..2b44296 100644 --- a/src/spectator/matchers/type_matcher.cr +++ b/src/spectator/matchers/type_matcher.cr @@ -4,11 +4,6 @@ module Spectator::Matchers # Matcher that tests a value is of a specified type. # The values are compared with the `Object#is_a?` method. struct TypeMatcher(Expected) < StandardMatcher - # Checks whether the matcher is satisifed with the expression given to it. - private def match?(actual : TestExpression(T)) forall T - actual.value.is_a?(Expected) - end - # Short text about the matcher's purpose. # This explains what condition satisfies the matcher. # The description is used when the one-liner syntax is used. @@ -16,6 +11,11 @@ module Spectator::Matchers "is as #{Expected}" end + # Checks whether the matcher is satisifed with the expression given to it. + private def match?(actual : TestExpression(T)) forall T + actual.value.is_a?(Expected) + end + # Message displayed when the matcher isn't satisifed. # # This is only called when `#match?` returns false.