diff-lcs 1.1.3 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +1 -0
  3. data/Code-of-Conduct.md +74 -0
  4. data/Contributing.md +119 -0
  5. data/History.md +400 -0
  6. data/{License.rdoc → License.md} +6 -5
  7. data/Manifest.txt +36 -4
  8. data/README.rdoc +35 -23
  9. data/Rakefile +106 -11
  10. data/bin/htmldiff +7 -4
  11. data/bin/ldiff +4 -1
  12. data/docs/COPYING.txt +21 -22
  13. data/docs/artistic.txt +127 -0
  14. data/lib/diff/lcs/array.rb +1 -15
  15. data/lib/diff/lcs/backports.rb +9 -0
  16. data/lib/diff/lcs/block.rb +4 -18
  17. data/lib/diff/lcs/callbacks.rb +233 -230
  18. data/lib/diff/lcs/change.rb +114 -109
  19. data/lib/diff/lcs/htmldiff.rb +17 -18
  20. data/lib/diff/lcs/hunk.rb +232 -116
  21. data/lib/diff/lcs/internals.rb +308 -0
  22. data/lib/diff/lcs/ldiff.rb +138 -177
  23. data/lib/diff/lcs/string.rb +1 -15
  24. data/lib/diff/lcs.rb +597 -963
  25. data/lib/diff-lcs.rb +1 -3
  26. data/spec/change_spec.rb +89 -0
  27. data/spec/diff_spec.rb +32 -16
  28. data/spec/fixtures/aX +1 -0
  29. data/spec/fixtures/bXaX +1 -0
  30. data/spec/fixtures/ds1.csv +50 -0
  31. data/spec/fixtures/ds2.csv +51 -0
  32. data/spec/fixtures/ldiff/output.diff +4 -0
  33. data/spec/fixtures/ldiff/output.diff-c +7 -0
  34. data/spec/fixtures/ldiff/output.diff-e +3 -0
  35. data/spec/fixtures/ldiff/output.diff-f +3 -0
  36. data/spec/fixtures/ldiff/output.diff-u +5 -0
  37. data/spec/fixtures/ldiff/output.diff.chef +4 -0
  38. data/spec/fixtures/ldiff/output.diff.chef-c +15 -0
  39. data/spec/fixtures/ldiff/output.diff.chef-e +3 -0
  40. data/spec/fixtures/ldiff/output.diff.chef-f +3 -0
  41. data/spec/fixtures/ldiff/output.diff.chef-u +9 -0
  42. data/spec/fixtures/ldiff/output.diff.chef2 +7 -0
  43. data/spec/fixtures/ldiff/output.diff.chef2-c +20 -0
  44. data/spec/fixtures/ldiff/output.diff.chef2-d +7 -0
  45. data/spec/fixtures/ldiff/output.diff.chef2-e +7 -0
  46. data/spec/fixtures/ldiff/output.diff.chef2-f +7 -0
  47. data/spec/fixtures/ldiff/output.diff.chef2-u +16 -0
  48. data/spec/fixtures/new-chef +4 -0
  49. data/spec/fixtures/new-chef2 +17 -0
  50. data/spec/fixtures/old-chef +4 -0
  51. data/spec/fixtures/old-chef2 +14 -0
  52. data/spec/hunk_spec.rb +83 -0
  53. data/spec/issues_spec.rb +154 -0
  54. data/spec/lcs_spec.rb +36 -16
  55. data/spec/ldiff_spec.rb +87 -0
  56. data/spec/patch_spec.rb +198 -172
  57. data/spec/sdiff_spec.rb +99 -89
  58. data/spec/spec_helper.rb +149 -59
  59. data/spec/traverse_balanced_spec.rb +191 -167
  60. data/spec/traverse_sequences_spec.rb +105 -51
  61. metadata +218 -99
  62. data/.gemtest +0 -0
  63. data/History.rdoc +0 -54
  64. data/diff-lcs.gemspec +0 -51
  65. data/docs/artistic.html +0 -289
@@ -0,0 +1,154 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require 'diff/lcs/hunk'
5
+
6
+ describe 'Diff::LCS Issues' do
7
+ include Diff::LCS::SpecHelper::Matchers
8
+
9
+ describe 'issue #1' do
10
+ shared_examples 'handles simple diffs' do |s1, s2, forward_diff|
11
+ before do
12
+ @diff_s1_s2 = Diff::LCS.diff(s1, s2)
13
+ end
14
+
15
+ it 'creates the correct diff' do
16
+ expect(change_diff(forward_diff)).to eq(@diff_s1_s2)
17
+ end
18
+
19
+ it 'creates the correct patch s1->s2' do
20
+ expect(Diff::LCS.patch(s1, @diff_s1_s2)).to eq(s2)
21
+ end
22
+
23
+ it 'creates the correct patch s2->s1' do
24
+ expect(Diff::LCS.patch(s2, @diff_s1_s2)).to eq(s1)
25
+ end
26
+ end
27
+
28
+ describe 'string' do
29
+ it_has_behavior 'handles simple diffs', 'aX', 'bXaX', [
30
+ [
31
+ ['+', 0, 'b'],
32
+ ['+', 1, 'X']
33
+ ]
34
+ ]
35
+ it_has_behavior 'handles simple diffs', 'bXaX', 'aX', [
36
+ [
37
+ ['-', 0, 'b'],
38
+ ['-', 1, 'X']
39
+ ]
40
+ ]
41
+ end
42
+
43
+ describe 'array' do
44
+ it_has_behavior 'handles simple diffs', %w(a X), %w(b X a X), [
45
+ [
46
+ ['+', 0, 'b'],
47
+ ['+', 1, 'X']
48
+ ]
49
+ ]
50
+ it_has_behavior 'handles simple diffs', %w(b X a X), %w(a X), [
51
+ [
52
+ ['-', 0, 'b'],
53
+ ['-', 1, 'X']
54
+ ]
55
+ ]
56
+ end
57
+ end
58
+
59
+ describe 'issue #57' do
60
+ it 'should fail with a correct error' do
61
+ expect {
62
+ actual = { :category => 'app.rack.request' }
63
+ expected = { :category => 'rack.middleware', :title => 'Anonymous Middleware' }
64
+ expect(actual).to eq(expected)
65
+ }.to raise_error(RSpec::Expectations::ExpectationNotMetError)
66
+ end
67
+ end
68
+
69
+ describe 'issue #60' do
70
+ it 'should produce unified output with correct context' do
71
+ old_data = <<-DATA_OLD.strip.split("\n").map(&:chomp)
72
+ {
73
+ "name": "x",
74
+ "description": "hi"
75
+ }
76
+ DATA_OLD
77
+
78
+ new_data = <<-DATA_NEW.strip.split("\n").map(&:chomp)
79
+ {
80
+ "name": "x",
81
+ "description": "lo"
82
+ }
83
+ DATA_NEW
84
+
85
+ diff = ::Diff::LCS.diff(old_data, new_data)
86
+ hunk = ::Diff::LCS::Hunk.new(old_data, new_data, diff.first, 3, 0)
87
+
88
+ expect(hunk.diff(:unified)).to eq(<<-EXPECTED.chomp)
89
+ @@ -1,5 +1,5 @@
90
+ {
91
+ "name": "x",
92
+ - "description": "hi"
93
+ + "description": "lo"
94
+ }
95
+ EXPECTED
96
+ end
97
+ end
98
+
99
+ describe 'issue #65' do
100
+ def diff_lines(old_lines, new_lines)
101
+ file_length_difference = 0
102
+ previous_hunk = nil
103
+ output = []
104
+
105
+ Diff::LCS.diff(old_lines, new_lines).each do |piece|
106
+ hunk = Diff::LCS::Hunk.new(old_lines, new_lines, piece, 3, file_length_difference)
107
+ file_length_difference = hunk.file_length_difference
108
+ maybe_contiguous_hunks = (previous_hunk.nil? || hunk.merge(previous_hunk))
109
+
110
+ output << "#{previous_hunk.diff(:unified)}\n" unless maybe_contiguous_hunks
111
+
112
+ previous_hunk = hunk
113
+ end
114
+ output << "#{previous_hunk.diff(:unified, true)}\n" unless previous_hunk.nil?
115
+ output.join
116
+ end
117
+
118
+ it 'should not misplace the new chunk' do
119
+ old_data = [
120
+ 'recipe[a::default]', 'recipe[b::default]', 'recipe[c::default]',
121
+ 'recipe[d::default]', 'recipe[e::default]', 'recipe[f::default]',
122
+ 'recipe[g::default]', 'recipe[h::default]', 'recipe[i::default]',
123
+ 'recipe[j::default]', 'recipe[k::default]', 'recipe[l::default]',
124
+ 'recipe[m::default]', 'recipe[n::default]'
125
+ ]
126
+
127
+ new_data = [
128
+ 'recipe[a::default]', 'recipe[c::default]', 'recipe[d::default]',
129
+ 'recipe[e::default]', 'recipe[f::default]', 'recipe[g::default]',
130
+ 'recipe[h::default]', 'recipe[i::default]', 'recipe[j::default]',
131
+ 'recipe[k::default]', 'recipe[l::default]', 'recipe[m::default]',
132
+ 'recipe[n::default]', 'recipe[o::new]', 'recipe[p::new]',
133
+ 'recipe[q::new]', 'recipe[r::new]'
134
+ ]
135
+
136
+ expect(diff_lines(old_data, new_data)).to eq(<<-EODIFF)
137
+ @@ -1,5 +1,4 @@
138
+ recipe[a::default]
139
+ -recipe[b::default]
140
+ recipe[c::default]
141
+ recipe[d::default]
142
+ recipe[e::default]
143
+ @@ -12,3 +11,7 @@
144
+ recipe[l::default]
145
+ recipe[m::default]
146
+ recipe[n::default]
147
+ +recipe[o::new]
148
+ +recipe[p::new]
149
+ +recipe[q::new]
150
+ +recipe[r::new]
151
+ EODIFF
152
+ end
153
+ end
154
+ end
data/spec/lcs_spec.rb CHANGED
@@ -1,36 +1,56 @@
1
- # -*- ruby encoding: utf-8 -*-
1
+ # frozen_string_literal: true
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe "Diff::LCS.LCS and Diff::LCS.__lcs" do
5
+ describe Diff::LCS::Internals, '.lcs' do
6
6
  include Diff::LCS::SpecHelper::Matchers
7
7
 
8
- it "should return the correct raw values from Diff::LCS.__lcs" do
9
- res = Diff::LCS.__lcs(seq1, seq2)
8
+ it 'returns a meaningful LCS array with (seq1, seq2)' do
9
+ res = Diff::LCS::Internals.lcs(seq1, seq2)
10
10
  # The result of the LCS (less the +nil+ values) must be as long as the
11
11
  # correct result.
12
- res.compact.size.should == correct_lcs.size
13
- res.should correctly_map_sequence(seq1).to_other_sequence(seq2)
12
+ expect(res.compact.size).to eq(correct_lcs.size)
13
+ expect(res).to correctly_map_sequence(seq1).to_other_sequence(seq2)
14
14
 
15
15
  # Compact these transformations and they should be the correct LCS.
16
16
  x_seq1 = (0...res.size).map { |ix| res[ix] ? seq1[ix] : nil }.compact
17
17
  x_seq2 = (0...res.size).map { |ix| res[ix] ? seq2[res[ix]] : nil }.compact
18
18
 
19
- x_seq1.should == correct_lcs
20
- x_seq2.should == correct_lcs
19
+ expect(x_seq1).to eq(correct_lcs)
20
+ expect(x_seq2).to eq(correct_lcs)
21
21
  end
22
22
 
23
- it "should return the correct compacted values from Diff::LCS.LCS" do
23
+ it 'returns all indexes with (hello, hello)' do
24
+ expect(Diff::LCS::Internals.lcs(hello, hello)).to \
25
+ eq((0...hello.size).to_a)
26
+ end
27
+
28
+ it 'returns all indexes with (hello_ary, hello_ary)' do
29
+ expect(Diff::LCS::Internals.lcs(hello_ary, hello_ary)).to \
30
+ eq((0...hello_ary.size).to_a)
31
+ end
32
+ end
33
+
34
+ describe Diff::LCS, '.LCS' do
35
+ include Diff::LCS::SpecHelper::Matchers
36
+
37
+ it 'returns the correct compacted values from Diff::LCS.LCS' do
24
38
  res = Diff::LCS.LCS(seq1, seq2)
25
- res.should == correct_lcs
26
- res.compact.should == res
39
+ expect(res).to eq(correct_lcs)
40
+ expect(res.compact).to eq(res)
27
41
  end
28
42
 
29
- it "should be transitive" do
43
+ it 'is transitive' do
30
44
  res = Diff::LCS.LCS(seq2, seq1)
31
- res.should == correct_lcs
32
- res.compact.should == res
45
+ expect(res).to eq(correct_lcs)
46
+ expect(res.compact).to eq(res)
47
+ end
48
+
49
+ it 'returns %W(h e l l o) with (hello, hello)' do
50
+ expect(Diff::LCS.LCS(hello, hello)).to eq(hello.split(//))
33
51
  end
34
- end
35
52
 
36
- # vim: ft=ruby
53
+ it 'returns hello_ary with (hello_ary, hello_ary)' do
54
+ expect(Diff::LCS.LCS(hello_ary, hello_ary)).to eq(hello_ary)
55
+ end
56
+ end
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe 'bin/ldiff' do
6
+ include CaptureSubprocessIO
7
+
8
+ fixtures = [
9
+ { :name => 'output.diff', :left => 'aX', :right => 'bXaX' },
10
+ { :name => 'output.diff.chef', :left => 'old-chef', :right => 'new-chef' },
11
+ { :name => 'output.diff.chef2', :left => 'old-chef2', :right => 'new-chef2' }
12
+ ].product([nil, '-e', '-f', '-c', '-u']).map { |(fixture, flag)|
13
+ fixture = fixture.dup
14
+ fixture[:flag] = flag
15
+ fixture
16
+ }
17
+
18
+ def self.test_ldiff(fixture)
19
+ desc = [
20
+ fixture[:flag],
21
+ "spec/fixtures/#{fixture[:left]}",
22
+ "spec/fixtures/#{fixture[:right]}",
23
+ '#',
24
+ '=>',
25
+ "spec/fixtures/ldiff/#{fixture[:name]}#{fixture[:flag]}"
26
+ ].join(' ')
27
+
28
+ it desc do
29
+ expect(run_ldiff(fixture)).to eq(read_fixture(fixture))
30
+ end
31
+ end
32
+
33
+ fixtures.each do |fixture|
34
+ test_ldiff(fixture)
35
+ end
36
+
37
+ def read_fixture(options)
38
+ fixture = options.fetch(:name)
39
+ flag = options.fetch(:flag)
40
+ name = "spec/fixtures/ldiff/#{fixture}#{flag}"
41
+ data = IO.__send__(IO.respond_to?(:binread) ? :binread : :read, name)
42
+ clean_data(data, flag)
43
+ end
44
+
45
+ def clean_data(data, flag)
46
+ data =
47
+ case flag
48
+ when '-c', '-u'
49
+ clean_output_timestamp(data)
50
+ else
51
+ data
52
+ end
53
+ data.gsub(/\r\n?/, "\n")
54
+ end
55
+
56
+ def clean_output_timestamp(data)
57
+ data.gsub(
58
+ %r{
59
+ ^
60
+ [-+*]{3}
61
+ \s*
62
+ spec/fixtures/(\S+)
63
+ \s*
64
+ \d{4}-\d\d-\d\d
65
+ \s*
66
+ \d\d:\d\d:\d\d(?:\.\d+)
67
+ \s*
68
+ (?:[-+]\d{4}|Z)
69
+ }x,
70
+ '*** spec/fixtures/\1 0000-00-00 :00 =>:00 =>00.000000000 -0000'
71
+ )
72
+ end
73
+
74
+ def run_ldiff(options)
75
+ flag = options.fetch(:flag)
76
+ left = options.fetch(:left)
77
+ right = options.fetch(:right)
78
+
79
+ stdout, stderr = capture_subprocess_io do
80
+ system("ruby -Ilib bin/ldiff #{flag} spec/fixtures/#{left} spec/fixtures/#{right}")
81
+ end
82
+
83
+ expect(stderr).to be_empty if RUBY_VERSION >= '1.9'
84
+ expect(stdout).not_to be_empty
85
+ clean_data(stdout, flag)
86
+ end
87
+ end