19
19
"""Black-box tests for bzr.
21
21
These check that it behaves properly when it's invoked through the regular
22
command-line interface. This doesn't actually run a new interpreter but
23
rather starts again from the run_bzr function.
22
command-line interface.
24
This always reinvokes bzr through a new Python interpreter, which is a
25
bit inefficient but arguably tests in a way more representative of how
26
it's normally invoked.
27
from cStringIO import StringIO
32
from bzrlib.selftest import TestCaseInTempDir, BzrTestBase
33
33
from bzrlib.branch import Branch
34
from bzrlib.errors import BzrCommandError
35
from bzrlib.osutils import has_symlinks
36
from bzrlib.selftest import TestCaseInTempDir, BzrTestBase
37
from bzrlib.selftest.HTTPTestUtil import TestCaseWithWebserver
34
from bzrlib.commands import run_bzr
40
37
class ExternalBase(TestCaseInTempDir):
42
def runbzr(self, args, retcode=0, backtick=False):
38
def runbzr(self, args, retcode=0,backtick=False):
43
39
if isinstance(args, basestring):
44
40
args = args.split()
47
return self.run_bzr_captured(args, retcode=retcode)[0]
43
return self.backtick(['python', self.BZRPATH,] + args,
49
return self.run_bzr_captured(args, retcode=retcode)
46
return self.runcmd(['python', self.BZRPATH,] + args,
52
50
class TestCommands(ExternalBase):
75
73
f = file('.bzr/email', 'wt')
76
74
f.write('Branch Identity <branch@identi.ty>')
78
bzr_email = os.environ.get('BZREMAIL')
79
if bzr_email is not None:
80
del os.environ['BZREMAIL']
81
76
whoami = self.runbzr("whoami",backtick=True)
82
77
whoami_email = self.runbzr("whoami --email",backtick=True)
83
78
self.assertTrue(whoami.startswith('Branch Identity <branch@identi.ty>'))
84
79
self.assertTrue(whoami_email.startswith('branch@identi.ty'))
85
# Verify that the environment variable overrides the value
87
os.environ['BZREMAIL'] = 'Different ID <other@environ.ment>'
88
whoami = self.runbzr("whoami",backtick=True)
89
whoami_email = self.runbzr("whoami --email",backtick=True)
90
self.assertTrue(whoami.startswith('Different ID <other@environ.ment>'))
91
self.assertTrue(whoami_email.startswith('other@environ.ment'))
92
if bzr_email is not None:
93
os.environ['BZREMAIL'] = bzr_email
95
81
def test_invalid_commands(self):
96
82
self.runbzr("pants", retcode=1)
104
90
self.runbzr("add hello.txt")
105
91
self.runbzr("commit -m added")
107
def test_empty_commit_message(self):
109
file('foo.c', 'wt').write('int main() {}')
110
self.runbzr(['add', 'foo.c'])
111
self.runbzr(["commit", "-m", ""] , retcode=1)
113
93
def test_ignore_patterns(self):
114
94
from bzrlib.branch import Branch
116
b = Branch.initialize('.')
96
b = Branch('.', init=True)
117
97
self.assertEquals(list(b.unknowns()), [])
119
99
file('foo.tmp', 'wt').write('tmp files are ignored')
120
100
self.assertEquals(list(b.unknowns()), [])
121
assert self.capture('unknowns') == ''
101
assert self.backtick('bzr unknowns') == ''
123
103
file('foo.c', 'wt').write('int main() {}')
124
104
self.assertEquals(list(b.unknowns()), ['foo.c'])
125
assert self.capture('unknowns') == 'foo.c\n'
105
assert self.backtick('bzr unknowns') == 'foo.c\n'
127
107
self.runbzr(['add', 'foo.c'])
128
assert self.capture('unknowns') == ''
108
assert self.backtick('bzr unknowns') == ''
130
110
# 'ignore' works when creating the .bzignore file
131
111
file('foo.blah', 'wt').write('blah')
132
112
self.assertEquals(list(b.unknowns()), ['foo.blah'])
133
113
self.runbzr('ignore *.blah')
134
114
self.assertEquals(list(b.unknowns()), [])
135
assert file('.bzrignore', 'rU').read() == '*.blah\n'
115
assert file('.bzrignore', 'rb').read() == '*.blah\n'
137
117
# 'ignore' works when then .bzrignore file already exists
138
118
file('garh', 'wt').write('garh')
139
119
self.assertEquals(list(b.unknowns()), ['garh'])
140
assert self.capture('unknowns') == 'garh\n'
120
assert self.backtick('bzr unknowns') == 'garh\n'
141
121
self.runbzr('ignore garh')
142
122
self.assertEquals(list(b.unknowns()), [])
143
assert file('.bzrignore', 'rU').read() == '*.blah\ngarh\n'
123
assert file('.bzrignore', 'rb').read() == '*.blah\ngarh\n'
145
125
def test_revert(self):
146
126
self.runbzr('init')
167
147
os.rmdir('revertdir')
168
148
self.runbzr('revert')
170
os.symlink('/unlikely/to/exist', 'symlink')
171
self.runbzr('add symlink')
172
self.runbzr('commit -m f')
174
self.runbzr('revert')
176
file('hello', 'wt').write('xyz')
177
self.runbzr('commit -m xyz hello')
178
self.runbzr('revert -r 1 hello')
179
self.check_file_contents('hello', 'foo')
180
self.runbzr('revert hello')
181
self.check_file_contents('hello', 'xyz')
182
os.chdir('revertdir')
183
self.runbzr('revert')
187
150
def test_mv_modes(self):
188
151
"""Test two modes of operation for mv"""
189
152
from bzrlib.branch import Branch
190
b = Branch.initialize('.')
153
b = Branch('.', init=True)
191
154
self.build_tree(['a', 'c', 'subdir/'])
192
self.run_bzr_captured(['add', self.test_dir])
193
self.run_bzr_captured(['mv', 'a', 'b'])
194
self.run_bzr_captured(['mv', 'b', 'subdir'])
195
self.run_bzr_captured(['mv', 'subdir/b', 'a'])
196
self.run_bzr_captured(['mv', 'a', 'c', 'subdir'])
197
self.run_bzr_captured(['mv', 'subdir/a', 'subdir/newa'])
155
self.run_bzr('add', self.test_dir)
156
self.run_bzr('mv', 'a', 'b')
157
self.run_bzr('mv', 'b', 'subdir')
158
self.run_bzr('mv', 'subdir/b', 'a')
159
self.run_bzr('mv', 'a', 'c', 'subdir')
160
self.run_bzr('mv', 'subdir/a', 'subdir/newa')
199
163
def test_main_version(self):
200
164
"""Check output from version command and master option is reasonable"""
220
184
test.runbzr('add goodbye')
221
185
test.runbzr('commit -m setup goodbye')
223
def test_export(self):
226
self.example_branch()
227
self.runbzr('export ../latest')
228
self.assertEqual(file('../latest/goodbye', 'rt').read(), 'baz')
229
self.runbzr('export ../first -r 1')
230
assert not os.path.exists('../first/goodbye')
231
self.assertEqual(file('../first/hello', 'rt').read(), 'foo')
232
self.runbzr('export ../first.gz -r 1')
233
self.assertEqual(file('../first.gz/hello', 'rt').read(), 'foo')
234
self.runbzr('export ../first.bz2 -r 1')
235
self.assertEqual(file('../first.bz2/hello', 'rt').read(), 'foo')
236
self.runbzr('export ../first.tar -r 1')
237
assert os.path.isfile('../first.tar')
238
from tarfile import TarFile
239
tf = TarFile('../first.tar')
240
assert 'first/hello' in tf.getnames(), tf.getnames()
241
self.assertEqual(tf.extractfile('first/hello').read(), 'foo')
242
self.runbzr('export ../first.tar.gz -r 1')
243
assert os.path.isfile('../first.tar.gz')
244
self.runbzr('export ../first.tbz2 -r 1')
245
assert os.path.isfile('../first.tbz2')
246
self.runbzr('export ../first.tar.bz2 -r 1')
247
assert os.path.isfile('../first.tar.bz2')
248
self.runbzr('export ../first.tar.tbz2 -r 1')
249
assert os.path.isfile('../first.tar.tbz2')
250
from bz2 import BZ2File
251
tf = TarFile('../first.tar.tbz2',
252
fileobj=BZ2File('../first.tar.tbz2', 'r'))
253
assert 'first.tar/hello' in tf.getnames(), tf.getnames()
254
self.assertEqual(tf.extractfile('first.tar/hello').read(), 'foo')
255
self.runbzr('export ../first2.tar -r 1 --root pizza')
256
tf = TarFile('../first2.tar')
257
assert 'pizza/hello' in tf.getnames(), tf.getnames()
260
self.example_branch()
261
file('hello', 'wt').write('hello world!')
262
self.runbzr('commit -m fixing hello')
263
output = self.runbzr('diff -r 2..3', backtick=1)
264
self.assert_('\n+hello world!' in output)
265
output = self.runbzr('diff -r last:3..last:1', backtick=1)
266
self.assert_('\n+baz' in output)
268
def test_branch(self):
269
"""Branch from one branch to another."""
272
self.example_branch()
274
self.runbzr('branch a b')
275
self.runbzr('branch a c -r 1')
277
self.runbzr('commit -m foo --unchanged')
279
# naughty - abstraction violations RBC 20050928
280
print "test_branch used to delete the stores, how is this meant to work ?"
281
#shutil.rmtree('a/.bzr/revision-store')
282
#shutil.rmtree('a/.bzr/inventory-store', ignore_errors=True)
283
#shutil.rmtree('a/.bzr/text-store', ignore_errors=True)
284
self.runbzr('branch a d --basis b')
187
def test_revert(self):
188
self.example_branch()
189
file('hello', 'wt').write('bar')
190
file('goodbye', 'wt').write('qux')
191
self.runbzr('revert hello')
192
self.check_file_contents('hello', 'foo')
193
self.check_file_contents('goodbye', 'qux')
194
self.runbzr('revert')
195
self.check_file_contents('goodbye', 'baz')
286
197
def test_merge(self):
287
198
from bzrlib.branch import Branch
303
214
self.runbzr('merge ../b')
304
215
self.check_file_contents('goodbye', 'quux')
305
216
# Merging a branch pulls its revision into the tree
307
b = Branch.open('../b')
308
a.get_revision_xml(b.last_revision())
219
a.get_revision_xml(b.last_patch())
309
220
self.log('pending merges: %s', a.pending_merges())
310
# assert a.pending_merges() == [b.last_revision()], "Assertion %s %s" \
311
# % (a.pending_merges(), b.last_revision())
313
def test_merge_with_missing_file(self):
314
"""Merge handles missing file conflicts"""
318
print >> file('sub/a.txt', 'wb'), "hello"
319
print >> file('b.txt', 'wb'), "hello"
320
print >> file('sub/c.txt', 'wb'), "hello"
323
self.runbzr(('commit', '-m', 'added a'))
324
self.runbzr('branch . ../b')
325
print >> file('sub/a.txt', 'ab'), "there"
326
print >> file('b.txt', 'ab'), "there"
327
print >> file('sub/c.txt', 'ab'), "there"
328
self.runbzr(('commit', '-m', 'Added there'))
329
os.unlink('sub/a.txt')
330
os.unlink('sub/c.txt')
333
self.runbzr(('commit', '-m', 'Removed a.txt'))
335
print >> file('sub/a.txt', 'ab'), "something"
336
print >> file('b.txt', 'ab'), "something"
337
print >> file('sub/c.txt', 'ab'), "something"
338
self.runbzr(('commit', '-m', 'Modified a.txt'))
339
self.runbzr('merge ../a/')
340
assert os.path.exists('sub/a.txt.THIS')
341
assert os.path.exists('sub/a.txt.BASE')
343
self.runbzr('merge ../b/')
344
assert os.path.exists('sub/a.txt.OTHER')
345
assert os.path.exists('sub/a.txt.BASE')
221
# assert a.pending_merges() == [b.last_patch()], "Assertion %s %s" \
222
# % (a.pending_merges(), b.last_patch())
347
224
def test_pull(self):
348
225
"""Pull changes from one branch to another."""
376
251
self.runbzr('commit -m blah3 --unchanged')
377
252
self.runbzr('pull ../a', retcode=1)
378
print "DECIDE IF PULL CAN CONVERGE, blackbox.py"
381
254
self.runbzr('merge ../b')
382
255
self.runbzr('commit -m blah4 --unchanged')
383
os.chdir('../b/subdir')
384
self.runbzr('pull ../../a')
257
self.runbzr('pull ../a')
385
258
assert a.revision_history()[-1] == b.revision_history()[-1]
386
self.runbzr('commit -m blah5 --unchanged')
387
self.runbzr('commit -m blah6 --unchanged')
389
self.runbzr('pull ../a')
391
self.runbzr('commit -m blah7 --unchanged')
392
self.runbzr('merge ../b')
393
self.runbzr('commit -m blah8 --unchanged')
394
self.runbzr('pull ../b')
395
self.runbzr('pull ../b')
397
261
def test_add_reports(self):
398
262
"""add command prints the names of added files."""
399
b = Branch.initialize('.')
263
b = Branch('.', init=True)
400
264
self.build_tree(['top.txt', 'dir/', 'dir/sub.txt'])
401
out = self.run_bzr_captured(['add'], retcode = 0)[0]
266
from cStringIO import StringIO
269
ret = self.apply_redirected(None, out, None,
272
self.assertEquals(ret, 0)
402
274
# the ordering is not defined at the moment
403
results = sorted(out.rstrip('\n').split('\n'))
275
results = sorted(out.getvalue().rstrip('\n').split('\n'))
404
276
self.assertEquals(['added dir',
405
'added dir'+os.sep+'sub.txt',
406
278
'added top.txt',],
409
def test_unknown_command(self):
410
"""Handling of unknown command."""
411
out, err = self.run_bzr_captured(['fluffy-badger'],
413
self.assertEquals(out, '')
414
err.index('unknown command')
417
def listdir_sorted(dir):
423
282
class OldTests(ExternalBase):
424
283
"""old tests moved from ./testbzr."""
445
304
f.write('hello world!\n')
448
self.assertEquals(capture('unknowns'), 'test.txt\n')
307
out = backtick("bzr unknowns")
308
self.assertEquals(out, 'test.txt\n')
450
out = capture("status")
310
out = backtick("bzr status")
451
311
assert out == 'unknown:\n test.txt\n'
453
out = capture("status --all")
313
out = backtick("bzr status --all")
454
314
assert out == "unknown:\n test.txt\n"
456
out = capture("status test.txt --all")
316
out = backtick("bzr status test.txt --all")
457
317
assert out == "unknown:\n test.txt\n"
459
319
f = file('test2.txt', 'wt')
460
320
f.write('goodbye cruel world...\n')
463
out = capture("status test.txt")
323
out = backtick("bzr status test.txt")
464
324
assert out == "unknown:\n test.txt\n"
466
out = capture("status")
326
out = backtick("bzr status")
467
327
assert out == ("unknown:\n"
538
398
runbzr(['commit', '-m', 'rename nested subdirectories'])
540
400
chdir('sub1/sub2')
541
self.assertEquals(capture('root')[:-1],
401
self.assertEquals(backtick('bzr root')[:-1],
542
402
os.path.join(self.test_dir, 'branch1'))
543
403
runbzr('move ../hello.txt .')
544
404
assert exists('./hello.txt')
545
self.assertEquals(capture('relpath hello.txt'),
546
os.path.join('sub1', 'sub2', 'hello.txt') + '\n')
547
assert capture('relpath ../../sub1/sub2/hello.txt') == os.path.join('sub1', 'sub2', 'hello.txt\n')
405
assert backtick('bzr relpath hello.txt') == os.path.join('sub1', 'sub2', 'hello.txt\n')
406
assert backtick('bzr relpath ../../sub1/sub2/hello.txt') == os.path.join('sub1', 'sub2', 'hello.txt\n')
548
407
runbzr(['commit', '-m', 'move to parent directory'])
550
assert capture('relpath sub2/hello.txt') == os.path.join('sub1', 'sub2', 'hello.txt\n')
409
assert backtick('bzr relpath sub2/hello.txt') == os.path.join('sub1', 'sub2', 'hello.txt\n')
552
411
runbzr('move sub2/hello.txt .')
553
412
assert exists('hello.txt')
598
os.symlink("NOWHERE1", "link1")
600
assert self.capture('unknowns') == ''
601
runbzr(['commit', '-m', '1: added symlink link1'])
605
assert self.capture('unknowns') == ''
606
os.symlink("NOWHERE2", "d1/link2")
607
assert self.capture('unknowns') == 'd1/link2\n'
608
# is d1/link2 found when adding d1
610
assert self.capture('unknowns') == ''
611
os.symlink("NOWHERE3", "d1/link3")
612
assert self.capture('unknowns') == 'd1/link3\n'
613
runbzr(['commit', '-m', '2: added dir, symlink'])
615
runbzr('rename d1 d2')
616
runbzr('move d2/link2 .')
617
runbzr('move link1 d2')
618
assert os.readlink("./link2") == "NOWHERE2"
619
assert os.readlink("d2/link1") == "NOWHERE1"
620
runbzr('add d2/link3')
622
runbzr(['commit', '-m', '3: rename of dir, move symlinks, add link3'])
625
os.symlink("TARGET 2", "link2")
626
os.unlink("d2/link1")
627
os.symlink("TARGET 1", "d2/link1")
629
assert self.capture("relpath d2/link1") == "d2/link1\n"
630
runbzr(['commit', '-m', '4: retarget of two links'])
632
runbzr('remove d2/link1')
633
assert self.capture('unknowns') == 'd2/link1\n'
634
runbzr(['commit', '-m', '5: remove d2/link1'])
638
runbzr('rename d2/link3 d1/link3new')
639
assert self.capture('unknowns') == 'd2/link1\n'
640
runbzr(['commit', '-m', '6: remove d2/link1, move/rename link3'])
644
runbzr(['export', '-r', '1', 'exp1.tmp'])
646
assert listdir_sorted(".") == [ "link1" ]
647
assert os.readlink("link1") == "NOWHERE1"
650
runbzr(['export', '-r', '2', 'exp2.tmp'])
652
assert listdir_sorted(".") == [ "d1", "link1" ]
655
runbzr(['export', '-r', '3', 'exp3.tmp'])
657
assert listdir_sorted(".") == [ "d2", "link2" ]
658
assert listdir_sorted("d2") == [ "link1", "link3" ]
659
assert os.readlink("d2/link1") == "NOWHERE1"
660
assert os.readlink("link2") == "NOWHERE2"
663
runbzr(['export', '-r', '4', 'exp4.tmp'])
665
assert listdir_sorted(".") == [ "d2", "link2" ]
666
assert os.readlink("d2/link1") == "TARGET 1"
667
assert os.readlink("link2") == "TARGET 2"
668
assert listdir_sorted("d2") == [ "link1", "link3" ]
671
runbzr(['export', '-r', '5', 'exp5.tmp'])
673
assert listdir_sorted(".") == [ "d2", "link2" ]
674
assert os.path.islink("link2")
675
assert listdir_sorted("d2")== [ "link3" ]
678
runbzr(['export', '-r', '6', 'exp6.tmp'])
680
assert listdir_sorted(".") == [ "d1", "d2", "link2" ]
681
assert listdir_sorted("d1") == [ "link3new" ]
682
assert listdir_sorted("d2") == []
683
assert os.readlink("d1/link3new") == "NOWHERE3"
686
progress("skipping symlink tests")
689
class HttpTests(TestCaseWithWebserver):
690
"""Test bzr ui commands against remote branches."""
692
def test_branch(self):
694
branch = Branch.initialize('from')
695
branch.commit('empty commit for nonsense', allow_pointless=True)
696
url = self.get_remote_url('from')
697
self.run_bzr('branch', url, 'to')
698
branch = Branch.open('to')
699
self.assertEqual(1, len(branch.revision_history()))