39
40
raise tests.TestSkipped(
40
41
"format %s doesn't support tags" % branch._format)
43
def make_branch_with_revisions(self, relpath, revisions):
44
builder = self.make_branch_builder(relpath)
45
builder.start_series()
46
for revid in revisions:
47
builder.build_commit(rev_id=revid)
48
builder.finish_series()
49
return builder.get_branch()
42
51
def test_tags_initially_empty(self):
43
52
b = self.make_branch('b')
44
53
tags = b.tags.get_tag_dict()
45
54
self.assertEqual(tags, {})
47
56
def test_make_and_lookup_tag(self):
48
b = self.make_branch('b')
57
b = self.make_branch_with_revisions('b',
58
['target-revid-1', 'target-revid-2'])
49
59
b.tags.set_tag('tag-name', 'target-revid-1')
50
60
b.tags.set_tag('other-name', 'target-revid-2')
51
61
# then reopen the branch and see they're still there
62
72
self.assertFalse(b.tags.has_tag('imaginary'))
64
74
def test_reverse_tag_dict(self):
65
b = self.make_branch('b')
75
b = self.make_branch_with_revisions('b',
76
['target-revid-1', 'target-revid-2'])
66
77
b.tags.set_tag('tag-name', 'target-revid-1')
67
78
b.tags.set_tag('other-name', 'target-revid-2')
68
79
# then reopen the branch and check reverse map id->tags list
69
80
b = branch.Branch.open('b')
70
self.assertEqual(b.tags.get_reverse_tag_dict(),
81
self.assertEqual(dict(b.tags.get_reverse_tag_dict()),
71
82
{'target-revid-1': ['tag-name'],
72
83
'target-revid-2': ['other-name'],
86
def test_ghost_tag(self):
87
b = self.make_branch('b')
88
if not b._format.supports_tags_referencing_ghosts():
89
self.assertRaises(errors.GhostTagsNotSupported,
90
b.tags.set_tag, "ghost", "idontexist")
92
b.tags.set_tag("ghost", "idontexist")
93
self.assertEquals("idontexist", b.tags.lookup_tag("ghost"))
75
95
def test_no_such_tag(self):
76
96
b = self.make_branch('b')
83
103
self.fail("didn't get expected exception")
85
105
def test_merge_tags(self):
86
b1 = self.make_branch('b1')
87
b2 = self.make_branch('b2')
106
b1 = self.make_branch_with_revisions('b1', ['revid', 'revid-1'])
107
b2 = self.make_branch_with_revisions('b2', ['revid', 'revid-2'])
88
108
# if there are tags in the source and not the destination, then they
90
110
b1.tags.set_tag('tagname', 'revid')
93
113
# if a tag is in the destination and not in the source, it is not
94
114
# removed when we merge them
95
115
b2.tags.set_tag('in-destination', 'revid')
96
result = b1.tags.merge_to(b2.tags)
97
self.assertEquals(list(result), [])
116
updates, conflicts = b1.tags.merge_to(b2.tags)
117
self.assertEquals(list(conflicts), [])
118
self.assertEquals(updates, {})
98
119
self.assertEquals(b2.tags.lookup_tag('in-destination'), 'revid')
99
120
# if there's a conflicting tag, it's reported -- the command line
100
121
# interface will say "these tags couldn't be copied"
101
122
b1.tags.set_tag('conflicts', 'revid-1')
102
123
b2.tags.set_tag('conflicts', 'revid-2')
103
result = b1.tags.merge_to(b2.tags)
104
self.assertEquals(list(result),
124
updates, conflicts = b1.tags.merge_to(b2.tags)
125
self.assertEquals(list(conflicts),
105
126
[('conflicts', 'revid-1', 'revid-2')])
106
127
# and it keeps the same value
128
self.assertEquals(updates, {})
107
129
self.assertEquals(b2.tags.lookup_tag('conflicts'), 'revid-2')
109
131
def test_unicode_tag(self):
110
b1 = self.make_branch('b')
111
132
tag_name = u'\u3070'
112
133
# in anticipation of the planned change to treating revision ids as
113
134
# just 8bit strings
114
135
revid = ('revid' + tag_name).encode('utf-8')
136
b1 = self.make_branch_with_revisions('b', [revid])
115
137
b1.tags.set_tag(tag_name, revid)
116
138
self.assertEquals(b1.tags.lookup_tag(tag_name), revid)
118
140
def test_delete_tag(self):
119
b = self.make_branch('b')
120
141
tag_name = u'\N{GREEK SMALL LETTER ALPHA}'
121
142
revid = ('revid' + tag_name).encode('utf-8')
143
b = self.make_branch_with_revisions('b', [revid])
122
144
b.tags.set_tag(tag_name, revid)
123
145
# now try to delete it
124
146
b.tags.delete_tag(tag_name)
145
167
# Open the same branch twice. Read-lock one, and then mutate the tags
146
168
# in the second. The read-locked branch never re-reads the tags, so it
147
169
# never observes the changed/new tags.
148
b1 = self.make_branch('b')
170
b1 = self.make_branch_with_revisions('b',
171
['rev-1', 'rev-1-changed', 'rev-2'])
149
172
b1.tags.set_tag('one', 'rev-1')
150
b2 = b1.bzrdir.open_branch()
173
b2 = _mod_bzrdir.BzrDir.open('b').open_branch()
152
175
self.assertEqual({'one': 'rev-1'}, b1.tags.get_tag_dict())
153
176
# Add a tag and modify a tag in b2. b1 is read-locked and has already
164
187
def test_unlocked_does_not_cache_tags(self):
165
188
"""Unlocked branches do not cache tags."""
166
189
# Open the same branch twice.
167
b1 = self.make_branch('b')
190
b1 = self.make_branch_with_revisions('b',
191
['rev-1', 'rev-1-changed', 'rev-2'])
168
192
b1.tags.set_tag('one', 'rev-1')
169
193
b2 = b1.bzrdir.open_branch()
170
194
self.assertEqual({'one': 'rev-1'}, b1.tags.get_tag_dict())
180
204
returns a copy of the cached data so that callers cannot accidentally
181
205
corrupt the cache.
183
b = self.make_branch('b')
207
b = self.make_branch_with_revisions('b',
208
['rev-1', 'rev-2', 'rev-3'])
184
209
b.tags.set_tag('one', 'rev-1')
185
210
self.addCleanup(b.lock_read().unlock)
186
211
# The first time the data returned will not be in the cache
194
219
self.assertEqual({'one': 'rev-1'}, b.tags.get_tag_dict())
196
221
def make_write_locked_branch_with_one_tag(self):
197
b = self.make_branch('b')
222
b = self.make_branch_with_revisions('b',
223
['rev-1', 'rev-1-changed', 'rev-2'])
198
224
b.tags.set_tag('one', 'rev-1')
199
225
self.addCleanup(b.lock_write().unlock)
200
226
# Populate the cache
214
240
def test_merge_to_invalides_cache(self):
215
241
b1 = self.make_write_locked_branch_with_one_tag()
216
b2 = self.make_branch('b2')
242
b2 = self.make_branch_with_revisions('b2', ['rev-2', 'rev-1'])
217
243
b2.tags.set_tag('two', 'rev-2')
218
244
b2.tags.merge_to(b1.tags)
219
245
self.assertEqual(
292
318
child.bind(master)
294
320
master.tags.set_tag('foo', 'rev-2')
295
tag_conflicts = other.tags.merge_to(child.tags, overwrite=True)
321
tag_updates, tag_conflicts = other.tags.merge_to(child.tags, overwrite=True)
296
322
self.assertEquals('rev-1', child.tags.lookup_tag('foo'))
297
323
self.assertEquals('rev-1', master.tags.lookup_tag('foo'))
324
self.assertEquals({"foo": "rev-1"}, tag_updates)
298
325
self.assertLength(0, tag_conflicts)
300
327
def test_merge_to_overwrite_conflict_in_child_and_master(self):
308
335
child = self.make_branch('child')
309
336
child.bind(master)
311
tag_conflicts = other.tags.merge_to(child.tags, overwrite=True)
338
tag_updates, tag_conflicts = other.tags.merge_to(
339
child.tags, overwrite=True)
312
340
self.assertEquals('rev-1', child.tags.lookup_tag('foo'))
313
341
self.assertEquals('rev-1', master.tags.lookup_tag('foo'))
342
self.assertEquals({u'foo': 'rev-1'}, tag_updates)
314
343
self.assertLength(0, tag_conflicts)
316
345
def test_merge_to_conflict_in_child_only(self):
325
354
child.bind(master)
327
356
master.tags.delete_tag('foo')
328
tag_conflicts = other.tags.merge_to(child.tags)
357
tag_updates, tag_conflicts = other.tags.merge_to(child.tags)
329
358
# Conflict in child, so it is unchanged.
330
359
self.assertEquals('rev-2', child.tags.lookup_tag('foo'))
331
360
# No conflict in the master, so the 'foo' tag equals other's value here.
332
361
self.assertEquals('rev-1', master.tags.lookup_tag('foo'))
333
362
# The conflict is reported.
334
363
self.assertEquals([(u'foo', 'rev-1', 'rev-2')], list(tag_conflicts))
364
self.assertEquals({u'foo': 'rev-1'}, tag_updates)
336
366
def test_merge_to_conflict_in_master_only(self):
337
367
"""When new_tags.merge_to(child.tags) conflicts with the master but not
344
374
child.bind(master)
346
376
master.tags.set_tag('foo', 'rev-2')
347
tag_conflicts = other.tags.merge_to(child.tags)
377
tag_updates, tag_conflicts = other.tags.merge_to(child.tags)
348
378
# No conflict in the child, so the 'foo' tag equals other's value here.
349
379
self.assertEquals('rev-1', child.tags.lookup_tag('foo'))
350
380
# Conflict in master, so it is unchanged.
351
381
self.assertEquals('rev-2', master.tags.lookup_tag('foo'))
352
382
# The conflict is reported.
383
self.assertEquals({u'foo': 'rev-1'}, tag_updates)
353
384
self.assertEquals([(u'foo', 'rev-1', 'rev-2')], list(tag_conflicts))
355
386
def test_merge_to_same_conflict_in_master_and_child(self):
363
394
child = self.make_branch('child')
364
395
child.bind(master)
366
tag_conflicts = other.tags.merge_to(child.tags)
397
tag_updates, tag_conflicts = other.tags.merge_to(child.tags)
367
398
# Both master and child conflict, so both stay as rev-2
368
399
self.assertEquals('rev-2', child.tags.lookup_tag('foo'))
369
400
self.assertEquals('rev-2', master.tags.lookup_tag('foo'))
370
401
# The conflict is reported exactly once, even though it occurs in both
371
402
# master and child.
403
self.assertEquals({}, tag_updates)
372
404
self.assertEquals([(u'foo', 'rev-1', 'rev-2')], list(tag_conflicts))
374
406
def test_merge_to_different_conflict_in_master_and_child(self):
385
417
# We use the private method _set_tag_dict because normally bzr tries to
386
418
# avoid this scenario.
387
419
child.tags._set_tag_dict({'foo': 'rev-3'})
388
tag_conflicts = other.tags.merge_to(child.tags)
420
tag_updates, tag_conflicts = other.tags.merge_to(child.tags)
389
421
# Both master and child conflict, so both stay as they were.
390
422
self.assertEquals('rev-3', child.tags.lookup_tag('foo'))
391
423
self.assertEquals('rev-2', master.tags.lookup_tag('foo'))
392
424
# Both conflicts are reported.
425
self.assertEquals({}, tag_updates)
393
426
self.assertEquals(
394
427
[(u'foo', 'rev-1', 'rev-2'), (u'foo', 'rev-1', 'rev-3')],
395
428
sorted(tag_conflicts))
453
486
get_tag_name, 'get tag name foo')
454
487
self.assertEquals("foo", self.branch.automatic_tag_name(
455
488
self.branch.last_revision()))
457
490
def test_uses_first_return(self):
458
491
get_tag_name_1 = lambda br, revid: "foo1"
459
492
get_tag_name_2 = lambda br, revid: "foo2"