Merge lp:~jelmer/bzr/foreign-tests into lp:~bzr/bzr/trunk-old

Proposed by Jelmer Vernooij
Status: Rejected
Rejected by: Ian Clatworthy
Proposed branch: lp:~jelmer/bzr/foreign-tests
Merge into: lp:~bzr/bzr/trunk-old
Diff against target: 151 lines
To merge this branch: bzr merge lp:~jelmer/bzr/foreign-tests
Reviewer Review Type Date Requested Status
John A Meinel Needs Fixing
Review via email: mp+9642@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Jelmer Vernooij (jelmer) wrote :

This branch adds two testcase classes in bzrlib.tests.foreign.test_branch that can be used as basis for the testcases in foreign branch plugins. I've posted matching branches of bzr-svn (lp:~jelmer/bzr-svn/foreign-tests and bzr-git (lp:~jelmer/bzr-git/foreign-tests) that use this. I'm hoping to add a lot more (and more complex) generic tests for the foreign code, to avoid duplicate work in each foreign vcs plugin.

I've considered using adapters rather than "manual" subclassing, but since some subclassing will be needed anyway (the generic tests don't test everything that should be tested) I think that would be overkill.

Does this seem like a reasonable approach?

Revision history for this message
John A Meinel (jameinel) wrote :

If we are going to go this route, I would probably call it a ForeignBranchTestMixin

since it is meant as a second parent class. (eg, users will do:

class TestMyBranchImpl(TestCase, ForeignBranchTestMixin)

However, I think I would tweak a few things differently anyway.

1) It should probably be called "per_foreign" rather than "foreign"

2) I think I would use adaptation rather than inheritance. Yes, there are going to be *more* tests that will be needed for specific foreign branch implementations, but those can just be created in another test class.

I think having a flag, etc on register_format to indicate this is a foreign format, would be a great move towards making registering the format automatically queue it for the appropriate tests.

It makes it less susceptible to accidentally missing some tests, because you forgot to inherit from the new base test class.

It also means that when we add a new base test class, it automatically starts getting run across all of the current implementations, we don't need to change anything in bzr-svn or bzr-git.

3) I would also like to see things like:
class ForeignBranchFormatTests(object):
  format = None # set by XXXXX

  def test_foo(self):
    self.format.x

It makes it easier to figure out where things are happening.

4) For something like ForiegnBranch, I think the tests you have are ok, though
126 + def test_last_revision(self):
127 + (revno, revid) = self.branch.last_revision_info()
128 + self.assertIsInstance(revno, int)
129 + self.assertIsInstance(revid, str)
130 + self.assertEquals(revno, self.branch.revision_id_to_revno(revid))
131 + self.assertEquals(revid, self.branch.last_revision())

^- this is testing more "last_revision_info" not last_revision. And I certainly thought you wanted to get away from 'revno' since it cannot be easily computed at all times.

I think what we should be doing is designing a reasonable factory interface, so that you can have the test case say:

 def test_something(self):
   self.factory.give_me_a_branch_like_X()

(a branch with 1 commit, a branch with a few commits, a branch with merges, etc.)

There was some discussion raised by Martin on the mailing list, which didn't quite as planned, but I think foreign branch testing is a *great* place to implement some of this, since a lot of them are going to be read-only sources, and thus doing:
  self.tree.commit('foo')
to generate the shape isn't going to work.

review: Approve
Revision history for this message
John A Meinel (jameinel) wrote :

sorry I marked the wrong status.

review: Needs Fixing
Revision history for this message
Jelmer Vernooij (jelmer) wrote :

Thanks for the review.

> However, I think I would tweak a few things differently anyway.
>
> 1) It should probably be called "per_foreign" rather than "foreign"
Wouldn't this mean we'd need per_foreign_branch, per_foreign_repository, per_foreign_branch_format, etc?

Cheers,

Jelmer

Revision history for this message
John A Meinel (jameinel) wrote :

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Jelmer Vernooij wrote:
> Thanks for the review.
>
>> However, I think I would tweak a few things differently anyway.
>>
>> 1) It should probably be called "per_foreign" rather than "foreign"
> Wouldn't this mean we'd need per_foreign_branch, per_foreign_repository, per_foreign_branch_format, etc?
>
> Cheers,
>
> Jelmer

It depends if you think you are going to have more than one branch type
per foreign type, and more than one repo type, etc.

At the moment, neither git nor hg have allowed anything of that sort.
I'm not sure that svn has either.

In which case adding the extra permutations doesn't seem to gain much of
anything.

John
=:->

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (Cygwin)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iEYEARECAAYFAkqFcJ4ACgkQJdeBCYSNAAMNzwCeIdhUQ5KvUi/8GNUgDyV1TayB
930An1GpW6cnBnBKvC2dwTWPuw4UY73s
=wjYm
-----END PGP SIGNATURE-----

Revision history for this message
Jelmer Vernooij (jelmer) wrote :

On Thu, Aug 13, 2009 at 05:09:06PM -0000, John A Meinel wrote:
> 3) I would also like to see things like:
> class ForeignBranchFormatTests(object):
> format = None # set by XXXXX

> def test_foo(self):
> self.format.x

> It makes it easier to figure out where things are happening.

This should work well for foreign branch formats. It's trickier though
in the case of foreign branches, where there is custom code necessary that
creates a branch. How would the adapter find the code that creates the
branch attribute that is used by the member methods of a testcase
class? This seems a lot easier with a MixIn, but I'm probably missing
something.

Cheers,

Jelmer

Revision history for this message
Martin Pool (mbp) wrote :

2009/9/3 Jelmer Vernooij <email address hidden>:
> On Thu, Aug 13, 2009 at 05:09:06PM -0000, John A Meinel wrote:
>> 3) I would also like to see things like:
>> class ForeignBranchFormatTests(object):
>>   format = None # set by XXXXX
>
>>   def test_foo(self):
>>     self.format.x
>
>> It makes it easier to figure out where things are happening.
>
> This should work well for foreign branch formats. It's trickier though
> in the case of foreign branches, where there is custom code necessary that
> creates a branch. How would the adapter find the code that creates the
> branch attribute that is used by the member methods of a testcase
> class? This seems a lot easier with a MixIn, but I'm probably missing
> something.

I might be missing the point, but I think you'd have

ForeignBranchTests(TestCase):

  branch_factory = None # set by scenario

  def test_log(self):
    branch = self.branch_factory.make_branch_with_crisscross_merges()

--
Martin <http://launchpad.net/~mbp/>

Revision history for this message
Jelmer Vernooij (jelmer) wrote :

On Thu, 2009-09-03 at 00:24 +0000, Martin Pool wrote:
> 2009/9/3 Jelmer Vernooij <email address hidden>:
> > On Thu, Aug 13, 2009 at 05:09:06PM -0000, John A Meinel wrote:
> >> 3) I would also like to see things like:
> >> class ForeignBranchFormatTests(object):
> >> format = None # set by XXXXX
> >
> >> def test_foo(self):
> >> self.format.x
> >
> >> It makes it easier to figure out where things are happening.
> >
> > This should work well for foreign branch formats. It's trickier though
> > in the case of foreign branches, where there is custom code necessary that
> > creates a branch. How would the adapter find the code that creates the
> > branch attribute that is used by the member methods of a testcase
> > class? This seems a lot easier with a MixIn, but I'm probably missing
> > something.
>
> I might be missing the point, but I think you'd have
>
> ForeignBranchTests(TestCase):
>
> branch_factory = None # set by scenario
>
> def test_log(self):
> branch = self.branch_factory.make_branch_with_crisscross_merges()
Yeah, that makes sense. What about something like the attached patch?

Cheers,

Jelmer

--
Jelmer Vernooij <email address hidden> - http://samba.org/~jelmer/
Jabber: <email address hidden>

# Bazaar merge directive format 2 (Bazaar 0.90)
# revision_id: jelmer@samba.org-20091011013123-zbcruv13w8q2h6r5
# target_branch: http://people.samba.org/bzr/jelmer/bzr/squash-xml-\
# invalid-chars
# testament_sha1: 32984381e00180079b59a5192388743b5ddf002e
# timestamp: 2009-10-11 03:33:30 +0200
# base_revision_id: pqm@pqm.ubuntu.com-20091006204548-bjnc3z4k256ppimz
#
# Begin patch
=== modified file 'bzrlib/foreign.py'
--- bzrlib/foreign.py 2009-10-06 14:40:37 +0000
+++ bzrlib/foreign.py 2009-10-11 01:31:23 +0000
@@ -36,7 +36,7 @@
36""")36""")
3737
38class VcsMapping(object):38class VcsMapping(object):
39 """Describes the mapping between the semantics of Bazaar and a foreign vcs.39 """Describes the mapping between the semantics of Bazaar and a foreign VCS.
4040
41 """41 """
42 # Whether this is an experimental mapping that is still open to changes.42 # Whether this is an experimental mapping that is still open to changes.
@@ -122,6 +122,8 @@
122class ForeignVcs(object):122class ForeignVcs(object):
123 """A foreign version control system."""123 """A foreign version control system."""
124124
125 branch_format = None
126
125 def __init__(self, mapping_registry):127 def __init__(self, mapping_registry):
126 self.mapping_registry = mapping_registry128 self.mapping_registry = mapping_registry
127129
128130
=== modified file 'bzrlib/tests/__init__.py'
--- bzrlib/tests/__init__.py 2009-10-01 14:44:43 +0000
+++ bzrlib/tests/__init__.py 2009-10-10 22:28:00 +0000
@@ -3650,6 +3650,7 @@
3650 'bzrlib.tests.commands',3650 'bzrlib.tests.commands',
3651 'bzrlib.tests.per_branch',3651 'bzrlib.tests.per_branch',
3652 'bzrlib.tests.per_bzrdir',3652 'bzrlib.tests.per_bzrdir',
3653 'bzrlib.tests.per_foreign_vcs',
3653 'bzrlib.tests.per_interrepository',3654 'bzrlib.tests.per_interrepository',
3654 'bzrlib.tests.per_intertree',3655 'bzrlib.tests.per_intertree',
3655 'bzrlib.tests.per_inventory',3656 'bzrlib.tests.per_inventory',
36563657
=== added directory 'bzrlib/tests/per_foreign_vcs'
=== added file 'bzrlib/tests/per_foreign_vcs/__init__.py'
--- bzrlib/tests/per_foreign_vcs/__init__.py 1970-01-01 00:00:00 +0000
+++ bzrlib/tests/per_foreign_vcs/__init__.py 2009-10-11 01:02:28 +0000
@@ -0,0 +1,47 @@
1# Copyright (C) 2009 Canonical Ltd
2#
3# This program is free software; you can redistribute it and/or modify
4# it under the terms of the GNU General Public License as published by
5# the Free Software Foundation; either version 2 of the License, or
6# (at your option) any later version.
7#
8# This program is distributed in the hope that it will be useful,
9# but WITHOUT ANY WARRANTY; without even the implied warranty of
10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11# GNU General Public License for more details.
12#
13# You should have received a copy of the GNU General Public License
14# along with this program; if not, write to the Free Software
15# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
17
18"""Tests specific to foreign branch implementations.
19
20"""
21
22from bzrlib import (
23 foreign,
24 tests,
25 )
26
27
28def vcs_scenarios():
29 scenarios = []
30 for name, vcs in foreign.foreign_vcs_registry.iteritems():
31 scenarios.append((vcs.__class__.__name__, {
32 "branch_factory": vcs.branch_format.get_foreign_tests_branch_factory(),
33 "branch_format": vcs.branch_format,
34 }))
35 return scenarios
36
37
38def load_tests(standard_tests, module, loader):
39 result = loader.suiteClass()
40 per_vcs_mod_names = [
41 'branch',
42 ]
43 sub_tests = loader.loadTestsFromModuleNames(
44 ['bzrlib.tests.per_foreign_vcs.test_' + name
45 for name in per_vcs_mod_names])
46 tests.multiply_tests(sub_tests, vcs_scenarios(), result)
47 return result
048
=== added file 'bzrlib/tests/per_foreign_vcs/test_branch.py'
--- bzrlib/tests/per_foreign_vcs/test_branch.py 1970-01-01 00:00:00 +0000
+++ bzrlib/tests/per_foreign_vcs/test_branch.py 2009-10-11 01:20:37 +0000
@@ -0,0 +1,151 @@
1# Copyright (C) 2009 Canonical Ltd
2#
3# This program is free software; you can redistribute it and/or modify
4# it under the terms of the GNU General Public License as published by
5# the Free Software Foundation; either version 2 of the License, or
6# (at your option) any later version.
7#
8# This program is distributed in the hope that it will be useful,
9# but WITHOUT ANY WARRANTY; without even the implied warranty of
10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11# GNU General Public License for more details.
12#
13# You should have received a copy of the GNU General Public License
14# along with this program; if not, write to the Free Software
15# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
17
18"""Tests specific to Branch implementations that use foreign VCS'es."""
19
20
21from bzrlib.errors import (
22 UnstackableBranchFormat,
23 )
24from bzrlib.revision import (
25 NULL_REVISION,
26 )
27from bzrlib.tests import (
28 TestCase,
29 TestCaseWithTransport,
30 )
31
32
33class ForeignBranchFactory(object):
34 """Factory of branches for ForeignBranchTests."""
35
36 def make_empty_branch(self, transport):
37 """Create an empty branch with no commits in it."""
38 raise NotImplementedError(self.make_empty_branch)
39
40 def make_branch(self, transport):
41 """Create *some* branch, may be empty or not."""
42 return self.make_empty_branch(transport)
43
44
45class ForeignBranchTests(TestCaseWithTransport):
46 """Basic tests for foreign branch implementations.
47
48 These tests mainly make sure that the implementation covers the required
49 bits of the API and returns reasonable values.
50 """
51 branch_factory = None # Set to an instance of ForeignBranchFactory by scenario
52
53 def make_empty_branch(self):
54 return self.branch_factory.make_empty_branch(self.get_transport())
55
56 def make_branch(self):
57 return self.branch_factory.make_branch(self.get_transport())
58
59 def test_set_parent(self):
60 """Test that setting the parent works."""
61 branch = self.make_branch()
62 branch.set_parent("foobar")
63
64 def test_break_lock(self):
65 """Test that break_lock() works, even if it is a no-op."""
66 branch = self.make_branch()
67 branch.break_lock()
68
69 def test_set_push_location(self):
70 """Test that setting the push location works."""
71 branch = self.make_branch()
72 branch.set_push_location("http://bar/bloe")
73
74 def test_repr_type(self):
75 branch = self.make_branch()
76 self.assertIsInstance(repr(branch), str)
77
78 def test_get_parent(self):
79 """Test that getting the parent location works, and returns None."""
80 # TODO: Allow this to be non-None when foreign branches add support
81 # for storing this URL.
82 branch = self.make_branch()
83 self.assertIs(None, branch.get_parent())
84
85 def test_get_push_location(self):
86 """Test that getting the push location works, and returns None."""
87 # TODO: Allow this to be non-None when foreign branches add support
88 # for storing this URL.
89 branch = self.make_branch()
90 self.assertIs(None, branch.get_push_location())
91
92 def test_attributes(self):
93 """Check that various required attributes are present."""
94 branch = self.make_branch()
95 self.assertIsNot(None, getattr(branch, "repository", None))
96 self.assertIsNot(None, getattr(branch, "mapping", None))
97 self.assertIsNot(None, getattr(branch, "_format", None))
98 self.assertIsNot(None, getattr(branch, "base", None))
99
100 def test__get_nick(self):
101 """Make sure _get_nick is implemented and returns a string."""
102 branch = self.make_branch()
103 self.assertIsInstance(branch._get_nick(local=False), str)
104 self.assertIsInstance(branch._get_nick(local=True), str)
105
106 def test_null_revid_revno(self):
107 """null: should return revno 0."""
108 branch = self.make_branch()
109 self.assertEquals(0, branch.revision_id_to_revno(NULL_REVISION))
110
111 def test_get_stacked_on_url(self):
112 """Test that get_stacked_on_url() behaves as expected.
113
114 Inter-Format stacking doesn't work yet, so all foreign implementations
115 should raise UnstackableBranchFormat at the moment.
116 """
117 branch = self.make_branch()
118 self.assertRaises(UnstackableBranchFormat,
119 branch.get_stacked_on_url)
120
121 def test_get_physical_lock_status(self):
122 branch = self.make_branch()
123 self.assertFalse(branch.get_physical_lock_status())
124
125 def test_last_revision_empty_branch(self):
126 branch = self.make_empty_branch()
127 self.assertEquals(NULL_REVISION, branch.last_revision())
128 self.assertEquals(0, branch.revno())
129 self.assertEquals((0, NULL_REVISION), branch.last_revision_info())
130
131
132class ForeignBranchFormatTests(TestCase):
133 """Basic tests for foreign branch format objects."""
134
135 branch_format = None # Set to a BranchFormat instance by adapter
136
137 def test_initialize(self):
138 """Test this format is not initializable.
139
140 Remote branches may be initializable on their own, but none currently
141 support living in .bzr/branch.
142 """
143 self.assertRaises(NotImplementedError, self.branch_format.initialize, None)
144
145 def test_get_format_description_type(self):
146 self.assertIsInstance(self.branch_format.get_format_description(), str)
147
148 def test_network_name(self):
149 self.assertIsInstance(self.branch_format.network_name(), str)
150
151
0152
# Begin bundle
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
73ZyxA1ihC6080hgggiL4PmTRbM44RhigwByNUw4CnycFQTK/32m5B5cvH0GfceSz8NxdwL6HrLBXh225ZyxA1ihC6080hgggiL4PmTRbM44RhigwByNUw4CnycFQTK/32m5B5cvH0GfceSz8NxdwL6HrLBXh
74oAeNtUX2hcPAqntseYTCZs7CxnoSycTy1GmBthIimGulQTm7REC48z4mhwpr1HtDSmYvWBh5i02Q226oAeNtUX2hcPAqntseYTCZs7CxnoSycTy1GmBthIimGulQTm7REC48z4mhwpr1HtDSmYvWBh5i02Q
75IMxQUgFiVJoTwLMoN34m6YjTqig8IhYrktYGo18ACPrBBJB/XtJId87xEVyb4SGxcC6Z0XDX7Grp227IMxQUgFiVJoTwLMoN34m6YjTqig8IhYrktYGo18ACPrBBJB/XtJId87xEVyb4SGxcC6Z0XDX7Grp
76CFqua6+UzykmDBYXOSjl5SQ8EhgOwloE40UykfeCClkICKR10CRtN2zt3+pC4lHX2nEh1FA3I50D228CFqua6+UzykmDBYXOSjl5SQ8EhgOwloE40UykfeCClkICKR10CRtN2zt3+pC4lHX2nEh1FA3I50D
77njYGrpeoPTXkjoa+NmWHWksiswWSSniYlZ2vK5wzeFxnChjyBicK6wnTfRUtq7gZcByDLQlCo1F7229njYGrpeoPTXkjoa+NmWHWksiswWSSniYlZ2vK5wzeFxnChjyBicK6wnTfRUtq7gZcByDLQlCo1F7
7877bSYpz1pBnsN76dJFP1AZATzcTbYlSC9ERtv7DtotxpbhMggiSSlISGYHNHsG7yQ6NQOJ0iQG0O23077bSYpz1pBnsN76dJFP1AZATzcTbYlSC9ERtv7DtotxpbhMggiSSlISGYHNHsG7yQ6NQOJ0iQG0O
79A/DXAObRGNYyMIOW7Ux+FOIg8+DEpTAUwXcFp0nk56iYYbshM+g5WeeRXp7MXJbqlSWwTq6y1o02231A/DXAObRGNYyMIOW7Ux+FOIg8+DEpTAUwXcFp0nk56iYYbshM+g5WeeRXp7MXJbqlSWwTq6y1o02
80oBlVpoImG4x0hdWrpDETQsVM1Bm7OkkE38Byt5bkqDOIViYrybAdhUr5j2qJYY24y0M+wSG1b8Ss232oBlVpoImG4x0hdWrpDETQsVM1Bm7OkkE38Byt5bkqDOIViYrybAdhUr5j2qJYY24y0M+wSG1b8Ss
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
Revision history for this message
Ian Clatworthy (ian-clatworthy) wrote :

I'm going to change the status to 'reject' because it looks like this has been superseded by the merge proposal for foreign-tests1. If I'm wrong, please resubmit this.

Updating diff...

An updated diff will be available in a few minutes. Reload to see the changes.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== added directory 'bzrlib/tests/foreign'
=== added file 'bzrlib/tests/foreign/__init__.py'
--- bzrlib/tests/foreign/__init__.py 1970-01-01 00:00:00 +0000
+++ bzrlib/tests/foreign/__init__.py 2009-08-31 04:36:07 +0000
@@ -0,0 +1,20 @@
1# Copyright (C) 2009 Canonical Ltd
2#
3# This program is free software; you can redistribute it and/or modify
4# it under the terms of the GNU General Public License as published by
5# the Free Software Foundation; either version 2 of the License, or
6# (at your option) any later version.
7#
8# This program is distributed in the hope that it will be useful,
9# but WITHOUT ANY WARRANTY; without even the implied warranty of
10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11# GNU General Public License for more details.
12#
13# You should have received a copy of the GNU General Public License
14# along with this program; if not, write to the Free Software
15# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
17
18"""Tests specific to foreign branch implementations.
19
20"""
021
=== added file 'bzrlib/tests/foreign/test_branch.py'
--- bzrlib/tests/foreign/test_branch.py 1970-01-01 00:00:00 +0000
+++ bzrlib/tests/foreign/test_branch.py 2009-08-31 04:36:07 +0000
@@ -0,0 +1,121 @@
1# Copyright (C) 2009 Canonical Ltd
2#
3# This program is free software; you can redistribute it and/or modify
4# it under the terms of the GNU General Public License as published by
5# the Free Software Foundation; either version 2 of the License, or
6# (at your option) any later version.
7#
8# This program is distributed in the hope that it will be useful,
9# but WITHOUT ANY WARRANTY; without even the implied warranty of
10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11# GNU General Public License for more details.
12#
13# You should have received a copy of the GNU General Public License
14# along with this program; if not, write to the Free Software
15# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
17
18"""Tests specific to Branch implementations that use foreign VCS'es."""
19
20
21from bzrlib.errors import (
22 UnstackableBranchFormat,
23 )
24from bzrlib.revision import (
25 NULL_REVISION,
26 )
27
28
29class ForeignBranchTests(object):
30 """Basic tests for foreign branch implementations.
31
32 These tests mainly make sure that the implementation covers the required
33 bits of the API and returns reasonable values.
34 """
35
36 def test_set_parent(self):
37 """Test that setting the parent works."""
38 self.branch.set_parent("foobar")
39
40 def test_break_lock(self):
41 """Test that break_lock() works, even if it is a no-op."""
42 self.branch.break_lock()
43
44 def test_set_push_location(self):
45 """Test that setting the push location works."""
46 self.branch.set_push_location("http://bar/bloe")
47
48 def test_repr_type(self):
49 self.assertIsInstance(repr(self.branch), str)
50
51 def test_get_parent(self):
52 """Test that getting the parent location works, and returns None."""
53 # TODO: Allow this to be non-None when foreign branches add support
54 # for storing this URL.
55 self.assertIs(None, self.branch.get_parent())
56
57 def test_get_push_location(self):
58 """Test that getting the push location works, and returns None."""
59 # TODO: Allow this to be non-None when foreign branches add support
60 # for storing this URL.
61 self.assertIs(None, self.branch.get_push_location())
62
63 def test_check(self):
64 """See if a basic check works."""
65 result = self.branch.check()
66 self.assertEqual(self.branch, result.branch)
67
68 def test_attributes(self):
69 """Check that various required attributes are present."""
70 self.assertIsNot(None, getattr(self.branch, "repository", None))
71 self.assertIsNot(None, getattr(self.branch, "mapping", None))
72 self.assertIsNot(None, getattr(self.branch, "_format", None))
73 self.assertIsNot(None, getattr(self.branch, "base", None))
74
75 def test__get_nick(self):
76 """Make sure _get_nick is implemented and returns a string."""
77 self.assertIsInstance(self.branch._get_nick(local=False), str)
78 self.assertIsInstance(self.branch._get_nick(local=True), str)
79
80 def test_null_revid_revno(self):
81 """null: should return revno 0."""
82 self.assertEquals(0, self.branch.revision_id_to_revno(NULL_REVISION))
83
84 def test_get_stacked_on_url(self):
85 """Test that get_stacked_on_url() behaves as expected.
86
87 Inter-Format stacking doesn't work yet, so all foreign implementations
88 should raise UnstackableBranchFormat at the moment.
89 """
90 self.assertRaises(UnstackableBranchFormat,
91 self.branch.get_stacked_on_url)
92
93 def test_get_physical_lock_status(self):
94 self.assertFalse(self.branch.get_physical_lock_status())
95
96 def test_last_revision(self):
97 (revno, revid) = self.branch.last_revision_info()
98 self.assertIsInstance(revno, int)
99 self.assertIsInstance(revid, str)
100 self.assertEquals(revno, self.branch.revision_id_to_revno(revid))
101 self.assertEquals(revid, self.branch.last_revision())
102
103
104class ForeignBranchFormatTests(object):
105 """Basic tests for foreign branch format objects."""
106
107 def test_initialize(self):
108 """Test this format is not initializable.
109
110 Remote branches may be initializable on their own, but none currently
111 support living in .bzr/branch.
112 """
113 self.assertRaises(NotImplementedError, self.format.initialize, None)
114
115 def test_get_format_description_type(self):
116 self.assertIsInstance(self.format.get_format_description(), str)
117
118 def test_network_name(self):
119 self.assertIsInstance(self.format.network_name(), str)
120
121