mirror of
https://gitea.invidious.io/iv-org/shard-spectator.git
synced 2024-08-15 00:53:35 +00:00
Support custom messages for failed expectations
Fixes https://gitlab.com/arctic-fox/spectator/-/issues/28
This commit is contained in:
parent
0c4379c731
commit
e8413db33f
4 changed files with 94 additions and 44 deletions
|
@ -23,6 +23,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
- Add `before_suite` and `after_suite` hooks. [#21](https://gitlab.com/arctic-fox/spectator/-/issues/21)
|
||||
- Support defining hooks in `Spectator.configure` block. [#21](https://gitlab.com/arctic-fox/spectator/-/issues/21)
|
||||
- Examples with failures or skipped during execution will report the location of that result. [#57](https://gitlab.com/arctic-fox/spectator/-/issues/57)
|
||||
- Support custom messages for failed expectations. [#28](https://gitlab.com/arctic-fox/spectator/-/issues/28)
|
||||
|
||||
### Changed
|
||||
- `around_each` hooks wrap `before_all` and `after_all` hooks. [#12](https://github.com/icy-arctic-fox/spectator/issues/12)
|
||||
|
|
31
spec/custom_message_spec.cr
Normal file
31
spec/custom_message_spec.cr
Normal file
|
@ -0,0 +1,31 @@
|
|||
require "./spec_helper"
|
||||
|
||||
Spectator.describe Spectator do
|
||||
it "supports custom expectation messages" do
|
||||
expect do
|
||||
expect(false).to be_true, "paradox!"
|
||||
end.to raise_error(Spectator::ExampleFailed, "paradox!")
|
||||
end
|
||||
|
||||
it "supports custom expectation messages with a proc" do
|
||||
count = 0
|
||||
expect do
|
||||
expect(false).to be_true, ->{ count += 1; "Failed #{count} times" }
|
||||
end.to raise_error(Spectator::ExampleFailed, "Failed 1 times")
|
||||
end
|
||||
|
||||
context "not_to" do
|
||||
it "supports custom expectation messages" do
|
||||
expect do
|
||||
expect(true).not_to be_true, "paradox!"
|
||||
end.to raise_error(Spectator::ExampleFailed, "paradox!")
|
||||
end
|
||||
|
||||
it "supports custom expectation messages with a proc" do
|
||||
count = 0
|
||||
expect do
|
||||
expect(true).not_to be_true, ->{ count += 1; "Failed #{count} times" }
|
||||
end.to raise_error(Spectator::ExampleFailed, "Failed 1 times")
|
||||
end
|
||||
end
|
||||
end
|
|
@ -24,7 +24,13 @@ module Spectator
|
|||
|
||||
# If nil, then the match was successful.
|
||||
def failure_message?
|
||||
@match_data.as?(Matchers::FailedMatchData).try(&.failure_message)
|
||||
return unless match_data = @match_data.as?(Matchers::FailedMatchData)
|
||||
|
||||
case message = @message
|
||||
when String then message
|
||||
when Proc(String) then @message = message.call # Cache result of call.
|
||||
else match_data.failure_message
|
||||
end
|
||||
end
|
||||
|
||||
# Description of why the match failed.
|
||||
|
@ -50,7 +56,9 @@ module Spectator
|
|||
# Creates the expectation.
|
||||
# The *match_data* comes from the result of calling `Matcher#match`.
|
||||
# The *location* is the location of the expectation in source code, if available.
|
||||
def initialize(@match_data : Matchers::MatchData, @location : Location? = nil)
|
||||
# A custom *message* can be used in case of a failure.
|
||||
def initialize(@match_data : Matchers::MatchData, @location : Location? = nil,
|
||||
@message : String? | Proc(String) = nil)
|
||||
end
|
||||
|
||||
# Creates the JSON representation of the expectation.
|
||||
|
@ -92,9 +100,10 @@ module Spectator
|
|||
end
|
||||
|
||||
# Asserts that some criteria defined by the matcher is satisfied.
|
||||
def to(matcher) : Nil
|
||||
# Allows a custom message to be used.
|
||||
def to(matcher, message = nil) : Nil
|
||||
match_data = matcher.match(@expression)
|
||||
report(match_data)
|
||||
report(match_data, message)
|
||||
end
|
||||
|
||||
def to(stub : Mocks::MethodStub) : Nil
|
||||
|
@ -110,9 +119,16 @@ module Spectator
|
|||
|
||||
# Asserts that some criteria defined by the matcher is not satisfied.
|
||||
# This is effectively the opposite of `#to`.
|
||||
def to_not(matcher) : Nil
|
||||
# Allows a custom message to be used.
|
||||
def to_not(matcher, message = nil) : Nil
|
||||
match_data = matcher.negated_match(@expression)
|
||||
report(match_data)
|
||||
report(match_data, message)
|
||||
end
|
||||
|
||||
# :ditto:
|
||||
@[AlwaysInline]
|
||||
def not_to(matcher, message = nil) : Nil
|
||||
to_not(matcher, message)
|
||||
end
|
||||
|
||||
def to_not(stub : Mocks::MethodStub) : Nil
|
||||
|
@ -125,16 +141,11 @@ module Spectator
|
|||
stubs.each { |stub| to_not(stub) }
|
||||
end
|
||||
|
||||
# :ditto:
|
||||
@[AlwaysInline]
|
||||
def not_to(matcher) : Nil
|
||||
to_not(matcher)
|
||||
end
|
||||
|
||||
# Asserts that some criteria defined by the matcher is eventually satisfied.
|
||||
# The expectation is checked after the example finishes and all hooks have run.
|
||||
def to_eventually(matcher) : Nil
|
||||
Harness.current.defer { to(matcher) }
|
||||
# Allows a custom message to be used.
|
||||
def to_eventually(matcher, message = nil) : Nil
|
||||
Harness.current.defer { to(matcher, message) }
|
||||
end
|
||||
|
||||
def to_eventually(stub : Mocks::MethodStub) : Nil
|
||||
|
@ -147,8 +158,15 @@ module Spectator
|
|||
|
||||
# Asserts that some criteria defined by the matcher is never satisfied.
|
||||
# The expectation is checked after the example finishes and all hooks have run.
|
||||
def to_never(matcher) : Nil
|
||||
Harness.current.defer { to_not(matcher) }
|
||||
# Allows a custom message to be used.
|
||||
def to_never(matcher, message = nil) : Nil
|
||||
Harness.current.defer { to_not(matcher, message) }
|
||||
end
|
||||
|
||||
# :ditto:
|
||||
@[AlwaysInline]
|
||||
def never_to(matcher, message = nil) : Nil
|
||||
to_never(matcher, message)
|
||||
end
|
||||
|
||||
def to_never(stub : Mocks::MethodStub) : Nil
|
||||
|
@ -159,15 +177,9 @@ module Spectator
|
|||
to_not(stub)
|
||||
end
|
||||
|
||||
# :ditto:
|
||||
@[AlwaysInline]
|
||||
def never_to(matcher) : Nil
|
||||
to_never(matcher)
|
||||
end
|
||||
|
||||
# Reports an expectation to the current harness.
|
||||
private def report(match_data : Matchers::MatchData)
|
||||
expectation = Expectation.new(match_data, @location)
|
||||
private def report(match_data : Matchers::MatchData, message : String? | Proc(String) = nil)
|
||||
expectation = Expectation.new(match_data, @location, message)
|
||||
Harness.current.report(expectation)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -9,6 +9,12 @@ class Object
|
|||
# end
|
||||
# ```
|
||||
#
|
||||
# An optional message can be used in case the expectation fails.
|
||||
# It can be a string or proc returning a string.
|
||||
# ```
|
||||
# subject.should_not be_nil, "Shouldn't be nil"
|
||||
# ```
|
||||
#
|
||||
# NOTE: By default, the should-syntax is disabled.
|
||||
# The expect-syntax is preferred,
|
||||
# since it doesn't [monkey-patch](https://en.wikipedia.org/wiki/Monkey_patch) all objects.
|
||||
|
@ -16,69 +22,69 @@ class Object
|
|||
# ```
|
||||
# require "spectator/should"
|
||||
# ```
|
||||
def should(matcher)
|
||||
def should(matcher, message = nil)
|
||||
actual = ::Spectator::Value.new(self)
|
||||
match_data = matcher.match(actual)
|
||||
expectation = ::Spectator::Expectation.new(match_data)
|
||||
expectation = ::Spectator::Expectation.new(match_data, message: message)
|
||||
::Spectator::Harness.current.report(expectation)
|
||||
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)
|
||||
def should_not(matcher, message = nil)
|
||||
actual = ::Spectator::Value.new(self)
|
||||
match_data = matcher.negated_match(actual)
|
||||
expectation = ::Spectator::Expectation.new(match_data)
|
||||
expectation = ::Spectator::Expectation.new(match_data, message: message)
|
||||
::Spectator::Harness.current.report(expectation)
|
||||
end
|
||||
|
||||
# Works the same as `#should` except that the condition check is postphoned.
|
||||
# The expectation is checked after the example finishes and all hooks have run.
|
||||
def should_eventually(matcher)
|
||||
::Spectator::Harness.current.defer { should(matcher) }
|
||||
def should_eventually(matcher, message = nil)
|
||||
::Spectator::Harness.current.defer { should(matcher, message) }
|
||||
end
|
||||
|
||||
# Works the same as `#should_not` except that the condition check is postphoned.
|
||||
# The expectation is checked after the example finishes and all hooks have run.
|
||||
def should_never(matcher)
|
||||
::Spectator::Harness.current.defer { should_not(matcher) }
|
||||
def should_never(matcher, message = nil)
|
||||
::Spectator::Harness.current.defer { should_not(matcher, message) }
|
||||
end
|
||||
end
|
||||
|
||||
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)
|
||||
def should(matcher, message = nil)
|
||||
actual = ::Spectator::Block.new(self)
|
||||
match_data = matcher.match(actual)
|
||||
expectation = ::Spectator::Expectation.new(match_data)
|
||||
expectation = ::Spectator::Expectation.new(match_data, message: message)
|
||||
::Spectator::Harness.current.report(expectation)
|
||||
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)
|
||||
def should_not(matcher, message = nil)
|
||||
actual = ::Spectator::Block.new(self)
|
||||
match_data = matcher.negated_match(actual)
|
||||
expectation = ::Spectator::Expectation.new(match_data)
|
||||
expectation = ::Spectator::Expectation.new(match_data, message: message)
|
||||
::Spectator::Harness.current.report(expectation)
|
||||
end
|
||||
end
|
||||
|
||||
module Spectator::DSL::Expectations
|
||||
macro should(matcher)
|
||||
expect(subject).to({{matcher}})
|
||||
macro should(*args)
|
||||
expect(subject).to({{args.splat}})
|
||||
end
|
||||
|
||||
macro should_not(matcher)
|
||||
expect(subject).to_not({{matcher}})
|
||||
macro should_not(*args)
|
||||
expect(subject).to_not({{args.splat}})
|
||||
end
|
||||
|
||||
macro should_eventually(matcher)
|
||||
expect(subject).to_eventually({{matcher}})
|
||||
macro should_eventually(*args)
|
||||
expect(subject).to_eventually({{args.splat}})
|
||||
end
|
||||
|
||||
macro should_never(matcher)
|
||||
expect(subject).to_never({{matcher}})
|
||||
macro should_never(*args)
|
||||
expect(subject).to_never({{args.splat}})
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue