1
# Copyright (C) 2005 by Canonical Ltd
2
# -*- coding: utf-8 -*-
4
# This program is free software; you can redistribute it and/or modify
5
# it under the terms of the GNU General Public License as published by
6
# the Free Software Foundation; either version 2 of the License, or
7
# (at your option) any later version.
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
# GNU General Public License for more details.
14
# You should have received a copy of the GNU General Public License
15
# along with this program; if not, write to the Free Software
16
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
"""Black-box tests for bzr.
21
These check that it behaves properly when it's invoked through the regular
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.
29
from cStringIO import StringIO
34
from bzrlib.selftest import TestCaseInTempDir, BzrTestBase
35
from bzrlib.branch import Branch
36
from bzrlib.errors import BzrCommandError
39
class ExternalBase(TestCaseInTempDir):
41
def runbzr(self, args, retcode=0, backtick=False):
42
if isinstance(args, basestring):
46
return self.run_bzr_captured(args, retcode=retcode)[0]
48
return self.run_bzr_captured(args, retcode=retcode)
51
class TestCommands(ExternalBase):
53
def test_help_commands(self):
56
self.runbzr('help commands')
57
self.runbzr('help help')
58
self.runbzr('commit -h')
60
def test_init_branch(self):
63
def test_whoami(self):
64
# this should always identify something, if only "john@localhost"
66
self.runbzr("whoami --email")
68
self.assertEquals(self.runbzr("whoami --email",
69
backtick=True).count('@'), 1)
71
def test_whoami_branch(self):
72
"""branch specific user identity works."""
74
f = file('.bzr/email', 'wt')
75
f.write('Branch Identity <branch@identi.ty>')
77
bzr_email = os.environ.get('BZREMAIL')
78
if bzr_email is not None:
79
del os.environ['BZREMAIL']
80
whoami = self.runbzr("whoami",backtick=True)
81
whoami_email = self.runbzr("whoami --email",backtick=True)
82
self.assertTrue(whoami.startswith('Branch Identity <branch@identi.ty>'))
83
self.assertTrue(whoami_email.startswith('branch@identi.ty'))
84
# Verify that the environment variable overrides the value
86
os.environ['BZREMAIL'] = 'Different ID <other@environ.ment>'
87
whoami = self.runbzr("whoami",backtick=True)
88
whoami_email = self.runbzr("whoami --email",backtick=True)
89
self.assertTrue(whoami.startswith('Different ID <other@environ.ment>'))
90
self.assertTrue(whoami_email.startswith('other@environ.ment'))
91
if bzr_email is not None:
92
os.environ['BZREMAIL'] = bzr_email
94
def test_invalid_commands(self):
95
self.runbzr("pants", retcode=1)
96
self.runbzr("--pants off", retcode=1)
97
self.runbzr("diff --message foo", retcode=1)
99
def test_empty_commit(self):
101
self.build_tree(['hello.txt'])
102
self.runbzr("commit -m empty", retcode=1)
103
self.runbzr("add hello.txt")
104
self.runbzr("commit -m added")
106
def test_empty_commit_message(self):
107
os.environ['BZR_EDITOR'] = 'touch'
109
file('foo.c', 'wt').write('int main() {}')
110
self.runbzr(['add', 'foo.c'])
111
self.runbzr("commit", retcode=1)
113
def test_ignore_patterns(self):
114
from bzrlib.branch import Branch
116
b = Branch.initialize('.')
117
self.assertEquals(list(b.unknowns()), [])
119
file('foo.tmp', 'wt').write('tmp files are ignored')
120
self.assertEquals(list(b.unknowns()), [])
121
assert self.capture('unknowns') == ''
123
file('foo.c', 'wt').write('int main() {}')
124
self.assertEquals(list(b.unknowns()), ['foo.c'])
125
assert self.capture('unknowns') == 'foo.c\n'
127
self.runbzr(['add', 'foo.c'])
128
assert self.capture('unknowns') == ''
130
# 'ignore' works when creating the .bzignore file
131
file('foo.blah', 'wt').write('blah')
132
self.assertEquals(list(b.unknowns()), ['foo.blah'])
133
self.runbzr('ignore *.blah')
134
self.assertEquals(list(b.unknowns()), [])
135
assert file('.bzrignore', 'rU').read() == '*.blah\n'
137
# 'ignore' works when then .bzrignore file already exists
138
file('garh', 'wt').write('garh')
139
self.assertEquals(list(b.unknowns()), ['garh'])
140
assert self.capture('unknowns') == 'garh\n'
141
self.runbzr('ignore garh')
142
self.assertEquals(list(b.unknowns()), [])
143
assert file('.bzrignore', 'rU').read() == '*.blah\ngarh\n'
145
def test_revert(self):
148
file('hello', 'wt').write('foo')
149
self.runbzr('add hello')
150
self.runbzr('commit -m setup hello')
152
file('goodbye', 'wt').write('baz')
153
self.runbzr('add goodbye')
154
self.runbzr('commit -m setup goodbye')
156
file('hello', 'wt').write('bar')
157
file('goodbye', 'wt').write('qux')
158
self.runbzr('revert hello')
159
self.check_file_contents('hello', 'foo')
160
self.check_file_contents('goodbye', 'qux')
161
self.runbzr('revert')
162
self.check_file_contents('goodbye', 'baz')
164
os.mkdir('revertdir')
165
self.runbzr('add revertdir')
166
self.runbzr('commit -m f')
167
os.rmdir('revertdir')
168
self.runbzr('revert')
170
file('hello', 'wt').write('xyz')
171
self.runbzr('commit -m xyz hello')
172
self.runbzr('revert -r 1 hello')
173
self.check_file_contents('hello', 'foo')
174
self.runbzr('revert hello')
175
self.check_file_contents('hello', 'xyz')
176
os.chdir('revertdir')
177
self.runbzr('revert')
181
def test_mv_modes(self):
182
"""Test two modes of operation for mv"""
183
from bzrlib.branch import Branch
184
b = Branch.initialize('.')
185
self.build_tree(['a', 'c', 'subdir/'])
186
self.run_bzr_captured(['add', self.test_dir])
187
self.run_bzr_captured(['mv', 'a', 'b'])
188
self.run_bzr_captured(['mv', 'b', 'subdir'])
189
self.run_bzr_captured(['mv', 'subdir/b', 'a'])
190
self.run_bzr_captured(['mv', 'a', 'c', 'subdir'])
191
self.run_bzr_captured(['mv', 'subdir/a', 'subdir/newa'])
194
def test_main_version(self):
195
"""Check output from version command and master option is reasonable"""
196
# output is intentionally passed through to stdout so that we
197
# can see the version being tested
198
output = self.runbzr('version', backtick=1)
199
self.log('bzr version output:')
201
self.assert_(output.startswith('bzr (bazaar-ng) '))
202
self.assertNotEqual(output.index('Canonical'), -1)
203
# make sure --version is consistent
204
tmp_output = self.runbzr('--version', backtick=1)
205
self.log('bzr --version output:')
207
self.assertEquals(output, tmp_output)
209
def example_branch(test):
211
file('hello', 'wt').write('foo')
212
test.runbzr('add hello')
213
test.runbzr('commit -m setup hello')
214
file('goodbye', 'wt').write('baz')
215
test.runbzr('add goodbye')
216
test.runbzr('commit -m setup goodbye')
218
def test_export(self):
221
self.example_branch()
222
self.runbzr('export ../latest')
223
self.assertEqual(file('../latest/goodbye', 'rt').read(), 'baz')
224
self.runbzr('export ../first -r 1')
225
assert not os.path.exists('../first/goodbye')
226
self.assertEqual(file('../first/hello', 'rt').read(), 'foo')
227
self.runbzr('export ../first.gz -r 1')
228
self.assertEqual(file('../first.gz/hello', 'rt').read(), 'foo')
229
self.runbzr('export ../first.bz2 -r 1')
230
self.assertEqual(file('../first.bz2/hello', 'rt').read(), 'foo')
231
self.runbzr('export ../first.tar -r 1')
232
assert os.path.isfile('../first.tar')
233
from tarfile import TarFile
234
tf = TarFile('../first.tar')
235
assert 'first/hello' in tf.getnames(), tf.getnames()
236
self.assertEqual(tf.extractfile('first/hello').read(), 'foo')
237
self.runbzr('export ../first.tar.gz -r 1')
238
assert os.path.isfile('../first.tar.gz')
239
self.runbzr('export ../first.tbz2 -r 1')
240
assert os.path.isfile('../first.tbz2')
241
self.runbzr('export ../first.tar.bz2 -r 1')
242
assert os.path.isfile('../first.tar.bz2')
243
self.runbzr('export ../first.tar.tbz2 -r 1')
244
assert os.path.isfile('../first.tar.tbz2')
245
from bz2 import BZ2File
246
tf = TarFile('../first.tar.tbz2',
247
fileobj=BZ2File('../first.tar.tbz2', 'r'))
248
assert 'first.tar/hello' in tf.getnames(), tf.getnames()
249
self.assertEqual(tf.extractfile('first.tar/hello').read(), 'foo')
250
self.runbzr('export ../first2.tar -r 1 --root pizza')
251
tf = TarFile('../first2.tar')
252
assert 'pizza/hello' in tf.getnames(), tf.getnames()
255
self.example_branch()
256
file('hello', 'wt').write('hello world!')
257
self.runbzr('commit -m fixing hello')
258
output = self.runbzr('diff -r 2..3', backtick=1)
259
self.assert_('\n+hello world!' in output)
260
output = self.runbzr('diff -r last:3..last:1', backtick=1)
261
self.assert_('\n+baz' in output)
263
def test_branch(self):
264
"""Branch from one branch to another."""
267
self.example_branch()
269
self.runbzr('branch a b')
270
self.runbzr('branch a c -r 1')
272
self.runbzr('commit -m foo --unchanged')
274
# naughty - abstraction violations RBC 20050928
275
print "test_branch used to delete the stores, how is this meant to work ?"
276
#shutil.rmtree('a/.bzr/revision-store')
277
#shutil.rmtree('a/.bzr/inventory-store', ignore_errors=True)
278
#shutil.rmtree('a/.bzr/text-store', ignore_errors=True)
279
self.runbzr('branch a d --basis b')
281
def test_merge(self):
282
from bzrlib.branch import Branch
286
self.example_branch()
288
self.runbzr('branch a b')
290
file('goodbye', 'wt').write('quux')
291
self.runbzr(['commit', '-m', "more u's are always good"])
294
file('hello', 'wt').write('quuux')
295
# We can't merge when there are in-tree changes
296
self.runbzr('merge ../b', retcode=1)
297
self.runbzr(['commit', '-m', "Like an epidemic of u's"])
298
self.runbzr('merge ../b')
299
self.check_file_contents('goodbye', 'quux')
300
# Merging a branch pulls its revision into the tree
302
b = Branch.open('../b')
303
a.get_revision_xml(b.last_revision())
304
self.log('pending merges: %s', a.pending_merges())
305
# assert a.pending_merges() == [b.last_revision()], "Assertion %s %s" \
306
# % (a.pending_merges(), b.last_revision())
308
def test_merge_with_missing_file(self):
309
"""Merge handles missing file conflicts"""
313
print >> file('sub/a.txt', 'wb'), "hello"
314
print >> file('b.txt', 'wb'), "hello"
315
print >> file('sub/c.txt', 'wb'), "hello"
318
self.runbzr(('commit', '-m', 'added a'))
319
self.runbzr('branch . ../b')
320
print >> file('sub/a.txt', 'ab'), "there"
321
print >> file('b.txt', 'ab'), "there"
322
print >> file('sub/c.txt', 'ab'), "there"
323
self.runbzr(('commit', '-m', 'Added there'))
324
os.unlink('sub/a.txt')
325
os.unlink('sub/c.txt')
328
self.runbzr(('commit', '-m', 'Removed a.txt'))
330
print >> file('sub/a.txt', 'ab'), "something"
331
print >> file('b.txt', 'ab'), "something"
332
print >> file('sub/c.txt', 'ab'), "something"
333
self.runbzr(('commit', '-m', 'Modified a.txt'))
334
self.runbzr('merge ../a/')
335
assert os.path.exists('sub/a.txt.THIS')
336
assert os.path.exists('sub/a.txt.BASE')
338
self.runbzr('merge ../b/')
339
assert os.path.exists('sub/a.txt.OTHER')
340
assert os.path.exists('sub/a.txt.BASE')
343
"""Pull changes from one branch to another."""
347
self.example_branch()
348
self.runbzr('pull', retcode=1)
349
self.runbzr('missing', retcode=1)
350
self.runbzr('missing .')
351
self.runbzr('missing')
353
self.runbzr('pull /', retcode=1)
357
self.runbzr('branch a b')
361
self.runbzr('add subdir')
362
self.runbzr('commit -m blah --unchanged')
365
b = Branch.open('../b')
366
assert a.revision_history() == b.revision_history()[:-1]
367
self.runbzr('pull ../b')
368
assert a.revision_history() == b.revision_history()
369
self.runbzr('commit -m blah2 --unchanged')
371
self.runbzr('commit -m blah3 --unchanged')
372
self.runbzr('pull ../a', retcode=1)
373
print "DECIDE IF PULL CAN CONVERGE, blackbox.py"
376
self.runbzr('merge ../b')
377
self.runbzr('commit -m blah4 --unchanged')
378
os.chdir('../b/subdir')
379
self.runbzr('pull ../../a')
380
assert a.revision_history()[-1] == b.revision_history()[-1]
381
self.runbzr('commit -m blah5 --unchanged')
382
self.runbzr('commit -m blah6 --unchanged')
384
self.runbzr('pull ../a')
386
self.runbzr('commit -m blah7 --unchanged')
387
self.runbzr('merge ../b')
388
self.runbzr('commit -m blah8 --unchanged')
389
self.runbzr('pull ../b')
390
self.runbzr('pull ../b')
392
def test_add_reports(self):
393
"""add command prints the names of added files."""
394
b = Branch.initialize('.')
395
self.build_tree(['top.txt', 'dir/', 'dir/sub.txt'])
396
out = self.run_bzr_captured(['add'], retcode = 0)[0]
397
# the ordering is not defined at the moment
398
results = sorted(out.rstrip('\n').split('\n'))
399
self.assertEquals(['added dir',
400
'added dir'+os.sep+'sub.txt',
404
def test_unknown_command(self):
405
"""Handling of unknown command."""
406
out, err = self.run_bzr_captured(['fluffy-badger'],
408
self.assertEquals(out, '')
409
err.index('unknown command')
413
class OldTests(ExternalBase):
414
"""old tests moved from ./testbzr."""
417
from os import chdir, mkdir
418
from os.path import exists
421
capture = self.capture
424
progress("basic branch creation")
429
self.assertEquals(capture('root').rstrip(),
430
os.path.join(self.test_dir, 'branch1'))
432
progress("status of new file")
434
f = file('test.txt', 'wt')
435
f.write('hello world!\n')
438
self.assertEquals(capture('unknowns'), 'test.txt\n')
440
out = capture("status")
441
assert out == 'unknown:\n test.txt\n'
443
out = capture("status --all")
444
assert out == "unknown:\n test.txt\n"
446
out = capture("status test.txt --all")
447
assert out == "unknown:\n test.txt\n"
449
f = file('test2.txt', 'wt')
450
f.write('goodbye cruel world...\n')
453
out = capture("status test.txt")
454
assert out == "unknown:\n test.txt\n"
456
out = capture("status")
457
assert out == ("unknown:\n"
461
os.unlink('test2.txt')
463
progress("command aliases")
464
out = capture("st --all")
465
assert out == ("unknown:\n"
468
out = capture("stat")
469
assert out == ("unknown:\n"
472
progress("command help")
475
runbzr("help commands")
476
runbzr("help slartibartfast", 1)
478
out = capture("help ci")
479
out.index('aliases: ')
481
progress("can't rename unversioned file")
482
runbzr("rename test.txt new-test.txt", 1)
484
progress("adding a file")
486
runbzr("add test.txt")
487
assert capture("unknowns") == ''
488
assert capture("status --all") == ("added:\n"
491
progress("rename newly-added file")
492
runbzr("rename test.txt hello.txt")
493
assert os.path.exists("hello.txt")
494
assert not os.path.exists("test.txt")
496
assert capture("revno") == '0\n'
498
progress("add first revision")
499
runbzr(['commit', '-m', 'add first revision'])
501
progress("more complex renames")
503
runbzr("rename hello.txt sub1", 1)
504
runbzr("rename hello.txt sub1/hello.txt", 1)
505
runbzr("move hello.txt sub1", 1)
508
runbzr("rename sub1 sub2")
509
runbzr("move hello.txt sub2")
510
assert capture("relpath sub2/hello.txt") == os.path.join("sub2", "hello.txt\n")
512
assert exists("sub2")
513
assert exists("sub2/hello.txt")
514
assert not exists("sub1")
515
assert not exists("hello.txt")
517
runbzr(['commit', '-m', 'commit with some things moved to subdirs'])
521
runbzr('move sub2/hello.txt sub1')
522
assert not exists('sub2/hello.txt')
523
assert exists('sub1/hello.txt')
524
runbzr('move sub2 sub1')
525
assert not exists('sub2')
526
assert exists('sub1/sub2')
528
runbzr(['commit', '-m', 'rename nested subdirectories'])
531
self.assertEquals(capture('root')[:-1],
532
os.path.join(self.test_dir, 'branch1'))
533
runbzr('move ../hello.txt .')
534
assert exists('./hello.txt')
535
self.assertEquals(capture('relpath hello.txt'),
536
os.path.join('sub1', 'sub2', 'hello.txt') + '\n')
537
assert capture('relpath ../../sub1/sub2/hello.txt') == os.path.join('sub1', 'sub2', 'hello.txt\n')
538
runbzr(['commit', '-m', 'move to parent directory'])
540
assert capture('relpath sub2/hello.txt') == os.path.join('sub1', 'sub2', 'hello.txt\n')
542
runbzr('move sub2/hello.txt .')
543
assert exists('hello.txt')
545
f = file('hello.txt', 'wt')
546
f.write('some nice new content\n')
549
f = file('msg.tmp', 'wt')
550
f.write('this is my new commit\n')
553
runbzr('commit -F msg.tmp')
555
assert capture('revno') == '5\n'
556
runbzr('export -r 5 export-5.tmp')
557
runbzr('export export.tmp')
561
runbzr('log -v --forward')
562
runbzr('log -m', retcode=1)
563
log_out = capture('log -m commit')
564
assert "this is my new commit" in log_out
565
assert "rename nested" not in log_out
566
assert 'revision-id' not in log_out
567
assert 'revision-id' in capture('log --show-ids -m commit')
570
progress("file with spaces in name")
571
mkdir('sub directory')
572
file('sub directory/file with spaces ', 'wt').write('see how this works\n')
575
runbzr('commit -m add-spaces')
579
runbzr('log --forward')