~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_revisionspec.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2008-05-29 15:57:16 UTC
  • mfrom: (3427.5.9 dep_warnings)
  • Revision ID: pqm@pqm.ubuntu.com-20080529155716-0w3kic8lioa63231
(jam) Enable Deprecation Warnings when running -Werror and when
        running selftest

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 TestOddRevisionSpec(TestRevisionSpec):
 
94
    """Test things that aren't normally thought of as revision specs"""
 
95
 
 
96
    def test_none(self):
 
97
        self.assertInHistoryIs(None, None, None)
 
98
 
 
99
    def test_object(self):
 
100
        self.assertRaises(TypeError, RevisionSpec.from_string, object())
 
101
 
 
102
    def test_unregistered_spec(self):
 
103
        self.assertRaises(errors.NoSuchRevisionSpec,
 
104
                          RevisionSpec.from_string, 'foo')
 
105
        self.assertRaises(errors.NoSuchRevisionSpec,
 
106
                          RevisionSpec.from_string, '123a')
 
107
 
 
108
 
 
109
 
 
110
class TestRevnoFromString(TestCase):
 
111
 
 
112
    def test_from_string_dotted_decimal(self):
 
113
        self.assertRaises(errors.NoSuchRevisionSpec, RevisionSpec.from_string, '-1.1')
 
114
        self.assertRaises(errors.NoSuchRevisionSpec, RevisionSpec.from_string, '.1')
 
115
        self.assertRaises(errors.NoSuchRevisionSpec, RevisionSpec.from_string, '1..1')
 
116
        self.assertRaises(errors.NoSuchRevisionSpec, RevisionSpec.from_string, '1.2..1')
 
117
        self.assertRaises(errors.NoSuchRevisionSpec, RevisionSpec.from_string, '1.')
 
118
        self.assertIsInstance(RevisionSpec.from_string('1.1'), RevisionSpec_revno)
 
119
        self.assertIsInstance(RevisionSpec.from_string('1.1.3'), RevisionSpec_revno)
 
120
 
 
121
 
 
122
class TestRevisionSpec_revno(TestRevisionSpec):
 
123
 
 
124
    def test_positive_int(self):
 
125
        self.assertInHistoryIs(0, 'null:', '0')
 
126
        self.assertInHistoryIs(1, 'r1', '1')
 
127
        self.assertInHistoryIs(2, 'r2', '2')
 
128
        self.assertInvalid('3')
 
129
 
 
130
    def test_dotted_decimal(self):
 
131
        self.assertInHistoryIs(None, 'alt_r2', '1.1.1')
 
132
 
 
133
    def test_negative_int(self):
 
134
        self.assertInHistoryIs(2, 'r2', '-1')
 
135
        self.assertInHistoryIs(1, 'r1', '-2')
 
136
 
 
137
        self.assertInHistoryIs(1, 'r1', '-3')
 
138
        self.assertInHistoryIs(1, 'r1', '-4')
 
139
        self.assertInHistoryIs(1, 'r1', '-100')
 
140
 
 
141
    def test_positive(self):
 
142
        self.assertInHistoryIs(0, 'null:', 'revno:0')
 
143
        self.assertInHistoryIs(1, 'r1', 'revno:1')
 
144
        self.assertInHistoryIs(2, 'r2', 'revno:2')
 
145
 
 
146
        self.assertInvalid('revno:3')
 
147
 
 
148
    def test_negative(self):
 
149
        self.assertInHistoryIs(2, 'r2', 'revno:-1')
 
150
        self.assertInHistoryIs(1, 'r1', 'revno:-2')
 
151
 
 
152
        self.assertInHistoryIs(1, 'r1', 'revno:-3')
 
153
        self.assertInHistoryIs(1, 'r1', 'revno:-4')
 
154
 
 
155
    def test_invalid_number(self):
 
156
        # Get the right exception text
 
157
        try:
 
158
            int('X')
 
159
        except ValueError, e:
 
160
            pass
 
161
        self.assertInvalid('revno:X', extra='\n' + str(e))
 
162
 
 
163
    def test_missing_number_and_branch(self):
 
164
        self.assertInvalid('revno::',
 
165
                           extra='\ncannot have an empty revno and no branch')
 
166
 
 
167
    def test_invalid_number_with_branch(self):
 
168
        try:
 
169
            int('X')
 
170
        except ValueError, e:
 
171
            pass
 
172
        self.assertInvalid('revno:X:tree2', extra='\n' + str(e))
 
173
 
 
174
    def test_non_exact_branch(self):
 
175
        # It seems better to require an exact path to the branch
 
176
        # Branch.open() rather than using Branch.open_containing()
 
177
        spec = RevisionSpec.from_string('revno:2:tree2/a')
 
178
        self.assertRaises(errors.NotBranchError,
 
179
                          spec.in_history, self.tree.branch)
 
180
 
 
181
    def test_with_branch(self):
 
182
        # Passing a URL overrides the supplied branch path
 
183
        revinfo = self.get_in_history('revno:2:tree2')
 
184
        self.assertNotEqual(self.tree.branch.base, revinfo.branch.base)
 
185
        self.assertEqual(self.tree2.branch.base, revinfo.branch.base)
 
186
        self.assertEqual(2, revinfo.revno)
 
187
        self.assertEqual('alt_r2', revinfo.rev_id)
 
188
 
 
189
    def test_int_with_branch(self):
 
190
        revinfo = self.get_in_history('2:tree2')
 
191
        self.assertNotEqual(self.tree.branch.base, revinfo.branch.base)
 
192
        self.assertEqual(self.tree2.branch.base, revinfo.branch.base)
 
193
        self.assertEqual(2, revinfo.revno)
 
194
        self.assertEqual('alt_r2', revinfo.rev_id)
 
195
 
 
196
    def test_with_url(self):
 
197
        url = self.get_url() + '/tree2'
 
198
        revinfo = self.get_in_history('revno:2:%s' % (url,))
 
199
        self.assertNotEqual(self.tree.branch.base, revinfo.branch.base)
 
200
        self.assertEqual(self.tree2.branch.base, revinfo.branch.base)
 
201
        self.assertEqual(2, revinfo.revno)
 
202
        self.assertEqual('alt_r2', revinfo.rev_id)
 
203
 
 
204
    def test_negative_with_url(self):
 
205
        url = self.get_url() + '/tree2'
 
206
        revinfo = self.get_in_history('revno:-1:%s' % (url,))
 
207
        self.assertNotEqual(self.tree.branch.base, revinfo.branch.base)
 
208
        self.assertEqual(self.tree2.branch.base, revinfo.branch.base)
 
209
        self.assertEqual(2, revinfo.revno)
 
210
        self.assertEqual('alt_r2', revinfo.rev_id)
 
211
 
 
212
    def test_different_history_lengths(self):
 
213
        # Make sure we use the revisions and offsets in the supplied branch
 
214
        # not the ones in the original branch.
 
215
        self.tree2.commit('three', rev_id='r3')
 
216
        self.assertInHistoryIs(3, 'r3', 'revno:3:tree2')
 
217
        self.assertInHistoryIs(3, 'r3', 'revno:-1:tree2')
 
218
 
 
219
    def test_invalid_branch(self):
 
220
        self.assertRaises(errors.NotBranchError,
 
221
                          self.get_in_history, 'revno:-1:tree3')
 
222
 
 
223
    def test_invalid_revno_in_branch(self):
 
224
        self.tree.commit('three', rev_id='r3')
 
225
        self.assertInvalid('revno:3:tree2')
 
226
 
 
227
    def test_revno_n_path(self):
 
228
        """Old revno:N:path tests"""
 
229
        wta = self.make_branch_and_tree('a')
 
230
        ba = wta.branch
 
231
        
 
232
        wta.commit('Commit one', rev_id='a@r-0-1')
 
233
        wta.commit('Commit two', rev_id='a@r-0-2')
 
234
        wta.commit('Commit three', rev_id='a@r-0-3')
 
235
 
 
236
        wtb = self.make_branch_and_tree('b')
 
237
        bb = wtb.branch
 
238
 
 
239
        wtb.commit('Commit one', rev_id='b@r-0-1')
 
240
        wtb.commit('Commit two', rev_id='b@r-0-2')
 
241
        wtb.commit('Commit three', rev_id='b@r-0-3')
 
242
 
 
243
 
 
244
        self.assertEqual((1, 'a@r-0-1'),
 
245
                         spec_in_history('revno:1:a/', ba))
 
246
        # The argument of in_history should be ignored since it is
 
247
        # redundant with the path in the spec.
 
248
        self.assertEqual((1, 'a@r-0-1'),
 
249
                         spec_in_history('revno:1:a/', None))
 
250
        self.assertEqual((1, 'a@r-0-1'),
 
251
                         spec_in_history('revno:1:a/', bb))
 
252
        self.assertEqual((2, 'b@r-0-2'),
 
253
                         spec_in_history('revno:2:b/', None))
 
254
 
 
255
    def test_as_revision_id(self):
 
256
        self.assertAsRevisionId('null:', '0')
 
257
        self.assertAsRevisionId('r1', '1')
 
258
        self.assertAsRevisionId('r2', '2')
 
259
        self.assertAsRevisionId('r1', '-2')
 
260
        self.assertAsRevisionId('r2', '-1')
 
261
        self.assertAsRevisionId('alt_r2', '1.1.1')
 
262
 
 
263
 
 
264
class TestRevisionSpec_revid(TestRevisionSpec):
 
265
    
 
266
    def test_in_history(self):
 
267
        # We should be able to access revisions that are directly
 
268
        # in the history.
 
269
        self.assertInHistoryIs(1, 'r1', 'revid:r1')
 
270
        self.assertInHistoryIs(2, 'r2', 'revid:r2')
 
271
        
 
272
    def test_missing(self):
 
273
        self.assertInvalid('revid:r3')
 
274
 
 
275
    def test_merged(self):
 
276
        """We can reach revisions in the ancestry"""
 
277
        self.assertInHistoryIs(None, 'alt_r2', 'revid:alt_r2')
 
278
 
 
279
    def test_not_here(self):
 
280
        self.tree2.commit('alt third', rev_id='alt_r3')
 
281
        # It exists in tree2, but not in tree
 
282
        self.assertInvalid('revid:alt_r3')
 
283
 
 
284
    def test_in_repository(self):
 
285
        """We can get any revision id in the repository"""
 
286
        # XXX: This may change in the future, but for now, it is true
 
287
        self.tree2.commit('alt third', rev_id='alt_r3')
 
288
        self.tree.branch.repository.fetch(self.tree2.branch.repository,
 
289
                                          revision_id='alt_r3')
 
290
        self.assertInHistoryIs(None, 'alt_r3', 'revid:alt_r3')
 
291
 
 
292
    def test_unicode(self):
 
293
        """We correctly convert a unicode ui string to an encoded revid."""
 
294
        revision_id = u'\N{SNOWMAN}'.encode('utf-8')
 
295
        self.tree.commit('unicode', rev_id=revision_id)
 
296
        self.assertInHistoryIs(3, revision_id, u'revid:\N{SNOWMAN}')
 
297
        self.assertInHistoryIs(3, revision_id, 'revid:' + revision_id)
 
298
 
 
299
    def test_as_revision_id(self):
 
300
        self.assertAsRevisionId('r1', 'revid:r1')
 
301
        self.assertAsRevisionId('r2', 'revid:r2')
 
302
        self.assertAsRevisionId('alt_r2', 'revid:alt_r2')
 
303
 
 
304
 
 
305
class TestRevisionSpec_last(TestRevisionSpec):
 
306
 
 
307
    def test_positive(self):
 
308
        self.assertInHistoryIs(2, 'r2', 'last:1')
 
309
        self.assertInHistoryIs(1, 'r1', 'last:2')
 
310
        self.assertInHistoryIs(0, 'null:', 'last:3')
 
311
 
 
312
    def test_empty(self):
 
313
        self.assertInHistoryIs(2, 'r2', 'last:')
 
314
 
 
315
    def test_negative(self):
 
316
        self.assertInvalid('last:-1',
 
317
                           extra='\nyou must supply a positive value')
 
318
 
 
319
    def test_missing(self):
 
320
        self.assertInvalid('last:4')
 
321
 
 
322
    def test_no_history(self):
 
323
        tree = self.make_branch_and_tree('tree3')
 
324
 
 
325
        self.assertRaises(errors.NoCommits,
 
326
                          spec_in_history, 'last:', tree.branch)
 
327
 
 
328
    def test_not_a_number(self):
 
329
        try:
 
330
            int('Y')
 
331
        except ValueError, e:
 
332
            pass
 
333
        self.assertInvalid('last:Y', extra='\n' + str(e))
 
334
 
 
335
    def test_as_revision_id(self):
 
336
        self.assertAsRevisionId('r2', 'last:1')
 
337
        self.assertAsRevisionId('r1', 'last:2')
 
338
 
 
339
 
 
340
class TestRevisionSpec_before(TestRevisionSpec):
 
341
 
 
342
    def test_int(self):
 
343
        self.assertInHistoryIs(1, 'r1', 'before:2')
 
344
        self.assertInHistoryIs(1, 'r1', 'before:-1')
 
345
 
 
346
    def test_before_one(self):
 
347
        self.assertInHistoryIs(0, 'null:', 'before:1')
 
348
 
 
349
    def test_before_none(self):
 
350
        self.assertInvalid('before:0',
 
351
                           extra='\ncannot go before the null: revision')
 
352
 
 
353
    def test_revid(self):
 
354
        self.assertInHistoryIs(1, 'r1', 'before:revid:r2')
 
355
 
 
356
    def test_last(self):
 
357
        self.assertInHistoryIs(1, 'r1', 'before:last:1')
 
358
 
 
359
    def test_alt_revid(self):
 
360
        # This will grab the left-most ancestor for alternate histories
 
361
        self.assertInHistoryIs(1, 'r1', 'before:revid:alt_r2')
 
362
 
 
363
    def test_alt_no_parents(self):
 
364
        new_tree = self.make_branch_and_tree('new_tree')
 
365
        new_tree.commit('first', rev_id='new_r1')
 
366
        self.tree.branch.repository.fetch(new_tree.branch.repository,
 
367
                                          revision_id='new_r1')
 
368
        self.assertInHistoryIs(0, 'null:', 'before:revid:new_r1')
 
369
 
 
370
    def test_as_revision_id(self):
 
371
        self.assertAsRevisionId('r1', 'before:revid:r2')
 
372
        self.assertAsRevisionId('r1', 'before:2')
 
373
        self.assertAsRevisionId('r1', 'before:1.1.1')
 
374
        self.assertAsRevisionId('r1', 'before:revid:alt_r2')
 
375
 
 
376
 
 
377
class TestRevisionSpec_tag(TestRevisionSpec):
 
378
    
 
379
    def make_branch_and_tree(self, relpath):
 
380
        # override format as the default one may not support tags
 
381
        return TestRevisionSpec.make_branch_and_tree(
 
382
            self, relpath, format='dirstate-tags')
 
383
 
 
384
    def test_from_string_tag(self):
 
385
        spec = RevisionSpec.from_string('tag:bzr-0.14')
 
386
        self.assertIsInstance(spec, RevisionSpec_tag)
 
387
        self.assertEqual(spec.spec, 'bzr-0.14')
 
388
 
 
389
    def test_lookup_tag(self):
 
390
        self.tree.branch.tags.set_tag('bzr-0.14', 'r1')
 
391
        self.assertInHistoryIs(1, 'r1', 'tag:bzr-0.14')
 
392
        self.tree.branch.tags.set_tag('null_rev', 'null:')
 
393
        self.assertInHistoryIs(0, 'null:', 'tag:null_rev')
 
394
 
 
395
    def test_failed_lookup(self):
 
396
        # tags that don't exist give a specific message: arguably we should
 
397
        # just give InvalidRevisionSpec but I think this is more helpful
 
398
        self.assertRaises(errors.NoSuchTag,
 
399
            self.get_in_history,
 
400
            'tag:some-random-tag')
 
401
 
 
402
    def test_as_revision_id(self):
 
403
        self.tree.branch.tags.set_tag('my-tag', 'r2')
 
404
        self.tree.branch.tags.set_tag('null_rev', 'null:')
 
405
        self.assertAsRevisionId('r2', 'tag:my-tag')
 
406
        self.assertAsRevisionId('null:', 'tag:null_rev')
 
407
        self.assertAsRevisionId('r1', 'before:tag:my-tag')
 
408
 
 
409
 
 
410
class TestRevisionSpec_date(TestRevisionSpec):
 
411
 
 
412
    def setUp(self):
 
413
        super(TestRevisionSpec, self).setUp()
 
414
 
 
415
        new_tree = self.make_branch_and_tree('new_tree')
 
416
        new_tree.commit('Commit one', rev_id='new_r1',
 
417
                        timestamp=time.time() - 60*60*24)
 
418
        new_tree.commit('Commit two', rev_id='new_r2')
 
419
        new_tree.commit('Commit three', rev_id='new_r3')
 
420
 
 
421
        self.tree = new_tree
 
422
 
 
423
    def test_tomorrow(self):
 
424
        self.assertInvalid('date:tomorrow')
 
425
 
 
426
    def test_today(self):
 
427
        self.assertInHistoryIs(2, 'new_r2', 'date:today')
 
428
        self.assertInHistoryIs(1, 'new_r1', 'before:date:today')
 
429
 
 
430
    def test_yesterday(self):
 
431
        self.assertInHistoryIs(1, 'new_r1', 'date:yesterday')
 
432
 
 
433
    def test_invalid(self):
 
434
        self.assertInvalid('date:foobar', extra='\ninvalid date')
 
435
        # You must have '-' between year/month/day
 
436
        self.assertInvalid('date:20040404', extra='\ninvalid date')
 
437
        # Need 2 digits for each date piece
 
438
        self.assertInvalid('date:2004-4-4', extra='\ninvalid date')
 
439
 
 
440
    def test_day(self):
 
441
        now = datetime.datetime.now()
 
442
        self.assertInHistoryIs(2, 'new_r2',
 
443
            'date:%04d-%02d-%02d' % (now.year, now.month, now.day))
 
444
 
 
445
    def test_as_revision_id(self):
 
446
        self.assertAsRevisionId('new_r2', 'date:today')
 
447
 
 
448
 
 
449
class TestRevisionSpec_ancestor(TestRevisionSpec):
 
450
    
 
451
    def test_non_exact_branch(self):
 
452
        # It seems better to require an exact path to the branch
 
453
        # Branch.open() rather than using Branch.open_containing()
 
454
        self.assertRaises(errors.NotBranchError,
 
455
                          self.get_in_history, 'ancestor:tree2/a')
 
456
 
 
457
    def test_simple(self):
 
458
        # Common ancestor of trees is 'alt_r2'
 
459
        self.assertInHistoryIs(None, 'alt_r2', 'ancestor:tree2')
 
460
 
 
461
        # Going the other way, we get a valid revno
 
462
        tmp = self.tree
 
463
        self.tree = self.tree2
 
464
        self.tree2 = tmp
 
465
        self.assertInHistoryIs(2, 'alt_r2', 'ancestor:tree')
 
466
 
 
467
    def test_self(self):
 
468
        self.assertInHistoryIs(2, 'r2', 'ancestor:tree')
 
469
 
 
470
    def test_unrelated(self):
 
471
        new_tree = self.make_branch_and_tree('new_tree')
 
472
 
 
473
        new_tree.commit('Commit one', rev_id='new_r1')
 
474
        new_tree.commit('Commit two', rev_id='new_r2')
 
475
        new_tree.commit('Commit three', rev_id='new_r3')
 
476
 
 
477
        # With no common ancestor, we should raise another user error
 
478
        self.assertRaises(errors.NoCommonAncestor,
 
479
                          self.get_in_history, 'ancestor:new_tree')
 
480
 
 
481
    def test_no_commits(self):
 
482
        new_tree = self.make_branch_and_tree('new_tree')
 
483
        self.assertRaises(errors.NoCommits,
 
484
                          spec_in_history, 'ancestor:new_tree',
 
485
                                           self.tree.branch)
 
486
                        
 
487
        self.assertRaises(errors.NoCommits,
 
488
                          spec_in_history, 'ancestor:tree',
 
489
                                           new_tree.branch)
 
490
 
 
491
    def test_as_revision_id(self):
 
492
        self.assertAsRevisionId('alt_r2', 'ancestor:tree2')
 
493
 
 
494
 
 
495
class TestRevisionSpec_branch(TestRevisionSpec):
 
496
    
 
497
    def test_non_exact_branch(self):
 
498
        # It seems better to require an exact path to the branch
 
499
        # Branch.open() rather than using Branch.open_containing()
 
500
        self.assertRaises(errors.NotBranchError,
 
501
                          self.get_in_history, 'branch:tree2/a')
 
502
 
 
503
    def test_simple(self):
 
504
        self.assertInHistoryIs(None, 'alt_r2', 'branch:tree2')
 
505
 
 
506
    def test_self(self):
 
507
        self.assertInHistoryIs(2, 'r2', 'branch:tree')
 
508
 
 
509
    def test_unrelated(self):
 
510
        new_tree = self.make_branch_and_tree('new_tree')
 
511
 
 
512
        new_tree.commit('Commit one', rev_id='new_r1')
 
513
        new_tree.commit('Commit two', rev_id='new_r2')
 
514
        new_tree.commit('Commit three', rev_id='new_r3')
 
515
 
 
516
        self.assertInHistoryIs(None, 'new_r3', 'branch:new_tree')
 
517
 
 
518
        # XXX: Right now, we use fetch() to make sure the remote revisions
 
519
        # have been pulled into the local branch. We may change that
 
520
        # behavior in the future.
 
521
        self.failUnless(self.tree.branch.repository.has_revision('new_r3'))
 
522
 
 
523
    def test_no_commits(self):
 
524
        new_tree = self.make_branch_and_tree('new_tree')
 
525
        self.assertRaises(errors.NoCommits,
 
526
                          self.get_in_history, 'branch:new_tree')
 
527
 
 
528
    def test_as_revision_id(self):
 
529
        self.assertAsRevisionId('alt_r2', 'branch:tree2')
 
530
 
 
531
 
 
532
class TestRevisionSpec_submit(TestRevisionSpec):
 
533
 
 
534
    def test_submit_branch(self):
 
535
        # Common ancestor of trees is 'alt_r2'
 
536
        self.assertRaises(errors.NoSubmitBranch, self.get_in_history,
 
537
                          'submit:')
 
538
        self.tree.branch.set_parent('../tree2')
 
539
        self.assertInHistoryIs(None, 'alt_r2', 'submit:')
 
540
        self.tree.branch.set_parent('bogus')
 
541
        self.assertRaises(errors.NotBranchError, self.get_in_history,
 
542
            'submit:')
 
543
        # submit branch overrides parent branch
 
544
        self.tree.branch.set_submit_branch('tree2')
 
545
        self.assertInHistoryIs(None, 'alt_r2', 'submit:')
 
546
 
 
547
    def test_as_revision_id(self):
 
548
        self.tree.branch.set_submit_branch('tree2')
 
549
        self.assertAsRevisionId('alt_r2', 'branch:tree2')