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

Public Class Methods

new(expected_error_or_message=nil, expected_message=nil, &block) click to toggle source
# File lib/rspec/matchers/built_in/raise_error.rb, line 12
def initialize(expected_error_or_message=nil, expected_message=nil, &block)
  @block = block
  @actual_error = nil
  @warn_about_bare_error = warn_about_potential_false_positives? && expected_error_or_message.nil?

  case expected_error_or_message
  when nil
    @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 97
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 69
def does_not_match?(given_proc)
  warn_for_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 79
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 85
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 91
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 41
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

  warn_about_bare_error if warning_about_bare_error && !negative_expectation
  eval_block if !negative_expectation && ready_to_eval_block?

  expectation_matched?
end
supports_block_expectations?() click to toggle source

@private

# File lib/rspec/matchers/built_in/raise_error.rb, line 75
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 32
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

block_matches?() click to toggle source
# File lib/rspec/matchers/built_in/raise_error.rb, line 111
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 107
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 119
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 103
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 179
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 210
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 194
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 199
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
raise_message_already_set() click to toggle source
# File lib/rspec/matchers/built_in/raise_error.rb, line 214
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 115
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 129
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 157
def warn_about_bare_error
  RSpec.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 supressed by setting: "                          "`RSpec::Expectations.configuration.warn_about_potential_false_positives = false`")
end
warn_about_negative_false_positive(expression) click to toggle source
# File lib/rspec/matchers/built_in/raise_error.rb, line 169
def warn_about_negative_false_positive(expression)
  RSpec.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`. This message can be supressed by setting: "                          "`RSpec::Expectations.configuration.warn_about_potential_false_positives = false`")
end
warn_about_potential_false_positives?() click to toggle source
# File lib/rspec/matchers/built_in/raise_error.rb, line 149
def warn_about_potential_false_positives?
  RSpec::Expectations.configuration.warn_about_potential_false_positives?
end
warn_for_false_positives() click to toggle source
# File lib/rspec/matchers/built_in/raise_error.rb, line 134
def warn_for_false_positives
  return unless warn_about_potential_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)`"
               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 219
def warning
  warning = "Actual error raised was #{description_of(@actual_error)}. "
  warning if @actual_error
end
warning_about_bare_error() click to toggle source
# File lib/rspec/matchers/built_in/raise_error.rb, line 153
def warning_about_bare_error
  @warn_about_bare_error && @block.nil?
end