diff --git a/.travis.yml b/.travis.yml index b455d4c9f..1eaad615f 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 d8b30d910..198a555ce 100644 --- a/Gemfile +++ b/Gemfile @@ -21,6 +21,12 @@ else gem 'rake', '>= 12.3.3' end +if ENV['DIFF_LCS_VERSION'] + gem 'diff-lcs', ENV['DIFF_LCS_VERSION'] +else + gem 'diff-lcs', '~> 1.4', '>= 1.4.3' +end + if RUBY_VERSION < '2.2.0' && !!(RbConfig::CONFIG['host_os'] =~ /cygwin|mswin|mingw|bccwin|wince|emx/) gem "childprocess", "< 1.0.0" elsif RUBY_VERSION < '2.3.0' diff --git a/lib/rspec/support/spec.rb b/lib/rspec/support/spec.rb index 6db588b2a..bd998903e 100644 --- a/lib/rspec/support/spec.rb +++ b/lib/rspec/support/spec.rb @@ -2,6 +2,7 @@ require 'rspec/support/spec/in_sub_process' RSpec::Support.require_rspec_support "spec/deprecation_helpers" +RSpec::Support.require_rspec_support "spec/diff_helpers" RSpec::Support.require_rspec_support "spec/with_isolated_stderr" RSpec::Support.require_rspec_support "spec/stderr_splitter" RSpec::Support.require_rspec_support "spec/formatting_support" diff --git a/lib/rspec/support/spec/diff_helpers.rb b/lib/rspec/support/spec/diff_helpers.rb new file mode 100644 index 000000000..84e6fbf37 --- /dev/null +++ b/lib/rspec/support/spec/diff_helpers.rb @@ -0,0 +1,29 @@ +require 'diff/lcs' + +module RSpec + module Support + module Spec + module DiffHelpers + # In the updated version of diff-lcs several diff headers change format slightly + # compensate for this and change minimum version in RSpec 4 + if ::Diff::LCS::VERSION.to_f < 1.4 + def one_line_header(line_number=2) + "-1,#{line_number} +1,#{line_number}" + end + + def removing_two_line_header + "-1,3 +1" + end + else + def one_line_header(_=2) + "-1 +1" + end + + def removing_two_line_header + "-1,3 +1,5" + end + end + end + end + end +end diff --git a/spec/rspec/support/differ_spec.rb b/spec/rspec/support/differ_spec.rb index b08f48fb4..0700a74a8 100644 --- a/spec/rspec/support/differ_spec.rb +++ b/spec/rspec/support/differ_spec.rb @@ -6,7 +6,9 @@ module RSpec module Support - describe Differ do + RSpec.describe Differ do + include Spec::DiffHelpers + describe '#diff' do let(:differ) { RSpec::Support::Differ.new } @@ -14,24 +16,46 @@ module Support expected = "foo\nzap\nbar\nthis\nis\nsoo\nvery\nvery\nequal\ninsert\na\nanother\nline\n" actual = "foo\nbar\nzap\nthis\nis\nsoo\nvery\nvery\nequal\ninsert\na\nline\n" - expected_diff = <<-'EOD' - - -@@ -1,6 +1,6 @@ - foo --zap - bar -+zap - this - is - soo -@@ -9,6 +9,5 @@ - equal - insert - a --another - line -EOD + if Diff::LCS::VERSION.to_f < 1.4 + expected_diff = dedent(<<-'EOD') + | + | + |@@ -1,6 +1,6 @@ + | foo + |-zap + | bar + |+zap + | this + | is + | soo + |@@ -9,6 +9,5 @@ + | equal + | insert + | a + |-another + | line + | + EOD + else + expected_diff = dedent(<<-'EOD') + | + | + |@@ -1,4 +1,6 @@ + | foo + |-zap + | bar + |+zap + | this + |@@ -9,6 +11,7 @@ + | equal + | insert + | a + |-another + | line + | + EOD + end + diff = differ.diff(actual, expected) expect(diff).to be_diffed_as(expected_diff) @@ -41,25 +65,45 @@ module Support expected = "foo\nzap\nbar\nthis\nis\nsoo\nvery\nvery\nequal\ninsert\na\nanother\nline\n" actual = "foo\nbar\nzap\nthis\nis\nsoo\nvery\nvery\nequal\ninsert\na\nline\n" - expected_diff = dedent(<<-'EOS') - | - | - |@@ -1,6 +1,6 @@ - | foo - |-zap - | bar - |+zap - | this - | is - | soo - |@@ -9,6 +9,5 @@ - | equal - | insert - | a - |-another - | line - | - EOS + if Diff::LCS::VERSION.to_f < 1.4 + expected_diff = dedent(<<-'EOS') + | + | + |@@ -1,6 +1,6 @@ + | foo + |-zap + | bar + |+zap + | this + | is + | soo + |@@ -9,6 +9,5 @@ + | equal + | insert + | a + |-another + | line + | + EOS + else + expected_diff = dedent(<<-'EOS') + | + | + |@@ -1,4 +1,6 @@ + | foo + |-zap + | bar + |+zap + | this + |@@ -9,6 +11,7 @@ + | equal + | insert + | a + |-another + | line + | + EOS + end diff = differ.diff(actual, expected) expect(diff).to be_diffed_as(expected_diff) @@ -79,7 +123,6 @@ def differ_ivars end if String.method_defined?(:encoding) - it "returns an empty string if strings are not multiline" do expected = "Tu avec carte {count} item has".encode('UTF-16LE') actual = "Tu avec carté {count} itém has".encode('UTF-16LE') @@ -92,12 +135,13 @@ def differ_ivars it 'copes with encoded strings', :skip => RSpec::Support::OS.windows? do expected = "Tu avec carte {count} item has\n".encode('UTF-16LE') actual = "Tu avec carté {count} itém has\n".encode('UTF-16LE') - expected_diff = <<-EOD.encode('UTF-16LE') - -@@ -1,2 +1,2 @@ --Tu avec carte {count} item has -+Tu avec carté {count} itém has -EOD + expected_diff = dedent(<<-EOD).encode('UTF-16LE') + | + |@@ #{one_line_header} @@ + |-Tu avec carte {count} item has + |+Tu avec carté {count} itém has + | + EOD diff = differ.diff(actual, expected) expect(diff).to be_diffed_as(expected_diff) @@ -106,7 +150,7 @@ def differ_ivars it 'handles differently encoded strings that are compatible' do expected = "abc\n".encode('us-ascii') actual = "강인철\n".encode('UTF-8') - expected_diff = "\n@@ -1,2 +1,2 @@\n-abc\n+강인철\n" + expected_diff = "\n@@ #{one_line_header} @@\n-abc\n+강인철\n" diff = differ.diff(actual, expected) expect(diff).to be_diffed_as(expected_diff) end @@ -114,7 +158,7 @@ def differ_ivars it 'uses the default external encoding when the two strings have incompatible encodings', :failing_on_appveyor do expected = "Tu avec carte {count} item has\n" actual = "Tu avec carté {count} itém has\n".encode('UTF-16LE') - expected_diff = "\n@@ -1,2 +1,2 @@\n-Tu avec carte {count} item has\n+Tu avec carté {count} itém has\n" + expected_diff = "\n@@ #{one_line_header} @@\n-Tu avec carte {count} item has\n+Tu avec carté {count} itém has\n" diff = differ.diff(actual, expected) expect(diff).to be_diffed_as(expected_diff) @@ -135,16 +179,18 @@ def differ_ivars it "outputs unified diff message of two objects" do animal_class = Class.new do + include RSpec::Support::FormattingSupport + def initialize(name, species) @name, @species = name, species end def inspect - <<-EOA - + dedent(<<-EOA) + | EOA end end @@ -152,15 +198,16 @@ def inspect expected = animal_class.new "bob", "giraffe" actual = animal_class.new "bob", "tortoise" - expected_diff = <<'EOD' - -@@ -1,5 +1,5 @@ - -EOD + expected_diff = dedent(<<-'EOD') + | + |@@ -1,5 +1,5 @@ + | + | + EOD diff = differ.diff(expected,actual) expect(diff).to be_diffed_as(expected_diff) @@ -170,19 +217,20 @@ def inspect expected = [ :foo, 'bar', :baz, 'quux', :metasyntactic, 'variable', :delta, 'charlie', :width, 'quite wide' ] actual = [ :foo, 'bar', :baz, 'quux', :metasyntactic, 'variable', :delta, 'tango' , :width, 'very wide' ] - expected_diff = <<'EOD' - - -@@ -5,7 +5,7 @@ - :metasyntactic, - "variable", - :delta, -- "tango", -+ "charlie", - :width, -- "very wide"] -+ "quite wide"] -EOD + expected_diff = dedent(<<-'EOD') + | + | + |@@ -5,7 +5,7 @@ + | :metasyntactic, + | "variable", + | :delta, + |- "tango", + |+ "charlie", + | :width, + |- "very wide"] + |+ "quite wide"] + | + EOD diff = differ.diff(expected,actual) expect(diff).to be_diffed_as(expected_diff) @@ -200,23 +248,25 @@ def inspect; ""; end diff = differ.diff [obj], [] end - expected_diff = <<-EOD - -@@ -1,2 +1,2 @@ --[] -+[] -EOD + expected_diff = dedent(<<-EOD) + | + |@@ #{one_line_header} @@ + |-[] + |+[] + | + EOD expect(diff).to be_diffed_as(expected_diff) end it 'outputs unified diff message of strings in arrays' do diff = differ.diff(["a\r\nb"], ["a\r\nc"]) - expected_diff = <<-EOD - -@@ -1,2 +1,2 @@ --a\\r\\nc -+a\\r\\nb -EOD + expected_diff = dedent(<<-EOD) + | + |@@ #{one_line_header} @@ + |-a\\r\\nc + |+a\\r\\nb + | + EOD expect(diff).to be_diffed_as(expected_diff) end @@ -224,16 +274,17 @@ def inspect; ""; end expected = { :foo => 'bar', :baz => 'quux', :metasyntactic => 'variable', :delta => 'charlie', :width =>'quite wide' } actual = { :foo => 'bar', :metasyntactic => 'variable', :delta => 'charlotte', :width =>'quite wide' } - expected_diff = <<'EOD' - -@@ -1,4 +1,5 @@ --:delta => "charlotte", -+:baz => "quux", -+:delta => "charlie", - :foo => "bar", - :metasyntactic => "variable", - :width => "quite wide", -EOD + expected_diff = dedent(<<-'EOD') + | + |@@ -1,4 +1,5 @@ + |-:delta => "charlotte", + |+:baz => "quux", + |+:delta => "charlie", + | :foo => "bar", + | :metasyntactic => "variable", + | :width => "quite wide", + | + EOD diff = differ.diff(expected,actual) expect(diff).to be_diffed_as(expected_diff) @@ -244,16 +295,17 @@ def inspect; ""; end expected = [{ :foo => 'bar', :baz => 'quux', :metasyntactic => 'variable', :delta => 'charlie', :width =>'quite wide' }] actual = [{ :metasyntactic => 'variable', :delta => 'charlotte', :width =>'quite wide', :foo => 'bar' }] - expected_diff = <<'EOD' - -@@ -1,4 +1,5 @@ --[{:delta=>"charlotte", -+[{:baz=>"quux", -+ :delta=>"charlie", - :foo=>"bar", - :metasyntactic=>"variable", - :width=>"quite wide"}] -EOD + expected_diff = dedent(<<-'EOD') + | + |@@ -1,4 +1,5 @@ + |-[{:delta=>"charlotte", + |+[{:baz=>"quux", + |+ :delta=>"charlie", + | :foo=>"bar", + | :metasyntactic=>"variable", + | :width=>"quite wide"}] + | + EOD diff = differ.diff(expected,actual) expect(diff).to be_diffed_as(expected_diff) @@ -261,33 +313,39 @@ def inspect; ""; end end it 'outputs unified diff message of two hashes with differing encoding', :failing_on_appveyor do - expected_diff = %Q{ -@@ -1,2 +1,2 @@ --"a" => "a", -#{ (RUBY_VERSION.to_f > 1.8) ? %Q{+"ö" => "ö"} : '+"\303\266" => "\303\266"' }, -} + expected_diff = dedent(<<-"EOD") + | + |@@ #{one_line_header} @@ + |-"a" => "a", + |#{ (RUBY_VERSION.to_f > 1.8) ? %Q{+"ö" => "ö"} : '+"\303\266" => "\303\266"' }, + | + EOD diff = differ.diff({'ö' => 'ö'}, {'a' => 'a'}) expect(diff).to be_diffed_as(expected_diff) end it 'outputs unified diff message of two hashes with encoding different to key encoding', :failing_on_appveyor do - expected_diff = %Q{ -@@ -1,2 +1,2 @@ --:a => "a", -#{ (RUBY_VERSION.to_f > 1.8) ? %Q{+\"한글\" => \"한글2\"} : '+"\355\225\234\352\270\200" => "\355\225\234\352\270\2002"' }, -} + expected_diff = dedent(<<-"EOD") + | + |@@ #{one_line_header} @@ + |-:a => "a", + |#{ (RUBY_VERSION.to_f > 1.8) ? %Q{+\"한글\" => \"한글2\"} : '+"\355\225\234\352\270\200" => "\355\225\234\352\270\2002"' }, + | + EOD diff = differ.diff({ "한글" => "한글2"}, { :a => "a"}) expect(diff).to be_diffed_as(expected_diff) end it "outputs unified diff message of two hashes with object keys" do - expected_diff = %Q{ -@@ -1,2 +1,2 @@ --["a", "c"] => "b", -+["d", "c"] => "b", -} + expected_diff = dedent(<<-"EOD") + | + |@@ #{one_line_header} @@ + |-["a", "c"] => "b", + |+["d", "c"] => "b", + | + EOD diff = differ.diff({ ['d','c'] => 'b'}, { ['a','c'] => 'b' }) expect(diff).to be_diffed_as(expected_diff) @@ -298,22 +356,26 @@ def inspect; ""; end let(:formatted_time) { ObjectFormatter.format(time) } it "outputs unified diff message of two hashes with Time object keys" do - expected_diff = %Q{ -@@ -1,2 +1,2 @@ --#{formatted_time} => "b", -+#{formatted_time} => "c", -} + expected_diff = dedent(<<-"EOD") + | + |@@ #{one_line_header} @@ + |-#{formatted_time} => "b", + |+#{formatted_time} => "c", + | + EOD diff = differ.diff({ time => 'c'}, { time => 'b' }) expect(diff).to be_diffed_as(expected_diff) end it "outputs unified diff message of two hashes with hashes inside them" do - expected_diff = %Q{ -@@ -1,2 +1,2 @@ --"b" => {"key_1"=>#{formatted_time}}, -+"c" => {"key_1"=>#{formatted_time}}, -} + expected_diff = dedent(<<-"EOD") + | + |@@ #{one_line_header} @@ + |-"b" => {"key_1"=>#{formatted_time}}, + |+"c" => {"key_1"=>#{formatted_time}}, + | + EOD left_side_hash = {'c' => {'key_1' => time}} right_side_hash = {'b' => {'key_1' => time}} @@ -327,22 +389,26 @@ def inspect; ""; end let(:formatted_time) { ObjectFormatter.format(time) } it "outputs unified diff message of two arrays with Time object keys" do - expected_diff = %Q{ -@@ -1,2 +1,2 @@ --[#{formatted_time}, "b"] -+[#{formatted_time}, "c"] -} + expected_diff = dedent(<<-"EOD") + | + |@@ #{one_line_header} @@ + |-[#{formatted_time}, "b"] + |+[#{formatted_time}, "c"] + | + EOD diff = differ.diff([time, 'c'], [time, 'b']) expect(diff).to be_diffed_as(expected_diff) end it "outputs unified diff message of two arrays with hashes inside them" do - expected_diff = %Q{ -@@ -1,2 +1,2 @@ --[{"b"=>#{formatted_time}}, "c"] -+[{"a"=>#{formatted_time}}, "c"] -} + expected_diff = dedent(<<-"EOD") + | + |@@ #{one_line_header} @@ + |-[{"b"=>#{formatted_time}}, "c"] + |+[{"a"=>#{formatted_time}}, "c"] + | + EOD left_side_array = [{'a' => time}, 'c'] right_side_array = [{'b' => time}, 'c'] @@ -355,37 +421,40 @@ def inspect; ""; end expected = "this is:\n one string" actual = "this is:\n another string" - expected_diff = <<'EOD' - -@@ -1,3 +1,3 @@ - this is: -- another string -+ one string -EOD + expected_diff = dedent(<<-'EOD') + | + |@@ -1,3 +1,3 @@ + | this is: + |- another string + |+ one string + | + EOD diff = differ.diff(expected,actual) expect(diff).to be_diffed_as(expected_diff) end it "splits items with newlines" do - expected_diff = <<'EOD' - -@@ -1,3 +1 @@ --a\nb --c\nd -EOD + expected_diff = dedent(<<-"EOD") + | + |@@ #{removing_two_line_header} @@ + |-a\\nb + |-c\\nd + | + EOD diff = differ.diff [], ["a\nb", "c\nd"] expect(diff).to be_diffed_as(expected_diff) end it "shows inner arrays on a single line" do - expected_diff = <<'EOD' - -@@ -1,3 +1 @@ --a\nb --["c\nd"] -EOD + expected_diff = dedent(<<-"EOD") + | + |@@ #{removing_two_line_header} @@ + |-a\\nb + |-["c\\nd"] + | + EOD diff = differ.diff [], ["a\nb", ["c\nd"]] expect(diff).to be_diffed_as(expected_diff) @@ -434,7 +503,7 @@ def inspect; ""; end expected_diff = dedent(<<-EOS) | - |@@ -1,2 +1,2 @@ + |@@ #{one_line_header} @@ |-[#] |+[#{object.inspect}] | @@ -456,7 +525,7 @@ def inspect; ""; end expected_diff = dedent(<<-EOS) | - |@@ -1,2 +1,2 @@ + |@@ #{one_line_header} @@ |-"oop" |+"oof" | @@ -473,7 +542,7 @@ def inspect; ""; end it "outputs colored diffs" 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" diff = differ.diff(expected,actual) expect(diff).to be_diffed_as(expected_diff)