You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@bloodhound.apache.org by gj...@apache.org on 2012/10/16 17:55:11 UTC

svn commit: r1398858 [33/33] - in /incubator/bloodhound/vendor/trac/current: ./ contrib/ doc/ doc/api/ doc/utils/ sample-plugins/ sample-plugins/permissions/ sample-plugins/workflow/ trac/ trac/admin/ trac/admin/templates/ trac/admin/tests/ trac/db/ tr...

Added: incubator/bloodhound/vendor/trac/current/tracopt/versioncontrol/svn/tests/svn_fs.py
URL: http://svn.apache.org/viewvc/incubator/bloodhound/vendor/trac/current/tracopt/versioncontrol/svn/tests/svn_fs.py?rev=1398858&view=auto
==============================================================================
--- incubator/bloodhound/vendor/trac/current/tracopt/versioncontrol/svn/tests/svn_fs.py (added)
+++ incubator/bloodhound/vendor/trac/current/tracopt/versioncontrol/svn/tests/svn_fs.py Tue Oct 16 15:55:00 2012
@@ -0,0 +1,916 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C)2005-2009 Edgewall Software
+# Copyright (C) 2005 Christopher Lenz <cm...@gmx.de>
+# All rights reserved.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution. The terms
+# are also available at http://trac.edgewall.org/wiki/TracLicense.
+#
+# This software consists of voluntary contributions made by many
+# individuals. For the exact contribution history, see the revision
+# history and logs, available at http://trac.edgewall.org/log/.
+#
+# Author: Christopher Lenz <cm...@gmx.de>
+
+from datetime import datetime
+import new
+import os.path
+import stat
+import shutil
+import tempfile
+import unittest
+
+from StringIO import StringIO
+
+try:
+    from svn import core, repos
+    has_svn = True
+except ImportError:
+    has_svn = False
+
+from trac.test import EnvironmentStub, TestSetup
+from trac.core import TracError
+from trac.resource import Resource, resource_exists
+from trac.util.concurrency import get_thread_id
+from trac.util.datefmt import utc
+from trac.versioncontrol import DbRepositoryProvider, Changeset, Node, \
+                                NoSuchChangeset
+from tracopt.versioncontrol.svn import svn_fs
+
+REPOS_PATH = os.path.join(tempfile.gettempdir(), 'trac-svnrepos')
+REPOS_NAME = 'repo'
+
+HEAD = 22
+TETE = 21
+
+
+class SubversionRepositoryTestSetup(TestSetup):
+
+    def setUp(self):
+        dumpfile = open(os.path.join(os.path.split(__file__)[0],
+                                     'svnrepos.dump'))
+
+        svn_fs._import_svn()
+        core.apr_initialize()
+        pool = core.svn_pool_create(None)
+        dumpstream = None
+        try:
+            if os.path.exists(REPOS_PATH):
+                print 'trouble ahead with db/rep-cache.db... see #8278'
+            r = repos.svn_repos_create(REPOS_PATH, '', '', None, None, pool)
+            if hasattr(repos, 'svn_repos_load_fs2'):
+                repos.svn_repos_load_fs2(r, dumpfile, StringIO(),
+                                        repos.svn_repos_load_uuid_default, '',
+                                        0, 0, None, pool)
+            else:
+                dumpstream = core.svn_stream_from_aprfile(dumpfile, pool)
+                repos.svn_repos_load_fs(r, dumpstream, None,
+                                        repos.svn_repos_load_uuid_default, '',
+                                        None, None, pool)
+        finally:
+            if dumpstream:
+                core.svn_stream_close(dumpstream)
+            core.svn_pool_destroy(pool)
+            core.apr_terminate()
+
+    def tearDown(self):
+        repos.svn_repos_delete(REPOS_PATH)
+
+
+# -- Re-usable test mixins
+
+class NormalTests(object):
+
+    def test_resource_exists(self):
+        repos = Resource('repository', REPOS_NAME)
+        self.assertEqual(True, resource_exists(self.env, repos))
+        self.assertEqual(False, resource_exists(self.env, repos(id='xxx')))
+        node = repos.child('source', u'tête')
+        self.assertEqual(True, resource_exists(self.env, node))
+        self.assertEqual(False, resource_exists(self.env, node(id='xxx')))
+        cset = repos.child('changeset', HEAD)
+        self.assertEqual(True, resource_exists(self.env, cset))
+        self.assertEqual(False, resource_exists(self.env, cset(id=123456)))
+                         
+    def test_repos_normalize_path(self):
+        self.assertEqual('/', self.repos.normalize_path('/'))
+        self.assertEqual('/', self.repos.normalize_path(''))
+        self.assertEqual('/', self.repos.normalize_path(None))
+        self.assertEqual(u'tête', self.repos.normalize_path(u'tête'))
+        self.assertEqual(u'tête', self.repos.normalize_path(u'/tête'))
+        self.assertEqual(u'tête', self.repos.normalize_path(u'tête/'))
+        self.assertEqual(u'tête', self.repos.normalize_path(u'/tête/'))
+
+    def test_repos_normalize_rev(self):
+        self.assertEqual(HEAD, self.repos.normalize_rev('latest'))
+        self.assertEqual(HEAD, self.repos.normalize_rev('head'))
+        self.assertEqual(HEAD, self.repos.normalize_rev(''))
+        self.assertRaises(NoSuchChangeset,
+                          self.repos.normalize_rev, 'something else')
+        self.assertEqual(HEAD, self.repos.normalize_rev(None))
+        self.assertEqual(11, self.repos.normalize_rev('11'))
+        self.assertEqual(11, self.repos.normalize_rev(11))
+
+    def test_rev_navigation(self):
+        self.assertEqual(1, self.repos.oldest_rev)
+        self.assertEqual(None, self.repos.previous_rev(0))
+        self.assertEqual(None, self.repos.previous_rev(1))
+        self.assertEqual(HEAD, self.repos.youngest_rev)
+        self.assertEqual(6, self.repos.next_rev(5))
+        self.assertEqual(7, self.repos.next_rev(6))
+        # ...
+        self.assertEqual(None, self.repos.next_rev(HEAD))
+        self.assertRaises(NoSuchChangeset, self.repos.normalize_rev, HEAD + 1)
+
+    def test_rev_path_navigation(self):
+        self.assertEqual(1, self.repos.oldest_rev)
+        self.assertEqual(None, self.repos.previous_rev(0, u'tête'))
+        self.assertEqual(None, self.repos.previous_rev(1, u'tête'))
+        self.assertEqual(HEAD, self.repos.youngest_rev)
+        self.assertEqual(6, self.repos.next_rev(5, u'tête'))
+        self.assertEqual(13, self.repos.next_rev(6, u'tête'))
+        # ...
+        self.assertEqual(None, self.repos.next_rev(HEAD, u'tête'))
+        # test accentuated characters
+        self.assertEqual(None,
+                         self.repos.previous_rev(17, u'tête/R\xe9sum\xe9.txt'))
+        self.assertEqual(17, self.repos.next_rev(16, u'tête/R\xe9sum\xe9.txt'))
+
+    def test_has_node(self):
+        self.assertEqual(False, self.repos.has_node(u'/tête/dir1', 3))
+        self.assertEqual(True, self.repos.has_node(u'/tête/dir1', 4))
+        self.assertEqual(True, self.repos.has_node(u'/tête/dir1'))
+        
+    def test_get_node(self):
+        node = self.repos.get_node(u'/tête')
+        self.assertEqual(u'tête', node.name)
+        self.assertEqual(u'/tête', node.path)
+        self.assertEqual(Node.DIRECTORY, node.kind)
+        self.assertEqual(HEAD, node.rev)
+        self.assertEqual(TETE, node.created_rev)
+        self.assertEqual(datetime(2007, 4, 30, 17, 45, 26, 234375, utc),
+                         node.last_modified)
+        node = self.repos.get_node(u'/tête/README.txt')
+        self.assertEqual('README.txt', node.name)
+        self.assertEqual(u'/tête/README.txt', node.path)
+        self.assertEqual(Node.FILE, node.kind)
+        self.assertEqual(HEAD, node.rev)
+        self.assertEqual(3, node.created_rev)
+        self.assertEqual(datetime(2005, 4, 1, 13, 24, 58, 234643, utc),
+                         node.last_modified)
+
+    def test_get_node_specific_rev(self):
+        node = self.repos.get_node(u'/tête', 1)
+        self.assertEqual(u'tête', node.name)
+        self.assertEqual(u'/tête', node.path)
+        self.assertEqual(Node.DIRECTORY, node.kind)
+        self.assertEqual(1, node.rev)
+        self.assertEqual(datetime(2005, 4, 1, 10, 0, 52, 353248, utc),
+                         node.last_modified)
+        node = self.repos.get_node(u'/tête/README.txt', 2)
+        self.assertEqual('README.txt', node.name)
+        self.assertEqual(u'/tête/README.txt', node.path)
+        self.assertEqual(Node.FILE, node.kind)
+        self.assertEqual(2, node.rev)
+        self.assertEqual(datetime(2005, 4, 1, 13, 12, 18, 216267, utc),
+                         node.last_modified)
+
+    def test_get_dir_entries(self):
+        node = self.repos.get_node(u'/tête')
+        entries = node.get_entries()
+        self.assertEqual('dir1', entries.next().name)
+        self.assertEqual('mpp_proc', entries.next().name)
+        self.assertEqual('v2', entries.next().name)
+        self.assertEqual('README3.txt', entries.next().name)
+        self.assertEqual(u'R\xe9sum\xe9.txt', entries.next().name)
+        self.assertEqual('README.txt', entries.next().name)
+        self.assertRaises(StopIteration, entries.next)
+
+    def test_get_file_entries(self):
+        node = self.repos.get_node(u'/tête/README.txt')
+        entries = node.get_entries()
+        self.assertRaises(StopIteration, entries.next)
+
+    def test_get_dir_content(self):
+        node = self.repos.get_node(u'/tête')
+        self.assertEqual(None, node.content_length)
+        self.assertEqual(None, node.content_type)
+        self.assertEqual(None, node.get_content())
+
+    def test_get_file_content(self):
+        node = self.repos.get_node(u'/tête/README.txt')
+        self.assertEqual(8, node.content_length)
+        self.assertEqual('text/plain', node.content_type)
+        self.assertEqual('A test.\n', node.get_content().read())
+
+    def test_get_dir_properties(self):
+        f = self.repos.get_node(u'/tête')
+        props = f.get_properties()
+        self.assertEqual(1, len(props))
+
+    def test_get_file_properties(self):
+        f = self.repos.get_node(u'/tête/README.txt')
+        props = f.get_properties()
+        self.assertEqual('native', props['svn:eol-style'])
+        self.assertEqual('text/plain', props['svn:mime-type'])
+
+    def test_created_path_rev(self):
+        node = self.repos.get_node(u'/tête/README3.txt', 15)
+        self.assertEqual(15, node.rev)
+        self.assertEqual(u'/tête/README3.txt', node.path)
+        self.assertEqual(14, node.created_rev)
+        self.assertEqual(u'tête/README3.txt', node.created_path)
+
+    def test_created_path_rev_parent_copy(self):
+        node = self.repos.get_node('/tags/v1/README.txt', 15)
+        self.assertEqual(15, node.rev)
+        self.assertEqual('/tags/v1/README.txt', node.path)
+        self.assertEqual(3, node.created_rev)
+        self.assertEqual(u'tête/README.txt', node.created_path)
+
+    # Revision Log / node history 
+
+    def test_get_node_history(self):
+        node = self.repos.get_node(u'/tête/README3.txt')
+        history = node.get_history()
+        self.assertEqual((u'tête/README3.txt', 14, 'copy'), history.next())
+        self.assertEqual((u'tête/README2.txt', 6, 'copy'), history.next())
+        self.assertEqual((u'tête/README.txt', 3, 'edit'), history.next())
+        self.assertEqual((u'tête/README.txt', 2, 'add'), history.next())
+        self.assertRaises(StopIteration, history.next)
+
+    def test_get_node_history_limit(self):
+        node = self.repos.get_node(u'/tête/README3.txt')
+        history = node.get_history(2)
+        self.assertEqual((u'tête/README3.txt', 14, 'copy'), history.next())
+        self.assertEqual((u'tête/README2.txt', 6, 'copy'), history.next())
+        self.assertRaises(StopIteration, history.next)
+
+    def test_get_node_history_follow_copy(self):
+        node = self.repos.get_node('/tags/v1/README.txt')
+        history = node.get_history()
+        self.assertEqual(('tags/v1/README.txt', 7, 'copy'), history.next())
+        self.assertEqual((u'tête/README.txt', 3, 'edit'), history.next())
+        self.assertEqual((u'tête/README.txt', 2, 'add'), history.next())
+        self.assertRaises(StopIteration, history.next)
+
+    def test_get_copy_ancestry(self):
+        node = self.repos.get_node('/tags/v1/README.txt')
+        ancestry = node.get_copy_ancestry()
+        self.assertEqual([(u'tête/README.txt', 6)], ancestry)
+        for path, rev in ancestry:
+            self.repos.get_node(path, rev) # shouldn't raise NoSuchNode
+
+        node = self.repos.get_node(u'/tête/README3.txt')
+        ancestry = node.get_copy_ancestry()
+        self.assertEqual([(u'tête/README2.txt', 13), 
+                          (u'tête/README.txt', 3)], ancestry)
+        for path, rev in ancestry:
+            self.repos.get_node(path, rev) # shouldn't raise NoSuchNode
+
+        node = self.repos.get_node('/branches/v1x')
+        ancestry = node.get_copy_ancestry()
+        self.assertEqual([(u'tags/v1.1', 11),
+                          (u'branches/v1x', 9), 
+                          (u'tags/v1', 7), 
+                          (u'tête', 6)], ancestry)
+        for path, rev in ancestry:
+            self.repos.get_node(path, rev) # shouldn't raise NoSuchNode
+
+    def test_get_copy_ancestry_for_move(self):
+        node = self.repos.get_node(u'/tête/dir1/dir2', 5)
+        ancestry = node.get_copy_ancestry()
+        self.assertEqual([(u'tête/dir2', 4)], ancestry)
+        for path, rev in ancestry:
+            self.repos.get_node(path, rev) # shouldn't raise NoSuchNode
+
+    def test_get_branch_origin(self):
+        node = self.repos.get_node('/tags/v1/README.txt')
+        self.assertEqual(7, node.get_branch_origin())
+        node = self.repos.get_node(u'/tête/README3.txt')
+        self.assertEqual(14, node.get_branch_origin())
+        node = self.repos.get_node('/branches/v1x')
+        self.assertEqual(12, node.get_branch_origin())
+        node = self.repos.get_node(u'/tête/dir1/dir2', 5)
+        self.assertEqual(5, node.get_branch_origin())
+
+    # Revision Log / path history 
+
+    def test_get_path_history(self):
+        history = self.repos.get_path_history(u'/tête/README2.txt', None)
+        self.assertEqual((u'tête/README2.txt', 14, 'delete'), history.next())
+        self.assertEqual((u'tête/README2.txt', 6, 'copy'), history.next())
+        self.assertEqual((u'tête/README.txt', 3, 'unknown'), history.next())
+        self.assertRaises(StopIteration, history.next)
+
+    def test_get_path_history_copied_file(self):
+        history = self.repos.get_path_history('/tags/v1/README.txt', None)
+        self.assertEqual(('tags/v1/README.txt', 7, 'copy'), history.next())
+        self.assertEqual((u'tête/README.txt', 3, 'unknown'), history.next())
+        self.assertRaises(StopIteration, history.next)
+        
+    def test_get_path_history_copied_dir(self):
+        history = self.repos.get_path_history('/branches/v1x', None)
+        self.assertEqual(('branches/v1x', 12, 'copy'), history.next())
+        self.assertEqual(('tags/v1.1', 10, 'unknown'), history.next())
+        self.assertEqual(('branches/v1x', 11, 'delete'), history.next())
+        self.assertEqual(('branches/v1x', 9, 'edit'), history.next())
+        self.assertEqual(('branches/v1x', 8, 'copy'), history.next())
+        self.assertEqual(('tags/v1', 7, 'unknown'), history.next())
+        self.assertRaises(StopIteration, history.next)
+
+    # Diffs
+
+    def _cmp_diff(self, expected, got):
+        if expected[0]:
+            old = self.repos.get_node(*expected[0])
+            self.assertEqual((old.path, old.rev), (got[0].path, got[0].rev))
+        if expected[1]:
+            new = self.repos.get_node(*expected[1])
+            self.assertEqual((new.path, new.rev), (got[1].path, got[1].rev))
+        self.assertEqual(expected[2], (got[2], got[3]))
+        
+    def test_diff_file_different_revs(self):
+        diffs = self.repos.get_changes(u'tête/README.txt', 2,
+                                       u'tête/README.txt', 3)
+        self._cmp_diff(((u'tête/README.txt', 2),
+                        (u'tête/README.txt', 3),
+                        (Node.FILE, Changeset.EDIT)), diffs.next())
+        self.assertRaises(StopIteration, diffs.next)
+
+    def test_diff_file_different_files(self):
+        diffs = self.repos.get_changes('branches/v1x/README.txt', 12,
+                                      'branches/v1x/README2.txt', 12)
+        self._cmp_diff((('branches/v1x/README.txt', 12),
+                        ('branches/v1x/README2.txt', 12),
+                        (Node.FILE, Changeset.EDIT)), diffs.next())
+        self.assertRaises(StopIteration, diffs.next)
+
+    def test_diff_file_no_change(self):
+        diffs = self.repos.get_changes(u'tête/README.txt', 7,
+                                      'tags/v1/README.txt', 7)
+        self.assertRaises(StopIteration, diffs.next)
+ 
+    def test_diff_dir_different_revs(self):
+        diffs = self.repos.get_changes(u'tête', 4, u'tête', 8)
+        self._cmp_diff((None, (u'tête/README2.txt', 8),
+                        (Node.FILE, Changeset.ADD)), diffs.next())
+        self._cmp_diff((None, (u'tête/dir1/dir2', 8),
+                        (Node.DIRECTORY, Changeset.ADD)), diffs.next())
+        self._cmp_diff((None, (u'tête/dir1/dir3', 8),
+                        (Node.DIRECTORY, Changeset.ADD)), diffs.next())
+        self._cmp_diff(((u'tête/dir2', 4), None,
+                        (Node.DIRECTORY, Changeset.DELETE)), diffs.next())
+        self._cmp_diff(((u'tête/dir3', 4), None,
+                        (Node.DIRECTORY, Changeset.DELETE)), diffs.next())
+        self.assertRaises(StopIteration, diffs.next)
+
+    def test_diff_dir_different_dirs(self):
+        diffs = self.repos.get_changes(u'tête', 1, 'branches/v1x', 12)
+        self._cmp_diff((None, ('branches/v1x/README.txt', 12),
+                        (Node.FILE, Changeset.ADD)), diffs.next())
+        self._cmp_diff((None, ('branches/v1x/README2.txt', 12),
+                        (Node.FILE, Changeset.ADD)), diffs.next())
+        self._cmp_diff((None, ('branches/v1x/dir1', 12),
+                        (Node.DIRECTORY, Changeset.ADD)), diffs.next())
+        self._cmp_diff((None, ('branches/v1x/dir1/dir2', 12),
+                        (Node.DIRECTORY, Changeset.ADD)), diffs.next())
+        self._cmp_diff((None, ('branches/v1x/dir1/dir3', 12),
+                        (Node.DIRECTORY, Changeset.ADD)), diffs.next())
+        self.assertRaises(StopIteration, diffs.next)
+
+    def test_diff_dir_no_change(self):
+        diffs = self.repos.get_changes(u'tête', 7,
+                                      'tags/v1', 7)
+        self.assertRaises(StopIteration, diffs.next)
+        
+    # Changesets
+
+    def test_changeset_repos_creation(self):
+        chgset = self.repos.get_changeset(0)
+        self.assertEqual(0, chgset.rev)
+        self.assertEqual('', chgset.message)
+        self.assertEqual('', chgset.author)
+        self.assertEqual(datetime(2005, 4, 1, 9, 57, 41, 312767, utc),
+                         chgset.date)
+        self.assertRaises(StopIteration, chgset.get_changes().next)
+
+    def test_changeset_added_dirs(self):
+        chgset = self.repos.get_changeset(1)
+        self.assertEqual(1, chgset.rev)
+        self.assertEqual('Initial directory layout.', chgset.message)
+        self.assertEqual('john', chgset.author)
+        self.assertEqual(datetime(2005, 4, 1, 10, 0, 52, 353248, utc),
+                         chgset.date)
+
+        changes = chgset.get_changes()
+        self.assertEqual(('branches', Node.DIRECTORY, Changeset.ADD, None, -1),
+                         changes.next())
+        self.assertEqual(('tags', Node.DIRECTORY, Changeset.ADD, None, -1),
+                         changes.next())
+        self.assertEqual((u'tête', Node.DIRECTORY, Changeset.ADD, None, -1),
+                         changes.next())
+        self.assertRaises(StopIteration, changes.next)
+
+    def test_changeset_file_edit(self):
+        chgset = self.repos.get_changeset(3)
+        self.assertEqual(3, chgset.rev)
+        self.assertEqual('Fixed README.\n', chgset.message)
+        self.assertEqual('kate', chgset.author)
+        self.assertEqual(datetime(2005, 4, 1, 13, 24, 58, 234643, utc),
+                         chgset.date)
+
+        changes = chgset.get_changes()
+        self.assertEqual((u'tête/README.txt', Node.FILE, Changeset.EDIT,
+                          u'tête/README.txt', 2), changes.next())
+        self.assertRaises(StopIteration, changes.next)
+
+    def test_changeset_dir_moves(self):
+        chgset = self.repos.get_changeset(5)
+        self.assertEqual(5, chgset.rev)
+        self.assertEqual('Moved directories.', chgset.message)
+        self.assertEqual('kate', chgset.author)
+        self.assertEqual(datetime(2005, 4, 1, 16, 25, 39, 658099, utc),
+                         chgset.date)
+
+        changes = chgset.get_changes()
+        self.assertEqual((u'tête/dir1/dir2', Node.DIRECTORY, Changeset.MOVE,
+                          u'tête/dir2', 4), changes.next())
+        self.assertEqual((u'tête/dir1/dir3', Node.DIRECTORY, Changeset.MOVE,
+                          u'tête/dir3', 4), changes.next())
+        self.assertRaises(StopIteration, changes.next)
+
+    def test_changeset_file_copy(self):
+        chgset = self.repos.get_changeset(6)
+        self.assertEqual(6, chgset.rev)
+        self.assertEqual('More things to read', chgset.message)
+        self.assertEqual('john', chgset.author)
+        self.assertEqual(datetime(2005, 4, 1, 18, 56, 46, 985846, utc),
+                         chgset.date)
+
+        changes = chgset.get_changes()
+        self.assertEqual((u'tête/README2.txt', Node.FILE, Changeset.COPY,
+                          u'tête/README.txt', 3), changes.next())
+        self.assertRaises(StopIteration, changes.next)
+
+    def test_changeset_root_propset(self):
+        chgset = self.repos.get_changeset(13)
+        self.assertEqual(13, chgset.rev)
+        self.assertEqual('Setting property on the repository_dir root',
+                         chgset.message)
+        changes = chgset.get_changes()
+        self.assertEqual(('/', Node.DIRECTORY, Changeset.EDIT, '/', 12),
+                         changes.next())
+        self.assertEqual((u'tête', Node.DIRECTORY, Changeset.EDIT, u'tête', 6),
+                         changes.next())
+        self.assertRaises(StopIteration, changes.next)
+
+    def test_changeset_base_path_rev(self):
+        chgset = self.repos.get_changeset(9)
+        self.assertEqual(9, chgset.rev)
+        changes = chgset.get_changes()
+        self.assertEqual(('branches/v1x/README.txt', Node.FILE,
+                          Changeset.EDIT, u'tête/README.txt', 3),
+                         changes.next())
+        self.assertRaises(StopIteration, changes.next)
+
+    def test_changeset_rename_and_edit(self):
+        chgset = self.repos.get_changeset(14)
+        self.assertEqual(14, chgset.rev)
+        changes = chgset.get_changes()
+        self.assertEqual((u'tête/README3.txt', Node.FILE,
+                          Changeset.MOVE, u'tête/README2.txt', 13),
+                         changes.next())
+        self.assertRaises(StopIteration, changes.next)
+
+    def test_changeset_edit_after_wc2wc_copy__original_deleted(self):
+        chgset = self.repos.get_changeset(16)
+        self.assertEqual(16, chgset.rev)
+        changes = chgset.get_changes()
+        self.assertEqual(('branches/v2', Node.DIRECTORY, Changeset.COPY,
+                          'tags/v1.1', 14),
+                         changes.next())
+        self.assertEqual(('branches/v2/README2.txt', Node.FILE,
+                          Changeset.EDIT, u'tête/README2.txt', 6),
+                         changes.next())
+        self.assertRaises(StopIteration, changes.next)
+
+    def test_fancy_rename_double_delete(self):
+        chgset = self.repos.get_changeset(19)
+        self.assertEqual(19, chgset.rev)
+        changes = chgset.get_changes()
+        self.assertEqual((u'tête/mpp_proc', Node.DIRECTORY,
+                          Changeset.MOVE, u'tête/Xprimary_proc', 18),
+                         changes.next())
+        self.assertEqual((u'tête/mpp_proc/Xprimary_pkg.vhd',
+                          Node.FILE, Changeset.DELETE,
+                          u'tête/Xprimary_proc/Xprimary_pkg.vhd', 18),
+                         changes.next())
+        self.assertEqual((u'tête/mpp_proc/Xprimary_proc', Node.DIRECTORY,
+                          Changeset.COPY, u'tête/Xprimary_proc', 18),
+                         changes.next())
+        self.assertEqual((u'tête/mpp_proc/Xprimary_proc/Xprimary_pkg.vhd',
+                          Node.FILE, Changeset.DELETE,
+                          u'tête/Xprimary_proc/Xprimary_pkg.vhd', 18),
+                         changes.next())
+        self.assertRaises(StopIteration, changes.next)
+
+    def test_copy_with_deletions_below_copy(self):
+        """Regression test for #4900."""
+        chgset = self.repos.get_changeset(22)
+        self.assertEqual(22, chgset.rev)
+        changes = chgset.get_changes()
+        self.assertEqual((u'branches/v3', 'dir', 'copy',
+                          u'tête', 21), changes.next())
+        self.assertEqual((u'branches/v3/dir1', 'dir', 'delete',
+                          u'tête/dir1', 21), changes.next())
+        self.assertEqual((u'branches/v3/mpp_proc', 'dir', 'delete',
+                          u'tête/mpp_proc', 21), changes.next())
+        self.assertEqual((u'branches/v3/v2', 'dir', 'delete',
+                          u'tête/v2', 21), changes.next())
+        self.assertRaises(StopIteration, changes.next)
+
+    def test_changeset_utf_8(self):
+        chgset = self.repos.get_changeset(20)
+        self.assertEqual(20, chgset.rev)
+        self.assertEqual(u'Chez moi ça marche\n', chgset.message)
+        self.assertEqual(u'Jonas Borgström', chgset.author)
+
+
+
+class ScopedTests(object):
+
+    def test_repos_normalize_path(self):
+        self.assertEqual('/', self.repos.normalize_path('/'))
+        self.assertEqual('/', self.repos.normalize_path(''))
+        self.assertEqual('/', self.repos.normalize_path(None))
+        self.assertEqual('dir1', self.repos.normalize_path('dir1'))
+        self.assertEqual('dir1', self.repos.normalize_path('/dir1'))
+        self.assertEqual('dir1', self.repos.normalize_path('dir1/'))
+        self.assertEqual('dir1', self.repos.normalize_path('/dir1/'))
+
+    def test_repos_normalize_rev(self):
+        self.assertEqual(TETE, self.repos.normalize_rev('latest'))
+        self.assertEqual(TETE, self.repos.normalize_rev('head'))
+        self.assertEqual(TETE, self.repos.normalize_rev(''))
+        self.assertEqual(TETE, self.repos.normalize_rev(None))
+        self.assertEqual(5, self.repos.normalize_rev('5'))
+        self.assertEqual(5, self.repos.normalize_rev(5))
+
+    def test_rev_navigation(self):
+        self.assertEqual(1, self.repos.oldest_rev)
+        self.assertEqual(None, self.repos.previous_rev(0))
+        self.assertEqual(1, self.repos.previous_rev(2))
+        self.assertEqual(TETE, self.repos.youngest_rev)
+        self.assertEqual(2, self.repos.next_rev(1))
+        self.assertEqual(3, self.repos.next_rev(2))
+        # ...
+        self.assertEqual(None, self.repos.next_rev(TETE))
+
+    def test_has_node(self):
+        self.assertEqual(False, self.repos.has_node('/dir1', 3))
+        self.assertEqual(True, self.repos.has_node('/dir1', 4))
+
+    def test_get_node(self):
+        node = self.repos.get_node('/dir1')
+        self.assertEqual('dir1', node.name)
+        self.assertEqual('/dir1', node.path)
+        self.assertEqual(Node.DIRECTORY, node.kind)
+        self.assertEqual(TETE, node.rev)
+        self.assertEqual(5, node.created_rev)
+        self.assertEqual(datetime(2005, 4, 1, 16, 25, 39, 658099, utc),
+                         node.last_modified)
+        node = self.repos.get_node('/README.txt')
+        self.assertEqual('README.txt', node.name)
+        self.assertEqual('/README.txt', node.path)
+        self.assertEqual(Node.FILE, node.kind)
+        self.assertEqual(TETE, node.rev)
+        self.assertEqual(3, node.created_rev)
+        self.assertEqual(datetime(2005, 4, 1, 13, 24, 58, 234643, utc),
+                         node.last_modified)
+
+    def test_get_node_specific_rev(self):
+        node = self.repos.get_node('/dir1', 4)
+        self.assertEqual('dir1', node.name)
+        self.assertEqual('/dir1', node.path)
+        self.assertEqual(Node.DIRECTORY, node.kind)
+        self.assertEqual(4, node.rev)
+        self.assertEqual(datetime(2005, 4, 1, 15, 42, 35, 450595, utc),
+                         node.last_modified)
+        node = self.repos.get_node('/README.txt', 2)
+        self.assertEqual('README.txt', node.name)
+        self.assertEqual('/README.txt', node.path)
+        self.assertEqual(Node.FILE, node.kind)
+        self.assertEqual(2, node.rev)
+        self.assertEqual(datetime(2005, 4, 1, 13, 12, 18, 216267, utc),
+                         node.last_modified)
+
+    def test_get_dir_entries(self):
+        node = self.repos.get_node('/')
+        entries = node.get_entries()
+        self.assertEqual('dir1', entries.next().name)
+        self.assertEqual('mpp_proc', entries.next().name)
+        self.assertEqual('v2', entries.next().name)
+        self.assertEqual('README3.txt', entries.next().name)
+        self.assertEqual(u'R\xe9sum\xe9.txt', entries.next().name)
+        self.assertEqual('README.txt', entries.next().name)
+        self.assertRaises(StopIteration, entries.next)
+
+    def test_get_file_entries(self):
+        node = self.repos.get_node('/README.txt')
+        entries = node.get_entries()
+        self.assertRaises(StopIteration, entries.next)
+
+    def test_get_dir_content(self):
+        node = self.repos.get_node('/dir1')
+        self.assertEqual(None, node.content_length)
+        self.assertEqual(None, node.content_type)
+        self.assertEqual(None, node.get_content())
+
+    def test_get_file_content(self):
+        node = self.repos.get_node('/README.txt')
+        self.assertEqual(8, node.content_length)
+        self.assertEqual('text/plain', node.content_type)
+        self.assertEqual('A test.\n', node.get_content().read())
+
+    def test_get_dir_properties(self):
+        f = self.repos.get_node('/dir1')
+        props = f.get_properties()
+        self.assertEqual(0, len(props))
+
+    def test_get_file_properties(self):
+        f = self.repos.get_node('/README.txt')
+        props = f.get_properties()
+        self.assertEqual('native', props['svn:eol-style'])
+        self.assertEqual('text/plain', props['svn:mime-type'])
+
+    # Revision Log / node history 
+
+    def test_get_history_scope(self): 
+        """Regression test for #9504"""
+        node = self.repos.get_node('/')
+        history = list(node.get_history())
+        self.assertEqual(('/', 1, 'add'), history[-1])
+        initial_cset = self.repos.get_changeset(history[-1][1])
+        self.assertEqual(1, initial_cset.rev)
+
+    def test_get_node_history(self):
+        node = self.repos.get_node('/README3.txt')
+        history = node.get_history()
+        self.assertEqual(('README3.txt', 14, 'copy'), history.next())
+        self.assertEqual(('README2.txt', 6, 'copy'), history.next())
+        self.assertEqual(('README.txt', 3, 'edit'), history.next())
+        self.assertEqual(('README.txt', 2, 'add'), history.next())
+        self.assertRaises(StopIteration, history.next)
+
+    def test_get_node_history_follow_copy(self):
+        node = self.repos.get_node('dir1/dir3', )
+        history = node.get_history()
+        self.assertEqual(('dir1/dir3', 5, 'copy'), history.next())
+        self.assertEqual(('dir3', 4, 'add'), history.next())
+        self.assertRaises(StopIteration, history.next)
+
+    def test_get_copy_ancestry(self):
+        node = self.repos.get_node(u'/README3.txt')
+        ancestry = node.get_copy_ancestry()
+        self.assertEqual([(u'README2.txt', 13), 
+                          (u'README.txt', 3)], ancestry)
+        for path, rev in ancestry:
+            self.repos.get_node(path, rev) # shouldn't raise NoSuchNode
+
+    def test_get_copy_ancestry_for_move(self):
+        node = self.repos.get_node(u'/dir1/dir2', 5)
+        ancestry = node.get_copy_ancestry()
+        self.assertEqual([(u'dir2', 4)], ancestry)
+        for path, rev in ancestry:
+            self.repos.get_node(path, rev) # shouldn't raise NoSuchNode
+
+    def test_get_branch_origin(self):
+        node = self.repos.get_node(u'/README3.txt')
+        self.assertEqual(14, node.get_branch_origin())
+        node = self.repos.get_node(u'/dir1/dir2', 5)
+        self.assertEqual(5, node.get_branch_origin())
+
+    # Revision Log / path history 
+
+    def test_get_path_history(self):
+        history = self.repos.get_path_history('dir3', None)
+        self.assertEqual(('dir3', 5, 'delete'), history.next())
+        self.assertEqual(('dir3', 4, 'add'), history.next())
+        self.assertRaises(StopIteration, history.next)
+
+    def test_get_path_history_copied_file(self):
+        history = self.repos.get_path_history('README3.txt', None)
+        self.assertEqual(('README3.txt', 14, 'copy'), history.next())
+        self.assertEqual(('README2.txt', 6, 'unknown'), history.next())
+        self.assertRaises(StopIteration, history.next)
+        
+    def test_get_path_history_copied_dir(self):
+        history = self.repos.get_path_history('dir1/dir3', None)
+        self.assertEqual(('dir1/dir3', 5, 'copy'), history.next())
+        self.assertEqual(('dir3', 4, 'unknown'), history.next())
+        self.assertRaises(StopIteration, history.next)
+
+    def test_changeset_repos_creation(self):
+        chgset = self.repos.get_changeset(0)
+        self.assertEqual(0, chgset.rev)
+        self.assertEqual('', chgset.message)
+        self.assertEqual('', chgset.author)
+        self.assertEqual(datetime(2005, 4, 1, 9, 57, 41, 312767, utc),
+                         chgset.date)
+        self.assertRaises(StopIteration, chgset.get_changes().next)
+
+    def test_changeset_added_dirs(self):
+        chgset = self.repos.get_changeset(4)
+        self.assertEqual(4, chgset.rev)
+        self.assertEqual('More directories.', chgset.message)
+        self.assertEqual('john', chgset.author)
+        self.assertEqual(datetime(2005, 4, 1, 15, 42, 35, 450595, utc),
+                         chgset.date)
+
+        changes = chgset.get_changes()
+        self.assertEqual(('dir1', Node.DIRECTORY, 'add', None, -1),
+                         changes.next())
+        self.assertEqual(('dir2', Node.DIRECTORY, 'add', None, -1),
+                         changes.next())
+        self.assertEqual(('dir3', Node.DIRECTORY, 'add', None, -1),
+                         changes.next())
+        self.assertRaises(StopIteration, changes.next)
+
+    def test_changeset_file_edit(self):
+        chgset = self.repos.get_changeset(3)
+        self.assertEqual(3, chgset.rev)
+        self.assertEqual('Fixed README.\n', chgset.message)
+        self.assertEqual('kate', chgset.author)
+        self.assertEqual(datetime(2005, 4, 1, 13, 24, 58, 234643, utc),
+                         chgset.date)
+
+        changes = chgset.get_changes()
+        self.assertEqual(('README.txt', Node.FILE, Changeset.EDIT,
+                          'README.txt', 2), changes.next())
+        self.assertRaises(StopIteration, changes.next)
+
+    def test_changeset_dir_moves(self):
+        chgset = self.repos.get_changeset(5)
+        self.assertEqual(5, chgset.rev)
+        self.assertEqual('Moved directories.', chgset.message)
+        self.assertEqual('kate', chgset.author)
+        self.assertEqual(datetime(2005, 4, 1, 16, 25, 39, 658099, utc),
+                         chgset.date)
+
+        changes = chgset.get_changes()
+        self.assertEqual(('dir1/dir2', Node.DIRECTORY, Changeset.MOVE,
+                          'dir2', 4), changes.next())
+        self.assertEqual(('dir1/dir3', Node.DIRECTORY, Changeset.MOVE,
+                          'dir3', 4), changes.next())
+        self.assertRaises(StopIteration, changes.next)
+
+    def test_changeset_file_copy(self):
+        chgset = self.repos.get_changeset(6)
+        self.assertEqual(6, chgset.rev)
+        self.assertEqual('More things to read', chgset.message)
+        self.assertEqual('john', chgset.author)
+        self.assertEqual(datetime(2005, 4, 1, 18, 56, 46, 985846, utc),
+                         chgset.date)
+
+        changes = chgset.get_changes()
+        self.assertEqual(('README2.txt', Node.FILE, Changeset.COPY,
+                          'README.txt', 3), changes.next())
+        self.assertRaises(StopIteration, changes.next)
+
+    def test_changeset_root_propset(self):
+        chgset = self.repos.get_changeset(13)
+        self.assertEqual(13, chgset.rev)
+        self.assertEqual('Setting property on the repository_dir root',
+                         chgset.message)
+        changes = chgset.get_changes()
+        self.assertEqual(('/', Node.DIRECTORY, Changeset.EDIT, '/', 6),
+                         changes.next())
+        self.assertRaises(StopIteration, changes.next)
+
+    def test_changeset_copy_from_outside_and_delete(self):
+        chgset = self.repos.get_changeset(21)
+        self.assertEqual(21, chgset.rev)
+        self.assertEqual('copy from outside of the scope + delete',
+                         chgset.message)
+        changes = chgset.get_changes()
+        self.assertEqual(('v2', Node.DIRECTORY, Changeset.ADD, None, -1),
+                         changes.next())
+        self.assertEqual(('v2/README2.txt', Node.FILE, Changeset.DELETE,
+                          None, -1), changes.next())
+        self.assertEqual(('v2/dir1', Node.DIRECTORY, Changeset.DELETE,
+                          None, -1), changes.next())
+        self.assertRaises(StopIteration, changes.next)
+
+
+class RecentPathScopedTests(object):
+
+    def test_rev_navigation(self):
+        self.assertEqual(False, self.repos.has_node('/', 1))
+        self.assertEqual(False, self.repos.has_node('/', 2))
+        self.assertEqual(False, self.repos.has_node('/', 3))
+        self.assertEqual(True, self.repos.has_node('/', 4))
+        # We can't make this work anymore because of #5213.
+        # self.assertEqual(4, self.repos.oldest_rev)
+        self.assertEqual(1, self.repos.oldest_rev) # should really be 4...
+        self.assertEqual(None, self.repos.previous_rev(4))
+
+
+class NonSelfContainedScopedTests(object):
+
+    def test_mixed_changeset(self):
+        chgset = self.repos.get_changeset(7)
+        self.assertEqual(7, chgset.rev)
+        changes = chgset.get_changes()
+        self.assertEqual(('/', Node.DIRECTORY, Changeset.ADD, None, -1),
+                         changes.next())
+        self.assertRaises(TracError, lambda: self.repos.get_node(None, 6))
+
+
+class AnotherNonSelfContainedScopedTests(object):
+
+    def test_mixed_changeset_with_edit(self):
+        chgset = self.repos.get_changeset(9)
+        self.assertEqual(9, chgset.rev)
+        changes = chgset.get_changes()
+        self.assertEqual(('v1x/README.txt', Node.FILE, Changeset.EDIT,
+                          'v1x/README.txt', 8),
+                         changes.next())
+
+
+# -- Test cases for SubversionRepository
+
+class SubversionRepositoryTestCase(unittest.TestCase):
+    
+    def setUp(self):
+        self.env = EnvironmentStub()
+        repositories = self.env.config['repositories']
+        DbRepositoryProvider(self.env).add_repository(REPOS_NAME, self.path,
+                                                      'direct-svnfs')
+        self.repos = self.env.get_repository(REPOS_NAME)
+
+    def tearDown(self):
+        self.env.reset_db()
+        # needed to avoid issue with 'WindowsError: The process cannot access
+        # the file ... being used by another process: ...\rep-cache.db'
+        self.env.shutdown(get_thread_id())
+
+
+# -- Test cases for SvnCachedRepository
+
+class SvnCachedRepositoryTestCase(unittest.TestCase):
+    
+    def setUp(self):
+        self.env = EnvironmentStub()
+        DbRepositoryProvider(self.env).add_repository(REPOS_NAME, self.path,
+                                                      'svn')
+        self.repos = self.env.get_repository(REPOS_NAME)
+        self.repos.sync()
+
+    def tearDown(self):
+        self.env.reset_db()
+        self.repos.close()
+        self.repos = None
+
+
+def suite():
+    suite = unittest.TestSuite()
+    if has_svn:
+        tests = [(NormalTests, ''),
+                 (ScopedTests, u'/tête'),
+                 (RecentPathScopedTests, u'/tête/dir1'),
+                 (NonSelfContainedScopedTests, '/tags/v1'),
+                 (AnotherNonSelfContainedScopedTests, '/branches'),
+                 ]
+        skipped = {
+            'SvnCachedRepositoryNormalTests': [
+                'test_changeset_repos_creation',
+                ],
+            'SvnCachedRepositoryScopedTests': [
+                'test_changeset_repos_creation',
+                'test_rev_navigation',
+                ],
+            }
+        for test, scope in tests:
+            tc = new.classobj('SubversionRepository' + test.__name__,
+                              (SubversionRepositoryTestCase, test),
+                              {'path': REPOS_PATH + scope})
+            suite.addTest(unittest.makeSuite(
+                tc, 'test', suiteClass=SubversionRepositoryTestSetup))
+            tc = new.classobj('SvnCachedRepository' + test.__name__,
+                              (SvnCachedRepositoryTestCase, test),
+                              {'path': REPOS_PATH + scope})
+            for skip in skipped.get(tc.__name__, []):
+                setattr(tc, skip, lambda self: None) # no skip, so we cheat...
+            suite.addTest(unittest.makeSuite(
+                tc, 'test', suiteClass=SubversionRepositoryTestSetup))
+    else:
+        print("SKIP: tracopt/versioncontrol/svn/tests/svn_fs.py (no svn "
+              "bindings)")
+    return suite
+
+if __name__ == '__main__':
+    runner = unittest.TextTestRunner()
+    runner.run(suite())

Propchange: incubator/bloodhound/vendor/trac/current/tracopt/versioncontrol/svn/tests/svn_fs.py
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/bloodhound/vendor/trac/current/tracopt/versioncontrol/svn/tests/svnrepos.dump
URL: http://svn.apache.org/viewvc/incubator/bloodhound/vendor/trac/current/tracopt/versioncontrol/svn/tests/svnrepos.dump?rev=1398858&view=auto
==============================================================================
--- incubator/bloodhound/vendor/trac/current/tracopt/versioncontrol/svn/tests/svnrepos.dump (added)
+++ incubator/bloodhound/vendor/trac/current/tracopt/versioncontrol/svn/tests/svnrepos.dump Tue Oct 16 15:55:00 2012
@@ -0,0 +1,748 @@
+SVN-fs-dump-format-version: 2
+
+UUID: 92ea810a-adf3-0310-b540-bef912dcf5ba
+
+Revision-number: 0
+Prop-content-length: 56
+Content-length: 56
+
+K 8
+svn:date
+V 27
+2005-04-01T09:57:41.312767Z
+PROPS-END
+
+Revision-number: 1
+Prop-content-length: 124
+Content-length: 124
+
+K 7
+svn:log
+V 25
+Initial directory layout.
+K 10
+svn:author
+V 4
+john
+K 8
+svn:date
+V 27
+2005-04-01T10:00:52.353248Z
+PROPS-END
+
+Node-path: branches
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Node-path: tags
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Node-path: tête
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Revision-number: 2
+Prop-content-length: 112
+Content-length: 112
+
+K 7
+svn:log
+V 13
+Added README.
+K 10
+svn:author
+V 4
+john
+K 8
+svn:date
+V 27
+2005-04-01T13:12:18.216267Z
+PROPS-END
+
+Node-path: tête/README.txt
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 8
+Text-content-md5: a0691c0f61f52683bcb05da98fe028c8
+Text-content-sha1: 59ccaf31a075b2a2fe64f83ca05e2694d692d4fc
+Content-length: 18
+
+PROPS-END
+A text.
+
+
+Revision-number: 3
+Prop-content-length: 113
+Content-length: 113
+
+K 7
+svn:log
+V 14
+Fixed README.
+
+K 10
+svn:author
+V 4
+kate
+K 8
+svn:date
+V 27
+2005-04-01T13:24:58.234643Z
+PROPS-END
+
+Node-path: tête/README.txt
+Node-kind: file
+Node-action: change
+Prop-content-length: 75
+Text-content-length: 8
+Text-content-md5: eaf1c95c78c9f848636d357788bd4a4c
+Text-content-sha1: 6aade8dde7d1b86b451b5d5f044a8ddcbab6b448
+Content-length: 83
+
+K 13
+svn:mime-type
+V 10
+text/plain
+K 13
+svn:eol-style
+V 6
+native
+PROPS-END
+A test.
+
+
+Revision-number: 4
+Prop-content-length: 116
+Content-length: 116
+
+K 7
+svn:log
+V 17
+More directories.
+K 10
+svn:author
+V 4
+john
+K 8
+svn:date
+V 27
+2005-04-01T15:42:35.450595Z
+PROPS-END
+
+Node-path: tête/dir1
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Node-path: tête/dir2
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Node-path: tête/dir3
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Revision-number: 5
+Prop-content-length: 117
+Content-length: 117
+
+K 7
+svn:log
+V 18
+Moved directories.
+K 10
+svn:author
+V 4
+kate
+K 8
+svn:date
+V 27
+2005-04-01T16:25:39.658099Z
+PROPS-END
+
+Node-path: tête/dir1/dir2
+Node-kind: dir
+Node-action: add
+Node-copyfrom-rev: 4
+Node-copyfrom-path: tête/dir2
+
+
+Node-path: tête/dir1/dir3
+Node-kind: dir
+Node-action: add
+Node-copyfrom-rev: 4
+Node-copyfrom-path: tête/dir3
+
+
+Node-path: tête/dir2
+Node-action: delete
+
+
+Node-path: tête/dir3
+Node-action: delete
+
+
+Revision-number: 6
+Prop-content-length: 118
+Content-length: 118
+
+K 7
+svn:log
+V 19
+More things to read
+K 10
+svn:author
+V 4
+john
+K 8
+svn:date
+V 27
+2005-04-01T18:56:46.985846Z
+PROPS-END
+
+Node-path: tête/README2.txt
+Node-kind: file
+Node-action: add
+Node-copyfrom-rev: 3
+Node-copyfrom-path: tête/README.txt
+Text-copy-source-md5: eaf1c95c78c9f848636d357788bd4a4c
+Text-copy-source-sha1: 6aade8dde7d1b86b451b5d5f044a8ddcbab6b448
+
+
+Revision-number: 7
+Prop-content-length: 151
+Content-length: 151
+
+K 7
+svn:log
+V 42
+test the tag operation (copy of directory)
+K 10
+svn:author
+V 13
+Administrator
+K 8
+svn:date
+V 27
+2005-04-14T15:06:20.717616Z
+PROPS-END
+
+Node-path: tags/v1
+Node-kind: dir
+Node-action: add
+Node-copyfrom-rev: 6
+Node-copyfrom-path: tête
+
+
+Revision-number: 8
+Prop-content-length: 124
+Content-length: 124
+
+K 7
+svn:log
+V 15
+Fix stuff in v1
+K 10
+svn:author
+V 13
+Administrator
+K 8
+svn:date
+V 27
+2005-04-22T08:57:33.499643Z
+PROPS-END
+
+Node-path: branches/v1x
+Node-kind: dir
+Node-action: add
+Node-copyfrom-rev: 7
+Node-copyfrom-path: tags/v1
+
+
+Revision-number: 9
+Prop-content-length: 127
+Content-length: 127
+
+K 7
+svn:log
+V 18
+Now that's the fix
+K 10
+svn:author
+V 13
+Administrator
+K 8
+svn:date
+V 27
+2005-04-22T08:59:24.308979Z
+PROPS-END
+
+Node-path: branches/v1x/README.txt
+Node-kind: file
+Node-action: change
+Text-content-length: 16
+Text-content-md5: 02bcabffffd16fe0fc250f08cad95e0c
+Text-content-sha1: 0828324174b10cc867b7255a84a8155cf89e1b8b
+Content-length: 16
+
+This is a test.
+
+
+Revision-number: 10
+Prop-content-length: 141
+Content-length: 141
+
+K 7
+svn:log
+V 32
+Tagging v1.1 from the fix branch
+K 10
+svn:author
+V 13
+Administrator
+K 8
+svn:date
+V 27
+2005-04-22T09:00:34.549980Z
+PROPS-END
+
+Node-path: tags/v1.1
+Node-kind: dir
+Node-action: add
+Node-copyfrom-rev: 9
+Node-copyfrom-path: branches/v1x
+
+
+Revision-number: 11
+Prop-content-length: 191
+Content-length: 191
+
+K 7
+svn:log
+V 82
+''(a few months later)'' We don't need the fix branch anymore, 1.1 is super-stable
+K 10
+svn:author
+V 13
+Administrator
+K 8
+svn:date
+V 27
+2005-04-22T09:01:38.361737Z
+PROPS-END
+
+Node-path: branches/v1x
+Node-action: delete
+
+
+Revision-number: 12
+Prop-content-length: 166
+Content-length: 166
+
+K 7
+svn:log
+V 57
+''(a few years later)'' Argh... v1.1 was buggy, after all
+K 10
+svn:author
+V 13
+Administrator
+K 8
+svn:date
+V 27
+2005-04-22T09:06:37.011174Z
+PROPS-END
+
+Node-path: branches/v1x
+Node-kind: dir
+Node-action: add
+Node-copyfrom-rev: 11
+Node-copyfrom-path: tags/v1.1
+
+
+Revision-number: 13
+Prop-content-length: 143
+Content-length: 143
+
+K 7
+svn:log
+V 43
+Setting property on the repository_dir root
+K 10
+svn:author
+V 5
+cboos
+K 8
+svn:date
+V 27
+2005-11-17T15:13:16.197772Z
+PROPS-END
+
+Node-path: 
+Node-kind: dir
+Node-action: change
+Prop-content-length: 37
+Content-length: 37
+
+K 10
+svn:ignore
+V 6
+*.pyc
+
+PROPS-END
+
+
+Node-path: tête
+Node-kind: dir
+Node-action: change
+Prop-content-length: 37
+Content-length: 37
+
+K 10
+svn:ignore
+V 6
+*.pyc
+
+PROPS-END
+
+
+Revision-number: 14
+Prop-content-length: 119
+Content-length: 119
+
+K 7
+svn:log
+V 19
+Testing rename+edit
+K 10
+svn:author
+V 5
+cboos
+K 8
+svn:date
+V 27
+2005-11-30T08:47:03.467814Z
+PROPS-END
+
+Node-path: tête/README3.txt
+Node-kind: file
+Node-action: add
+Node-copyfrom-rev: 13
+Node-copyfrom-path: tête/README2.txt
+Text-copy-source-md5: eaf1c95c78c9f848636d357788bd4a4c
+Text-copy-source-sha1: 6aade8dde7d1b86b451b5d5f044a8ddcbab6b448
+Text-content-length: 42
+Text-content-md5: 211b820b566541dd49a1283d6476d89f
+Text-content-sha1: 7e9f46800519d6ae305f44cc07bd7568be3c9d5c
+Content-length: 42
+
+A test of svn move, followed by a change.
+
+
+Node-path: tête/README2.txt
+Node-action: delete
+
+
+Revision-number: 15
+Prop-content-length: 162
+Content-length: 162
+
+K 7
+svn:log
+V 62
+Removing original file, just before committing the wc->wc copy
+K 10
+svn:author
+V 5
+cboos
+K 8
+svn:date
+V 27
+2005-12-06T12:47:36.271020Z
+PROPS-END
+
+Node-path: tags/v1.1/README2.txt
+Node-action: delete
+
+
+Revision-number: 16
+Prop-content-length: 138
+Content-length: 138
+
+K 7
+svn:log
+V 38
+Committing wc->wc copy + local changes
+K 10
+svn:author
+V 5
+cboos
+K 8
+svn:date
+V 27
+2005-12-06T12:47:51.122376Z
+PROPS-END
+
+Node-path: branches/v2
+Node-kind: dir
+Node-action: add
+Node-copyfrom-rev: 14
+Node-copyfrom-path: tags/v1.1
+
+
+Node-path: branches/v2/README2.txt
+Node-kind: file
+Node-action: change
+Text-content-length: 47
+Text-content-md5: 9b7bad978c6ad159f939c3db2038cbb1
+Text-content-sha1: 4a475c10d832c28f9a9798477885c48146c0bc18
+Content-length: 47
+
+A test + local modifications after wc->wc copy
+
+
+Revision-number: 17
+Prop-content-length: 139
+Content-length: 139
+
+K 7
+svn:log
+V 39
+Test des caractères accentués (cp437)
+K 10
+svn:author
+V 5
+cboos
+K 8
+svn:date
+V 27
+2006-03-31T12:30:25.421875Z
+PROPS-END
+
+Node-path: tête/Résumé.txt
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 13
+Text-content-md5: 858e52306ecdfcb6f6eadb50d6f9086b
+Text-content-sha1: f4802e1b42e6256148438ce62d9b95ba671c23f8
+Content-length: 23
+
+PROPS-END
+En résumé ...
+
+Revision-number: 18
+Prop-content-length: 124
+Content-length: 124
+
+K 7
+svn:log
+V 24
+Prepare for fancy rename
+K 10
+svn:author
+V 5
+cboos
+K 8
+svn:date
+V 27
+2006-09-27T10:40:38.671875Z
+PROPS-END
+
+Node-path: tête/Xprimary_proc
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Node-path: tête/Xprimary_proc/Xprimary_pkg.vhd
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 5
+Text-content-md5: 2debfdcf79f03e4a65a667d21ef9de14
+Text-content-sha1: 4c49b08e9b258e0e5867d76ce583c159597b6857
+Content-length: 15
+
+PROPS-END
+TEST
+
+
+Revision-number: 19
+Prop-content-length: 145
+Content-length: 145
+
+K 7
+svn:log
+V 45
+Fancy copy+rename resulting in double delete.
+K 10
+svn:author
+V 5
+cboos
+K 8
+svn:date
+V 27
+2006-09-27T10:41:27.484375Z
+PROPS-END
+
+Node-path: tête/mpp_proc
+Node-kind: dir
+Node-action: add
+Node-copyfrom-rev: 18
+Node-copyfrom-path: tête/Xprimary_proc
+
+
+Node-path: tête/mpp_proc/Xprimary_proc
+Node-kind: dir
+Node-action: add
+Node-copyfrom-rev: 18
+Node-copyfrom-path: tête/Xprimary_proc
+
+
+Node-path: tête/mpp_proc/Xprimary_proc/Xprimary_pkg.vhd
+Node-action: delete
+
+
+Node-path: tête/mpp_proc/Xprimary_pkg.vhd
+Node-action: delete
+
+
+Node-path: tête/Xprimary_proc
+Node-action: delete
+
+
+Revision-number: 20
+Prop-content-length: 132
+Content-length: 132
+
+K 7
+svn:log
+V 20
+Chez moi ça marche
+
+K 10
+svn:author
+V 16
+Jonas Borgström
+K 8
+svn:date
+V 27
+2006-12-04T10:47:24.015625Z
+PROPS-END
+
+Node-path: tête/Résumé.txt
+Node-kind: file
+Node-action: change
+Text-content-length: 25
+Text-content-md5: c3744e0035c756a17fdf6dbbdd5719f0
+Text-content-sha1: f7453fe6bac18f7dc717295a30331297ff05ae14
+Content-length: 25
+
+En résumé ... ça marche.
+
+
+Revision-number: 21
+Prop-content-length: 139
+Content-length: 139
+
+K 7
+svn:log
+V 39
+copy from outside of the scope + delete
+K 10
+svn:author
+V 5
+cboos
+K 8
+svn:date
+V 27
+2007-04-30T17:45:26.234375Z
+PROPS-END
+
+Node-path: tête/v2
+Node-kind: dir
+Node-action: add
+Node-copyfrom-rev: 20
+Node-copyfrom-path: branches/v2
+
+
+Node-path: tête/v2/dir1
+Node-action: delete
+
+
+Node-path: tête/v2/README2.txt
+Node-action: delete
+
+
+Revision-number: 22
+Prop-content-length: 130
+Content-length: 130
+
+K 7
+svn:log
+V 30
+test delete after copy (#4900)
+K 10
+svn:author
+V 5
+cboos
+K 8
+svn:date
+V 27
+2010-02-26T14:48:19.377000Z
+PROPS-END
+
+Node-path: branches/v3
+Node-kind: dir
+Node-action: add
+Node-copyfrom-rev: 21
+Node-copyfrom-path: tête
+
+
+Node-path: branches/v3/v2
+Node-action: delete
+
+
+Node-path: branches/v3/dir1
+Node-action: delete
+
+
+Node-path: branches/v3/mpp_proc
+Node-action: delete
+
+