~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_revisionnamespaces.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2006-07-12 12:36:57 UTC
  • mfrom: (1732.3.4 bzr.revnoX)
  • Revision ID: pqm@pqm.ubuntu.com-20060712123657-365eeb32b69308bf
(matthieu) revno:x:url revision spec

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2010 Canonical Ltd
2
 
#
 
1
# Copyright (C) 2004, 2005, 2006 by Canonical Ltd
 
2
 
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
5
5
# the Free Software Foundation; either version 2 of the License, or
6
6
# (at your option) any later version.
7
 
#
 
7
 
8
8
# This program is distributed in the hope that it will be useful,
9
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
11
# GNU General Public License for more details.
12
 
#
 
12
 
13
13
# You should have received a copy of the GNU General Public License
14
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
 
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
16
 
17
 
import datetime
18
17
import os
19
18
import time
20
19
 
21
 
from bzrlib import (
22
 
    branch,
23
 
    bzrdir,
24
 
    errors,
25
 
    repository,
26
 
    revision as _mod_revision,
27
 
    )
28
 
from bzrlib.tests import TestCase, TestCaseWithTransport
29
 
from bzrlib.revisionspec import (
30
 
    RevisionSpec,
31
 
    RevisionSpec_revno,
32
 
    RevisionSpec_tag,
33
 
    )
34
 
 
35
 
 
36
 
def spec_in_history(spec, branch):
37
 
    """A simple helper to change a revision spec into a branch search"""
38
 
    return RevisionSpec.from_string(spec).in_history(branch)
39
 
 
40
 
 
41
 
# Basic class, which just creates a really basic set of revisions
42
 
class TestRevisionSpec(TestCaseWithTransport):
43
 
 
44
 
    def setUp(self):
45
 
        super(TestRevisionSpec, self).setUp()
46
 
        # this sets up a revision graph:
47
 
        # r1: []             1
48
 
        # alt_r2: [r1]       1.1.1
49
 
        # r2: [r1, alt_r2]   2
50
 
 
51
 
        self.tree = self.make_branch_and_tree('tree')
52
 
        self.build_tree(['tree/a'])
53
 
        self.tree.lock_write()
54
 
        self.addCleanup(self.tree.unlock)
55
 
        self.tree.add(['a'])
56
 
        self.tree.commit('a', rev_id='r1')
57
 
 
58
 
        self.tree2 = self.tree.bzrdir.sprout('tree2').open_workingtree()
59
 
        self.tree2.commit('alt', rev_id='alt_r2')
60
 
 
61
 
        self.tree.merge_from_branch(self.tree2.branch)
62
 
        self.tree.commit('second', rev_id='r2')
63
 
 
64
 
    def get_in_history(self, revision_spec):
65
 
        return spec_in_history(revision_spec, self.tree.branch)
66
 
 
67
 
    def assertInHistoryIs(self, exp_revno, exp_revision_id, revision_spec):
68
 
        rev_info = self.get_in_history(revision_spec)
69
 
        self.assertEqual(exp_revno, rev_info.revno,
70
 
                         'Revision spec: %r returned wrong revno: %r != %r'
71
 
                         % (revision_spec, exp_revno, rev_info.revno))
72
 
        self.assertEqual(exp_revision_id, rev_info.rev_id,
73
 
                         'Revision spec: %r returned wrong revision id:'
74
 
                         ' %r != %r'
75
 
                         % (revision_spec, exp_revision_id, rev_info.rev_id))
76
 
 
77
 
    def assertInvalid(self, revision_spec, extra='',
78
 
                      invalid_as_revision_id=True):
79
 
        try:
80
 
            self.get_in_history(revision_spec)
81
 
        except errors.InvalidRevisionSpec, e:
82
 
            self.assertEqual(revision_spec, e.spec)
83
 
            self.assertEqual(extra, e.extra)
84
 
        else:
85
 
            self.fail('Expected InvalidRevisionSpec to be raised for'
86
 
                      ' %r.in_history' % (revision_spec,))
87
 
        if invalid_as_revision_id:
88
 
            try:
89
 
                spec = RevisionSpec.from_string(revision_spec)
90
 
                spec.as_revision_id(self.tree.branch)
91
 
            except errors.InvalidRevisionSpec, e:
92
 
                self.assertEqual(revision_spec, e.spec)
93
 
                self.assertEqual(extra, e.extra)
94
 
            else:
95
 
                self.fail('Expected InvalidRevisionSpec to be raised for'
96
 
                          ' %r.as_revision_id' % (revision_spec,))
97
 
 
98
 
    def assertAsRevisionId(self, revision_id, revision_spec):
99
 
        """Calling as_revision_id() should return the specified id."""
100
 
        spec = RevisionSpec.from_string(revision_spec)
101
 
        self.assertEqual(revision_id,
102
 
                         spec.as_revision_id(self.tree.branch))
103
 
 
104
 
    def get_as_tree(self, revision_spec, tree=None):
105
 
        if tree is None:
106
 
            tree = self.tree
107
 
        spec = RevisionSpec.from_string(revision_spec)
108
 
        return spec.as_tree(tree.branch)
109
 
 
110
 
 
111
 
class RevisionSpecMatchOnTrap(RevisionSpec):
112
 
 
113
 
    def _match_on(self, branch, revs):
114
 
        self.last_call = (branch, revs)
115
 
        return super(RevisionSpecMatchOnTrap, self)._match_on(branch, revs)
116
 
 
117
 
 
118
 
class TestRevisionSpecBase(TestRevisionSpec):
119
 
 
120
 
    def test_wants_revision_history(self):
121
 
        # If wants_revision_history = True, then _match_on should get the
122
 
        # branch revision history
123
 
        spec = RevisionSpecMatchOnTrap('foo', _internal=True)
124
 
        spec.in_history(self.tree.branch)
125
 
 
126
 
        self.assertEqual((self.tree.branch, ['r1' ,'r2']),
127
 
                         spec.last_call)
128
 
 
129
 
    def test_wants_no_revision_history(self):
130
 
        # If wants_revision_history = False, then _match_on should get None for
131
 
        # the branch revision history
132
 
        spec = RevisionSpecMatchOnTrap('foo', _internal=True)
133
 
        spec.wants_revision_history = False
134
 
        spec.in_history(self.tree.branch)
135
 
 
136
 
        self.assertEqual((self.tree.branch, None), spec.last_call)
137
 
 
138
 
 
139
 
 
140
 
class TestOddRevisionSpec(TestRevisionSpec):
141
 
    """Test things that aren't normally thought of as revision specs"""
142
 
 
143
 
    def test_none(self):
144
 
        self.assertInHistoryIs(None, None, None)
145
 
 
146
 
    def test_object(self):
147
 
        self.assertRaises(TypeError, RevisionSpec.from_string, object())
148
 
 
149
 
 
150
 
class TestRevisionSpec_dwim(TestRevisionSpec):
151
 
 
152
 
    # Don't need to test revno's explicitly since TRS_revno already
153
 
    # covers that well for us
154
 
    def test_dwim_spec_revno(self):
155
 
        self.assertInHistoryIs(2, 'r2', '2')
156
 
        self.assertAsRevisionId('alt_r2', '1.1.1')
157
 
 
158
 
    def test_dwim_spec_revid(self):
159
 
        self.assertInHistoryIs(2, 'r2', 'r2')
160
 
 
161
 
    def test_dwim_spec_tag(self):
162
 
        self.tree.branch.tags.set_tag('footag', 'r1')
163
 
        self.assertAsRevisionId('r1', 'footag')
164
 
        self.tree.branch.tags.delete_tag('footag')
165
 
        self.assertRaises(errors.InvalidRevisionSpec,
166
 
                          self.get_in_history, 'footag')
167
 
 
168
 
    def test_dwim_spec_tag_that_looks_like_revno(self):
169
 
        # Test that we slip past revno with things that look like revnos,
170
 
        # but aren't.  Tags are convenient for testing this since we can
171
 
        # make them look however we want.
172
 
        self.tree.branch.tags.set_tag('3', 'r2')
173
 
        self.assertAsRevisionId('r2', '3')
174
 
        self.build_tree(['tree/b'])
175
 
        self.tree.add(['b'])
176
 
        self.tree.commit('b', rev_id='r3')
177
 
        self.assertAsRevisionId('r3', '3')
178
 
 
179
 
    def test_dwim_spec_date(self):
180
 
        self.assertAsRevisionId('r1', 'today')
181
 
 
182
 
    def test_dwim_spec_branch(self):
183
 
        self.assertInHistoryIs(None, 'alt_r2', 'tree2')
184
 
 
185
 
    def test_dwim_spec_nonexistent(self):
186
 
        self.assertInvalid('somethingrandom', invalid_as_revision_id=False)
187
 
        self.assertInvalid('-1.1', invalid_as_revision_id=False)
188
 
        self.assertInvalid('.1', invalid_as_revision_id=False)
189
 
        self.assertInvalid('1..1', invalid_as_revision_id=False)
190
 
        self.assertInvalid('1.2..1', invalid_as_revision_id=False)
191
 
        self.assertInvalid('1.', invalid_as_revision_id=False)
192
 
 
193
 
 
194
 
class TestRevisionSpec_revno(TestRevisionSpec):
195
 
 
196
 
    def test_positive_int(self):
197
 
        self.assertInHistoryIs(0, 'null:', '0')
198
 
        self.assertInHistoryIs(1, 'r1', '1')
199
 
        self.assertInHistoryIs(2, 'r2', '2')
200
 
        self.assertInvalid('3')
201
 
 
202
 
    def test_dotted_decimal(self):
203
 
        self.assertInHistoryIs(None, 'alt_r2', '1.1.1')
204
 
        self.assertInvalid('1.1.123')
205
 
 
206
 
    def test_negative_int(self):
207
 
        self.assertInHistoryIs(2, 'r2', '-1')
208
 
        self.assertInHistoryIs(1, 'r1', '-2')
209
 
 
210
 
        self.assertInHistoryIs(1, 'r1', '-3')
211
 
        self.assertInHistoryIs(1, 'r1', '-4')
212
 
        self.assertInHistoryIs(1, 'r1', '-100')
213
 
 
214
 
    def test_positive(self):
215
 
        self.assertInHistoryIs(0, 'null:', 'revno:0')
216
 
        self.assertInHistoryIs(1, 'r1', 'revno:1')
217
 
        self.assertInHistoryIs(2, 'r2', 'revno:2')
218
 
 
219
 
        self.assertInvalid('revno:3')
220
 
 
221
 
    def test_negative(self):
222
 
        self.assertInHistoryIs(2, 'r2', 'revno:-1')
223
 
        self.assertInHistoryIs(1, 'r1', 'revno:-2')
224
 
 
225
 
        self.assertInHistoryIs(1, 'r1', 'revno:-3')
226
 
        self.assertInHistoryIs(1, 'r1', 'revno:-4')
227
 
 
228
 
    def test_invalid_number(self):
229
 
        # Get the right exception text
230
 
        try:
231
 
            int('X')
232
 
        except ValueError, e:
233
 
            pass
234
 
        self.assertInvalid('revno:X', extra='\n' + str(e))
235
 
 
236
 
    def test_missing_number_and_branch(self):
237
 
        self.assertInvalid('revno::',
238
 
                           extra='\ncannot have an empty revno and no branch')
239
 
 
240
 
    def test_invalid_number_with_branch(self):
241
 
        try:
242
 
            int('X')
243
 
        except ValueError, e:
244
 
            pass
245
 
        self.assertInvalid('revno:X:tree2', extra='\n' + str(e))
246
 
 
247
 
    def test_non_exact_branch(self):
248
 
        # It seems better to require an exact path to the branch
249
 
        # Branch.open() rather than using Branch.open_containing()
250
 
        spec = RevisionSpec.from_string('revno:2:tree2/a')
251
 
        self.assertRaises(errors.NotBranchError,
252
 
                          spec.in_history, self.tree.branch)
253
 
 
254
 
    def test_with_branch(self):
255
 
        # Passing a URL overrides the supplied branch path
256
 
        revinfo = self.get_in_history('revno:2:tree2')
257
 
        self.assertNotEqual(self.tree.branch.base, revinfo.branch.base)
258
 
        self.assertEqual(self.tree2.branch.base, revinfo.branch.base)
259
 
        self.assertEqual(2, revinfo.revno)
260
 
        self.assertEqual('alt_r2', revinfo.rev_id)
261
 
 
262
 
    def test_int_with_branch(self):
263
 
        revinfo = self.get_in_history('2:tree2')
264
 
        self.assertNotEqual(self.tree.branch.base, revinfo.branch.base)
265
 
        self.assertEqual(self.tree2.branch.base, revinfo.branch.base)
266
 
        self.assertEqual(2, revinfo.revno)
267
 
        self.assertEqual('alt_r2', revinfo.rev_id)
268
 
 
269
 
    def test_with_url(self):
270
 
        url = self.get_url() + '/tree2'
271
 
        revinfo = self.get_in_history('revno:2:%s' % (url,))
272
 
        self.assertNotEqual(self.tree.branch.base, revinfo.branch.base)
273
 
        self.assertEqual(self.tree2.branch.base, revinfo.branch.base)
274
 
        self.assertEqual(2, revinfo.revno)
275
 
        self.assertEqual('alt_r2', revinfo.rev_id)
276
 
 
277
 
    def test_negative_with_url(self):
278
 
        url = self.get_url() + '/tree2'
279
 
        revinfo = self.get_in_history('revno:-1:%s' % (url,))
280
 
        self.assertNotEqual(self.tree.branch.base, revinfo.branch.base)
281
 
        self.assertEqual(self.tree2.branch.base, revinfo.branch.base)
282
 
        self.assertEqual(2, revinfo.revno)
283
 
        self.assertEqual('alt_r2', revinfo.rev_id)
284
 
 
285
 
    def test_different_history_lengths(self):
286
 
        # Make sure we use the revisions and offsets in the supplied branch
287
 
        # not the ones in the original branch.
288
 
        self.tree2.commit('three', rev_id='r3')
289
 
        self.assertInHistoryIs(3, 'r3', 'revno:3:tree2')
290
 
        self.assertInHistoryIs(3, 'r3', 'revno:-1:tree2')
291
 
 
292
 
    def test_invalid_branch(self):
293
 
        self.assertRaises(errors.NotBranchError,
294
 
                          self.get_in_history, 'revno:-1:tree3')
295
 
 
296
 
    def test_invalid_revno_in_branch(self):
297
 
        self.tree.commit('three', rev_id='r3')
298
 
        self.assertInvalid('revno:3:tree2')
 
20
from bzrlib.builtins import merge
 
21
from bzrlib.branch import Branch
 
22
from bzrlib.tests import TestCaseWithTransport
 
23
from bzrlib.errors import NoCommonAncestor, NoCommits
 
24
from bzrlib.errors import NoSuchRevision
 
25
from bzrlib.revisionspec import RevisionSpec
 
26
 
 
27
 
 
28
class TestRevisionNamespaces(TestCaseWithTransport):
299
29
 
300
30
    def test_revno_n_path(self):
301
 
        """Old revno:N:path tests"""
 
31
        """Test revision specifiers.
 
32
 
 
33
        These identify revisions by date, etc."""
302
34
        wta = self.make_branch_and_tree('a')
303
35
        ba = wta.branch
304
 
 
 
36
        
305
37
        wta.commit('Commit one', rev_id='a@r-0-1')
306
38
        wta.commit('Commit two', rev_id='a@r-0-2')
307
39
        wta.commit('Commit three', rev_id='a@r-0-3')
313
45
        wtb.commit('Commit two', rev_id='b@r-0-2')
314
46
        wtb.commit('Commit three', rev_id='b@r-0-3')
315
47
 
316
 
 
317
 
        self.assertEqual((1, 'a@r-0-1'),
318
 
                         spec_in_history('revno:1:a/', ba))
 
48
        self.assertEquals(RevisionSpec('revno:1:a/').in_history(ba),
 
49
                          (1, 'a@r-0-1'))
319
50
        # The argument of in_history should be ignored since it is
320
51
        # redundant with the path in the spec.
321
 
        self.assertEqual((1, 'a@r-0-1'),
322
 
                         spec_in_history('revno:1:a/', None))
323
 
        self.assertEqual((1, 'a@r-0-1'),
324
 
                         spec_in_history('revno:1:a/', bb))
325
 
        self.assertEqual((2, 'b@r-0-2'),
326
 
                         spec_in_history('revno:2:b/', None))
327
 
 
328
 
    def test_as_revision_id(self):
329
 
        self.assertAsRevisionId('null:', '0')
330
 
        self.assertAsRevisionId('r1', '1')
331
 
        self.assertAsRevisionId('r2', '2')
332
 
        self.assertAsRevisionId('r1', '-2')
333
 
        self.assertAsRevisionId('r2', '-1')
334
 
        self.assertAsRevisionId('alt_r2', '1.1.1')
335
 
 
336
 
    def test_as_tree(self):
337
 
        tree = self.get_as_tree('0')
338
 
        self.assertEquals(_mod_revision.NULL_REVISION, tree.get_revision_id())
339
 
        tree = self.get_as_tree('1')
340
 
        self.assertEquals('r1', tree.get_revision_id())
341
 
        tree = self.get_as_tree('2')
342
 
        self.assertEquals('r2', tree.get_revision_id())
343
 
        tree = self.get_as_tree('-2')
344
 
        self.assertEquals('r1', tree.get_revision_id())
345
 
        tree = self.get_as_tree('-1')
346
 
        self.assertEquals('r2', tree.get_revision_id())
347
 
        tree = self.get_as_tree('1.1.1')
348
 
        self.assertEquals('alt_r2', tree.get_revision_id())
349
 
 
350
 
 
351
 
class TestRevisionSpec_revid(TestRevisionSpec):
352
 
 
353
 
    def test_in_history(self):
354
 
        # We should be able to access revisions that are directly
355
 
        # in the history.
356
 
        self.assertInHistoryIs(1, 'r1', 'revid:r1')
357
 
        self.assertInHistoryIs(2, 'r2', 'revid:r2')
358
 
 
359
 
    def test_missing(self):
360
 
        self.assertInvalid('revid:r3', invalid_as_revision_id=False)
361
 
 
362
 
    def test_merged(self):
363
 
        """We can reach revisions in the ancestry"""
364
 
        self.assertInHistoryIs(None, 'alt_r2', 'revid:alt_r2')
365
 
 
366
 
    def test_not_here(self):
367
 
        self.tree2.commit('alt third', rev_id='alt_r3')
368
 
        # It exists in tree2, but not in tree
369
 
        self.assertInvalid('revid:alt_r3', invalid_as_revision_id=False)
370
 
 
371
 
    def test_in_repository(self):
372
 
        """We can get any revision id in the repository"""
373
 
        # XXX: This may change in the future, but for now, it is true
374
 
        self.tree2.commit('alt third', rev_id='alt_r3')
375
 
        self.tree.branch.repository.fetch(self.tree2.branch.repository,
376
 
                                          revision_id='alt_r3')
377
 
        self.assertInHistoryIs(None, 'alt_r3', 'revid:alt_r3')
378
 
 
379
 
    def test_unicode(self):
380
 
        """We correctly convert a unicode ui string to an encoded revid."""
381
 
        revision_id = u'\N{SNOWMAN}'.encode('utf-8')
382
 
        self.tree.commit('unicode', rev_id=revision_id)
383
 
        self.assertInHistoryIs(3, revision_id, u'revid:\N{SNOWMAN}')
384
 
        self.assertInHistoryIs(3, revision_id, 'revid:' + revision_id)
385
 
 
386
 
    def test_as_revision_id(self):
387
 
        self.assertAsRevisionId('r1', 'revid:r1')
388
 
        self.assertAsRevisionId('r2', 'revid:r2')
389
 
        self.assertAsRevisionId('alt_r2', 'revid:alt_r2')
390
 
 
391
 
 
392
 
class TestRevisionSpec_last(TestRevisionSpec):
393
 
 
394
 
    def test_positive(self):
395
 
        self.assertInHistoryIs(2, 'r2', 'last:1')
396
 
        self.assertInHistoryIs(1, 'r1', 'last:2')
397
 
        self.assertInHistoryIs(0, 'null:', 'last:3')
398
 
 
399
 
    def test_empty(self):
400
 
        self.assertInHistoryIs(2, 'r2', 'last:')
401
 
 
402
 
    def test_negative(self):
403
 
        self.assertInvalid('last:-1',
404
 
                           extra='\nyou must supply a positive value')
405
 
 
406
 
    def test_missing(self):
407
 
        self.assertInvalid('last:4')
408
 
 
409
 
    def test_no_history(self):
410
 
        tree = self.make_branch_and_tree('tree3')
411
 
 
412
 
        self.assertRaises(errors.NoCommits,
413
 
                          spec_in_history, 'last:', tree.branch)
414
 
 
415
 
    def test_not_a_number(self):
416
 
        try:
417
 
            int('Y')
418
 
        except ValueError, e:
419
 
            pass
420
 
        self.assertInvalid('last:Y', extra='\n' + str(e))
421
 
 
422
 
    def test_as_revision_id(self):
423
 
        self.assertAsRevisionId('r2', 'last:1')
424
 
        self.assertAsRevisionId('r1', 'last:2')
425
 
 
426
 
 
427
 
class TestRevisionSpec_before(TestRevisionSpec):
428
 
 
429
 
    def test_int(self):
430
 
        self.assertInHistoryIs(1, 'r1', 'before:2')
431
 
        self.assertInHistoryIs(1, 'r1', 'before:-1')
432
 
 
433
 
    def test_before_one(self):
434
 
        self.assertInHistoryIs(0, 'null:', 'before:1')
435
 
 
436
 
    def test_before_none(self):
437
 
        self.assertInvalid('before:0',
438
 
                           extra='\ncannot go before the null: revision')
439
 
 
440
 
    def test_revid(self):
441
 
        self.assertInHistoryIs(1, 'r1', 'before:revid:r2')
442
 
 
443
 
    def test_last(self):
444
 
        self.assertInHistoryIs(1, 'r1', 'before:last:1')
445
 
 
446
 
    def test_alt_revid(self):
447
 
        # This will grab the left-most ancestor for alternate histories
448
 
        self.assertInHistoryIs(1, 'r1', 'before:revid:alt_r2')
449
 
 
450
 
    def test_alt_no_parents(self):
451
 
        new_tree = self.make_branch_and_tree('new_tree')
452
 
        new_tree.commit('first', rev_id='new_r1')
453
 
        self.tree.branch.repository.fetch(new_tree.branch.repository,
454
 
                                          revision_id='new_r1')
455
 
        self.assertInHistoryIs(0, 'null:', 'before:revid:new_r1')
456
 
 
457
 
    def test_as_revision_id(self):
458
 
        self.assertAsRevisionId('r1', 'before:revid:r2')
459
 
        self.assertAsRevisionId('r1', 'before:2')
460
 
        self.assertAsRevisionId('r1', 'before:1.1.1')
461
 
        self.assertAsRevisionId('r1', 'before:revid:alt_r2')
462
 
 
463
 
 
464
 
class TestRevisionSpec_tag(TestRevisionSpec):
465
 
 
466
 
    def make_branch_and_tree(self, relpath):
467
 
        # override format as the default one may not support tags
468
 
        return TestRevisionSpec.make_branch_and_tree(
469
 
            self, relpath, format='dirstate-tags')
470
 
 
471
 
    def test_from_string_tag(self):
472
 
        spec = RevisionSpec.from_string('tag:bzr-0.14')
473
 
        self.assertIsInstance(spec, RevisionSpec_tag)
474
 
        self.assertEqual(spec.spec, 'bzr-0.14')
475
 
 
476
 
    def test_lookup_tag(self):
477
 
        self.tree.branch.tags.set_tag('bzr-0.14', 'r1')
478
 
        self.assertInHistoryIs(1, 'r1', 'tag:bzr-0.14')
479
 
        self.tree.branch.tags.set_tag('null_rev', 'null:')
480
 
        self.assertInHistoryIs(0, 'null:', 'tag:null_rev')
481
 
 
482
 
    def test_failed_lookup(self):
483
 
        # tags that don't exist give a specific message: arguably we should
484
 
        # just give InvalidRevisionSpec but I think this is more helpful
485
 
        self.assertRaises(errors.NoSuchTag,
486
 
            self.get_in_history,
487
 
            'tag:some-random-tag')
488
 
 
489
 
    def test_as_revision_id(self):
490
 
        self.tree.branch.tags.set_tag('my-tag', 'r2')
491
 
        self.tree.branch.tags.set_tag('null_rev', 'null:')
492
 
        self.assertAsRevisionId('r2', 'tag:my-tag')
493
 
        self.assertAsRevisionId('null:', 'tag:null_rev')
494
 
        self.assertAsRevisionId('r1', 'before:tag:my-tag')
495
 
 
496
 
 
497
 
class TestRevisionSpec_date(TestRevisionSpec):
498
 
 
499
 
    def setUp(self):
500
 
        super(TestRevisionSpec, self).setUp()
501
 
 
502
 
        new_tree = self.make_branch_and_tree('new_tree')
503
 
        new_tree.commit('Commit one', rev_id='new_r1',
504
 
                        timestamp=time.time() - 60*60*24)
505
 
        new_tree.commit('Commit two', rev_id='new_r2')
506
 
        new_tree.commit('Commit three', rev_id='new_r3')
507
 
 
508
 
        self.tree = new_tree
509
 
 
510
 
    def test_tomorrow(self):
511
 
        self.assertInvalid('date:tomorrow')
512
 
 
513
 
    def test_today(self):
514
 
        self.assertInHistoryIs(2, 'new_r2', 'date:today')
515
 
        self.assertInHistoryIs(1, 'new_r1', 'before:date:today')
516
 
 
517
 
    def test_yesterday(self):
518
 
        self.assertInHistoryIs(1, 'new_r1', 'date:yesterday')
519
 
 
520
 
    def test_invalid(self):
521
 
        self.assertInvalid('date:foobar', extra='\ninvalid date')
522
 
        # You must have '-' between year/month/day
523
 
        self.assertInvalid('date:20040404', extra='\ninvalid date')
524
 
        # Need 2 digits for each date piece
525
 
        self.assertInvalid('date:2004-4-4', extra='\ninvalid date')
526
 
 
527
 
    def test_day(self):
528
 
        now = datetime.datetime.now()
529
 
        self.assertInHistoryIs(2, 'new_r2',
530
 
            'date:%04d-%02d-%02d' % (now.year, now.month, now.day))
531
 
 
532
 
    def test_as_revision_id(self):
533
 
        self.assertAsRevisionId('new_r2', 'date:today')
534
 
 
535
 
 
536
 
class TestRevisionSpec_ancestor(TestRevisionSpec):
537
 
 
538
 
    def test_non_exact_branch(self):
539
 
        # It seems better to require an exact path to the branch
540
 
        # Branch.open() rather than using Branch.open_containing()
541
 
        self.assertRaises(errors.NotBranchError,
542
 
                          self.get_in_history, 'ancestor:tree2/a')
543
 
 
544
 
    def test_simple(self):
545
 
        # Common ancestor of trees is 'alt_r2'
546
 
        self.assertInHistoryIs(None, 'alt_r2', 'ancestor:tree2')
547
 
 
548
 
        # Going the other way, we get a valid revno
549
 
        tmp = self.tree
550
 
        self.tree = self.tree2
551
 
        self.tree2 = tmp
552
 
        self.assertInHistoryIs(2, 'alt_r2', 'ancestor:tree')
553
 
 
554
 
    def test_self(self):
555
 
        self.assertInHistoryIs(2, 'r2', 'ancestor:tree')
556
 
 
557
 
    def test_unrelated(self):
558
 
        new_tree = self.make_branch_and_tree('new_tree')
559
 
 
560
 
        new_tree.commit('Commit one', rev_id='new_r1')
561
 
        new_tree.commit('Commit two', rev_id='new_r2')
562
 
        new_tree.commit('Commit three', rev_id='new_r3')
563
 
 
564
 
        # With no common ancestor, we should raise another user error
565
 
        self.assertRaises(errors.NoCommonAncestor,
566
 
                          self.get_in_history, 'ancestor:new_tree')
567
 
 
568
 
    def test_no_commits(self):
569
 
        new_tree = self.make_branch_and_tree('new_tree')
570
 
        self.assertRaises(errors.NoCommits,
571
 
                          spec_in_history, 'ancestor:new_tree',
572
 
                                           self.tree.branch)
573
 
 
574
 
        self.assertRaises(errors.NoCommits,
575
 
                          spec_in_history, 'ancestor:tree',
576
 
                                           new_tree.branch)
577
 
 
578
 
    def test_as_revision_id(self):
579
 
        self.assertAsRevisionId('alt_r2', 'ancestor:tree2')
580
 
 
581
 
    def test_default(self):
582
 
        # We don't have a parent to default to
583
 
        self.assertRaises(errors.NotBranchError, self.get_in_history,
584
 
                          'ancestor:')
585
 
 
586
 
        # Create a branch with a parent to default to
587
 
        tree3 = self.tree.bzrdir.sprout('tree3').open_workingtree()
588
 
        tree3.commit('foo', rev_id='r3')
589
 
        self.tree = tree3
590
 
        self.assertInHistoryIs(2, 'r2', 'ancestor:')
591
 
 
592
 
 
593
 
class TestRevisionSpec_branch(TestRevisionSpec):
594
 
 
595
 
    def test_non_exact_branch(self):
596
 
        # It seems better to require an exact path to the branch
597
 
        # Branch.open() rather than using Branch.open_containing()
598
 
        self.assertRaises(errors.NotBranchError,
599
 
                          self.get_in_history, 'branch:tree2/a')
600
 
 
601
 
    def test_simple(self):
602
 
        self.assertInHistoryIs(None, 'alt_r2', 'branch:tree2')
603
 
 
604
 
    def test_self(self):
605
 
        self.assertInHistoryIs(2, 'r2', 'branch:tree')
606
 
 
607
 
    def test_unrelated(self):
608
 
        new_tree = self.make_branch_and_tree('new_tree')
609
 
 
610
 
        new_tree.commit('Commit one', rev_id='new_r1')
611
 
        new_tree.commit('Commit two', rev_id='new_r2')
612
 
        new_tree.commit('Commit three', rev_id='new_r3')
613
 
 
614
 
        self.assertInHistoryIs(None, 'new_r3', 'branch:new_tree')
615
 
 
616
 
        # XXX: Right now, we use fetch() to make sure the remote revisions
617
 
        # have been pulled into the local branch. We may change that
618
 
        # behavior in the future.
619
 
        self.failUnless(self.tree.branch.repository.has_revision('new_r3'))
620
 
 
621
 
    def test_no_commits(self):
622
 
        new_tree = self.make_branch_and_tree('new_tree')
623
 
        self.assertRaises(errors.NoCommits,
624
 
                          self.get_in_history, 'branch:new_tree')
625
 
        self.assertRaises(errors.NoCommits,
626
 
                          self.get_as_tree, 'branch:new_tree')
627
 
 
628
 
    def test_as_revision_id(self):
629
 
        self.assertAsRevisionId('alt_r2', 'branch:tree2')
630
 
 
631
 
    def test_as_tree(self):
632
 
        tree = self.get_as_tree('branch:tree', self.tree2)
633
 
        self.assertEquals('r2', tree.get_revision_id())
634
 
        self.assertFalse(self.tree2.branch.repository.has_revision('r2'))
635
 
 
636
 
 
637
 
class TestRevisionSpec_submit(TestRevisionSpec):
638
 
 
639
 
    def test_submit_branch(self):
640
 
        # Common ancestor of trees is 'alt_r2'
641
 
        self.assertRaises(errors.NoSubmitBranch, self.get_in_history,
642
 
                          'submit:')
643
 
        self.tree.branch.set_parent('../tree2')
644
 
        self.assertInHistoryIs(None, 'alt_r2', 'submit:')
645
 
        self.tree.branch.set_parent('bogus')
646
 
        self.assertRaises(errors.NotBranchError, self.get_in_history,
647
 
            'submit:')
648
 
        # submit branch overrides parent branch
649
 
        self.tree.branch.set_submit_branch('tree2')
650
 
        self.assertInHistoryIs(None, 'alt_r2', 'submit:')
651
 
 
652
 
    def test_as_revision_id(self):
653
 
        self.tree.branch.set_submit_branch('tree2')
654
 
        self.assertAsRevisionId('alt_r2', 'branch:tree2')
655
 
 
656
 
 
657
 
class TestRevisionSpec_mainline(TestRevisionSpec):
658
 
 
659
 
    def test_as_revision_id(self):
660
 
        self.assertAsRevisionId('r1', 'mainline:1')
661
 
        self.assertAsRevisionId('r2', 'mainline:1.1.1')
662
 
        self.assertAsRevisionId('r2', 'mainline:revid:alt_r2')
663
 
        spec = RevisionSpec.from_string('mainline:revid:alt_r22')
664
 
        e = self.assertRaises(errors.InvalidRevisionSpec,
665
 
                              spec.as_revision_id, self.tree.branch)
666
 
        self.assertContainsRe(str(e),
667
 
            "Requested revision: 'mainline:revid:alt_r22' does not exist in"
668
 
            " branch: ")
669
 
 
670
 
    def test_in_history(self):
671
 
        self.assertInHistoryIs(2, 'r2', 'mainline:revid:alt_r2')
672
 
 
673
 
 
674
 
class TestRevisionSpec_annotate(TestRevisionSpec):
675
 
 
676
 
    def setUp(self):
677
 
        TestRevisionSpec.setUp(self)
678
 
        self.tree = self.make_branch_and_tree('annotate-tree')
679
 
        self.build_tree_contents([('annotate-tree/file1', '1\n')])
680
 
        self.tree.add('file1')
681
 
        self.tree.commit('r1', rev_id='r1')
682
 
        self.build_tree_contents([('annotate-tree/file1', '2\n1\n')])
683
 
        self.tree.commit('r2', rev_id='r2')
684
 
        self.build_tree_contents([('annotate-tree/file1', '2\n1\n3\n')])
685
 
 
686
 
    def test_as_revision_id_r1(self):
687
 
        self.assertAsRevisionId('r1', 'annotate:annotate-tree/file1:2')
688
 
 
689
 
    def test_as_revision_id_r2(self):
690
 
        self.assertAsRevisionId('r2', 'annotate:annotate-tree/file1:1')
691
 
 
692
 
    def test_as_revision_id_uncommitted(self):
693
 
        spec = RevisionSpec.from_string('annotate:annotate-tree/file1:3')
694
 
        e = self.assertRaises(errors.InvalidRevisionSpec,
695
 
                              spec.as_revision_id, self.tree.branch)
696
 
        self.assertContainsRe(str(e),
697
 
            r"Requested revision: \'annotate:annotate-tree/file1:3\' does not"
698
 
            " exist in branch: .*\nLine 3 has not been committed.")
699
 
 
700
 
    def test_non_existent_line(self):
701
 
        spec = RevisionSpec.from_string('annotate:annotate-tree/file1:4')
702
 
        e = self.assertRaises(errors.InvalidRevisionSpec,
703
 
                              spec.as_revision_id, self.tree.branch)
704
 
        self.assertContainsRe(str(e),
705
 
            r"Requested revision: \'annotate:annotate-tree/file1:4\' does not"
706
 
            " exist in branch: .*\nNo such line: 4")
707
 
 
708
 
    def test_invalid_line(self):
709
 
        spec = RevisionSpec.from_string('annotate:annotate-tree/file1:q')
710
 
        e = self.assertRaises(errors.InvalidRevisionSpec,
711
 
                              spec.as_revision_id, self.tree.branch)
712
 
        self.assertContainsRe(str(e),
713
 
            r"Requested revision: \'annotate:annotate-tree/file1:q\' does not"
714
 
            " exist in branch: .*\nNo such line: q")
715
 
 
716
 
    def test_no_such_file(self):
717
 
        spec = RevisionSpec.from_string('annotate:annotate-tree/file2:1')
718
 
        e = self.assertRaises(errors.InvalidRevisionSpec,
719
 
                              spec.as_revision_id, self.tree.branch)
720
 
        self.assertContainsRe(str(e),
721
 
            r"Requested revision: \'annotate:annotate-tree/file2:1\' does not"
722
 
            " exist in branch: .*\nFile 'file2' is not versioned")
723
 
 
724
 
    def test_no_such_file_with_colon(self):
725
 
        spec = RevisionSpec.from_string('annotate:annotate-tree/fi:le2:1')
726
 
        e = self.assertRaises(errors.InvalidRevisionSpec,
727
 
                              spec.as_revision_id, self.tree.branch)
728
 
        self.assertContainsRe(str(e),
729
 
            r"Requested revision: \'annotate:annotate-tree/fi:le2:1\' does not"
730
 
            " exist in branch: .*\nFile 'fi:le2' is not versioned")
 
52
        self.assertEquals(RevisionSpec('revno:1:a/').in_history(None),
 
53
                          (1, 'a@r-0-1'))
 
54
        self.assertEquals(RevisionSpec('revno:1:a/').in_history(bb),
 
55
                          (1, 'a@r-0-1'))
 
56
        self.assertEquals(RevisionSpec('revno:2:b/').in_history(None),
 
57
                          (2, 'b@r-0-2'))
 
58
 
 
59
 
 
60
    def test_revision_namespaces(self):
 
61
        """Test revision specifiers.
 
62
 
 
63
        These identify revisions by date, etc."""
 
64
        wt = self.make_branch_and_tree('.')
 
65
        b = wt.branch
 
66
 
 
67
        wt.commit('Commit one', rev_id='a@r-0-1', timestamp=time.time() - 60*60*24)
 
68
        wt.commit('Commit two', rev_id='a@r-0-2')
 
69
        wt.commit('Commit three', rev_id='a@r-0-3')
 
70
 
 
71
        self.assertEquals(RevisionSpec(None).in_history(b), (0, None))
 
72
        self.assertEquals(RevisionSpec(1).in_history(b), (1, 'a@r-0-1'))
 
73
        self.assertEquals(RevisionSpec('revno:1').in_history(b),
 
74
                          (1, 'a@r-0-1'))
 
75
        self.assertEquals(RevisionSpec('revid:a@r-0-1').in_history(b),
 
76
                          (1, 'a@r-0-1'))
 
77
        self.assertRaises(NoSuchRevision,
 
78
                          RevisionSpec('revid:a@r-0-0').in_history, b)
 
79
        self.assertRaises(TypeError, RevisionSpec, object)
 
80
 
 
81
        self.assertEquals(RevisionSpec('date:today').in_history(b),
 
82
                          (2, 'a@r-0-2'))
 
83
        self.assertRaises(NoSuchRevision,
 
84
                          RevisionSpec('date:tomorrow').in_history, b)
 
85
        self.assertEquals(RevisionSpec('date:yesterday').in_history(b),
 
86
                          (1, 'a@r-0-1'))
 
87
        self.assertEquals(RevisionSpec('before:date:today').in_history(b),
 
88
                          (1, 'a@r-0-1'))
 
89
 
 
90
        self.assertEquals(RevisionSpec('last:1').in_history(b),
 
91
                          (3, 'a@r-0-3'))
 
92
        self.assertEquals(RevisionSpec('-1').in_history(b), (3, 'a@r-0-3'))
 
93
#        self.assertEquals(b.get_revision_info('last:1'), (3, 'a@r-0-3'))
 
94
#        self.assertEquals(b.get_revision_info('-1'), (3, 'a@r-0-3'))
 
95
 
 
96
        self.assertEquals(RevisionSpec('ancestor:.').in_history(b).rev_id,
 
97
                          'a@r-0-3')
 
98
 
 
99
        os.mkdir('newbranch')
 
100
        wt2 = self.make_branch_and_tree('newbranch')
 
101
        b2 = wt2.branch
 
102
        self.assertRaises(NoCommits, RevisionSpec('ancestor:.').in_history, b2)
 
103
 
 
104
        d3 = b.bzrdir.sprout('copy')
 
105
        b3 = d3.open_branch()
 
106
        wt3 = d3.open_workingtree()
 
107
        wt3.commit('Commit four', rev_id='b@r-0-4')
 
108
        self.assertEquals(RevisionSpec('ancestor:.').in_history(b3).rev_id,
 
109
                          'a@r-0-3')
 
110
        merge(['copy', -1], [None, None])
 
111
        wt.commit('Commit five', rev_id='a@r-0-4')
 
112
        self.assertEquals(RevisionSpec('ancestor:copy').in_history(b).rev_id,
 
113
                          'b@r-0-4')
 
114
        self.assertEquals(RevisionSpec('ancestor:.').in_history(b3).rev_id,
 
115
                          'b@r-0-4')
 
116
 
 
117
        # This should be in the revision store, but not in revision-history
 
118
        self.assertEquals((None, 'b@r-0-4'),
 
119
                RevisionSpec('revid:b@r-0-4').in_history(b))
 
120
 
 
121
    def test_branch_namespace(self):
 
122
        """Ensure that the branch namespace pulls in the requisite content."""
 
123
        self.build_tree(['branch1/', 'branch1/file', 'branch2/'])
 
124
        wt = self.make_branch_and_tree('branch1')
 
125
        branch = wt.branch
 
126
        wt.add(['file'])
 
127
        wt.commit('add file')
 
128
        d2 = branch.bzrdir.sprout('branch2')
 
129
        print >> open('branch2/file', 'w'), 'new content'
 
130
        branch2 = d2.open_branch()
 
131
        d2.open_workingtree().commit('update file', rev_id='A')
 
132
        spec = RevisionSpec('branch:./branch2/.bzr/../')
 
133
        rev_info = spec.in_history(branch)
 
134
        self.assertEqual(rev_info, (None, 'A'))
 
135