/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to breezy/tests/test_shelf.py

  • Committer: Jelmer Vernooij
  • Date: 2020-05-24 00:39:50 UTC
  • mto: This revision was merged to the branch mainline in revision 7504.
  • Revision ID: jelmer@jelmer.uk-20200524003950-bbc545r76vc5yajg
Add github action.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2008-2011 Canonical Ltd
 
2
#
 
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.
 
7
#
 
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.
 
12
#
 
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
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
16
 
 
17
import os
 
18
 
 
19
from .. import (
 
20
    errors,
 
21
    ignores,
 
22
    osutils,
 
23
    shelf,
 
24
    tests,
 
25
    transform,
 
26
    workingtree,
 
27
    )
 
28
from ..bzr import (
 
29
    pack,
 
30
    )
 
31
from . import (
 
32
    features,
 
33
    KnownFailure,
 
34
    )
 
35
from ..errors import (
 
36
    MalformedTransform,
 
37
    )
 
38
 
 
39
 
 
40
EMPTY_SHELF = (b"Bazaar pack format 1 (introduced in 0.18)\n"
 
41
               b"B23\n"
 
42
               b"metadata\n\n"
 
43
               b"d11:revision_id5:null:e"
 
44
               b"B159\n"
 
45
               b"attribs\n\n"
 
46
               b"d10:_id_numberi0e18:_new_executabilityde7:_new_idde"
 
47
               b"9:_new_namede11:_new_parentde16:_non_present_idsde"
 
48
               b"17:_removed_contentsle11:_removed_idle14:_tree_path_idsdeeE")
 
49
 
 
50
 
 
51
class TestErrors(tests.TestCase):
 
52
 
 
53
    def test_invalid_shelf_id(self):
 
54
        invalid_id = "foo"
 
55
        err = shelf.InvalidShelfId(invalid_id)
 
56
        self.assertEqual('"foo" is not a valid shelf id, '
 
57
                         'try a number instead.', str(err))
 
58
 
 
59
 
 
60
class TestPrepareShelf(tests.TestCaseWithTransport):
 
61
 
 
62
    def prepare_shelve_rename(self):
 
63
        tree = self.make_branch_and_tree('.')
 
64
        self.build_tree(['foo'])
 
65
        tree.add(['foo'], [b'foo-id'])
 
66
        tree.commit('foo')
 
67
        tree.rename_one('foo', 'bar')
 
68
        tree.lock_tree_write()
 
69
        self.addCleanup(tree.unlock)
 
70
        creator = shelf.ShelfCreator(tree, tree.basis_tree())
 
71
        self.addCleanup(creator.finalize)
 
72
        self.assertEqual([('rename', b'foo-id', 'foo', 'bar')],
 
73
                         list(creator.iter_shelvable()))
 
74
        return creator
 
75
 
 
76
    def check_shelve_rename(self, creator):
 
77
        work_trans_id = creator.work_transform.trans_id_file_id(b'foo-id')
 
78
        self.assertEqual('foo', creator.work_transform.final_name(
 
79
                         work_trans_id))
 
80
        shelf_trans_id = creator.shelf_transform.trans_id_file_id(b'foo-id')
 
81
        self.assertEqual('bar', creator.shelf_transform.final_name(
 
82
                         shelf_trans_id))
 
83
 
 
84
    def test_shelve_rename(self):
 
85
        creator = self.prepare_shelve_rename()
 
86
        creator.shelve_rename(b'foo-id')
 
87
        self.check_shelve_rename(creator)
 
88
 
 
89
    def test_shelve_change_handles_rename(self):
 
90
        creator = self.prepare_shelve_rename()
 
91
        creator.shelve_change(('rename', b'foo-id', 'foo', 'bar'))
 
92
        self.check_shelve_rename(creator)
 
93
 
 
94
    def prepare_shelve_move(self):
 
95
        tree = self.make_branch_and_tree('.')
 
96
        self.build_tree(['foo/', 'bar/', 'foo/baz'])
 
97
        tree.add(['foo', 'bar', 'foo/baz'], [b'foo-id', b'bar-id', b'baz-id'])
 
98
        tree.commit('foo')
 
99
        tree.rename_one('foo/baz', 'bar/baz')
 
100
        tree.lock_tree_write()
 
101
        self.addCleanup(tree.unlock)
 
102
        creator = shelf.ShelfCreator(tree, tree.basis_tree())
 
103
        self.addCleanup(creator.finalize)
 
104
        self.assertEqual([('rename', b'baz-id', 'foo/baz', 'bar/baz')],
 
105
                         list(creator.iter_shelvable()))
 
106
        return creator, tree
 
107
 
 
108
    def check_shelve_move(self, creator, tree):
 
109
        work_trans_id = creator.work_transform.trans_id_file_id(b'baz-id')
 
110
        work_foo = creator.work_transform.trans_id_file_id(b'foo-id')
 
111
        self.assertEqual(work_foo, creator.work_transform.final_parent(
 
112
                         work_trans_id))
 
113
        shelf_trans_id = creator.shelf_transform.trans_id_file_id(b'baz-id')
 
114
        shelf_bar = creator.shelf_transform.trans_id_file_id(b'bar-id')
 
115
        self.assertEqual(shelf_bar, creator.shelf_transform.final_parent(
 
116
                         shelf_trans_id))
 
117
        creator.transform()
 
118
        self.assertEqual('foo/baz', tree.id2path(b'baz-id'))
 
119
 
 
120
    def test_shelve_move(self):
 
121
        creator, tree = self.prepare_shelve_move()
 
122
        creator.shelve_rename(b'baz-id')
 
123
        self.check_shelve_move(creator, tree)
 
124
 
 
125
    def test_shelve_change_handles_move(self):
 
126
        creator, tree = self.prepare_shelve_move()
 
127
        creator.shelve_change(('rename', b'baz-id', 'foo/baz', 'bar/baz'))
 
128
        self.check_shelve_move(creator, tree)
 
129
 
 
130
    def test_shelve_changed_root_id(self):
 
131
        tree = self.make_branch_and_tree('.')
 
132
        self.build_tree(['foo'])
 
133
        tree.set_root_id(b'first-root-id')
 
134
        tree.add(['foo'], [b'foo-id'])
 
135
        tree.commit('foo')
 
136
        tree.set_root_id(b'second-root-id')
 
137
        tree.lock_tree_write()
 
138
        self.addCleanup(tree.unlock)
 
139
        creator = shelf.ShelfCreator(tree, tree.basis_tree())
 
140
        self.addCleanup(creator.finalize)
 
141
        self.expectFailure(
 
142
            'shelf doesn\'t support shelving root changes yet',
 
143
            self.assertEqual, [
 
144
                ('delete file', b'first-root-id', 'directory', ''),
 
145
                ('add file', b'second-root-id', 'directory', ''),
 
146
                ('rename', b'foo-id', u'foo', u'foo'),
 
147
                ], list(creator.iter_shelvable()))
 
148
 
 
149
        self.assertEqual([('delete file', b'first-root-id', 'directory', ''),
 
150
                          ('add file', b'second-root-id', 'directory', ''),
 
151
                          ('rename', b'foo-id', u'foo', u'foo'),
 
152
                          ], list(creator.iter_shelvable()))
 
153
 
 
154
    def assertShelvedFileEqual(self, expected_content, creator, file_id):
 
155
        s_trans_id = creator.shelf_transform.trans_id_file_id(file_id)
 
156
        shelf_file = creator.shelf_transform._limbo_name(s_trans_id)
 
157
        self.assertFileEqual(expected_content, shelf_file)
 
158
 
 
159
    def prepare_content_change(self):
 
160
        tree = self.make_branch_and_tree('.')
 
161
        tree.lock_write()
 
162
        self.addCleanup(tree.unlock)
 
163
        self.build_tree_contents([('foo', b'a\n')])
 
164
        tree.add('foo', b'foo-id')
 
165
        tree.commit('Committed foo')
 
166
        self.build_tree_contents([('foo', b'b\na\nc\n')])
 
167
        creator = shelf.ShelfCreator(tree, tree.basis_tree())
 
168
        self.addCleanup(creator.finalize)
 
169
        return creator
 
170
 
 
171
    def test_shelve_content_change(self):
 
172
        creator = self.prepare_content_change()
 
173
        self.assertEqual([('modify text', b'foo-id')],
 
174
                         list(creator.iter_shelvable()))
 
175
        creator.shelve_lines(b'foo-id', [b'a\n', b'c\n'])
 
176
        creator.transform()
 
177
        self.assertFileEqual(b'a\nc\n', 'foo')
 
178
        self.assertShelvedFileEqual(b'b\na\n', creator, b'foo-id')
 
179
 
 
180
    def test_shelve_change_handles_modify_text(self):
 
181
        creator = self.prepare_content_change()
 
182
        creator.shelve_change(('modify text', b'foo-id'))
 
183
        creator.transform()
 
184
        self.assertFileEqual(b'a\n', 'foo')
 
185
        self.assertShelvedFileEqual(b'b\na\nc\n', creator, b'foo-id')
 
186
 
 
187
    def test_shelve_all(self):
 
188
        creator = self.prepare_content_change()
 
189
        creator.shelve_all()
 
190
        creator.transform()
 
191
        self.assertFileEqual(b'a\n', 'foo')
 
192
        self.assertShelvedFileEqual(b'b\na\nc\n', creator, b'foo-id')
 
193
 
 
194
    def prepare_shelve_creation(self):
 
195
        tree = self.make_branch_and_tree('.')
 
196
        tree.lock_write()
 
197
        self.addCleanup(tree.unlock)
 
198
        tree.commit('Empty tree')
 
199
        self.build_tree_contents([('foo', b'a\n'), ('bar/',)])
 
200
        tree.add(['foo', 'bar'], [b'foo-id', b'bar-id'])
 
201
        creator = shelf.ShelfCreator(tree, tree.basis_tree())
 
202
        self.addCleanup(creator.finalize)
 
203
        self.assertEqual([('add file', b'bar-id', 'directory', 'bar'),
 
204
                          ('add file', b'foo-id', 'file', 'foo')],
 
205
                         sorted(list(creator.iter_shelvable())))
 
206
        return creator, tree
 
207
 
 
208
    def check_shelve_creation(self, creator, tree):
 
209
        self.assertRaises(
 
210
            StopIteration, next,
 
211
            tree.iter_entries_by_dir(specific_files=['foo']))
 
212
        s_trans_id = creator.shelf_transform.trans_id_file_id(b'foo-id')
 
213
        self.assertEqual(b'foo-id',
 
214
                         creator.shelf_transform.final_file_id(s_trans_id))
 
215
        self.assertPathDoesNotExist('foo')
 
216
        self.assertPathDoesNotExist('bar')
 
217
        self.assertShelvedFileEqual('a\n', creator, b'foo-id')
 
218
        s_bar_trans_id = creator.shelf_transform.trans_id_file_id(b'bar-id')
 
219
        self.assertEqual('directory',
 
220
                         creator.shelf_transform.final_kind(s_bar_trans_id))
 
221
 
 
222
    def test_shelve_creation(self):
 
223
        creator, tree = self.prepare_shelve_creation()
 
224
        creator.shelve_creation(b'foo-id')
 
225
        creator.shelve_creation(b'bar-id')
 
226
        creator.transform()
 
227
        self.check_shelve_creation(creator, tree)
 
228
 
 
229
    def test_shelve_change_handles_creation(self):
 
230
        creator, tree = self.prepare_shelve_creation()
 
231
        creator.shelve_change(('add file', b'foo-id', 'file', 'foo'))
 
232
        creator.shelve_change(('add file', b'bar-id', 'directory', 'bar'))
 
233
        creator.transform()
 
234
        self.check_shelve_creation(creator, tree)
 
235
 
 
236
    def test_shelve_directory_with_ignored(self):
 
237
        tree = self.make_branch_and_tree('.')
 
238
        tree.lock_write()
 
239
        self.addCleanup(tree.unlock)
 
240
        tree.commit('Empty tree')
 
241
        self.build_tree_contents(
 
242
            [('foo', b'a\n'), ('bar/',), ('bar/ignored', b'ign\n')])
 
243
        tree.add(['foo', 'bar'], [b'foo-id', b'bar-id'])
 
244
        creator = shelf.ShelfCreator(tree, tree.basis_tree())
 
245
        self.addCleanup(creator.finalize)
 
246
        self.assertEqual([('add file', b'bar-id', 'directory', 'bar'),
 
247
                          ('add file', b'foo-id', 'file', 'foo')],
 
248
                         sorted(list(creator.iter_shelvable())))
 
249
        ignores._set_user_ignores([])
 
250
        in_patterns = ['ignored', ]
 
251
        ignores.add_unique_user_ignores(in_patterns)
 
252
 
 
253
        creator.shelve_change(('add file', b'bar-id', 'directory', 'bar'))
 
254
        try:
 
255
            creator.transform()
 
256
            self.check_shelve_creation(creator, tree)
 
257
        except MalformedTransform:
 
258
            raise KnownFailure(
 
259
                'shelving directory with ignored file: see bug #611739')
 
260
 
 
261
    def _test_shelve_symlink_creation(self, link_name, link_target,
 
262
                                      shelve_change=False):
 
263
        self.requireFeature(features.SymlinkFeature)
 
264
        tree = self.make_branch_and_tree('.')
 
265
        tree.lock_write()
 
266
        self.addCleanup(tree.unlock)
 
267
        tree.commit('Empty tree')
 
268
        os.symlink(link_target, link_name)
 
269
        tree.add(link_name, b'foo-id')
 
270
        creator = shelf.ShelfCreator(tree, tree.basis_tree())
 
271
        self.addCleanup(creator.finalize)
 
272
        self.assertEqual([('add file', b'foo-id', 'symlink', link_name)],
 
273
                         list(creator.iter_shelvable()))
 
274
        if shelve_change:
 
275
            creator.shelve_change(
 
276
                ('add file', b'foo-id', 'symlink', link_name))
 
277
        else:
 
278
            creator.shelve_creation(b'foo-id')
 
279
        creator.transform()
 
280
        s_trans_id = creator.shelf_transform.trans_id_file_id(b'foo-id')
 
281
        self.assertPathDoesNotExist(link_name)
 
282
        limbo_name = creator.shelf_transform._limbo_name(s_trans_id)
 
283
        self.assertEqual(link_target, osutils.readlink(limbo_name))
 
284
        ptree = creator.shelf_transform.get_preview_tree()
 
285
        self.assertEqual(
 
286
            link_target,
 
287
            ptree.get_symlink_target(ptree.id2path(b'foo-id')))
 
288
 
 
289
    def test_shelve_symlink_creation(self):
 
290
        self._test_shelve_symlink_creation('foo', 'bar')
 
291
 
 
292
    def test_shelve_unicode_symlink_creation(self):
 
293
        self.requireFeature(features.UnicodeFilenameFeature)
 
294
        self._test_shelve_symlink_creation(u'fo\N{Euro Sign}o',
 
295
                                           u'b\N{Euro Sign}ar')
 
296
 
 
297
    def test_shelve_change_handles_symlink_creation(self):
 
298
        self._test_shelve_symlink_creation('foo', 'bar', shelve_change=True)
 
299
 
 
300
    def _test_shelve_symlink_target_change(self, link_name,
 
301
                                           old_target, new_target,
 
302
                                           shelve_change=False):
 
303
        self.requireFeature(features.SymlinkFeature)
 
304
        tree = self.make_branch_and_tree('.')
 
305
        tree.lock_write()
 
306
        self.addCleanup(tree.unlock)
 
307
        os.symlink(old_target, link_name)
 
308
        tree.add(link_name, b'foo-id')
 
309
        tree.commit("commit symlink")
 
310
        os.unlink(link_name)
 
311
        os.symlink(new_target, link_name)
 
312
        creator = shelf.ShelfCreator(tree, tree.basis_tree())
 
313
        self.addCleanup(creator.finalize)
 
314
        self.assertEqual([('modify target', b'foo-id', link_name,
 
315
                           old_target, new_target)],
 
316
                         list(creator.iter_shelvable()))
 
317
        if shelve_change:
 
318
            creator.shelve_change(('modify target', b'foo-id', link_name,
 
319
                                   old_target, new_target))
 
320
        else:
 
321
            creator.shelve_modify_target(b'foo-id')
 
322
        creator.transform()
 
323
        self.assertEqual(old_target, osutils.readlink(link_name))
 
324
        s_trans_id = creator.shelf_transform.trans_id_file_id(b'foo-id')
 
325
        limbo_name = creator.shelf_transform._limbo_name(s_trans_id)
 
326
        self.assertEqual(new_target, osutils.readlink(limbo_name))
 
327
        ptree = creator.shelf_transform.get_preview_tree()
 
328
        self.assertEqual(new_target, ptree.get_symlink_target(
 
329
            ptree.id2path(b'foo-id')))
 
330
 
 
331
    def test_shelve_symlink_target_change(self):
 
332
        self._test_shelve_symlink_target_change('foo', 'bar', 'baz')
 
333
 
 
334
    def test_shelve_unicode_symlink_target_change(self):
 
335
        self.requireFeature(features.UnicodeFilenameFeature)
 
336
        self._test_shelve_symlink_target_change(
 
337
            u'fo\N{Euro Sign}o', u'b\N{Euro Sign}ar', u'b\N{Euro Sign}az')
 
338
 
 
339
    def test_shelve_change_handles_symlink_target_change(self):
 
340
        self._test_shelve_symlink_target_change('foo', 'bar', 'baz',
 
341
                                                shelve_change=True)
 
342
 
 
343
    def test_shelve_creation_no_contents(self):
 
344
        tree = self.make_branch_and_tree('.')
 
345
        tree.lock_write()
 
346
        self.addCleanup(tree.unlock)
 
347
        tree.commit('Empty tree')
 
348
        self.build_tree(['foo'])
 
349
        tree.add('foo', b'foo-id')
 
350
        os.unlink('foo')
 
351
        creator = shelf.ShelfCreator(tree, tree.basis_tree())
 
352
        self.addCleanup(creator.finalize)
 
353
        self.assertEqual([('add file', b'foo-id', None, 'foo')],
 
354
                         sorted(list(creator.iter_shelvable())))
 
355
        creator.shelve_creation(b'foo-id')
 
356
        creator.transform()
 
357
        self.assertRaises(
 
358
            StopIteration, next,
 
359
            tree.iter_entries_by_dir(specific_files=['foo']))
 
360
        self.assertShelvedFileEqual('', creator, b'foo-id')
 
361
        s_trans_id = creator.shelf_transform.trans_id_file_id(b'foo-id')
 
362
        self.assertEqual(b'foo-id',
 
363
                         creator.shelf_transform.final_file_id(s_trans_id))
 
364
        self.assertPathDoesNotExist('foo')
 
365
 
 
366
    def prepare_shelve_deletion(self):
 
367
        tree = self.make_branch_and_tree('tree')
 
368
        tree.lock_write()
 
369
        self.addCleanup(tree.unlock)
 
370
        self.build_tree_contents([('tree/foo/',), ('tree/foo/bar', b'baz')])
 
371
        tree.add(['foo', 'foo/bar'], [b'foo-id', b'bar-id'])
 
372
        tree.commit('Added file and directory')
 
373
        tree.unversion(['foo', 'foo/bar'])
 
374
        os.unlink('tree/foo/bar')
 
375
        os.rmdir('tree/foo')
 
376
        creator = shelf.ShelfCreator(tree, tree.basis_tree())
 
377
        self.addCleanup(creator.finalize)
 
378
        self.assertEqual([('delete file', b'bar-id', 'file', 'foo/bar'),
 
379
                          ('delete file', b'foo-id', 'directory', 'foo')],
 
380
                         sorted(list(creator.iter_shelvable())))
 
381
        return creator, tree
 
382
 
 
383
    def check_shelve_deletion(self, tree):
 
384
        self.assertEqual(tree.id2path(b'foo-id'), 'foo')
 
385
        self.assertEqual(tree.id2path(b'bar-id'), 'foo/bar')
 
386
        self.assertFileEqual(b'baz', 'tree/foo/bar')
 
387
 
 
388
    def test_shelve_deletion(self):
 
389
        creator, tree = self.prepare_shelve_deletion()
 
390
        creator.shelve_deletion(b'foo-id')
 
391
        creator.shelve_deletion(b'bar-id')
 
392
        creator.transform()
 
393
        self.check_shelve_deletion(tree)
 
394
 
 
395
    def test_shelve_change_handles_deletion(self):
 
396
        creator, tree = self.prepare_shelve_deletion()
 
397
        creator.shelve_change(('delete file', b'foo-id', 'directory', 'foo'))
 
398
        creator.shelve_change(('delete file', b'bar-id', 'file', 'foo/bar'))
 
399
        creator.transform()
 
400
        self.check_shelve_deletion(tree)
 
401
 
 
402
    def test_shelve_delete_contents(self):
 
403
        tree = self.make_branch_and_tree('tree')
 
404
        self.build_tree(['tree/foo', ])
 
405
        tree.add('foo', b'foo-id')
 
406
        tree.commit('Added file and directory')
 
407
        os.unlink('tree/foo')
 
408
        tree.lock_tree_write()
 
409
        self.addCleanup(tree.unlock)
 
410
        creator = shelf.ShelfCreator(tree, tree.basis_tree())
 
411
        self.addCleanup(creator.finalize)
 
412
        self.assertEqual([('delete file', b'foo-id', 'file', 'foo')],
 
413
                         sorted(list(creator.iter_shelvable())))
 
414
        creator.shelve_deletion(b'foo-id')
 
415
        creator.transform()
 
416
        self.assertPathExists('tree/foo')
 
417
 
 
418
    def prepare_shelve_change_kind(self):
 
419
        tree = self.make_branch_and_tree('tree')
 
420
        self.build_tree_contents([('tree/foo', b'bar')])
 
421
        tree.add('foo', b'foo-id')
 
422
        tree.commit('Added file and directory')
 
423
        os.unlink('tree/foo')
 
424
        os.mkdir('tree/foo')
 
425
        tree.lock_tree_write()
 
426
        self.addCleanup(tree.unlock)
 
427
        creator = shelf.ShelfCreator(tree, tree.basis_tree())
 
428
        self.addCleanup(creator.finalize)
 
429
        self.assertEqual([('change kind', b'foo-id', 'file', 'directory',
 
430
                           'foo')], sorted(list(creator.iter_shelvable())))
 
431
        return creator
 
432
 
 
433
    def check_shelve_change_kind(self, creator):
 
434
        self.assertFileEqual(b'bar', 'tree/foo')
 
435
        s_trans_id = creator.shelf_transform.trans_id_file_id(b'foo-id')
 
436
        self.assertEqual('directory',
 
437
                         creator.shelf_transform._new_contents[s_trans_id])
 
438
 
 
439
    def test_shelve_change_kind(self):
 
440
        creator = self.prepare_shelve_change_kind()
 
441
        creator.shelve_content_change(b'foo-id')
 
442
        creator.transform()
 
443
        self.check_shelve_change_kind(creator)
 
444
 
 
445
    def test_shelve_change_handles_change_kind(self):
 
446
        creator = self.prepare_shelve_change_kind()
 
447
        creator.shelve_change(('change kind', b'foo-id', 'file', 'directory',
 
448
                               'foo'))
 
449
        creator.transform()
 
450
        self.check_shelve_change_kind(creator)
 
451
 
 
452
    def test_shelve_change_unknown_change(self):
 
453
        tree = self.make_branch_and_tree('tree')
 
454
        tree.lock_tree_write()
 
455
        self.addCleanup(tree.unlock)
 
456
        creator = shelf.ShelfCreator(tree, tree.basis_tree())
 
457
        self.addCleanup(creator.finalize)
 
458
        e = self.assertRaises(ValueError, creator.shelve_change, ('unknown',))
 
459
        self.assertEqual('Unknown change kind: "unknown"', str(e))
 
460
 
 
461
    def test_shelve_unversion(self):
 
462
        tree = self.make_branch_and_tree('tree')
 
463
        self.build_tree(['tree/foo', ])
 
464
        tree.add('foo', b'foo-id')
 
465
        tree.commit('Added file and directory')
 
466
        tree.unversion(['foo'])
 
467
        tree.lock_tree_write()
 
468
        self.addCleanup(tree.unlock)
 
469
        creator = shelf.ShelfCreator(tree, tree.basis_tree())
 
470
        self.addCleanup(creator.finalize)
 
471
        self.assertEqual([('delete file', b'foo-id', 'file', 'foo')],
 
472
                         sorted(list(creator.iter_shelvable())))
 
473
        creator.shelve_deletion(b'foo-id')
 
474
        creator.transform()
 
475
        self.assertPathExists('tree/foo')
 
476
 
 
477
    def test_shelve_serialization(self):
 
478
        tree = self.make_branch_and_tree('.')
 
479
        tree.lock_tree_write()
 
480
        self.addCleanup(tree.unlock)
 
481
        creator = shelf.ShelfCreator(tree, tree.basis_tree())
 
482
        self.addCleanup(creator.finalize)
 
483
        shelf_file = open('shelf', 'wb')
 
484
        self.addCleanup(shelf_file.close)
 
485
        try:
 
486
            creator.write_shelf(shelf_file)
 
487
        finally:
 
488
            shelf_file.close()
 
489
        self.assertFileEqual(EMPTY_SHELF, 'shelf')
 
490
 
 
491
    def test_write_shelf(self):
 
492
        tree = self.make_branch_and_tree('tree')
 
493
        self.build_tree(['tree/foo'])
 
494
        tree.add('foo', b'foo-id')
 
495
        tree.lock_tree_write()
 
496
        self.addCleanup(tree.unlock)
 
497
        creator = shelf.ShelfCreator(tree, tree.basis_tree())
 
498
        self.addCleanup(creator.finalize)
 
499
        list(creator.iter_shelvable())
 
500
        creator.shelve_creation(b'foo-id')
 
501
        with open('shelf', 'wb') as shelf_file:
 
502
            creator.write_shelf(shelf_file)
 
503
        parser = pack.ContainerPushParser()
 
504
        with open('shelf', 'rb') as shelf_file:
 
505
            parser.accept_bytes(shelf_file.read())
 
506
        tt = transform.TransformPreview(tree)
 
507
        self.addCleanup(tt.finalize)
 
508
        records = iter(parser.read_pending_records())
 
509
        # skip revision-id
 
510
        next(records)
 
511
        tt.deserialize(records)
 
512
 
 
513
    def test_shelve_unversioned(self):
 
514
        tree = self.make_branch_and_tree('tree')
 
515
        with tree.lock_tree_write():
 
516
            self.assertRaises(errors.PathsNotVersionedError,
 
517
                              shelf.ShelfCreator, tree, tree.basis_tree(),
 
518
                              ['foo'])
 
519
        # We should be able to lock/unlock the tree if ShelfCreator cleaned
 
520
        # after itself.
 
521
        wt = workingtree.WorkingTree.open('tree')
 
522
        wt.lock_tree_write()
 
523
        wt.unlock()
 
524
        # And a second tentative should raise the same error (no
 
525
        # limbo/pending_deletion leftovers).
 
526
        with tree.lock_tree_write():
 
527
            self.assertRaises(errors.PathsNotVersionedError,
 
528
                              shelf.ShelfCreator, tree, tree.basis_tree(),
 
529
                              ['foo'])
 
530
 
 
531
    def test_shelve_skips_added_root(self):
 
532
        """Skip adds of the root when iterating through shelvable changes."""
 
533
        tree = self.make_branch_and_tree('tree')
 
534
        tree.lock_tree_write()
 
535
        self.addCleanup(tree.unlock)
 
536
        creator = shelf.ShelfCreator(tree, tree.basis_tree())
 
537
        self.addCleanup(creator.finalize)
 
538
        self.assertEqual([], list(creator.iter_shelvable()))
 
539
 
 
540
    def test_shelve_skips_added_root(self):
 
541
        """Skip adds of the root when iterating through shelvable changes."""
 
542
        tree = self.make_branch_and_tree('tree')
 
543
        tree.lock_tree_write()
 
544
        self.addCleanup(tree.unlock)
 
545
        creator = shelf.ShelfCreator(tree, tree.basis_tree())
 
546
        self.addCleanup(creator.finalize)
 
547
        self.assertEqual([], list(creator.iter_shelvable()))
 
548
 
 
549
 
 
550
class TestUnshelver(tests.TestCaseWithTransport):
 
551
 
 
552
    def test_make_merger(self):
 
553
        tree = self.make_branch_and_tree('tree')
 
554
        tree.commit('first commit')
 
555
        self.build_tree_contents([('tree/foo', b'bar')])
 
556
        tree.lock_write()
 
557
        self.addCleanup(tree.unlock)
 
558
        tree.add('foo', b'foo-id')
 
559
        creator = shelf.ShelfCreator(tree, tree.basis_tree())
 
560
        self.addCleanup(creator.finalize)
 
561
        list(creator.iter_shelvable())
 
562
        creator.shelve_creation(b'foo-id')
 
563
        with open('shelf-file', 'w+b') as shelf_file:
 
564
            creator.write_shelf(shelf_file)
 
565
            creator.transform()
 
566
            shelf_file.seek(0)
 
567
            unshelver = shelf.Unshelver.from_tree_and_shelf(tree, shelf_file)
 
568
            unshelver.make_merger().do_merge()
 
569
            self.addCleanup(unshelver.finalize)
 
570
            self.assertFileEqual(b'bar', 'tree/foo')
 
571
 
 
572
    def test_unshelve_changed(self):
 
573
        tree = self.make_branch_and_tree('tree')
 
574
        tree.lock_write()
 
575
        self.addCleanup(tree.unlock)
 
576
        self.build_tree_contents([('tree/foo', b'a\nb\nc\n')])
 
577
        tree.add('foo', b'foo-id')
 
578
        tree.commit('first commit')
 
579
        self.build_tree_contents([('tree/foo', b'a\nb\nd\n')])
 
580
        creator = shelf.ShelfCreator(tree, tree.basis_tree())
 
581
        self.addCleanup(creator.finalize)
 
582
        list(creator.iter_shelvable())
 
583
        creator.shelve_lines(b'foo-id', [b'a\n', b'b\n', b'c\n'])
 
584
        shelf_file = open('shelf', 'w+b')
 
585
        self.addCleanup(shelf_file.close)
 
586
        creator.write_shelf(shelf_file)
 
587
        creator.transform()
 
588
        self.build_tree_contents([('tree/foo', b'z\na\nb\nc\n')])
 
589
        shelf_file.seek(0)
 
590
        unshelver = shelf.Unshelver.from_tree_and_shelf(tree, shelf_file)
 
591
        self.addCleanup(unshelver.finalize)
 
592
        unshelver.make_merger().do_merge()
 
593
        self.assertFileEqual(b'z\na\nb\nd\n', 'tree/foo')
 
594
 
 
595
    def test_unshelve_deleted(self):
 
596
        tree = self.make_branch_and_tree('tree')
 
597
        tree.lock_write()
 
598
        self.addCleanup(tree.unlock)
 
599
        self.build_tree_contents([('tree/foo/',), ('tree/foo/bar', b'baz')])
 
600
        tree.add(['foo', 'foo/bar'], [b'foo-id', b'bar-id'])
 
601
        tree.commit('Added file and directory')
 
602
        tree.unversion(['foo', 'foo/bar'])
 
603
        os.unlink('tree/foo/bar')
 
604
        os.rmdir('tree/foo')
 
605
        creator = shelf.ShelfCreator(tree, tree.basis_tree())
 
606
        list(creator.iter_shelvable())
 
607
        creator.shelve_deletion(b'foo-id')
 
608
        creator.shelve_deletion(b'bar-id')
 
609
        with open('shelf', 'w+b') as shelf_file:
 
610
            creator.write_shelf(shelf_file)
 
611
            creator.transform()
 
612
            creator.finalize()
 
613
        # validate the test setup
 
614
        self.assertEqual(tree.id2path(b'foo-id'), 'foo')
 
615
        self.assertEqual(tree.id2path(b'bar-id'), 'foo/bar')
 
616
        self.assertFileEqual(b'baz', 'tree/foo/bar')
 
617
        with open('shelf', 'r+b') as shelf_file:
 
618
            unshelver = shelf.Unshelver.from_tree_and_shelf(tree, shelf_file)
 
619
            self.addCleanup(unshelver.finalize)
 
620
            unshelver.make_merger().do_merge()
 
621
        self.assertRaises(errors.NoSuchId, tree.id2path, b'foo-id')
 
622
        self.assertRaises(errors.NoSuchId, tree.id2path, b'bar-id')
 
623
 
 
624
    def test_unshelve_base(self):
 
625
        tree = self.make_branch_and_tree('tree')
 
626
        tree.lock_write()
 
627
        self.addCleanup(tree.unlock)
 
628
        tree.commit('rev1', rev_id=b'rev1')
 
629
        creator = shelf.ShelfCreator(tree, tree.basis_tree())
 
630
        self.addCleanup(creator.finalize)
 
631
        manager = tree.get_shelf_manager()
 
632
        shelf_id, shelf_file = manager.new_shelf()
 
633
        try:
 
634
            creator.write_shelf(shelf_file)
 
635
        finally:
 
636
            shelf_file.close()
 
637
        tree.commit('rev2', rev_id=b'rev2')
 
638
        shelf_file = manager.read_shelf(1)
 
639
        self.addCleanup(shelf_file.close)
 
640
        unshelver = shelf.Unshelver.from_tree_and_shelf(tree, shelf_file)
 
641
        self.addCleanup(unshelver.finalize)
 
642
        self.assertEqual(b'rev1', unshelver.base_tree.get_revision_id())
 
643
 
 
644
    def test_unshelve_serialization(self):
 
645
        tree = self.make_branch_and_tree('.')
 
646
        self.build_tree_contents([('shelf', EMPTY_SHELF)])
 
647
        shelf_file = open('shelf', 'rb')
 
648
        self.addCleanup(shelf_file.close)
 
649
        unshelver = shelf.Unshelver.from_tree_and_shelf(tree, shelf_file)
 
650
        unshelver.finalize()
 
651
 
 
652
    def test_corrupt_shelf(self):
 
653
        tree = self.make_branch_and_tree('.')
 
654
        self.build_tree_contents([('shelf', EMPTY_SHELF.replace(b'metadata',
 
655
                                                                b'foo'))])
 
656
        shelf_file = open('shelf', 'rb')
 
657
        self.addCleanup(shelf_file.close)
 
658
        e = self.assertRaises(shelf.ShelfCorrupt,
 
659
                              shelf.Unshelver.from_tree_and_shelf, tree,
 
660
                              shelf_file)
 
661
        self.assertEqual('Shelf corrupt.', str(e))
 
662
 
 
663
    def test_unshelve_subdir_in_now_removed_dir(self):
 
664
        tree = self.make_branch_and_tree('.')
 
665
        self.addCleanup(tree.lock_write().unlock)
 
666
        self.build_tree(['dir/', 'dir/subdir/', 'dir/subdir/foo'])
 
667
        tree.add(['dir'], [b'dir-id'])
 
668
        tree.commit('versioned dir')
 
669
        tree.add(['dir/subdir', 'dir/subdir/foo'], [b'subdir-id', b'foo-id'])
 
670
        creator = shelf.ShelfCreator(tree, tree.basis_tree())
 
671
        self.addCleanup(creator.finalize)
 
672
        for change in creator.iter_shelvable():
 
673
            creator.shelve_change(change)
 
674
        shelf_manager = tree.get_shelf_manager()
 
675
        shelf_id = shelf_manager.shelve_changes(creator)
 
676
        self.assertPathDoesNotExist('dir/subdir')
 
677
        tree.remove(['dir'])
 
678
        unshelver = shelf_manager.get_unshelver(shelf_id)
 
679
        self.addCleanup(unshelver.finalize)
 
680
        unshelver.make_merger().do_merge()
 
681
        self.assertPathExists('dir/subdir/foo')
 
682
        self.assertEqual(b'dir-id', tree.path2id('dir'))
 
683
        self.assertEqual(b'subdir-id', tree.path2id('dir/subdir'))
 
684
        self.assertEqual(b'foo-id', tree.path2id('dir/subdir/foo'))
 
685
 
 
686
 
 
687
class TestShelfManager(tests.TestCaseWithTransport):
 
688
 
 
689
    def test_get_shelf_manager(self):
 
690
        tree = self.make_branch_and_tree('.')
 
691
        manager = tree.get_shelf_manager()
 
692
        self.assertEqual(tree._transport.base + 'shelf/',
 
693
                         manager.transport.base)
 
694
 
 
695
    def get_manager(self):
 
696
        return self.make_branch_and_tree('.').get_shelf_manager()
 
697
 
 
698
    def test_get_shelf_filename(self):
 
699
        tree = self.make_branch_and_tree('.')
 
700
        manager = tree.get_shelf_manager()
 
701
        self.assertEqual('shelf-1', manager.get_shelf_filename(1))
 
702
 
 
703
    def test_get_shelf_ids(self):
 
704
        tree = self.make_branch_and_tree('.')
 
705
        manager = tree.get_shelf_manager()
 
706
        self.assertEqual([1, 3], manager.get_shelf_ids(
 
707
                         ['shelf-1', 'shelf-02', 'shelf-3']))
 
708
 
 
709
    def test_new_shelf(self):
 
710
        manager = self.get_manager()
 
711
        shelf_id, shelf_file = manager.new_shelf()
 
712
        shelf_file.close()
 
713
        self.assertEqual(1, shelf_id)
 
714
        shelf_id, shelf_file = manager.new_shelf()
 
715
        shelf_file.close()
 
716
        self.assertEqual(2, shelf_id)
 
717
        manager.delete_shelf(1)
 
718
        shelf_id, shelf_file = manager.new_shelf()
 
719
        shelf_file.close()
 
720
        self.assertEqual(3, shelf_id)
 
721
 
 
722
    def test_active_shelves(self):
 
723
        manager = self.get_manager()
 
724
        self.assertEqual([], manager.active_shelves())
 
725
        shelf_id, shelf_file = manager.new_shelf()
 
726
        shelf_file.close()
 
727
        self.assertEqual([1], manager.active_shelves())
 
728
 
 
729
    def test_delete_shelf(self):
 
730
        manager = self.get_manager()
 
731
        shelf_id, shelf_file = manager.new_shelf()
 
732
        shelf_file.close()
 
733
        self.assertEqual([1], manager.active_shelves())
 
734
        manager.delete_shelf(1)
 
735
        self.assertEqual([], manager.active_shelves())
 
736
 
 
737
    def test_last_shelf(self):
 
738
        manager = self.get_manager()
 
739
        self.assertIs(None, manager.last_shelf())
 
740
        shelf_id, shelf_file = manager.new_shelf()
 
741
        shelf_file.close()
 
742
        self.assertEqual(1, manager.last_shelf())
 
743
 
 
744
    def test_read_shelf(self):
 
745
        manager = self.get_manager()
 
746
        shelf_id, shelf_file = manager.new_shelf()
 
747
        try:
 
748
            shelf_file.write(b'foo')
 
749
        finally:
 
750
            shelf_file.close()
 
751
        shelf_id, shelf_file = manager.new_shelf()
 
752
        try:
 
753
            shelf_file.write(b'bar')
 
754
        finally:
 
755
            shelf_file.close()
 
756
        shelf_file = manager.read_shelf(1)
 
757
        try:
 
758
            self.assertEqual(b'foo', shelf_file.read())
 
759
        finally:
 
760
            shelf_file.close()
 
761
        shelf_file = manager.read_shelf(2)
 
762
        try:
 
763
            self.assertEqual(b'bar', shelf_file.read())
 
764
        finally:
 
765
            shelf_file.close()
 
766
 
 
767
    def test_read_non_existant(self):
 
768
        manager = self.get_manager()
 
769
        e = self.assertRaises(shelf.NoSuchShelfId, manager.read_shelf, 1)
 
770
        self.assertEqual('No changes are shelved with id "1".', str(e))
 
771
 
 
772
    def test_shelve_changes(self):
 
773
        tree = self.make_branch_and_tree('tree')
 
774
        tree.commit('no-change commit')
 
775
        tree.lock_write()
 
776
        self.addCleanup(tree.unlock)
 
777
        self.build_tree_contents([('tree/foo', b'bar')])
 
778
        self.assertFileEqual(b'bar', 'tree/foo')
 
779
        tree.add('foo', b'foo-id')
 
780
        creator = shelf.ShelfCreator(tree, tree.basis_tree())
 
781
        self.addCleanup(creator.finalize)
 
782
        list(creator.iter_shelvable())
 
783
        creator.shelve_creation(b'foo-id')
 
784
        shelf_manager = tree.get_shelf_manager()
 
785
        shelf_id = shelf_manager.shelve_changes(creator)
 
786
        self.assertPathDoesNotExist('tree/foo')
 
787
        unshelver = shelf_manager.get_unshelver(shelf_id)
 
788
        self.addCleanup(unshelver.finalize)
 
789
        unshelver.make_merger().do_merge()
 
790
        self.assertFileEqual(b'bar', 'tree/foo')
 
791
 
 
792
    def test_get_metadata(self):
 
793
        tree = self.make_branch_and_tree('.')
 
794
        tree.lock_tree_write()
 
795
        self.addCleanup(tree.unlock)
 
796
        creator = shelf.ShelfCreator(tree, tree.basis_tree())
 
797
        self.addCleanup(creator.finalize)
 
798
        shelf_manager = tree.get_shelf_manager()
 
799
        shelf_id = shelf_manager.shelve_changes(creator, 'foo')
 
800
        metadata = shelf_manager.get_metadata(shelf_id)
 
801
        self.assertEqual('foo', metadata[b'message'])
 
802
        self.assertEqual(b'null:', metadata[b'revision_id'])