1
# Copyright (C) 2007, 2009, 2010 Canonical Ltd
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.
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.
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
17
"""Tags stored within a branch
19
The tags are actually in the Branch.tags namespace, but these are
20
1:1 with Branch implementations so can be tested from here.
30
from bzrlib.tests import per_branch
33
class TestBranchTags(per_branch.TestCaseWithBranch):
36
super(TestBranchTags, self).setUp()
37
# formats that don't support tags can skip the rest of these
39
branch = self.make_branch('probe')
40
if not branch._format.supports_tags():
41
raise tests.TestSkipped(
42
"format %s doesn't support tags" % branch._format)
44
def test_tags_initially_empty(self):
45
b = self.make_branch('b')
46
tags = b.tags.get_tag_dict()
47
self.assertEqual(tags, {})
49
def test_make_and_lookup_tag(self):
50
b = self.make_branch('b')
51
b.tags.set_tag('tag-name', 'target-revid-1')
52
b.tags.set_tag('other-name', 'target-revid-2')
53
# then reopen the branch and see they're still there
54
b = branch.Branch.open('b')
55
self.assertEqual(b.tags.get_tag_dict(),
56
{'tag-name': 'target-revid-1',
57
'other-name': 'target-revid-2',
60
result = b.tags.lookup_tag('tag-name')
61
self.assertEqual(result, 'target-revid-1')
63
self.assertTrue(b.tags.has_tag('tag-name'))
64
self.assertFalse(b.tags.has_tag('imaginary'))
66
def test_reverse_tag_dict(self):
67
b = self.make_branch('b')
68
b.tags.set_tag('tag-name', 'target-revid-1')
69
b.tags.set_tag('other-name', 'target-revid-2')
70
# then reopen the branch and check reverse map id->tags list
71
b = branch.Branch.open('b')
72
self.assertEqual(b.tags.get_reverse_tag_dict(),
73
{'target-revid-1': ['tag-name'],
74
'target-revid-2': ['other-name'],
77
def test_no_such_tag(self):
78
b = self.make_branch('b')
80
b.tags.lookup_tag('bosko')
81
except errors.NoSuchTag, e:
82
self.assertEquals(e.tag_name, 'bosko')
83
self.assertEquals(str(e), 'No such tag: bosko')
85
self.fail("didn't get expected exception")
87
def test_merge_tags(self):
88
b1 = self.make_branch('b1')
89
b2 = self.make_branch('b2')
90
# if there are tags in the source and not the destination, then they
92
b1.tags.set_tag('tagname', 'revid')
93
b1.tags.merge_to(b2.tags)
94
self.assertEquals(b2.tags.lookup_tag('tagname'), 'revid')
95
# if a tag is in the destination and not in the source, it is not
96
# removed when we merge them
97
b2.tags.set_tag('in-destination', 'revid')
98
result = b1.tags.merge_to(b2.tags)
99
self.assertEquals(result, [])
100
self.assertEquals(b2.tags.lookup_tag('in-destination'), 'revid')
101
# if there's a conflicting tag, it's reported -- the command line
102
# interface will say "these tags couldn't be copied"
103
b1.tags.set_tag('conflicts', 'revid-1')
104
b2.tags.set_tag('conflicts', 'revid-2')
105
result = b1.tags.merge_to(b2.tags)
106
self.assertEquals(result,
107
[('conflicts', 'revid-1', 'revid-2')])
108
# and it keeps the same value
109
self.assertEquals(b2.tags.lookup_tag('conflicts'), 'revid-2')
112
def test_unicode_tag(self):
113
b1 = self.make_branch('b')
115
# in anticipation of the planned change to treating revision ids as
117
revid = ('revid' + tag_name).encode('utf-8')
118
b1.tags.set_tag(tag_name, revid)
119
self.assertEquals(b1.tags.lookup_tag(tag_name), revid)
121
def test_delete_tag(self):
122
b = self.make_branch('b')
123
tag_name = u'\N{GREEK SMALL LETTER ALPHA}'
124
revid = ('revid' + tag_name).encode('utf-8')
125
b.tags.set_tag(tag_name, revid)
126
# now try to delete it
127
b.tags.delete_tag(tag_name)
128
# now you can't look it up
129
self.assertRaises(errors.NoSuchTag,
130
b.tags.lookup_tag, tag_name)
131
# and it's not in the dictionary
132
self.assertEquals(b.tags.get_tag_dict(), {})
133
# and you can't remove it a second time
134
self.assertRaises(errors.NoSuchTag,
135
b.tags.delete_tag, tag_name)
136
# or remove a tag that never existed
137
self.assertRaises(errors.NoSuchTag,
138
b.tags.delete_tag, tag_name + '2')
140
def test_merge_empty_tags(self):
141
# you can merge tags between two instances, since neither have tags
142
b1 = self.make_branch('b1')
143
b2 = self.make_branch('b2')
144
b1.tags.merge_to(b2.tags)
147
class TestUnsupportedTags(per_branch.TestCaseWithBranch):
148
"""Formats that don't support tags should give reasonable errors."""
151
super(TestUnsupportedTags, self).setUp()
152
branch = self.make_branch('probe')
153
if branch._format.supports_tags():
154
raise tests.TestSkipped("Format %s declares that tags are supported"
156
# it's covered by TestBranchTags
158
def test_tag_methods_raise(self):
159
b = self.make_branch('b')
160
self.assertRaises(errors.TagsNotSupported,
161
b.tags.set_tag, 'foo', 'bar')
162
self.assertRaises(errors.TagsNotSupported,
163
b.tags.lookup_tag, 'foo')
164
self.assertRaises(errors.TagsNotSupported,
165
b.tags.set_tag, 'foo', 'bar')
166
self.assertRaises(errors.TagsNotSupported,
167
b.tags.delete_tag, 'foo')
169
def test_merge_empty_tags(self):
170
# you can merge tags between two instances, since neither have tags
171
b1 = self.make_branch('b1')
172
b2 = self.make_branch('b2')
173
b1.tags.merge_to(b2.tags)
176
class AutomaticTagNameTests(per_branch.TestCaseWithBranch):
179
super(AutomaticTagNameTests, self).setUp()
180
if isinstance(self.branch_format, branch.BranchReferenceFormat):
181
# This test could in principle apply to BranchReferenceFormat, but
182
# make_branch_builder doesn't support it.
183
raise tests.TestSkipped(
184
"BranchBuilder can't make reference branches.")
185
self.builder = self.make_branch_builder('.')
186
self.builder.build_snapshot('foo', None,
187
[('add', ('', None, 'directory', None))],
189
self.branch = self.builder.get_branch()
190
if not self.branch._format.supports_tags():
191
raise tests.TestSkipped(
192
"format %s doesn't support tags" % self.branch._format)
194
def test_no_functions(self):
195
rev = self.branch.last_revision()
196
self.assertEquals(None, self.branch.automatic_tag_name(rev))
198
def test_returns_tag_name(self):
199
def get_tag_name(br, revid):
201
branch.Branch.hooks.install_named_hook('automatic_tag_name',
202
get_tag_name, 'get tag name foo')
203
self.assertEquals("foo", self.branch.automatic_tag_name(
204
self.branch.last_revision()))
206
def test_uses_first_return(self):
207
get_tag_name_1 = lambda br, revid: "foo1"
208
get_tag_name_2 = lambda br, revid: "foo2"
209
branch.Branch.hooks.install_named_hook('automatic_tag_name',
210
get_tag_name_1, 'tagname1')
211
branch.Branch.hooks.install_named_hook('automatic_tag_name',
212
get_tag_name_2, 'tagname2')
213
self.assertEquals("foo1", self.branch.automatic_tag_name(
214
self.branch.last_revision()))
216
def test_ignores_none(self):
217
get_tag_name_1 = lambda br, revid: None
218
get_tag_name_2 = lambda br, revid: "foo2"
219
branch.Branch.hooks.install_named_hook('automatic_tag_name',
220
get_tag_name_1, 'tagname1')
221
branch.Branch.hooks.install_named_hook('automatic_tag_name',
222
get_tag_name_2, 'tagname2')
223
self.assertEquals("foo2", self.branch.automatic_tag_name(
224
self.branch.last_revision()))