summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorQijiang Fan <fqj1994@gmail.com>2012-11-15 17:11:37 +0800
committerQijiang Fan <fqj1994@gmail.com>2012-11-15 17:11:37 +0800
commit206ab31e9e0aae6866a27511724298dd00a7d90e (patch)
tree651928c31b80fee0b7cd4a6213e8c7642e615a7a /tests
parent41ab46d551a1287a4dfb60d04e132af468923d95 (diff)
Upstream version 1.5
Diffstat (limited to 'tests')
-rw-r--r--tests/comprehensive/test_stupid_pull.py4
-rw-r--r--tests/comprehensive/test_verify.py55
-rw-r--r--tests/comprehensive/test_verify_and_startrev.py116
-rw-r--r--tests/fixtures/addspecial.sh51
-rw-r--r--tests/fixtures/addspecial.svndump302
-rwxr-xr-xtests/fixtures/copies.sh29
-rw-r--r--tests/fixtures/copies.svndump158
-rw-r--r--tests/fixtures/correct.svndump103
-rw-r--r--tests/fixtures/corrupt.svndump97
-rwxr-xr-xtests/fixtures/delete_restore_trunk.sh31
-rw-r--r--tests/fixtures/delete_restore_trunk.svndump167
-rwxr-xr-xtests/fixtures/emptyrepo2.sh44
-rw-r--r--tests/fixtures/emptyrepo2.svndump129
-rwxr-xr-xtests/fixtures/invalid_utf8.sh34
-rw-r--r--tests/fixtures/invalid_utf8.tar.gzbin0 -> 8227 bytes
-rwxr-xr-xtests/fixtures/movetotrunk.sh34
-rw-r--r--tests/fixtures/movetotrunk.svndump154
-rwxr-xr-xtests/fixtures/revert.sh39
-rw-r--r--tests/fixtures/revert.svndump197
-rw-r--r--tests/fixtures/subdir_is_file_prefix.svndump72
-rw-r--r--tests/run.py7
-rw-r--r--tests/test_fetch_branches.py3
-rw-r--r--tests/test_fetch_command.py76
-rw-r--r--tests/test_fetch_mappings.py76
-rw-r--r--tests/test_fetch_renames.py7
-rw-r--r--tests/test_fetch_symlinks.py14
-rw-r--r--tests/test_helpers.py37
-rw-r--r--tests/test_hooks.py48
-rw-r--r--tests/test_pull.py28
-rw-r--r--tests/test_pull_fallback.py106
-rw-r--r--tests/test_push_autoprops.py107
-rw-r--r--tests/test_push_command.py35
-rw-r--r--tests/test_rebuildmeta.py53
-rw-r--r--tests/test_single_dir_clone.py9
-rw-r--r--tests/test_startrev.py71
-rw-r--r--tests/test_tags.py1
-rw-r--r--tests/test_updatemeta.py81
-rw-r--r--tests/test_util.py88
-rw-r--r--tests/test_utility_commands.py94
39 files changed, 2560 insertions, 197 deletions
diff --git a/tests/comprehensive/test_stupid_pull.py b/tests/comprehensive/test_stupid_pull.py
index 17e8122..fcc1ed6 100644
--- a/tests/comprehensive/test_stupid_pull.py
+++ b/tests/comprehensive/test_stupid_pull.py
@@ -45,7 +45,9 @@ def buildmethod(case, name, layout):
attrs = {'_do_case': _do_case,
}
for case in (f for f in os.listdir(test_util.FIXTURES) if f.endswith('.svndump')):
- name = 'test_' + case[:-len('.svndump')]
+ if case == 'corrupt.svndump':
+ continue
+ name = 'test_' + case[:-len('.svndump')].replace('-', '_')
# Automatic layout branchtag collision exposes a minor defect
# here, but since it isn't a regression we suppress the test case.
if case != 'branchtagcollision.svndump':
diff --git a/tests/comprehensive/test_verify.py b/tests/comprehensive/test_verify.py
deleted file mode 100644
index 65bdfa9..0000000
--- a/tests/comprehensive/test_verify.py
+++ /dev/null
@@ -1,55 +0,0 @@
-import os
-import pickle
-import sys
-import unittest
-
-# wrapped in a try/except because of weirdness in how
-# run.py works as compared to nose.
-try:
- import test_util
-except ImportError:
- sys.path.insert(0, os.path.dirname(os.path.dirname(__file__)))
- import test_util
-
-from mercurial import hg
-from mercurial import ui
-
-from hgsubversion import svncommands
-
-def _do_case(self, name, stupid, layout):
- subdir = test_util.subdir.get(name, '')
- repo = self._load_fixture_and_fetch(name, subdir=subdir, stupid=stupid, layout=layout)
- assert len(self.repo) > 0
- for i in repo:
- ctx = repo[i]
- self.assertEqual(svncommands.verify(repo.ui, repo, rev=ctx.node()), 0)
-
-def buildmethod(case, name, stupid, layout):
- m = lambda self: self._do_case(case, stupid, layout)
- m.__name__ = name
- bits = case, stupid and 'stupid' or 'real', layout
- m.__doc__ = 'Test verify on %s with %s replay. (%s)' % bits
- return m
-
-attrs = {'_do_case': _do_case}
-fixtures = [f for f in os.listdir(test_util.FIXTURES) if f.endswith('.svndump')]
-for case in fixtures:
- # this fixture results in an empty repository, don't use it
- if case == 'project_root_not_repo_root.svndump':
- continue
- bname = 'test_' + case[:-len('.svndump')]
- attrs[bname] = buildmethod(case, bname, False, 'standard')
- name = bname + '_stupid'
- attrs[name] = buildmethod(case, name, True, 'standard')
- name = bname + '_single'
- attrs[name] = buildmethod(case, name, False, 'single')
- # Disabled because the "stupid and real are the same" tests
- # verify this plus even more.
- # name = bname + '_single_stupid'
- # attrs[name] = buildmethod(case, name, True, 'single')
-
-VerifyTests = type('VerifyTests', (test_util.TestBase,), attrs)
-
-def suite():
- all_tests = [unittest.TestLoader().loadTestsFromTestCase(VerifyTests)]
- return unittest.TestSuite(all_tests)
diff --git a/tests/comprehensive/test_verify_and_startrev.py b/tests/comprehensive/test_verify_and_startrev.py
new file mode 100644
index 0000000..0834caf
--- /dev/null
+++ b/tests/comprehensive/test_verify_and_startrev.py
@@ -0,0 +1,116 @@
+import os
+import pickle
+import sys
+import unittest
+
+# wrapped in a try/except because of weirdness in how
+# run.py works as compared to nose.
+try:
+ import test_util
+except ImportError:
+ sys.path.insert(0, os.path.dirname(os.path.dirname(__file__)))
+ import test_util
+
+from mercurial import hg
+from mercurial import ui
+
+from hgsubversion import verify
+
+# these fixtures contain no files at HEAD and would result in empty clones
+_skipshallow = set([
+ 'binaryfiles.svndump',
+ 'binaryfiles-broken.svndump',
+ 'emptyrepo.svndump',
+ 'correct.svndump',
+ 'corrupt.svndump',
+])
+
+_skipall = set([
+ 'project_root_not_repo_root.svndump',
+ 'movetotrunk.svndump',
+])
+
+_skipstandard = set([
+ 'subdir_is_file_prefix.svndump',
+ 'correct.svndump',
+ 'corrupt.svndump',
+ 'emptyrepo2.svndump',
+])
+
+def _do_case(self, name, stupid, layout):
+ subdir = test_util.subdir.get(name, '')
+ repo, svnpath = self.load_and_fetch(name, subdir=subdir, stupid=stupid,
+ layout=layout)
+ assert len(self.repo) > 0
+ for i in repo:
+ ctx = repo[i]
+ self.assertEqual(verify.verify(repo.ui, repo, rev=ctx.node(),
+ stupid=True), 0)
+ self.assertEqual(verify.verify(repo.ui, repo, rev=ctx.node(),
+ stupid=False), 0)
+
+ # check a startrev clone
+ if layout == 'single' and name not in _skipshallow:
+ self.wc_path += '_shallow'
+ shallowrepo = self.fetch(svnpath, subdir=subdir, stupid=stupid,
+ layout='single', startrev='HEAD')
+
+ self.assertEqual(len(shallowrepo), 1,
+ "shallow clone should have just one revision, not %d"
+ % len(shallowrepo))
+
+ fulltip = repo['tip']
+ shallowtip = shallowrepo['tip']
+
+ repo.ui.pushbuffer()
+ self.assertEqual(0, verify.verify(repo.ui, shallowrepo,
+ rev=shallowtip.node(),
+ stupid=True))
+ self.assertEqual(0, verify.verify(repo.ui, shallowrepo,
+ rev=shallowtip.node(),
+ stupid=False))
+
+ stupidui = ui.ui(repo.ui)
+ stupidui.config('hgsubversion', 'stupid', True)
+ self.assertEqual(verify.verify(stupidui, repo, rev=ctx.node(),
+ stupid=True), 0)
+ self.assertEqual(verify.verify(stupidui, repo, rev=ctx.node(),
+ stupid=False), 0)
+
+ # viewing diff's of lists of files is easier on the eyes
+ self.assertMultiLineEqual('\n'.join(fulltip), '\n'.join(shallowtip),
+ repo.ui.popbuffer())
+
+ for f in fulltip:
+ self.assertMultiLineEqual(fulltip[f].data(), shallowtip[f].data())
+
+
+def buildmethod(case, name, stupid, layout):
+ m = lambda self: self._do_case(case, stupid, layout)
+ m.__name__ = name
+ bits = case, stupid and 'stupid' or 'real', layout
+ m.__doc__ = 'Test verify on %s with %s replay. (%s)' % bits
+ return m
+
+attrs = {'_do_case': _do_case}
+fixtures = [f for f in os.listdir(test_util.FIXTURES) if f.endswith('.svndump')]
+for case in fixtures:
+ if case in _skipall:
+ continue
+ bname = 'test_' + case[:-len('.svndump')]
+ if case not in _skipstandard:
+ attrs[bname] = buildmethod(case, bname, False, 'standard')
+ name = bname + '_stupid'
+ attrs[name] = buildmethod(case, name, True, 'standard')
+ name = bname + '_single'
+ attrs[name] = buildmethod(case, name, False, 'single')
+ # Disabled because the "stupid and real are the same" tests
+ # verify this plus even more.
+ # name = bname + '_single_stupid'
+ # attrs[name] = buildmethod(case, name, True, 'single')
+
+VerifyTests = type('VerifyTests', (test_util.TestBase,), attrs)
+
+def suite():
+ all_tests = [unittest.TestLoader().loadTestsFromTestCase(VerifyTests)]
+ return unittest.TestSuite(all_tests)
diff --git a/tests/fixtures/addspecial.sh b/tests/fixtures/addspecial.sh
new file mode 100644
index 0000000..1d242bc
--- /dev/null
+++ b/tests/fixtures/addspecial.sh
@@ -0,0 +1,51 @@
+#!/bin/sh
+
+mkdir temp
+cd temp
+
+svnadmin create repo
+svn co file://`pwd`/repo wc
+cd wc
+
+mkdir -p trunk branches
+svn add trunk branches
+svn ci -m'initial structure'
+cd trunk
+echo a>a
+svn add a
+svn ci -mci1 a
+cd ..
+svn up
+svn cp trunk branches/foo
+svn ci -m'branch foo'
+cd branches/foo
+ln -s a fnord
+svn add fnord
+svn ci -msymlink fnord
+mkdir 'spacy name'
+echo a > 'spacy name/spacy file'
+svn add 'spacy name'
+svn ci -mspacy 'spacy name'
+svn up
+echo b > 'spacy name/surprise ~'
+svn add 'spacy name/surprise ~'
+svn ci -mtilde 'spacy name'
+svn up ../..
+echo foo > exe
+chmod +x exe
+svn add exe
+svn ci -mexecutable exe
+svn up ../..
+cd ../../trunk
+svn merge ../branches/foo
+svn ci -mmerge
+svn up
+
+pwd
+cd ../../..
+svnadmin dump temp/repo > addspecial.svndump
+echo
+echo 'Complete.'
+echo 'You probably want to clean up temp now.'
+echo 'Dump in addspecial.svndump'
+exit 0
diff --git a/tests/fixtures/addspecial.svndump b/tests/fixtures/addspecial.svndump
new file mode 100644
index 0000000..6cc3e4c
--- /dev/null
+++ b/tests/fixtures/addspecial.svndump
@@ -0,0 +1,302 @@
+SVN-fs-dump-format-version: 2
+
+UUID: 01df53ad-5d72-4756-8742-f669dc98f791
+
+Revision-number: 0
+Prop-content-length: 56
+Content-length: 56
+
+K 8
+svn:date
+V 27
+2012-05-13T22:22:43.218190Z
+PROPS-END
+
+Revision-number: 1
+Prop-content-length: 118
+Content-length: 118
+
+K 10
+svn:author
+V 6
+bryano
+K 8
+svn:date
+V 27
+2012-05-13T22:22:44.112163Z
+K 7
+svn:log
+V 17
+initial structure
+PROPS-END
+
+Node-path: branches
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Node-path: trunk
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Revision-number: 2
+Prop-content-length: 103
+Content-length: 103
+
+K 10
+svn:author
+V 6
+bryano
+K 8
+svn:date
+V 27
+2012-05-13T22:22:45.111247Z
+K 7
+svn:log
+V 3
+ci1
+PROPS-END
+
+Node-path: trunk/a
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 2
+Text-content-md5: 60b725f10c9c85c70d97880dfe8191b3
+Text-content-sha1: 3f786850e387550fdab836ed7e6dc881de23001b
+Content-length: 12
+
+PROPS-END
+a
+
+
+Revision-number: 3
+Prop-content-length: 111
+Content-length: 111
+
+K 10
+svn:author
+V 6
+bryano
+K 8
+svn:date
+V 27
+2012-05-13T22:22:48.110257Z
+K 7
+svn:log
+V 10
+branch foo
+PROPS-END
+
+Node-path: branches/foo
+Node-kind: dir
+Node-action: add
+Node-copyfrom-rev: 2
+Node-copyfrom-path: trunk
+
+
+Revision-number: 4
+Prop-content-length: 107
+Content-length: 107
+
+K 10
+svn:author
+V 6
+bryano
+K 8
+svn:date
+V 27
+2012-05-13T22:22:49.115096Z
+K 7
+svn:log
+V 7
+symlink
+PROPS-END
+
+Node-path: branches/foo/fnord
+Node-kind: file
+Node-action: add
+Prop-content-length: 33
+Text-content-length: 6
+Text-content-md5: c118dba188202a1efc975bef6064180b
+Text-content-sha1: 41f94e4692313bf7f7c92aa600002f1dff93d6bf
+Content-length: 39
+
+K 11
+svn:special
+V 1
+*
+PROPS-END
+link a
+
+Revision-number: 5
+Prop-content-length: 105
+Content-length: 105
+
+K 10
+svn:author
+V 6
+bryano
+K 8
+svn:date
+V 27
+2012-05-13T22:22:50.119266Z
+K 7
+svn:log
+V 5
+spacy
+PROPS-END
+
+Node-path: branches/foo/spacy name
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Node-path: branches/foo/spacy name/spacy file
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 2
+Text-content-md5: 60b725f10c9c85c70d97880dfe8191b3
+Text-content-sha1: 3f786850e387550fdab836ed7e6dc881de23001b
+Content-length: 12
+
+PROPS-END
+a
+
+
+Revision-number: 6
+Prop-content-length: 105
+Content-length: 105
+
+K 10
+svn:author
+V 6
+bryano
+K 8
+svn:date
+V 27
+2012-05-13T22:22:52.123367Z
+K 7
+svn:log
+V 5
+tilde
+PROPS-END
+
+Node-path: branches/foo/spacy name/surprise ~
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 2
+Text-content-md5: 3b5d5c3712955042212316173ccf37be
+Text-content-sha1: 89e6c98d92887913cadf06b2adb97f26cde4849b
+Content-length: 12
+
+PROPS-END
+b
+
+
+Revision-number: 7
+Prop-content-length: 111
+Content-length: 111
+
+K 10
+svn:author
+V 6
+bryano
+K 8
+svn:date
+V 27
+2012-05-13T22:22:54.129462Z
+K 7
+svn:log
+V 10
+executable
+PROPS-END
+
+Node-path: branches/foo/exe
+Node-kind: file
+Node-action: add
+Prop-content-length: 36
+Text-content-length: 4
+Text-content-md5: d3b07384d113edec49eaa6238ad5ff00
+Text-content-sha1: f1d2d2f924e986ac86fdf7b36c94bcdf32beec15
+Content-length: 40
+
+K 14
+svn:executable
+V 1
+*
+PROPS-END
+foo
+
+
+Revision-number: 8
+Prop-content-length: 105
+Content-length: 105
+
+K 10
+svn:author
+V 6
+bryano
+K 8
+svn:date
+V 27
+2012-05-13T22:22:57.111370Z
+K 7
+svn:log
+V 5
+merge
+PROPS-END
+
+Node-path: trunk
+Node-kind: dir
+Node-action: change
+Prop-content-length: 52
+Content-length: 52
+
+K 13
+svn:mergeinfo
+V 17
+/branches/foo:3-7
+PROPS-END
+
+
+Node-path: trunk/exe
+Node-kind: file
+Node-action: add
+Node-copyfrom-rev: 7
+Node-copyfrom-path: branches/foo/exe
+Text-copy-source-md5: d3b07384d113edec49eaa6238ad5ff00
+Text-copy-source-sha1: f1d2d2f924e986ac86fdf7b36c94bcdf32beec15
+
+
+Node-path: trunk/fnord
+Node-kind: file
+Node-action: add
+Node-copyfrom-rev: 7
+Node-copyfrom-path: branches/foo/fnord
+Text-copy-source-md5: c118dba188202a1efc975bef6064180b
+Text-copy-source-sha1: 41f94e4692313bf7f7c92aa600002f1dff93d6bf
+
+
+Node-path: trunk/spacy name
+Node-kind: dir
+Node-action: add
+Node-copyfrom-rev: 7
+Node-copyfrom-path: branches/foo/spacy name
+
+
diff --git a/tests/fixtures/copies.sh b/tests/fixtures/copies.sh
new file mode 100755
index 0000000..4709bc9
--- /dev/null
+++ b/tests/fixtures/copies.sh
@@ -0,0 +1,29 @@
+#!/bin/sh
+#
+# Generate copies.svndump
+#
+
+rm -rf temp
+mkdir temp
+cd temp
+mkdir -p import/trunk/dir
+echo a > import/trunk/dir/a
+
+svnadmin create testrepo
+svnurl=file://`pwd`/testrepo
+svn import import $svnurl -m init
+
+svn co $svnurl project
+cd project
+svn cp trunk/dir trunk/dir2
+echo b >> trunk/dir2/a
+svn ci -m 'copy/edit trunk/dir/a'
+svn up
+svn cp trunk/dir2 trunk/dir3
+svn ci -m 'copy dir2 to dir3'
+svn rm trunk/dir3/a
+svn cp trunk/dir2/a trunk/dir3/a
+svn ci -m 'copy and remove'
+cd ..
+
+svnadmin dump testrepo > ../copies.svndump
diff --git a/tests/fixtures/copies.svndump b/tests/fixtures/copies.svndump
new file mode 100644
index 0000000..76cfd97
--- /dev/null
+++ b/tests/fixtures/copies.svndump
@@ -0,0 +1,158 @@
+SVN-fs-dump-format-version: 2
+
+UUID: 6f377846-a035-4244-a154-e87a9351a653
+
+Revision-number: 0
+Prop-content-length: 56
+Content-length: 56
+
+K 8
+svn:date
+V 27
+2012-10-15T19:02:56.936694Z
+PROPS-END
+
+Revision-number: 1
+Prop-content-length: 105
+Content-length: 105
+
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2012-10-15T19:02:56.958201Z
+K 7
+svn:log
+V 4
+init
+PROPS-END
+
+Node-path: trunk
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Node-path: trunk/dir
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Node-path: trunk/dir/a
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 2
+Text-content-md5: 60b725f10c9c85c70d97880dfe8191b3
+Text-content-sha1: 3f786850e387550fdab836ed7e6dc881de23001b
+Content-length: 12
+
+PROPS-END
+a
+
+
+Revision-number: 2
+Prop-content-length: 123
+Content-length: 123
+
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2012-10-15T19:02:58.046478Z
+K 7
+svn:log
+V 21
+copy/edit trunk/dir/a
+PROPS-END
+
+Node-path: trunk/dir2
+Node-kind: dir
+Node-action: add
+Node-copyfrom-rev: 1
+Node-copyfrom-path: trunk/dir
+
+
+Node-path: trunk/dir2/a
+Node-kind: file
+Node-action: change
+Text-content-length: 4
+Text-content-md5: dd8c6a395b5dd36c56d23275028f526c
+Text-content-sha1: 05dec960e24d918b8a73a1c53bcbbaac2ee5c2e0
+Content-length: 4
+
+a
+b
+
+
+Revision-number: 3
+Prop-content-length: 119
+Content-length: 119
+
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2012-10-15T19:03:01.045897Z
+K 7
+svn:log
+V 17
+copy dir2 to dir3
+PROPS-END
+
+Node-path: trunk/dir3
+Node-kind: dir
+Node-action: add
+Node-copyfrom-rev: 2
+Node-copyfrom-path: trunk/dir2
+
+
+Revision-number: 4
+Prop-content-length: 117
+Content-length: 117
+
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2012-10-15T19:03:03.046654Z
+K 7
+svn:log
+V 15
+copy and remove
+PROPS-END
+
+Node-path: trunk/dir3/a
+Node-kind: file
+Node-action: delete
+
+Node-path: trunk/dir3/a
+Node-kind: file
+Node-action: add
+Node-copyfrom-rev: 2
+Node-copyfrom-path: trunk/dir2/a
+Text-copy-source-md5: dd8c6a395b5dd36c56d23275028f526c
+Text-copy-source-sha1: 05dec960e24d918b8a73a1c53bcbbaac2ee5c2e0
+
+
+
+
diff --git a/tests/fixtures/correct.svndump b/tests/fixtures/correct.svndump
new file mode 100644
index 0000000..9e24c3c
--- /dev/null
+++ b/tests/fixtures/correct.svndump
@@ -0,0 +1,103 @@
+SVN-fs-dump-format-version: 2
+
+UUID: 00000000-0000-0000-0000-000000000000
+
+Revision-number: 0
+Prop-content-length: 56
+Content-length: 56
+
+K 8
+svn:date
+V 27
+2010-11-30T15:10:25.898546Z
+PROPS-END
+
+Revision-number: 1
+Prop-content-length: 100
+Content-length: 100
+
+K 7
+svn:log
+V 0
+
+K 10
+svn:author
+V 6
+danchr
+K 8
+svn:date
+V 27
+2010-11-30T15:16:01.077550Z
+PROPS-END
+
+Node-path: empty-file
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 0
+Text-content-md5: d41d8cd98f00b204e9800998ecf8427e
+Text-content-sha1: da39a3ee5e6b4b0d3255bfef95601890afd80709
+Content-length: 10
+
+PROPS-END
+
+
+Node-path: executable-file
+Node-kind: file
+Node-action: add
+Prop-content-length: 36
+Text-content-length: 11
+Text-content-md5: 01839ba8c81c3b2c7486607e0c683e62
+Text-content-sha1: 5e70f8a25fe8ad4ad971bfd3388c258b019268d4
+Content-length: 47
+
+K 14
+svn:executable
+V 1
+*
+PROPS-END
+Executable
+
+
+Node-path: regular-file
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 10
+Text-content-md5: 2e01b7f4ab0c18c05a3059eb2e2420d9
+Text-content-sha1: 6e530e985be313a43dc9734251656be8f0c94ab8
+Content-length: 20
+
+PROPS-END
+Contents.
+
+
+Node-path: another-regular-file
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 10
+Text-content-md5: 2e01b7f4ab0c18c05a3059eb2e2420d9
+Text-content-sha1: 6e530e985be313a43dc9734251656be8f0c94ab8
+Content-length: 20
+
+PROPS-END
+Contents.
+
+
+Node-path: symlink
+Node-kind: file
+Node-action: add
+Prop-content-length: 33
+Text-content-length: 6
+Text-content-md5: 654580f41818cd6f51408c7cbd313728
+Text-content-sha1: 130b8faaf3e1acc1b95f77ac835e9c8b6eee5c96
+Content-length: 39
+
+K 11
+svn:special
+V 1
+*
+PROPS-END
+link A
+
diff --git a/tests/fixtures/corrupt.svndump b/tests/fixtures/corrupt.svndump
new file mode 100644
index 0000000..bcc0941
--- /dev/null
+++ b/tests/fixtures/corrupt.svndump
@@ -0,0 +1,97 @@
+SVN-fs-dump-format-version: 2
+
+UUID: 00000000-0000-0000-0000-000000000000
+
+Revision-number: 0
+Prop-content-length: 56
+Content-length: 56
+
+K 8
+svn:date
+V 27
+2010-11-30T15:10:25.898546Z
+PROPS-END
+
+Revision-number: 1
+Prop-content-length: 100
+Content-length: 100
+
+K 10
+svn:author
+V 6
+danchr
+K 8
+svn:date
+V 27
+2010-11-30T15:16:01.077550Z
+K 7
+svn:log
+V 0
+
+PROPS-END
+
+Node-path: another-regular-file
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 0
+Text-content-md5: d41d8cd98f00b204e9800998ecf8427e
+Text-content-sha1: da39a3ee5e6b4b0d3255bfef95601890afd80709
+Content-length: 10
+
+PROPS-END
+
+
+Node-path: executable-file
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 11
+Text-content-md5: 01839ba8c81c3b2c7486607e0c683e62
+Text-content-sha1: 5e70f8a25fe8ad4ad971bfd3388c258b019268d4
+Content-length: 21
+
+PROPS-END
+Executable
+
+
+Node-path: missing-file
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 0
+Text-content-md5: d41d8cd98f00b204e9800998ecf8427e
+Text-content-sha1: da39a3ee5e6b4b0d3255bfef95601890afd80709
+Content-length: 10
+
+PROPS-END
+
+
+Node-path: regular-file
+Node-kind: file
+Node-action: add
+Prop-content-length: 33
+Text-content-length: 18
+Text-content-md5: adf66a0cec83e25644c63f3c3007ae7c
+Text-content-sha1: 047e6e482d0c9cb812f89d18a9f07a43caab76bb
+Content-length: 51
+
+K 11
+svn:special
+V 1
+*
+PROPS-END
+link Bad contents.
+
+Node-path: symlink
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 1
+Text-content-md5: 7fc56270e7a70fa81a5935b72eacbe29
+Text-content-sha1: 6dcd4ce23d88e2ee9568ba546c007c63d9131c1b
+Content-length: 11
+
+PROPS-END
+A
+
diff --git a/tests/fixtures/delete_restore_trunk.sh b/tests/fixtures/delete_restore_trunk.sh
new file mode 100755
index 0000000..340b5ef
--- /dev/null
+++ b/tests/fixtures/delete_restore_trunk.sh
@@ -0,0 +1,31 @@
+#!/bin/bash
+set -e
+mkdir temp
+cd temp
+svnadmin create repo
+svn co file://`pwd`/repo wc
+cd wc
+mkdir branches trunk tags
+svn add *
+svn ci -m 'btt'
+echo foo > trunk/foo
+svn add trunk/foo
+svn ci -m 'add file'
+svn up
+svn rm trunk
+svn ci -m 'delete trunk'
+svn up
+cd ..
+svn cp -m 'restore trunk' file://`pwd`/repo/trunk@2 file://`pwd`/repo/trunk
+cd wc
+svn up
+echo bar >> trunk/foo
+svn ci -m 'append to file'
+svn up
+cd ../..
+svnadmin dump temp/repo > delete_restore_trunk.svndump
+echo
+echo 'Complete.'
+echo 'You probably want to clean up temp now.'
+echo 'Dump in branch_delete_parent_dir.svndump'
+exit 0
diff --git a/tests/fixtures/delete_restore_trunk.svndump b/tests/fixtures/delete_restore_trunk.svndump
new file mode 100644
index 0000000..2d95813
--- /dev/null
+++ b/tests/fixtures/delete_restore_trunk.svndump
@@ -0,0 +1,167 @@
+SVN-fs-dump-format-version: 2
+
+UUID: fca176f4-a346-479b-ae2c-78c8442c3809
+
+Revision-number: 0
+Prop-content-length: 56
+Content-length: 56
+
+K 8
+svn:date
+V 27
+2012-05-16T22:55:55.613464Z
+PROPS-END
+
+Revision-number: 1
+Prop-content-length: 103
+Content-length: 103
+
+K 7
+svn:log
+V 3
+btt
+K 10
+svn:author
+V 6
+bryano
+K 8
+svn:date
+V 27
+2012-05-16T22:55:56.081065Z
+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: trunk
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Revision-number: 2
+Prop-content-length: 108
+Content-length: 108
+
+K 7
+svn:log
+V 8
+add file
+K 10
+svn:author
+V 6
+bryano
+K 8
+svn:date
+V 27
+2012-05-16T22:55:57.071178Z
+PROPS-END
+
+Node-path: trunk/foo
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 4
+Text-content-md5: d3b07384d113edec49eaa6238ad5ff00
+Text-content-sha1: f1d2d2f924e986ac86fdf7b36c94bcdf32beec15
+Content-length: 14
+
+PROPS-END
+foo
+
+
+Revision-number: 3
+Prop-content-length: 113
+Content-length: 113
+
+K 7
+svn:log
+V 12
+delete trunk
+K 10
+svn:author
+V 6
+bryano
+K 8
+svn:date
+V 27
+2012-05-16T22:55:59.058026Z
+PROPS-END
+
+Node-path: trunk
+Node-action: delete
+
+
+Revision-number: 4
+Prop-content-length: 114
+Content-length: 114
+
+K 7
+svn:log
+V 13
+restore trunk
+K 10
+svn:author
+V 6
+bryano
+K 8
+svn:date
+V 27
+2012-05-16T22:56:01.055887Z
+PROPS-END
+
+Node-path: trunk
+Node-kind: dir
+Node-action: add
+Node-copyfrom-rev: 2
+Node-copyfrom-path: trunk
+
+
+Revision-number: 5
+Prop-content-length: 115
+Content-length: 115
+
+K 7
+svn:log
+V 14
+append to file
+K 10
+svn:author
+V 6
+bryano
+K 8
+svn:date
+V 27
+2012-05-16T22:56:02.060991Z
+PROPS-END
+
+Node-path: trunk/foo
+Node-kind: file
+Node-action: change
+Text-content-length: 8
+Text-content-md5: f47c75614087a8dd938ba4acff252494
+Text-content-sha1: 4e48e2c9a3d2ca8a708cb0cc545700544efb5021
+Content-length: 8
+
+foo
+bar
+
+
diff --git a/tests/fixtures/emptyrepo2.sh b/tests/fixtures/emptyrepo2.sh
new file mode 100755
index 0000000..a29afdd
--- /dev/null
+++ b/tests/fixtures/emptyrepo2.sh
@@ -0,0 +1,44 @@
+#!/bin/sh
+#
+# Create emptyrepo2.svndump
+#
+# The generated repository contains a sequence of empty revisions
+# created with a combination of svnsync and filtering
+
+mkdir temp
+cd temp
+
+mkdir project-orig
+cd project-orig
+mkdir -p sub/trunk other
+echo a > other/a
+cd ..
+
+svnadmin create testrepo
+svnurl=file://`pwd`/testrepo
+svn import project-orig $svnurl -m init
+
+svn co $svnurl project
+cd project
+echo a >> other/a
+svn ci -m othera
+echo a >> other/a
+svn ci -m othera2
+echo b > sub/trunk/a
+svn add sub/trunk/a
+svn ci -m adda
+cd ..
+
+svnadmin create testrepo2
+cat > testrepo2/hooks/pre-revprop-change <<EOF
+#!/bin/sh
+exit 0
+EOF
+chmod +x testrepo2/hooks/pre-revprop-change
+
+svnurl2=file://`pwd`/testrepo2
+svnsync init --username svnsync $svnurl2 $svnurl/sub
+svnsync sync $svnurl2
+
+svnadmin dump testrepo2 > ../emptyrepo2.svndump
+
diff --git a/tests/fixtures/emptyrepo2.svndump b/tests/fixtures/emptyrepo2.svndump
new file mode 100644
index 0000000..3f6e553
--- /dev/null
+++ b/tests/fixtures/emptyrepo2.svndump
@@ -0,0 +1,129 @@
+SVN-fs-dump-format-version: 2
+
+UUID: 293d1f29-635d-48b8-9cdf-468fd987067a
+
+Revision-number: 0
+Prop-content-length: 261
+Content-length: 261
+
+K 8
+svn:date
+V 27
+2012-10-03T18:58:42.535317Z
+K 17
+svn:sync-from-url
+V 74
+file:///Users/pmezard/dev/hg/hgsubversion/tests/fixtures/temp/testrepo/sub
+K 18
+svn:sync-from-uuid
+V 36
+241badf9-093f-4e71-8a58-1028abf52758
+K 24
+svn:sync-last-merged-rev
+V 1
+4
+PROPS-END
+
+Revision-number: 1
+Prop-content-length: 105
+Content-length: 105
+
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2012-10-03T18:58:42.556405Z
+K 7
+svn:log
+V 4
+init
+PROPS-END
+
+Node-path: sub
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Node-path: sub/trunk
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Revision-number: 2
+Prop-content-length: 107
+Content-length: 107
+
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2012-10-03T18:58:43.040912Z
+K 7
+svn:log
+V 6
+othera
+PROPS-END
+
+Revision-number: 3
+Prop-content-length: 108
+Content-length: 108
+
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2012-10-03T18:58:44.042124Z
+K 7
+svn:log
+V 7
+othera2
+PROPS-END
+
+Revision-number: 4
+Prop-content-length: 105
+Content-length: 105
+
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2012-10-03T18:58:45.053459Z
+K 7
+svn:log
+V 4
+adda
+PROPS-END
+
+Node-path: sub/trunk/a
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 2
+Text-content-md5: 3b5d5c3712955042212316173ccf37be
+Text-content-sha1: 89e6c98d92887913cadf06b2adb97f26cde4849b
+Content-length: 12
+
+PROPS-END
+b
+
+
diff --git a/tests/fixtures/invalid_utf8.sh b/tests/fixtures/invalid_utf8.sh
new file mode 100755
index 0000000..76dd9f8
--- /dev/null
+++ b/tests/fixtures/invalid_utf8.sh
@@ -0,0 +1,34 @@
+#!/bin/bash
+#-*- coding: utf-8 -*-
+#
+# Generate invalid_utf8.svndump
+#
+
+#check svnadmin version, must be >= 1.7
+SVNVERSION=$(svnadmin --version | head -n 1 | cut -d \ -f 3)
+if [[ "$SVNVERSION" < '1.7' ]] ; then
+ echo "You MUST have svn 1.7 or above to use this script"
+ exit 1
+fi
+
+set -x
+
+TMPDIR=$(mktemp -d)
+WD=$(pwd)
+
+cd $TMPDIR
+
+svnadmin create failrepo
+svn co file://$PWD/failrepo fail
+(
+ cd fail
+ touch A
+ svn add A
+ svn ci -m blabargrod
+)
+svnadmin --pre-1.6-compatible create invalid_utf8
+svnadmin dump failrepo | \
+ sed "s/blabargrod/$(echo blåbærgrød | iconv -f utf-8 -t latin1)/g" | \
+ svnadmin load --bypass-prop-validation invalid_utf8
+
+tar cz -C invalid_utf8 -f "$WD"/invalid_utf8.tar.gz .
diff --git a/tests/fixtures/invalid_utf8.tar.gz b/tests/fixtures/invalid_utf8.tar.gz
new file mode 100644
index 0000000..537021f
--- /dev/null
+++ b/tests/fixtures/invalid_utf8.tar.gz
Binary files differ
diff --git a/tests/fixtures/movetotrunk.sh b/tests/fixtures/movetotrunk.sh
new file mode 100755
index 0000000..b27572c
--- /dev/null
+++ b/tests/fixtures/movetotrunk.sh
@@ -0,0 +1,34 @@
+#!/bin/sh
+#
+# Generate movetotrunk.svndump
+#
+
+mkdir temp
+cd temp
+
+mkdir project-orig
+cd project-orig
+cd ..
+
+svnadmin create testrepo
+svnurl=file://`pwd`/testrepo
+svn mkdir --parents $svnurl/sub1/sub2 -m subpaths
+svn import project-orig $svnurl/sub1/sub2 -m "init project"
+
+svn co $svnurl/sub1/sub2 project
+cd project
+echo a > a
+svn add a
+mkdir dir
+echo b > dir/b
+svn add dir
+svn ci -m adda
+svn up
+mkdir trunk
+svn add trunk
+svn mv a trunk/a
+svn mv dir trunk/dir
+svn ci -m 'move to trunk'
+cd ..
+
+svnadmin dump testrepo > ../movetotrunk.svndump
diff --git a/tests/fixtures/movetotrunk.svndump b/tests/fixtures/movetotrunk.svndump
new file mode 100644
index 0000000..928a8f3
--- /dev/null
+++ b/tests/fixtures/movetotrunk.svndump
@@ -0,0 +1,154 @@
+SVN-fs-dump-format-version: 2
+
+UUID: bb3f8dfd-83a8-4fe0-b57e-00a3838532ab
+
+Revision-number: 0
+Prop-content-length: 56
+Content-length: 56
+
+K 8
+svn:date
+V 27
+2012-10-20T20:23:15.254324Z
+PROPS-END
+
+Revision-number: 1
+Prop-content-length: 109
+Content-length: 109
+
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2012-10-20T20:23:15.271492Z
+K 7
+svn:log
+V 8
+subpaths
+PROPS-END
+
+Node-path: sub1
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Node-path: sub1/sub2
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Revision-number: 2
+Prop-content-length: 105
+Content-length: 105
+
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2012-10-20T20:23:16.068226Z
+K 7
+svn:log
+V 4
+adda
+PROPS-END
+
+Node-path: sub1/sub2/a
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 2
+Text-content-md5: 60b725f10c9c85c70d97880dfe8191b3
+Text-content-sha1: 3f786850e387550fdab836ed7e6dc881de23001b
+Content-length: 12
+
+PROPS-END
+a
+
+
+Node-path: sub1/sub2/dir
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Node-path: sub1/sub2/dir/b
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 2
+Text-content-md5: 3b5d5c3712955042212316173ccf37be
+Text-content-sha1: 89e6c98d92887913cadf06b2adb97f26cde4849b
+Content-length: 12
+
+PROPS-END
+b
+
+
+Revision-number: 3
+Prop-content-length: 115
+Content-length: 115
+
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2012-10-20T20:23:20.043626Z
+K 7
+svn:log
+V 13
+move to trunk
+PROPS-END
+
+Node-path: sub1/sub2/trunk
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Node-path: sub1/sub2/trunk/a
+Node-kind: file
+Node-action: add
+Node-copyfrom-rev: 2
+Node-copyfrom-path: sub1/sub2/a
+Text-copy-source-md5: 60b725f10c9c85c70d97880dfe8191b3
+Text-copy-source-sha1: 3f786850e387550fdab836ed7e6dc881de23001b
+
+
+Node-path: sub1/sub2/trunk/dir
+Node-kind: dir
+Node-action: add
+Node-copyfrom-rev: 2
+Node-copyfrom-path: sub1/sub2/dir
+
+
+Node-path: sub1/sub2/dir
+Node-action: delete
+
+
+Node-path: sub1/sub2/a
+Node-action: delete
+
+
diff --git a/tests/fixtures/revert.sh b/tests/fixtures/revert.sh
new file mode 100755
index 0000000..aaab485
--- /dev/null
+++ b/tests/fixtures/revert.sh
@@ -0,0 +1,39 @@
+#!/bin/sh
+#
+# Generate revert.svndump
+#
+
+rm -rf temp
+mkdir temp
+cd temp
+mkdir -p import/trunk/dir
+cd import/trunk
+echo a > a
+echo b > dir/b
+cd ../..
+
+svnadmin create testrepo
+svnurl=file://`pwd`/testrepo
+svn import import $svnurl -m init
+
+svn co $svnurl project
+cd project
+echo a >> trunk/a
+echo b >> trunk/dir/b
+svn ci -m changefiles
+svn up
+# Test directory revert
+svn rm trunk
+svn cp $svnurl/trunk@1 trunk
+svn st
+svn ci -m revert
+svn up
+# Test file revert
+svn rm trunk/a
+svn rm trunk/dir/b
+svn cp $svnurl/trunk/a@2 trunk/a
+svn cp $svnurl/trunk/dir/b@2 trunk/dir/b
+svn ci -m revert2
+cd ..
+
+svnadmin dump testrepo > ../revert.svndump
diff --git a/tests/fixtures/revert.svndump b/tests/fixtures/revert.svndump
new file mode 100644
index 0000000..2a368ae
--- /dev/null
+++ b/tests/fixtures/revert.svndump
@@ -0,0 +1,197 @@
+SVN-fs-dump-format-version: 2
+
+UUID: 307f02f4-2d74-44cb-98a4-4e162241d396
+
+Revision-number: 0
+Prop-content-length: 56
+Content-length: 56
+
+K 8
+svn:date
+V 27
+2012-10-06T08:50:46.559327Z
+PROPS-END
+
+Revision-number: 1
+Prop-content-length: 105
+Content-length: 105
+
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2012-10-06T08:50:46.581582Z
+K 7
+svn:log
+V 4
+init
+PROPS-END
+
+Node-path: trunk
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Node-path: trunk/a
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 2
+Text-content-md5: 60b725f10c9c85c70d97880dfe8191b3
+Text-content-sha1: 3f786850e387550fdab836ed7e6dc881de23001b
+Content-length: 12
+
+PROPS-END
+a
+
+
+Node-path: trunk/dir
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Node-path: trunk/dir/b
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 2
+Text-content-md5: 3b5d5c3712955042212316173ccf37be
+Text-content-sha1: 89e6c98d92887913cadf06b2adb97f26cde4849b
+Content-length: 12
+
+PROPS-END
+b
+
+
+Revision-number: 2
+Prop-content-length: 113
+Content-length: 113
+
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2012-10-06T08:50:47.048033Z
+K 7
+svn:log
+V 11
+changefiles
+PROPS-END
+
+Node-path: trunk/a
+Node-kind: file
+Node-action: change
+Text-content-length: 4
+Text-content-md5: 0d227f1abf8c2932d342e9b99cc957eb
+Text-content-sha1: d7c8127a20a396cff08af086a1c695b0636f0c29
+Content-length: 4
+
+a
+a
+
+
+Node-path: trunk/dir/b
+Node-kind: file
+Node-action: change
+Text-content-length: 4
+Text-content-md5: 06ac26ed8b614fc0b141e4542aa067c2
+Text-content-sha1: f6980469e74f7125178e88ec571e06fe6ce86e95
+Content-length: 4
+
+b
+b
+
+
+Revision-number: 3
+Prop-content-length: 107
+Content-length: 107
+
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2012-10-06T08:50:50.058224Z
+K 7
+svn:log
+V 6
+revert
+PROPS-END
+
+Node-path: trunk
+Node-kind: dir
+Node-action: delete
+
+Node-path: trunk
+Node-kind: dir
+Node-action: add
+Node-copyfrom-rev: 1
+Node-copyfrom-path: trunk
+
+
+
+
+Revision-number: 4
+Prop-content-length: 108
+Content-length: 108
+
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2012-10-06T08:50:54.047396Z
+K 7
+svn:log
+V 7
+revert2
+PROPS-END
+
+Node-path: trunk/a
+Node-kind: file
+Node-action: delete
+
+Node-path: trunk/a
+Node-kind: file
+Node-action: add
+Node-copyfrom-rev: 2
+Node-copyfrom-path: trunk/a
+Text-copy-source-md5: 0d227f1abf8c2932d342e9b99cc957eb
+Text-copy-source-sha1: d7c8127a20a396cff08af086a1c695b0636f0c29
+
+
+
+
+Node-path: trunk/dir/b
+Node-kind: file
+Node-action: delete
+
+Node-path: trunk/dir/b
+Node-kind: file
+Node-action: add
+Node-copyfrom-rev: 2
+Node-copyfrom-path: trunk/dir/b
+Text-copy-source-md5: 06ac26ed8b614fc0b141e4542aa067c2
+Text-copy-source-sha1: f6980469e74f7125178e88ec571e06fe6ce86e95
+
+
+
+
diff --git a/tests/fixtures/subdir_is_file_prefix.svndump b/tests/fixtures/subdir_is_file_prefix.svndump
new file mode 100644
index 0000000..c09b45a
--- /dev/null
+++ b/tests/fixtures/subdir_is_file_prefix.svndump
@@ -0,0 +1,72 @@
+SVN-fs-dump-format-version: 2
+
+UUID: 924a052a-5e5a-4a8e-a677-da5565bec340
+
+Revision-number: 0
+Prop-content-length: 56
+Content-length: 56
+
+K 8
+svn:date
+V 27
+2011-03-04T12:33:29.342045Z
+PROPS-END
+
+Revision-number: 1
+Prop-content-length: 123
+Content-length: 123
+
+K 7
+svn:log
+V 22
+Create directory flaf.
+K 10
+svn:author
+V 6
+danchr
+K 8
+svn:date
+V 27
+2011-03-04T12:34:00.349950Z
+PROPS-END
+
+Node-path: flaf
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Revision-number: 2
+Prop-content-length: 138
+Content-length: 138
+
+K 7
+svn:log
+V 37
+Create the file flaf.txt within flaf.
+K 10
+svn:author
+V 6
+danchr
+K 8
+svn:date
+V 27
+2011-03-04T12:45:01.701033Z
+PROPS-END
+
+Node-path: flaf/flaf.txt
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 15
+Text-content-md5: 8c0059c8f7998e8003836b8e8fcb74d7
+Text-content-sha1: b7d680bc5411f46395c4ef267001e1a307d7b0d5
+Content-length: 25
+
+PROPS-END
+Goodbye world.
+
+
diff --git a/tests/run.py b/tests/run.py
index 98cf0a6..3832633 100644
--- a/tests/run.py
+++ b/tests/run.py
@@ -18,26 +18,29 @@ def tests():
import test_fetch_renames
import test_fetch_symlinks
import test_fetch_truncated
+ import test_hooks
import test_pull
+ import test_pull_fallback
import test_push_command
import test_push_renames
import test_push_dirs
import test_push_eol
+ import test_push_autoprops
import test_rebuildmeta
import test_single_dir_clone
- import test_startrev
import test_svnwrap
import test_tags
import test_template_keywords
import test_utility_commands
import test_unaffected_core
+ import test_updatemeta
import test_urls
sys.path.append(os.path.dirname(__file__))
sys.path.append(os.path.join(os.path.dirname(__file__), 'comprehensive'))
import test_stupid_pull
- import test_verify
+ import test_verify_and_startrev
return locals()
diff --git a/tests/test_fetch_branches.py b/tests/test_fetch_branches.py
index 7a9287c..18fdd40 100644
--- a/tests/test_fetch_branches.py
+++ b/tests/test_fetch_branches.py
@@ -58,8 +58,9 @@ class TestFetchBranches(test_util.TestBase):
self.test_unorderedbranch(True)
def test_renamed_branch_to_trunk(self, stupid=False):
+ config = {'hgsubversion.failonmissing': 'true'}
repo = self._load_fixture_and_fetch('branch_rename_to_trunk.svndump',
- stupid=stupid)
+ stupid=stupid, config=config)
self.assertEqual(repo['default'].parents()[0].branch(), 'dev_branch')
self.assert_('iota' in repo['default'])
self.assertEqual(repo['old_trunk'].parents()[0].branch(), 'default')
diff --git a/tests/test_fetch_command.py b/tests/test_fetch_command.py
index b4e3fce..b1683fc 100644
--- a/tests/test_fetch_command.py
+++ b/tests/test_fetch_command.py
@@ -8,6 +8,7 @@ from mercurial import commands
from mercurial import hg
from mercurial import node
from mercurial import ui
+from mercurial import encoding
class TestBasicRepoLayout(test_util.TestBase):
@@ -94,13 +95,16 @@ class TestBasicRepoLayout(test_util.TestBase):
assert 'README' not in repo
assert '../branches' not in repo
- def test_files_copied_from_outside_btt(self):
+ def test_files_copied_from_outside_btt(self, stupid=False):
repo = self._load_fixture_and_fetch(
- 'test_files_copied_from_outside_btt.svndump')
+ 'test_files_copied_from_outside_btt.svndump', stupid=stupid)
self.assertEqual(node.hex(repo['tip'].node()),
'3c78170e30ddd35f2c32faa0d8646ab75bba4f73')
self.assertEqual(len(repo.changelog), 2)
+ def test_files_copied_from_outside_btt_stupid(self):
+ self.test_files_copied_from_outside_btt(stupid=True)
+
def test_file_renamed_in_from_outside_btt(self):
repo = self._load_fixture_and_fetch(
'file_renamed_in_from_outside_btt.svndump')
@@ -175,7 +179,8 @@ class TestBasicRepoLayout(test_util.TestBase):
self.assertEqual(repo[r].hex(), repo2[r].hex())
def test_path_quoting_stupid(self):
- self.test_path_quoting(True)
+ repo = self.test_path_quoting(True)
+
def test_identical_fixtures(self):
'''ensure that the non_ascii_path_N fixtures are identical'''
@@ -186,6 +191,14 @@ class TestBasicRepoLayout(test_util.TestBase):
self.assertMultiLineEqual(open(fixturepaths[0]).read(),
open(fixturepaths[1]).read())
+ def test_invalid_message(self):
+ repo = self._load_fixture_and_fetch('invalid_utf8.tar.gz')
+ # changelog returns descriptions in local encoding
+ desc = encoding.fromlocal(repo[0].description())
+ self.assertEqual(desc.decode('utf8'),
+ u'bl\xe5b\xe6rgr\xf8d')
+
+
class TestStupidPull(test_util.TestBase):
def test_stupid(self):
repo = self._load_fixture_and_fetch('two_heads.svndump', stupid=True)
@@ -216,6 +229,63 @@ class TestStupidPull(test_util.TestBase):
self.assertEqual(node.hex(repo['tip'].node()),
'1a6c3f30911d57abb67c257ec0df3e7bc44786f7')
+ def test_empty_repo(self, stupid=False):
+ # This used to crash HgEditor because it could be closed without
+ # having been initialized again.
+ self._load_fixture_and_fetch('emptyrepo2.svndump', stupid=stupid)
+
+ def test_empty_repo_stupid(self):
+ self.test_empty_repo(stupid=True)
+
+ def test_fetch_revert(self, stupid=False):
+ repo = self._load_fixture_and_fetch('revert.svndump', stupid=stupid)
+ graph = self.getgraph(repo)
+ refgraph = """\
+o changeset: 3:937dcd1206d4
+| branch:
+| tags: tip
+| summary: revert2
+| files: a dir/b
+|
+o changeset: 2:9317a748b7c3
+| branch:
+| tags:
+| summary: revert
+| files: a dir/b
+|
+o changeset: 1:243259a4138a
+| branch:
+| tags:
+| summary: changefiles
+| files: a dir/b
+|
+o changeset: 0:ab86791fc857
+ branch:
+ tags:
+ summary: init
+ files: a dir/b
+"""
+ self.assertEqual(refgraph.strip(), graph.strip())
+
+ def test_fetch_revert_stupid(self):
+ self.test_fetch_revert(stupid=True)
+
+ def test_fetch_movetotrunk(self, stupid=False):
+ repo = self._load_fixture_and_fetch('movetotrunk.svndump',
+ stupid=stupid, subdir='sub1/sub2')
+ graph = self.getgraph(repo)
+ refgraph = """\
+o changeset: 0:02996a5980ba
+ branch:
+ tags: tip
+ summary: move to trunk
+ files: a dir/b
+"""
+ self.assertEqual(refgraph.strip(), graph.strip())
+
+ def test_fetch_movetotrunk_stupid(self):
+ self.test_fetch_movetotrunk(stupid=True)
+
def suite():
all_tests = [unittest.TestLoader().loadTestsFromTestCase(TestBasicRepoLayout),
unittest.TestLoader().loadTestsFromTestCase(TestStupidPull),
diff --git a/tests/test_fetch_mappings.py b/tests/test_fetch_mappings.py
index 02727f6..267515c 100644
--- a/tests/test_fetch_mappings.py
+++ b/tests/test_fetch_mappings.py
@@ -13,6 +13,7 @@ from mercurial import util as hgutil
from hgsubversion import maps
from hgsubversion import svncommands
from hgsubversion import util
+from hgsubversion import verify
class MapTests(test_util.TestBase):
@property
@@ -100,49 +101,43 @@ class MapTests(test_util.TestBase):
all_tests = set(test)
self.assertEqual(fromself.symmetric_difference(all_tests), set())
- def test_file_map(self, stupid=False):
- repo_path = self.load_svndump('replace_trunk_with_branch.svndump')
+ def _loadwithfilemap(self, svndump, filemapcontent, stupid=False,
+ failonmissing=True):
+ repo_path = self.load_svndump(svndump)
filemap = open(self.filemap, 'w')
- filemap.write("include alpha\n")
+ filemap.write(filemapcontent)
filemap.close()
ui = self.ui(stupid)
ui.setconfig('hgsubversion', 'filemap', self.filemap)
+ ui.setconfig('hgsubversion', 'failoninvalidreplayfile', 'true')
+ ui.setconfig('hgsubversion', 'failonmissing', failonmissing)
commands.clone(ui, test_util.fileurl(repo_path),
self.wc_path, filemap=self.filemap)
- self.assertEqual(node.hex(self.repo[0].node()), '88e2c7492d83e4bf30fbb2dcbf6aa24d60ac688d')
- self.assertEqual(node.hex(self.repo['default'].node()), 'e524296152246b3837fe9503c83b727075835155')
+ return self.repo
+
+ def test_file_map(self, stupid=False):
+ repo = self._loadwithfilemap('replace_trunk_with_branch.svndump',
+ "include alpha\n", stupid)
+ self.assertEqual(node.hex(repo[0].node()), '88e2c7492d83e4bf30fbb2dcbf6aa24d60ac688d')
+ self.assertEqual(node.hex(repo['default'].node()), 'e524296152246b3837fe9503c83b727075835155')
def test_file_map_stupid(self):
# TODO: re-enable test if we ever reinstate this feature
self.assertRaises(hgutil.Abort, self.test_file_map, True)
def test_file_map_exclude(self, stupid=False):
- repo_path = self.load_svndump('replace_trunk_with_branch.svndump')
- filemap = open(self.filemap, 'w')
- filemap.write("exclude alpha\n")
- filemap.close()
- ui = self.ui(stupid)
- ui.setconfig('hgsubversion', 'filemap', self.filemap)
- commands.clone(ui, test_util.fileurl(repo_path),
- self.wc_path, filemap=self.filemap)
- self.assertEqual(node.hex(self.repo[0].node()), '2c48f3525926ab6c8b8424bcf5eb34b149b61841')
- self.assertEqual(node.hex(self.repo['default'].node()), 'b37a3c0297b71f989064d9b545b5a478bbed7cc1')
+ repo = self._loadwithfilemap('replace_trunk_with_branch.svndump',
+ "exclude alpha\n", stupid)
+ self.assertEqual(node.hex(repo[0].node()), '2c48f3525926ab6c8b8424bcf5eb34b149b61841')
+ self.assertEqual(node.hex(repo['default'].node()), 'b37a3c0297b71f989064d9b545b5a478bbed7cc1')
def test_file_map_exclude_stupid(self):
# TODO: re-enable test if we ever reinstate this feature
self.assertRaises(hgutil.Abort, self.test_file_map_exclude, True)
def test_file_map_rule_order(self):
- repo_path = self.load_svndump('replace_trunk_with_branch.svndump')
- filemap = open(self.filemap, 'w')
- filemap.write("exclude alpha\n")
- filemap.write("include .\n")
- filemap.write("exclude gamma\n")
- filemap.close()
- ui = self.ui(False)
- ui.setconfig('hgsubversion', 'filemap', self.filemap)
- commands.clone(ui, test_util.fileurl(repo_path),
- self.wc_path, filemap=self.filemap)
+ repo = self._loadwithfilemap('replace_trunk_with_branch.svndump',
+ "exclude alpha\ninclude .\nexclude gamma\n")
# The exclusion of alpha is overridden by the later rule to
# include all of '.', whereas gamma should remain excluded
# because it's excluded after the root directory.
@@ -151,6 +146,33 @@ class MapTests(test_util.TestBase):
self.assertEqual(self.repo['default'].manifest().keys(),
['alpha', 'beta'])
+ def test_file_map_copy(self):
+ # Exercise excluding files copied from a non-excluded directory.
+ # There will be missing files as we are copying from an excluded
+ # directory.
+ repo = self._loadwithfilemap('copies.svndump', "exclude dir2\n",
+ failonmissing=False)
+ self.assertEqual(['dir/a', 'dir3/a'], list(repo[2]))
+
+ def test_file_map_exclude_copy_source_and_dest(self):
+ # dir3 is excluded and copied from dir2 which is also excluded.
+ # dir3 files should not be marked as missing and fetched.
+ repo = self._loadwithfilemap('copies.svndump',
+ "exclude dir2\nexclude dir3\n")
+ self.assertEqual(['dir/a'], list(repo[2]))
+
+ def test_file_map_include_file_exclude_dir(self):
+ # dir3 is excluded but we want dir3/a, which is also copied from
+ # an exluded dir2. dir3/a should be fetched.
+ repo = self._loadwithfilemap('copies.svndump',
+ "include .\nexclude dir2\nexclude dir3\ninclude dir3/a\n",
+ failonmissing=False)
+ self.assertEqual(['dir/a', 'dir3/a'], list(repo[2]))
+
+ def test_file_map_delete_dest(self):
+ repo = self._loadwithfilemap('copies.svndump', 'exclude dir3\n')
+ self.assertEqual(['dir/a', 'dir2/a'], list(repo[3]))
+
def test_branchmap(self, stupid=False):
repo_path = self.load_svndump('branchmap.svndump')
branchmap = open(self.branchmap, 'w')
@@ -244,6 +266,8 @@ class MapTests(test_util.TestBase):
ui = self.ui(stupid)
src, dest = test_util.hgclone(ui, self.wc_path, self.wc_path + '_clone',
update=False)
+ src = test_util.getlocalpeer(src)
+ dest = test_util.getlocalpeer(dest)
svncommands.rebuildmeta(ui, dest,
args=[test_util.fileurl(repo_path)])
@@ -270,7 +294,7 @@ class MapTests(test_util.TestBase):
repo = self.repo
for r in repo:
- self.assertEquals(svncommands.verify(ui, repo, rev=r), 0)
+ self.assertEquals(verify.verify(ui, repo, rev=r), 0)
def test_branchmap_verify_stupid(self):
'''test verify on a branchmapped clone (stupid)'''
diff --git a/tests/test_fetch_renames.py b/tests/test_fetch_renames.py
index 64b69d3..625e48d 100644
--- a/tests/test_fetch_renames.py
+++ b/tests/test_fetch_renames.py
@@ -14,8 +14,11 @@ class TestFetchRenames(test_util.TestBase):
w('%s: %r %r\n' % (f, fctx.data(), fctx.renamed()))
def _test_rename(self, stupid):
- repo = self._load_fixture_and_fetch('renames.svndump', stupid=stupid)
- # self._debug_print_copies(repo)
+ config = {
+ 'hgsubversion.filestoresize': '0',
+ }
+ repo = self._load_fixture_and_fetch('renames.svndump', stupid=stupid,
+ config=config)
# Map revnum to mappings of dest name to (source name, dest content)
copies = {
diff --git a/tests/test_fetch_symlinks.py b/tests/test_fetch_symlinks.py
index 7f9252b..42d5518 100644
--- a/tests/test_fetch_symlinks.py
+++ b/tests/test_fetch_symlinks.py
@@ -50,7 +50,17 @@ class TestFetchSymlinks(test_util.TestBase):
def test_symlinks_stupid(self):
self.test_symlinks(True)
+class TestMergeSpecial(test_util.TestBase):
+ def test_special(self):
+ repo = self._load_fixture_and_fetch('addspecial.svndump',
+ subdir='trunk')
+ ctx = repo['tip']
+ self.assertEqual(ctx['fnord'].flags(), 'l')
+ self.assertEqual(ctx['exe'].flags(), 'x')
+
def suite():
- all_tests = [unittest.TestLoader().loadTestsFromTestCase(TestFetchSymlinks),
- ]
+ all_tests = [
+ unittest.TestLoader().loadTestsFromTestCase(TestFetchSymlinks),
+ unittest.TestLoader().loadTestsFromTestCase(TestMergeSpecial),
+ ]
return unittest.TestSuite(all_tests)
diff --git a/tests/test_helpers.py b/tests/test_helpers.py
new file mode 100644
index 0000000..ebcb381
--- /dev/null
+++ b/tests/test_helpers.py
@@ -0,0 +1,37 @@
+import os, sys, unittest
+
+_rootdir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+sys.path.insert(0, _rootdir)
+
+from hgsubversion import editor
+
+class TestHelpers(unittest.TestCase):
+ def test_filestore(self):
+ fs = editor.FileStore(2)
+ fs.setfile('a', 'a')
+ fs.setfile('b', 'b')
+ self.assertEqual('a', fs._data.get('a'))
+ self.assertEqual('b', fs._data.get('b'))
+
+ fs.delfile('b')
+ self.assertRaises(IOError, lambda: fs.getfile('b'))
+ fs.setfile('bb', 'bb')
+ self.assertTrue('bb' in fs._files)
+ self.assertTrue('bb' not in fs._data)
+ self.assertEqual('bb', fs.getfile('bb'))
+
+ fs.delfile('bb')
+ self.assertTrue('bb' not in fs._files)
+ self.assertEqual([], os.listdir(fs._tempdir))
+ self.assertRaises(IOError, lambda: fs.getfile('bb'))
+
+ fs.setfile('bb', 'bb')
+ self.assertEqual(1, len(os.listdir(fs._tempdir)))
+ fs.popfile('bb')
+ self.assertEqual([], os.listdir(fs._tempdir))
+ self.assertRaises(editor.EditingError, lambda: fs.getfile('bb'))
+
+def suite():
+ return unittest.TestSuite([
+ unittest.TestLoader().loadTestsFromTestCase(TestHelpers),
+ ])
diff --git a/tests/test_hooks.py b/tests/test_hooks.py
new file mode 100644
index 0000000..bff3730
--- /dev/null
+++ b/tests/test_hooks.py
@@ -0,0 +1,48 @@
+import sys
+import test_util
+import unittest
+
+from mercurial import hg
+from mercurial import commands
+
+class TestHooks(test_util.TestBase):
+ def setUp(self):
+ super(TestHooks, self).setUp()
+
+ def _loadupdate(self, fixture_name, *args, **kwargs):
+ kwargs = kwargs.copy()
+ kwargs.update(stupid=False, noupdate=False)
+ repo, repo_path = self.load_and_fetch(fixture_name, *args, **kwargs)
+ return repo, repo_path
+
+ def test_updatemetahook(self):
+ repo, repo_path = self._loadupdate('single_rev.svndump')
+ state = repo.parents()
+ self.add_svn_rev(repo_path, {'trunk/alpha': 'Changed'})
+ commands.pull(self.repo.ui, self.repo)
+
+ # Clone to a new repository and add a hook
+ new_wc_path = "%s-2" % self.wc_path
+ commands.clone(self.repo.ui, self.wc_path, new_wc_path)
+ newrepo = hg.repository(test_util.testui(), new_wc_path)
+ newrepo.ui.setconfig('hooks', 'changegroup.meta',
+ 'python:hgsubversion.hooks.updatemeta.hook')
+
+ # Commit a rev that should trigger svn meta update
+ self.add_svn_rev(repo_path, {'trunk/alpha': 'Changed Again'})
+ commands.pull(self.repo.ui, self.repo)
+
+ self.called = False
+ import hgsubversion.svncommands
+ oldupdatemeta = hgsubversion.svncommands.updatemeta
+ def _updatemeta(ui, repo, args=[]):
+ self.called = True
+ hgsubversion.svncommands.updatemeta = _updatemeta
+
+ # Pull and make sure our updatemeta function gets called
+ commands.pull(newrepo.ui, newrepo)
+ hgsubversion.svncommands.updatemeta = oldupdatemeta
+ self.assertTrue(self.called)
+
+def suite():
+ return unittest.findTestCases(sys.modules[__name__])
diff --git a/tests/test_pull.py b/tests/test_pull.py
index 556fbf1..ebfe85a 100644
--- a/tests/test_pull.py
+++ b/tests/test_pull.py
@@ -6,14 +6,16 @@ from mercurial import node
from mercurial import ui
from mercurial import util as hgutil
from mercurial import commands
+from hgsubversion import verify
class TestPull(test_util.TestBase):
def setUp(self):
super(TestPull, self).setUp()
- def _loadupdate(self, fixture_name):
- repo, repo_path = self.load_and_fetch(fixture_name, stupid=False,
- noupdate=False)
+ def _loadupdate(self, fixture_name, *args, **kwargs):
+ kwargs = kwargs.copy()
+ kwargs.update(stupid=False, noupdate=False)
+ repo, repo_path = self.load_and_fetch(fixture_name, *args, **kwargs)
return repo, repo_path
def test_nochanges(self):
@@ -58,6 +60,26 @@ class TestPull(test_util.TestBase):
commands.pull(repo.ui, repo)
self.assertEqual(oldheads, map(node.hex, repo.heads()))
+ def test_skip_basic(self):
+ repo, repo_path = self._loadupdate('single_rev.svndump')
+ self.add_svn_rev(repo_path, {'trunk/alpha': 'Changed'})
+ self.add_svn_rev(repo_path, {'trunk/beta': 'More changed'})
+ self.add_svn_rev(repo_path, {'trunk/gamma': 'Even more changeder'})
+ repo.ui.setconfig('hgsubversion', 'unsafeskip', '3 4')
+ commands.pull(repo.ui, repo)
+ tip = repo['tip'].rev()
+ self.assertEqual(tip, 1)
+ self.assertEquals(verify.verify(repo.ui, repo, rev=tip), 1)
+
+ def test_skip_delete_restore(self):
+ repo, repo_path = self._loadupdate('delete_restore_trunk.svndump',
+ rev=2)
+ repo.ui.setconfig('hgsubversion', 'unsafeskip', '3 4')
+ commands.pull(repo.ui, repo)
+ tip = repo['tip'].rev()
+ self.assertEqual(tip, 1)
+ self.assertEquals(verify.verify(repo.ui, repo, rev=tip), 0)
+
def suite():
import unittest, sys
return unittest.findTestCases(sys.modules[__name__])
diff --git a/tests/test_pull_fallback.py b/tests/test_pull_fallback.py
new file mode 100644
index 0000000..e543d4e
--- /dev/null
+++ b/tests/test_pull_fallback.py
@@ -0,0 +1,106 @@
+import test_util
+
+import re
+import mercurial
+from mercurial import commands
+from hgsubversion import stupid
+from hgsubversion import svnwrap
+from hgsubversion import wrappers
+
+class TestPullFallback(test_util.TestBase):
+ def setUp(self):
+ super(TestPullFallback, self).setUp()
+
+ def _loadupdate(self, fixture_name, *args, **kwargs):
+ kwargs = kwargs.copy()
+ kwargs.update(noupdate=False)
+ repo, repo_path = self.load_and_fetch(fixture_name, *args, **kwargs)
+ return repo, repo_path
+
+ def test_stupid_fallback_to_stupid_fullrevs(self):
+ return
+ to_patch = {
+ 'mercurial.patch.patchbackend': _patchbackend_raise,
+ 'stupid.diff_branchrev': stupid.diff_branchrev,
+ 'stupid.fetch_branchrev': stupid.fetch_branchrev,
+ }
+
+ expected_calls = {
+ 'mercurial.patch.patchbackend': 1,
+ 'stupid.diff_branchrev': 1,
+ 'stupid.fetch_branchrev': 1,
+ }
+
+ repo, repo_path = self._loadupdate(
+ 'single_rev.svndump', stupid=True)
+
+ # Passing stupid=True doesn't seem to be working - force it
+ repo.ui.setconfig('hgsubversion', 'stupid', "true")
+ state = repo.parents()
+
+ calls, replaced = _monkey_patch(to_patch)
+
+ try:
+ self.add_svn_rev(repo_path, {'trunk/alpha': 'Changed'})
+ commands.pull(self.repo.ui, repo, update=True)
+ self.failIfEqual(state, repo.parents())
+ self.assertTrue('tip' in repo[None].tags())
+ self.assertEqual(expected_calls, calls)
+
+ finally:
+ _monkey_unpatch(replaced)
+
+def _monkey_patch(to_patch, start=None):
+ if start is None:
+ import sys
+ start = sys.modules[__name__]
+
+ calls = {}
+ replaced = {}
+
+ for path, replacement in to_patch.iteritems():
+ obj = start
+ owner, attr = path.rsplit('.', 1)
+
+ for a in owner.split('.', -1):
+ obj = getattr(obj, a)
+
+ replaced[path] = getattr(obj, attr)
+ calls[path] = 0
+
+ def outer(path=path, calls=calls, replacement=replacement):
+ def wrapper(*p, **kw):
+ calls[path] += 1
+ return replacement(*p, **kw)
+
+ return wrapper
+
+ setattr(obj, attr, outer())
+
+ return calls, replaced
+
+def _monkey_unpatch(to_patch, start=None):
+ if start is None:
+ import sys
+ start = sys.modules[__name__]
+
+ replaced = {}
+
+ for path, replacement in to_patch.iteritems():
+ obj = start
+ owner, attr = path.rsplit('.', 1)
+
+ for a in owner.split('.', -1):
+ obj = getattr(obj, a)
+
+ replaced[path] = getattr(obj, attr)
+ setattr(obj, attr, replacement)
+
+ return replaced
+
+def _patchbackend_raise(*p, **kw):
+ raise mercurial.patch.PatchError("patch failed")
+
+def suite():
+ import unittest, sys
+ return unittest.findTestCases(sys.modules[__name__])
diff --git a/tests/test_push_autoprops.py b/tests/test_push_autoprops.py
new file mode 100644
index 0000000..3dfba47
--- /dev/null
+++ b/tests/test_push_autoprops.py
@@ -0,0 +1,107 @@
+import subprocess
+import sys
+import unittest
+import os
+
+import test_util
+
+from hgsubversion import svnwrap
+
+class PushAutoPropsTests(test_util.TestBase):
+ def setUp(self):
+ test_util.TestBase.setUp(self)
+ repo, self.repo_path = self.load_and_fetch('emptyrepo.svndump')
+
+ def test_push_honors_svn_autoprops(self):
+ self.setup_svn_config(
+ "[miscellany]\n"
+ "enable-auto-props = yes\n"
+ "[auto-props]\n"
+ "*.py = test:prop=success\n")
+ changes = [('test.py', 'test.py', 'echo hallo')]
+ self.commitchanges(changes)
+ self.pushrevisions(True)
+ prop_val = test_util.svnpropget(
+ self.repo_path, "trunk/test.py", 'test:prop')
+ self.assertEqual('success', prop_val)
+
+
+class AutoPropsConfigTest(test_util.TestBase):
+ def test_use_autoprops_for_matching_file_when_enabled(self):
+ self.setup_svn_config(
+ "[miscellany]\n"
+ "enable-auto-props = yes\n"
+ "[auto-props]\n"
+ "*.py = test:prop=success\n")
+ props = self.new_autoprops_config().properties('xxx/test.py')
+ self.assertEqual({ 'test:prop': 'success'}, props)
+
+ def new_autoprops_config(self):
+ return svnwrap.AutoPropsConfig(self.config_dir)
+
+ def test_ignore_nonexisting_config(self):
+ config_file = os.path.join(self.config_dir, 'config')
+ os.remove(config_file)
+ self.assertTrue(not os.path.exists(config_file))
+ props = self.new_autoprops_config().properties('xxx/test.py')
+ self.assertEqual({}, props)
+
+ def test_ignore_autoprops_when_file_doesnt_match(self):
+ self.setup_svn_config(
+ "[miscellany]\n"
+ "enable-auto-props = yes\n"
+ "[auto-props]\n"
+ "*.py = test:prop=success\n")
+ props = self.new_autoprops_config().properties('xxx/test.sh')
+ self.assertEqual({}, props)
+
+ def test_ignore_autoprops_when_disabled(self):
+ self.setup_svn_config(
+ "[miscellany]\n"
+ "#enable-auto-props = yes\n"
+ "[auto-props]\n"
+ "*.py = test:prop=success\n")
+ props = self.new_autoprops_config().properties('xxx/test.py')
+ self.assertEqual({}, props)
+
+ def test_combine_properties_of_multiple_matches(self):
+ self.setup_svn_config(
+ "[miscellany]\n"
+ "enable-auto-props = yes\n"
+ "[auto-props]\n"
+ "*.py = test:prop=success\n"
+ "test.* = test:prop2=success\n")
+ props = self.new_autoprops_config().properties('xxx/test.py')
+ self.assertEqual({
+ 'test:prop': 'success', 'test:prop2': 'success'}, props)
+
+
+class ParseAutoPropsTests(test_util.TestBase):
+ def test_property_value_is_optional(self):
+ props = svnwrap.parse_autoprops("svn:executable")
+ self.assertEqual({'svn:executable': ''}, props)
+ props = svnwrap.parse_autoprops("svn:executable=")
+ self.assertEqual({'svn:executable': ''}, props)
+
+ def test_property_value_may_be_quoted(self):
+ props = svnwrap.parse_autoprops("svn:eol-style=\" native \"")
+ self.assertEqual({'svn:eol-style': ' native '}, props)
+ props = svnwrap.parse_autoprops("svn:eol-style=' native '")
+ self.assertEqual({'svn:eol-style': ' native '}, props)
+
+ def test_surrounding_whitespaces_are_ignored(self):
+ props = svnwrap.parse_autoprops(" svn:eol-style = native ")
+ self.assertEqual({'svn:eol-style': 'native'}, props)
+
+ def test_multiple_properties_are_separated_by_semicolon(self):
+ props = svnwrap.parse_autoprops(
+ "svn:eol-style=native;svn:executable=true\n")
+ self.assertEqual({
+ 'svn:eol-style': 'native',
+ 'svn:executable': 'true'},
+ props)
+
+
+def suite():
+ return unittest.findTestCases(sys.modules[__name__])
+
diff --git a/tests/test_push_command.py b/tests/test_push_command.py
index 8342100..1c41596 100644
--- a/tests/test_push_command.py
+++ b/tests/test_push_command.py
@@ -134,7 +134,7 @@ class PushTests(test_util.TestBase):
finally:
if sys.version_info >= (2,6):
svnserve.kill()
- else:
+ else:
test_util.kill_process(svnserve)
def test_push_over_svnserve(self):
@@ -487,7 +487,40 @@ class PushTests(test_util.TestBase):
'Outgoing changesets parent is not at subversion '
'HEAD\n'
'(pull again and rebase on a newer revision)')
+ # verify that any pending transactions on the server got cleaned up
+ self.assertEqual([], os.listdir(
+ os.path.join(self.tmpdir, 'testrepo-1', 'db', 'transactions')))
+ def test_push_encoding(self):
+ self.test_push_two_revs()
+ # Writing then rebasing UTF-8 filenames in a cp1252 windows console
+ # used to fail because hg internal encoding was being changed during
+ # the interactions with subversion, *and during the rebase*, which
+ # confused the dirstate and made it believe the file was deleted.
+ fn = 'pi\xc3\xa8ce/test'
+ changes = [(fn, fn, 'a')]
+ par = self.repo['tip'].rev()
+ self.commitchanges(changes, parent=par)
+ self.pushrevisions()
+
+ def test_push_emptying_changeset(self):
+ r = self.repo['tip']
+ changes = [
+ ('alpha', None, None),
+ ('beta', None, None),
+ ]
+ parent = self.repo['tip'].rev()
+ self.commitchanges(changes, parent=parent)
+ self.pushrevisions()
+ self.assertEqual({}, self.repo['tip'].manifest())
+
+ # Try to re-add a file after emptying the branch
+ changes = [
+ ('alpha', 'alpha', 'alpha'),
+ ]
+ self.commitchanges(changes, parent=self.repo['tip'].rev())
+ self.pushrevisions()
+ self.assertEqual(['alpha'], list(self.repo['tip'].manifest()))
def suite():
test_classes = [PushTests, ]
diff --git a/tests/test_rebuildmeta.py b/tests/test_rebuildmeta.py
index bee8e37..5e2de4b 100644
--- a/tests/test_rebuildmeta.py
+++ b/tests/test_rebuildmeta.py
@@ -34,6 +34,8 @@ def _do_case(self, name, stupid, single):
wc2_path = self.wc_path + '_clone'
u = ui.ui()
src, dest = test_util.hgclone(u, self.wc_path, wc2_path, update=False)
+ src = test_util.getlocalpeer(src)
+ dest = test_util.getlocalpeer(dest)
# insert a wrapper that prevents calling changectx.children()
def failfn(orig, ctx):
@@ -51,9 +53,48 @@ def _do_case(self, name, stupid, single):
# remove the wrapper
context.changectx.children = origchildren
+ self._run_assertions(name, stupid, single, src, dest, u)
+
+ wc3_path = self.wc_path + '_partial'
+ src, dest = test_util.hgclone(u,
+ self.wc_path,
+ wc3_path,
+ update=False,
+ rev=[0])
+ srcrepo = test_util.getlocalpeer(src)
+ dest = test_util.getlocalpeer(dest)
+
+ # insert a wrapper that prevents calling changectx.children()
+ extensions.wrapfunction(context.changectx, 'children', failfn)
+
+ try:
+ svncommands.rebuildmeta(u, dest,
+ args=[test_util.fileurl(repo_path +
+ subdir), ])
+ finally:
+ # remove the wrapper
+ context.changectx.children = origchildren
+
+ dest.pull(src)
+
+ # insert a wrapper that prevents calling changectx.children()
+ extensions.wrapfunction(context.changectx, 'children', failfn)
+ try:
+ svncommands.updatemeta(u, dest,
+ args=[test_util.fileurl(repo_path +
+ subdir), ])
+ finally:
+ # remove the wrapper
+ context.changectx.children = origchildren
+
+ self._run_assertions(name, stupid, single, srcrepo, dest, u)
+
+
+def _run_assertions(self, name, stupid, single, src, dest, u):
+
self.assertTrue(os.path.isdir(os.path.join(src.path, 'svn')),
'no .hg/svn directory in the source!')
- self.assertTrue(os.path.isdir(os.path.join(src.path, 'svn')),
+ self.assertTrue(os.path.isdir(os.path.join(dest.path, 'svn')),
'no .hg/svn directory in the destination!')
dest = hg.repository(u, os.path.dirname(dest.path))
for tf in ('lastpulled', 'rev_map', 'uuid', 'tagmap', 'layout', 'subdir',):
@@ -68,7 +109,7 @@ def _do_case(self, name, stupid, single):
self.assertNotEqual(old, new,
'rebuildmeta unexpected match on youngest rev!')
continue
- self.assertMultiLineEqual(old, new)
+ self.assertMultiLineEqual(old, new, tf + ' differs')
self.assertEqual(src.branchtags(), dest.branchtags())
srcbi = pickle.load(open(os.path.join(src.path, 'svn', 'branch_info')))
destbi = pickle.load(open(os.path.join(dest.path, 'svn', 'branch_info')))
@@ -101,11 +142,17 @@ def buildmethod(case, name, stupid, single):
return m
+skip = set([
+ 'project_root_not_repo_root.svndump',
+ 'corrupt.svndump',
+])
+
attrs = {'_do_case': _do_case,
+ '_run_assertions': _run_assertions,
}
for case in [f for f in os.listdir(test_util.FIXTURES) if f.endswith('.svndump')]:
# this fixture results in an empty repository, don't use it
- if case == 'project_root_not_repo_root.svndump':
+ if case in skip:
continue
bname = 'test_' + case[:-len('.svndump')]
attrs[bname] = buildmethod(case, bname, False, False)
diff --git a/tests/test_single_dir_clone.py b/tests/test_single_dir_clone.py
index 52ebe0f..7c3cb3e 100644
--- a/tests/test_single_dir_clone.py
+++ b/tests/test_single_dir_clone.py
@@ -44,6 +44,15 @@ class TestSingleDir(test_util.TestBase):
self.assertEqual(repo.branchtags().keys(), ['default', ])
self.assertEqual(repo['default'].manifest().keys(), oldmanifest)
+ def test_clone_subdir_is_file_prefix(self, stupid=False):
+ FIXTURE = 'subdir_is_file_prefix.svndump'
+ repo = self._load_fixture_and_fetch(FIXTURE,
+ stupid=stupid,
+ layout='single',
+ subdir=test_util.subdir[FIXTURE])
+ self.assertEqual(repo.branchtags().keys(), ['default'])
+ self.assertEqual(repo['tip'].manifest().keys(), ['flaf.txt'])
+
def test_externals_single(self):
repo = self._load_fixture_and_fetch('externals.svndump',
stupid=False,
diff --git a/tests/test_startrev.py b/tests/test_startrev.py
deleted file mode 100644
index e544bff..0000000
--- a/tests/test_startrev.py
+++ /dev/null
@@ -1,71 +0,0 @@
-import test_util
-
-import os
-import unittest
-
-def _do_case(self, name, subdir, stupid):
- wc_base = self.wc_path
- self.wc_path = wc_base + '_full'
- headclone = self._load_fixture_and_fetch(name, subdir=subdir, stupid=stupid,
- layout='single', startrev='HEAD')
- self.wc_path = wc_base + '_head'
- fullclone = self._load_fixture_and_fetch(name, subdir=subdir, stupid=stupid,
- layout='single')
-
- fulltip = fullclone['tip']
- headtip = headclone['tip']
- # viewing diff's of lists of files is easier on the eyes
- self.assertMultiLineEqual('\n'.join(fulltip), '\n'.join(headtip))
-
- for f in fulltip:
- self.assertMultiLineEqual(fulltip[f].data(), headtip[f].data())
-
- self.assertNotEqual(len(fullclone), 0, "full clone shouldn't be empty")
- self.assertEqual(len(headclone), 1,
- "shallow clone should have just one revision, not %d"
- % len(headclone))
-
-def buildmethod(case, name, subdir, stupid):
- m = lambda self: self._do_case(case, subdir.strip('/'), stupid)
- m.__name__ = name
- m.__doc__ = ('Test clone with startrev on %s%s with %s replay.' %
- (case, subdir, (stupid and 'stupid') or 'real'))
- return m
-
-
-# these fixtures contain no files at HEAD and would result in empty clones
-nofiles = set([
- 'binaryfiles.svndump',
- 'binaryfiles-broken.svndump',
- 'emptyrepo.svndump',
-])
-
-# these fixtures contain no files in trunk at HEAD and would result in an empty
-# shallow clone if cloning trunk, so we use another subdirectory
-subdirmap = {
- 'commit-to-tag.svndump': '/branches/magic',
- 'pushexternals.svndump': '',
- 'tag_name_same_as_branch.svndump': '/branches/magic',
-}
-
-attrs = {'_do_case': _do_case,
- }
-
-for case in [f for f in os.listdir(test_util.FIXTURES) if f.endswith('.svndump')]:
- if case in nofiles:
- continue
-
- subdir = test_util.subdir.get(case, '') + subdirmap.get(case, '/trunk')
-
- bname = 'test_' + case[:-len('.svndump')]
- attrs[bname] = buildmethod(case, bname, subdir, False)
- name = bname + '_stupid'
- attrs[name] = buildmethod(case, name, subdir, True)
-
-StartRevTests = type('StartRevTests', (test_util.TestBase,), attrs)
-
-
-def suite():
- all_tests = [unittest.TestLoader().loadTestsFromTestCase(StartRevTests),
- ]
- return unittest.TestSuite(all_tests)
diff --git a/tests/test_tags.py b/tests/test_tags.py
index 630e039..29afcdb 100644
--- a/tests/test_tags.py
+++ b/tests/test_tags.py
@@ -112,6 +112,7 @@ rename a tag
"You should check that before assuming issues with this test.\n")
wc2_path = self.wc_path + '2'
src, dest = test_util.hgclone(repo.ui, self.wc_path, wc2_path, update=False)
+ dest = test_util.getlocalpeer(dest)
svncommands.rebuildmeta(repo.ui,
dest,
args=[test_util.fileurl(repo_path), ])
diff --git a/tests/test_updatemeta.py b/tests/test_updatemeta.py
new file mode 100644
index 0000000..37bb1f8
--- /dev/null
+++ b/tests/test_updatemeta.py
@@ -0,0 +1,81 @@
+import test_util
+
+import os
+import pickle
+import unittest
+import test_rebuildmeta
+
+from mercurial import context
+from mercurial import extensions
+from mercurial import hg
+from mercurial import ui
+
+from hgsubversion import svncommands
+from hgsubversion import svnmeta
+
+
+
+def _do_case(self, name, stupid, single):
+ subdir = test_util.subdir.get(name, '')
+ layout = 'auto'
+ if single:
+ layout = 'single'
+ repo, repo_path = self.load_and_fetch(name, subdir=subdir, stupid=stupid,
+ layout=layout)
+ assert len(self.repo) > 0
+ wc2_path = self.wc_path + '_clone'
+ u = ui.ui()
+ src, dest = test_util.hgclone(u, self.wc_path, wc2_path, update=False)
+ src = test_util.getlocalpeer(src)
+ dest = test_util.getlocalpeer(dest)
+
+ # insert a wrapper that prevents calling changectx.children()
+ def failfn(orig, ctx):
+ self.fail('calling %s is forbidden; it can cause massive slowdowns '
+ 'when rebuilding large repositories' % orig)
+
+ origchildren = getattr(context.changectx, 'children')
+ extensions.wrapfunction(context.changectx, 'children', failfn)
+
+ # test updatemeta on an empty repo
+ try:
+ svncommands.updatemeta(u, dest,
+ args=[test_util.fileurl(repo_path +
+ subdir), ])
+ finally:
+ # remove the wrapper
+ context.changectx.children = origchildren
+
+ self._run_assertions(name, stupid, single, src, dest, u)
+
+
+def _run_assertions(self, name, stupid, single, src, dest, u):
+ test_rebuildmeta._run_assertions(self, name, stupid, single, src, dest, u)
+
+
+skip = set([
+ 'project_root_not_repo_root.svndump',
+ 'corrupt.svndump',
+])
+
+attrs = {'_do_case': _do_case,
+ '_run_assertions': _run_assertions,
+ }
+for case in [f for f in os.listdir(test_util.FIXTURES) if f.endswith('.svndump')]:
+ # this fixture results in an empty repository, don't use it
+ if case in skip:
+ continue
+ bname = 'test_' + case[:-len('.svndump')]
+ attrs[bname] = test_rebuildmeta.buildmethod(case, bname, False, False)
+ name = bname + '_stupid'
+ attrs[name] = test_rebuildmeta.buildmethod(case, name, True, False)
+ name = bname + '_single'
+ attrs[name] = test_rebuildmeta.buildmethod(case, name, False, True)
+
+UpdateMetaTests = type('UpdateMetaTests', (test_util.TestBase,), attrs)
+
+
+def suite():
+ all_tests = [unittest.TestLoader().loadTestsFromTestCase(UpdateMetaTests),
+ ]
+ return unittest.TestSuite(all_tests)
diff --git a/tests/test_util.py b/tests/test_util.py
index 0343fe2..c2c67de 100644
--- a/tests/test_util.py
+++ b/tests/test_util.py
@@ -7,6 +7,7 @@ import shutil
import stat
import subprocess
import sys
+import tarfile
import tempfile
import unittest
import urllib
@@ -37,6 +38,7 @@ except AttributeError:
SkipTest = None
from hgsubversion import util
+from hgsubversion import svnwrap
# Documentation for Subprocess.Popen() says:
# "Note that on Windows, you cannot set close_fds to true and
@@ -96,11 +98,17 @@ subdir = {'truncatedhistory.svndump': '/project2',
'project_name_with_space.svndump': '/project name',
'non_ascii_path_1.svndump': '/b\xC3\xB8b',
'non_ascii_path_2.svndump': '/b%C3%B8b',
+ 'subdir_is_file_prefix.svndump': '/flaf',
}
FIXTURES = os.path.join(os.path.abspath(os.path.dirname(__file__)),
'fixtures')
+def getlocalpeer(repo):
+ localrepo = getattr(repo, 'local', lambda: repo)()
+ if isinstance(localrepo, bool):
+ localrepo = repo
+ return localrepo
def _makeskip(name, message):
if SkipTest:
@@ -143,7 +151,10 @@ def fileurl(path):
path = os.path.abspath(path).replace(os.sep, '/')
drive, path = os.path.splitdrive(path)
if drive:
- drive = '/' + drive
+ # In svn 1.7, the swig svn wrapper returns local svn URLs
+ # with an uppercase drive letter, try to match that to
+ # simplify svn info tests.
+ drive = '/' + drive.upper()
url = 'file://%s%s' % (drive, path)
return url
@@ -158,11 +169,8 @@ def testui(stupid=False, layout='auto', startrev=0):
return u
def dispatch(cmd):
- try:
- req = dispatchmod.request(cmd)
- dispatchmod.dispatch(req)
- except AttributeError, e:
- dispatchmod.dispatch(cmd)
+ cmd = getattr(dispatchmod, 'request', lambda x: x)(cmd)
+ dispatchmod.dispatch(cmd)
def rmtree(path):
# Read-only files cannot be removed under Windows
@@ -198,12 +206,12 @@ def _verify_our_modules():
'from the wrong path!'
)
-def hgclone(ui, source, dest, update=True):
+def hgclone(ui, source, dest, update=True, rev=None):
if getattr(hg, 'peer', None):
# Since 1.9 (d976542986d2)
- src, dest = hg.clone(ui, {}, source, dest, update=update)
+ src, dest = hg.clone(ui, {}, source, dest, update=update, rev=rev)
else:
- src, dest = hg.clone(ui, source, dest, update=update)
+ src, dest = hg.clone(ui, source, dest, update=update, rev=rev)
return src, dest
def svnls(repo_path, path, rev='HEAD'):
@@ -236,6 +244,9 @@ class TestBase(unittest.TestCase):
def setUp(self):
_verify_our_modules()
+ # the Python 2.7 default of 640 is obnoxiously low
+ self.maxDiff = 4096
+
self.oldenv = dict([(k, os.environ.get(k, None),) for k in
('LANG', 'LC_ALL', 'HGRCPATH',)])
self.oldt = i18n.t
@@ -255,6 +266,10 @@ class TestBase(unittest.TestCase):
self.wc_path = '%s/testrepo_wc' % self.tmpdir
self.svn_wc = None
+ self.config_dir = self.tmpdir
+ svnwrap.common._svn_config_dir = self.config_dir
+ self.setup_svn_config('')
+
# Previously, we had a MockUI class that wrapped ui, and giving access
# to the stream. The ui.pushbuffer() and ui.popbuffer() can be used
# instead. Using the regular UI class, with all stderr redirected to
@@ -263,6 +278,10 @@ class TestBase(unittest.TestCase):
self.patch = (ui.ui.write_err, ui.ui.write)
setattr(ui.ui, self.patch[0].func_name, self.patch[1])
+ def setup_svn_config(self, config):
+ with open(self.config_dir + '/config', 'w') as c:
+ c.write(config)
+
def _makerepopath(self):
self.repocount += 1
return '%s/testrepo-%d' % (self.tmpdir, self.repocount)
@@ -297,15 +316,31 @@ class TestBase(unittest.TestCase):
proc.communicate()
return path
- def load_and_fetch(self, fixture_name, subdir=None, stupid=False,
- layout='auto', startrev=0, externals=None,
- noupdate=True):
+ def load_repo_tarball(self, fixture_name):
+ '''Extracts a tarball of an svn repo and returns the svn repo path.'''
+ path = self._makerepopath()
+ assert not os.path.exists(path)
+ os.mkdir(path)
+ tarball = tarfile.open(os.path.join(FIXTURES, fixture_name))
+ # This is probably somewhat fragile, but I'm not sure how to
+ # do better in particular, I think it assumes that the tar
+ # entries are in the right order and that directories appear
+ # before their contents. This is a valid assummption for sane
+ # tarballs, from what I can tell. In particular, for a simple
+ # tarball of a svn repo with paths relative to the repo root,
+ # it seems to work
+ for entry in tarball:
+ tarball.extract(entry, path)
+ return path
+
+ def fetch(self, repo_path, subdir=None, stupid=False, layout='auto',
+ startrev=0, externals=None, noupdate=True, dest=None, rev=None,
+ config=None):
if layout == 'single':
if subdir is None:
subdir = 'trunk'
elif subdir is None:
subdir = ''
- repo_path = self.load_svndump(fixture_name)
projectpath = repo_path
if subdir:
projectpath += '/' + subdir
@@ -321,12 +356,27 @@ class TestBase(unittest.TestCase):
cmd.append('--stupid')
if noupdate:
cmd.append('--noupdate')
+ if rev is not None:
+ cmd.append('--rev=%s' % rev)
+ config = dict(config or {})
if externals:
- cmd[:0] = ['--config', 'hgsubversion.externals=%s' % externals]
+ config['hgsubversion.externals'] = str(externals)
+ for k,v in reversed(sorted(config.iteritems())):
+ cmd[:0] = ['--config', '%s=%s' % (k, v)]
dispatch(cmd)
- return hg.repository(testui(), self.wc_path), repo_path
+ return hg.repository(testui(), self.wc_path)
+
+ def load_and_fetch(self, fixture_name, *args, **opts):
+ if fixture_name.endswith('.svndump'):
+ repo_path = self.load_svndump(fixture_name)
+ elif fixture_name.endswith('tar.gz'):
+ repo_path = self.load_repo_tarball(fixture_name)
+ else:
+ assert False, 'Unknown fixture type'
+
+ return self.fetch(repo_path, *args, **opts), repo_path
def _load_fixture_and_fetch(self, *args, **kwargs):
repo, repo_path = self.load_and_fetch(*args, **kwargs)
@@ -470,7 +520,7 @@ class TestBase(unittest.TestCase):
msg = '%s\n%s' % (msg or '', diff)
raise self.failureException, msg
- def draw(self, repo):
+ def getgraph(self, repo):
"""Helper function displaying a repository graph, especially
useful when debugging comprehensive tests.
"""
@@ -487,4 +537,10 @@ summary: {desc|firstline}
files: {files}
"""
+ _ui.pushbuffer()
graphlog.graphlog(_ui, repo, rev=None, template=templ)
+ return _ui.popbuffer()
+
+ def draw(self, repo):
+ sys.stdout.write(self.getgraph(repo))
+
diff --git a/tests/test_utility_commands.py b/tests/test_utility_commands.py
index 10926e2..338dc82 100644
--- a/tests/test_utility_commands.py
+++ b/tests/test_utility_commands.py
@@ -14,6 +14,7 @@ from mercurial import util as hgutil
from hgsubversion import util
from hgsubversion import svncommands
+from hgsubversion import verify
from hgsubversion import wrappers
expected_info_output = '''URL: %(repourl)s/%(branch)s
@@ -66,6 +67,23 @@ class UtilityTests(test_util.TestBase):
'rev': 5,
})
self.assertMultiLineEqual(actual, expected)
+ destpath = self.wc_path + '_clone'
+ test_util.hgclone(u, self.repo, destpath)
+ repo2 = hg.repository(u, destpath)
+ repo2.ui.setconfig('paths', 'default-push',
+ self.repo.ui.config('paths', 'default'))
+ hg.update(repo2, 'default')
+ svncommands.rebuildmeta(u, repo2, [])
+ u.pushbuffer()
+ svncommands.info(u, repo2)
+ actual = u.popbuffer()
+ expected = (expected_info_output %
+ {'date': '2008-10-08 01:39:29 +0000 (Wed, 08 Oct 2008)',
+ 'repourl': repourl(repo_path),
+ 'branch': 'trunk',
+ 'rev': 6,
+ })
+ self.assertMultiLineEqual(actual, expected)
def test_info_single(self):
repo, repo_path = self.load_and_fetch('two_heads.svndump', subdir='trunk')
@@ -245,28 +263,82 @@ class UtilityTests(test_util.TestBase):
authors=author_path)
self.assertMultiLineEqual(open(author_path).read(), 'Augie=\nevil=\n')
- def test_svnverify(self):
+ def test_svnverify(self, stupid=False):
repo, repo_path = self.load_and_fetch('binaryfiles.svndump',
- noupdate=False)
- ret = svncommands.verify(self.ui(), repo, [], rev=1)
+ noupdate=False, stupid=stupid)
+ ret = verify.verify(self.ui(), repo, [], rev=1, stupid=stupid)
self.assertEqual(0, ret)
repo_path = self.load_svndump('binaryfiles-broken.svndump')
u = self.ui()
u.pushbuffer()
- ret = svncommands.verify(u, repo, [test_util.fileurl(repo_path)],
- rev=1)
+ ret = verify.verify(u, repo, [test_util.fileurl(repo_path)],
+ rev=1, stupid=stupid)
output = u.popbuffer()
self.assertEqual(1, ret)
output = re.sub(r'file://\S+', 'file://', output)
- self.assertEqual("""\
+ self.assertMultiLineEqual("""\
verifying d51f46a715a1 against file://
-difference in file binary2
-unexpected files:
- binary1
-missing files:
- binary3
+difference in: binary2
+unexpected file: binary1
+missing file: binary3
""", output)
+ def test_svnverify_stupid(self):
+ self.test_svnverify(True)
+
+ def test_corruption(self, stupid=False):
+ SUCCESS = 0
+ FAILURE = 1
+
+ repo, repo_path = self.load_and_fetch('correct.svndump', layout='single',
+ subdir='', stupid=stupid)
+
+ ui = self.ui()
+
+ self.assertEqual(SUCCESS, verify.verify(ui, self.repo, rev='tip',
+ stupid=stupid))
+
+ corrupt_source = test_util.fileurl(self.load_svndump('corrupt.svndump'))
+
+ repo.ui.setconfig('paths', 'default', corrupt_source)
+
+ ui.pushbuffer()
+ code = verify.verify(ui, repo, rev='tip')
+ actual = ui.popbuffer()
+
+ actual = actual.replace(corrupt_source, '$REPO')
+ actual = set(actual.splitlines())
+
+ expected = set([
+ 'verifying 78e965230a13 against $REPO@1',
+ 'missing file: missing-file',
+ 'wrong flags for: executable-file',
+ 'wrong flags for: symlink',
+ 'wrong flags for: regular-file',
+ 'difference in: another-regular-file',
+ 'difference in: regular-file',
+ 'unexpected file: empty-file',
+ ])
+
+ self.assertEqual((FAILURE, expected), (code, actual))
+
+ def test_corruption_stupid(self):
+ self.test_corruption(True)
+
+ def test_svnrebuildmeta(self):
+ otherpath = self.load_svndump('binaryfiles-broken.svndump')
+ otherurl = test_util.fileurl(otherpath)
+ self.load_and_fetch('replace_trunk_with_branch.svndump')
+ # rebuildmeta with original repo
+ svncommands.rebuildmeta(self.ui(), repo=self.repo, args=[])
+ # rebuildmeta with unrelated repo
+ self.assertRaises(hgutil.Abort,
+ svncommands.rebuildmeta,
+ self.ui(), repo=self.repo, args=[otherurl])
+ # rebuildmeta --unsafe-skip-uuid-check with unrelated repo
+ svncommands.rebuildmeta(self.ui(), repo=self.repo, args=[otherurl],
+ unsafe_skip_uuid_check=True)
+
def suite():
all_tests = [unittest.TestLoader().loadTestsFromTestCase(UtilityTests),
]