summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenoit Daloze <eregontp@gmail.com>2026-05-08 01:30:46 +0200
committerBenoit Daloze <eregontp@gmail.com>2026-05-08 01:30:46 +0200
commit72d032e13edc4b9b17bd66ef69109d581641d5c1 (patch)
treef7e527b949b524b9fe0f6b1f548f12154953a961
parentd5e2779bbb8fcbaacd5f6b63894a86b4916157c7 (diff)
Update to ruby/mspec@dffcdf7
-rw-r--r--spec/mspec/lib/mspec/matchers/base.rb16
-rw-r--r--spec/mspec/lib/mspec/matchers/raise_error.rb56
-rw-r--r--spec/mspec/spec/matchers/raise_error_spec.rb73
3 files changed, 120 insertions, 25 deletions
diff --git a/spec/mspec/lib/mspec/matchers/base.rb b/spec/mspec/lib/mspec/matchers/base.rb
index d9d7f6fec0..3534520d88 100644
--- a/spec/mspec/lib/mspec/matchers/base.rb
+++ b/spec/mspec/lib/mspec/matchers/base.rb
@@ -36,6 +36,14 @@ class SpecPositiveOperatorMatcher < BasicObject
end
end
+ def raise(exception = ::Exception, message = nil, options = nil, &block)
+ matcher = ::RaiseErrorMatcher.new(exception, message, options, &block)
+ unless matcher.matches? @actual
+ expected, actual = matcher.failure_message
+ ::SpecExpectation.fail_with(expected, actual)
+ end
+ end
+
def method_missing(name, *args, &block)
result = @actual.__send__(name, *args, &block)
unless result
@@ -70,6 +78,14 @@ class SpecNegativeOperatorMatcher < BasicObject
end
end
+ def raise(exception = ::Exception, message = nil, options = nil, &block)
+ matcher = ::RaiseErrorMatcher.new(exception, message, options, &block)
+ if matcher.matches? @actual
+ expected, actual = matcher.negative_failure_message
+ ::SpecExpectation.fail_with(expected, actual)
+ end
+ end
+
def method_missing(name, *args, &block)
result = @actual.__send__(name, *args, &block)
if result
diff --git a/spec/mspec/lib/mspec/matchers/raise_error.rb b/spec/mspec/lib/mspec/matchers/raise_error.rb
index 2aa3038ed1..8cba842ce3 100644
--- a/spec/mspec/lib/mspec/matchers/raise_error.rb
+++ b/spec/mspec/lib/mspec/matchers/raise_error.rb
@@ -1,11 +1,18 @@
class RaiseErrorMatcher
FAILURE_MESSAGE_FOR_EXCEPTION = {}.compare_by_identity
+ UNDEF_CAUSE = Object.new
attr_writer :block
- def initialize(exception, message, &block)
+ def initialize(exception, message = nil, options = nil, &block)
+ if message.is_a? Hash
+ @message = nil
+ options = message
+ else
+ @message = message
+ end
+ @cause = options ? options.fetch(:cause, UNDEF_CAUSE) : UNDEF_CAUSE
@exception = exception
- @message = message
@block = block
@actual = nil
end
@@ -45,24 +52,45 @@ class RaiseErrorMatcher
end
end
+ def matching_cause?(exc)
+ case @cause
+ when UNDEF_CAUSE
+ true
+ else
+ @cause == exc.cause
+ end
+ end
+
def matching_exception?(exc)
- matching_class?(exc) and matching_message?(exc)
+ matching_class?(exc) and matching_message?(exc) and matching_cause?(exc)
end
- def exception_class_and_message(exception_class, message)
- if message
- "#{exception_class} (#{message})"
- else
- "#{exception_class}"
+ def exception_class_and_message_and_cause(exception_class, message, cause)
+ string = "#{exception_class}"
+ prefixed = false
+ prefix = -> { prefixed ? ", " : prefixed = "(" }
+
+ if message != nil
+ string << "#{prefix.()}#{message.inspect}"
+ end
+
+ if cause != UNDEF_CAUSE
+ string << "#{prefix.()}cause: #{cause.inspect}"
end
+
+ string << ")" if prefixed
+
+ string
end
def format_expected_exception
- exception_class_and_message(@exception, @message)
+ exception_class_and_message_and_cause(@exception, @message, @cause)
end
def format_exception(exception)
- exception_class_and_message(exception.class, exception.message)
+ exception_class_and_message_and_cause(exception.class,
+ @message == nil ? nil : exception.message,
+ @cause == UNDEF_CAUSE ? UNDEF_CAUSE : exception.cause)
end
def failure_message
@@ -87,18 +115,18 @@ class RaiseErrorMatcher
end
module MSpecMatchers
- private def raise_error(exception = Exception, message = nil, &block)
- RaiseErrorMatcher.new(exception, message, &block)
+ private def raise_error(exception = Exception, message = nil, options = nil, &block)
+ RaiseErrorMatcher.new(exception, message, options, &block)
end
# CRuby < 4.1 has inconsistent coercion errors:
# https://bugs.ruby-lang.org/issues/21864
# This matcher ignores the message on CRuby < 4.1
# and checks the message for all other cases, including other Rubies
- private def raise_consistent_error(exception = Exception, message = nil, &block)
+ private def raise_consistent_error(exception = Exception, message = nil, options = nil, &block)
if RUBY_ENGINE == "ruby" and ruby_version_is ""..."4.1"
message = nil
end
- RaiseErrorMatcher.new(exception, message, &block)
+ RaiseErrorMatcher.new(exception, message, options, &block)
end
end
diff --git a/spec/mspec/spec/matchers/raise_error_spec.rb b/spec/mspec/spec/matchers/raise_error_spec.rb
index 8613eee118..3849c7dd2a 100644
--- a/spec/mspec/spec/matchers/raise_error_spec.rb
+++ b/spec/mspec/spec/matchers/raise_error_spec.rb
@@ -84,10 +84,10 @@ RSpec.describe RaiseErrorMatcher do
matcher.matches?(Proc.new { raise exc })
rescue UnexpectedException => e
expect(matcher.failure_message).to eq(
- ["Expected ExpectedException (message)", "but got: UnexpectedException (message)"]
+ ['Expected ExpectedException("message")', 'but got: UnexpectedException("message")']
)
expect(ExceptionState.new(nil, nil, e).message).to eq(
- "Expected ExpectedException (message)\nbut got: UnexpectedException (message)"
+ "Expected ExpectedException(\"message\")\nbut got: UnexpectedException(\"message\")"
)
else
raise "no exception"
@@ -103,10 +103,10 @@ RSpec.describe RaiseErrorMatcher do
matcher.matches?(Proc.new { raise exc })
rescue ExpectedException => e
expect(matcher.failure_message).to eq(
- ["Expected ExpectedException (expected)", "but got: ExpectedException (unexpected)"]
+ ['Expected ExpectedException("expected")', 'but got: ExpectedException("unexpected")']
)
expect(ExceptionState.new(nil, nil, e).message).to eq(
- "Expected ExpectedException (expected)\nbut got: ExpectedException (unexpected)"
+ "Expected ExpectedException(\"expected\")\nbut got: ExpectedException(\"unexpected\")"
)
else
raise "no exception"
@@ -122,10 +122,10 @@ RSpec.describe RaiseErrorMatcher do
matcher.matches?(Proc.new { raise exc })
rescue UnexpectedException => e
expect(matcher.failure_message).to eq(
- ["Expected ExpectedException (expected)", "but got: UnexpectedException (unexpected)"]
+ ['Expected ExpectedException("expected")', 'but got: UnexpectedException("unexpected")']
)
expect(ExceptionState.new(nil, nil, e).message).to eq(
- "Expected ExpectedException (expected)\nbut got: UnexpectedException (unexpected)"
+ "Expected ExpectedException(\"expected\")\nbut got: UnexpectedException(\"unexpected\")"
)
else
raise "no exception"
@@ -137,7 +137,7 @@ RSpec.describe RaiseErrorMatcher do
matcher = RaiseErrorMatcher.new(ExpectedException, "expected")
matcher.matches?(proc)
expect(matcher.failure_message).to eq(
- ["Expected ExpectedException (expected)", "but no exception was raised (120 was returned)"]
+ ['Expected ExpectedException("expected")', "but no exception was raised (120 was returned)"]
)
end
@@ -146,7 +146,7 @@ RSpec.describe RaiseErrorMatcher do
matcher = RaiseErrorMatcher.new(ExpectedException, "expected")
matcher.matches?(proc)
expect(matcher.failure_message).to eq(
- ["Expected ExpectedException (expected)", "but no exception was raised (nil was returned)"]
+ ['Expected ExpectedException("expected")', "but no exception was raised (nil was returned)"]
)
end
@@ -159,7 +159,7 @@ RSpec.describe RaiseErrorMatcher do
matcher = RaiseErrorMatcher.new(ExpectedException, "expected")
matcher.matches?(proc)
expect(matcher.failure_message).to eq(
- ["Expected ExpectedException (expected)", "but no exception was raised (#<Object>(#pretty_inspect raised #<ArgumentError: bad>) was returned)"]
+ ['Expected ExpectedException("expected")', 'but no exception was raised (#<Object>(#pretty_inspect raised #<ArgumentError: bad>) was returned)']
)
end
@@ -168,7 +168,7 @@ RSpec.describe RaiseErrorMatcher do
matcher = RaiseErrorMatcher.new(ExpectedException, "expected")
matcher.matches?(proc)
expect(matcher.negative_failure_message).to eq(
- ["Expected to not get ExpectedException (expected)", ""]
+ ['Expected to not get ExpectedException("expected")', ""]
)
end
@@ -177,7 +177,58 @@ RSpec.describe RaiseErrorMatcher do
matcher = RaiseErrorMatcher.new(Exception, nil)
matcher.matches?(proc)
expect(matcher.negative_failure_message).to eq(
- ["Expected to not get Exception", "but got: UnexpectedException (unexpected)"]
+ ['Expected to not get Exception', 'but got: UnexpectedException']
)
end
+
+ it "matches cause if given" do
+ cause = RuntimeError.new("foo")
+ proc = -> do
+ raise cause
+ rescue
+ raise "bar"
+ end
+
+ matcher = RaiseErrorMatcher.new(RuntimeError, cause: cause)
+ expect(matcher.matches?(proc)).to eq(true)
+ end
+
+ it "matches message and cause if given" do
+ cause = RuntimeError.new("foo")
+ proc = -> do
+ raise cause
+ rescue
+ raise "bar"
+ end
+
+ matcher = RaiseErrorMatcher.new(RuntimeError, "bar", cause: cause)
+ expect(matcher.matches?(proc)).to eq(true)
+ end
+
+ it "provides useful negative failure message when cause does not match" do
+ cause = RuntimeError.new("bar")
+ proc = -> do
+ raise "foo"
+ end
+
+ matcher = RaiseErrorMatcher.new(RuntimeError, cause: cause)
+
+ begin
+ matcher.matches?(proc)
+ rescue RuntimeError
+ expect(matcher.failure_message).to eq(
+ ['Expected RuntimeError(cause: #<RuntimeError: bar>)', 'but got: RuntimeError(cause: nil)']
+ )
+ end
+
+ matcher = RaiseErrorMatcher.new(RuntimeError, "foo", cause: cause)
+
+ begin
+ matcher.matches?(proc)
+ rescue RuntimeError
+ expect(matcher.failure_message).to eq(
+ ['Expected RuntimeError("foo", cause: #<RuntimeError: bar>)', 'but got: RuntimeError("foo", cause: nil)']
+ )
+ end
+ end
end