Fix compiler warning due to missing function prototype.
[svn.git] / subversion / bindings / swig / ruby / test / test_delta.rb
blob3f3503d7e4a0cd717d79d1b0b549dc3958494e25
1 require "util"
2 require "stringio"
3 require 'md5'
4 require 'tempfile'
6 require "svn/info"
8 class SvnDeltaTest < Test::Unit::TestCase
9   include SvnTestUtil
11   def setup
12     setup_basic
13   end
15   def teardown
16     teardown_basic
17   end
19   def test_version
20     assert_equal(Svn::Core.subr_version, Svn::Delta.version)
21   end
23   def test_txdelta_window
24     s = ("a\nb\nc\nd\ne" + "\n" * 100) * 1000
25     t = ("a\nb\nX\nd\ne" + "\n" * 100) * 1000
26     source = StringIO.new(s)
27     target = StringIO.new(t)
28     stream = Svn::Delta::TextDeltaStream.new(source, target)
29     assert_nil(stream.md5_digest)
30     _wrap_assertion do
31       stream.each do |window|
32         window.ops.each do |op|
33           op_size = op.offset + op.length
34           case op.action_code
35           when Svn::Delta::TXDELTA_SOURCE
36             assert_operator(op_size, :<=, window.sview_len)
37           when Svn::Delta::TXDELTA_NEW
38             assert_operator(op_size, :<=, window.new_data.length)
39           when Svn::Delta::TXDELTA_TARGET
40             assert_operator(op_size, :<=, window.tview_len)
41           else
42             flunk
43           end
44         end
45       end
46     end
47     assert_equal(MD5.new(t).hexdigest, stream.md5_digest)
48   end
50   def test_txdelta_window_compose
51     s = ("a\nb\nc\nd\ne" + "\n" * 100) * 1000
52     t = ("a\nb\nX\nd\ne" + "\n" * 100) * 1000
53     source = StringIO.new(s)
54     target = StringIO.new(t)
55     stream = Svn::Delta::TextDeltaStream.new(source, target)
56     composed_window = nil
57     stream.each do |window|
58       if composed_window.nil?
59         composed_window = window
60       else
61         composed_window = composed_window.compose(window)
62       end
63     end
65     _wrap_assertion do
66       composed_window.ops.each do |op|
67         op_size = op.offset + op.length
68         case op.action_code
69         when Svn::Delta::TXDELTA_SOURCE
70           assert_operator(op_size, :<=, composed_window.sview_len)
71         when Svn::Delta::TXDELTA_NEW
72           assert_operator(op_size, :<=, composed_window.new_data.length)
73         when Svn::Delta::TXDELTA_TARGET
74           assert_operator(op_size, :<=, composed_window.tview_len)
75         else
76           flunk
77         end
78       end
79     end
80   end
82   def test_txdelta_apply_instructions
83     s = ("a\nb\nc\nd\ne" + "\n" * 100) * 1000
84     t = ("a\nb\nX\nd\ne" + "\n" * 100) * 1000
85     source = StringIO.new(s)
86     target = StringIO.new(t)
87     stream = Svn::Delta::TextDeltaStream.new(source, target)
89     result = ""
90     offset = 0
91     stream.each do |window|
92       result << window.apply_instructions(s[offset, window.sview_len])
93       offset += window.sview_len
94     end
95     assert_equal(t, result)
96   end
98   def test_push_target
99     source = StringIO.new("abcde")
100     target_content = "ZZZ" * 100
101     data = ""
102     finished = false
103     handler = Proc.new do |window|
104       if window
105         data << window.new_data
106       else
107         finished = true
108       end
109     end
110     target = Svn::Delta::TextDeltaStream.push_target(source, &handler)
111     target.write(target_content)
112     assert(!finished)
113     target.close
114     assert(finished)
115     assert_equal(target_content, data)
116   end
118   def test_apply
119     source_text = "abcde"
120     target_text = "abXde"
121     source = StringIO.new(source_text)
122     target = StringIO.new(target_text)
123     stream = Svn::Delta::TextDeltaStream.new(source, target)
125     apply_source = StringIO.new(source_text)
126     apply_result = StringIO.new("")
128     handler, digest = Svn::Delta.apply(apply_source, apply_result)
129     handler.send(stream)
130     apply_result.rewind
131     assert_equal(target_text, apply_result.read)
133     handler, digest = Svn::Delta.apply(apply_source, apply_result)
134     handler.send(target_text)
135     apply_result.rewind
136     assert_equal(target_text * 2, apply_result.read)
138     handler, digest = Svn::Delta.apply(apply_source, apply_result)
139     handler.send(StringIO.new(target_text))
140     apply_result.rewind
141     assert_equal(target_text * 3, apply_result.read)
142   end
144   def test_svndiff
145     source_text = "abcde"
146     target_text = "abXde"
147     source = StringIO.new(source_text)
148     target = StringIO.new(target_text)
149     stream = Svn::Delta::TextDeltaStream.new(source, target)
151     output = StringIO.new("")
152     handler = Svn::Delta.svndiff_handler(output)
154     Svn::Delta.send(target_text, handler)
155     output.rewind
156     result = output.read
157     assert_match(/\ASVN.*#{target_text}\z/, result)
159     # skip svndiff window
160     input = StringIO.new(result[4..-1])
161     window = Svn::Delta.read_svndiff_window(input, 0)
162     assert_equal(target_text, window.new_data)
164     finished = false
165     data = ""
166     stream = Svn::Delta.parse_svndiff do |window|
167       if window
168         data << window.new_data
169       else
170         finished = true
171       end
172     end
173     stream.write(result)
174     stream.close
175     assert(finished)
176     assert_equal(target_text, data)
177   end
179   def test_path_driver
180     editor = Svn::Delta::BaseEditor.new
181     sorted_paths = []
182     callback = Proc.new do |parent_baton, path|
183       sorted_paths << path
184     end
186     targets = [
187       "/",
188       "/file1",
189       "/dir1",
190       "/dir2/file2",
191       "/dir2/dir3/file3",
192       "/dir2/dir3/file4"
193     ]
194     10.times do
195       x = rand(targets.size)
196       y = rand(targets.size)
197       targets[x], targets[y] = targets[y], targets[x]
198     end
199     Svn::Delta.path_driver(editor, 0, targets, &callback)
200     assert_equal(targets.sort, sorted_paths)
201   end
203   def test_changed
204     dir = "changed_dir"
205     dir1 = "changed_dir1"
206     dir2 = "changed_dir2"
207     dir_path = File.join(@wc_path, dir)
208     dir1_path = File.join(@wc_path, dir1)
209     dir2_path = File.join(@wc_path, dir2)
210     dir_svn_path = dir
211     dir1_svn_path = dir1
212     dir2_svn_path = dir2
214     log = "added 3 dirs\nanded 5 files"
215     ctx = make_context(log)
217     ctx.mkdir([dir_path, dir1_path, dir2_path])
219     file1 = "changed1.txt"
220     file2 = "changed2.txt"
221     file3 = "changed3.txt"
222     file4 = "changed4.txt"
223     file5 = "changed5.txt"
224     file1_path = File.join(@wc_path, file1)
225     file2_path = File.join(dir_path, file2)
226     file3_path = File.join(@wc_path, file3)
227     file4_path = File.join(dir_path, file4)
228     file5_path = File.join(@wc_path, file5)
229     file1_svn_path = file1
230     file2_svn_path = [dir_svn_path, file2].join("/")
231     file3_svn_path = file3
232     file4_svn_path = [dir_svn_path, file4].join("/")
233     file5_svn_path = file5
234     FileUtils.touch(file1_path)
235     FileUtils.touch(file2_path)
236     FileUtils.touch(file3_path)
237     FileUtils.touch(file4_path)
238     FileUtils.touch(file5_path)
239     ctx.add(file1_path)
240     ctx.add(file2_path)
241     ctx.add(file3_path)
242     ctx.add(file4_path)
243     ctx.add(file5_path)
245     commit_info = ctx.commit(@wc_path)
246     first_rev = commit_info.revision
248     editor = traverse(Svn::Delta::ChangedEditor, commit_info.revision, true)
249     assert_equal([
250                    file1_svn_path, file2_svn_path,
251                    file3_svn_path, file4_svn_path,
252                    file5_svn_path,
253                  ].sort,
254                  editor.added_files)
255     assert_equal([], editor.updated_files)
256     assert_equal([], editor.deleted_files)
257     assert_equal([].sort, editor.updated_dirs)
258     assert_equal([].sort, editor.deleted_dirs)
259     assert_equal([
260                    "#{dir_svn_path}/",
261                    "#{dir1_svn_path}/",
262                    "#{dir2_svn_path}/"
263                  ].sort,
264                  editor.added_dirs)
267     log = "deleted 2 dirs\nchanged 3 files\ndeleted 2 files\nadded 3 files"
268     ctx = make_context(log)
270     dir3 = "changed_dir3"
271     dir4 = "changed_dir4"
272     dir3_path = File.join(dir_path, dir3)
273     dir4_path = File.join(@wc_path, dir4)
274     dir3_svn_path = [dir_svn_path, dir3].join("/")
275     dir4_svn_path = dir4
277     file6 = "changed6.txt"
278     file7 = "changed7.txt"
279     file8 = "changed8.txt"
280     file9 = "changed9.txt"
281     file10 = "changed10.txt"
282     file6_path = File.join(dir_path, file6)
283     file7_path = File.join(@wc_path, file7)
284     file8_path = File.join(dir_path, file8)
285     file9_path = File.join(dir_path, file9)
286     file10_path = File.join(dir_path, file10)
287     file6_svn_path = [dir_svn_path, file6].join("/")
288     file7_svn_path = file7
289     file8_svn_path = [dir_svn_path, file8].join("/")
290     file9_svn_path = [dir_svn_path, file9].join("/")
291     file10_svn_path = [dir_svn_path, file10].join("/")
293     File.open(file1_path, "w") {|f| f.puts "changed"}
294     File.open(file2_path, "w") {|f| f.puts "changed"}
295     File.open(file3_path, "w") {|f| f.puts "changed"}
296     ctx.rm_f([file4_path, file5_path])
297     FileUtils.touch(file6_path)
298     FileUtils.touch(file7_path)
299     FileUtils.touch(file8_path)
300     ctx.add(file6_path)
301     ctx.add(file7_path)
302     ctx.add(file8_path)
303     ctx.cp(file1_path, file9_path)
304     ctx.cp(file2_path, file10_path)
305     ctx.rm(dir1_path)
306     ctx.mv(dir2_path, dir3_path)
307     ctx.cp(dir1_path, dir4_path)
309     commit_info = ctx.commit(@wc_path)
310     second_rev = commit_info.revision
312     editor = traverse(Svn::Delta::ChangedEditor, commit_info.revision, true)
313     assert_equal([file1_svn_path, file2_svn_path, file3_svn_path].sort,
314                  editor.updated_files)
315     assert_equal([file4_svn_path, file5_svn_path].sort,
316                  editor.deleted_files)
317     assert_equal([file6_svn_path, file7_svn_path, file8_svn_path].sort,
318                  editor.added_files)
319     assert_equal([].sort, editor.updated_dirs)
320     assert_equal([
321                    [file9_svn_path, file1_svn_path, first_rev],
322                    [file10_svn_path, file2_svn_path, first_rev],
323                  ].sort_by{|x| x[0]},
324                  editor.copied_files)
325     assert_equal([
326                    ["#{dir3_svn_path}/", "#{dir2_svn_path}/", first_rev],
327                    ["#{dir4_svn_path}/", "#{dir1_svn_path}/", first_rev],
328                  ].sort_by{|x| x[0]},
329                  editor.copied_dirs)
330     assert_equal(["#{dir1_svn_path}/", "#{dir2_svn_path}/"].sort,
331                  editor.deleted_dirs)
332     assert_equal([].sort, editor.added_dirs)
333   end
335   def test_change_prop
336     prop_name = "prop"
337     prop_value = "value"
339     dir = "dir"
340     dir_path = File.join(@wc_path, dir)
341     dir_svn_path = dir
343     log = "added 1 dirs\nanded 2 files"
344     ctx = make_context(log)
346     ctx.mkdir([dir_path])
348     file1 = "file1.txt"
349     file2 = "file2.txt"
350     file1_path = File.join(@wc_path, file1)
351     file2_path = File.join(dir_path, file2)
352     file1_svn_path = file1
353     file2_svn_path = [dir_svn_path, file2].join("/")
354     FileUtils.touch(file1_path)
355     FileUtils.touch(file2_path)
356     ctx.add(file1_path)
357     ctx.add(file2_path)
359     ctx.propset(prop_name, prop_value, dir_path)
361     commit_info = ctx.commit(@wc_path)
363     editor = traverse(Svn::Delta::ChangedDirsEditor, commit_info.revision)
364     assert_equal(["", dir_svn_path].collect{|path| "#{path}/"}.sort,
365                  editor.changed_dirs)
368     log = "prop changed"
369     ctx = make_context(log)
371     ctx.propdel(prop_name, dir_path)
373     commit_info = ctx.commit(@wc_path)
375     editor = traverse(Svn::Delta::ChangedDirsEditor, commit_info.revision)
376     assert_equal([dir_svn_path].collect{|path| "#{path}/"}.sort,
377                  editor.changed_dirs)
380     ctx.propset(prop_name, prop_value, file1_path)
382     commit_info = ctx.commit(@wc_path)
384     editor = traverse(Svn::Delta::ChangedDirsEditor, commit_info.revision)
385     assert_equal([""].collect{|path| "#{path}/"}.sort,
386                  editor.changed_dirs)
389     ctx.propdel(prop_name, file1_path)
390     ctx.propset(prop_name, prop_value, file2_path)
392     commit_info = ctx.commit(@wc_path)
394     editor = traverse(Svn::Delta::ChangedDirsEditor, commit_info.revision)
395     assert_equal(["", dir_svn_path].collect{|path| "#{path}/"}.sort,
396                  editor.changed_dirs)
397   end
399   def test_deep_copy
400     dir1 = "dir1"
401     dir2 = "dir2"
402     dir1_path = File.join(@wc_path, dir1)
403     dir2_path = File.join(dir1_path, dir2)
404     dir1_svn_path = dir1
405     dir2_svn_path = [dir1, dir2].join("/")
407     log = "added 2 dirs\nanded 3 files"
408     ctx = make_context(log)
410     ctx.mkdir([dir1_path, dir2_path])
412     file1 = "file1.txt"
413     file2 = "file2.txt"
414     file3 = "file3.txt"
415     file1_path = File.join(@wc_path, file1)
416     file2_path = File.join(dir1_path, file2)
417     file3_path = File.join(dir2_path, file3)
418     file1_svn_path = file1
419     file2_svn_path = [dir1_svn_path, file2].join("/")
420     file3_svn_path = [dir2_svn_path, file3].join("/")
421     FileUtils.touch(file1_path)
422     FileUtils.touch(file2_path)
423     FileUtils.touch(file3_path)
424     ctx.add(file1_path)
425     ctx.add(file2_path)
426     ctx.add(file3_path)
428     commit_info = ctx.commit(@wc_path)
429     first_rev = commit_info.revision
431     editor = traverse(Svn::Delta::ChangedEditor, commit_info.revision, true)
432     assert_equal([
433                    file1_svn_path, file2_svn_path,
434                    file3_svn_path,
435                  ].sort,
436                  editor.added_files)
437     assert_equal([].sort, editor.updated_files)
438     assert_equal([].sort, editor.deleted_files)
439     assert_equal([].sort, editor.updated_dirs)
440     assert_equal([].sort, editor.deleted_dirs)
441     assert_equal([
442                    "#{dir1_svn_path}/",
443                    "#{dir2_svn_path}/",
444                  ].sort,
445                  editor.added_dirs)
448     log = "copied top dir"
449     ctx = make_context(log)
451     dir3 = "dir3"
452     dir3_path = File.join(@wc_path, dir3)
453     dir3_svn_path = dir3
455     ctx.cp(dir1_path, dir3_path)
457     commit_info = ctx.commit(@wc_path)
458     second_rev = commit_info.revision
460     editor = traverse(Svn::Delta::ChangedEditor, commit_info.revision, true)
461     assert_equal([].sort, editor.updated_files)
462     assert_equal([].sort, editor.deleted_files)
463     assert_equal([].sort, editor.added_files)
464     assert_equal([].sort, editor.updated_dirs)
465     assert_equal([].sort, editor.copied_files)
466     assert_equal([
467                    ["#{dir3_svn_path}/", "#{dir1_svn_path}/", first_rev]
468                  ].sort_by{|x| x[0]},
469                  editor.copied_dirs)
470     assert_equal([].sort, editor.deleted_dirs)
471     assert_equal([].sort, editor.added_dirs)
472   end
474   private
475   def traverse(editor_class, rev, pass_root=false)
476     root = @fs.root
477     base_rev = rev - 1
478     base_root = @fs.root(base_rev)
479     if pass_root
480       editor = editor_class.new(root, base_root)
481     else
482       editor = editor_class.new
483     end
484     base_root.dir_delta("", "", root, "", editor)
485     editor
486   end