~bzr-pqm/bzr/bzr.dev

2220.2.3 by Martin Pool
Add tag: revision namespace.
1
# Copyright (C) 2004, 2005, 2006, 2007 Canonical Ltd
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
2
#
897 by Martin Pool
- merge john's revision-naming code
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
7
#
897 by Martin Pool
- merge john's revision-naming code
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
12
#
897 by Martin Pool
- merge john's revision-naming code
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
897 by Martin Pool
- merge john's revision-naming code
16
1948.4.12 by John Arbash Meinel
Some tests for the date: spec
17
import datetime
974.1.52 by aaron.bentley at utoronto
Merged mpool's latest changes (~0.0.7)
18
import os
1185.1.39 by Robert Collins
Robey Pointers before: namespace to clear up usage of dates in revision parameters
19
import time
1432 by Robert Collins
branch: namespace
20
1948.4.1 by John Arbash Meinel
Update number parsers to raise InvalidRevisionSpec. Update revno: itself so it supports negative numbers
21
from bzrlib import (
2220.2.11 by mbp at sourcefrog
Get tag tests working again, stored in the Branch
22
    branch,
2220.2.3 by Martin Pool
Add tag: revision namespace.
23
    bzrdir,
1948.4.1 by John Arbash Meinel
Update number parsers to raise InvalidRevisionSpec. Update revno: itself so it supports negative numbers
24
    errors,
2220.2.3 by Martin Pool
Add tag: revision namespace.
25
    repository,
3655.3.1 by Lukáš Lalinský
Fix `bzr st -rbranch:PATH_TO_BRANCH`
26
    revision as _mod_revision,
1948.4.1 by John Arbash Meinel
Update number parsers to raise InvalidRevisionSpec. Update revno: itself so it supports negative numbers
27
    )
1988.4.5 by Robert Collins
revisions can now be specified using dotted-decimal revision numbers.
28
from bzrlib.tests import TestCase, TestCaseWithTransport
2220.2.3 by Martin Pool
Add tag: revision namespace.
29
from bzrlib.revisionspec import (
30
    RevisionSpec,
31
    RevisionSpec_revno,
32
    RevisionSpec_tag,
33
    )
1948.4.33 by John Arbash Meinel
Switch from get_revision_spec() to RevisionSpec.from_string() (as advised by Martin)
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)
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
39
40
1948.4.3 by John Arbash Meinel
Create direct tests for RevisionSpec_int
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()
1988.4.5 by Robert Collins
revisions can now be specified using dotted-decimal revision numbers.
46
        # this sets up a revision graph:
47
        # r1: []             1
48
        # alt_r2: [r1]       1.1.1
49
        # r2: [r1, alt_r2]   2
1948.4.3 by John Arbash Meinel
Create direct tests for RevisionSpec_int
50
51
        self.tree = self.make_branch_and_tree('tree')
52
        self.build_tree(['tree/a'])
3298.2.3 by John Arbash Meinel
Add tests that all RevisionSpecs implement in_branch(b, needs_revno)
53
        self.tree.lock_write()
3298.2.11 by Aaron Bentley
Update tests for null:, clea up slightly
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')
1948.4.3 by John Arbash Meinel
Create direct tests for RevisionSpec_int
63
64
    def get_in_history(self, revision_spec):
1948.4.33 by John Arbash Meinel
Switch from get_revision_spec() to RevisionSpec.from_string() (as advised by Martin)
65
        return spec_in_history(revision_spec, self.tree.branch)
1948.4.3 by John Arbash Meinel
Create direct tests for RevisionSpec_int
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,
2325.2.1 by Marien Zwart
Make the test suite failure reporting a bit more robust.
70
                         'Revision spec: %r returned wrong revno: %r != %r'
1948.4.3 by John Arbash Meinel
Create direct tests for RevisionSpec_int
71
                         % (revision_spec, exp_revno, rev_info.revno))
72
        self.assertEqual(exp_revision_id, rev_info.rev_id,
2325.2.1 by Marien Zwart
Make the test suite failure reporting a bit more robust.
73
                         'Revision spec: %r returned wrong revision id:'
74
                         ' %r != %r'
1948.4.3 by John Arbash Meinel
Create direct tests for RevisionSpec_int
75
                         % (revision_spec, exp_revision_id, rev_info.rev_id))
76
3495.1.1 by John Arbash Meinel
Fix bug #239933, use the right exception for -c0
77
    def assertInvalid(self, revision_spec, extra='',
78
                      invalid_as_revision_id=True):
1948.4.3 by John Arbash Meinel
Create direct tests for RevisionSpec_int
79
        try:
80
            self.get_in_history(revision_spec)
81
        except errors.InvalidRevisionSpec, e:
1948.4.23 by John Arbash Meinel
Change the handling of negative numbers, to be trapped at revno 1
82
            self.assertEqual(revision_spec, e.spec)
1948.4.3 by John Arbash Meinel
Create direct tests for RevisionSpec_int
83
            self.assertEqual(extra, e.extra)
1948.4.5 by John Arbash Meinel
Fix tests for negative entries, and add tests for revno:
84
        else:
3495.1.1 by John Arbash Meinel
Fix bug #239933, use the right exception for -c0
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'
3495.1.2 by John Arbash Meinel
tweak
96
                          ' %r.as_revision_id' % (revision_spec,))
1948.4.3 by John Arbash Meinel
Create direct tests for RevisionSpec_int
97
3298.2.4 by John Arbash Meinel
Introduce as_revision_id() as a function instead of in_branch(need_revno=False)
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
3655.3.1 by Lukáš Lalinský
Fix `bzr st -rbranch:PATH_TO_BRANCH`
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
1948.4.3 by John Arbash Meinel
Create direct tests for RevisionSpec_int
110
3460.1.2 by John Arbash Meinel
Add a test for wants_revision_history
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
1948.4.19 by John Arbash Meinel
All old tests are covered elsewhere
140
class TestOddRevisionSpec(TestRevisionSpec):
141
    """Test things that aren't normally thought of as revision specs"""
142
143
    def test_none(self):
3298.2.11 by Aaron Bentley
Update tests for null:, clea up slightly
144
        self.assertInHistoryIs(None, None, None)
1948.4.19 by John Arbash Meinel
All old tests are covered elsewhere
145
146
    def test_object(self):
1948.4.33 by John Arbash Meinel
Switch from get_revision_spec() to RevisionSpec.from_string() (as advised by Martin)
147
        self.assertRaises(TypeError, RevisionSpec.from_string, object())
1948.4.19 by John Arbash Meinel
All old tests are covered elsewhere
148
1948.4.25 by John Arbash Meinel
Check that invalid specs are properly handled
149
    def test_unregistered_spec(self):
1948.4.33 by John Arbash Meinel
Switch from get_revision_spec() to RevisionSpec.from_string() (as advised by Martin)
150
        self.assertRaises(errors.NoSuchRevisionSpec,
151
                          RevisionSpec.from_string, 'foo')
152
        self.assertRaises(errors.NoSuchRevisionSpec,
153
                          RevisionSpec.from_string, '123a')
1948.4.32 by John Arbash Meinel
Clean up __repr__, as well as add tests that we can handle -r12:branch/
154
155
1988.4.5 by Robert Collins
revisions can now be specified using dotted-decimal revision numbers.
156
157
class TestRevnoFromString(TestCase):
158
159
    def test_from_string_dotted_decimal(self):
160
        self.assertRaises(errors.NoSuchRevisionSpec, RevisionSpec.from_string, '-1.1')
161
        self.assertRaises(errors.NoSuchRevisionSpec, RevisionSpec.from_string, '.1')
162
        self.assertRaises(errors.NoSuchRevisionSpec, RevisionSpec.from_string, '1..1')
163
        self.assertRaises(errors.NoSuchRevisionSpec, RevisionSpec.from_string, '1.2..1')
164
        self.assertRaises(errors.NoSuchRevisionSpec, RevisionSpec.from_string, '1.')
165
        self.assertIsInstance(RevisionSpec.from_string('1.1'), RevisionSpec_revno)
166
        self.assertIsInstance(RevisionSpec.from_string('1.1.3'), RevisionSpec_revno)
167
168
1948.4.32 by John Arbash Meinel
Clean up __repr__, as well as add tests that we can handle -r12:branch/
169
class TestRevisionSpec_revno(TestRevisionSpec):
170
171
    def test_positive_int(self):
2598.5.10 by Aaron Bentley
Return NULL_REVISION instead of None for the null revision
172
        self.assertInHistoryIs(0, 'null:', '0')
1948.4.3 by John Arbash Meinel
Create direct tests for RevisionSpec_int
173
        self.assertInHistoryIs(1, 'r1', '1')
174
        self.assertInHistoryIs(2, 'r2', '2')
1948.4.23 by John Arbash Meinel
Change the handling of negative numbers, to be trapped at revno 1
175
        self.assertInvalid('3')
1948.4.3 by John Arbash Meinel
Create direct tests for RevisionSpec_int
176
1988.4.5 by Robert Collins
revisions can now be specified using dotted-decimal revision numbers.
177
    def test_dotted_decimal(self):
178
        self.assertInHistoryIs(None, 'alt_r2', '1.1.1')
3878.3.1 by Marius Kruger
Test invalid dotted revion number directly in TestRevisionSpec_revno
179
        self.assertInvalid('1.1.123')
1988.4.5 by Robert Collins
revisions can now be specified using dotted-decimal revision numbers.
180
1948.4.32 by John Arbash Meinel
Clean up __repr__, as well as add tests that we can handle -r12:branch/
181
    def test_negative_int(self):
1948.4.3 by John Arbash Meinel
Create direct tests for RevisionSpec_int
182
        self.assertInHistoryIs(2, 'r2', '-1')
183
        self.assertInHistoryIs(1, 'r1', '-2')
184
1948.4.23 by John Arbash Meinel
Change the handling of negative numbers, to be trapped at revno 1
185
        self.assertInHistoryIs(1, 'r1', '-3')
186
        self.assertInHistoryIs(1, 'r1', '-4')
187
        self.assertInHistoryIs(1, 'r1', '-100')
1948.4.5 by John Arbash Meinel
Fix tests for negative entries, and add tests for revno:
188
189
    def test_positive(self):
2598.5.10 by Aaron Bentley
Return NULL_REVISION instead of None for the null revision
190
        self.assertInHistoryIs(0, 'null:', 'revno:0')
1948.4.5 by John Arbash Meinel
Fix tests for negative entries, and add tests for revno:
191
        self.assertInHistoryIs(1, 'r1', 'revno:1')
192
        self.assertInHistoryIs(2, 'r2', 'revno:2')
193
194
        self.assertInvalid('revno:3')
195
196
    def test_negative(self):
197
        self.assertInHistoryIs(2, 'r2', 'revno:-1')
198
        self.assertInHistoryIs(1, 'r1', 'revno:-2')
199
1948.4.23 by John Arbash Meinel
Change the handling of negative numbers, to be trapped at revno 1
200
        self.assertInHistoryIs(1, 'r1', 'revno:-3')
201
        self.assertInHistoryIs(1, 'r1', 'revno:-4')
1948.4.6 by John Arbash Meinel
A small bugfix, and more tests for revno:
202
203
    def test_invalid_number(self):
204
        # Get the right exception text
205
        try:
206
            int('X')
207
        except ValueError, e:
208
            pass
1948.4.15 by John Arbash Meinel
Change the InvalidRevisionSpec formatting to be more readable
209
        self.assertInvalid('revno:X', extra='\n' + str(e))
1948.4.6 by John Arbash Meinel
A small bugfix, and more tests for revno:
210
211
    def test_missing_number_and_branch(self):
212
        self.assertInvalid('revno::',
1948.4.15 by John Arbash Meinel
Change the InvalidRevisionSpec formatting to be more readable
213
                           extra='\ncannot have an empty revno and no branch')
1948.4.7 by John Arbash Meinel
More revno: tests, now testing the branch/url parameter
214
215
    def test_invalid_number_with_branch(self):
216
        try:
217
            int('X')
218
        except ValueError, e:
219
            pass
1948.4.15 by John Arbash Meinel
Change the InvalidRevisionSpec formatting to be more readable
220
        self.assertInvalid('revno:X:tree2', extra='\n' + str(e))
1948.4.7 by John Arbash Meinel
More revno: tests, now testing the branch/url parameter
221
1948.4.16 by John Arbash Meinel
Move the tests into the associated tester, remove redundant tests, some small PEP8 changes
222
    def test_non_exact_branch(self):
223
        # It seems better to require an exact path to the branch
224
        # Branch.open() rather than using Branch.open_containing()
1948.4.33 by John Arbash Meinel
Switch from get_revision_spec() to RevisionSpec.from_string() (as advised by Martin)
225
        spec = RevisionSpec.from_string('revno:2:tree2/a')
1948.4.16 by John Arbash Meinel
Move the tests into the associated tester, remove redundant tests, some small PEP8 changes
226
        self.assertRaises(errors.NotBranchError,
1948.4.33 by John Arbash Meinel
Switch from get_revision_spec() to RevisionSpec.from_string() (as advised by Martin)
227
                          spec.in_history, self.tree.branch)
1948.4.16 by John Arbash Meinel
Move the tests into the associated tester, remove redundant tests, some small PEP8 changes
228
1948.4.7 by John Arbash Meinel
More revno: tests, now testing the branch/url parameter
229
    def test_with_branch(self):
230
        # Passing a URL overrides the supplied branch path
231
        revinfo = self.get_in_history('revno:2:tree2')
232
        self.assertNotEqual(self.tree.branch.base, revinfo.branch.base)
233
        self.assertEqual(self.tree2.branch.base, revinfo.branch.base)
234
        self.assertEqual(2, revinfo.revno)
235
        self.assertEqual('alt_r2', revinfo.rev_id)
236
1948.4.32 by John Arbash Meinel
Clean up __repr__, as well as add tests that we can handle -r12:branch/
237
    def test_int_with_branch(self):
238
        revinfo = self.get_in_history('2:tree2')
239
        self.assertNotEqual(self.tree.branch.base, revinfo.branch.base)
240
        self.assertEqual(self.tree2.branch.base, revinfo.branch.base)
241
        self.assertEqual(2, revinfo.revno)
242
        self.assertEqual('alt_r2', revinfo.rev_id)
243
1948.4.7 by John Arbash Meinel
More revno: tests, now testing the branch/url parameter
244
    def test_with_url(self):
245
        url = self.get_url() + '/tree2'
246
        revinfo = self.get_in_history('revno:2:%s' % (url,))
247
        self.assertNotEqual(self.tree.branch.base, revinfo.branch.base)
248
        self.assertEqual(self.tree2.branch.base, revinfo.branch.base)
249
        self.assertEqual(2, revinfo.revno)
250
        self.assertEqual('alt_r2', revinfo.rev_id)
251
252
    def test_negative_with_url(self):
253
        url = self.get_url() + '/tree2'
254
        revinfo = self.get_in_history('revno:-1:%s' % (url,))
255
        self.assertNotEqual(self.tree.branch.base, revinfo.branch.base)
256
        self.assertEqual(self.tree2.branch.base, revinfo.branch.base)
257
        self.assertEqual(2, revinfo.revno)
258
        self.assertEqual('alt_r2', revinfo.rev_id)
259
1948.4.22 by John Arbash Meinel
Refactor common code from integer revno handlers
260
    def test_different_history_lengths(self):
261
        # Make sure we use the revisions and offsets in the supplied branch
262
        # not the ones in the original branch.
263
        self.tree2.commit('three', rev_id='r3')
264
        self.assertInHistoryIs(3, 'r3', 'revno:3:tree2')
265
        self.assertInHistoryIs(3, 'r3', 'revno:-1:tree2')
266
1948.4.7 by John Arbash Meinel
More revno: tests, now testing the branch/url parameter
267
    def test_invalid_branch(self):
268
        self.assertRaises(errors.NotBranchError,
269
                          self.get_in_history, 'revno:-1:tree3')
270
271
    def test_invalid_revno_in_branch(self):
272
        self.tree.commit('three', rev_id='r3')
273
        self.assertInvalid('revno:3:tree2')
1948.4.8 by John Arbash Meinel
Testing the revid: spec
274
1948.4.16 by John Arbash Meinel
Move the tests into the associated tester, remove redundant tests, some small PEP8 changes
275
    def test_revno_n_path(self):
276
        """Old revno:N:path tests"""
277
        wta = self.make_branch_and_tree('a')
278
        ba = wta.branch
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
279
1948.4.16 by John Arbash Meinel
Move the tests into the associated tester, remove redundant tests, some small PEP8 changes
280
        wta.commit('Commit one', rev_id='a@r-0-1')
281
        wta.commit('Commit two', rev_id='a@r-0-2')
282
        wta.commit('Commit three', rev_id='a@r-0-3')
283
284
        wtb = self.make_branch_and_tree('b')
285
        bb = wtb.branch
286
287
        wtb.commit('Commit one', rev_id='b@r-0-1')
288
        wtb.commit('Commit two', rev_id='b@r-0-2')
289
        wtb.commit('Commit three', rev_id='b@r-0-3')
290
1948.4.33 by John Arbash Meinel
Switch from get_revision_spec() to RevisionSpec.from_string() (as advised by Martin)
291
292
        self.assertEqual((1, 'a@r-0-1'),
293
                         spec_in_history('revno:1:a/', ba))
1948.4.16 by John Arbash Meinel
Move the tests into the associated tester, remove redundant tests, some small PEP8 changes
294
        # The argument of in_history should be ignored since it is
295
        # redundant with the path in the spec.
1948.4.33 by John Arbash Meinel
Switch from get_revision_spec() to RevisionSpec.from_string() (as advised by Martin)
296
        self.assertEqual((1, 'a@r-0-1'),
297
                         spec_in_history('revno:1:a/', None))
298
        self.assertEqual((1, 'a@r-0-1'),
299
                         spec_in_history('revno:1:a/', bb))
300
        self.assertEqual((2, 'b@r-0-2'),
301
                         spec_in_history('revno:2:b/', None))
1948.4.16 by John Arbash Meinel
Move the tests into the associated tester, remove redundant tests, some small PEP8 changes
302
3298.2.4 by John Arbash Meinel
Introduce as_revision_id() as a function instead of in_branch(need_revno=False)
303
    def test_as_revision_id(self):
3298.2.11 by Aaron Bentley
Update tests for null:, clea up slightly
304
        self.assertAsRevisionId('null:', '0')
3298.2.4 by John Arbash Meinel
Introduce as_revision_id() as a function instead of in_branch(need_revno=False)
305
        self.assertAsRevisionId('r1', '1')
306
        self.assertAsRevisionId('r2', '2')
307
        self.assertAsRevisionId('r1', '-2')
308
        self.assertAsRevisionId('r2', '-1')
309
        self.assertAsRevisionId('alt_r2', '1.1.1')
310
3655.3.1 by Lukáš Lalinský
Fix `bzr st -rbranch:PATH_TO_BRANCH`
311
    def test_as_tree(self):
312
        tree = self.get_as_tree('0')
313
        self.assertEquals(_mod_revision.NULL_REVISION, tree.get_revision_id())
314
        tree = self.get_as_tree('1')
315
        self.assertEquals('r1', tree.get_revision_id())
316
        tree = self.get_as_tree('2')
317
        self.assertEquals('r2', tree.get_revision_id())
318
        tree = self.get_as_tree('-2')
319
        self.assertEquals('r1', tree.get_revision_id())
320
        tree = self.get_as_tree('-1')
321
        self.assertEquals('r2', tree.get_revision_id())
322
        tree = self.get_as_tree('1.1.1')
323
        self.assertEquals('alt_r2', tree.get_revision_id())
324
1948.4.8 by John Arbash Meinel
Testing the revid: spec
325
326
class TestRevisionSpec_revid(TestRevisionSpec):
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
327
1948.4.8 by John Arbash Meinel
Testing the revid: spec
328
    def test_in_history(self):
329
        # We should be able to access revisions that are directly
330
        # in the history.
331
        self.assertInHistoryIs(1, 'r1', 'revid:r1')
332
        self.assertInHistoryIs(2, 'r2', 'revid:r2')
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
333
1948.4.8 by John Arbash Meinel
Testing the revid: spec
334
    def test_missing(self):
3495.1.1 by John Arbash Meinel
Fix bug #239933, use the right exception for -c0
335
        self.assertInvalid('revid:r3', invalid_as_revision_id=False)
1948.4.8 by John Arbash Meinel
Testing the revid: spec
336
337
    def test_merged(self):
338
        """We can reach revisions in the ancestry"""
339
        self.assertInHistoryIs(None, 'alt_r2', 'revid:alt_r2')
340
341
    def test_not_here(self):
342
        self.tree2.commit('alt third', rev_id='alt_r3')
343
        # It exists in tree2, but not in tree
3495.1.1 by John Arbash Meinel
Fix bug #239933, use the right exception for -c0
344
        self.assertInvalid('revid:alt_r3', invalid_as_revision_id=False)
1948.4.8 by John Arbash Meinel
Testing the revid: spec
345
346
    def test_in_repository(self):
347
        """We can get any revision id in the repository"""
348
        # XXX: This may change in the future, but for now, it is true
349
        self.tree2.commit('alt third', rev_id='alt_r3')
350
        self.tree.branch.repository.fetch(self.tree2.branch.repository,
351
                                          revision_id='alt_r3')
352
        self.assertInHistoryIs(None, 'alt_r3', 'revid:alt_r3')
1948.4.9 by John Arbash Meinel
Cleanup and test last:
353
2325.2.2 by Marien Zwart
Make the revid RevisionSpec always return a str object, not a unicode object.
354
    def test_unicode(self):
355
        """We correctly convert a unicode ui string to an encoded revid."""
2325.2.4 by Marien Zwart
Rename rev_id to revision_id because HACKING says so.
356
        revision_id = u'\N{SNOWMAN}'.encode('utf-8')
357
        self.tree.commit('unicode', rev_id=revision_id)
358
        self.assertInHistoryIs(3, revision_id, u'revid:\N{SNOWMAN}')
359
        self.assertInHistoryIs(3, revision_id, 'revid:' + revision_id)
2325.2.2 by Marien Zwart
Make the revid RevisionSpec always return a str object, not a unicode object.
360
3298.2.4 by John Arbash Meinel
Introduce as_revision_id() as a function instead of in_branch(need_revno=False)
361
    def test_as_revision_id(self):
362
        self.assertAsRevisionId('r1', 'revid:r1')
363
        self.assertAsRevisionId('r2', 'revid:r2')
364
        self.assertAsRevisionId('alt_r2', 'revid:alt_r2')
365
1948.4.9 by John Arbash Meinel
Cleanup and test last:
366
367
class TestRevisionSpec_last(TestRevisionSpec):
368
369
    def test_positive(self):
370
        self.assertInHistoryIs(2, 'r2', 'last:1')
371
        self.assertInHistoryIs(1, 'r1', 'last:2')
2598.5.10 by Aaron Bentley
Return NULL_REVISION instead of None for the null revision
372
        self.assertInHistoryIs(0, 'null:', 'last:3')
1948.4.9 by John Arbash Meinel
Cleanup and test last:
373
374
    def test_empty(self):
375
        self.assertInHistoryIs(2, 'r2', 'last:')
376
377
    def test_negative(self):
378
        self.assertInvalid('last:-1',
1948.4.15 by John Arbash Meinel
Change the InvalidRevisionSpec formatting to be more readable
379
                           extra='\nyou must supply a positive value')
1948.4.9 by John Arbash Meinel
Cleanup and test last:
380
381
    def test_missing(self):
382
        self.assertInvalid('last:4')
383
384
    def test_no_history(self):
385
        tree = self.make_branch_and_tree('tree3')
386
387
        self.assertRaises(errors.NoCommits,
1948.4.33 by John Arbash Meinel
Switch from get_revision_spec() to RevisionSpec.from_string() (as advised by Martin)
388
                          spec_in_history, 'last:', tree.branch)
1948.4.9 by John Arbash Meinel
Cleanup and test last:
389
390
    def test_not_a_number(self):
391
        try:
392
            int('Y')
393
        except ValueError, e:
394
            pass
1948.4.15 by John Arbash Meinel
Change the InvalidRevisionSpec formatting to be more readable
395
        self.assertInvalid('last:Y', extra='\n' + str(e))
1948.4.10 by John Arbash Meinel
test the before: spec, currently asserting what seems to be buggy behavior
396
3298.2.4 by John Arbash Meinel
Introduce as_revision_id() as a function instead of in_branch(need_revno=False)
397
    def test_as_revision_id(self):
398
        self.assertAsRevisionId('r2', 'last:1')
399
        self.assertAsRevisionId('r1', 'last:2')
400
1948.4.10 by John Arbash Meinel
test the before: spec, currently asserting what seems to be buggy behavior
401
402
class TestRevisionSpec_before(TestRevisionSpec):
403
404
    def test_int(self):
405
        self.assertInHistoryIs(1, 'r1', 'before:2')
406
        self.assertInHistoryIs(1, 'r1', 'before:-1')
407
408
    def test_before_one(self):
2598.5.10 by Aaron Bentley
Return NULL_REVISION instead of None for the null revision
409
        self.assertInHistoryIs(0, 'null:', 'before:1')
1948.4.10 by John Arbash Meinel
test the before: spec, currently asserting what seems to be buggy behavior
410
411
    def test_before_none(self):
1948.4.13 by John Arbash Meinel
Going before:0 is an error, and if you are on another history, use the leftmost parent
412
        self.assertInvalid('before:0',
1948.4.15 by John Arbash Meinel
Change the InvalidRevisionSpec formatting to be more readable
413
                           extra='\ncannot go before the null: revision')
1948.4.10 by John Arbash Meinel
test the before: spec, currently asserting what seems to be buggy behavior
414
415
    def test_revid(self):
416
        self.assertInHistoryIs(1, 'r1', 'before:revid:r2')
417
418
    def test_last(self):
419
        self.assertInHistoryIs(1, 'r1', 'before:last:1')
420
421
    def test_alt_revid(self):
1948.4.13 by John Arbash Meinel
Going before:0 is an error, and if you are on another history, use the leftmost parent
422
        # This will grab the left-most ancestor for alternate histories
423
        self.assertInHistoryIs(1, 'r1', 'before:revid:alt_r2')
1948.4.11 by John Arbash Meinel
Update and test the tag: spec
424
1948.4.14 by John Arbash Meinel
Test the code path for a no-parent alternate history
425
    def test_alt_no_parents(self):
426
        new_tree = self.make_branch_and_tree('new_tree')
427
        new_tree.commit('first', rev_id='new_r1')
428
        self.tree.branch.repository.fetch(new_tree.branch.repository,
429
                                          revision_id='new_r1')
2598.5.10 by Aaron Bentley
Return NULL_REVISION instead of None for the null revision
430
        self.assertInHistoryIs(0, 'null:', 'before:revid:new_r1')
1948.4.14 by John Arbash Meinel
Test the code path for a no-parent alternate history
431
3298.2.4 by John Arbash Meinel
Introduce as_revision_id() as a function instead of in_branch(need_revno=False)
432
    def test_as_revision_id(self):
433
        self.assertAsRevisionId('r1', 'before:revid:r2')
434
        self.assertAsRevisionId('r1', 'before:2')
435
        self.assertAsRevisionId('r1', 'before:1.1.1')
436
        self.assertAsRevisionId('r1', 'before:revid:alt_r2')
437
1948.4.11 by John Arbash Meinel
Update and test the tag: spec
438
439
class TestRevisionSpec_tag(TestRevisionSpec):
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
440
2220.2.3 by Martin Pool
Add tag: revision namespace.
441
    def make_branch_and_tree(self, relpath):
442
        # override format as the default one may not support tags
3031.3.1 by Robert Collins
Remove the unneeded ExperimentalBranch class.
443
        return TestRevisionSpec.make_branch_and_tree(
444
            self, relpath, format='dirstate-tags')
2220.2.3 by Martin Pool
Add tag: revision namespace.
445
446
    def test_from_string_tag(self):
447
        spec = RevisionSpec.from_string('tag:bzr-0.14')
448
        self.assertIsInstance(spec, RevisionSpec_tag)
449
        self.assertEqual(spec.spec, 'bzr-0.14')
450
451
    def test_lookup_tag(self):
2220.2.20 by Martin Pool
Tag methods now available through Branch.tags.add_tag, etc
452
        self.tree.branch.tags.set_tag('bzr-0.14', 'r1')
2220.2.3 by Martin Pool
Add tag: revision namespace.
453
        self.assertInHistoryIs(1, 'r1', 'tag:bzr-0.14')
3298.2.11 by Aaron Bentley
Update tests for null:, clea up slightly
454
        self.tree.branch.tags.set_tag('null_rev', 'null:')
455
        self.assertInHistoryIs(0, 'null:', 'tag:null_rev')
2220.2.3 by Martin Pool
Add tag: revision namespace.
456
457
    def test_failed_lookup(self):
458
        # tags that don't exist give a specific message: arguably we should
459
        # just give InvalidRevisionSpec but I think this is more helpful
460
        self.assertRaises(errors.NoSuchTag,
461
            self.get_in_history,
462
            'tag:some-random-tag')
1948.4.12 by John Arbash Meinel
Some tests for the date: spec
463
3298.2.4 by John Arbash Meinel
Introduce as_revision_id() as a function instead of in_branch(need_revno=False)
464
    def test_as_revision_id(self):
465
        self.tree.branch.tags.set_tag('my-tag', 'r2')
3298.2.11 by Aaron Bentley
Update tests for null:, clea up slightly
466
        self.tree.branch.tags.set_tag('null_rev', 'null:')
3298.2.4 by John Arbash Meinel
Introduce as_revision_id() as a function instead of in_branch(need_revno=False)
467
        self.assertAsRevisionId('r2', 'tag:my-tag')
3298.2.11 by Aaron Bentley
Update tests for null:, clea up slightly
468
        self.assertAsRevisionId('null:', 'tag:null_rev')
3298.2.4 by John Arbash Meinel
Introduce as_revision_id() as a function instead of in_branch(need_revno=False)
469
        self.assertAsRevisionId('r1', 'before:tag:my-tag')
470
1948.4.12 by John Arbash Meinel
Some tests for the date: spec
471
472
class TestRevisionSpec_date(TestRevisionSpec):
473
474
    def setUp(self):
475
        super(TestRevisionSpec, self).setUp()
476
477
        new_tree = self.make_branch_and_tree('new_tree')
478
        new_tree.commit('Commit one', rev_id='new_r1',
479
                        timestamp=time.time() - 60*60*24)
480
        new_tree.commit('Commit two', rev_id='new_r2')
481
        new_tree.commit('Commit three', rev_id='new_r3')
482
483
        self.tree = new_tree
484
485
    def test_tomorrow(self):
486
        self.assertInvalid('date:tomorrow')
487
488
    def test_today(self):
489
        self.assertInHistoryIs(2, 'new_r2', 'date:today')
490
        self.assertInHistoryIs(1, 'new_r1', 'before:date:today')
491
492
    def test_yesterday(self):
493
        self.assertInHistoryIs(1, 'new_r1', 'date:yesterday')
494
495
    def test_invalid(self):
1948.4.15 by John Arbash Meinel
Change the InvalidRevisionSpec formatting to be more readable
496
        self.assertInvalid('date:foobar', extra='\ninvalid date')
1948.4.12 by John Arbash Meinel
Some tests for the date: spec
497
        # You must have '-' between year/month/day
1948.4.15 by John Arbash Meinel
Change the InvalidRevisionSpec formatting to be more readable
498
        self.assertInvalid('date:20040404', extra='\ninvalid date')
1948.4.12 by John Arbash Meinel
Some tests for the date: spec
499
        # Need 2 digits for each date piece
1948.4.15 by John Arbash Meinel
Change the InvalidRevisionSpec formatting to be more readable
500
        self.assertInvalid('date:2004-4-4', extra='\ninvalid date')
1948.4.12 by John Arbash Meinel
Some tests for the date: spec
501
502
    def test_day(self):
503
        now = datetime.datetime.now()
504
        self.assertInHistoryIs(2, 'new_r2',
505
            'date:%04d-%02d-%02d' % (now.year, now.month, now.day))
1948.4.17 by John Arbash Meinel
Update tests for ancestor: spec
506
3298.2.4 by John Arbash Meinel
Introduce as_revision_id() as a function instead of in_branch(need_revno=False)
507
    def test_as_revision_id(self):
508
        self.assertAsRevisionId('new_r2', 'date:today')
509
1948.4.17 by John Arbash Meinel
Update tests for ancestor: spec
510
511
class TestRevisionSpec_ancestor(TestRevisionSpec):
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
512
1948.4.17 by John Arbash Meinel
Update tests for ancestor: spec
513
    def test_non_exact_branch(self):
514
        # It seems better to require an exact path to the branch
515
        # Branch.open() rather than using Branch.open_containing()
516
        self.assertRaises(errors.NotBranchError,
1948.4.33 by John Arbash Meinel
Switch from get_revision_spec() to RevisionSpec.from_string() (as advised by Martin)
517
                          self.get_in_history, 'ancestor:tree2/a')
1948.4.17 by John Arbash Meinel
Update tests for ancestor: spec
518
519
    def test_simple(self):
520
        # Common ancestor of trees is 'alt_r2'
521
        self.assertInHistoryIs(None, 'alt_r2', 'ancestor:tree2')
522
523
        # Going the other way, we get a valid revno
524
        tmp = self.tree
525
        self.tree = self.tree2
526
        self.tree2 = tmp
527
        self.assertInHistoryIs(2, 'alt_r2', 'ancestor:tree')
528
529
    def test_self(self):
530
        self.assertInHistoryIs(2, 'r2', 'ancestor:tree')
531
532
    def test_unrelated(self):
533
        new_tree = self.make_branch_and_tree('new_tree')
534
535
        new_tree.commit('Commit one', rev_id='new_r1')
536
        new_tree.commit('Commit two', rev_id='new_r2')
537
        new_tree.commit('Commit three', rev_id='new_r3')
538
539
        # With no common ancestor, we should raise another user error
540
        self.assertRaises(errors.NoCommonAncestor,
1948.4.33 by John Arbash Meinel
Switch from get_revision_spec() to RevisionSpec.from_string() (as advised by Martin)
541
                          self.get_in_history, 'ancestor:new_tree')
1948.4.17 by John Arbash Meinel
Update tests for ancestor: spec
542
543
    def test_no_commits(self):
544
        new_tree = self.make_branch_and_tree('new_tree')
545
        self.assertRaises(errors.NoCommits,
1948.4.33 by John Arbash Meinel
Switch from get_revision_spec() to RevisionSpec.from_string() (as advised by Martin)
546
                          spec_in_history, 'ancestor:new_tree',
547
                                           self.tree.branch)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
548
1948.4.17 by John Arbash Meinel
Update tests for ancestor: spec
549
        self.assertRaises(errors.NoCommits,
1948.4.33 by John Arbash Meinel
Switch from get_revision_spec() to RevisionSpec.from_string() (as advised by Martin)
550
                          spec_in_history, 'ancestor:tree',
551
                                           new_tree.branch)
1948.4.18 by John Arbash Meinel
Update branch: spec and tests
552
3298.2.4 by John Arbash Meinel
Introduce as_revision_id() as a function instead of in_branch(need_revno=False)
553
    def test_as_revision_id(self):
554
        self.assertAsRevisionId('alt_r2', 'ancestor:tree2')
555
3984.1.1 by Daniel Watkins
Added test.
556
    def test_default(self):
557
        # We don't have a parent to default to
558
        self.assertRaises(errors.NotBranchError, self.get_in_history,
559
                          'ancestor:')
560
561
        # Create a branch with a parent to default to
562
        tree3 = self.tree.bzrdir.sprout('tree3').open_workingtree()
563
        tree3.commit('foo', rev_id='r3')
564
        self.tree = tree3
565
        self.assertInHistoryIs(2, 'r2', 'ancestor:')
566
1948.4.18 by John Arbash Meinel
Update branch: spec and tests
567
568
class TestRevisionSpec_branch(TestRevisionSpec):
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
569
1948.4.18 by John Arbash Meinel
Update branch: spec and tests
570
    def test_non_exact_branch(self):
571
        # It seems better to require an exact path to the branch
572
        # Branch.open() rather than using Branch.open_containing()
573
        self.assertRaises(errors.NotBranchError,
1948.4.33 by John Arbash Meinel
Switch from get_revision_spec() to RevisionSpec.from_string() (as advised by Martin)
574
                          self.get_in_history, 'branch:tree2/a')
1948.4.18 by John Arbash Meinel
Update branch: spec and tests
575
576
    def test_simple(self):
577
        self.assertInHistoryIs(None, 'alt_r2', 'branch:tree2')
578
579
    def test_self(self):
580
        self.assertInHistoryIs(2, 'r2', 'branch:tree')
581
582
    def test_unrelated(self):
583
        new_tree = self.make_branch_and_tree('new_tree')
584
585
        new_tree.commit('Commit one', rev_id='new_r1')
586
        new_tree.commit('Commit two', rev_id='new_r2')
587
        new_tree.commit('Commit three', rev_id='new_r3')
588
589
        self.assertInHistoryIs(None, 'new_r3', 'branch:new_tree')
590
591
        # XXX: Right now, we use fetch() to make sure the remote revisions
592
        # have been pulled into the local branch. We may change that
593
        # behavior in the future.
594
        self.failUnless(self.tree.branch.repository.has_revision('new_r3'))
595
596
    def test_no_commits(self):
597
        new_tree = self.make_branch_and_tree('new_tree')
598
        self.assertRaises(errors.NoCommits,
1948.4.33 by John Arbash Meinel
Switch from get_revision_spec() to RevisionSpec.from_string() (as advised by Martin)
599
                          self.get_in_history, 'branch:new_tree')
3655.3.1 by Lukáš Lalinský
Fix `bzr st -rbranch:PATH_TO_BRANCH`
600
        self.assertRaises(errors.NoCommits,
601
                          self.get_as_tree, 'branch:new_tree')
1551.10.32 by Aaron Bentley
Add submit: specifier, for merge-directive-like diffs
602
3298.2.4 by John Arbash Meinel
Introduce as_revision_id() as a function instead of in_branch(need_revno=False)
603
    def test_as_revision_id(self):
604
        self.assertAsRevisionId('alt_r2', 'branch:tree2')
605
3655.3.1 by Lukáš Lalinský
Fix `bzr st -rbranch:PATH_TO_BRANCH`
606
    def test_as_tree(self):
607
        tree = self.get_as_tree('branch:tree', self.tree2)
608
        self.assertEquals('r2', tree.get_revision_id())
609
        self.assertFalse(self.tree2.branch.repository.has_revision('r2'))
610
1551.10.32 by Aaron Bentley
Add submit: specifier, for merge-directive-like diffs
611
612
class TestRevisionSpec_submit(TestRevisionSpec):
613
614
    def test_submit_branch(self):
615
        # Common ancestor of trees is 'alt_r2'
616
        self.assertRaises(errors.NoSubmitBranch, self.get_in_history,
617
                          'submit:')
618
        self.tree.branch.set_parent('../tree2')
619
        self.assertInHistoryIs(None, 'alt_r2', 'submit:')
620
        self.tree.branch.set_parent('bogus')
621
        self.assertRaises(errors.NotBranchError, self.get_in_history,
622
            'submit:')
623
        # submit branch overrides parent branch
624
        self.tree.branch.set_submit_branch('tree2')
625
        self.assertInHistoryIs(None, 'alt_r2', 'submit:')
3298.2.3 by John Arbash Meinel
Add tests that all RevisionSpecs implement in_branch(b, needs_revno)
626
3298.2.4 by John Arbash Meinel
Introduce as_revision_id() as a function instead of in_branch(need_revno=False)
627
    def test_as_revision_id(self):
628
        self.tree.branch.set_submit_branch('tree2')
629
        self.assertAsRevisionId('alt_r2', 'branch:tree2')