~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: 2007-07-04 14:02:09 UTC
  • mfrom: (2584.1.1 Aaron's integration)
  • Revision ID: pqm@pqm.ubuntu.com-20070704140209-ldl1njlpcclszadu
Fix #102019 by not asking strace to follow children

Show diffs side-by-side

added added

removed removed

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