1
# Copyright (C) 2008-2011, 2016 Canonical Ltd
1
# Copyright (C) 2008, 2009, 2010 Canonical Ltd
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
15
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
from cStringIO import StringIO
20
21
from textwrap import dedent
29
from ..sixish import (
29
from bzrlib.tests import script
38
32
class ExpectShelver(shelf_ui.Shelver):
45
39
auto, auto_apply, file_list, message,
46
40
destroy, reporter=reporter)
48
self.diff_writer = BytesIO()
50
def expect(self, message, response):
51
self.expected.append((message, response))
53
def prompt(self, message, choices, default):
42
self.diff_writer = StringIO()
44
def expect(self, prompt, response):
45
self.expected.append((prompt, response))
47
def prompt(self, message):
55
expected_message, response = self.expected.pop(0)
49
prompt, response = self.expected.pop(0)
57
51
raise AssertionError('Unexpected prompt: %s' % message)
58
if message != expected_message:
59
53
raise AssertionError('Wrong prompt: %s' % message)
60
if choices != '&yes\n&No\n&finish\n&quit':
61
raise AssertionError('Wrong choices: %s' % choices)
65
LINES_AJ = b'a\nb\nc\nd\ne\nf\ng\nh\ni\nj\n'
68
LINES_ZY = b'z\nb\nc\nd\ne\nf\ng\nh\ni\ny\n'
71
LINES_AY = b'a\nb\nc\nd\ne\nf\ng\nh\ni\ny\n'
74
class ShelfTestCase(tests.TestCaseWithTransport):
57
LINES_AJ = 'a\nb\nc\nd\ne\nf\ng\nh\ni\nj\n'
60
LINES_ZY = 'z\nb\nc\nd\ne\nf\ng\nh\ni\ny\n'
63
LINES_AY = 'a\nb\nc\nd\ne\nf\ng\nh\ni\ny\n'
66
class TestShelver(tests.TestCaseWithTransport):
76
68
def create_shelvable_tree(self):
77
69
tree = self.make_branch_and_tree('tree')
78
70
self.build_tree_contents([('tree/foo', LINES_AJ)])
79
tree.add('foo', b'foo-id')
71
tree.add('foo', 'foo-id')
80
72
tree.commit('added foo')
81
73
self.build_tree_contents([('tree/foo', LINES_ZY)])
85
class TestShelver(ShelfTestCase):
87
76
def test_unexpected_prompt_failure(self):
88
77
tree = self.create_shelvable_tree()
89
78
tree.lock_tree_write()
91
80
shelver = ExpectShelver(tree, tree.basis_tree())
92
81
self.addCleanup(shelver.finalize)
93
82
e = self.assertRaises(AssertionError, shelver.run)
94
self.assertEqual('Unexpected prompt: Shelve?', str(e))
83
self.assertEqual('Unexpected prompt: Shelve? [yNfq?]', str(e))
96
85
def test_wrong_prompt_failure(self):
97
86
tree = self.create_shelvable_tree()
99
88
self.addCleanup(tree.unlock)
100
89
shelver = ExpectShelver(tree, tree.basis_tree())
101
90
self.addCleanup(shelver.finalize)
102
shelver.expect('foo', 0)
91
shelver.expect('foo', 'y')
103
92
e = self.assertRaises(AssertionError, shelver.run)
104
self.assertEqual('Wrong prompt: Shelve?', str(e))
93
self.assertEqual('Wrong prompt: Shelve? [yNfq?]', str(e))
106
95
def test_shelve_not_diff(self):
107
96
tree = self.create_shelvable_tree()
109
98
self.addCleanup(tree.unlock)
110
99
shelver = ExpectShelver(tree, tree.basis_tree())
111
100
self.addCleanup(shelver.finalize)
112
shelver.expect('Shelve?', 1)
113
shelver.expect('Shelve?', 1)
101
shelver.expect('Shelve? [yNfq?]', 'n')
102
shelver.expect('Shelve? [yNfq?]', 'n')
114
103
# No final shelving prompt because no changes were selected
116
105
self.assertFileEqual(LINES_ZY, 'tree/foo')
121
110
self.addCleanup(tree.unlock)
122
111
shelver = ExpectShelver(tree, tree.basis_tree())
123
112
self.addCleanup(shelver.finalize)
124
shelver.expect('Shelve?', 0)
125
shelver.expect('Shelve?', 0)
126
shelver.expect('Shelve 2 change(s)?', 1)
113
shelver.expect('Shelve? [yNfq?]', 'y')
114
shelver.expect('Shelve? [yNfq?]', 'y')
115
shelver.expect('Shelve 2 change(s)? [yNfq?]', 'n')
128
117
self.assertFileEqual(LINES_ZY, 'tree/foo')
133
122
self.addCleanup(tree.unlock)
134
123
shelver = ExpectShelver(tree, tree.basis_tree())
135
124
self.addCleanup(shelver.finalize)
136
shelver.expect('Shelve?', 0)
137
shelver.expect('Shelve?', 0)
138
shelver.expect('Shelve 2 change(s)?', 0)
125
shelver.expect('Shelve? [yNfq?]', 'y')
126
shelver.expect('Shelve? [yNfq?]', 'y')
127
shelver.expect('Shelve 2 change(s)? [yNfq?]', 'y')
140
129
self.assertFileEqual(LINES_AJ, 'tree/foo')
145
134
self.addCleanup(tree.unlock)
146
135
shelver = ExpectShelver(tree, tree.basis_tree())
147
136
self.addCleanup(shelver.finalize)
148
shelver.expect('Shelve?', 0)
149
shelver.expect('Shelve?', 1)
150
shelver.expect('Shelve 1 change(s)?', 0)
137
shelver.expect('Shelve? [yNfq?]', 'y')
138
shelver.expect('Shelve? [yNfq?]', 'n')
139
shelver.expect('Shelve 1 change(s)? [yNfq?]', 'y')
152
141
self.assertFileEqual(LINES_AY, 'tree/foo')
154
143
def test_shelve_binary_change(self):
155
144
tree = self.create_shelvable_tree()
156
self.build_tree_contents([('tree/foo', b'\x00')])
145
self.build_tree_contents([('tree/foo', '\x00')])
157
146
tree.lock_tree_write()
158
147
self.addCleanup(tree.unlock)
159
148
shelver = ExpectShelver(tree, tree.basis_tree())
160
149
self.addCleanup(shelver.finalize)
161
shelver.expect('Shelve binary changes?', 0)
162
shelver.expect('Shelve 1 change(s)?', 0)
150
shelver.expect('Shelve binary changes? [yNfq?]', 'y')
151
shelver.expect('Shelve 1 change(s)? [yNfq?]', 'y')
164
153
self.assertFileEqual(LINES_AJ, 'tree/foo')
170
159
self.addCleanup(tree.unlock)
171
160
shelver = ExpectShelver(tree, tree.basis_tree())
172
161
self.addCleanup(shelver.finalize)
173
shelver.expect('Shelve renaming "foo" => "bar"?', 0)
174
shelver.expect('Shelve?', 0)
175
shelver.expect('Shelve?', 0)
176
shelver.expect('Shelve 3 change(s)?', 0)
162
shelver.expect('Shelve renaming "foo" => "bar"? [yNfq?]', 'y')
163
shelver.expect('Shelve? [yNfq?]', 'y')
164
shelver.expect('Shelve? [yNfq?]', 'y')
165
shelver.expect('Shelve 3 change(s)? [yNfq?]', 'y')
178
167
self.assertFileEqual(LINES_AJ, 'tree/foo')
184
173
self.addCleanup(tree.unlock)
185
174
shelver = ExpectShelver(tree, tree.basis_tree())
186
175
self.addCleanup(shelver.finalize)
187
shelver.expect('Shelve removing file "foo"?', 0)
188
shelver.expect('Shelve 1 change(s)?', 0)
176
shelver.expect('Shelve removing file "foo"? [yNfq?]', 'y')
177
shelver.expect('Shelve 1 change(s)? [yNfq?]', 'y')
190
179
self.assertFileEqual(LINES_AJ, 'tree/foo')
198
187
self.addCleanup(tree.unlock)
199
188
shelver = ExpectShelver(tree, tree.basis_tree())
200
189
self.addCleanup(shelver.finalize)
201
shelver.expect('Shelve adding file "foo"?', 0)
202
shelver.expect('Shelve 1 change(s)?', 0)
190
shelver.expect('Shelve adding file "foo"? [yNfq?]', 'y')
191
shelver.expect('Shelve 1 change(s)? [yNfq?]', 'y')
204
self.assertPathDoesNotExist('tree/foo')
193
self.failIfExists('tree/foo')
206
195
def test_shelve_kind_change(self):
207
196
tree = self.create_shelvable_tree()
211
200
self.addCleanup(tree.unlock)
212
201
shelver = ExpectShelver(tree, tree.basis_tree())
213
202
self.addCleanup(shelver.finalize)
214
shelver.expect('Shelve changing "foo" from file to directory?',
216
shelver.expect('Shelve 1 change(s)?', 0)
203
shelver.expect('Shelve changing "foo" from file to directory? [yNfq?]',
205
shelver.expect('Shelve 1 change(s)? [yNfq?]', 'y')
218
207
def test_shelve_modify_target(self):
219
self.requireFeature(features.SymlinkFeature)
208
self.requireFeature(tests.SymlinkFeature)
220
209
tree = self.create_shelvable_tree()
221
210
os.symlink('bar', 'tree/baz')
222
tree.add('baz', b'baz-id')
211
tree.add('baz', 'baz-id')
223
212
tree.commit("Add symlink")
224
213
os.unlink('tree/baz')
225
214
os.symlink('vax', 'tree/baz')
228
217
shelver = ExpectShelver(tree, tree.basis_tree())
229
218
self.addCleanup(shelver.finalize)
230
219
shelver.expect('Shelve changing target of "baz" from "bar" to '
232
shelver.expect('Shelve 1 change(s)?', 0)
220
'"vax"? [yNfq?]', 'y')
221
shelver.expect('Shelve 1 change(s)? [yNfq?]', 'y')
234
223
self.assertEqual('bar', os.readlink('tree/baz'))
239
228
self.addCleanup(tree.unlock)
240
229
shelver = ExpectShelver(tree, tree.basis_tree())
241
230
self.addCleanup(shelver.finalize)
242
shelver.expect('Shelve?', 2)
243
shelver.expect('Shelve 2 change(s)?', 0)
231
shelver.expect('Shelve? [yNfq?]', 'f')
232
shelver.expect('Shelve 2 change(s)? [yNfq?]', 'y')
245
234
self.assertFileEqual(LINES_AJ, 'tree/foo')
250
239
self.addCleanup(tree.unlock)
251
240
shelver = ExpectShelver(tree, tree.basis_tree())
252
241
self.addCleanup(shelver.finalize)
253
shelver.expect('Shelve?', 3)
242
shelver.expect('Shelve? [yNfq?]', 'q')
254
243
self.assertRaises(errors.UserAbort, shelver.run)
255
244
self.assertFileEqual(LINES_ZY, 'tree/foo')
257
246
def test_shelve_all(self):
258
self.create_shelvable_tree()
247
tree = self.create_shelvable_tree()
259
248
shelver = ExpectShelver.from_args(sys.stdout, all=True,
272
261
self.addCleanup(tree.unlock)
273
262
shelver = ExpectShelver(tree, tree.basis_tree(), file_list=['bar'])
274
263
self.addCleanup(shelver.finalize)
275
shelver.expect('Shelve adding file "bar"?', 0)
276
shelver.expect('Shelve 1 change(s)?', 0)
264
shelver.expect('Shelve adding file "bar"? [yNfq?]', 'y')
265
shelver.expect('Shelve 1 change(s)? [yNfq?]', 'y')
268
def test_shelve_help(self):
269
tree = self.create_shelvable_tree()
270
tree.lock_tree_write()
271
self.addCleanup(tree.unlock)
272
shelver = ExpectShelver(tree, tree.basis_tree())
273
self.addCleanup(shelver.finalize)
274
shelver.expect('Shelve? [yNfq?]', '?')
275
shelver.expect('Shelve? [(y)es, (N)o, (f)inish, or (q)uit]', 'f')
276
shelver.expect('Shelve 2 change(s)? [yNfq?]', 'y')
279
279
def test_shelve_destroy(self):
302
def test_shelve_old_root_preserved(self):
302
def test_shelve_old_root_deleted(self):
303
303
tree1 = self.make_branch_and_tree('tree1')
304
304
tree1.commit('add root')
305
tree1_root_id = tree1.path2id('')
306
305
tree2 = self.make_branch_and_tree('tree2')
307
306
rev2 = tree2.commit('add root')
308
self.assertNotEqual(tree1_root_id, tree2.path2id(''))
309
307
tree1.merge_from_branch(tree2.branch,
310
308
from_revision=revision.NULL_REVISION)
311
tree1.commit('merging in tree2')
312
self.assertEqual(tree1_root_id, tree1.path2id(''))
309
tree1.commit('Replaced root entry')
313
310
# This is essentially assertNotRaises(InconsistentDelta)
314
# With testtools 0.9.9, it can be rewritten as:
315
# with ExpectedException(AssertionError,
316
# 'InconsistentDelta not raised'):
317
# with ExpectedException(errors.InconsistentDelta, ''):
318
# self.shelve_all(tree1, rev2)
319
e = self.assertRaises(AssertionError, self.assertRaises,
320
errors.InconsistentDelta, self.shelve_all, tree1,
322
self.assertContainsRe('InconsistentDelta not raised', str(e))
311
self.expectFailure('Cannot shelve replacing a root entry',
312
self.assertRaises, AssertionError,
313
self.assertRaises, errors.InconsistentDelta,
314
self.shelve_all, tree1, rev2)
324
316
def test_shelve_split(self):
325
317
outer_tree = self.make_branch_and_tree('outer')
344
336
shelver = ExpectShelver(tree, tree.basis_tree(),
345
337
reporter=shelf_ui.ApplyReporter())
346
338
self.addCleanup(shelver.finalize)
347
shelver.expect('Apply change?', 1)
348
shelver.expect('Apply change?', 1)
339
shelver.expect('Apply change? [yNfq?]', 'n')
340
shelver.expect('Apply change? [yNfq?]', 'n')
349
341
# No final shelving prompt because no changes were selected
351
343
self.assertFileEqual(LINES_ZY, 'tree/foo')
357
349
shelver = ExpectShelver(tree, tree.basis_tree(),
358
350
reporter=shelf_ui.ApplyReporter())
359
351
self.addCleanup(shelver.finalize)
360
shelver.expect('Apply change?', 0)
361
shelver.expect('Apply change?', 0)
362
shelver.expect('Apply 2 change(s)?', 1)
352
shelver.expect('Apply change? [yNfq?]', 'y')
353
shelver.expect('Apply change? [yNfq?]', 'y')
354
shelver.expect('Apply 2 change(s)? [yNfq?]', 'n')
364
356
self.assertFileEqual(LINES_ZY, 'tree/foo')
370
362
shelver = ExpectShelver(tree, tree.basis_tree(),
371
363
reporter=shelf_ui.ApplyReporter())
372
364
self.addCleanup(shelver.finalize)
373
shelver.expect('Apply change?', 0)
374
shelver.expect('Apply change?', 0)
375
shelver.expect('Apply 2 change(s)?', 0)
365
shelver.expect('Apply change? [yNfq?]', 'y')
366
shelver.expect('Apply change? [yNfq?]', 'y')
367
shelver.expect('Apply 2 change(s)? [yNfq?]', 'y')
377
369
self.assertFileEqual(LINES_AJ, 'tree/foo')
379
371
def test_shelve_binary_change(self):
380
372
tree = self.create_shelvable_tree()
381
self.build_tree_contents([('tree/foo', b'\x00')])
373
self.build_tree_contents([('tree/foo', '\x00')])
382
374
tree.lock_tree_write()
383
375
self.addCleanup(tree.unlock)
384
376
shelver = ExpectShelver(tree, tree.basis_tree(),
385
377
reporter=shelf_ui.ApplyReporter())
386
378
self.addCleanup(shelver.finalize)
387
shelver.expect('Apply binary changes?', 0)
388
shelver.expect('Apply 1 change(s)?', 0)
379
shelver.expect('Apply binary changes? [yNfq?]', 'y')
380
shelver.expect('Apply 1 change(s)? [yNfq?]', 'y')
390
382
self.assertFileEqual(LINES_AJ, 'tree/foo')
397
389
shelver = ExpectShelver(tree, tree.basis_tree(),
398
390
reporter=shelf_ui.ApplyReporter())
399
391
self.addCleanup(shelver.finalize)
400
shelver.expect('Rename "bar" => "foo"?', 0)
401
shelver.expect('Apply change?', 0)
402
shelver.expect('Apply change?', 0)
403
shelver.expect('Apply 3 change(s)?', 0)
392
shelver.expect('Rename "bar" => "foo"? [yNfq?]', 'y')
393
shelver.expect('Apply change? [yNfq?]', 'y')
394
shelver.expect('Apply change? [yNfq?]', 'y')
395
shelver.expect('Apply 3 change(s)? [yNfq?]', 'y')
405
397
self.assertFileEqual(LINES_AJ, 'tree/foo')
412
404
shelver = ExpectShelver(tree, tree.basis_tree(),
413
405
reporter=shelf_ui.ApplyReporter())
414
406
self.addCleanup(shelver.finalize)
415
shelver.expect('Add file "foo"?', 0)
416
shelver.expect('Apply 1 change(s)?', 0)
407
shelver.expect('Add file "foo"? [yNfq?]', 'y')
408
shelver.expect('Apply 1 change(s)? [yNfq?]', 'y')
418
410
self.assertFileEqual(LINES_AJ, 'tree/foo')
427
419
shelver = ExpectShelver(tree, tree.basis_tree(),
428
420
reporter=shelf_ui.ApplyReporter())
429
421
self.addCleanup(shelver.finalize)
430
shelver.expect('Delete file "foo"?', 0)
431
shelver.expect('Apply 1 change(s)?', 0)
422
shelver.expect('Delete file "foo"? [yNfq?]', 'y')
423
shelver.expect('Apply 1 change(s)? [yNfq?]', 'y')
433
self.assertPathDoesNotExist('tree/foo')
425
self.failIfExists('tree/foo')
435
427
def test_shelve_kind_change(self):
436
428
tree = self.create_shelvable_tree()
439
431
tree.lock_tree_write()
440
432
self.addCleanup(tree.unlock)
441
433
shelver = ExpectShelver(tree, tree.basis_tree(),
442
reporter=shelf_ui.ApplyReporter())
434
reporter=shelf_ui.ApplyReporter())
443
435
self.addCleanup(shelver.finalize)
444
shelver.expect('Change "foo" from directory to a file?', 0)
445
shelver.expect('Apply 1 change(s)?', 0)
436
shelver.expect('Change "foo" from directory to a file? [yNfq?]', 'y')
437
shelver.expect('Apply 1 change(s)? [yNfq?]', 'y')
447
439
def test_shelve_modify_target(self):
448
self.requireFeature(features.SymlinkFeature)
440
self.requireFeature(tests.SymlinkFeature)
449
441
tree = self.create_shelvable_tree()
450
442
os.symlink('bar', 'tree/baz')
451
tree.add('baz', b'baz-id')
443
tree.add('baz', 'baz-id')
452
444
tree.commit("Add symlink")
453
445
os.unlink('tree/baz')
454
446
os.symlink('vax', 'tree/baz')
457
449
shelver = ExpectShelver(tree, tree.basis_tree(),
458
450
reporter=shelf_ui.ApplyReporter())
459
451
self.addCleanup(shelver.finalize)
460
shelver.expect('Change target of "baz" from "vax" to "bar"?',
462
shelver.expect('Apply 1 change(s)?', 0)
452
shelver.expect('Change target of "baz" from "vax" to "bar"? [yNfq?]',
454
shelver.expect('Apply 1 change(s)? [yNfq?]', 'y')
464
456
self.assertEqual('bar', os.readlink('tree/baz'))
471
463
tree.lock_write()
473
465
self.build_tree_contents([('tree/foo', LINES_AJ)])
474
tree.add('foo', b'foo-id')
466
tree.add('foo', 'foo-id')
475
467
tree.commit('added foo')
476
468
self.build_tree_contents([('tree/foo', LINES_ZY)])
477
469
shelver = shelf_ui.Shelver(tree, tree.basis_tree(),
516
508
def test_unshelve_args_preview(self):
517
509
tree = self.create_tree_with_shelf()
518
write_diff_to = BytesIO()
510
write_diff_to = StringIO()
519
511
unshelver = shelf_ui.Unshelver.from_args(
520
512
directory='tree', action='preview', write_diff_to=write_diff_to)
546
self.assertEqualDiff(expected.encode('utf-8'), diff[-len(expected):])
538
self.assertEqualDiff(expected, diff[-len(expected):])
548
540
def test_unshelve_args_delete_only(self):
549
541
tree = self.make_branch_and_tree('tree')
550
542
manager = tree.get_shelf_manager()
551
543
shelf_file = manager.new_shelf()[1]
553
shelf_file.write(b'garbage')
545
shelf_file.write('garbage')
555
547
shelf_file.close()
556
548
unshelver = shelf_ui.Unshelver.from_args(directory='tree',
566
558
manager = tree.get_shelf_manager()
567
559
shelf_file = manager.new_shelf()[1]
569
shelf_file.write(b'garbage')
561
shelf_file.write('garbage')
571
563
shelf_file.close()
572
self.assertRaises(shelf.InvalidShelfId,
573
shelf_ui.Unshelver.from_args, directory='tree',
574
action='delete-only', shelf_id='foo')
577
class TestUnshelveScripts(TestUnshelver,
578
script.TestCaseWithTransportAndScript):
564
self.assertRaises(errors.InvalidShelfId,
565
shelf_ui.Unshelver.from_args, directory='tree',
566
action='delete-only', shelf_id='foo')
569
class TestUnshelveScripts(TestUnshelver,
570
script.TestCaseWithTransportAndScript):
580
572
def test_unshelve_messages_keep(self):
581
573
self.create_tree_with_shelf()
582
574
self.run_script("""
584
$ brz unshelve --keep
576
$ bzr unshelve --keep
585
577
2>Using changes with id "1".
587
579
2>All changes applied successfully.