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