Exemplo n.º 1
0
    def setUp(self):
        if not is_exe_in_path('svn'):
            raise SkipTest('svn not found in path')

        super(SVNClientTests, self).setUp()

        self.options.svn_show_copies_as_adds = None
        self.client = SVNClient(options=self.options)
Exemplo n.º 2
0
    def setUp(self):
        super(SVNClientTests, self).setUp()

        if not is_exe_in_path('svn'):
            raise SkipTest('svn not found in path')

        self.svn_dir = os.path.join(self.testdata_dir, 'svn-repo')
        self.clone_dir = self.chdir_tmp()
        self.svn_repo_url = 'file://' + self.svn_dir
        self._run_svn(['co', self.svn_repo_url, 'svn-repo'])
        os.chdir(os.path.join(self.clone_dir, 'svn-repo'))

        self.client = SVNClient(options=self.options)
        self.options.svn_show_copies_as_adds = None
Exemplo n.º 3
0
    def scan_for_server(self, repository_info):
        # Scan first for dot files, since it's faster and will cover the
        # user's $HOME/.reviewboardrc
        server_url = super(GitClient, self).scan_for_server(repository_info)

        if server_url:
            return server_url

        # TODO: Maybe support a server per remote later? Is that useful?
        url = execute([self.git, "config", "--get", "reviewboard.url"],
                      ignore_errors=True).strip()
        if url:
            return url

        if self.type == "svn":
            # Try using the reviewboard:url property on the SVN repo, if it
            # exists.
            prop = SVNClient().scan_for_server_property(repository_info)

            if prop:
                return prop
        elif self.type == 'perforce':
            prop = PerforceClient().scan_for_server(repository_info)

            if prop:
                return prop

        return None
Exemplo n.º 4
0
    def scan_for_server(self, repository_info):
        """Find the Review Board server matching this repository.

        Args:
            repository_info (rbtools.clients.RepositoryInfo):
                The repository information structure.

        Returns:
            unicode:
            The Review Board server URL, if available.
        """
        # Scan first for dot files, since it's faster and will cover the
        # user's $HOME/.reviewboardrc
        server_url = \
            super(MercurialClient, self).scan_for_server(repository_info)

        if not server_url and self.hgrc.get('reviewboard.url'):
            server_url = self.hgrc.get('reviewboard.url').strip()

        if not server_url and self._type == 'svn':
            # Try using the reviewboard:url property on the SVN repo, if it
            # exists.
            prop = SVNClient().scan_for_server_property(repository_info)

            if prop:
                return prop

        return server_url
Exemplo n.º 5
0
    def test_find_matching_server_repository_with_mirror_path_match(self):
        """Testing SVNClient.find_matching_server_repository with mirror_path
        match
        """
        url = 'svn+ssh://svn2.example.com/'
        self.options.repository_url = url
        client = SVNClient(options=self.options)

        repository, info = get_repository_resource(self.root_resource,
                                                   tool=client,
                                                   repository_paths=url)
        self.assertEqual(repository.id, 2)
Exemplo n.º 6
0
    def test_find_matching_server_repository_with_uuid_match(self):
        """Testing SVNClient.find_matching_server_repository with UUID
        match
        """
        url = 'svn+ssh://blargle/'
        self.options.repository_url = url
        client = SVNClient(options=self.options)

        self.spy_on(client.svn_info,
                    op=kgb.SpyOpReturn({
                        'Repository UUID': 'UUID-3',
                    }))

        repository, info = get_repository_resource(self.root_resource,
                                                   tool=client,
                                                   repository_paths=url)
        self.assertEqual(repository.id, 3)
Exemplo n.º 7
0
    def scan_for_server(self, repository_info):
        # Scan first for dot files, since it's faster and will cover the
        # user's $HOME/.reviewboardrc
        server_url = \
            super(MercurialClient, self).scan_for_server(repository_info)

        if not server_url and self.hgrc.get('reviewboard.url'):
            server_url = self.hgrc.get('reviewboard.url').strip()

        if not server_url and self._type == "svn":
            # Try using the reviewboard:url property on the SVN repo, if it
            # exists.
            prop = SVNClient().scan_for_server_property(repository_info)

            if prop:
                return prop

        return server_url
Exemplo n.º 8
0
def load_scmclients(options):
    global SCMCLIENTS

    from rbtools.clients.clearcase import ClearCaseClient
    from rbtools.clients.cvs import CVSClient
    from rbtools.clients.git import GitClient
    from rbtools.clients.mercurial import MercurialClient
    from rbtools.clients.perforce import PerforceClient
    from rbtools.clients.plastic import PlasticClient
    from rbtools.clients.svn import SVNClient

    SCMCLIENTS = [
        CVSClient(options=options),
        ClearCaseClient(options=options),
        GitClient(options=options),
        MercurialClient(options=options),
        PerforceClient(options=options),
        PlasticClient(options=options),
        SVNClient(options=options),
    ]
Exemplo n.º 9
0
    def scan_for_server(self, repository_info):
        """Find the Review Board server matching this repository.

        Args:
            repository_info (rbtools.clients.RepositoryInfo):
                The repository information structure.

        Returns:
            unicode:
            The Review Board server URL, if available.
        """
        server_url = self.hgrc.get('reviewboard.url', '').strip()

        if server_url:
            return server_url
        elif self._type == 'svn':
            # Try using the reviewboard:url property on the SVN repo, if it
            # exists.
            return SVNClient().scan_for_server_property(repository_info)

        return None
Exemplo n.º 10
0
    def scan_for_server(self, repository_info):
        """Find the Review Board server matching this repository.

        Args:
            repository_info (rbtools.clients.RepositoryInfo):
                The repository information structure.

        Returns:
            unicode:
            The Review Board server URL, if available.
        """
        # Scan first for dot files, since it's faster and will cover the
        # user's $HOME/.reviewboardrc
        server_url = super(GitClient, self).scan_for_server(repository_info)

        if server_url:
            return server_url

        # TODO: Maybe support a server per remote later? Is that useful?
        url = self._execute([self.git, 'config', '--get', 'reviewboard.url'],
                            ignore_errors=True).strip()
        if url:
            return url

        if self._type == self.TYPE_GIT_SVN:
            # Try using the reviewboard:url property on the SVN repo, if it
            # exists.
            prop = SVNClient().scan_for_server_property(repository_info)

            if prop:
                return prop
        elif self._type == self.TYPE_GIT_P4:
            prop = PerforceClient().scan_for_server(repository_info)

            if prop:
                return prop

        return None
Exemplo n.º 11
0
class SVNClientTests(SCMClientTests):
    def setUp(self):
        super(SVNClientTests, self).setUp()

        if not is_exe_in_path('svn'):
            raise SkipTest('svn not found in path')

        self.svn_dir = os.path.join(self.testdata_dir, 'svn-repo')
        self.clone_dir = self.chdir_tmp()
        self.svn_repo_url = 'file://' + self.svn_dir
        self._run_svn(['co', self.svn_repo_url, 'svn-repo'])
        os.chdir(os.path.join(self.clone_dir, 'svn-repo'))

        self.client = SVNClient(options=self.options)
        self.options.svn_show_copies_as_adds = None

    def _run_svn(self, command):
        return execute(['svn'] + command,
                       env=None,
                       split_lines=False,
                       ignore_errors=False,
                       extra_ignore_errors=())

    def _svn_add_file(self, filename, data, changelist=None):
        """Add a file to the test repo."""
        is_new = not os.path.exists(filename)

        with open(filename, 'wb') as f:
            f.write(data)

        if is_new:
            self._run_svn(['add', filename])

        if changelist:
            self._run_svn(['changelist', changelist, filename])

    def _svn_add_dir(self, dirname):
        """Add a directory to the test repo."""
        if not os.path.exists(dirname):
            os.mkdir(dirname)

        self._run_svn(['add', dirname])

    def test_parse_revision_spec_no_args(self):
        """Testing SVNClient.parse_revision_spec with no specified revisions"""
        revisions = self.client.parse_revision_spec()
        self.assertTrue(isinstance(revisions, dict))
        self.assertTrue('base' in revisions)
        self.assertTrue('tip' in revisions)
        self.assertTrue('parent_base' not in revisions)
        self.assertEqual(revisions['base'], 'BASE')
        self.assertEqual(revisions['tip'], '--rbtools-working-copy')

    def test_parse_revision_spec_one_revision(self):
        """Testing SVNClient.parse_revision_spec with one specified numeric
        revision"""
        revisions = self.client.parse_revision_spec(['3'])
        self.assertTrue(isinstance(revisions, dict))
        self.assertTrue('base' in revisions)
        self.assertTrue('tip' in revisions)
        self.assertTrue('parent_base' not in revisions)
        self.assertEqual(revisions['base'], 2)
        self.assertEqual(revisions['tip'], 3)

    def test_parse_revision_spec_one_revision_changelist(self):
        """Testing SVNClient.parse_revision_spec with one specified changelist
        revision"""
        self._svn_add_file('foo.txt', FOO3, 'my-change')

        revisions = self.client.parse_revision_spec(['my-change'])
        self.assertTrue(isinstance(revisions, dict))
        self.assertTrue('base' in revisions)
        self.assertTrue('tip' in revisions)
        self.assertTrue('parent_base' not in revisions)
        self.assertEqual(revisions['base'], 'BASE')
        self.assertEqual(revisions['tip'],
                         SVNClient.REVISION_CHANGELIST_PREFIX + 'my-change')

    def test_parse_revision_spec_one_revision_nonexistant_changelist(self):
        """Testing SVNClient.parse_revision_spec with one specified invalid
        changelist revision"""
        self._svn_add_file('foo.txt', FOO3, 'my-change')

        self.assertRaises(
            InvalidRevisionSpecError,
            lambda: self.client.parse_revision_spec(['not-my-change']))

    def test_parse_revision_spec_one_arg_two_revisions(self):
        """Testing SVNClient.parse_revision_spec with R1:R2 syntax"""
        revisions = self.client.parse_revision_spec(['1:3'])
        self.assertTrue(isinstance(revisions, dict))
        self.assertTrue('base' in revisions)
        self.assertTrue('tip' in revisions)
        self.assertTrue('parent_base' not in revisions)
        self.assertEqual(revisions['base'], 1)
        self.assertEqual(revisions['tip'], 3)

    def test_parse_revision_spec_two_arguments(self):
        """Testing SVNClient.parse_revision_spec with two revisions"""
        revisions = self.client.parse_revision_spec(['1', '3'])
        self.assertTrue(isinstance(revisions, dict))
        self.assertTrue('base' in revisions)
        self.assertTrue('tip' in revisions)
        self.assertTrue('parent_base' not in revisions)
        self.assertEqual(revisions['base'], 1)
        self.assertEqual(revisions['tip'], 3)

    def test_parse_revision_spec_one_revision_url(self):
        """Testing SVNClient.parse_revision_spec with one revision and a
        repository URL"""
        self.options.repository_url = \
            'http://svn.apache.org/repos/asf/subversion/trunk'

        revisions = self.client.parse_revision_spec(['1549823'])
        self.assertTrue(isinstance(revisions, dict))
        self.assertTrue('base' in revisions)
        self.assertTrue('tip' in revisions)
        self.assertTrue('parent_base' not in revisions)
        self.assertEqual(revisions['base'], 1549822)
        self.assertEqual(revisions['tip'], 1549823)

    def test_parse_revision_spec_two_revisions_url(self):
        """Testing SVNClient.parse_revision_spec with R1:R2 syntax and a
        repository URL"""
        self.options.repository_url = \
            'http://svn.apache.org/repos/asf/subversion/trunk'

        revisions = self.client.parse_revision_spec(['1549823:1550211'])
        self.assertTrue(isinstance(revisions, dict))
        self.assertTrue('base' in revisions)
        self.assertTrue('tip' in revisions)
        self.assertTrue('parent_base' not in revisions)
        self.assertEqual(revisions['base'], 1549823)
        self.assertEqual(revisions['tip'], 1550211)

    def test_parse_revision_spec_invalid_spec(self):
        """Testing SVNClient.parse_revision_spec with invalid specifications"""
        self.assertRaises(InvalidRevisionSpecError,
                          self.client.parse_revision_spec, ['aoeu'])
        self.assertRaises(InvalidRevisionSpecError,
                          self.client.parse_revision_spec, ['aoeu', '1234'])
        self.assertRaises(TooManyRevisionsError,
                          self.client.parse_revision_spec, ['1', '2', '3'])

    def test_parse_revision_spec_non_unicode_log(self):
        """Testing SVNClient.parse_revision_spec with a non-utf8 log entry"""
        # Note: the svn log entry for commit r2 contains one non-utf8 character
        revisions = self.client.parse_revision_spec(['2'])
        self.assertTrue(isinstance(revisions, dict))
        self.assertTrue('base' in revisions)
        self.assertTrue('tip' in revisions)
        self.assertTrue('parent_base' not in revisions)
        self.assertEqual(revisions['base'], 1)
        self.assertEqual(revisions['tip'], 2)

    def test_get_commit_message_working_copy(self):
        """Testing SVNClient.get_commit_message with a working copy change"""
        revisions = self.client.parse_revision_spec()
        message = self.client.get_commit_message(revisions)
        self.assertIsNone(message)

    def test_get_commit_message_committed_revision(self):
        """Testing SVNClient.get_commit_message with a single committed
        revision
        """
        revisions = self.client.parse_revision_spec(['2'])
        message = self.client.get_commit_message(revisions)

        self.assertTrue('summary' in message)
        self.assertTrue('description' in message)

        self.assertEqual(message['summary'],
                         'Commit 2 -- a non-utf8 character: \xe9')
        self.assertEqual(message['description'],
                         'Commit 2 -- a non-utf8 character: \xe9\n')

    def test_get_commit_message_committed_revisions(self):
        """Testing SVNClient.get_commit_message with multiple committed
        revisions
        """
        revisions = self.client.parse_revision_spec(['1:3'])
        message = self.client.get_commit_message(revisions)

        self.assertTrue('summary' in message)
        self.assertTrue('description' in message)

        self.assertEqual(message['summary'],
                         'Commit 2 -- a non-utf8 character: \xe9')
        self.assertEqual(message['description'], 'Commit 3')

    @svn_version_set_hash('6613644d417f7c90f83f3a2d16b1dad5',
                          '7630ea80056a7340d93a556e9af60c63',
                          '6a5339da19e60c7706e44aeebfa4da5f')
    def test_diff_exclude(self, md5sum):
        """Testing SVNClient diff with file exclude patterns"""
        self._svn_add_file('bar.txt', FOO1)
        self._svn_add_file('exclude.txt', FOO2)

        revisions = self.client.parse_revision_spec([])
        result = self.client.diff(revisions, exclude_patterns=['exclude.txt'])
        self.assertTrue(isinstance(result, dict))
        self.assertTrue('diff' in result)

        self.assertEqual(md5(result['diff']).hexdigest(), md5sum)

    def test_diff_exclude_in_subdir(self):
        """Testing SVNClient diff with exclude patterns in a subdir"""
        self._svn_add_file('foo.txt', FOO1)
        self._svn_add_dir('subdir')
        self._svn_add_file(os.path.join('subdir', 'exclude.txt'), FOO2)

        os.chdir('subdir')

        revisions = self.client.parse_revision_spec([])
        result = self.client.diff(revisions, exclude_patterns=['exclude.txt'])

        self.assertTrue(isinstance(result, dict))
        self.assertTrue('diff' in result)

        self.assertEqual(result['diff'], b'')

    def test_diff_exclude_root_pattern_in_subdir(self):
        """Testing SVNClient diff with repo exclude patterns in a subdir"""
        self._svn_add_file('exclude.txt', FOO1)
        self._svn_add_dir('subdir')

        os.chdir('subdir')

        revisions = self.client.parse_revision_spec([])
        result = self.client.diff(
            revisions,
            exclude_patterns=[os.path.join(os.path.sep, 'exclude.txt'), '.'])

        self.assertTrue(isinstance(result, dict))
        self.assertTrue('diff' in result)

        self.assertEqual(result['diff'], b'')

    @svn_version_set_hash('043befc507b8177a0f010dc2cecc4205',
                          '1b68063237c584d38a9a3ddbdf1f72a2',
                          '466f7c2092e085354f5b24b91d48dd80')
    def test_same_diff_multiple_methods(self, md5_sum):
        """Testing SVNClient identical diff generated from root, subdirectory,
        and via target"""

        # Test diff generation for a single file, where 'svn diff' is invoked
        # from three different locations.  This should result in an identical
        # diff for all three cases.  Add a new subdirectory and file
        # (dir1/A.txt) which will be the lone change captured in the diff.
        # Cases:
        #  1) Invoke 'svn diff' from checkout root.
        #  2) Invoke 'svn diff' from dir1/ subdirectory.
        #  3) Create dir2/ subdirectory parallel to dir1/.  Invoke 'svn diff'
        #     from dir2/ where '../dir1/A.txt' is provided as a specific
        #     target.
        #
        # This test is inspired by #3749 which broke cases 2 and 3.

        self._svn_add_dir('dir1')
        self._svn_add_file('dir1/A.txt', FOO3)

        # Case 1: Generate diff from checkout root.
        revisions = self.client.parse_revision_spec()
        result = self.client.diff(revisions)
        self.assertTrue(isinstance(result, dict))
        self.assertTrue('diff' in result)
        self.assertEqual(md5(result['diff']).hexdigest(), md5_sum)

        # Case 2: Generate diff from dir1 subdirectory.
        os.chdir('dir1')
        result = self.client.diff(revisions)
        self.assertTrue(isinstance(result, dict))
        self.assertTrue('diff' in result)
        self.assertEqual(md5(result['diff']).hexdigest(), md5_sum)

        # Case 3: Generate diff from dir2 subdirectory, but explicitly target
        # only ../dir1/A.txt.
        os.chdir('..')
        self._svn_add_dir('dir2')
        os.chdir('dir2')
        result = self.client.diff(revisions, ['../dir1/A.txt'])
        self.assertTrue(isinstance(result, dict))
        self.assertTrue('diff' in result)
        self.assertEqual(md5(result['diff']).hexdigest(), md5_sum)

    @svn_version_set_hash('902d662a110400f7470294b2d9e72d36',
                          '13803373ded9af750384a4601d5173ce',
                          'f11dfbe58925871c5f64b6ca647a8d3c')
    def test_diff_non_unicode_characters(self, md5_sum):
        """Testing SVNClient diff with a non-utf8 file"""
        self._svn_add_file('A.txt', '\xe2'.encode('iso-8859-1'))
        self._run_svn(['propset', 'svn:mime-type', 'text/plain', 'A.txt'])

        revisions = self.client.parse_revision_spec()
        result = self.client.diff(revisions)
        self.assertTrue(isinstance(result, dict))
        self.assertTrue('diff' in result)
        self.assertEqual(md5(result['diff']).hexdigest(), md5_sum)

    @svn_version_set_hash('60c4d21f4d414da947f4e7273e6d1326',
                          '60c4d21f4d414da947f4e7273e6d1326',
                          '571e47c456698bad35bca06523473008')
    def test_diff_non_unicode_filename_repository_url(self, md5sum):
        """Testing SVNClient diff with a non-utf8 filename via repository_url
        option"""
        self.options.repository_url = self.svn_repo_url

        # Note: commit r4 adds one file with a non-utf8 character in both its
        # filename and content.
        revisions = self.client.parse_revision_spec(['4'])
        result = self.client.diff(revisions)
        self.assertTrue(isinstance(result, dict))
        self.assertTrue('diff' in result)
        self.assertEqual(md5(result['diff']).hexdigest(), md5sum)

    @svn_version_set_hash('ac1835240ec86ee14ddccf1f2236c442',
                          'ac1835240ec86ee14ddccf1f2236c442',
                          '610f5506e670dc55a2464a6ad9af015c')
    def test_show_copies_as_adds_enabled(self, md5sum):
        """Testing SVNClient with --show-copies-as-adds functionality
        enabled"""
        self.check_show_copies_as_adds('y', md5sum)

    @svn_version_set_hash('d41d8cd98f00b204e9800998ecf8427e',
                          'd41d8cd98f00b204e9800998ecf8427e',
                          'b656e2f9b70ade256c3fe855c13ee52c')
    def test_show_copies_as_adds_disabled(self, md5sum):
        """Testing SVNClient with --show-copies-as-adds functionality
        disabled"""
        self.check_show_copies_as_adds('n', md5sum)

    def check_show_copies_as_adds(self, state, md5sum):
        """Helper function to evaluate --show-copies-as-adds"""
        self.client.get_repository_info()

        # Ensure valid SVN client version.
        if not is_valid_version(self.client.subversion_client_version,
                                self.client.SHOW_COPIES_AS_ADDS_MIN_VERSION):
            raise SkipTest('Subversion client is too old to test '
                           '--show-copies-as-adds.')

        self.options.svn_show_copies_as_adds = state

        self._svn_add_dir('dir1')
        self._svn_add_dir('dir2')
        self._run_svn(['copy', 'foo.txt', 'dir1'])

        # Generate identical diff via several methods:
        #  1) from checkout root
        #  2) via changelist
        #  3) from checkout root when all relevant files belong to a changelist
        #  4) via explicit include target

        revisions = self.client.parse_revision_spec()
        result = self.client.diff(revisions)
        self.assertTrue(isinstance(result, dict))
        self.assertTrue('diff' in result)
        self.assertEqual(md5(result['diff']).hexdigest(), md5sum)

        self._run_svn(['changelist', 'cl1', 'dir1/foo.txt'])
        revisions = self.client.parse_revision_spec(['cl1'])
        result = self.client.diff(revisions)
        self.assertTrue(isinstance(result, dict))
        self.assertTrue('diff' in result)
        self.assertEqual(md5(result['diff']).hexdigest(), md5sum)

        revisions = self.client.parse_revision_spec()
        result = self.client.diff(revisions)
        self.assertTrue(isinstance(result, dict))
        self.assertTrue('diff' in result)
        self.assertEqual(md5(result['diff']).hexdigest(), md5sum)

        self._run_svn(['changelist', '--remove', 'dir1/foo.txt'])

        os.chdir('dir2')
        revisions = self.client.parse_revision_spec()
        result = self.client.diff(revisions, ['../dir1'])
        self.assertTrue(isinstance(result, dict))
        self.assertTrue('diff' in result)
        self.assertEqual(md5(result['diff']).hexdigest(), md5sum)

    def test_history_scheduled_with_commit_nominal(self):
        """Testing SVNClient.history_scheduled_with_commit nominal cases"""
        self.client.get_repository_info()

        # Ensure valid SVN client version.
        if not is_valid_version(self.client.subversion_client_version,
                                self.client.SHOW_COPIES_AS_ADDS_MIN_VERSION):
            raise SkipTest('Subversion client is too old to test '
                           'history_scheduled_with_commit().')

        self._svn_add_dir('dir1')
        self._svn_add_dir('dir2')
        self._run_svn(['copy', 'foo.txt', 'dir1'])

        # Squash stderr to prevent error message in test output.
        sys.stderr = StringIO()

        # Ensure SystemExit is raised when attempting to generate diff via
        # several methods:
        #  1) from checkout root
        #  2) via changelist
        #  3) from checkout root when all relevant files belong to a changelist
        #  4) via explicit include target

        revisions = self.client.parse_revision_spec()
        self.assertRaises(SystemExit, self.client.diff, revisions)

        self._run_svn(['changelist', 'cl1', 'dir1/foo.txt'])
        revisions = self.client.parse_revision_spec(['cl1'])
        self.assertRaises(SystemExit, self.client.diff, revisions)

        revisions = self.client.parse_revision_spec()
        self.assertRaises(SystemExit, self.client.diff, revisions)

        self._run_svn(['changelist', '--remove', 'dir1/foo.txt'])

        os.chdir('dir2')
        revisions = self.client.parse_revision_spec()
        self.assertRaises(SystemExit, self.client.diff, revisions, ['../dir1'])

    def test_history_scheduled_with_commit_special_case_non_local_mods(self):
        """Testing SVNClient.history_scheduled_with_commit is bypassed when
        diff is not for local modifications in a working copy"""
        self.client.get_repository_info()

        # Ensure valid SVN client version.
        if not is_valid_version(self.client.subversion_client_version,
                                self.client.SHOW_COPIES_AS_ADDS_MIN_VERSION):
            raise SkipTest('Subversion client is too old to test '
                           'history_scheduled_with_commit().')

        # While within a working copy which contains a scheduled commit with
        # addition-with-history, ensure history_scheduled_with_commit() is not
        # executed when generating a diff between two revisions either
        # 1) locally or 2) via --reposistory-url option.

        self._run_svn(['copy', 'foo.txt', 'foo_copy.txt'])
        revisions = self.client.parse_revision_spec(['1:2'])
        result = self.client.diff(revisions)
        self.assertTrue(isinstance(result, dict))
        self.assertTrue('diff' in result)
        self.assertEqual(
            md5(result['diff']).hexdigest(),
            'ed154720a7459c2649cab4d2fa34fa93')

        self.options.repository_url = self.svn_repo_url
        revisions = self.client.parse_revision_spec(['2'])
        result = self.client.diff(revisions)
        self.assertTrue(isinstance(result, dict))
        self.assertTrue('diff' in result)
        self.assertEqual(
            md5(result['diff']).hexdigest(),
            'ed154720a7459c2649cab4d2fa34fa93')

    def test_history_scheduled_with_commit_special_case_exclude(self):
        """Testing SVNClient.history_scheduled_with_commit with exclude file"""
        self.client.get_repository_info()

        # Ensure valid SVN client version.
        if not is_valid_version(self.client.subversion_client_version,
                                self.client.SHOW_COPIES_AS_ADDS_MIN_VERSION):
            raise SkipTest('Subversion client is too old to test '
                           'history_scheduled_with_commit().')

        # Lone file with history is also excluded.  In this case there should
        # be no SystemExit raised and an (empty) diff should be produced. Test
        # from checkout root and via changelist.

        self._run_svn(['copy', 'foo.txt', 'foo_copy.txt'])
        revisions = self.client.parse_revision_spec([])
        result = self.client.diff(revisions, [], ['foo_copy.txt'])
        self.assertTrue(isinstance(result, dict))
        self.assertTrue('diff' in result)
        self.assertEqual(
            md5(result['diff']).hexdigest(),
            'd41d8cd98f00b204e9800998ecf8427e')

        self._run_svn(['changelist', 'cl1', 'foo_copy.txt'])
        revisions = self.client.parse_revision_spec(['cl1'])
        result = self.client.diff(revisions, [], ['foo_copy.txt'])
        self.assertTrue(isinstance(result, dict))
        self.assertTrue('diff' in result)
        self.assertEqual(
            md5(result['diff']).hexdigest(),
            'd41d8cd98f00b204e9800998ecf8427e')

    def test_rename_diff_mangling_bug_4546(self):
        """Test diff with removal of lines that look like headers"""
        # If a file has lines that look like "-- XX (YY)", and one of those
        # files gets removed, our rename handling would filter them out. Test
        # that the bug is fixed.
        with open('bug-4546.txt', 'w') as f:
            f.write('-- test line1\n'
                    '-- test line2\n'
                    '-- test line (test2)\n')

        revisions = self.client.parse_revision_spec()
        result = self.client.diff(revisions)
        self.assertTrue(isinstance(result, dict))
        self.assertTrue('diff' in result)
        self.assertTrue(b'--- test line (test1)' in result['diff'])