class RSpec::Matchers::BuiltIn::RaiseError
@api private Provides the implementation for `raise_error`. Not intended to be instantiated directly. rubocop:disable ClassLength rubocop:disable RescueException
Constants
- UndefinedValue
Used as a sentinel value to be able to tell when the user did not pass an argument. We can't use `nil` for that because we need to warn when `nil` is passed in a different way. It's an
Object
, not a Module, since Module's `===` does not evaluate to true when compared to itself.
Public Class Methods
new(expected_error_or_message, expected_message, &block)
click to toggle source
# File lib/rspec/matchers/built_in/raise_error.rb, line 18 def initialize(expected_error_or_message, expected_message, &block) @block = block @actual_error = nil @warn_about_bare_error = UndefinedValue === expected_error_or_message @warn_about_nil_error = expected_error_or_message.nil? case expected_error_or_message when nil, UndefinedValue @expected_error = Exception @expected_message = expected_message when String @expected_error = Exception @expected_message = expected_error_or_message else @expected_error = expected_error_or_message @expected_message = expected_message end end
Public Instance Methods
description()
click to toggle source
@api private @return [String]
# File lib/rspec/matchers/built_in/raise_error.rb, line 107 def description "raise #{expected_error}" end
does_not_match?(given_proc)
click to toggle source
@private
# File lib/rspec/matchers/built_in/raise_error.rb, line 79 def does_not_match?(given_proc) warn_for_negative_false_positives! !matches?(given_proc, :negative_expectation) && Proc === given_proc end
expects_call_stack_jump?()
click to toggle source
# File lib/rspec/matchers/built_in/raise_error.rb, line 89 def expects_call_stack_jump? true end
failure_message()
click to toggle source
@api private @return [String]
# File lib/rspec/matchers/built_in/raise_error.rb, line 95 def failure_message @eval_block ? actual_error_message : "expected #{expected_error}#{given_error}" end
failure_message_when_negated()
click to toggle source
@api private @return [String]
# File lib/rspec/matchers/built_in/raise_error.rb, line 101 def failure_message_when_negated "expected no #{expected_error}#{given_error}" end
matches?(given_proc, negative_expectation=false, &block)
click to toggle source
rubocop:disable MethodLength @private
# File lib/rspec/matchers/built_in/raise_error.rb, line 48 def matches?(given_proc, negative_expectation=false, &block) @given_proc = given_proc @block ||= block @raised_expected_error = false @with_expected_message = false @eval_block = false @eval_block_passed = false return false unless Proc === given_proc begin given_proc.call rescue Exception => @actual_error if values_match?(@expected_error, @actual_error) || values_match?(@expected_error, actual_error_message) @raised_expected_error = true @with_expected_message = verify_message end end unless negative_expectation warn_about_bare_error! if warn_about_bare_error? warn_about_nil_error! if warn_about_nil_error? eval_block if ready_to_eval_block? end expectation_matched? end
supports_block_expectations?()
click to toggle source
@private
# File lib/rspec/matchers/built_in/raise_error.rb, line 85 def supports_block_expectations? true end
with_message(expected_message)
click to toggle source
@api public Specifies the expected error message.
# File lib/rspec/matchers/built_in/raise_error.rb, line 39 def with_message(expected_message) raise_message_already_set if @expected_message @warn_about_bare_error = false @expected_message = expected_message self end
Private Instance Methods
actual_error_message()
click to toggle source
# File lib/rspec/matchers/built_in/raise_error.rb, line 113 def actual_error_message return nil unless @actual_error @actual_error.respond_to?(:original_message) ? @actual_error.original_message : @actual_error.message end
block_matches?()
click to toggle source
# File lib/rspec/matchers/built_in/raise_error.rb, line 127 def block_matches? @eval_block ? @eval_block_passed : true end
error_and_message_match?()
click to toggle source
# File lib/rspec/matchers/built_in/raise_error.rb, line 123 def error_and_message_match? @raised_expected_error && @with_expected_message end
eval_block()
click to toggle source
# File lib/rspec/matchers/built_in/raise_error.rb, line 135 def eval_block @eval_block = true begin @block[@actual_error] @eval_block_passed = true rescue Exception => err @actual_error = err end end
expectation_matched?()
click to toggle source
# File lib/rspec/matchers/built_in/raise_error.rb, line 119 def expectation_matched? error_and_message_match? && block_matches? end
expected_error()
click to toggle source
# File lib/rspec/matchers/built_in/raise_error.rb, line 216 def expected_error case @expected_message when nil if RSpec::Support.is_a_matcher?(@expected_error) "Exception with #{description_of(@expected_error)}" else description_of(@expected_error) end when Regexp "#{@expected_error} with message matching #{description_of(@expected_message)}" else "#{@expected_error} with #{description_of(@expected_message)}" end end
expecting_specific_exception?()
click to toggle source
# File lib/rspec/matchers/built_in/raise_error.rb, line 247 def expecting_specific_exception? @expected_error != Exception end
format_backtrace(backtrace)
click to toggle source
# File lib/rspec/matchers/built_in/raise_error.rb, line 231 def format_backtrace(backtrace) formatter = Matchers.configuration.backtrace_formatter formatter.format_backtrace(backtrace) end
given_error()
click to toggle source
# File lib/rspec/matchers/built_in/raise_error.rb, line 236 def given_error return " but was not given a block" unless Proc === @given_proc return " but nothing was raised" unless @actual_error backtrace = format_backtrace(@actual_error.backtrace) [ ", got #{description_of(@actual_error)} with backtrace:", *backtrace ].join("\n # ") end
handle_warning(message)
click to toggle source
# File lib/rspec/matchers/built_in/raise_error.rb, line 166 def handle_warning(message) RSpec::Expectations.configuration.false_positives_handler.call(message) end
raise_message_already_set()
click to toggle source
# File lib/rspec/matchers/built_in/raise_error.rb, line 251 def raise_message_already_set raise "`expect { }.to raise_error(message).with_message(message)` is not valid. " \ 'The matcher only allows the expected message to be specified once' end
ready_to_eval_block?()
click to toggle source
# File lib/rspec/matchers/built_in/raise_error.rb, line 131 def ready_to_eval_block? @raised_expected_error && @with_expected_message && @block end
verify_message()
click to toggle source
# File lib/rspec/matchers/built_in/raise_error.rb, line 145 def verify_message return true if @expected_message.nil? values_match?(@expected_message, actual_error_message.to_s) end
warn_about_bare_error!()
click to toggle source
# File lib/rspec/matchers/built_in/raise_error.rb, line 178 def warn_about_bare_error! handle_warning("Using the `raise_error` matcher without providing a specific " \ "error or message risks false positives, since `raise_error` " \ "will match when Ruby raises a `NoMethodError`, `NameError` or " \ "`ArgumentError`, potentially allowing the expectation to pass " \ "without even executing the method you are intending to call. " \ "#{warning}"\ "Instead consider providing a specific error class or message. " \ "This message can be suppressed by setting: " \ "`RSpec::Expectations.configuration.on_potential_false" \ "_positives = :nothing`") end
warn_about_bare_error?()
click to toggle source
# File lib/rspec/matchers/built_in/raise_error.rb, line 170 def warn_about_bare_error? @warn_about_bare_error && @block.nil? end
warn_about_negative_false_positive!(expression)
click to toggle source
# File lib/rspec/matchers/built_in/raise_error.rb, line 204 def warn_about_negative_false_positive!(expression) handle_warning("Using #{expression} risks false positives, since literally " \ "any other error would cause the expectation to pass, " \ "including those raised by Ruby (e.g. `NoMethodError`, `NameError` " \ "and `ArgumentError`), meaning the code you are intending to test " \ "may not even get reached. Instead consider using " \ "`expect { }.not_to raise_error` or `expect { }.to raise_error" \ "(DifferentSpecificErrorClass)`. This message can be suppressed by " \ "setting: `RSpec::Expectations.configuration.on_potential_false" \ "_positives = :nothing`") end
warn_about_nil_error!()
click to toggle source
# File lib/rspec/matchers/built_in/raise_error.rb, line 191 def warn_about_nil_error! handle_warning("Using the `raise_error` matcher with a `nil` error is probably " \ "unintentional, it risks false positives, since `raise_error` " \ "will match when Ruby raises a `NoMethodError`, `NameError` or " \ "`ArgumentError`, potentially allowing the expectation to pass " \ "without even executing the method you are intending to call. " \ "#{warning}"\ "Instead consider providing a specific error class or message. " \ "This message can be suppressed by setting: " \ "`RSpec::Expectations.configuration.on_potential_false" \ "_positives = :nothing`") end
warn_about_nil_error?()
click to toggle source
# File lib/rspec/matchers/built_in/raise_error.rb, line 174 def warn_about_nil_error? @warn_about_nil_error end
warn_for_negative_false_positives!()
click to toggle source
# File lib/rspec/matchers/built_in/raise_error.rb, line 150 def warn_for_negative_false_positives! expression = if expecting_specific_exception? && @expected_message "`expect { }.not_to raise_error(SpecificErrorClass, message)`" elsif expecting_specific_exception? "`expect { }.not_to raise_error(SpecificErrorClass)`" elsif @expected_message "`expect { }.not_to raise_error(message)`" elsif @warn_about_nil_error "`expect { }.not_to raise_error(nil)`" end return unless expression warn_about_negative_false_positive! expression end
warning()
click to toggle source
# File lib/rspec/matchers/built_in/raise_error.rb, line 256 def warning warning = "Actual error raised was #{description_of(@actual_error)}. " warning if @actual_error end