diff-lcs 1.1.2 → 1.1.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,284 @@
1
+ # -*- ruby encoding: utf-8 -*-
2
+
3
+ require 'rubygems'
4
+ require 'pathname'
5
+
6
+ file = Pathname.new(__FILE__).expand_path
7
+ path = file.parent
8
+ parent = path.parent
9
+
10
+ $:.unshift parent.join('lib')
11
+
12
+ require 'diff-lcs'
13
+
14
+ module Diff::LCS::SpecHelper
15
+ def seq1
16
+ %w(a b c e h j l m n p)
17
+ end
18
+
19
+ def skipped_seq1
20
+ %w(a h n p)
21
+ end
22
+
23
+ def seq2
24
+ %w(b c d e f j k l m r s t)
25
+ end
26
+
27
+ def skipped_seq2
28
+ %w(d f k r s t)
29
+ end
30
+
31
+ def word_sequence
32
+ %w(abcd efgh ijkl mnopqrstuvwxyz)
33
+ end
34
+
35
+ def correct_lcs
36
+ %w(b c e j l m)
37
+ end
38
+
39
+ def correct_forward_diff
40
+ [
41
+ [ [ '-', 0, 'a' ] ],
42
+ [ [ '+', 2, 'd' ] ],
43
+ [ [ '-', 4, 'h' ],
44
+ [ '+', 4, 'f' ] ],
45
+ [ [ '+', 6, 'k' ] ],
46
+ [ [ '-', 8, 'n' ],
47
+ [ '-', 9, 'p' ],
48
+ [ '+', 9, 'r' ],
49
+ [ '+', 10, 's' ],
50
+ [ '+', 11, 't' ] ]
51
+ ]
52
+ end
53
+
54
+ def correct_backward_diff
55
+ [
56
+ [ [ '+', 0, 'a' ] ],
57
+ [ [ '-', 2, 'd' ] ],
58
+ [ [ '-', 4, 'f' ],
59
+ [ '+', 4, 'h' ] ],
60
+ [ [ '-', 6, 'k' ] ],
61
+ [
62
+ [ '-', 9, 'r' ],
63
+ [ '-', 10, 's' ],
64
+ [ '+', 8, 'n' ],
65
+ [ '-', 11, 't' ],
66
+ [ '+', 9, 'p' ] ]
67
+ ]
68
+ end
69
+
70
+ def correct_forward_sdiff
71
+ [
72
+ [ '-', [ 0, 'a' ], [ 0, nil ] ],
73
+ [ '=', [ 1, 'b' ], [ 0, 'b' ] ],
74
+ [ '=', [ 2, 'c' ], [ 1, 'c' ] ],
75
+ [ '+', [ 3, nil ], [ 2, 'd' ] ],
76
+ [ '=', [ 3, 'e' ], [ 3, 'e' ] ],
77
+ [ '!', [ 4, 'h' ], [ 4, 'f' ] ],
78
+ [ '=', [ 5, 'j' ], [ 5, 'j' ] ],
79
+ [ '+', [ 6, nil ], [ 6, 'k' ] ],
80
+ [ '=', [ 6, 'l' ], [ 7, 'l' ] ],
81
+ [ '=', [ 7, 'm' ], [ 8, 'm' ] ],
82
+ [ '!', [ 8, 'n' ], [ 9, 'r' ] ],
83
+ [ '!', [ 9, 'p' ], [ 10, 's' ] ],
84
+ [ '+', [ 10, nil ], [ 11, 't' ] ]
85
+ ]
86
+ end
87
+
88
+ def reverse_sdiff(forward_sdiff)
89
+ forward_sdiff.map { |line|
90
+ line[1], line[2] = line[2], line[1]
91
+ case line[0]
92
+ when '-' then line[0] = '+'
93
+ when '+' then line[0] = '-'
94
+ end
95
+ line
96
+ }
97
+ end
98
+
99
+ def change_diff(diff)
100
+ map_diffs(diff, Diff::LCS::Change)
101
+ end
102
+
103
+ def context_diff(diff)
104
+ map_diffs(diff, Diff::LCS::ContextChange)
105
+ end
106
+
107
+ def format_diffs(diffs)
108
+ diffs.map do |e|
109
+ if e.kind_of?(Array)
110
+ e.map { |f| f.to_a.join }.join(", ")
111
+ else
112
+ e.to_a.join
113
+ end
114
+ end.join("\n")
115
+ end
116
+
117
+ def map_diffs(diffs, klass = Diff::LCS::ContextChange)
118
+ diffs.map do |chunks|
119
+ if klass == Diff::LCS::ContextChange
120
+ klass.from_a(chunks)
121
+ else
122
+ chunks.map { |changes| klass.from_a(changes) }
123
+ end
124
+ end
125
+ end
126
+
127
+ def balanced_traversal(s1, s2, callback_type)
128
+ callback = __send__(callback_type)
129
+ Diff::LCS.traverse_balanced(s1, s2, callback)
130
+ callback
131
+ end
132
+
133
+ def balanced_reverse(change_result)
134
+ new_result = []
135
+ change_result.each { |line|
136
+ line = [ line[0], line[2], line[1] ]
137
+ case line[0]
138
+ when '<'
139
+ line[0] = '>'
140
+ when '>'
141
+ line[0] = '<'
142
+ end
143
+ new_result << line
144
+ }
145
+ new_result.sort_by { |line| [ line[1], line[2] ] }
146
+ end
147
+
148
+ def map_to_no_change(change_result)
149
+ new_result = []
150
+ change_result.each { |line|
151
+ case line[0]
152
+ when '!'
153
+ new_result << [ '<', line[1], line[2] ]
154
+ new_result << [ '>', line[1] + 1, line[2] ]
155
+ else
156
+ new_result << line
157
+ end
158
+ }
159
+ new_result
160
+ end
161
+
162
+
163
+ def simple_callback
164
+ callbacks = Object.new
165
+ class << callbacks
166
+ attr_reader :matched_a
167
+ attr_reader :matched_b
168
+ attr_reader :discards_a
169
+ attr_reader :discards_b
170
+ attr_reader :done_a
171
+ attr_reader :done_b
172
+
173
+ def reset
174
+ @matched_a = []
175
+ @matched_b = []
176
+ @discards_a = []
177
+ @discards_b = []
178
+ @done_a = []
179
+ @done_b = []
180
+ end
181
+
182
+ def match(event)
183
+ @matched_a << event.old_element
184
+ @matched_b << event.new_element
185
+ end
186
+
187
+ def discard_b(event)
188
+ @discards_b << event.new_element
189
+ end
190
+
191
+ def discard_a(event)
192
+ @discards_a << event.old_element
193
+ end
194
+
195
+ def finished_a(event)
196
+ @done_a << [event.old_element, event.old_position,
197
+ event.new_element, event.new_position]
198
+ end
199
+
200
+ def finished_b(event)
201
+ p "called #finished_b"
202
+ @done_b << [event.old_element, event.old_position,
203
+ event.new_element, event.new_position]
204
+ end
205
+ end
206
+ callbacks.reset
207
+ callbacks
208
+ end
209
+
210
+ def simple_callback_no_finishers
211
+ simple = simple_callback
212
+ class << simple
213
+ undef :finished_a
214
+ undef :finished_b
215
+ end
216
+ simple
217
+ end
218
+
219
+ def balanced_callback
220
+ cb = Object.new
221
+ class << cb
222
+ attr_reader :result
223
+
224
+ def reset
225
+ @result = []
226
+ end
227
+
228
+ def match(event)
229
+ @result << [ "=", event.old_position, event.new_position ]
230
+ end
231
+
232
+ def discard_a(event)
233
+ @result << [ "<", event.old_position, event.new_position ]
234
+ end
235
+
236
+ def discard_b(event)
237
+ @result << [ ">", event.old_position, event.new_position ]
238
+ end
239
+
240
+ def change(event)
241
+ @result << [ "!", event.old_position, event.new_position ]
242
+ end
243
+ end
244
+ cb.reset
245
+ cb
246
+ end
247
+
248
+ def balanced_callback_no_change
249
+ balanced = balanced_callback
250
+ class << balanced
251
+ undef :change
252
+ end
253
+ balanced
254
+ end
255
+
256
+ module Matchers
257
+ extend RSpec::Matchers::DSL
258
+
259
+ matcher :be_nil_or_match_values do |ii, s1, s2|
260
+ match do |ee|
261
+ ee.should satisfy { |vee| vee.nil? || s1[ii] == s2[ee] }
262
+ end
263
+ end
264
+
265
+ matcher :correctly_map_sequence do |s1|
266
+ match do |actual|
267
+ actual.each_with_index { |ee, ii|
268
+ ee.should be_nil_or_match_values(ii, s1, @s2)
269
+ }
270
+ end
271
+
272
+ chain :to_other_sequence do |s2|
273
+ @s2 = s2
274
+ end
275
+ end
276
+ end
277
+ end
278
+
279
+ RSpec.configure do |conf|
280
+ conf.include Diff::LCS::SpecHelper
281
+ conf.alias_it_should_behave_like_to :it_has_behavior, 'has behavior:'
282
+ end
283
+
284
+ # vim: ft=ruby
@@ -0,0 +1,286 @@
1
+ # -*- ruby encoding: utf-8 -*-
2
+
3
+ require 'spec_helper'
4
+
5
+ describe "Diff::LCS.traverse_balanced" do
6
+ include Diff::LCS::SpecHelper::Matchers
7
+
8
+ shared_examples "with a #change callback" do |s1, s2, result|
9
+ it "should traverse s1 -> s2 correctly" do
10
+ traversal = balanced_traversal(s1, s2, :balanced_callback)
11
+ traversal.result.should == result
12
+ end
13
+
14
+ it "should traverse s2 -> s1 correctly" do
15
+ traversal = balanced_traversal(s2, s1, :balanced_callback)
16
+ traversal.result.should == balanced_reverse(result)
17
+ end
18
+ end
19
+
20
+ shared_examples "without a #change callback" do |s1, s2, result|
21
+ it "should traverse s1 -> s2 correctly" do
22
+ traversal = balanced_traversal(s1, s2, :balanced_callback_no_change)
23
+ traversal.result.should == map_to_no_change(result)
24
+ end
25
+
26
+ it "should traverse s2 -> s1 correctly" do
27
+ traversal = balanced_traversal(s2, s1, :balanced_callback_no_change)
28
+ traversal.result.should == map_to_no_change(balanced_reverse(result))
29
+ end
30
+ end
31
+
32
+ describe "sequences %w(a b c) & %w(a x c)" do
33
+ s1 = %w(a b c)
34
+ s2 = %w(a x c)
35
+
36
+ result = [
37
+ [ '=', 0, 0 ],
38
+ [ '!', 1, 1 ],
39
+ [ '=', 2, 2 ]
40
+ ]
41
+
42
+ it_has_behavior "with a #change callback", s1, s2, result
43
+ it_has_behavior "without a #change callback", s1, s2, result
44
+ end
45
+
46
+ describe "sequences %w(a x y c) & %w(a v w c)" do
47
+ s1 = %w(a x y c)
48
+ s2 = %w(a v w c)
49
+
50
+ result = [
51
+ [ '=', 0, 0 ],
52
+ [ '!', 1, 1 ],
53
+ [ '!', 2, 2 ],
54
+ [ '=', 3, 3 ]
55
+ ]
56
+
57
+ it_has_behavior "with a #change callback", s1, s2, result
58
+ it_has_behavior "without a #change callback", s1, s2, result
59
+ end
60
+
61
+ describe "sequences %w(x y c) & %w(v w c)" do
62
+ s1 = %w(x y c)
63
+ s2 = %w(v w c)
64
+ result = [
65
+ [ '!', 0, 0 ],
66
+ [ '!', 1, 1 ],
67
+ [ '=', 2, 2 ]
68
+ ]
69
+
70
+ it_has_behavior "with a #change callback", s1, s2, result
71
+ it_has_behavior "without a #change callback", s1, s2, result
72
+ end
73
+
74
+ describe "sequences %w(a x y z) & %w(b v w)" do
75
+ s1 = %w(a x y z)
76
+ s2 = %w(b v w)
77
+ result = [
78
+ [ '!', 0, 0 ],
79
+ [ '!', 1, 1 ],
80
+ [ '!', 2, 2 ],
81
+ [ '<', 3, 3 ]
82
+ ]
83
+
84
+ it_has_behavior "with a #change callback", s1, s2, result
85
+ it_has_behavior "without a #change callback", s1, s2, result
86
+ end
87
+
88
+ describe "sequences %w(a z) & %w(a)" do
89
+ s1 = %w(a z)
90
+ s2 = %w(a)
91
+ result = [
92
+ [ '=', 0, 0 ],
93
+ [ '<', 1, 1 ]
94
+ ]
95
+
96
+ it_has_behavior "with a #change callback", s1, s2, result
97
+ it_has_behavior "without a #change callback", s1, s2, result
98
+ end
99
+
100
+ describe "sequences %w(z a) & %w(a)" do
101
+ s1 = %w(z a)
102
+ s2 = %w(a)
103
+ result = [
104
+ [ '<', 0, 0 ],
105
+ [ '=', 1, 0 ]
106
+ ]
107
+
108
+ it_has_behavior "with a #change callback", s1, s2, result
109
+ it_has_behavior "without a #change callback", s1, s2, result
110
+ end
111
+
112
+ describe "sequences %w(a b c) & %w(x y z)" do
113
+ s1 = %w(a b c)
114
+ s2 = %w(x y z)
115
+ result = [
116
+ [ '!', 0, 0 ],
117
+ [ '!', 1, 1 ],
118
+ [ '!', 2, 2 ]
119
+ ]
120
+
121
+ it_has_behavior "with a #change callback", s1, s2, result
122
+ it_has_behavior "without a #change callback", s1, s2, result
123
+ end
124
+
125
+ describe "sequences %w(abcd efgh ijkl mnoopqrstuvwxyz) & []" do
126
+ s1 = %w(abcd efgh ijkl mnopqrstuvwxyz)
127
+ s2 = []
128
+ result = [
129
+ [ '<', 0, 0 ],
130
+ [ '<', 1, 0 ],
131
+ [ '<', 2, 0 ],
132
+ [ '<', 3, 0 ]
133
+ ]
134
+
135
+ it_has_behavior "with a #change callback", s1, s2, result
136
+ it_has_behavior "without a #change callback", s1, s2, result
137
+ end
138
+
139
+ describe "strings %Q(a b c) & %Q(a x c)" do
140
+ s1 = %Q(a b c)
141
+ s2 = %Q(a x c)
142
+
143
+ result = [
144
+ [ '=', 0, 0 ],
145
+ [ '=', 1, 1 ],
146
+ [ '!', 2, 2 ],
147
+ [ '=', 3, 3 ],
148
+ [ '=', 4, 4 ]
149
+ ]
150
+
151
+ it_has_behavior "with a #change callback", s1, s2, result
152
+ it_has_behavior "without a #change callback", s1, s2, result
153
+ end
154
+
155
+ describe "strings %Q(a x y c) & %Q(a v w c)" do
156
+ s1 = %Q(a x y c)
157
+ s2 = %Q(a v w c)
158
+
159
+ result = [
160
+ [ '=', 0, 0 ],
161
+ [ '=', 1, 1 ],
162
+ [ '!', 2, 2 ],
163
+ [ '=', 3, 3 ],
164
+ [ '!', 4, 4 ],
165
+ [ '=', 5, 5 ],
166
+ [ '=', 6, 6 ]
167
+ ]
168
+
169
+ it_has_behavior "with a #change callback", s1, s2, result
170
+ it_has_behavior "without a #change callback", s1, s2, result
171
+ end
172
+
173
+ describe "strings %Q(x y c) & %Q(v w c)" do
174
+ s1 = %Q(x y c)
175
+ s2 = %Q(v w c)
176
+ result = [
177
+ [ '!', 0, 0 ],
178
+ [ '=', 1, 1 ],
179
+ [ '!', 2, 2 ],
180
+ [ '=', 3, 3 ],
181
+ [ '=', 4, 4 ]
182
+ ]
183
+
184
+ it_has_behavior "with a #change callback", s1, s2, result
185
+ it_has_behavior "without a #change callback", s1, s2, result
186
+ end
187
+
188
+ describe "strings %Q(a x y z) & %Q(b v w)" do
189
+ s1 = %Q(a x y z)
190
+ s2 = %Q(b v w)
191
+ result = [
192
+ [ '!', 0, 0 ],
193
+ [ '=', 1, 1 ],
194
+ [ '!', 2, 2 ],
195
+ [ '=', 3, 3 ],
196
+ [ '!', 4, 4 ],
197
+ [ '<', 5, 5 ],
198
+ [ '<', 6, 5 ]
199
+ ]
200
+
201
+ it_has_behavior "with a #change callback", s1, s2, result
202
+ it_has_behavior "without a #change callback", s1, s2, result
203
+ end
204
+
205
+ describe "strings %Q(a z) & %Q(a)" do
206
+ s1 = %Q(a z)
207
+ s2 = %Q(a)
208
+ result = [
209
+ [ '=', 0, 0 ],
210
+ [ '<', 1, 1 ],
211
+ [ '<', 2, 1 ]
212
+ ]
213
+
214
+ it_has_behavior "with a #change callback", s1, s2, result
215
+ it_has_behavior "without a #change callback", s1, s2, result
216
+ end
217
+
218
+ describe "strings %Q(z a) & %Q(a)" do
219
+ s1 = %Q(z a)
220
+ s2 = %Q(a)
221
+ result = [
222
+ [ '<', 0, 0 ],
223
+ [ '<', 1, 0 ],
224
+ [ '=', 2, 0 ]
225
+ ]
226
+
227
+ it_has_behavior "with a #change callback", s1, s2, result
228
+ it_has_behavior "without a #change callback", s1, s2, result
229
+ end
230
+
231
+ describe "strings %Q(a b c) & %Q(x y z)" do
232
+ s1 = %Q(a b c)
233
+ s2 = %Q(x y z)
234
+ result = [
235
+ [ '!', 0, 0 ],
236
+ [ '=', 1, 1 ],
237
+ [ '!', 2, 2 ],
238
+ [ '=', 3, 3 ],
239
+ [ '!', 4, 4 ]
240
+ ]
241
+
242
+ it_has_behavior "with a #change callback", s1, s2, result
243
+ it_has_behavior "without a #change callback", s1, s2, result
244
+ end
245
+
246
+ describe "strings %Q(abcd efgh ijkl mnopqrstuvwxyz) & %Q()" do
247
+ s1 = %Q(abcd efgh ijkl mnopqrstuvwxyz)
248
+ s2 = ""
249
+ result = [
250
+ [ '<', 0, 0 ],
251
+ [ '<', 1, 0 ],
252
+ [ '<', 2, 0 ],
253
+ [ '<', 3, 0 ],
254
+ [ '<', 4, 0 ],
255
+ [ '<', 5, 0 ],
256
+ [ '<', 6, 0 ],
257
+ [ '<', 7, 0 ],
258
+ [ '<', 8, 0 ],
259
+ [ '<', 9, 0 ],
260
+ [ '<', 10, 0 ],
261
+ [ '<', 11, 0 ],
262
+ [ '<', 12, 0 ],
263
+ [ '<', 13, 0 ],
264
+ [ '<', 14, 0 ],
265
+ [ '<', 15, 0 ],
266
+ [ '<', 16, 0 ],
267
+ [ '<', 17, 0 ],
268
+ [ '<', 18, 0 ],
269
+ [ '<', 19, 0 ],
270
+ [ '<', 20, 0 ],
271
+ [ '<', 21, 0 ],
272
+ [ '<', 22, 0 ],
273
+ [ '<', 23, 0 ],
274
+ [ '<', 24, 0 ],
275
+ [ '<', 25, 0 ],
276
+ [ '<', 26, 0 ],
277
+ [ '<', 27, 0 ],
278
+ [ '<', 28, 0 ],
279
+ ]
280
+
281
+ it_has_behavior "with a #change callback", s1, s2, result
282
+ it_has_behavior "without a #change callback", s1, s2, result
283
+ end
284
+ end
285
+
286
+ # vim: ft=ruby