~bzr-pqm/bzr/bzr.dev

5557.1.15 by John Arbash Meinel
Merge bzr.dev 5597 to resolve NEWS, aka bzr-2.3.txt
1
# Copyright (C) 2005-2011 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
1185.1.39 by Robert Collins
Robey Pointers before: namespace to clear up usage of dates in revision parameters
18
import time
1432 by Robert Collins
branch: namespace
19
1948.4.1 by John Arbash Meinel
Update number parsers to raise InvalidRevisionSpec. Update revno: itself so it supports negative numbers
20
from bzrlib import (
21
    errors,
3655.3.1 by Lukáš Lalinský
Fix `bzr st -rbranch:PATH_TO_BRANCH`
22
    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
23
    )
5579.3.1 by Jelmer Vernooij
Remove unused imports.
24
from bzrlib.tests import TestCaseWithTransport
2220.2.3 by Martin Pool
Add tag: revision namespace.
25
from bzrlib.revisionspec import (
26
    RevisionSpec,
27
    RevisionSpec_tag,
28
    )
1948.4.33 by John Arbash Meinel
Switch from get_revision_spec() to RevisionSpec.from_string() (as advised by Martin)
29
30
31
def spec_in_history(spec, branch):
32
    """A simple helper to change a revision spec into a branch search"""
33
    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.
34
35
1948.4.3 by John Arbash Meinel
Create direct tests for RevisionSpec_int
36
# Basic class, which just creates a really basic set of revisions
37
class TestRevisionSpec(TestCaseWithTransport):
38
39
    def setUp(self):
40
        super(TestRevisionSpec, self).setUp()
1988.4.5 by Robert Collins
revisions can now be specified using dotted-decimal revision numbers.
41
        # this sets up a revision graph:
42
        # r1: []             1
43
        # alt_r2: [r1]       1.1.1
44
        # r2: [r1, alt_r2]   2
1948.4.3 by John Arbash Meinel
Create direct tests for RevisionSpec_int
45
46
        self.tree = self.make_branch_and_tree('tree')
47
        self.build_tree(['tree/a'])
3298.2.3 by John Arbash Meinel
Add tests that all RevisionSpecs implement in_branch(b, needs_revno)
48
        self.tree.lock_write()
3298.2.11 by Aaron Bentley
Update tests for null:, clea up slightly
49
        self.addCleanup(self.tree.unlock)
50
        self.tree.add(['a'])
51
        self.tree.commit('a', rev_id='r1')
52
53
        self.tree2 = self.tree.bzrdir.sprout('tree2').open_workingtree()
54
        self.tree2.commit('alt', rev_id='alt_r2')
55
56
        self.tree.merge_from_branch(self.tree2.branch)
57
        self.tree.commit('second', rev_id='r2')
1948.4.3 by John Arbash Meinel
Create direct tests for RevisionSpec_int
58
59
    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)
60
        return spec_in_history(revision_spec, self.tree.branch)
1948.4.3 by John Arbash Meinel
Create direct tests for RevisionSpec_int
61
62
    def assertInHistoryIs(self, exp_revno, exp_revision_id, revision_spec):
63
        rev_info = self.get_in_history(revision_spec)
64
        self.assertEqual(exp_revno, rev_info.revno,
2325.2.1 by Marien Zwart
Make the test suite failure reporting a bit more robust.
65
                         'Revision spec: %r returned wrong revno: %r != %r'
1948.4.3 by John Arbash Meinel
Create direct tests for RevisionSpec_int
66
                         % (revision_spec, exp_revno, rev_info.revno))
67
        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.
68
                         'Revision spec: %r returned wrong revision id:'
69
                         ' %r != %r'
1948.4.3 by John Arbash Meinel
Create direct tests for RevisionSpec_int
70
                         % (revision_spec, exp_revision_id, rev_info.rev_id))
71
3495.1.1 by John Arbash Meinel
Fix bug #239933, use the right exception for -c0
72
    def assertInvalid(self, revision_spec, extra='',
73
                      invalid_as_revision_id=True):
1948.4.3 by John Arbash Meinel
Create direct tests for RevisionSpec_int
74
        try:
75
            self.get_in_history(revision_spec)
76
        except errors.InvalidRevisionSpec, e:
1948.4.23 by John Arbash Meinel
Change the handling of negative numbers, to be trapped at revno 1
77
            self.assertEqual(revision_spec, e.spec)
1948.4.3 by John Arbash Meinel
Create direct tests for RevisionSpec_int
78
            self.assertEqual(extra, e.extra)
1948.4.5 by John Arbash Meinel
Fix tests for negative entries, and add tests for revno:
79
        else:
3495.1.1 by John Arbash Meinel
Fix bug #239933, use the right exception for -c0
80
            self.fail('Expected InvalidRevisionSpec to be raised for'
81
                      ' %r.in_history' % (revision_spec,))
82
        if invalid_as_revision_id:
83
            try:
84
                spec = RevisionSpec.from_string(revision_spec)
85
                spec.as_revision_id(self.tree.branch)
86
            except errors.InvalidRevisionSpec, e:
87
                self.assertEqual(revision_spec, e.spec)
88
                self.assertEqual(extra, e.extra)
89
            else:
90
                self.fail('Expected InvalidRevisionSpec to be raised for'
3495.1.2 by John Arbash Meinel
tweak
91
                          ' %r.as_revision_id' % (revision_spec,))
1948.4.3 by John Arbash Meinel
Create direct tests for RevisionSpec_int
92
3298.2.4 by John Arbash Meinel
Introduce as_revision_id() as a function instead of in_branch(need_revno=False)
93
    def assertAsRevisionId(self, revision_id, revision_spec):
94
        """Calling as_revision_id() should return the specified id."""
95
        spec = RevisionSpec.from_string(revision_spec)
96
        self.assertEqual(revision_id,
97
                         spec.as_revision_id(self.tree.branch))
98
3655.3.1 by Lukáš Lalinský
Fix `bzr st -rbranch:PATH_TO_BRANCH`
99
    def get_as_tree(self, revision_spec, tree=None):
100
        if tree is None:
101
            tree = self.tree
102
        spec = RevisionSpec.from_string(revision_spec)
103
        return spec.as_tree(tree.branch)
104
1948.4.3 by John Arbash Meinel
Create direct tests for RevisionSpec_int
105
3460.1.2 by John Arbash Meinel
Add a test for wants_revision_history
106
class RevisionSpecMatchOnTrap(RevisionSpec):
107
108
    def _match_on(self, branch, revs):
109
        self.last_call = (branch, revs)
110
        return super(RevisionSpecMatchOnTrap, self)._match_on(branch, revs)
111
112
113
class TestRevisionSpecBase(TestRevisionSpec):
114
115
    def test_wants_revision_history(self):
116
        # If wants_revision_history = True, then _match_on should get the
117
        # branch revision history
118
        spec = RevisionSpecMatchOnTrap('foo', _internal=True)
119
        spec.in_history(self.tree.branch)
120
121
        self.assertEqual((self.tree.branch, ['r1' ,'r2']),
122
                         spec.last_call)
123
124
    def test_wants_no_revision_history(self):
125
        # If wants_revision_history = False, then _match_on should get None for
126
        # the branch revision history
127
        spec = RevisionSpecMatchOnTrap('foo', _internal=True)
128
        spec.wants_revision_history = False
129
        spec.in_history(self.tree.branch)
130
131
        self.assertEqual((self.tree.branch, None), spec.last_call)
132
133
134
1948.4.19 by John Arbash Meinel
All old tests are covered elsewhere
135
class TestOddRevisionSpec(TestRevisionSpec):
136
    """Test things that aren't normally thought of as revision specs"""
137
138
    def test_none(self):
3298.2.11 by Aaron Bentley
Update tests for null:, clea up slightly
139
        self.assertInHistoryIs(None, None, None)
1948.4.19 by John Arbash Meinel
All old tests are covered elsewhere
140
141
    def test_object(self):
1948.4.33 by John Arbash Meinel
Switch from get_revision_spec() to RevisionSpec.from_string() (as advised by Martin)
142
        self.assertRaises(TypeError, RevisionSpec.from_string, object())
1948.4.19 by John Arbash Meinel
All old tests are covered elsewhere
143
1948.4.32 by John Arbash Meinel
Clean up __repr__, as well as add tests that we can handle -r12:branch/
144
4569.2.2 by Matthew Fuller
Add tests for DWIM revspecs.
145
class TestRevisionSpec_dwim(TestRevisionSpec):
146
147
    # Don't need to test revno's explicitly since TRS_revno already
148
    # covers that well for us
4569.2.11 by Matthew Fuller
Eliminate the TestRevnoFromString() test class by moving all its tests
149
    def test_dwim_spec_revno(self):
150
        self.assertInHistoryIs(2, 'r2', '2')
151
        self.assertAsRevisionId('alt_r2', '1.1.1')
4569.2.2 by Matthew Fuller
Add tests for DWIM revspecs.
152
153
    def test_dwim_spec_revid(self):
154
        self.assertInHistoryIs(2, 'r2', 'r2')
155
156
    def test_dwim_spec_tag(self):
157
        self.tree.branch.tags.set_tag('footag', 'r1')
158
        self.assertAsRevisionId('r1', 'footag')
159
        self.tree.branch.tags.delete_tag('footag')
160
        self.assertRaises(errors.InvalidRevisionSpec,
161
                          self.get_in_history, 'footag')
162
4569.2.16 by Matthew Fuller
Add a test that we slip past the revno-checking stage when we're
163
    def test_dwim_spec_tag_that_looks_like_revno(self):
164
        # Test that we slip past revno with things that look like revnos,
165
        # but aren't.  Tags are convenient for testing this since we can
166
        # make them look however we want.
167
        self.tree.branch.tags.set_tag('3', 'r2')
168
        self.assertAsRevisionId('r2', '3')
169
        self.build_tree(['tree/b'])
170
        self.tree.add(['b'])
171
        self.tree.commit('b', rev_id='r3')
172
        self.assertAsRevisionId('r3', '3')
173
4569.2.4 by Matthew Fuller
Add date: to the list of things DWIM auto-tries.
174
    def test_dwim_spec_date(self):
175
        self.assertAsRevisionId('r1', 'today')
176
4569.2.2 by Matthew Fuller
Add tests for DWIM revspecs.
177
    def test_dwim_spec_branch(self):
178
        self.assertInHistoryIs(None, 'alt_r2', 'tree2')
179
180
    def test_dwim_spec_nonexistent(self):
4569.2.8 by Matthew Fuller
Use a more precise nonexistent thing in test_dwim_spec_nonexistent().
181
        self.assertInvalid('somethingrandom', invalid_as_revision_id=False)
4569.2.11 by Matthew Fuller
Eliminate the TestRevnoFromString() test class by moving all its tests
182
        self.assertInvalid('-1.1', invalid_as_revision_id=False)
183
        self.assertInvalid('.1', invalid_as_revision_id=False)
184
        self.assertInvalid('1..1', invalid_as_revision_id=False)
185
        self.assertInvalid('1.2..1', invalid_as_revision_id=False)
186
        self.assertInvalid('1.', invalid_as_revision_id=False)
1988.4.5 by Robert Collins
revisions can now be specified using dotted-decimal revision numbers.
187
188
1948.4.32 by John Arbash Meinel
Clean up __repr__, as well as add tests that we can handle -r12:branch/
189
class TestRevisionSpec_revno(TestRevisionSpec):
190
191
    def test_positive_int(self):
2598.5.10 by Aaron Bentley
Return NULL_REVISION instead of None for the null revision
192
        self.assertInHistoryIs(0, 'null:', '0')
1948.4.3 by John Arbash Meinel
Create direct tests for RevisionSpec_int
193
        self.assertInHistoryIs(1, 'r1', '1')
194
        self.assertInHistoryIs(2, 'r2', '2')
1948.4.23 by John Arbash Meinel
Change the handling of negative numbers, to be trapped at revno 1
195
        self.assertInvalid('3')
1948.4.3 by John Arbash Meinel
Create direct tests for RevisionSpec_int
196
1988.4.5 by Robert Collins
revisions can now be specified using dotted-decimal revision numbers.
197
    def test_dotted_decimal(self):
198
        self.assertInHistoryIs(None, 'alt_r2', '1.1.1')
3878.3.1 by Marius Kruger
Test invalid dotted revion number directly in TestRevisionSpec_revno
199
        self.assertInvalid('1.1.123')
1988.4.5 by Robert Collins
revisions can now be specified using dotted-decimal revision numbers.
200
1948.4.32 by John Arbash Meinel
Clean up __repr__, as well as add tests that we can handle -r12:branch/
201
    def test_negative_int(self):
1948.4.3 by John Arbash Meinel
Create direct tests for RevisionSpec_int
202
        self.assertInHistoryIs(2, 'r2', '-1')
203
        self.assertInHistoryIs(1, 'r1', '-2')
204
1948.4.23 by John Arbash Meinel
Change the handling of negative numbers, to be trapped at revno 1
205
        self.assertInHistoryIs(1, 'r1', '-3')
206
        self.assertInHistoryIs(1, 'r1', '-4')
207
        self.assertInHistoryIs(1, 'r1', '-100')
1948.4.5 by John Arbash Meinel
Fix tests for negative entries, and add tests for revno:
208
209
    def test_positive(self):
2598.5.10 by Aaron Bentley
Return NULL_REVISION instead of None for the null revision
210
        self.assertInHistoryIs(0, 'null:', 'revno:0')
1948.4.5 by John Arbash Meinel
Fix tests for negative entries, and add tests for revno:
211
        self.assertInHistoryIs(1, 'r1', 'revno:1')
212
        self.assertInHistoryIs(2, 'r2', 'revno:2')
213
214
        self.assertInvalid('revno:3')
215
216
    def test_negative(self):
217
        self.assertInHistoryIs(2, 'r2', 'revno:-1')
218
        self.assertInHistoryIs(1, 'r1', 'revno:-2')
219
1948.4.23 by John Arbash Meinel
Change the handling of negative numbers, to be trapped at revno 1
220
        self.assertInHistoryIs(1, 'r1', 'revno:-3')
221
        self.assertInHistoryIs(1, 'r1', 'revno:-4')
1948.4.6 by John Arbash Meinel
A small bugfix, and more tests for revno:
222
223
    def test_invalid_number(self):
224
        # Get the right exception text
225
        try:
226
            int('X')
227
        except ValueError, e:
228
            pass
1948.4.15 by John Arbash Meinel
Change the InvalidRevisionSpec formatting to be more readable
229
        self.assertInvalid('revno:X', extra='\n' + str(e))
1948.4.6 by John Arbash Meinel
A small bugfix, and more tests for revno:
230
231
    def test_missing_number_and_branch(self):
232
        self.assertInvalid('revno::',
1948.4.15 by John Arbash Meinel
Change the InvalidRevisionSpec formatting to be more readable
233
                           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
234
235
    def test_invalid_number_with_branch(self):
236
        try:
237
            int('X')
238
        except ValueError, e:
239
            pass
1948.4.15 by John Arbash Meinel
Change the InvalidRevisionSpec formatting to be more readable
240
        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
241
1948.4.16 by John Arbash Meinel
Move the tests into the associated tester, remove redundant tests, some small PEP8 changes
242
    def test_non_exact_branch(self):
243
        # It seems better to require an exact path to the branch
244
        # 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)
245
        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
246
        self.assertRaises(errors.NotBranchError,
1948.4.33 by John Arbash Meinel
Switch from get_revision_spec() to RevisionSpec.from_string() (as advised by Martin)
247
                          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
248
1948.4.7 by John Arbash Meinel
More revno: tests, now testing the branch/url parameter
249
    def test_with_branch(self):
250
        # Passing a URL overrides the supplied branch path
251
        revinfo = self.get_in_history('revno:2:tree2')
252
        self.assertNotEqual(self.tree.branch.base, revinfo.branch.base)
253
        self.assertEqual(self.tree2.branch.base, revinfo.branch.base)
254
        self.assertEqual(2, revinfo.revno)
255
        self.assertEqual('alt_r2', revinfo.rev_id)
256
1948.4.32 by John Arbash Meinel
Clean up __repr__, as well as add tests that we can handle -r12:branch/
257
    def test_int_with_branch(self):
258
        revinfo = self.get_in_history('2:tree2')
259
        self.assertNotEqual(self.tree.branch.base, revinfo.branch.base)
260
        self.assertEqual(self.tree2.branch.base, revinfo.branch.base)
261
        self.assertEqual(2, revinfo.revno)
262
        self.assertEqual('alt_r2', revinfo.rev_id)
263
1948.4.7 by John Arbash Meinel
More revno: tests, now testing the branch/url parameter
264
    def test_with_url(self):
265
        url = self.get_url() + '/tree2'
266
        revinfo = self.get_in_history('revno:2:%s' % (url,))
267
        self.assertNotEqual(self.tree.branch.base, revinfo.branch.base)
268
        self.assertEqual(self.tree2.branch.base, revinfo.branch.base)
269
        self.assertEqual(2, revinfo.revno)
270
        self.assertEqual('alt_r2', revinfo.rev_id)
271
272
    def test_negative_with_url(self):
273
        url = self.get_url() + '/tree2'
274
        revinfo = self.get_in_history('revno:-1:%s' % (url,))
275
        self.assertNotEqual(self.tree.branch.base, revinfo.branch.base)
276
        self.assertEqual(self.tree2.branch.base, revinfo.branch.base)
277
        self.assertEqual(2, revinfo.revno)
278
        self.assertEqual('alt_r2', revinfo.rev_id)
279
1948.4.22 by John Arbash Meinel
Refactor common code from integer revno handlers
280
    def test_different_history_lengths(self):
281
        # Make sure we use the revisions and offsets in the supplied branch
282
        # not the ones in the original branch.
283
        self.tree2.commit('three', rev_id='r3')
284
        self.assertInHistoryIs(3, 'r3', 'revno:3:tree2')
285
        self.assertInHistoryIs(3, 'r3', 'revno:-1:tree2')
286
1948.4.7 by John Arbash Meinel
More revno: tests, now testing the branch/url parameter
287
    def test_invalid_branch(self):
288
        self.assertRaises(errors.NotBranchError,
289
                          self.get_in_history, 'revno:-1:tree3')
290
291
    def test_invalid_revno_in_branch(self):
292
        self.tree.commit('three', rev_id='r3')
293
        self.assertInvalid('revno:3:tree2')
1948.4.8 by John Arbash Meinel
Testing the revid: spec
294
1948.4.16 by John Arbash Meinel
Move the tests into the associated tester, remove redundant tests, some small PEP8 changes
295
    def test_revno_n_path(self):
296
        """Old revno:N:path tests"""
297
        wta = self.make_branch_and_tree('a')
298
        ba = wta.branch
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
299
1948.4.16 by John Arbash Meinel
Move the tests into the associated tester, remove redundant tests, some small PEP8 changes
300
        wta.commit('Commit one', rev_id='a@r-0-1')
301
        wta.commit('Commit two', rev_id='a@r-0-2')
302
        wta.commit('Commit three', rev_id='a@r-0-3')
303
304
        wtb = self.make_branch_and_tree('b')
305
        bb = wtb.branch
306
307
        wtb.commit('Commit one', rev_id='b@r-0-1')
308
        wtb.commit('Commit two', rev_id='b@r-0-2')
309
        wtb.commit('Commit three', rev_id='b@r-0-3')
310
1948.4.33 by John Arbash Meinel
Switch from get_revision_spec() to RevisionSpec.from_string() (as advised by Martin)
311
312
        self.assertEqual((1, 'a@r-0-1'),
313
                         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
314
        # The argument of in_history should be ignored since it is
315
        # 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)
316
        self.assertEqual((1, 'a@r-0-1'),
317
                         spec_in_history('revno:1:a/', None))
318
        self.assertEqual((1, 'a@r-0-1'),
319
                         spec_in_history('revno:1:a/', bb))
320
        self.assertEqual((2, 'b@r-0-2'),
321
                         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
322
3298.2.4 by John Arbash Meinel
Introduce as_revision_id() as a function instead of in_branch(need_revno=False)
323
    def test_as_revision_id(self):
3298.2.11 by Aaron Bentley
Update tests for null:, clea up slightly
324
        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)
325
        self.assertAsRevisionId('r1', '1')
326
        self.assertAsRevisionId('r2', '2')
327
        self.assertAsRevisionId('r1', '-2')
328
        self.assertAsRevisionId('r2', '-1')
329
        self.assertAsRevisionId('alt_r2', '1.1.1')
330
3655.3.1 by Lukáš Lalinský
Fix `bzr st -rbranch:PATH_TO_BRANCH`
331
    def test_as_tree(self):
332
        tree = self.get_as_tree('0')
333
        self.assertEquals(_mod_revision.NULL_REVISION, tree.get_revision_id())
334
        tree = self.get_as_tree('1')
335
        self.assertEquals('r1', tree.get_revision_id())
336
        tree = self.get_as_tree('2')
337
        self.assertEquals('r2', tree.get_revision_id())
338
        tree = self.get_as_tree('-2')
339
        self.assertEquals('r1', tree.get_revision_id())
340
        tree = self.get_as_tree('-1')
341
        self.assertEquals('r2', tree.get_revision_id())
342
        tree = self.get_as_tree('1.1.1')
343
        self.assertEquals('alt_r2', tree.get_revision_id())
344
1948.4.8 by John Arbash Meinel
Testing the revid: spec
345
346
class TestRevisionSpec_revid(TestRevisionSpec):
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
347
1948.4.8 by John Arbash Meinel
Testing the revid: spec
348
    def test_in_history(self):
349
        # We should be able to access revisions that are directly
350
        # in the history.
351
        self.assertInHistoryIs(1, 'r1', 'revid:r1')
352
        self.assertInHistoryIs(2, 'r2', 'revid:r2')
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
353
1948.4.8 by John Arbash Meinel
Testing the revid: spec
354
    def test_missing(self):
3495.1.1 by John Arbash Meinel
Fix bug #239933, use the right exception for -c0
355
        self.assertInvalid('revid:r3', invalid_as_revision_id=False)
1948.4.8 by John Arbash Meinel
Testing the revid: spec
356
357
    def test_merged(self):
358
        """We can reach revisions in the ancestry"""
359
        self.assertInHistoryIs(None, 'alt_r2', 'revid:alt_r2')
360
361
    def test_not_here(self):
362
        self.tree2.commit('alt third', rev_id='alt_r3')
363
        # It exists in tree2, but not in tree
3495.1.1 by John Arbash Meinel
Fix bug #239933, use the right exception for -c0
364
        self.assertInvalid('revid:alt_r3', invalid_as_revision_id=False)
1948.4.8 by John Arbash Meinel
Testing the revid: spec
365
366
    def test_in_repository(self):
367
        """We can get any revision id in the repository"""
368
        # XXX: This may change in the future, but for now, it is true
369
        self.tree2.commit('alt third', rev_id='alt_r3')
370
        self.tree.branch.repository.fetch(self.tree2.branch.repository,
371
                                          revision_id='alt_r3')
372
        self.assertInHistoryIs(None, 'alt_r3', 'revid:alt_r3')
1948.4.9 by John Arbash Meinel
Cleanup and test last:
373
2325.2.2 by Marien Zwart
Make the revid RevisionSpec always return a str object, not a unicode object.
374
    def test_unicode(self):
375
        """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.
376
        revision_id = u'\N{SNOWMAN}'.encode('utf-8')
377
        self.tree.commit('unicode', rev_id=revision_id)
378
        self.assertInHistoryIs(3, revision_id, u'revid:\N{SNOWMAN}')
379
        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.
380
3298.2.4 by John Arbash Meinel
Introduce as_revision_id() as a function instead of in_branch(need_revno=False)
381
    def test_as_revision_id(self):
382
        self.assertAsRevisionId('r1', 'revid:r1')
383
        self.assertAsRevisionId('r2', 'revid:r2')
384
        self.assertAsRevisionId('alt_r2', 'revid:alt_r2')
385
1948.4.9 by John Arbash Meinel
Cleanup and test last:
386
387
class TestRevisionSpec_last(TestRevisionSpec):
388
389
    def test_positive(self):
390
        self.assertInHistoryIs(2, 'r2', 'last:1')
391
        self.assertInHistoryIs(1, 'r1', 'last:2')
2598.5.10 by Aaron Bentley
Return NULL_REVISION instead of None for the null revision
392
        self.assertInHistoryIs(0, 'null:', 'last:3')
1948.4.9 by John Arbash Meinel
Cleanup and test last:
393
394
    def test_empty(self):
395
        self.assertInHistoryIs(2, 'r2', 'last:')
396
397
    def test_negative(self):
398
        self.assertInvalid('last:-1',
1948.4.15 by John Arbash Meinel
Change the InvalidRevisionSpec formatting to be more readable
399
                           extra='\nyou must supply a positive value')
1948.4.9 by John Arbash Meinel
Cleanup and test last:
400
401
    def test_missing(self):
402
        self.assertInvalid('last:4')
403
404
    def test_no_history(self):
405
        tree = self.make_branch_and_tree('tree3')
406
407
        self.assertRaises(errors.NoCommits,
1948.4.33 by John Arbash Meinel
Switch from get_revision_spec() to RevisionSpec.from_string() (as advised by Martin)
408
                          spec_in_history, 'last:', tree.branch)
1948.4.9 by John Arbash Meinel
Cleanup and test last:
409
410
    def test_not_a_number(self):
411
        try:
412
            int('Y')
413
        except ValueError, e:
414
            pass
1948.4.15 by John Arbash Meinel
Change the InvalidRevisionSpec formatting to be more readable
415
        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
416
3298.2.4 by John Arbash Meinel
Introduce as_revision_id() as a function instead of in_branch(need_revno=False)
417
    def test_as_revision_id(self):
418
        self.assertAsRevisionId('r2', 'last:1')
419
        self.assertAsRevisionId('r1', 'last:2')
420
1948.4.10 by John Arbash Meinel
test the before: spec, currently asserting what seems to be buggy behavior
421
422
class TestRevisionSpec_before(TestRevisionSpec):
423
424
    def test_int(self):
425
        self.assertInHistoryIs(1, 'r1', 'before:2')
426
        self.assertInHistoryIs(1, 'r1', 'before:-1')
427
428
    def test_before_one(self):
2598.5.10 by Aaron Bentley
Return NULL_REVISION instead of None for the null revision
429
        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
430
431
    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
432
        self.assertInvalid('before:0',
1948.4.15 by John Arbash Meinel
Change the InvalidRevisionSpec formatting to be more readable
433
                           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
434
435
    def test_revid(self):
436
        self.assertInHistoryIs(1, 'r1', 'before:revid:r2')
437
438
    def test_last(self):
439
        self.assertInHistoryIs(1, 'r1', 'before:last:1')
440
441
    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
442
        # This will grab the left-most ancestor for alternate histories
443
        self.assertInHistoryIs(1, 'r1', 'before:revid:alt_r2')
1948.4.11 by John Arbash Meinel
Update and test the tag: spec
444
1948.4.14 by John Arbash Meinel
Test the code path for a no-parent alternate history
445
    def test_alt_no_parents(self):
446
        new_tree = self.make_branch_and_tree('new_tree')
447
        new_tree.commit('first', rev_id='new_r1')
448
        self.tree.branch.repository.fetch(new_tree.branch.repository,
449
                                          revision_id='new_r1')
2598.5.10 by Aaron Bentley
Return NULL_REVISION instead of None for the null revision
450
        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
451
3298.2.4 by John Arbash Meinel
Introduce as_revision_id() as a function instead of in_branch(need_revno=False)
452
    def test_as_revision_id(self):
453
        self.assertAsRevisionId('r1', 'before:revid:r2')
454
        self.assertAsRevisionId('r1', 'before:2')
455
        self.assertAsRevisionId('r1', 'before:1.1.1')
456
        self.assertAsRevisionId('r1', 'before:revid:alt_r2')
457
1948.4.11 by John Arbash Meinel
Update and test the tag: spec
458
459
class TestRevisionSpec_tag(TestRevisionSpec):
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
460
2220.2.3 by Martin Pool
Add tag: revision namespace.
461
    def make_branch_and_tree(self, relpath):
462
        # override format as the default one may not support tags
3031.3.1 by Robert Collins
Remove the unneeded ExperimentalBranch class.
463
        return TestRevisionSpec.make_branch_and_tree(
464
            self, relpath, format='dirstate-tags')
2220.2.3 by Martin Pool
Add tag: revision namespace.
465
466
    def test_from_string_tag(self):
467
        spec = RevisionSpec.from_string('tag:bzr-0.14')
468
        self.assertIsInstance(spec, RevisionSpec_tag)
469
        self.assertEqual(spec.spec, 'bzr-0.14')
470
471
    def test_lookup_tag(self):
2220.2.20 by Martin Pool
Tag methods now available through Branch.tags.add_tag, etc
472
        self.tree.branch.tags.set_tag('bzr-0.14', 'r1')
2220.2.3 by Martin Pool
Add tag: revision namespace.
473
        self.assertInHistoryIs(1, 'r1', 'tag:bzr-0.14')
3298.2.11 by Aaron Bentley
Update tests for null:, clea up slightly
474
        self.tree.branch.tags.set_tag('null_rev', 'null:')
475
        self.assertInHistoryIs(0, 'null:', 'tag:null_rev')
2220.2.3 by Martin Pool
Add tag: revision namespace.
476
477
    def test_failed_lookup(self):
478
        # tags that don't exist give a specific message: arguably we should
479
        # just give InvalidRevisionSpec but I think this is more helpful
480
        self.assertRaises(errors.NoSuchTag,
481
            self.get_in_history,
482
            'tag:some-random-tag')
1948.4.12 by John Arbash Meinel
Some tests for the date: spec
483
3298.2.4 by John Arbash Meinel
Introduce as_revision_id() as a function instead of in_branch(need_revno=False)
484
    def test_as_revision_id(self):
485
        self.tree.branch.tags.set_tag('my-tag', 'r2')
3298.2.11 by Aaron Bentley
Update tests for null:, clea up slightly
486
        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)
487
        self.assertAsRevisionId('r2', 'tag:my-tag')
3298.2.11 by Aaron Bentley
Update tests for null:, clea up slightly
488
        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)
489
        self.assertAsRevisionId('r1', 'before:tag:my-tag')
490
1948.4.12 by John Arbash Meinel
Some tests for the date: spec
491
492
class TestRevisionSpec_date(TestRevisionSpec):
493
494
    def setUp(self):
495
        super(TestRevisionSpec, self).setUp()
496
497
        new_tree = self.make_branch_and_tree('new_tree')
498
        new_tree.commit('Commit one', rev_id='new_r1',
499
                        timestamp=time.time() - 60*60*24)
500
        new_tree.commit('Commit two', rev_id='new_r2')
501
        new_tree.commit('Commit three', rev_id='new_r3')
502
503
        self.tree = new_tree
504
505
    def test_tomorrow(self):
506
        self.assertInvalid('date:tomorrow')
507
508
    def test_today(self):
509
        self.assertInHistoryIs(2, 'new_r2', 'date:today')
510
        self.assertInHistoryIs(1, 'new_r1', 'before:date:today')
511
512
    def test_yesterday(self):
513
        self.assertInHistoryIs(1, 'new_r1', 'date:yesterday')
514
515
    def test_invalid(self):
1948.4.15 by John Arbash Meinel
Change the InvalidRevisionSpec formatting to be more readable
516
        self.assertInvalid('date:foobar', extra='\ninvalid date')
1948.4.12 by John Arbash Meinel
Some tests for the date: spec
517
        # You must have '-' between year/month/day
1948.4.15 by John Arbash Meinel
Change the InvalidRevisionSpec formatting to be more readable
518
        self.assertInvalid('date:20040404', extra='\ninvalid date')
1948.4.12 by John Arbash Meinel
Some tests for the date: spec
519
        # Need 2 digits for each date piece
1948.4.15 by John Arbash Meinel
Change the InvalidRevisionSpec formatting to be more readable
520
        self.assertInvalid('date:2004-4-4', extra='\ninvalid date')
1948.4.12 by John Arbash Meinel
Some tests for the date: spec
521
522
    def test_day(self):
523
        now = datetime.datetime.now()
524
        self.assertInHistoryIs(2, 'new_r2',
525
            'date:%04d-%02d-%02d' % (now.year, now.month, now.day))
1948.4.17 by John Arbash Meinel
Update tests for ancestor: spec
526
3298.2.4 by John Arbash Meinel
Introduce as_revision_id() as a function instead of in_branch(need_revno=False)
527
    def test_as_revision_id(self):
528
        self.assertAsRevisionId('new_r2', 'date:today')
529
1948.4.17 by John Arbash Meinel
Update tests for ancestor: spec
530
531
class TestRevisionSpec_ancestor(TestRevisionSpec):
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
532
1948.4.17 by John Arbash Meinel
Update tests for ancestor: spec
533
    def test_non_exact_branch(self):
534
        # It seems better to require an exact path to the branch
535
        # Branch.open() rather than using Branch.open_containing()
536
        self.assertRaises(errors.NotBranchError,
1948.4.33 by John Arbash Meinel
Switch from get_revision_spec() to RevisionSpec.from_string() (as advised by Martin)
537
                          self.get_in_history, 'ancestor:tree2/a')
1948.4.17 by John Arbash Meinel
Update tests for ancestor: spec
538
539
    def test_simple(self):
540
        # Common ancestor of trees is 'alt_r2'
541
        self.assertInHistoryIs(None, 'alt_r2', 'ancestor:tree2')
542
543
        # Going the other way, we get a valid revno
544
        tmp = self.tree
545
        self.tree = self.tree2
546
        self.tree2 = tmp
547
        self.assertInHistoryIs(2, 'alt_r2', 'ancestor:tree')
548
549
    def test_self(self):
550
        self.assertInHistoryIs(2, 'r2', 'ancestor:tree')
551
552
    def test_unrelated(self):
553
        new_tree = self.make_branch_and_tree('new_tree')
554
555
        new_tree.commit('Commit one', rev_id='new_r1')
556
        new_tree.commit('Commit two', rev_id='new_r2')
557
        new_tree.commit('Commit three', rev_id='new_r3')
558
559
        # With no common ancestor, we should raise another user error
560
        self.assertRaises(errors.NoCommonAncestor,
1948.4.33 by John Arbash Meinel
Switch from get_revision_spec() to RevisionSpec.from_string() (as advised by Martin)
561
                          self.get_in_history, 'ancestor:new_tree')
1948.4.17 by John Arbash Meinel
Update tests for ancestor: spec
562
563
    def test_no_commits(self):
564
        new_tree = self.make_branch_and_tree('new_tree')
565
        self.assertRaises(errors.NoCommits,
1948.4.33 by John Arbash Meinel
Switch from get_revision_spec() to RevisionSpec.from_string() (as advised by Martin)
566
                          spec_in_history, 'ancestor:new_tree',
567
                                           self.tree.branch)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
568
1948.4.17 by John Arbash Meinel
Update tests for ancestor: spec
569
        self.assertRaises(errors.NoCommits,
1948.4.33 by John Arbash Meinel
Switch from get_revision_spec() to RevisionSpec.from_string() (as advised by Martin)
570
                          spec_in_history, 'ancestor:tree',
571
                                           new_tree.branch)
1948.4.18 by John Arbash Meinel
Update branch: spec and tests
572
3298.2.4 by John Arbash Meinel
Introduce as_revision_id() as a function instead of in_branch(need_revno=False)
573
    def test_as_revision_id(self):
574
        self.assertAsRevisionId('alt_r2', 'ancestor:tree2')
575
3984.1.1 by Daniel Watkins
Added test.
576
    def test_default(self):
577
        # We don't have a parent to default to
578
        self.assertRaises(errors.NotBranchError, self.get_in_history,
579
                          'ancestor:')
580
581
        # Create a branch with a parent to default to
582
        tree3 = self.tree.bzrdir.sprout('tree3').open_workingtree()
583
        tree3.commit('foo', rev_id='r3')
584
        self.tree = tree3
585
        self.assertInHistoryIs(2, 'r2', 'ancestor:')
586
1948.4.18 by John Arbash Meinel
Update branch: spec and tests
587
588
class TestRevisionSpec_branch(TestRevisionSpec):
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
589
1948.4.18 by John Arbash Meinel
Update branch: spec and tests
590
    def test_non_exact_branch(self):
591
        # It seems better to require an exact path to the branch
592
        # Branch.open() rather than using Branch.open_containing()
593
        self.assertRaises(errors.NotBranchError,
1948.4.33 by John Arbash Meinel
Switch from get_revision_spec() to RevisionSpec.from_string() (as advised by Martin)
594
                          self.get_in_history, 'branch:tree2/a')
1948.4.18 by John Arbash Meinel
Update branch: spec and tests
595
596
    def test_simple(self):
597
        self.assertInHistoryIs(None, 'alt_r2', 'branch:tree2')
598
599
    def test_self(self):
600
        self.assertInHistoryIs(2, 'r2', 'branch:tree')
601
602
    def test_unrelated(self):
603
        new_tree = self.make_branch_and_tree('new_tree')
604
605
        new_tree.commit('Commit one', rev_id='new_r1')
606
        new_tree.commit('Commit two', rev_id='new_r2')
607
        new_tree.commit('Commit three', rev_id='new_r3')
608
609
        self.assertInHistoryIs(None, 'new_r3', 'branch:new_tree')
610
611
        # XXX: Right now, we use fetch() to make sure the remote revisions
612
        # have been pulled into the local branch. We may change that
613
        # behavior in the future.
614
        self.failUnless(self.tree.branch.repository.has_revision('new_r3'))
615
616
    def test_no_commits(self):
617
        new_tree = self.make_branch_and_tree('new_tree')
618
        self.assertRaises(errors.NoCommits,
1948.4.33 by John Arbash Meinel
Switch from get_revision_spec() to RevisionSpec.from_string() (as advised by Martin)
619
                          self.get_in_history, 'branch:new_tree')
3655.3.1 by Lukáš Lalinský
Fix `bzr st -rbranch:PATH_TO_BRANCH`
620
        self.assertRaises(errors.NoCommits,
621
                          self.get_as_tree, 'branch:new_tree')
1551.10.32 by Aaron Bentley
Add submit: specifier, for merge-directive-like diffs
622
3298.2.4 by John Arbash Meinel
Introduce as_revision_id() as a function instead of in_branch(need_revno=False)
623
    def test_as_revision_id(self):
624
        self.assertAsRevisionId('alt_r2', 'branch:tree2')
625
3655.3.1 by Lukáš Lalinský
Fix `bzr st -rbranch:PATH_TO_BRANCH`
626
    def test_as_tree(self):
627
        tree = self.get_as_tree('branch:tree', self.tree2)
628
        self.assertEquals('r2', tree.get_revision_id())
629
        self.assertFalse(self.tree2.branch.repository.has_revision('r2'))
630
1551.10.32 by Aaron Bentley
Add submit: specifier, for merge-directive-like diffs
631
632
class TestRevisionSpec_submit(TestRevisionSpec):
633
634
    def test_submit_branch(self):
635
        # Common ancestor of trees is 'alt_r2'
636
        self.assertRaises(errors.NoSubmitBranch, self.get_in_history,
637
                          'submit:')
638
        self.tree.branch.set_parent('../tree2')
639
        self.assertInHistoryIs(None, 'alt_r2', 'submit:')
640
        self.tree.branch.set_parent('bogus')
641
        self.assertRaises(errors.NotBranchError, self.get_in_history,
642
            'submit:')
643
        # submit branch overrides parent branch
644
        self.tree.branch.set_submit_branch('tree2')
645
        self.assertInHistoryIs(None, 'alt_r2', 'submit:')
3298.2.3 by John Arbash Meinel
Add tests that all RevisionSpecs implement in_branch(b, needs_revno)
646
3298.2.4 by John Arbash Meinel
Introduce as_revision_id() as a function instead of in_branch(need_revno=False)
647
    def test_as_revision_id(self):
648
        self.tree.branch.set_submit_branch('tree2')
649
        self.assertAsRevisionId('alt_r2', 'branch:tree2')
5365.6.4 by Aaron Bentley
Implement mainline revision spec.
650
651
652
class TestRevisionSpec_mainline(TestRevisionSpec):
653
654
    def test_as_revision_id(self):
655
        self.assertAsRevisionId('r1', 'mainline:1')
656
        self.assertAsRevisionId('r2', 'mainline:1.1.1')
657
        self.assertAsRevisionId('r2', 'mainline:revid:alt_r2')
658
        spec = RevisionSpec.from_string('mainline:revid:alt_r22')
659
        e = self.assertRaises(errors.InvalidRevisionSpec,
660
                              spec.as_revision_id, self.tree.branch)
661
        self.assertContainsRe(str(e),
662
            "Requested revision: 'mainline:revid:alt_r22' does not exist in"
663
            " branch: ")
664
665
    def test_in_history(self):
666
        self.assertInHistoryIs(2, 'r2', 'mainline:revid:alt_r2')
5365.6.6 by Aaron Bentley
Implement 'annotate' revision-id.
667
668
669
class TestRevisionSpec_annotate(TestRevisionSpec):
670
671
    def setUp(self):
672
        TestRevisionSpec.setUp(self)
673
        self.tree = self.make_branch_and_tree('annotate-tree')
674
        self.build_tree_contents([('annotate-tree/file1', '1\n')])
675
        self.tree.add('file1')
676
        self.tree.commit('r1', rev_id='r1')
677
        self.build_tree_contents([('annotate-tree/file1', '2\n1\n')])
678
        self.tree.commit('r2', rev_id='r2')
679
        self.build_tree_contents([('annotate-tree/file1', '2\n1\n3\n')])
680
681
    def test_as_revision_id_r1(self):
682
        self.assertAsRevisionId('r1', 'annotate:annotate-tree/file1:2')
683
684
    def test_as_revision_id_r2(self):
685
        self.assertAsRevisionId('r2', 'annotate:annotate-tree/file1:1')
686
687
    def test_as_revision_id_uncommitted(self):
688
        spec = RevisionSpec.from_string('annotate:annotate-tree/file1:3')
689
        e = self.assertRaises(errors.InvalidRevisionSpec,
690
                              spec.as_revision_id, self.tree.branch)
691
        self.assertContainsRe(str(e),
692
            r"Requested revision: \'annotate:annotate-tree/file1:3\' does not"
693
            " exist in branch: .*\nLine 3 has not been committed.")
694
5365.6.10 by Andrew Bennetts
Fix typo in test method name.
695
    def test_non_existent_line(self):
5365.6.6 by Aaron Bentley
Implement 'annotate' revision-id.
696
        spec = RevisionSpec.from_string('annotate:annotate-tree/file1:4')
697
        e = self.assertRaises(errors.InvalidRevisionSpec,
698
                              spec.as_revision_id, self.tree.branch)
699
        self.assertContainsRe(str(e),
700
            r"Requested revision: \'annotate:annotate-tree/file1:4\' does not"
701
            " exist in branch: .*\nNo such line: 4")
702
703
    def test_invalid_line(self):
704
        spec = RevisionSpec.from_string('annotate:annotate-tree/file1:q')
705
        e = self.assertRaises(errors.InvalidRevisionSpec,
706
                              spec.as_revision_id, self.tree.branch)
707
        self.assertContainsRe(str(e),
708
            r"Requested revision: \'annotate:annotate-tree/file1:q\' does not"
709
            " exist in branch: .*\nNo such line: q")
710
711
    def test_no_such_file(self):
712
        spec = RevisionSpec.from_string('annotate:annotate-tree/file2:1')
713
        e = self.assertRaises(errors.InvalidRevisionSpec,
714
                              spec.as_revision_id, self.tree.branch)
715
        self.assertContainsRe(str(e),
716
            r"Requested revision: \'annotate:annotate-tree/file2:1\' does not"
717
            " exist in branch: .*\nFile 'file2' is not versioned")
718
719
    def test_no_such_file_with_colon(self):
720
        spec = RevisionSpec.from_string('annotate:annotate-tree/fi:le2:1')
721
        e = self.assertRaises(errors.InvalidRevisionSpec,
722
                              spec.as_revision_id, self.tree.branch)
723
        self.assertContainsRe(str(e),
724
            r"Requested revision: \'annotate:annotate-tree/fi:le2:1\' does not"
725
            " exist in branch: .*\nFile 'fi:le2' is not versioned")