/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_revisionspec.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2008-06-05 03:02:10 UTC
  • mfrom: (3472.1.1 ianc-integration)
  • Revision ID: pqm@pqm.ubuntu.com-20080605030210-xwokghqkg4sqo1xy
Isolate the test HTTPServer from chdir calls (Robert Collins)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2004, 2005 by Canonical Ltd
2
 
 
 
1
# Copyright (C) 2004, 2005, 2006, 2007 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
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
16
 
 
17
import datetime
17
18
import os
18
19
import time
19
20
 
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):
29
 
 
30
 
    def test_revision_namespaces(self):
31
 
        """Test revision specifiers.
32
 
 
33
 
        These identify revisions by date, etc."""
34
 
        wt = self.make_branch_and_tree('.')
35
 
        b = wt.branch
36
 
 
37
 
        wt.commit('Commit one', rev_id='a@r-0-1', timestamp=time.time() - 60*60*24)
38
 
        wt.commit('Commit two', rev_id='a@r-0-2')
39
 
        wt.commit('Commit three', rev_id='a@r-0-3')
40
 
 
41
 
        self.assertEquals(RevisionSpec(None).in_history(b), (0, None))
42
 
        self.assertEquals(RevisionSpec(1).in_history(b), (1, 'a@r-0-1'))
43
 
        self.assertEquals(RevisionSpec('revno:1').in_history(b),
44
 
                          (1, 'a@r-0-1'))
45
 
        self.assertEquals(RevisionSpec('revid:a@r-0-1').in_history(b),
46
 
                          (1, 'a@r-0-1'))
47
 
        self.assertRaises(NoSuchRevision,
48
 
                          RevisionSpec('revid:a@r-0-0').in_history, b)
49
 
        self.assertRaises(TypeError, RevisionSpec, object)
50
 
 
51
 
        self.assertEquals(RevisionSpec('date:today').in_history(b),
52
 
                          (2, 'a@r-0-2'))
53
 
        self.assertEquals(RevisionSpec('date:yesterday').in_history(b),
54
 
                          (1, 'a@r-0-1'))
55
 
        self.assertEquals(RevisionSpec('before:date:today').in_history(b),
56
 
                          (1, 'a@r-0-1'))
57
 
 
58
 
        self.assertEquals(RevisionSpec('last:1').in_history(b),
59
 
                          (3, 'a@r-0-3'))
60
 
        self.assertEquals(RevisionSpec('-1').in_history(b), (3, 'a@r-0-3'))
61
 
#        self.assertEquals(b.get_revision_info('last:1'), (3, 'a@r-0-3'))
62
 
#        self.assertEquals(b.get_revision_info('-1'), (3, 'a@r-0-3'))
63
 
 
64
 
        self.assertEquals(RevisionSpec('ancestor:.').in_history(b).rev_id,
65
 
                          'a@r-0-3')
66
 
 
67
 
        os.mkdir('newbranch')
68
 
        wt2 = self.make_branch_and_tree('newbranch')
69
 
        b2 = wt2.branch
70
 
        self.assertRaises(NoCommits, RevisionSpec('ancestor:.').in_history, b2)
71
 
 
72
 
        d3 = b.bzrdir.sprout('copy')
73
 
        b3 = d3.open_branch()
74
 
        wt3 = d3.open_workingtree()
75
 
        wt3.commit('Commit four', rev_id='b@r-0-4')
76
 
        self.assertEquals(RevisionSpec('ancestor:.').in_history(b3).rev_id,
77
 
                          'a@r-0-3')
78
 
        merge(['copy', -1], [None, None])
79
 
        wt.commit('Commit five', rev_id='a@r-0-4')
80
 
        self.assertEquals(RevisionSpec('ancestor:copy').in_history(b).rev_id,
81
 
                          'b@r-0-4')
82
 
        self.assertEquals(RevisionSpec('ancestor:.').in_history(b3).rev_id,
83
 
                          'b@r-0-4')
84
 
 
85
 
        # This should be in the revision store, but not in revision-history
86
 
        self.assertEquals((None, 'b@r-0-4'),
87
 
                RevisionSpec('revid:b@r-0-4').in_history(b))
88
 
 
89
 
    def test_branch_namespace(self):
90
 
        """Ensure that the branch namespace pulls in the requisite content."""
91
 
        self.build_tree(['branch1/', 'branch1/file', 'branch2/'])
92
 
        wt = self.make_branch_and_tree('branch1')
93
 
        branch = wt.branch
94
 
        wt.add(['file'])
95
 
        wt.commit('add file')
96
 
        d2 = branch.bzrdir.sprout('branch2')
97
 
        print >> open('branch2/file', 'w'), 'new content'
98
 
        branch2 = d2.open_branch()
99
 
        d2.open_workingtree().commit('update file', rev_id='A')
100
 
        spec = RevisionSpec('branch:./branch2/.bzr/../')
101
 
        rev_info = spec.in_history(branch)
102
 
        self.assertEqual(rev_info, (None, 'A'))
103
 
 
 
21
from bzrlib import (
 
22
    branch,
 
23
    bzrdir,
 
24
    errors,
 
25
    repository,
 
26
    )
 
27
from bzrlib.tests import TestCase, TestCaseWithTransport
 
28
from bzrlib.revisionspec import (
 
29
    RevisionSpec,
 
30
    RevisionSpec_revno,
 
31
    RevisionSpec_tag,
 
32
    )
 
33
 
 
34
 
 
35
def spec_in_history(spec, branch):
 
36
    """A simple helper to change a revision spec into a branch search"""
 
37
    return RevisionSpec.from_string(spec).in_history(branch)
 
38
 
 
39
 
 
40
# Basic class, which just creates a really basic set of revisions
 
41
class TestRevisionSpec(TestCaseWithTransport):
 
42
 
 
43
    def setUp(self):
 
44
        super(TestRevisionSpec, self).setUp()
 
45
        # this sets up a revision graph:
 
46
        # r1: []             1
 
47
        # alt_r2: [r1]       1.1.1
 
48
        # r2: [r1, alt_r2]   2
 
49
 
 
50
        self.tree = self.make_branch_and_tree('tree')
 
51
        self.build_tree(['tree/a'])
 
52
        self.tree.lock_write()
 
53
        self.addCleanup(self.tree.unlock)
 
54
        self.tree.add(['a'])
 
55
        self.tree.commit('a', rev_id='r1')
 
56
 
 
57
        self.tree2 = self.tree.bzrdir.sprout('tree2').open_workingtree()
 
58
        self.tree2.commit('alt', rev_id='alt_r2')
 
59
 
 
60
        self.tree.merge_from_branch(self.tree2.branch)
 
61
        self.tree.commit('second', rev_id='r2')
 
62
 
 
63
    def get_in_history(self, revision_spec):
 
64
        return spec_in_history(revision_spec, self.tree.branch)
 
65
 
 
66
    def assertInHistoryIs(self, exp_revno, exp_revision_id, revision_spec):
 
67
        rev_info = self.get_in_history(revision_spec)
 
68
        self.assertEqual(exp_revno, rev_info.revno,
 
69
                         'Revision spec: %r returned wrong revno: %r != %r'
 
70
                         % (revision_spec, exp_revno, rev_info.revno))
 
71
        self.assertEqual(exp_revision_id, rev_info.rev_id,
 
72
                         'Revision spec: %r returned wrong revision id:'
 
73
                         ' %r != %r'
 
74
                         % (revision_spec, exp_revision_id, rev_info.rev_id))
 
75
 
 
76
    def assertInvalid(self, revision_spec, extra=''):
 
77
        try:
 
78
            self.get_in_history(revision_spec)
 
79
        except errors.InvalidRevisionSpec, e:
 
80
            self.assertEqual(revision_spec, e.spec)
 
81
            self.assertEqual(extra, e.extra)
 
82
        else:
 
83
            self.fail('Expected InvalidRevisionSpec to be raised for %s'
 
84
                      % (revision_spec,))
 
85
 
 
86
    def assertAsRevisionId(self, revision_id, revision_spec):
 
87
        """Calling as_revision_id() should return the specified id."""
 
88
        spec = RevisionSpec.from_string(revision_spec)
 
89
        self.assertEqual(revision_id,
 
90
                         spec.as_revision_id(self.tree.branch))
 
91
 
 
92
 
 
93
class RevisionSpecMatchOnTrap(RevisionSpec):
 
94
 
 
95
    def _match_on(self, branch, revs):
 
96
        self.last_call = (branch, revs)
 
97
        return super(RevisionSpecMatchOnTrap, self)._match_on(branch, revs)
 
98
 
 
99
 
 
100
class TestRevisionSpecBase(TestRevisionSpec):
 
101
 
 
102
    def test_wants_revision_history(self):
 
103
        # If wants_revision_history = True, then _match_on should get the
 
104
        # branch revision history
 
105
        spec = RevisionSpecMatchOnTrap('foo', _internal=True)
 
106
        spec.in_history(self.tree.branch)
 
107
 
 
108
        self.assertEqual((self.tree.branch, ['r1' ,'r2']),
 
109
                         spec.last_call)
 
110
 
 
111
    def test_wants_no_revision_history(self):
 
112
        # If wants_revision_history = False, then _match_on should get None for
 
113
        # the branch revision history
 
114
        spec = RevisionSpecMatchOnTrap('foo', _internal=True)
 
115
        spec.wants_revision_history = False
 
116
        spec.in_history(self.tree.branch)
 
117
 
 
118
        self.assertEqual((self.tree.branch, None), spec.last_call)
 
119
 
 
120
 
 
121
 
 
122
class TestOddRevisionSpec(TestRevisionSpec):
 
123
    """Test things that aren't normally thought of as revision specs"""
 
124
 
 
125
    def test_none(self):
 
126
        self.assertInHistoryIs(None, None, None)
 
127
 
 
128
    def test_object(self):
 
129
        self.assertRaises(TypeError, RevisionSpec.from_string, object())
 
130
 
 
131
    def test_unregistered_spec(self):
 
132
        self.assertRaises(errors.NoSuchRevisionSpec,
 
133
                          RevisionSpec.from_string, 'foo')
 
134
        self.assertRaises(errors.NoSuchRevisionSpec,
 
135
                          RevisionSpec.from_string, '123a')
 
136
 
 
137
 
 
138
 
 
139
class TestRevnoFromString(TestCase):
 
140
 
 
141
    def test_from_string_dotted_decimal(self):
 
142
        self.assertRaises(errors.NoSuchRevisionSpec, RevisionSpec.from_string, '-1.1')
 
143
        self.assertRaises(errors.NoSuchRevisionSpec, RevisionSpec.from_string, '.1')
 
144
        self.assertRaises(errors.NoSuchRevisionSpec, RevisionSpec.from_string, '1..1')
 
145
        self.assertRaises(errors.NoSuchRevisionSpec, RevisionSpec.from_string, '1.2..1')
 
146
        self.assertRaises(errors.NoSuchRevisionSpec, RevisionSpec.from_string, '1.')
 
147
        self.assertIsInstance(RevisionSpec.from_string('1.1'), RevisionSpec_revno)
 
148
        self.assertIsInstance(RevisionSpec.from_string('1.1.3'), RevisionSpec_revno)
 
149
 
 
150
 
 
151
class TestRevisionSpec_revno(TestRevisionSpec):
 
152
 
 
153
    def test_positive_int(self):
 
154
        self.assertInHistoryIs(0, 'null:', '0')
 
155
        self.assertInHistoryIs(1, 'r1', '1')
 
156
        self.assertInHistoryIs(2, 'r2', '2')
 
157
        self.assertInvalid('3')
 
158
 
 
159
    def test_dotted_decimal(self):
 
160
        self.assertInHistoryIs(None, 'alt_r2', '1.1.1')
 
161
 
 
162
    def test_negative_int(self):
 
163
        self.assertInHistoryIs(2, 'r2', '-1')
 
164
        self.assertInHistoryIs(1, 'r1', '-2')
 
165
 
 
166
        self.assertInHistoryIs(1, 'r1', '-3')
 
167
        self.assertInHistoryIs(1, 'r1', '-4')
 
168
        self.assertInHistoryIs(1, 'r1', '-100')
 
169
 
 
170
    def test_positive(self):
 
171
        self.assertInHistoryIs(0, 'null:', 'revno:0')
 
172
        self.assertInHistoryIs(1, 'r1', 'revno:1')
 
173
        self.assertInHistoryIs(2, 'r2', 'revno:2')
 
174
 
 
175
        self.assertInvalid('revno:3')
 
176
 
 
177
    def test_negative(self):
 
178
        self.assertInHistoryIs(2, 'r2', 'revno:-1')
 
179
        self.assertInHistoryIs(1, 'r1', 'revno:-2')
 
180
 
 
181
        self.assertInHistoryIs(1, 'r1', 'revno:-3')
 
182
        self.assertInHistoryIs(1, 'r1', 'revno:-4')
 
183
 
 
184
    def test_invalid_number(self):
 
185
        # Get the right exception text
 
186
        try:
 
187
            int('X')
 
188
        except ValueError, e:
 
189
            pass
 
190
        self.assertInvalid('revno:X', extra='\n' + str(e))
 
191
 
 
192
    def test_missing_number_and_branch(self):
 
193
        self.assertInvalid('revno::',
 
194
                           extra='\ncannot have an empty revno and no branch')
 
195
 
 
196
    def test_invalid_number_with_branch(self):
 
197
        try:
 
198
            int('X')
 
199
        except ValueError, e:
 
200
            pass
 
201
        self.assertInvalid('revno:X:tree2', extra='\n' + str(e))
 
202
 
 
203
    def test_non_exact_branch(self):
 
204
        # It seems better to require an exact path to the branch
 
205
        # Branch.open() rather than using Branch.open_containing()
 
206
        spec = RevisionSpec.from_string('revno:2:tree2/a')
 
207
        self.assertRaises(errors.NotBranchError,
 
208
                          spec.in_history, self.tree.branch)
 
209
 
 
210
    def test_with_branch(self):
 
211
        # Passing a URL overrides the supplied branch path
 
212
        revinfo = self.get_in_history('revno:2:tree2')
 
213
        self.assertNotEqual(self.tree.branch.base, revinfo.branch.base)
 
214
        self.assertEqual(self.tree2.branch.base, revinfo.branch.base)
 
215
        self.assertEqual(2, revinfo.revno)
 
216
        self.assertEqual('alt_r2', revinfo.rev_id)
 
217
 
 
218
    def test_int_with_branch(self):
 
219
        revinfo = self.get_in_history('2:tree2')
 
220
        self.assertNotEqual(self.tree.branch.base, revinfo.branch.base)
 
221
        self.assertEqual(self.tree2.branch.base, revinfo.branch.base)
 
222
        self.assertEqual(2, revinfo.revno)
 
223
        self.assertEqual('alt_r2', revinfo.rev_id)
 
224
 
 
225
    def test_with_url(self):
 
226
        url = self.get_url() + '/tree2'
 
227
        revinfo = self.get_in_history('revno:2:%s' % (url,))
 
228
        self.assertNotEqual(self.tree.branch.base, revinfo.branch.base)
 
229
        self.assertEqual(self.tree2.branch.base, revinfo.branch.base)
 
230
        self.assertEqual(2, revinfo.revno)
 
231
        self.assertEqual('alt_r2', revinfo.rev_id)
 
232
 
 
233
    def test_negative_with_url(self):
 
234
        url = self.get_url() + '/tree2'
 
235
        revinfo = self.get_in_history('revno:-1:%s' % (url,))
 
236
        self.assertNotEqual(self.tree.branch.base, revinfo.branch.base)
 
237
        self.assertEqual(self.tree2.branch.base, revinfo.branch.base)
 
238
        self.assertEqual(2, revinfo.revno)
 
239
        self.assertEqual('alt_r2', revinfo.rev_id)
 
240
 
 
241
    def test_different_history_lengths(self):
 
242
        # Make sure we use the revisions and offsets in the supplied branch
 
243
        # not the ones in the original branch.
 
244
        self.tree2.commit('three', rev_id='r3')
 
245
        self.assertInHistoryIs(3, 'r3', 'revno:3:tree2')
 
246
        self.assertInHistoryIs(3, 'r3', 'revno:-1:tree2')
 
247
 
 
248
    def test_invalid_branch(self):
 
249
        self.assertRaises(errors.NotBranchError,
 
250
                          self.get_in_history, 'revno:-1:tree3')
 
251
 
 
252
    def test_invalid_revno_in_branch(self):
 
253
        self.tree.commit('three', rev_id='r3')
 
254
        self.assertInvalid('revno:3:tree2')
 
255
 
 
256
    def test_revno_n_path(self):
 
257
        """Old revno:N:path tests"""
 
258
        wta = self.make_branch_and_tree('a')
 
259
        ba = wta.branch
 
260
        
 
261
        wta.commit('Commit one', rev_id='a@r-0-1')
 
262
        wta.commit('Commit two', rev_id='a@r-0-2')
 
263
        wta.commit('Commit three', rev_id='a@r-0-3')
 
264
 
 
265
        wtb = self.make_branch_and_tree('b')
 
266
        bb = wtb.branch
 
267
 
 
268
        wtb.commit('Commit one', rev_id='b@r-0-1')
 
269
        wtb.commit('Commit two', rev_id='b@r-0-2')
 
270
        wtb.commit('Commit three', rev_id='b@r-0-3')
 
271
 
 
272
 
 
273
        self.assertEqual((1, 'a@r-0-1'),
 
274
                         spec_in_history('revno:1:a/', ba))
 
275
        # The argument of in_history should be ignored since it is
 
276
        # redundant with the path in the spec.
 
277
        self.assertEqual((1, 'a@r-0-1'),
 
278
                         spec_in_history('revno:1:a/', None))
 
279
        self.assertEqual((1, 'a@r-0-1'),
 
280
                         spec_in_history('revno:1:a/', bb))
 
281
        self.assertEqual((2, 'b@r-0-2'),
 
282
                         spec_in_history('revno:2:b/', None))
 
283
 
 
284
    def test_as_revision_id(self):
 
285
        self.assertAsRevisionId('null:', '0')
 
286
        self.assertAsRevisionId('r1', '1')
 
287
        self.assertAsRevisionId('r2', '2')
 
288
        self.assertAsRevisionId('r1', '-2')
 
289
        self.assertAsRevisionId('r2', '-1')
 
290
        self.assertAsRevisionId('alt_r2', '1.1.1')
 
291
 
 
292
 
 
293
class TestRevisionSpec_revid(TestRevisionSpec):
 
294
    
 
295
    def test_in_history(self):
 
296
        # We should be able to access revisions that are directly
 
297
        # in the history.
 
298
        self.assertInHistoryIs(1, 'r1', 'revid:r1')
 
299
        self.assertInHistoryIs(2, 'r2', 'revid:r2')
 
300
        
 
301
    def test_missing(self):
 
302
        self.assertInvalid('revid:r3')
 
303
 
 
304
    def test_merged(self):
 
305
        """We can reach revisions in the ancestry"""
 
306
        self.assertInHistoryIs(None, 'alt_r2', 'revid:alt_r2')
 
307
 
 
308
    def test_not_here(self):
 
309
        self.tree2.commit('alt third', rev_id='alt_r3')
 
310
        # It exists in tree2, but not in tree
 
311
        self.assertInvalid('revid:alt_r3')
 
312
 
 
313
    def test_in_repository(self):
 
314
        """We can get any revision id in the repository"""
 
315
        # XXX: This may change in the future, but for now, it is true
 
316
        self.tree2.commit('alt third', rev_id='alt_r3')
 
317
        self.tree.branch.repository.fetch(self.tree2.branch.repository,
 
318
                                          revision_id='alt_r3')
 
319
        self.assertInHistoryIs(None, 'alt_r3', 'revid:alt_r3')
 
320
 
 
321
    def test_unicode(self):
 
322
        """We correctly convert a unicode ui string to an encoded revid."""
 
323
        revision_id = u'\N{SNOWMAN}'.encode('utf-8')
 
324
        self.tree.commit('unicode', rev_id=revision_id)
 
325
        self.assertInHistoryIs(3, revision_id, u'revid:\N{SNOWMAN}')
 
326
        self.assertInHistoryIs(3, revision_id, 'revid:' + revision_id)
 
327
 
 
328
    def test_as_revision_id(self):
 
329
        self.assertAsRevisionId('r1', 'revid:r1')
 
330
        self.assertAsRevisionId('r2', 'revid:r2')
 
331
        self.assertAsRevisionId('alt_r2', 'revid:alt_r2')
 
332
 
 
333
 
 
334
class TestRevisionSpec_last(TestRevisionSpec):
 
335
 
 
336
    def test_positive(self):
 
337
        self.assertInHistoryIs(2, 'r2', 'last:1')
 
338
        self.assertInHistoryIs(1, 'r1', 'last:2')
 
339
        self.assertInHistoryIs(0, 'null:', 'last:3')
 
340
 
 
341
    def test_empty(self):
 
342
        self.assertInHistoryIs(2, 'r2', 'last:')
 
343
 
 
344
    def test_negative(self):
 
345
        self.assertInvalid('last:-1',
 
346
                           extra='\nyou must supply a positive value')
 
347
 
 
348
    def test_missing(self):
 
349
        self.assertInvalid('last:4')
 
350
 
 
351
    def test_no_history(self):
 
352
        tree = self.make_branch_and_tree('tree3')
 
353
 
 
354
        self.assertRaises(errors.NoCommits,
 
355
                          spec_in_history, 'last:', tree.branch)
 
356
 
 
357
    def test_not_a_number(self):
 
358
        try:
 
359
            int('Y')
 
360
        except ValueError, e:
 
361
            pass
 
362
        self.assertInvalid('last:Y', extra='\n' + str(e))
 
363
 
 
364
    def test_as_revision_id(self):
 
365
        self.assertAsRevisionId('r2', 'last:1')
 
366
        self.assertAsRevisionId('r1', 'last:2')
 
367
 
 
368
 
 
369
class TestRevisionSpec_before(TestRevisionSpec):
 
370
 
 
371
    def test_int(self):
 
372
        self.assertInHistoryIs(1, 'r1', 'before:2')
 
373
        self.assertInHistoryIs(1, 'r1', 'before:-1')
 
374
 
 
375
    def test_before_one(self):
 
376
        self.assertInHistoryIs(0, 'null:', 'before:1')
 
377
 
 
378
    def test_before_none(self):
 
379
        self.assertInvalid('before:0',
 
380
                           extra='\ncannot go before the null: revision')
 
381
 
 
382
    def test_revid(self):
 
383
        self.assertInHistoryIs(1, 'r1', 'before:revid:r2')
 
384
 
 
385
    def test_last(self):
 
386
        self.assertInHistoryIs(1, 'r1', 'before:last:1')
 
387
 
 
388
    def test_alt_revid(self):
 
389
        # This will grab the left-most ancestor for alternate histories
 
390
        self.assertInHistoryIs(1, 'r1', 'before:revid:alt_r2')
 
391
 
 
392
    def test_alt_no_parents(self):
 
393
        new_tree = self.make_branch_and_tree('new_tree')
 
394
        new_tree.commit('first', rev_id='new_r1')
 
395
        self.tree.branch.repository.fetch(new_tree.branch.repository,
 
396
                                          revision_id='new_r1')
 
397
        self.assertInHistoryIs(0, 'null:', 'before:revid:new_r1')
 
398
 
 
399
    def test_as_revision_id(self):
 
400
        self.assertAsRevisionId('r1', 'before:revid:r2')
 
401
        self.assertAsRevisionId('r1', 'before:2')
 
402
        self.assertAsRevisionId('r1', 'before:1.1.1')
 
403
        self.assertAsRevisionId('r1', 'before:revid:alt_r2')
 
404
 
 
405
 
 
406
class TestRevisionSpec_tag(TestRevisionSpec):
 
407
    
 
408
    def make_branch_and_tree(self, relpath):
 
409
        # override format as the default one may not support tags
 
410
        return TestRevisionSpec.make_branch_and_tree(
 
411
            self, relpath, format='dirstate-tags')
 
412
 
 
413
    def test_from_string_tag(self):
 
414
        spec = RevisionSpec.from_string('tag:bzr-0.14')
 
415
        self.assertIsInstance(spec, RevisionSpec_tag)
 
416
        self.assertEqual(spec.spec, 'bzr-0.14')
 
417
 
 
418
    def test_lookup_tag(self):
 
419
        self.tree.branch.tags.set_tag('bzr-0.14', 'r1')
 
420
        self.assertInHistoryIs(1, 'r1', 'tag:bzr-0.14')
 
421
        self.tree.branch.tags.set_tag('null_rev', 'null:')
 
422
        self.assertInHistoryIs(0, 'null:', 'tag:null_rev')
 
423
 
 
424
    def test_failed_lookup(self):
 
425
        # tags that don't exist give a specific message: arguably we should
 
426
        # just give InvalidRevisionSpec but I think this is more helpful
 
427
        self.assertRaises(errors.NoSuchTag,
 
428
            self.get_in_history,
 
429
            'tag:some-random-tag')
 
430
 
 
431
    def test_as_revision_id(self):
 
432
        self.tree.branch.tags.set_tag('my-tag', 'r2')
 
433
        self.tree.branch.tags.set_tag('null_rev', 'null:')
 
434
        self.assertAsRevisionId('r2', 'tag:my-tag')
 
435
        self.assertAsRevisionId('null:', 'tag:null_rev')
 
436
        self.assertAsRevisionId('r1', 'before:tag:my-tag')
 
437
 
 
438
 
 
439
class TestRevisionSpec_date(TestRevisionSpec):
 
440
 
 
441
    def setUp(self):
 
442
        super(TestRevisionSpec, self).setUp()
 
443
 
 
444
        new_tree = self.make_branch_and_tree('new_tree')
 
445
        new_tree.commit('Commit one', rev_id='new_r1',
 
446
                        timestamp=time.time() - 60*60*24)
 
447
        new_tree.commit('Commit two', rev_id='new_r2')
 
448
        new_tree.commit('Commit three', rev_id='new_r3')
 
449
 
 
450
        self.tree = new_tree
 
451
 
 
452
    def test_tomorrow(self):
 
453
        self.assertInvalid('date:tomorrow')
 
454
 
 
455
    def test_today(self):
 
456
        self.assertInHistoryIs(2, 'new_r2', 'date:today')
 
457
        self.assertInHistoryIs(1, 'new_r1', 'before:date:today')
 
458
 
 
459
    def test_yesterday(self):
 
460
        self.assertInHistoryIs(1, 'new_r1', 'date:yesterday')
 
461
 
 
462
    def test_invalid(self):
 
463
        self.assertInvalid('date:foobar', extra='\ninvalid date')
 
464
        # You must have '-' between year/month/day
 
465
        self.assertInvalid('date:20040404', extra='\ninvalid date')
 
466
        # Need 2 digits for each date piece
 
467
        self.assertInvalid('date:2004-4-4', extra='\ninvalid date')
 
468
 
 
469
    def test_day(self):
 
470
        now = datetime.datetime.now()
 
471
        self.assertInHistoryIs(2, 'new_r2',
 
472
            'date:%04d-%02d-%02d' % (now.year, now.month, now.day))
 
473
 
 
474
    def test_as_revision_id(self):
 
475
        self.assertAsRevisionId('new_r2', 'date:today')
 
476
 
 
477
 
 
478
class TestRevisionSpec_ancestor(TestRevisionSpec):
 
479
    
 
480
    def test_non_exact_branch(self):
 
481
        # It seems better to require an exact path to the branch
 
482
        # Branch.open() rather than using Branch.open_containing()
 
483
        self.assertRaises(errors.NotBranchError,
 
484
                          self.get_in_history, 'ancestor:tree2/a')
 
485
 
 
486
    def test_simple(self):
 
487
        # Common ancestor of trees is 'alt_r2'
 
488
        self.assertInHistoryIs(None, 'alt_r2', 'ancestor:tree2')
 
489
 
 
490
        # Going the other way, we get a valid revno
 
491
        tmp = self.tree
 
492
        self.tree = self.tree2
 
493
        self.tree2 = tmp
 
494
        self.assertInHistoryIs(2, 'alt_r2', 'ancestor:tree')
 
495
 
 
496
    def test_self(self):
 
497
        self.assertInHistoryIs(2, 'r2', 'ancestor:tree')
 
498
 
 
499
    def test_unrelated(self):
 
500
        new_tree = self.make_branch_and_tree('new_tree')
 
501
 
 
502
        new_tree.commit('Commit one', rev_id='new_r1')
 
503
        new_tree.commit('Commit two', rev_id='new_r2')
 
504
        new_tree.commit('Commit three', rev_id='new_r3')
 
505
 
 
506
        # With no common ancestor, we should raise another user error
 
507
        self.assertRaises(errors.NoCommonAncestor,
 
508
                          self.get_in_history, 'ancestor:new_tree')
 
509
 
 
510
    def test_no_commits(self):
 
511
        new_tree = self.make_branch_and_tree('new_tree')
 
512
        self.assertRaises(errors.NoCommits,
 
513
                          spec_in_history, 'ancestor:new_tree',
 
514
                                           self.tree.branch)
 
515
                        
 
516
        self.assertRaises(errors.NoCommits,
 
517
                          spec_in_history, 'ancestor:tree',
 
518
                                           new_tree.branch)
 
519
 
 
520
    def test_as_revision_id(self):
 
521
        self.assertAsRevisionId('alt_r2', 'ancestor:tree2')
 
522
 
 
523
 
 
524
class TestRevisionSpec_branch(TestRevisionSpec):
 
525
    
 
526
    def test_non_exact_branch(self):
 
527
        # It seems better to require an exact path to the branch
 
528
        # Branch.open() rather than using Branch.open_containing()
 
529
        self.assertRaises(errors.NotBranchError,
 
530
                          self.get_in_history, 'branch:tree2/a')
 
531
 
 
532
    def test_simple(self):
 
533
        self.assertInHistoryIs(None, 'alt_r2', 'branch:tree2')
 
534
 
 
535
    def test_self(self):
 
536
        self.assertInHistoryIs(2, 'r2', 'branch:tree')
 
537
 
 
538
    def test_unrelated(self):
 
539
        new_tree = self.make_branch_and_tree('new_tree')
 
540
 
 
541
        new_tree.commit('Commit one', rev_id='new_r1')
 
542
        new_tree.commit('Commit two', rev_id='new_r2')
 
543
        new_tree.commit('Commit three', rev_id='new_r3')
 
544
 
 
545
        self.assertInHistoryIs(None, 'new_r3', 'branch:new_tree')
 
546
 
 
547
        # XXX: Right now, we use fetch() to make sure the remote revisions
 
548
        # have been pulled into the local branch. We may change that
 
549
        # behavior in the future.
 
550
        self.failUnless(self.tree.branch.repository.has_revision('new_r3'))
 
551
 
 
552
    def test_no_commits(self):
 
553
        new_tree = self.make_branch_and_tree('new_tree')
 
554
        self.assertRaises(errors.NoCommits,
 
555
                          self.get_in_history, 'branch:new_tree')
 
556
 
 
557
    def test_as_revision_id(self):
 
558
        self.assertAsRevisionId('alt_r2', 'branch:tree2')
 
559
 
 
560
 
 
561
class TestRevisionSpec_submit(TestRevisionSpec):
 
562
 
 
563
    def test_submit_branch(self):
 
564
        # Common ancestor of trees is 'alt_r2'
 
565
        self.assertRaises(errors.NoSubmitBranch, self.get_in_history,
 
566
                          'submit:')
 
567
        self.tree.branch.set_parent('../tree2')
 
568
        self.assertInHistoryIs(None, 'alt_r2', 'submit:')
 
569
        self.tree.branch.set_parent('bogus')
 
570
        self.assertRaises(errors.NotBranchError, self.get_in_history,
 
571
            'submit:')
 
572
        # submit branch overrides parent branch
 
573
        self.tree.branch.set_submit_branch('tree2')
 
574
        self.assertInHistoryIs(None, 'alt_r2', 'submit:')
 
575
 
 
576
    def test_as_revision_id(self):
 
577
        self.tree.branch.set_submit_branch('tree2')
 
578
        self.assertAsRevisionId('alt_r2', 'branch:tree2')