Skip to content
This repository has been archived by the owner on Nov 30, 2024. It is now read-only.

Commit

Permalink
Merge pull request #1458 from nevinera/nev--improve-test-coverage
Browse files Browse the repository at this point in the history
100% test coverage
  • Loading branch information
pirj authored and JonRowe committed Aug 20, 2024
1 parent 7cf92aa commit 6b97659
Show file tree
Hide file tree
Showing 23 changed files with 250 additions and 22 deletions.
2 changes: 2 additions & 0 deletions lib/rspec/expectations/block_snippet_extractor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,13 @@ def source
RSpec.world.source_from_file(file_path)
end
else
# :nocov:
RSpec::Support.require_rspec_support 'source'
def source
raise TargetNotFoundError unless File.exist?(file_path)
@source ||= RSpec::Support::Source.from_file(file_path)
end
# :nocov:
end

def file_path
Expand Down
5 changes: 5 additions & 0 deletions lib/rspec/expectations/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ def color?
::RSpec.configuration.color_enabled?
end
else
# :nocov:
# Indicates whether or not diffs should be colored.
# Delegates to rspec-core's color option if rspec-core
# is loaded; otherwise you can set it here.
Expand All @@ -100,8 +101,11 @@ def color?
def color?
defined?(@color) && @color
end
# :nocov:
end

# :nocov: Because this is only really _useful_ on 1.8, and hard to test elsewhere.
#
# Adds `should` and `should_not` to the given classes
# or modules. This can be used to ensure `should` works
# properly on things like proxy objects (particular
Expand All @@ -114,6 +118,7 @@ def add_should_and_should_not_to(*modules)
Expectations::Syntax.enable_should(mod)
end
end
# :nocov:

# Sets or gets the backtrace formatter. The backtrace formatter should
# implement `#format_backtrace(Array<String>)`. This is used
Expand Down
7 changes: 7 additions & 0 deletions lib/rspec/expectations/failure_aggregator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ class FailureAggregator

# @private
class AggregatedFailure
# :nocov:
# `inspect` was apparently used by some versions early in ruby 3 while constructing
# NoMethodError, but seems to be no longer.
#
# @private
MESSAGE =
'AggregatedFailure: This method caused a failure which has been ' \
Expand All @@ -15,6 +19,7 @@ class AggregatedFailure
def inspect
MESSAGE
end
# :nocov:
end

AGGREGATED_FAILURE = AggregatedFailure.new
Expand Down Expand Up @@ -75,11 +80,13 @@ def call(failure, options)
# a backtrace that has a continuous common section with the raised `MultipleExpectationsNotMetError`,
# so that rspec-core's truncation logic can work properly on it to list the backtrace
# relative to the `aggregate_failures` block.
# :nocov:
def assign_backtrace(failure)
raise failure
rescue failure.class => e
failure.set_backtrace(e.backtrace)
end
# :nocov:
else
# Using `caller` performs better (and is simpler) than `raise` on most Rubies.
def assign_backtrace(failure)
Expand Down
2 changes: 2 additions & 0 deletions lib/rspec/matchers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1018,6 +1018,7 @@ class << self
# than _before_, like `append_features`. It's important we check this before
# in order to find the cases where it was already previously included.
# @api private
# :nocov:
def append_features(mod)
return super if mod < self # `mod < self` indicates a re-inclusion.

Expand All @@ -1038,6 +1039,7 @@ def append_features(mod)

super
end
# :nocov:
end
end
end
Expand Down
4 changes: 4 additions & 0 deletions lib/rspec/matchers/built_in/base_matcher.rb
Original file line number Diff line number Diff line change
Expand Up @@ -156,9 +156,11 @@ def string_encoding_differs?
else
# @api private
# @return [Boolean] False always as the curent Ruby version does not support String encoding
# :nocov:
def string_encoding_differs?
false
end
# :nocov:
end
module_function :string_encoding_differs?

Expand All @@ -175,9 +177,11 @@ def format_encoding(value)
# Formats a String's encoding as a human readable string
# @param _value [String]
# @return [nil] nil as the curent Ruby version does not support String encoding
# :nocov:
def format_encoding(_value)
nil
end
# :nocov:
end
module_function :format_encoding
end
Expand Down
2 changes: 2 additions & 0 deletions lib/rspec/matchers/built_in/change.rb
Original file line number Diff line number Diff line change
Expand Up @@ -440,9 +440,11 @@ def extract_value_block_snippet
Expectations::BlockSnippetExtractor.try_extracting_single_line_body_of(@value_proc, @matcher_name)
end
else
# :nocov:
def extract_value_block_snippet
nil
end
# :nocov:
end
end
end
Expand Down
2 changes: 2 additions & 0 deletions lib/rspec/matchers/built_in/contain_exactly.rb
Original file line number Diff line number Diff line change
Expand Up @@ -108,12 +108,14 @@ def safe_sort(array)
end

if RUBY_VERSION == "1.8.7"
# :nocov:
def to_a_disallowed?(object)
case object
when NilClass, String then true
else Kernel == RSpec::Support.method_handle_for(object, :to_a).owner
end
end
# :nocov:
else
def to_a_disallowed?(object)
NilClass === object
Expand Down
2 changes: 2 additions & 0 deletions lib/rspec/matchers/built_in/count_expectation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,11 @@ def cover?(count, number)
count.cover?(number)
end
else
# :nocov:
def cover?(count, number)
number >= count.first && number <= count.last
end
# :nocov:
end

def expected_count_matches?(actual_count)
Expand Down
2 changes: 2 additions & 0 deletions lib/rspec/matchers/built_in/has.rb
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,11 @@ def really_responds_to?(method)
end
end
else
# :nocov:
def really_responds_to?(method)
@actual.respond_to?(method)
end
# :nocov:
end

def predicate_accessible?
Expand Down
2 changes: 2 additions & 0 deletions lib/rspec/matchers/built_in/include.rb
Original file line number Diff line number Diff line change
Expand Up @@ -174,9 +174,11 @@ def actual_collection_includes?(expected_item)
end

if RUBY_VERSION < '1.9'
# :nocov:
def count_enumerable(expected_item)
actual.select { |value| values_match?(expected_item, value) }.size
end
# :nocov:
else
def count_enumerable(expected_item)
actual.count { |value| values_match?(expected_item, value) }
Expand Down
2 changes: 2 additions & 0 deletions lib/rspec/matchers/built_in/match.rb
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,11 @@ def initialize(match_data)
# @api private
# Returns match data names for named captures
# @return Array
# :nocov:
def names
[]
end
# :nocov:
else
# @api private
# Returns match data names for named captures
Expand Down
2 changes: 2 additions & 0 deletions lib/rspec/matchers/built_in/satisfy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,11 @@ def extract_block_snippet
Expectations::BlockSnippetExtractor.try_extracting_single_line_body_of(@block, matcher_name)
end
else
# :nocov:
def block_representation
'block'
end
# :nocov:
end
end
end
Expand Down
2 changes: 2 additions & 0 deletions lib/rspec/matchers/english_phrasing.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,14 @@ def self.list(obj)
# So here we replace `Kernel#Array` with our own warning-free implementation for 1.8.7.
# @private
# rubocop:disable Naming/MethodName
# :nocov:
def self.Array(obj)
case obj
when Array then obj
else [obj]
end
end
# :nocov:
# rubocop:enable Naming/MethodName
end
end
Expand Down
6 changes: 6 additions & 0 deletions spec/rspec/expectations/configuration_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,12 @@ def delegated?; true; end
config.on_potential_false_positives = :raise
expect(config.on_potential_false_positives).to eq :raise
end

it 'cannot be set to :fooba' do
expect {
config.on_potential_false_positives = :fooba
}.to raise_error(ArgumentError, /Supported values are/)
end
end

shared_examples "configuring the expectation syntax" do
Expand Down
27 changes: 13 additions & 14 deletions spec/rspec/expectations/failure_aggregator_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -273,20 +273,19 @@ def expect_error_included_in_aggregated_failure(error)
array = dbl.get(2)
array << :foo
end
}.to raise_error(
be_a(MultipleExpectationsNotMetError).and have_attributes(
:failures => [
be_a(RSpec::Mocks::MockExpectationError)
],
:other_errors => [
# Checking only the class name, not the full message, because the hehaviour differes bettern Ruby 2 and 3.
# Ruby 3 uses #inspect in NoMethodError, while Ruby 2.x uses format that I can't override:
# NoMethodError (undefined method `<<' for #<RSpec::Expectations::FailureAggregator::AggregatedFailure:0x000055e4bac69ba8>)
# even if I override #to_s
be_a(NoMethodError).and(have_attributes(:message => /AggregatedFailure/))
]
)
)
}.to raise_error do |err|
expect(err).to be_a(MultipleExpectationsNotMetError)
expect(err.failures).to contain_exactly(be_a(RSpec::Mocks::MockExpectationError))
expect(err.other_errors).to contain_exactly(be_a(NoMethodError))

# Checking only the class name, not the full message, because the behaviour across ruby versions.
# Some versions of Ruby 3 use #inspect in NoMethodError, but Ruby 2.x and 3.3 use formats that we
# can't control:
#
# Ruby2: undefined method `<<' for #<RSpec::Expectations::FailureAggregator::AggregatedFailure:0x000055e4bac69ba8>
# Ruby3: undefined method `<<' for an instance of RSpec::Expectations::FailureAggregator::AggregatedFailure
expect(err.other_errors.first.message).to match(/AggregatedFailure/)
end
end
end

Expand Down
6 changes: 6 additions & 0 deletions spec/rspec/matchers/built_in/all_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ module RSpec::Matchers::BuiltIn
end
end

it "refuses to invert" do
expect {
expect([5, 3, 3]).not_to all(be_odd)
}.to raise_error(NotImplementedError, /not_to all.*is not supported/)
end

context 'when single matcher is given' do

describe 'expect(...).to all(expected)' do
Expand Down
32 changes: 32 additions & 0 deletions spec/rspec/matchers/built_in/be_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -524,6 +524,22 @@ def mouth2.frowns?; yield; end
end
end

RSpec.describe "expect(...).not_to be_truthy" do
it "passes when actual equal?(false)" do
expect(false).not_to be_truthy
end

it "passes when actual equal?(nil)" do
expect(nil).not_to be_truthy
end

it "fails when actual equal?(true)" do
expect {
expect(true).not_to be_truthy
}.to fail_with("expected: falsey value\n got: true")
end
end

RSpec.describe "expect(...).to be_falsey" do
it "passes when actual equal?(false)" do
expect(false).to be_falsey
Expand Down Expand Up @@ -556,6 +572,22 @@ def mouth2.frowns?; yield; end
end
end

RSpec.describe "expect(...).not_to be_falsey" do
it "passes when actual equal?(true)" do
expect(true).not_to be_falsey
end

it "passes when actual is 1" do
expect(1).not_to be_falsey
end

it "fails when actual equal?(false)" do
expect {
expect(false).not_to be_falsey
}.to fail_with("expected: truthy value\n got: false")
end
end

RSpec.describe "expect(...).to be_nil" do
it "passes when actual is nil" do
expect(nil).to be_nil
Expand Down
45 changes: 45 additions & 0 deletions spec/rspec/matchers/built_in/compound_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,26 @@ def expect_block
end
end

describe "expect(...).to custom_matcher.and(other_matcher)" do
it "treats a matcher that doesn't support value expectations correctly" do
expect {
expect([1, 2]).to include(1).and raise_error(/test/)
}.to fail_with(/but was not given a block/)
end

it "treats a matcher that does support value expectations correctly" do
expect([1, 2]).to include(1).and include(2)
end

it "treats a matcher that doesn't _specify_ as supporting value expectations" do
unsupporting_includes_class = Class.new(Object) do
def matches?(actual); actual.include?(2); end
end
unsupporting_includes = unsupporting_includes_class.new
expect([1, 2]).to include(1).and unsupporting_includes
end
end

describe "expect(...).to matcher.and(other_matcher)" do

it_behaves_like "an RSpec value matcher", :valid_value => 3, :invalid_value => 4, :disallows_negation => true do
Expand Down Expand Up @@ -973,5 +993,30 @@ def actual
}.to raise_error(NotImplementedError, /matcher.or matcher` is not supported/)
end
end

describe "#expects_call_stack_jump?" do
subject(:expects_call_stack_jump?) { matcher.expects_call_stack_jump? }
let(:matcher) { described_class.new(matcher_1, matcher_2) }
let(:matcher_1) { double("Matcher 1") }
let(:matcher_2) { double("Matcher 2") }

context "when neither matcher expects a call-stack jump" do
let(:matcher_1) { double("Matcher 1", :expects_call_stack_jump? => false) }
let(:matcher_2) { double("Matcher 2", :expects_call_stack_jump? => false) }
it { is_expected.to be_falsey }
end

context "when one of the matchers expects a call-stack jump" do
let(:matcher_1) { double("Matcher 1", :expects_call_stack_jump? => false) }
let(:matcher_2) { double("Matcher 2", :expects_call_stack_jump? => true) }
it { is_expected.to be_truthy }
end

context "when neither matcher _specifies_ that it expects a call-stack jump" do
let(:matcher_1) { Object.new }
let(:matcher_2) { Object.new }
it { is_expected.to be_falsey }
end
end
end
end
Loading

0 comments on commit 6b97659

Please sign in to comment.