* subversion/bindings/swig/python/libsvn_swig_py/swigutil_py.c
[svn.git] / subversion / bindings / swig / ruby / test / test_repos.rb
blobdc3ec0ce9ad5b57427ad54e7cbd9261e4bfeafd6
1 require "tempfile"
3 require "my-assertions"
4 require "util"
6 require "svn/core"
7 require "svn/fs"
8 require "svn/repos"
9 require "svn/client"
11 class SvnReposTest < Test::Unit::TestCase
12   include SvnTestUtil
14   def setup
15     setup_basic
16   end
18   def teardown
19     teardown_basic
20   end
22   def test_version
23     assert_equal(Svn::Core.subr_version, Svn::Repos.version)
24   end
26   def test_path
27     assert_equal(@repos_path, @repos.path)
29     assert_equal(File.join(@repos_path, "db"), @repos.db_env)
31     assert_equal(File.join(@repos_path, "conf"), @repos.conf_dir)
32     assert_equal(File.join(@repos_path, "conf", "svnserve.conf"),
33                  @repos.svnserve_conf)
35     locks_dir = File.join(@repos_path, "locks")
36     assert_equal(locks_dir, @repos.lock_dir)
37     assert_equal(File.join(locks_dir, "db.lock"),
38                  @repos.db_lockfile)
39     assert_equal(File.join(locks_dir, "db-logs.lock"),
40                  @repos.db_logs_lockfile)
42     hooks_dir = File.join(@repos_path, "hooks")
43     assert_equal(hooks_dir, @repos.hook_dir)
45     assert_equal(File.join(hooks_dir, "start-commit"),
46                  @repos.start_commit_hook)
47     assert_equal(File.join(hooks_dir, "pre-commit"),
48                  @repos.pre_commit_hook)
49     assert_equal(File.join(hooks_dir, "post-commit"),
50                  @repos.post_commit_hook)
52     assert_equal(File.join(hooks_dir, "pre-revprop-change"),
53                  @repos.pre_revprop_change_hook)
54     assert_equal(File.join(hooks_dir, "post-revprop-change"),
55                  @repos.post_revprop_change_hook)
57     assert_equal(File.join(hooks_dir, "pre-lock"),
58                  @repos.pre_lock_hook)
59     assert_equal(File.join(hooks_dir, "post-lock"),
60                  @repos.post_lock_hook)
62     assert_equal(File.join(hooks_dir, "pre-unlock"),
63                  @repos.pre_unlock_hook)
64     assert_equal(File.join(hooks_dir, "post-unlock"),
65                  @repos.post_unlock_hook)
68     search_path = @repos_path
69     assert_equal(@repos_path, Svn::Repos.find_root_path(search_path))
70     search_path = "#{@repos_path}/XXX"
71     assert_equal(@repos_path, Svn::Repos.find_root_path(search_path))
73     search_path = "not-found"
74     assert_equal(nil, Svn::Repos.find_root_path(search_path))
75   end
77   def test_create
78     tmp_repos_path = File.join(@tmp_path, "repos")
79     fs_type = Svn::Fs::TYPE_FSFS
80     fs_config = {Svn::Fs::CONFIG_FS_TYPE => fs_type}
81     repos = nil
82     Svn::Repos.create(tmp_repos_path, {}, fs_config) do |repos|
83       assert(File.exist?(tmp_repos_path))
84       fs_type_path = File.join(repos.fs.path, Svn::Fs::CONFIG_FS_TYPE)
85       assert_equal(fs_type, File.open(fs_type_path) {|f| f.read.chop})
86       repos.fs.set_warning_func(&warning_func)
87     end
89     assert(repos.closed?)
90     assert_raises(Svn::Error::ReposAlreadyClose) do
91       repos.fs
92     end
94     Svn::Repos.delete(tmp_repos_path)
95     assert(!File.exist?(tmp_repos_path))
96   end
98   def test_logs
99     log1 = "sample log1"
100     log2 = "sample log2"
101     log3 = "sample log3"
102     file = "file"
103     src = "source"
104     props = {"myprop" => "value"}
105     path = File.join(@wc_path, file)
107     ctx = make_context(log1)
108     File.open(path, "w") {|f| f.print(src)}
109     ctx.add(path)
110     info1 = ctx.ci(@wc_path)
111     start_rev = info1.revision
113     ctx = make_context(log2)
114     File.open(path, "a") {|f| f.print(src)}
115     info2 = ctx.ci(@wc_path)
117     ctx = make_context(log3)
118     File.open(path, "a") {|f| f.print(src)}
119     props.each do |key, value|
120       ctx.prop_set(key, value, path)
121     end
122     info3 = ctx.ci(@wc_path)
123     end_rev = info3.revision
125     logs = @repos.logs(file, start_rev, end_rev, end_rev - start_rev + 1)
126     logs = logs.collect do |changed_paths, revision, author, date, message|
127       paths = {}
128       changed_paths.each do |key, changed_path|
129         paths[key] = changed_path.action
130       end
131       [paths, revision, author, date, message]
132     end
133     assert_equal([
134                    [
135                      {"/#{file}" => "A"},
136                      info1.revision,
137                      @author,
138                      info1.date,
139                      log1,
140                    ],
141                    [
142                      {"/#{file}" => "M"},
143                      info2.revision,
144                      @author,
145                      info2.date,
146                      log2,
147                    ],
148                    [
149                      {"/#{file}" => "M"},
150                      info3.revision,
151                      @author,
152                      info3.date,
153                      log3,
154                    ],
155                  ],
156                  logs)
157     revs = []
158     args = [file, start_rev, end_rev]
159     @repos.file_revs(*args) do |path, rev, rev_props, prop_diffs|
160       hashed_prop_diffs = {}
161       prop_diffs.each do |prop|
162         hashed_prop_diffs[prop.name] = prop.value
163       end
164       revs << [path, rev, hashed_prop_diffs]
165     end
166     assert_equal([
167                    ["/#{file}", info1.revision, {}],
168                    ["/#{file}", info2.revision, {}],
169                    ["/#{file}", info3.revision, props],
170                  ],
171                  revs)
173     revs = []
174     @repos.file_revs2(*args) do |path, rev, rev_props, prop_diffs|
175       revs << [path, rev, prop_diffs]
176     end
177     assert_equal([
178                    ["/#{file}", info1.revision, {}],
179                    ["/#{file}", info2.revision, {}],
180                    ["/#{file}", info3.revision, props],
181                  ],
182                  revs)
185     rev, date, author = @repos.fs.root.committed_info("/")
186     assert_equal(info3.revision, rev)
187     assert_equal(info3.date, date)
188     assert_equal(info3.author, author)
189   end
191   def test_hotcopy
192     log = "sample log"
193     file = "hello.txt"
194     path = File.join(@wc_path, file)
195     FileUtils.touch(path)
197     ctx = make_context(log)
198     ctx.add(path)
199     commit_info = ctx.commit(@wc_path)
200     rev = commit_info.revision
202     assert_equal(log, ctx.log_message(path, rev))
204     dest_path = File.join(@tmp_path, "dest")
205     backup_path = File.join(@tmp_path, "back")
206     config = {}
207     fs_config = {}
209     repos = Svn::Repos.create(dest_path, config, fs_config)
210     repos.fs.set_warning_func(&warning_func)
212     FileUtils.mv(@repos.path, backup_path)
213     FileUtils.mv(repos.path, @repos.path)
215     assert_raises(Svn::Error::FsNoSuchRevision) do
216       assert_equal(log, ctx.log_message(path, rev))
217     end
219     FileUtils.rm_r(@repos.path)
220     Svn::Repos.hotcopy(backup_path, @repos.path)
221     assert_equal(log, ctx.log_message(path, rev))
222   end
224   def assert_transaction
225     log = "sample log"
226     ctx = make_context(log)
227     ctx.checkout(@repos_uri, @wc_path)
228     ctx.mkdir(["#{@wc_path}/new_dir"])
230     prev_rev = @repos.youngest_rev
231     past_date = Time.now
232     args = {
233       :author => @author,
234       :log => log,
235       :revision => prev_rev,
236     }
237     callback = Proc.new do |txn|
238       txn.abort
239     end
240     yield(:commit, @repos, args, callback)
241     assert_equal(prev_rev, @repos.youngest_rev)
242     assert_equal(prev_rev, @repos.dated_revision(past_date))
244     prev_rev = @repos.youngest_rev
245     @repos.transaction_for_commit(@author, log) do |txn|
246     end
247     assert_equal(prev_rev + 1, @repos.youngest_rev)
248     assert_equal(prev_rev, @repos.dated_revision(past_date))
249     assert_equal(prev_rev + 1, @repos.dated_revision(Time.now))
251     prev_rev = @repos.youngest_rev
252     args = {
253       :author => @author,
254       :revision => prev_rev,
255     }
256     callback = Proc.new do |txn|
257     end
258     yield(:update, @repos, args, callback)
259     assert_equal(prev_rev, @repos.youngest_rev)
260   end
262   def test_transaction
263     assert_transaction do |type, repos, args, callback|
264       case type
265       when :commit
266         repos.transaction_for_commit(args[:author], args[:log], &callback)
267       when :update
268         repos.transaction_for_update(args[:author], &callback)
269       end
270     end
271   end
273   def test_transaction_with_revision
274     assert_transaction do |type, repos, args, callback|
275       case type
276       when :commit
277         repos.transaction_for_commit(args[:author], args[:log],
278                                      args[:revision], &callback)
279       when :update
280         repos.transaction_for_update(args[:author], args[:revision], &callback)
281       end
282     end
283   end
285   def test_transaction2
286     assert_transaction do |type, repos, args, callback|
287       case type
288       when :commit
289         props = {
290           Svn::Core::PROP_REVISION_AUTHOR => args[:author],
291           Svn::Core::PROP_REVISION_LOG => args[:log],
292         }
293         repos.transaction_for_commit(props, &callback)
294       when :update
295         repos.transaction_for_update(args[:author], &callback)
296       end
297     end
298   end
300   def test_transaction2_with_revision
301     assert_transaction do |type, repos, args, callback|
302       case type
303       when :commit
304         props = {
305           Svn::Core::PROP_REVISION_AUTHOR => args[:author],
306           Svn::Core::PROP_REVISION_LOG => args[:log],
307         }
308         repos.transaction_for_commit(props,
309                                      args[:revision],
310                                      &callback)
311       when :update
312         repos.transaction_for_update(args[:author],
313                                      args[:revision],
314                                      &callback)
315       end
316     end
317   end
319   def test_trace_node_locations
320     file1 = "file1"
321     file2 = "file2"
322     file3 = "file3"
323     path1 = File.join(@wc_path, file1)
324     path2 = File.join(@wc_path, file2)
325     path3 = File.join(@wc_path, file3)
326     log = "sample log"
327     ctx = make_context(log)
329     FileUtils.touch(path1)
330     ctx.add(path1)
331     rev1 = ctx.ci(@wc_path).revision
333     ctx.mv(path1, path2)
334     rev2 = ctx.ci(@wc_path).revision
336     ctx.cp(path2, path3)
337     rev3 = ctx.ci(@wc_path).revision
339     assert_equal({
340                    rev1 => "/#{file1}",
341                    rev2 => "/#{file2}",
342                    rev3 => "/#{file2}",
343                  },
344                  @repos.fs.trace_node_locations("/#{file2}",
345                                                 [rev1, rev2, rev3]))
346   end
348   def assert_report
349     file = "file"
350     file2 = "file2"
351     fs_base = "base"
352     path = File.join(@wc_path, file)
353     path2 = File.join(@wc_path, file2)
354     source = "sample source"
355     log = "sample log"
356     ctx = make_context(log)
358     File.open(path, "w") {|f| f.print(source)}
359     ctx.add(path)
360     rev = ctx.ci(@wc_path).revision
362     assert_equal(Svn::Core::NODE_FILE, @repos.fs.root.stat(file).kind)
364     editor = TestEditor.new
365     args = {
366       :revision => rev,
367       :user_name => @author,
368       :fs_base => fs_base,
369       :target => "/",
370       :target_path => nil,
371       :editor => editor,
372       :text_deltas => true,
373       :recurse => true,
374       :ignore_ancestry => false,
375     }
376     callback = Proc.new do |baton|
377       baton.link_path(file, file2, rev)
378       baton.delete_path(file)
379     end
380     yield(@repos, args, callback)
381     assert_equal([
382                    :set_target_revision,
383                    :open_root,
384                    :close_directory,
385                    :close_edit,
386                  ],
387                  editor.sequence.collect{|meth, *args| meth})
388   end
390   def test_report
391     assert_report do |repos, args, callback|
392       @repos.report(args[:revision], args[:user_name], args[:fs_base],
393                     args[:target], args[:target_path], args[:editor],
394                     args[:text_deltas], args[:recurse], args[:ignore_ancestry],
395                     &callback)
396     end
397   end
399   def test_report2
400     assert_report do |repos, args, callback|
401       if args[:recurse]
402         depth = Svn::Core::DEPTH_INFINITY
403       else
404         depth = Svn::Core::DEPTH_FILES
405       end
406       @repos.report2(args[:revision], args[:fs_base], args[:target],
407                      args[:target_path], args[:editor], args[:text_deltas],
408                      args[:ignore_ancestry], depth, &callback)
409     end
410   end
412   def assert_commit_editor
413     trunk = "trunk"
414     tags = "tags"
415     tags_sub = "sub"
416     file = "file"
417     source = "sample source"
418     user = "user"
419     log_message = "log"
420     trunk_dir_path = File.join(@wc_path, trunk)
421     tags_dir_path = File.join(@wc_path, tags)
422     tags_sub_dir_path = File.join(tags_dir_path, tags_sub)
423     trunk_path = File.join(trunk_dir_path, file)
424     tags_path = File.join(tags_dir_path, file)
425     tags_sub_path = File.join(tags_sub_dir_path, file)
426     trunk_repos_uri = "#{@repos_uri}/#{trunk}"
427     rev1 = @repos.youngest_rev
429     commit_callback_result = {}
430     args = {
431       :repos_url => @repos_uri,
432       :base_path => "/",
433       :user => user,
434       :log_message => log_message,
435      }
437     editor = yield(@repos, commit_callback_result, args)
438     root_baton = editor.open_root(rev1)
439     dir_baton = editor.add_directory(trunk, root_baton, nil, rev1)
440     file_baton = editor.add_file("#{trunk}/#{file}", dir_baton, nil, -1)
441     ret = editor.apply_textdelta(file_baton, nil)
442     ret.send(source)
443     editor.close_edit
445     assert_equal(rev1 + 1, @repos.youngest_rev)
446     assert_equal({
447                    :revision => @repos.youngest_rev,
448                    :date => @repos.prop(Svn::Core::PROP_REVISION_DATE),
449                    :author => user,
450                  },
451                  commit_callback_result)
452     rev2 = @repos.youngest_rev
454     ctx = make_context("")
455     ctx.up(@wc_path)
456     assert_equal(source, File.open(trunk_path) {|f| f.read})
458     commit_callback_result = {}
459     editor = yield(@repos, commit_callback_result, args)
460     root_baton = editor.open_root(rev2)
461     dir_baton = editor.add_directory(tags, root_baton, nil, rev2)
462     subdir_baton = editor.add_directory("#{tags}/#{tags_sub}",
463                                         dir_baton,
464                                         trunk_repos_uri,
465                                         rev2)
466     editor.close_edit
468     assert_equal(rev2 + 1, @repos.youngest_rev)
469     assert_equal({
470                    :revision => @repos.youngest_rev,
471                    :date => @repos.prop(Svn::Core::PROP_REVISION_DATE),
472                    :author => user,
473                  },
474                  commit_callback_result)
475     rev3 = @repos.youngest_rev
477     ctx.up(@wc_path)
478     assert_equal([
479                    ["/#{tags}/#{tags_sub}/#{file}", rev3],
480                    ["/#{trunk}/#{file}", rev2],
481                  ],
482                  @repos.fs.history("#{tags}/#{tags_sub}/#{file}",
483                                    rev1, rev3, rev2))
485     commit_callback_result = {}
486     editor = yield(@repos, commit_callback_result, args)
487     root_baton = editor.open_root(rev3)
488     dir_baton = editor.delete_entry(tags, rev3, root_baton)
489     editor.close_edit
491     assert_equal({
492                    :revision => @repos.youngest_rev,
493                    :date => @repos.prop(Svn::Core::PROP_REVISION_DATE),
494                    :author => user,
495                  },
496                  commit_callback_result)
498     ctx.up(@wc_path)
499     assert(!File.exist?(tags_path))
500   end
502   def test_commit_editor
503     assert_commit_editor do |receiver, commit_callback_result, args|
504       commit_callback = Proc.new do |revision, date, author|
505         commit_callback_result[:revision] = revision
506         commit_callback_result[:date] = date
507         commit_callback_result[:author] = author
508       end
509       receiver.commit_editor(args[:repos_url], args[:base_path], args[:txn],
510                              args[:user], args[:log_message], commit_callback)
511     end
512   end
514   def test_commit_editor2
515     assert_commit_editor do |receiver, commit_callback_result, args|
516       commit_callback = Proc.new do |info|
517         commit_callback_result[:revision] = info.revision
518         commit_callback_result[:date] = info.date
519         commit_callback_result[:author] = info.author
520       end
521       receiver.commit_editor2(args[:repos_url], args[:base_path], args[:txn],
522                               args[:user], args[:log_message], commit_callback)
523     end
524   end
526   def test_commit_editor3
527     assert_commit_editor do |receiver, commit_callback_result, args|
528       props = {
529         Svn::Core::PROP_REVISION_AUTHOR => args[:user],
530         Svn::Core::PROP_REVISION_LOG => args[:log_message],
531       }
532       commit_callback = Proc.new do |info|
533         commit_callback_result[:revision] = info.revision
534         commit_callback_result[:date] = info.date
535         commit_callback_result[:author] = info.author
536       end
537       receiver.commit_editor3(args[:repos_url], args[:base_path], args[:txn],
538                               props, commit_callback)
539     end
540   end
542   def test_prop
543     file = "file"
544     path = File.join(@wc_path, file)
545     source = "sample source"
546     log = "sample log"
547     ctx = make_context(log)
549     File.open(path, "w") {|f| f.print(source)}
550     ctx.add(path)
551     ctx.ci(@wc_path)
553     assert_equal([
554                    Svn::Core::PROP_REVISION_AUTHOR,
555                    Svn::Core::PROP_REVISION_LOG,
556                    Svn::Core::PROP_REVISION_DATE,
557                  ].sort,
558                  @repos.proplist.keys.sort)
559     assert_equal(log, @repos.prop(Svn::Core::PROP_REVISION_LOG))
560     @repos.set_prop(@author, Svn::Core::PROP_REVISION_LOG, nil)
561     assert_nil(@repos.prop(Svn::Core::PROP_REVISION_LOG))
562     assert_equal([
563                    Svn::Core::PROP_REVISION_AUTHOR,
564                    Svn::Core::PROP_REVISION_DATE,
565                  ].sort,
566                  @repos.proplist.keys.sort)
568     assert_raises(Svn::Error::ReposHookFailure) do
569       @repos.set_prop(@author, Svn::Core::PROP_REVISION_DATE, nil)
570     end
571     assert_not_nil(@repos.prop(Svn::Core::PROP_REVISION_DATE))
573     assert_nothing_raised do
574       @repos.set_prop(@author, Svn::Core::PROP_REVISION_DATE, nil, nil, nil,
575                       false)
576     end
577     assert_nil(@repos.prop(Svn::Core::PROP_REVISION_DATE))
578     assert_equal([
579                    Svn::Core::PROP_REVISION_AUTHOR,
580                  ].sort,
581                  @repos.proplist.keys.sort)
582   end
584   def test_dump
585     file = "file"
586     path = File.join(@wc_path, file)
587     source = "sample source"
588     log = "sample log"
589     ctx = make_context(log)
591     File.open(path, "w") {|f| f.print(source)}
592     ctx.add(path)
593     rev1 = ctx.ci(@wc_path).revision
595     File.open(path, "a") {|f| f.print(source)}
596     rev2 = ctx.ci(@wc_path).revision
598     assert_nothing_raised do
599       @repos.dump_fs(nil, nil, rev1, rev2)
600     end
602     dump = StringIO.new("")
603     feedback = StringIO.new("")
604     @repos.dump_fs(dump, feedback, rev1, rev2)
606     dump_unless_feedback = StringIO.new("")
607     @repos.dump_fs(dump_unless_feedback, nil, rev1, rev2)
609     dump.rewind
610     dump_unless_feedback.rewind
611     assert_equal(dump.read, dump_unless_feedback.read)
612   end
614   def test_load
615     file = "file"
616     path = File.join(@wc_path, file)
617     source = "sample source"
618     log = "sample log"
619     ctx = make_context(log)
621     File.open(path, "w") {|f| f.print(source)}
622     ctx.add(path)
623     rev1 = ctx.ci(@wc_path).revision
625     File.open(path, "a") {|f| f.print(source)}
626     rev2 = ctx.ci(@wc_path).revision
628     dump = StringIO.new("")
629     @repos.dump_fs(dump, nil, rev1, rev2)
631     dest_path = File.join(@tmp_path, "dest")
632     repos = Svn::Repos.create(dest_path)
633     assert_raises(NoMethodError) do
634       repos.load_fs(nil)
635     end
637     [
638      [StringIO.new(""), Svn::Repos::LOAD_UUID_DEFAULT, "/"],
639      [StringIO.new("")],
640      [],
641     ].each_with_index do |args, i|
642       dest_path = File.join(@tmp_path, "dest#{i}")
643       repos = Svn::Repos.create(dest_path)
644       assert_not_equal(@repos.fs.root.committed_info("/"),
645                        repos.fs.root.committed_info("/"))
646       dump.rewind
647       repos.load_fs(dump, *args)
648       assert_equal(@repos.fs.root.committed_info("/"),
649                    repos.fs.root.committed_info("/"))
650     end
651   end
653   def test_node_editor
654     file = "file"
655     dir1 = "dir1"
656     dir2 = "dir2"
657     dir3 = "dir3"
658     dir1_path = File.join(@wc_path, dir1)
659     dir2_path = File.join(dir1_path, dir2)
660     dir3_path = File.join(dir2_path, dir3)
661     path = File.join(dir3_path, file)
662     source = "sample source"
663     log = "sample log"
665     ctx = make_context(log)
666     FileUtils.mkdir_p(dir3_path)
667     FileUtils.touch(path)
668     ctx.add(dir1_path)
669     rev1 = ctx.ci(@wc_path).revision
671     ctx.rm(dir3_path)
672     rev2 = ctx.ci(@wc_path).revision
674     rev1_root = @repos.fs.root(rev1)
675     rev2_root = @repos.fs.root(rev2)
676     editor = @repos.node_editor(rev1_root, rev2_root)
677     rev2_root.replay(editor)
679     tree = editor.baton.node
681     assert_equal("", tree.name)
682     assert_equal(dir1, tree.child.name)
683     assert_equal(dir2, tree.child.child.name)
684   end
686   def test_lock
687     file = "file"
688     log = "sample log"
689     path = File.join(@wc_path, file)
690     path_in_repos = "/#{file}"
691     ctx = make_context(log)
693     FileUtils.touch(path)
694     ctx.add(path)
695     rev = ctx.ci(@wc_path).revision
697     access = Svn::Fs::Access.new(@author)
698     @repos.fs.access = access
699     lock = @repos.lock(file)
700     locks = @repos.get_locks(file)
701     assert_equal([path_in_repos], locks.keys)
702     assert_equal(lock.token, locks[path_in_repos].token)
703     @repos.unlock(file, lock.token)
704     assert_equal({}, @repos.get_locks(file))
705   end
707   def test_authz
708     name = "REPOS"
709     conf_path = File.join(@tmp_path, "authz_file")
710     File.open(conf_path, "w") do |f|
711       f.print(<<-EOF)
713 #{@author} = r
715     end
717     authz = Svn::Repos::Authz.read(conf_path)
718     assert(authz.can_access?(name, "/", @author, Svn::Repos::AUTHZ_READ))
719     assert(!authz.can_access?(name, "/", @author, Svn::Repos::AUTHZ_WRITE))
720     assert(!authz.can_access?(name, "/", "FOO", Svn::Repos::AUTHZ_READ))
721   end
723   def test_recover
724     started = false
725     Svn::Repos.recover(@repos_path, false) do
726       started = true
727     end
728     assert(started)
729   end
731   def test_mergeinfo
732     log = "sample log"
733     file = "sample.txt"
734     src = "sample\n"
735     trunk = File.join(@wc_path, "trunk")
736     branch = File.join(@wc_path, "branch")
737     trunk_path = File.join(trunk, file)
738     branch_path = File.join(branch, file)
739     trunk_path_in_repos = "/trunk/#{file}"
740     branch_path_in_repos = "/branch/#{file}"
742     ctx = make_context(log)
743     ctx.mkdir(trunk, branch)
744     File.open(trunk_path, "w") {}
745     File.open(branch_path, "w") {}
746     ctx.add(trunk_path)
747     ctx.add(branch_path)
748     original_rev = ctx.commit(@wc_path).revision
750     File.open(branch_path, "w") {|f| f.print(src)}
751     merged_rev = ctx.commit(@wc_path).revision
753     ctx.merge(branch, original_rev, branch, merged_rev, trunk)
754     ctx.commit(@wc_path)
756     mergeinfo = Svn::Core::MergeInfo.parse("#{branch_path_in_repos}:#{merged_rev}")
757     assert_equal({trunk_path_in_repos => mergeinfo},
758                  @repos.mergeinfo([trunk_path_in_repos]))
759     assert_equal(mergeinfo, @repos.mergeinfo(trunk_path_in_repos))
760   end
762   private
763   def warning_func
764     Proc.new do |err|
765       STDERR.puts err if $DEBUG
766     end
767   end
769   class TestEditor < Svn::Delta::BaseEditor
770     attr_reader :sequence
771     def initialize
772       @sequence = []
773     end
775     def set_target_revision(target_revision)
776       @sequence << [:set_target_revision, target_revision]
777     end
779     def open_root(base_revision)
780       @sequence << [:open_root, base_revision]
781     end
783     def delete_entry(path, revision, parent_baton)
784       @sequence << [:delete_entry, path, revision, parent_baton]
785     end
787     def add_directory(path, parent_baton,
788                       copyfrom_path, copyfrom_revision)
789       @sequence << [:add_directory, path, parent_baton,
790         copyfrom_path, copyfrom_revision]
791     end
793     def open_directory(path, parent_baton, base_revision)
794       @sequence << [:open_directory, path, parent_baton, base_revision]
795     end
797     def change_dir_prop(dir_baton, name, value)
798       @sequence << [:change_dir_prop, dir_baton, name, value]
799     end
801     def close_directory(dir_baton)
802       @sequence << [:close_directory, dir_baton]
803     end
805     def absent_directory(path, parent_baton)
806       @sequence << [:absent_directory, path, parent_baton]
807     end
809     def add_file(path, parent_baton,
810                  copyfrom_path, copyfrom_revision)
811       @sequence << [:add_file, path, parent_baton,
812         copyfrom_path, copyfrom_revision]
813     end
815     def open_file(path, parent_baton, base_revision)
816       @sequence << [:open_file, path, parent_baton, base_revision]
817     end
819     # return nil or object which has `call' method.
820     def apply_textdelta(file_baton, base_checksum)
821       @sequence << [:apply_textdelta, file_baton, base_checksum]
822       nil
823     end
825     def change_file_prop(file_baton, name, value)
826       @sequence << [:change_file_prop, file_baton, name, value]
827     end
829     def close_file(file_baton, text_checksum)
830       @sequence << [:close_file, file_baton, text_checksum]
831     end
833     def absent_file(path, parent_baton)
834       @sequence << [:absent_file, path, parent_baton]
835     end
837     def close_edit(baton)
838       @sequence << [:close_edit, baton]
839     end
841     def abort_edit(baton)
842       @sequence << [:abort_edit, baton]
843     end
844   end