~bzr-pqm/bzr/bzr.dev

4763.2.4 by John Arbash Meinel
merge bzr.2.1 in preparation for NEWS entry.
1
# Copyright (C) 2005-2010 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.32 by John Arbash Meinel
Clean up __repr__, as well as add tests that we can handle -r12:branch/
149
4569.2.2 by Matthew Fuller
Add tests for DWIM revspecs.
150
class TestRevisionSpec_dwim(TestRevisionSpec):
151
152
    # Don't need to test revno's explicitly since TRS_revno already
153
    # covers that well for us
4569.2.11 by Matthew Fuller
Eliminate the TestRevnoFromString() test class by moving all its tests
154
    def test_dwim_spec_revno(self):
155
        self.assertInHistoryIs(2, 'r2', '2')
156
        self.assertAsRevisionId('alt_r2', '1.1.1')
4569.2.2 by Matthew Fuller
Add tests for DWIM revspecs.
157
158
    def test_dwim_spec_revid(self):
159
        self.assertInHistoryIs(2, 'r2', 'r2')
160
161
    def test_dwim_spec_tag(self):
162
        self.tree.branch.tags.set_tag('footag', 'r1')
163
        self.assertAsRevisionId('r1', 'footag')
164
        self.tree.branch.tags.delete_tag('footag')
165
        self.assertRaises(errors.InvalidRevisionSpec,
166
                          self.get_in_history, 'footag')
167
4569.2.16 by Matthew Fuller
Add a test that we slip past the revno-checking stage when we're
168
    def test_dwim_spec_tag_that_looks_like_revno(self):
169
        # Test that we slip past revno with things that look like revnos,
170
        # but aren't.  Tags are convenient for testing this since we can
171
        # make them look however we want.
172
        self.tree.branch.tags.set_tag('3', 'r2')
173
        self.assertAsRevisionId('r2', '3')
174
        self.build_tree(['tree/b'])
175
        self.tree.add(['b'])
176
        self.tree.commit('b', rev_id='r3')
177
        self.assertAsRevisionId('r3', '3')
178
4569.2.4 by Matthew Fuller
Add date: to the list of things DWIM auto-tries.
179
    def test_dwim_spec_date(self):
180
        self.assertAsRevisionId('r1', 'today')
181
4569.2.2 by Matthew Fuller
Add tests for DWIM revspecs.
182
    def test_dwim_spec_branch(self):
183
        self.assertInHistoryIs(None, 'alt_r2', 'tree2')
184
185
    def test_dwim_spec_nonexistent(self):
4569.2.8 by Matthew Fuller
Use a more precise nonexistent thing in test_dwim_spec_nonexistent().
186
        self.assertInvalid('somethingrandom', invalid_as_revision_id=False)
4569.2.11 by Matthew Fuller
Eliminate the TestRevnoFromString() test class by moving all its tests
187
        self.assertInvalid('-1.1', invalid_as_revision_id=False)
188
        self.assertInvalid('.1', invalid_as_revision_id=False)
189
        self.assertInvalid('1..1', invalid_as_revision_id=False)
190
        self.assertInvalid('1.2..1', invalid_as_revision_id=False)
191
        self.assertInvalid('1.', invalid_as_revision_id=False)
1988.4.5 by Robert Collins
revisions can now be specified using dotted-decimal revision numbers.
192
193
1948.4.32 by John Arbash Meinel
Clean up __repr__, as well as add tests that we can handle -r12:branch/
194
class TestRevisionSpec_revno(TestRevisionSpec):
195
196
    def test_positive_int(self):
2598.5.10 by Aaron Bentley
Return NULL_REVISION instead of None for the null revision
197
        self.assertInHistoryIs(0, 'null:', '0')
1948.4.3 by John Arbash Meinel
Create direct tests for RevisionSpec_int
198
        self.assertInHistoryIs(1, 'r1', '1')
199
        self.assertInHistoryIs(2, 'r2', '2')
1948.4.23 by John Arbash Meinel
Change the handling of negative numbers, to be trapped at revno 1
200
        self.assertInvalid('3')
1948.4.3 by John Arbash Meinel
Create direct tests for RevisionSpec_int
201
1988.4.5 by Robert Collins
revisions can now be specified using dotted-decimal revision numbers.
202
    def test_dotted_decimal(self):
203
        self.assertInHistoryIs(None, 'alt_r2', '1.1.1')
3878.3.1 by Marius Kruger
Test invalid dotted revion number directly in TestRevisionSpec_revno
204
        self.assertInvalid('1.1.123')
1988.4.5 by Robert Collins
revisions can now be specified using dotted-decimal revision numbers.
205
1948.4.32 by John Arbash Meinel
Clean up __repr__, as well as add tests that we can handle -r12:branch/
206
    def test_negative_int(self):
1948.4.3 by John Arbash Meinel
Create direct tests for RevisionSpec_int
207
        self.assertInHistoryIs(2, 'r2', '-1')
208
        self.assertInHistoryIs(1, 'r1', '-2')
209
1948.4.23 by John Arbash Meinel
Change the handling of negative numbers, to be trapped at revno 1
210
        self.assertInHistoryIs(1, 'r1', '-3')
211
        self.assertInHistoryIs(1, 'r1', '-4')
212
        self.assertInHistoryIs(1, 'r1', '-100')
1948.4.5 by John Arbash Meinel
Fix tests for negative entries, and add tests for revno:
213
214
    def test_positive(self):
2598.5.10 by Aaron Bentley
Return NULL_REVISION instead of None for the null revision
215
        self.assertInHistoryIs(0, 'null:', 'revno:0')
1948.4.5 by John Arbash Meinel
Fix tests for negative entries, and add tests for revno:
216
        self.assertInHistoryIs(1, 'r1', 'revno:1')
217
        self.assertInHistoryIs(2, 'r2', 'revno:2')
218
219
        self.assertInvalid('revno:3')
220
221
    def test_negative(self):
222
        self.assertInHistoryIs(2, 'r2', 'revno:-1')
223
        self.assertInHistoryIs(1, 'r1', 'revno:-2')
224
1948.4.23 by John Arbash Meinel
Change the handling of negative numbers, to be trapped at revno 1
225
        self.assertInHistoryIs(1, 'r1', 'revno:-3')
226
        self.assertInHistoryIs(1, 'r1', 'revno:-4')
1948.4.6 by John Arbash Meinel
A small bugfix, and more tests for revno:
227
228
    def test_invalid_number(self):
229
        # Get the right exception text
230
        try:
231
            int('X')
232
        except ValueError, e:
233
            pass
1948.4.15 by John Arbash Meinel
Change the InvalidRevisionSpec formatting to be more readable
234
        self.assertInvalid('revno:X', extra='\n' + str(e))
1948.4.6 by John Arbash Meinel
A small bugfix, and more tests for revno:
235
236
    def test_missing_number_and_branch(self):
237
        self.assertInvalid('revno::',
1948.4.15 by John Arbash Meinel
Change the InvalidRevisionSpec formatting to be more readable
238
                           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
239
240
    def test_invalid_number_with_branch(self):
241
        try:
242
            int('X')
243
        except ValueError, e:
244
            pass
1948.4.15 by John Arbash Meinel
Change the InvalidRevisionSpec formatting to be more readable
245
        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
246
1948.4.16 by John Arbash Meinel
Move the tests into the associated tester, remove redundant tests, some small PEP8 changes
247
    def test_non_exact_branch(self):
248
        # It seems better to require an exact path to the branch
249
        # Branch.open() rather than using Branch.open_containing()
1948.4.33 by John Arbash Meinel
Switch from get_revision_spec() to RevisionSpec.from_string() (as advised by Martin)
250
        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
251
        self.assertRaises(errors.NotBranchError,
1948.4.33 by John Arbash Meinel
Switch from get_revision_spec() to RevisionSpec.from_string() (as advised by Martin)
252
                          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
253
1948.4.7 by John Arbash Meinel
More revno: tests, now testing the branch/url parameter
254
    def test_with_branch(self):
255
        # Passing a URL overrides the supplied branch path
256
        revinfo = self.get_in_history('revno:2:tree2')
257
        self.assertNotEqual(self.tree.branch.base, revinfo.branch.base)
258
        self.assertEqual(self.tree2.branch.base, revinfo.branch.base)
259
        self.assertEqual(2, revinfo.revno)
260
        self.assertEqual('alt_r2', revinfo.rev_id)
261
1948.4.32 by John Arbash Meinel
Clean up __repr__, as well as add tests that we can handle -r12:branch/
262
    def test_int_with_branch(self):
263
        revinfo = self.get_in_history('2:tree2')
264
        self.assertNotEqual(self.tree.branch.base, revinfo.branch.base)
265
        self.assertEqual(self.tree2.branch.base, revinfo.branch.base)
266
        self.assertEqual(2, revinfo.revno)
267
        self.assertEqual('alt_r2', revinfo.rev_id)
268
1948.4.7 by John Arbash Meinel
More revno: tests, now testing the branch/url parameter
269
    def test_with_url(self):
270
        url = self.get_url() + '/tree2'
271
        revinfo = self.get_in_history('revno:2:%s' % (url,))
272
        self.assertNotEqual(self.tree.branch.base, revinfo.branch.base)
273
        self.assertEqual(self.tree2.branch.base, revinfo.branch.base)
274
        self.assertEqual(2, revinfo.revno)
275
        self.assertEqual('alt_r2', revinfo.rev_id)
276
277
    def test_negative_with_url(self):
278
        url = self.get_url() + '/tree2'
279
        revinfo = self.get_in_history('revno:-1:%s' % (url,))
280
        self.assertNotEqual(self.tree.branch.base, revinfo.branch.base)
281
        self.assertEqual(self.tree2.branch.base, revinfo.branch.base)
282
        self.assertEqual(2, revinfo.revno)
283
        self.assertEqual('alt_r2', revinfo.rev_id)
284
1948.4.22 by John Arbash Meinel
Refactor common code from integer revno handlers
285
    def test_different_history_lengths(self):
286
        # Make sure we use the revisions and offsets in the supplied branch
287
        # not the ones in the original branch.
288
        self.tree2.commit('three', rev_id='r3')
289
        self.assertInHistoryIs(3, 'r3', 'revno:3:tree2')
290
        self.assertInHistoryIs(3, 'r3', 'revno:-1:tree2')
291
1948.4.7 by John Arbash Meinel
More revno: tests, now testing the branch/url parameter
292
    def test_invalid_branch(self):
293
        self.assertRaises(errors.NotBranchError,
294
                          self.get_in_history, 'revno:-1:tree3')
295
296
    def test_invalid_revno_in_branch(self):
297
        self.tree.commit('three', rev_id='r3')
298
        self.assertInvalid('revno:3:tree2')
1948.4.8 by John Arbash Meinel
Testing the revid: spec
299
1948.4.16 by John Arbash Meinel
Move the tests into the associated tester, remove redundant tests, some small PEP8 changes
300
    def test_revno_n_path(self):
301
        """Old revno:N:path tests"""
302
        wta = self.make_branch_and_tree('a')
303
        ba = wta.branch
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
304
1948.4.16 by John Arbash Meinel
Move the tests into the associated tester, remove redundant tests, some small PEP8 changes
305
        wta.commit('Commit one', rev_id='a@r-0-1')
306
        wta.commit('Commit two', rev_id='a@r-0-2')
307
        wta.commit('Commit three', rev_id='a@r-0-3')
308
309
        wtb = self.make_branch_and_tree('b')
310
        bb = wtb.branch
311
312
        wtb.commit('Commit one', rev_id='b@r-0-1')
313
        wtb.commit('Commit two', rev_id='b@r-0-2')
314
        wtb.commit('Commit three', rev_id='b@r-0-3')
315
1948.4.33 by John Arbash Meinel
Switch from get_revision_spec() to RevisionSpec.from_string() (as advised by Martin)
316
317
        self.assertEqual((1, 'a@r-0-1'),
318
                         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
319
        # The argument of in_history should be ignored since it is
320
        # 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)
321
        self.assertEqual((1, 'a@r-0-1'),
322
                         spec_in_history('revno:1:a/', None))
323
        self.assertEqual((1, 'a@r-0-1'),
324
                         spec_in_history('revno:1:a/', bb))
325
        self.assertEqual((2, 'b@r-0-2'),
326
                         spec_in_history('revno:2:b/', None))
1948.4.16 by John Arbash Meinel
Move the tests into the associated tester, remove redundant tests, some small PEP8 changes
327
3298.2.4 by John Arbash Meinel
Introduce as_revision_id() as a function instead of in_branch(need_revno=False)
328
    def test_as_revision_id(self):
3298.2.11 by Aaron Bentley
Update tests for null:, clea up slightly
329
        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)
330
        self.assertAsRevisionId('r1', '1')
331
        self.assertAsRevisionId('r2', '2')
332
        self.assertAsRevisionId('r1', '-2')
333
        self.assertAsRevisionId('r2', '-1')
334
        self.assertAsRevisionId('alt_r2', '1.1.1')
335
3655.3.1 by Lukáš Lalinský
Fix `bzr st -rbranch:PATH_TO_BRANCH`
336
    def test_as_tree(self):
337
        tree = self.get_as_tree('0')
338
        self.assertEquals(_mod_revision.NULL_REVISION, tree.get_revision_id())
339
        tree = self.get_as_tree('1')
340
        self.assertEquals('r1', tree.get_revision_id())
341
        tree = self.get_as_tree('2')
342
        self.assertEquals('r2', tree.get_revision_id())
343
        tree = self.get_as_tree('-2')
344
        self.assertEquals('r1', tree.get_revision_id())
345
        tree = self.get_as_tree('-1')
346
        self.assertEquals('r2', tree.get_revision_id())
347
        tree = self.get_as_tree('1.1.1')
348
        self.assertEquals('alt_r2', tree.get_revision_id())
349
1948.4.8 by John Arbash Meinel
Testing the revid: spec
350
351
class TestRevisionSpec_revid(TestRevisionSpec):
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
352
1948.4.8 by John Arbash Meinel
Testing the revid: spec
353
    def test_in_history(self):
354
        # We should be able to access revisions that are directly
355
        # in the history.
356
        self.assertInHistoryIs(1, 'r1', 'revid:r1')
357
        self.assertInHistoryIs(2, 'r2', 'revid:r2')
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
358
1948.4.8 by John Arbash Meinel
Testing the revid: spec
359
    def test_missing(self):
3495.1.1 by John Arbash Meinel
Fix bug #239933, use the right exception for -c0
360
        self.assertInvalid('revid:r3', invalid_as_revision_id=False)
1948.4.8 by John Arbash Meinel
Testing the revid: spec
361
362
    def test_merged(self):
363
        """We can reach revisions in the ancestry"""
364
        self.assertInHistoryIs(None, 'alt_r2', 'revid:alt_r2')
365
366
    def test_not_here(self):
367
        self.tree2.commit('alt third', rev_id='alt_r3')
368
        # It exists in tree2, but not in tree
3495.1.1 by John Arbash Meinel
Fix bug #239933, use the right exception for -c0
369
        self.assertInvalid('revid:alt_r3', invalid_as_revision_id=False)
1948.4.8 by John Arbash Meinel
Testing the revid: spec
370
371
    def test_in_repository(self):
372
        """We can get any revision id in the repository"""
373
        # XXX: This may change in the future, but for now, it is true
374
        self.tree2.commit('alt third', rev_id='alt_r3')
375
        self.tree.branch.repository.fetch(self.tree2.branch.repository,
376
                                          revision_id='alt_r3')
377
        self.assertInHistoryIs(None, 'alt_r3', 'revid:alt_r3')
1948.4.9 by John Arbash Meinel
Cleanup and test last:
378
2325.2.2 by Marien Zwart
Make the revid RevisionSpec always return a str object, not a unicode object.
379
    def test_unicode(self):
380
        """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.
381
        revision_id = u'\N{SNOWMAN}'.encode('utf-8')
382
        self.tree.commit('unicode', rev_id=revision_id)
383
        self.assertInHistoryIs(3, revision_id, u'revid:\N{SNOWMAN}')
384
        self.assertInHistoryIs(3, revision_id, 'revid:' + revision_id)
2325.2.2 by Marien Zwart
Make the revid RevisionSpec always return a str object, not a unicode object.
385
3298.2.4 by John Arbash Meinel
Introduce as_revision_id() as a function instead of in_branch(need_revno=False)
386
    def test_as_revision_id(self):
387
        self.assertAsRevisionId('r1', 'revid:r1')
388
        self.assertAsRevisionId('r2', 'revid:r2')
389
        self.assertAsRevisionId('alt_r2', 'revid:alt_r2')
390
1948.4.9 by John Arbash Meinel
Cleanup and test last:
391
392
class TestRevisionSpec_last(TestRevisionSpec):
393
394
    def test_positive(self):
395
        self.assertInHistoryIs(2, 'r2', 'last:1')
396
        self.assertInHistoryIs(1, 'r1', 'last:2')
2598.5.10 by Aaron Bentley
Return NULL_REVISION instead of None for the null revision
397
        self.assertInHistoryIs(0, 'null:', 'last:3')
1948.4.9 by John Arbash Meinel
Cleanup and test last:
398
399
    def test_empty(self):
400
        self.assertInHistoryIs(2, 'r2', 'last:')
401
402
    def test_negative(self):
403
        self.assertInvalid('last:-1',
1948.4.15 by John Arbash Meinel
Change the InvalidRevisionSpec formatting to be more readable
404
                           extra='\nyou must supply a positive value')
1948.4.9 by John Arbash Meinel
Cleanup and test last:
405
406
    def test_missing(self):
407
        self.assertInvalid('last:4')
408
409
    def test_no_history(self):
410
        tree = self.make_branch_and_tree('tree3')
411
412
        self.assertRaises(errors.NoCommits,
1948.4.33 by John Arbash Meinel
Switch from get_revision_spec() to RevisionSpec.from_string() (as advised by Martin)
413
                          spec_in_history, 'last:', tree.branch)
1948.4.9 by John Arbash Meinel
Cleanup and test last:
414
415
    def test_not_a_number(self):
416
        try:
417
            int('Y')
418
        except ValueError, e:
419
            pass
1948.4.15 by John Arbash Meinel
Change the InvalidRevisionSpec formatting to be more readable
420
        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
421
3298.2.4 by John Arbash Meinel
Introduce as_revision_id() as a function instead of in_branch(need_revno=False)
422
    def test_as_revision_id(self):
423
        self.assertAsRevisionId('r2', 'last:1')
424
        self.assertAsRevisionId('r1', 'last:2')
425
1948.4.10 by John Arbash Meinel
test the before: spec, currently asserting what seems to be buggy behavior
426
427
class TestRevisionSpec_before(TestRevisionSpec):
428
429
    def test_int(self):
430
        self.assertInHistoryIs(1, 'r1', 'before:2')
431
        self.assertInHistoryIs(1, 'r1', 'before:-1')
432
433
    def test_before_one(self):
2598.5.10 by Aaron Bentley
Return NULL_REVISION instead of None for the null revision
434
        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
435
436
    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
437
        self.assertInvalid('before:0',
1948.4.15 by John Arbash Meinel
Change the InvalidRevisionSpec formatting to be more readable
438
                           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
439
440
    def test_revid(self):
441
        self.assertInHistoryIs(1, 'r1', 'before:revid:r2')
442
443
    def test_last(self):
444
        self.assertInHistoryIs(1, 'r1', 'before:last:1')
445
446
    def test_alt_revid(self):
1948.4.13 by John Arbash Meinel
Going before:0 is an error, and if you are on another history, use the leftmost parent
447
        # This will grab the left-most ancestor for alternate histories
448
        self.assertInHistoryIs(1, 'r1', 'before:revid:alt_r2')
1948.4.11 by John Arbash Meinel
Update and test the tag: spec
449
1948.4.14 by John Arbash Meinel
Test the code path for a no-parent alternate history
450
    def test_alt_no_parents(self):
451
        new_tree = self.make_branch_and_tree('new_tree')
452
        new_tree.commit('first', rev_id='new_r1')
453
        self.tree.branch.repository.fetch(new_tree.branch.repository,
454
                                          revision_id='new_r1')
2598.5.10 by Aaron Bentley
Return NULL_REVISION instead of None for the null revision
455
        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
456
3298.2.4 by John Arbash Meinel
Introduce as_revision_id() as a function instead of in_branch(need_revno=False)
457
    def test_as_revision_id(self):
458
        self.assertAsRevisionId('r1', 'before:revid:r2')
459
        self.assertAsRevisionId('r1', 'before:2')
460
        self.assertAsRevisionId('r1', 'before:1.1.1')
461
        self.assertAsRevisionId('r1', 'before:revid:alt_r2')
462
1948.4.11 by John Arbash Meinel
Update and test the tag: spec
463
464
class TestRevisionSpec_tag(TestRevisionSpec):
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
465
2220.2.3 by Martin Pool
Add tag: revision namespace.
466
    def make_branch_and_tree(self, relpath):
467
        # override format as the default one may not support tags
3031.3.1 by Robert Collins
Remove the unneeded ExperimentalBranch class.
468
        return TestRevisionSpec.make_branch_and_tree(
469
            self, relpath, format='dirstate-tags')
2220.2.3 by Martin Pool
Add tag: revision namespace.
470
471
    def test_from_string_tag(self):
472
        spec = RevisionSpec.from_string('tag:bzr-0.14')
473
        self.assertIsInstance(spec, RevisionSpec_tag)
474
        self.assertEqual(spec.spec, 'bzr-0.14')
475
476
    def test_lookup_tag(self):
2220.2.20 by Martin Pool
Tag methods now available through Branch.tags.add_tag, etc
477
        self.tree.branch.tags.set_tag('bzr-0.14', 'r1')
2220.2.3 by Martin Pool
Add tag: revision namespace.
478
        self.assertInHistoryIs(1, 'r1', 'tag:bzr-0.14')
3298.2.11 by Aaron Bentley
Update tests for null:, clea up slightly
479
        self.tree.branch.tags.set_tag('null_rev', 'null:')
480
        self.assertInHistoryIs(0, 'null:', 'tag:null_rev')
2220.2.3 by Martin Pool
Add tag: revision namespace.
481
482
    def test_failed_lookup(self):
483
        # tags that don't exist give a specific message: arguably we should
484
        # just give InvalidRevisionSpec but I think this is more helpful
485
        self.assertRaises(errors.NoSuchTag,
486
            self.get_in_history,
487
            'tag:some-random-tag')
1948.4.12 by John Arbash Meinel
Some tests for the date: spec
488
3298.2.4 by John Arbash Meinel
Introduce as_revision_id() as a function instead of in_branch(need_revno=False)
489
    def test_as_revision_id(self):
490
        self.tree.branch.tags.set_tag('my-tag', 'r2')
3298.2.11 by Aaron Bentley
Update tests for null:, clea up slightly
491
        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)
492
        self.assertAsRevisionId('r2', 'tag:my-tag')
3298.2.11 by Aaron Bentley
Update tests for null:, clea up slightly
493
        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)
494
        self.assertAsRevisionId('r1', 'before:tag:my-tag')
495
1948.4.12 by John Arbash Meinel
Some tests for the date: spec
496
497
class TestRevisionSpec_date(TestRevisionSpec):
498
499
    def setUp(self):
500
        super(TestRevisionSpec, self).setUp()
501
502
        new_tree = self.make_branch_and_tree('new_tree')
503
        new_tree.commit('Commit one', rev_id='new_r1',
504
                        timestamp=time.time() - 60*60*24)
505
        new_tree.commit('Commit two', rev_id='new_r2')
506
        new_tree.commit('Commit three', rev_id='new_r3')
507
508
        self.tree = new_tree
509
510
    def test_tomorrow(self):
511
        self.assertInvalid('date:tomorrow')
512
513
    def test_today(self):
514
        self.assertInHistoryIs(2, 'new_r2', 'date:today')
515
        self.assertInHistoryIs(1, 'new_r1', 'before:date:today')
516
517
    def test_yesterday(self):
518
        self.assertInHistoryIs(1, 'new_r1', 'date:yesterday')
519
520
    def test_invalid(self):
1948.4.15 by John Arbash Meinel
Change the InvalidRevisionSpec formatting to be more readable
521
        self.assertInvalid('date:foobar', extra='\ninvalid date')
1948.4.12 by John Arbash Meinel
Some tests for the date: spec
522
        # You must have '-' between year/month/day
1948.4.15 by John Arbash Meinel
Change the InvalidRevisionSpec formatting to be more readable
523
        self.assertInvalid('date:20040404', extra='\ninvalid date')
1948.4.12 by John Arbash Meinel
Some tests for the date: spec
524
        # Need 2 digits for each date piece
1948.4.15 by John Arbash Meinel
Change the InvalidRevisionSpec formatting to be more readable
525
        self.assertInvalid('date:2004-4-4', extra='\ninvalid date')
1948.4.12 by John Arbash Meinel
Some tests for the date: spec
526
527
    def test_day(self):
528
        now = datetime.datetime.now()
529
        self.assertInHistoryIs(2, 'new_r2',
530
            'date:%04d-%02d-%02d' % (now.year, now.month, now.day))
1948.4.17 by John Arbash Meinel
Update tests for ancestor: spec
531
3298.2.4 by John Arbash Meinel
Introduce as_revision_id() as a function instead of in_branch(need_revno=False)
532
    def test_as_revision_id(self):
533
        self.assertAsRevisionId('new_r2', 'date:today')
534
1948.4.17 by John Arbash Meinel
Update tests for ancestor: spec
535
536
class TestRevisionSpec_ancestor(TestRevisionSpec):
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
537
1948.4.17 by John Arbash Meinel
Update tests for ancestor: spec
538
    def test_non_exact_branch(self):
539
        # It seems better to require an exact path to the branch
540
        # Branch.open() rather than using Branch.open_containing()
541
        self.assertRaises(errors.NotBranchError,
1948.4.33 by John Arbash Meinel
Switch from get_revision_spec() to RevisionSpec.from_string() (as advised by Martin)
542
                          self.get_in_history, 'ancestor:tree2/a')
1948.4.17 by John Arbash Meinel
Update tests for ancestor: spec
543
544
    def test_simple(self):
545
        # Common ancestor of trees is 'alt_r2'
546
        self.assertInHistoryIs(None, 'alt_r2', 'ancestor:tree2')
547
548
        # Going the other way, we get a valid revno
549
        tmp = self.tree
550
        self.tree = self.tree2
551
        self.tree2 = tmp
552
        self.assertInHistoryIs(2, 'alt_r2', 'ancestor:tree')
553
554
    def test_self(self):
555
        self.assertInHistoryIs(2, 'r2', 'ancestor:tree')
556
557
    def test_unrelated(self):
558
        new_tree = self.make_branch_and_tree('new_tree')
559
560
        new_tree.commit('Commit one', rev_id='new_r1')
561
        new_tree.commit('Commit two', rev_id='new_r2')
562
        new_tree.commit('Commit three', rev_id='new_r3')
563
564
        # With no common ancestor, we should raise another user error
565
        self.assertRaises(errors.NoCommonAncestor,
1948.4.33 by John Arbash Meinel
Switch from get_revision_spec() to RevisionSpec.from_string() (as advised by Martin)
566
                          self.get_in_history, 'ancestor:new_tree')
1948.4.17 by John Arbash Meinel
Update tests for ancestor: spec
567
568
    def test_no_commits(self):
569
        new_tree = self.make_branch_and_tree('new_tree')
570
        self.assertRaises(errors.NoCommits,
1948.4.33 by John Arbash Meinel
Switch from get_revision_spec() to RevisionSpec.from_string() (as advised by Martin)
571
                          spec_in_history, 'ancestor:new_tree',
572
                                           self.tree.branch)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
573
1948.4.17 by John Arbash Meinel
Update tests for ancestor: spec
574
        self.assertRaises(errors.NoCommits,
1948.4.33 by John Arbash Meinel
Switch from get_revision_spec() to RevisionSpec.from_string() (as advised by Martin)
575
                          spec_in_history, 'ancestor:tree',
576
                                           new_tree.branch)
1948.4.18 by John Arbash Meinel
Update branch: spec and tests
577
3298.2.4 by John Arbash Meinel
Introduce as_revision_id() as a function instead of in_branch(need_revno=False)
578
    def test_as_revision_id(self):
579
        self.assertAsRevisionId('alt_r2', 'ancestor:tree2')
580
3984.1.1 by Daniel Watkins
Added test.
581
    def test_default(self):
582
        # We don't have a parent to default to
583
        self.assertRaises(errors.NotBranchError, self.get_in_history,
584
                          'ancestor:')
585
586
        # Create a branch with a parent to default to
587
        tree3 = self.tree.bzrdir.sprout('tree3').open_workingtree()
588
        tree3.commit('foo', rev_id='r3')
589
        self.tree = tree3
590
        self.assertInHistoryIs(2, 'r2', 'ancestor:')
591
1948.4.18 by John Arbash Meinel
Update branch: spec and tests
592
593
class TestRevisionSpec_branch(TestRevisionSpec):
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
594
1948.4.18 by John Arbash Meinel
Update branch: spec and tests
595
    def test_non_exact_branch(self):
596
        # It seems better to require an exact path to the branch
597
        # Branch.open() rather than using Branch.open_containing()
598
        self.assertRaises(errors.NotBranchError,
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:tree2/a')
1948.4.18 by John Arbash Meinel
Update branch: spec and tests
600
601
    def test_simple(self):
602
        self.assertInHistoryIs(None, 'alt_r2', 'branch:tree2')
603
604
    def test_self(self):
605
        self.assertInHistoryIs(2, 'r2', 'branch:tree')
606
607
    def test_unrelated(self):
608
        new_tree = self.make_branch_and_tree('new_tree')
609
610
        new_tree.commit('Commit one', rev_id='new_r1')
611
        new_tree.commit('Commit two', rev_id='new_r2')
612
        new_tree.commit('Commit three', rev_id='new_r3')
613
614
        self.assertInHistoryIs(None, 'new_r3', 'branch:new_tree')
615
616
        # XXX: Right now, we use fetch() to make sure the remote revisions
617
        # have been pulled into the local branch. We may change that
618
        # behavior in the future.
619
        self.failUnless(self.tree.branch.repository.has_revision('new_r3'))
620
621
    def test_no_commits(self):
622
        new_tree = self.make_branch_and_tree('new_tree')
623
        self.assertRaises(errors.NoCommits,
1948.4.33 by John Arbash Meinel
Switch from get_revision_spec() to RevisionSpec.from_string() (as advised by Martin)
624
                          self.get_in_history, 'branch:new_tree')
3655.3.1 by Lukáš Lalinský
Fix `bzr st -rbranch:PATH_TO_BRANCH`
625
        self.assertRaises(errors.NoCommits,
626
                          self.get_as_tree, 'branch:new_tree')
1551.10.32 by Aaron Bentley
Add submit: specifier, for merge-directive-like diffs
627
3298.2.4 by John Arbash Meinel
Introduce as_revision_id() as a function instead of in_branch(need_revno=False)
628
    def test_as_revision_id(self):
629
        self.assertAsRevisionId('alt_r2', 'branch:tree2')
630
3655.3.1 by Lukáš Lalinský
Fix `bzr st -rbranch:PATH_TO_BRANCH`
631
    def test_as_tree(self):
632
        tree = self.get_as_tree('branch:tree', self.tree2)
633
        self.assertEquals('r2', tree.get_revision_id())
634
        self.assertFalse(self.tree2.branch.repository.has_revision('r2'))
635
1551.10.32 by Aaron Bentley
Add submit: specifier, for merge-directive-like diffs
636
637
class TestRevisionSpec_submit(TestRevisionSpec):
638
639
    def test_submit_branch(self):
640
        # Common ancestor of trees is 'alt_r2'
641
        self.assertRaises(errors.NoSubmitBranch, self.get_in_history,
642
                          'submit:')
643
        self.tree.branch.set_parent('../tree2')
644
        self.assertInHistoryIs(None, 'alt_r2', 'submit:')
645
        self.tree.branch.set_parent('bogus')
646
        self.assertRaises(errors.NotBranchError, self.get_in_history,
647
            'submit:')
648
        # submit branch overrides parent branch
649
        self.tree.branch.set_submit_branch('tree2')
650
        self.assertInHistoryIs(None, 'alt_r2', 'submit:')
3298.2.3 by John Arbash Meinel
Add tests that all RevisionSpecs implement in_branch(b, needs_revno)
651
3298.2.4 by John Arbash Meinel
Introduce as_revision_id() as a function instead of in_branch(need_revno=False)
652
    def test_as_revision_id(self):
653
        self.tree.branch.set_submit_branch('tree2')
654
        self.assertAsRevisionId('alt_r2', 'branch:tree2')