diff --git a/.travis.yml b/.travis.yml index bfd795e62..8120f3839 100644 --- a/.travis.yml +++ b/.travis.yml @@ -38,6 +38,8 @@ matrix: include: - rvm: jruby-1.7 env: JRUBY_OPTS='--dev --1.8' + - rvm: 2.7.1 + env: DIFF_LCS_VERSION="~> 1.3.0" allow_failures: - rvm: jruby-head - rvm: ruby-head diff --git a/Gemfile b/Gemfile index e9fa3d7c8..00a3c3009 100644 --- a/Gemfile +++ b/Gemfile @@ -20,6 +20,12 @@ else gem 'rake', '> 12.3.2' end +if ENV['DIFF_LCS_VERSION'] + gem 'diff-lcs', ENV['DIFF_LCS_VERSION'] +else + gem 'diff-lcs', '~> 1.4', '>= 1.4.3' +end + gem 'coderay' # for syntax highlighting gem 'yard', '~> 0.9.24', :require => false diff --git a/features/custom_matchers/define_diffable_matcher.feature b/features/custom_matchers/define_diffable_matcher.feature index ab7aa97fc..c3fa1a577 100644 --- a/features/custom_matchers/define_diffable_matcher.feature +++ b/features/custom_matchers/define_diffable_matcher.feature @@ -2,7 +2,33 @@ Feature: define diffable matcher When a matcher is defined as diffable, the output will include a diff of the submitted objects when the objects are more than simple primitives. - Scenario: define a diffable matcher + @skip-when-diff-lcs-1.3 + Scenario: define a diffable matcher (with diff-lcs 1.4) + Given a file named "diffable_matcher_spec.rb" with: + """ruby + RSpec::Matchers.define :be_just_like do |expected| + match do |actual| + actual == expected + end + + diffable + end + + RSpec.describe "two\nlines" do + it { is_expected.to be_just_like("three\nlines") } + end + """ + When I run `rspec ./diffable_matcher_spec.rb` + Then it should fail with: + """ + Diff: + @@ -1 +1 @@ + -three + +two + """ + + @skip-when-diff-lcs-1.4 + Scenario: define a diffable matcher (with diff-lcs 1.3) Given a file named "diffable_matcher_spec.rb" with: """ruby RSpec::Matchers.define :be_just_like do |expected| @@ -27,10 +53,53 @@ Feature: define diffable matcher lines """ + @skip-when-diff-lcs-1.3 Scenario: Redefine actual Sometimes is neccessary to overwrite actual to make diffing work, e.g. if `actual` is a name of a file you want to read from. For this to work you need to overwrite `@actual` in your matcher. + Given a file named "redefine_actual_matcher_spec.rb" with: + """ruby + RSpec::Matchers.define :have_content do |expected| + match do |actual| + @actual = File.read(actual).chomp + + values_match? expected, @actual + end + + diffable + end + + RSpec.describe 'Compare files' do + context 'when content is equal' do + it { expect('data.txt').to have_content 'Data' } + end + + context 'when files are different' do + it { expect('data.txt').to have_content "No\nData\nhere" } + end + end + """ + And a file named "data.txt" with: + """ + Data + """ + When I run `rspec ./redefine_actual_matcher_spec.rb --format documentation` + Then the exit status should not be 0 + And the output should contain: + """ + 2 examples, 1 failure + """ + And the output should contain: + """ + @@ -1,4 +1,6 @@ + -No + Data + -here + """ + + @skip-when-diff-lcs-1.4 + Scenario: Redefine actual (with diff-lcs 1.3) Given a file named "redefine_actual_matcher_spec.rb" with: """ruby RSpec::Matchers.define :have_content do |expected| diff --git a/features/diffing.feature b/features/diffing.feature index 8f5321148..ad73203b4 100644 --- a/features/diffing.feature +++ b/features/diffing.feature @@ -32,7 +32,35 @@ Feature: diffing string """ - Scenario: diff for a multiline string and a regexp + @skip-when-diff-lcs-1.3 + Scenario: diff for a multiline string and a regexp on diff-lcs 1.4 + Given a file named "example_spec.rb" with: + """ruby + RSpec.describe "a multiline string" do + it "is like another string" do + expected = /expected/m + actual = <<-ACTUAL + this is the + actual + string + ACTUAL + expect(actual).to match expected + end + end + """ + When I run `rspec example_spec.rb` + Then the output should contain: + """ + Diff: + @@ -1,3 +1,5 @@ + -/expected/m + +this is the + + actual + + string + """ + + @skip-when-diff-lcs-1.4 + Scenario: diff for a multiline string and a regexp on diff-lcs 1.3 Given a file named "example_spec.rb" with: """ruby RSpec.describe "a multiline string" do diff --git a/features/support/diff_lcs_versions.rb b/features/support/diff_lcs_versions.rb new file mode 100644 index 000000000..ac5bd2851 --- /dev/null +++ b/features/support/diff_lcs_versions.rb @@ -0,0 +1,15 @@ +Around "@skip-when-diff-lcs-1.4" do |scenario, block| + if Diff::LCS::VERSION.to_f >= 1.4 + warn "Skipping scenario #{scenario.title} on #{Diff::LCS::VERSION.to_f}" + else + block.call + end +end + +Around "@skip-when-diff-lcs-1.3" do |scenario, block| + if Diff::LCS::VERSION.to_f < 1.4 + warn "Skipping scenario #{scenario.title} on #{Diff::LCS::VERSION.to_f}" + else + block.call + end +end diff --git a/spec/rspec/expectations/fail_with_spec.rb b/spec/rspec/expectations/fail_with_spec.rb index 24008ef9c..a6c7bca19 100644 --- a/spec/rspec/expectations/fail_with_spec.rb +++ b/spec/rspec/expectations/fail_with_spec.rb @@ -32,6 +32,8 @@ end RSpec.describe RSpec::Expectations, "#fail_with with matchers" do + include RSpec::Support::Spec::DiffHelpers + before do allow(RSpec::Matchers.configuration).to receive_messages(:color? => false) end @@ -42,7 +44,7 @@ expected_diff = dedent(<<-EOS) | - |@@ -1,2 +1,2 @@ + |@@ #{one_line_header} @@ |-["poo", "car"] |+[(a string matching /foo/), (a string matching /bar/)] | @@ -55,6 +57,8 @@ end RSpec.describe RSpec::Expectations, "#fail_with with --color" do + include RSpec::Support::Spec::DiffHelpers + before do allow(RSpec::Matchers.configuration).to receive_messages(:color? => true) end @@ -62,7 +66,7 @@ it "tells the differ to use color" do expected = "foo bar baz\n" actual = "foo bang baz\n" - expected_diff = "\e[0m\n\e[0m\e[34m@@ -1,2 +1,2 @@\n\e[0m\e[31m-foo bang baz\n\e[0m\e[32m+foo bar baz\n\e[0m" + expected_diff = "\e[0m\n\e[0m\e[34m@@ #{one_line_header} @@\n\e[0m\e[31m-foo bang baz\n\e[0m\e[32m+foo bar baz\n\e[0m" expect { RSpec::Expectations.fail_with "message", actual, expected diff --git a/spec/rspec/matchers/built_in/have_attributes_spec.rb b/spec/rspec/matchers/built_in/have_attributes_spec.rb index 2a5a2f283..d70130e0a 100644 --- a/spec/rspec/matchers/built_in/have_attributes_spec.rb +++ b/spec/rspec/matchers/built_in/have_attributes_spec.rb @@ -1,4 +1,5 @@ RSpec.describe "#have_attributes matcher" do + include RSpec::Support::Spec::DiffHelpers Person = Struct.new(:name, :age) @@ -36,7 +37,6 @@ def respond_to?(method_name) end describe "expect(...).to have_attributes(with_one_attribute)" do - it_behaves_like "an RSpec matcher", :valid_value => Person.new("Correct name", 33), :invalid_value => Person.new("Wrong Name", 11) do let(:matcher) { have_attributes(:name => "Correct name") } end @@ -71,7 +71,7 @@ def count allow(RSpec::Matchers.configuration).to receive_messages(:color? => false) expected_diff = dedent(<<-EOS) - |@@ -1,2 +1,2 @@ + |@@ #{one_line_header} @@ |-:name => "Wrong Name", |+:name => "Correct name", EOS @@ -100,7 +100,6 @@ def count end describe "expect(...).to have_attributes(key => matcher)" do - it "passes when the matchers match" do expect(person).to have_attributes(:age => (a_value > 30)) end @@ -119,7 +118,6 @@ def count end describe "expect(...).to_not have_attributes(with_one_attribute)" do - it "passes if target does not have any of the expected attributes" do expect(person).to_not have_attributes(:age => wrong_age) end @@ -150,7 +148,6 @@ def count end describe "expect(...).to have_attributes(with_multiple_attributes)" do - it_behaves_like "an RSpec matcher", :valid_value => Person.new("Correct name", 33), :invalid_value => Person.new("Wrong Name", 11) do let(:matcher) { have_attributes(:name => "Correct name", :age => 33) } end @@ -169,11 +166,11 @@ def count allow(RSpec::Matchers.configuration).to receive_messages(:color? => false) expected_diff = dedent(<<-EOS) - |@@ -1,3 +1,3 @@ + |@@ #{one_line_header(3)} @@ |-:age => 11, |+:age => 33, - | :name => "Correct name", EOS + expected_diff << "\n :name => \"Correct name\",\n" if Diff::LCS::VERSION.to_f < 1.4 expect { expect(person).to have_attributes(:name => correct_name, :age => wrong_age) @@ -194,7 +191,6 @@ def count end describe "expect(...).to_not have_attributes(with_multiple_attributes)" do - it "passes if target has none of the expected attributes" do expect(person).to_not have_attributes(:name => wrong_name, :age => wrong_age) end @@ -229,5 +225,4 @@ def count def object_inspect(object) surface_descriptions_in object.inspect end - end diff --git a/spec/rspec/matchers/built_in/include_spec.rb b/spec/rspec/matchers/built_in/include_spec.rb index 96d94e788..b32bada7d 100644 --- a/spec/rspec/matchers/built_in/include_spec.rb +++ b/spec/rspec/matchers/built_in/include_spec.rb @@ -34,6 +34,8 @@ def to_hash end RSpec.describe "#include matcher" do + include RSpec::Support::Spec::DiffHelpers + it "is diffable" do expect(include("a")).to be_diffable end @@ -87,13 +89,14 @@ def hash.send; :sent; end |+"foo" => 1, END else - dedent(<<-END) + diff = dedent(<<-END) |Diff: - |@@ -1,3 +1,3 @@ + |@@ #{one_line_header(3)} @@ |-:bar => 3, |+:bar => 2, - | :foo => 1, END + diff << "\n :foo => 1,\n" if Diff::LCS::VERSION.to_f < 1.4 + diff end expect { @@ -297,7 +300,7 @@ class PseudoHash < SimpleDelegator ) }.to fail_including(dedent(<<-END)) |Diff: - |@@ -1,2 +1,2 @@ + |@@ #{one_line_header} @@ |-[{:number=>1}, {:number=>0}, {:number=>3}] |+[{:number=>1}, {:number=>2}, {:number=>3}] END diff --git a/spec/rspec/matchers/built_in/match_spec.rb b/spec/rspec/matchers/built_in/match_spec.rb index 1f88ef69d..5360ceebc 100644 --- a/spec/rspec/matchers/built_in/match_spec.rb +++ b/spec/rspec/matchers/built_in/match_spec.rb @@ -1,4 +1,6 @@ RSpec.describe "expect(...).to match(expected)" do + include RSpec::Support::Spec::DiffHelpers + it_behaves_like "an RSpec matcher", :valid_value => 'ab', :invalid_value => 'bc' do let(:matcher) { match(/a/) } end @@ -68,7 +70,7 @@ failure_message_that_includes_diff = %r| \s*Diff: -\s*@@ -1,2 \+1,2 @@ +\s*@@ #{Regexp.escape one_line_header} @@ \s*-/bar/ \s*\+"foo"| diff --git a/spec/rspec/matchers/dsl_spec.rb b/spec/rspec/matchers/dsl_spec.rb index e0f98c5cc..88477ccfd 100644 --- a/spec/rspec/matchers/dsl_spec.rb +++ b/spec/rspec/matchers/dsl_spec.rb @@ -513,7 +513,13 @@ def foo diff = e.message.sub(/\A.*Diff:/m, "Diff:").gsub(/^\s*/, '') end - expect(diff).to eq "Diff:\n@@ -1,3 +1,3 @@\n-line1\n+LINE1\nline2\n" + if Diff::LCS::VERSION.to_f < 1.4 + expected_diff = "Diff:\n@@ -1,3 +1,3 @@\n-line1\n+LINE1\nline2\n" + else + expected_diff = "Diff:\n@@ -1 +1 @@\n-line1\n+LINE1\n" + end + + expect(diff).to eq expected_diff end it 'does not confuse the diffability of different matchers' do