Support casting types with should statements
This commit is contained in:
parent
acf810553a
commit
c4bcf54b98
|
@ -6,7 +6,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
### Added
|
### Added
|
||||||
- Added ability to cast types using the return value from expect statements with a type matcher.
|
- Added ability to cast types using the return value from expect/should statements with a type matcher.
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- Fix invalid syntax (unterminated call) when recording calls to stubs with an un-named splat.
|
- Fix invalid syntax (unterminated call) when recording calls to stubs with an un-named splat.
|
||||||
|
|
|
@ -1,36 +1,70 @@
|
||||||
require "../spec_helper"
|
require "../spec_helper"
|
||||||
|
|
||||||
Spectator.describe "Expect Type" do
|
Spectator.describe "Expect Type", :smoke do
|
||||||
it "ensures a type is cast" do
|
context "with expect syntax" do
|
||||||
value = 42.as(String | Int32)
|
it "ensures a type is cast" do
|
||||||
expect(value).to be_a(String | Int32)
|
value = 42.as(String | Int32)
|
||||||
expect(value).to compile_as(String | Int32)
|
expect(value).to be_a(String | Int32)
|
||||||
value = expect(value).to be_a(Int32)
|
expect(value).to compile_as(String | Int32)
|
||||||
expect(value).to eq(42)
|
value = expect(value).to be_a(Int32)
|
||||||
expect(value).to be_a(Int32)
|
expect(value).to eq(42)
|
||||||
expect(value).to compile_as(Int32)
|
expect(value).to be_a(Int32)
|
||||||
expect(value).to_not respond_to(:downcase)
|
expect(value).to compile_as(Int32)
|
||||||
|
expect(value).to_not respond_to(:downcase)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "ensures a type is not nil" do
|
||||||
|
value = 42.as(Int32?)
|
||||||
|
expect(value).to be_a(Int32?)
|
||||||
|
expect(value).to compile_as(Int32?)
|
||||||
|
value = expect(value).to_not be_nil
|
||||||
|
expect(value).to eq(42)
|
||||||
|
expect(value).to be_a(Int32)
|
||||||
|
expect(value).to compile_as(Int32)
|
||||||
|
expect { value.not_nil! }.to_not raise_error(NilAssertionError)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "removes types from a union" do
|
||||||
|
value = 42.as(String | Int32)
|
||||||
|
expect(value).to be_a(String | Int32)
|
||||||
|
expect(value).to compile_as(String | Int32)
|
||||||
|
value = expect(value).to_not be_a(String)
|
||||||
|
expect(value).to eq(42)
|
||||||
|
expect(value).to be_a(Int32)
|
||||||
|
expect(value).to compile_as(Int32)
|
||||||
|
expect(value).to_not respond_to(:downcase)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it "ensures a type is not nil" do
|
context "with should syntax" do
|
||||||
value = 42.as(Int32?)
|
it "ensures a type is cast" do
|
||||||
expect(value).to be_a(Int32?)
|
value = 42.as(String | Int32)
|
||||||
expect(value).to compile_as(Int32?)
|
value.should be_a(String | Int32)
|
||||||
value = expect(value).to_not be_nil
|
value = value.should be_a(Int32)
|
||||||
expect(value).to eq(42)
|
value.should eq(42)
|
||||||
expect(value).to be_a(Int32)
|
value.should be_a(Int32)
|
||||||
expect(value).to compile_as(Int32)
|
value.should compile_as(Int32)
|
||||||
expect { value.not_nil! }.to_not raise_error(NilAssertionError)
|
value.should_not respond_to(:downcase)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "removes types from a union" do
|
it "ensures a type is not nil" do
|
||||||
value = 42.as(String | Int32)
|
value = 42.as(Int32?)
|
||||||
expect(value).to be_a(String | Int32)
|
value.should be_a(Int32?)
|
||||||
expect(value).to compile_as(String | Int32)
|
value = value.should_not be_nil
|
||||||
value = expect(value).to_not be_a(String)
|
value.should eq(42)
|
||||||
expect(value).to eq(42)
|
value.should be_a(Int32)
|
||||||
expect(value).to be_a(Int32)
|
value.should compile_as(Int32)
|
||||||
expect(value).to compile_as(Int32)
|
expect { value.not_nil! }.to_not raise_error(NilAssertionError)
|
||||||
expect(value).to_not respond_to(:downcase)
|
end
|
||||||
|
|
||||||
|
it "removes types from a union" do
|
||||||
|
value = 42.as(String | Int32)
|
||||||
|
value.should be_a(String | Int32)
|
||||||
|
value = value.should_not be_a(String)
|
||||||
|
value.should eq(42)
|
||||||
|
value.should be_a(Int32)
|
||||||
|
value.should compile_as(Int32)
|
||||||
|
value.should_not respond_to(:downcase)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -30,6 +30,23 @@ class Object
|
||||||
::Spectator::Harness.current.report(expectation)
|
::Spectator::Harness.current.report(expectation)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Asserts that some criteria defined by the matcher is satisfied.
|
||||||
|
# Allows a custom message to be used.
|
||||||
|
# Returns the expected value cast as the expected type, if the matcher is satisfied.
|
||||||
|
def should(matcher : ::Spectator::Matchers::TypeMatcher(U), message = nil, *, _file = __FILE__, _line = __LINE__) forall U
|
||||||
|
actual = ::Spectator::Value.new(self)
|
||||||
|
location = ::Spectator::Location.new(_file, _line)
|
||||||
|
match_data = matcher.match(actual)
|
||||||
|
expectation = ::Spectator::Expectation.new(match_data, location, message)
|
||||||
|
if ::Spectator::Harness.current.report(expectation)
|
||||||
|
return self if self.is_a?(U)
|
||||||
|
|
||||||
|
raise "Spectator bug: expected value should have cast to #{U}"
|
||||||
|
else
|
||||||
|
raise TypeCastError.new("Expected value should be a #{U}, but was actually #{self.class}")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# Works the same as `#should` except the condition is inverted.
|
# Works the same as `#should` except the condition is inverted.
|
||||||
# When `#should` succeeds, this method will fail, and vice-versa.
|
# When `#should` succeeds, this method will fail, and vice-versa.
|
||||||
def should_not(matcher, message = nil, *, _file = __FILE__, _line = __LINE__)
|
def should_not(matcher, message = nil, *, _file = __FILE__, _line = __LINE__)
|
||||||
|
@ -40,6 +57,40 @@ class Object
|
||||||
::Spectator::Harness.current.report(expectation)
|
::Spectator::Harness.current.report(expectation)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Asserts that some criteria defined by the matcher is not satisfied.
|
||||||
|
# Allows a custom message to be used.
|
||||||
|
# Returns the expected value cast without the unexpected type, if the matcher is satisfied.
|
||||||
|
def should_not(matcher : ::Spectator::Matchers::TypeMatcher(U), message = nil, *, _file = __FILE__, _line = __LINE__) forall U
|
||||||
|
actual = ::Spectator::Value.new(self)
|
||||||
|
location = ::Spectator::Location.new(_file, _line)
|
||||||
|
match_data = matcher.negated_match(actual)
|
||||||
|
expectation = ::Spectator::Expectation.new(match_data, location, message)
|
||||||
|
if ::Spectator::Harness.current.report(expectation)
|
||||||
|
return self unless self.is_a?(U)
|
||||||
|
|
||||||
|
raise "Spectator bug: expected value should not be #{U}"
|
||||||
|
else
|
||||||
|
raise TypeCastError.new("Expected value is not expected to be a #{U}, but was actually #{self.class}")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Asserts that some criteria defined by the matcher is not satisfied.
|
||||||
|
# Allows a custom message to be used.
|
||||||
|
# Returns the expected value cast as a non-nillable type, if the matcher is satisfied.
|
||||||
|
def should_not(matcher : ::Spectator::Matchers::NilMatcher, message = nil, *, _file = __FILE__, _line = __LINE__)
|
||||||
|
actual = ::Spectator::Value.new(self)
|
||||||
|
location = ::Spectator::Location.new(_file, _line)
|
||||||
|
match_data = matcher.negated_match(actual)
|
||||||
|
expectation = ::Spectator::Expectation.new(match_data, location, message)
|
||||||
|
if ::Spectator::Harness.current.report(expectation)
|
||||||
|
return self unless self.nil?
|
||||||
|
|
||||||
|
raise "Spectator bug: expected value should not be nil"
|
||||||
|
else
|
||||||
|
raise NilAssertionError.new("Expected value should not be nil.")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# Works the same as `#should` except that the condition check is postponed.
|
# Works the same as `#should` except that the condition check is postponed.
|
||||||
# The expectation is checked after the example finishes and all hooks have run.
|
# The expectation is checked after the example finishes and all hooks have run.
|
||||||
def should_eventually(matcher, message = nil, *, _file = __FILE__, _line = __LINE__)
|
def should_eventually(matcher, message = nil, *, _file = __FILE__, _line = __LINE__)
|
||||||
|
|
Loading…
Reference in New Issue