1
# Copyright (C) 2005-2010 Canonical Ltd
1
# Copyright (C) 2005 by Canonical Ltd
2
# -*- coding: utf-8 -*-
3
4
# This program is free software; you can redistribute it and/or modify
4
5
# it under the terms of the GNU General Public License as published by
5
6
# the Free Software Foundation; either version 2 of the License, or
6
7
# (at your option) any later version.
8
9
# This program is distributed in the hope that it will be useful,
9
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
12
# GNU General Public License for more details.
13
14
# You should have received a copy of the GNU General Public License
14
15
# 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
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
# Mr. Smoketoomuch: I'm sorry?
18
# Mr. Bounder: You'd better cut down a little then.
19
# Mr. Smoketoomuch: Oh, I see! Smoke too much so I'd better cut down a little
22
19
"""Black-box tests for bzr.
24
21
These check that it behaves properly when it's invoked through the regular
25
command-line interface. This doesn't actually run a new interpreter but
26
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.
30
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
31
# Note: Please don't add new tests here, it's too big and bulky. Instead add
32
# them into small suites in bzrlib.tests.blackbox.test_FOO for the particular
33
# UI command/aspect that is being tested.
36
29
from cStringIO import StringIO
35
from bzrlib.selftest import TestCaseInTempDir, BzrTestBase
45
36
from bzrlib.branch import Branch
46
from bzrlib.errors import BzrCommandError
47
from bzrlib.tests.http_utils import TestCaseWithWebserver
48
from bzrlib.tests.test_sftp_transport import TestCaseWithSFTPServer
49
from bzrlib.tests.blackbox import ExternalBase
50
from bzrlib.workingtree import WorkingTree
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)
53
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
55
94
def test_invalid_commands(self):
56
self.run_bzr("pants", retcode=3)
57
self.run_bzr("--pants off", retcode=3)
58
self.run_bzr("diff --message foo", retcode=3)
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_ignore_patterns(self):
107
from bzrlib.branch import Branch
109
b = Branch.initialize('.')
110
self.assertEquals(list(b.unknowns()), [])
112
file('foo.tmp', 'wt').write('tmp files are ignored')
113
self.assertEquals(list(b.unknowns()), [])
114
assert self.capture('unknowns') == ''
116
file('foo.c', 'wt').write('int main() {}')
117
self.assertEquals(list(b.unknowns()), ['foo.c'])
118
assert self.capture('unknowns') == 'foo.c\n'
120
self.runbzr(['add', 'foo.c'])
121
assert self.capture('unknowns') == ''
123
# 'ignore' works when creating the .bzignore file
124
file('foo.blah', 'wt').write('blah')
125
self.assertEquals(list(b.unknowns()), ['foo.blah'])
126
self.runbzr('ignore *.blah')
127
self.assertEquals(list(b.unknowns()), [])
128
assert file('.bzrignore', 'rU').read() == '*.blah\n'
130
# 'ignore' works when then .bzrignore file already exists
131
file('garh', 'wt').write('garh')
132
self.assertEquals(list(b.unknowns()), ['garh'])
133
assert self.capture('unknowns') == 'garh\n'
134
self.runbzr('ignore garh')
135
self.assertEquals(list(b.unknowns()), [])
136
assert file('.bzrignore', 'rU').read() == '*.blah\ngarh\n'
60
138
def test_revert(self):
63
141
file('hello', 'wt').write('foo')
64
self.run_bzr('add hello')
65
self.run_bzr('commit -m setup hello')
142
self.runbzr('add hello')
143
self.runbzr('commit -m setup hello')
67
145
file('goodbye', 'wt').write('baz')
68
self.run_bzr('add goodbye')
69
self.run_bzr('commit -m setup goodbye')
146
self.runbzr('add goodbye')
147
self.runbzr('commit -m setup goodbye')
71
149
file('hello', 'wt').write('bar')
72
150
file('goodbye', 'wt').write('qux')
73
self.run_bzr('revert hello')
151
self.runbzr('revert hello')
74
152
self.check_file_contents('hello', 'foo')
75
153
self.check_file_contents('goodbye', 'qux')
76
self.run_bzr('revert')
154
self.runbzr('revert')
77
155
self.check_file_contents('goodbye', 'baz')
79
157
os.mkdir('revertdir')
80
self.run_bzr('add revertdir')
81
self.run_bzr('commit -m f')
158
self.runbzr('add revertdir')
159
self.runbzr('commit -m f')
82
160
os.rmdir('revertdir')
83
self.run_bzr('revert')
85
if osutils.has_symlinks():
86
os.symlink('/unlikely/to/exist', 'symlink')
87
self.run_bzr('add symlink')
88
self.run_bzr('commit -m f')
90
self.run_bzr('revert')
91
self.failUnlessExists('symlink')
93
os.symlink('a-different-path', 'symlink')
94
self.run_bzr('revert')
95
self.assertEqual('/unlikely/to/exist',
96
os.readlink('symlink'))
98
self.log("skipping revert symlink tests")
161
self.runbzr('revert')
163
os.symlink('/unlikely/to/exist', 'symlink')
164
self.runbzr('add symlink')
165
self.runbzr('commit -m f')
167
self.runbzr('revert')
100
169
file('hello', 'wt').write('xyz')
101
self.run_bzr('commit -m xyz hello')
102
self.run_bzr('revert -r 1 hello')
170
self.runbzr('commit -m xyz hello')
171
self.runbzr('revert -r 1 hello')
103
172
self.check_file_contents('hello', 'foo')
104
self.run_bzr('revert hello')
173
self.runbzr('revert hello')
105
174
self.check_file_contents('hello', 'xyz')
106
175
os.chdir('revertdir')
107
self.run_bzr('revert')
176
self.runbzr('revert')
180
def test_mv_modes(self):
181
"""Test two modes of operation for mv"""
182
from bzrlib.branch import Branch
183
b = Branch.initialize('.')
184
self.build_tree(['a', 'c', 'subdir/'])
185
self.run_bzr_captured(['add', self.test_dir])
186
self.run_bzr_captured(['mv', 'a', 'b'])
187
self.run_bzr_captured(['mv', 'b', 'subdir'])
188
self.run_bzr_captured(['mv', 'subdir/b', 'a'])
189
self.run_bzr_captured(['mv', 'a', 'c', 'subdir'])
190
self.run_bzr_captured(['mv', 'subdir/a', 'subdir/newa'])
193
def test_main_version(self):
194
"""Check output from version command and master option is reasonable"""
195
# output is intentionally passed through to stdout so that we
196
# can see the version being tested
197
output = self.runbzr('version', backtick=1)
198
self.log('bzr version output:')
200
self.assert_(output.startswith('bzr (bazaar-ng) '))
201
self.assertNotEqual(output.index('Canonical'), -1)
202
# make sure --version is consistent
203
tmp_output = self.runbzr('--version', backtick=1)
204
self.log('bzr --version output:')
206
self.assertEquals(output, tmp_output)
110
208
def example_branch(test):
112
210
file('hello', 'wt').write('foo')
113
test.run_bzr('add hello')
114
test.run_bzr('commit -m setup hello')
211
test.runbzr('add hello')
212
test.runbzr('commit -m setup hello')
115
213
file('goodbye', 'wt').write('baz')
116
test.run_bzr('add goodbye')
117
test.run_bzr('commit -m setup goodbye')
119
def test_pull_verbose(self):
120
"""Pull changes from one branch to another and watch the output."""
125
self.example_branch()
128
self.run_bzr('branch a b')
130
open('b', 'wb').write('else\n')
131
self.run_bzr('add b')
132
self.run_bzr(['commit', '-m', 'added b'])
135
out = self.run_bzr('pull --verbose ../b')[0]
136
self.failIfEqual(out.find('Added Revisions:'), -1)
137
self.failIfEqual(out.find('message:\n added b'), -1)
138
self.failIfEqual(out.find('added b'), -1)
140
# Check that --overwrite --verbose prints out the removed entries
141
self.run_bzr('commit -m foo --unchanged')
143
self.run_bzr('commit -m baz --unchanged')
144
self.run_bzr('pull ../a', retcode=3)
145
out = self.run_bzr('pull --overwrite --verbose ../a')[0]
147
remove_loc = out.find('Removed Revisions:')
148
self.failIfEqual(remove_loc, -1)
149
added_loc = out.find('Added Revisions:')
150
self.failIfEqual(added_loc, -1)
152
removed_message = out.find('message:\n baz')
153
self.failIfEqual(removed_message, -1)
154
self.failUnless(remove_loc < removed_message < added_loc)
156
added_message = out.find('message:\n foo')
157
self.failIfEqual(added_message, -1)
158
self.failUnless(added_loc < added_message)
160
def test_locations(self):
161
"""Using and remembering different locations"""
165
self.run_bzr('commit -m unchanged --unchanged')
166
self.run_bzr('pull', retcode=3)
167
self.run_bzr('merge', retcode=3)
168
self.run_bzr('branch . ../b')
171
self.run_bzr('branch . ../c')
172
self.run_bzr('pull ../c')
173
self.run_bzr('merge')
175
self.run_bzr('pull ../b')
177
self.run_bzr('pull ../c')
178
self.run_bzr('branch ../c ../d')
179
osutils.rmtree('../c')
184
self.run_bzr('pull', retcode=3)
185
self.run_bzr('pull ../a --remember')
214
test.runbzr('add goodbye')
215
test.runbzr('commit -m setup goodbye')
217
def test_export(self):
220
self.example_branch()
221
self.runbzr('export ../latest')
222
self.assertEqual(file('../latest/goodbye', 'rt').read(), 'baz')
223
self.runbzr('export ../first -r 1')
224
assert not os.path.exists('../first/goodbye')
225
self.assertEqual(file('../first/hello', 'rt').read(), 'foo')
226
self.runbzr('export ../first.gz -r 1')
227
self.assertEqual(file('../first.gz/hello', 'rt').read(), 'foo')
228
self.runbzr('export ../first.bz2 -r 1')
229
self.assertEqual(file('../first.bz2/hello', 'rt').read(), 'foo')
230
self.runbzr('export ../first.tar -r 1')
231
assert os.path.isfile('../first.tar')
232
from tarfile import TarFile
233
tf = TarFile('../first.tar')
234
assert 'first/hello' in tf.getnames(), tf.getnames()
235
self.assertEqual(tf.extractfile('first/hello').read(), 'foo')
236
self.runbzr('export ../first.tar.gz -r 1')
237
assert os.path.isfile('../first.tar.gz')
238
self.runbzr('export ../first.tbz2 -r 1')
239
assert os.path.isfile('../first.tbz2')
240
self.runbzr('export ../first.tar.bz2 -r 1')
241
assert os.path.isfile('../first.tar.bz2')
242
self.runbzr('export ../first.tar.tbz2 -r 1')
243
assert os.path.isfile('../first.tar.tbz2')
244
from bz2 import BZ2File
245
tf = TarFile('../first.tar.tbz2',
246
fileobj=BZ2File('../first.tar.tbz2', 'r'))
247
assert 'first.tar/hello' in tf.getnames(), tf.getnames()
248
self.assertEqual(tf.extractfile('first.tar/hello').read(), 'foo')
249
self.runbzr('export ../first2.tar -r 1 --root pizza')
250
tf = TarFile('../first2.tar')
251
assert 'pizza/hello' in tf.getnames(), tf.getnames()
254
self.example_branch()
255
file('hello', 'wt').write('hello world!')
256
self.runbzr('commit -m fixing hello')
257
output = self.runbzr('diff -r 2..3', backtick=1)
258
self.assert_('\n+hello world!' in output)
259
output = self.runbzr('diff -r last:3..last:1', backtick=1)
260
self.assert_('\n+baz' in output)
262
def test_branch(self):
263
"""Branch from one branch to another."""
266
self.example_branch()
268
self.runbzr('branch a b')
269
self.runbzr('branch a c -r 1')
271
self.runbzr('commit -m foo --unchanged')
273
# naughty - abstraction violations RBC 20050928
274
print "test_branch used to delete the stores, how is this meant to work ?"
275
#shutil.rmtree('a/.bzr/revision-store')
276
#shutil.rmtree('a/.bzr/inventory-store', ignore_errors=True)
277
#shutil.rmtree('a/.bzr/text-store', ignore_errors=True)
278
self.runbzr('branch a d --basis b')
280
def test_merge(self):
281
from bzrlib.branch import Branch
285
self.example_branch()
287
self.runbzr('branch a b')
289
file('goodbye', 'wt').write('quux')
290
self.runbzr(['commit', '-m', "more u's are always good"])
293
file('hello', 'wt').write('quuux')
294
# We can't merge when there are in-tree changes
295
self.runbzr('merge ../b', retcode=1)
296
self.runbzr(['commit', '-m', "Like an epidemic of u's"])
297
self.runbzr('merge ../b')
298
self.check_file_contents('goodbye', 'quux')
299
# Merging a branch pulls its revision into the tree
301
b = Branch.open('../b')
302
a.get_revision_xml(b.last_revision())
303
self.log('pending merges: %s', a.pending_merges())
304
# assert a.pending_merges() == [b.last_revision()], "Assertion %s %s" \
305
# % (a.pending_merges(), b.last_patch())
307
def test_merge_with_missing_file(self):
308
"""Merge handles missing file conflicts"""
312
print >> file('sub/a.txt', 'wb'), "hello"
313
print >> file('b.txt', 'wb'), "hello"
314
print >> file('sub/c.txt', 'wb'), "hello"
317
self.runbzr(('commit', '-m', 'added a'))
318
self.runbzr('branch . ../b')
319
print >> file('sub/a.txt', 'ab'), "there"
320
print >> file('b.txt', 'ab'), "there"
321
print >> file('sub/c.txt', 'ab'), "there"
322
self.runbzr(('commit', '-m', 'Added there'))
323
os.unlink('sub/a.txt')
324
os.unlink('sub/c.txt')
327
self.runbzr(('commit', '-m', 'Removed a.txt'))
329
print >> file('sub/a.txt', 'ab'), "something"
330
print >> file('b.txt', 'ab'), "something"
331
print >> file('sub/c.txt', 'ab'), "something"
332
self.runbzr(('commit', '-m', 'Modified a.txt'))
333
self.runbzr('merge ../a/')
334
assert os.path.exists('sub/a.txt.THIS')
335
assert os.path.exists('sub/a.txt.BASE')
337
self.runbzr('merge ../b/')
338
assert os.path.exists('sub/a.txt.OTHER')
339
assert os.path.exists('sub/a.txt.BASE')
341
def test_merge_with_missing_file(self):
342
"""Merge handles missing file conflicts"""
346
print >> file('sub/a.txt', 'wb'), "hello"
347
print >> file('b.txt', 'wb'), "hello"
348
print >> file('sub/c.txt', 'wb'), "hello"
351
self.runbzr(('commit', '-m', 'added a'))
352
self.runbzr('branch . ../b')
353
print >> file('sub/a.txt', 'ab'), "there"
354
print >> file('b.txt', 'ab'), "there"
355
print >> file('sub/c.txt', 'ab'), "there"
356
self.runbzr(('commit', '-m', 'Added there'))
357
os.unlink('sub/a.txt')
358
os.unlink('sub/c.txt')
361
self.runbzr(('commit', '-m', 'Removed a.txt'))
363
print >> file('sub/a.txt', 'ab'), "something"
364
print >> file('b.txt', 'ab'), "something"
365
print >> file('sub/c.txt', 'ab'), "something"
366
self.runbzr(('commit', '-m', 'Modified a.txt'))
367
self.runbzr('merge ../a/')
368
assert os.path.exists('sub/a.txt.THIS')
369
assert os.path.exists('sub/a.txt.BASE')
371
self.runbzr('merge ../b/')
372
assert os.path.exists('sub/a.txt.OTHER')
373
assert os.path.exists('sub/a.txt.BASE')
376
"""Pull changes from one branch to another."""
380
self.example_branch()
381
self.runbzr('pull', retcode=1)
382
self.runbzr('missing', retcode=1)
383
self.runbzr('missing .')
384
self.runbzr('missing')
386
self.runbzr('pull /', retcode=1)
390
self.runbzr('branch a b')
394
self.runbzr('add subdir')
395
self.runbzr('commit -m blah --unchanged')
398
b = Branch.open('../b')
399
assert a.revision_history() == b.revision_history()[:-1]
400
self.runbzr('pull ../b')
401
assert a.revision_history() == b.revision_history()
402
self.runbzr('commit -m blah2 --unchanged')
404
self.runbzr('commit -m blah3 --unchanged')
405
self.runbzr('pull ../a', retcode=1)
406
print "DECIDE IF PULL CAN CONVERGE, blackbox.py"
409
self.runbzr('merge ../b')
410
self.runbzr('commit -m blah4 --unchanged')
411
os.chdir('../b/subdir')
412
self.runbzr('pull ../../a')
413
assert a.revision_history()[-1] == b.revision_history()[-1]
414
self.runbzr('commit -m blah5 --unchanged')
415
self.runbzr('commit -m blah6 --unchanged')
417
self.runbzr('pull ../a')
419
self.runbzr('commit -m blah7 --unchanged')
420
self.runbzr('merge ../b')
421
self.runbzr('commit -m blah8 --unchanged')
422
self.runbzr('pull ../b')
423
self.runbzr('pull ../b')
425
def test_add_reports(self):
426
"""add command prints the names of added files."""
427
b = Branch.initialize('.')
428
self.build_tree(['top.txt', 'dir/', 'dir/sub.txt'])
429
out = self.run_bzr_captured(['add'], retcode = 0)[0]
430
# the ordering is not defined at the moment
431
results = sorted(out.rstrip('\n').split('\n'))
432
self.assertEquals(['added dir',
433
'added dir'+os.sep+'sub.txt',
188
437
def test_unknown_command(self):
189
438
"""Handling of unknown command."""
190
out, err = self.run_bzr('fluffy-badger', retcode=3)
439
out, err = self.run_bzr_captured(['fluffy-badger'],
191
441
self.assertEquals(out, '')
192
442
err.index('unknown command')
194
def create_conflicts(self):
195
"""Create a conflicted tree"""
444
def test_conflicts(self):
445
"""Handling of merge conflicts"""
198
448
file('hello', 'wb').write("hi world")
199
449
file('answer', 'wb').write("42")
202
self.run_bzr('commit -m base')
203
self.run_bzr('branch . ../other')
204
self.run_bzr('branch . ../this')
452
self.runbzr('commit -m base')
453
self.runbzr('branch . ../other')
454
self.runbzr('branch . ../this')
205
455
os.chdir('../other')
206
456
file('hello', 'wb').write("Hello.")
207
457
file('answer', 'wb').write("Is anyone there?")
208
self.run_bzr('commit -m other')
458
self.runbzr('commit -m other')
209
459
os.chdir('../this')
210
460
file('hello', 'wb').write("Hello, world")
211
self.run_bzr('mv answer question')
461
self.runbzr('mv answer question')
212
462
file('question', 'wb').write("What do you get when you multiply six"
214
self.run_bzr('commit -m this')
216
def test_status(self):
220
self.run_bzr('commit --unchanged --message f')
221
self.run_bzr('branch . ../branch2')
222
self.run_bzr('branch . ../branch3')
223
self.run_bzr('commit --unchanged --message peter')
224
os.chdir('../branch2')
225
self.run_bzr('merge ../branch1')
226
self.run_bzr('commit --unchanged --message pumpkin')
227
os.chdir('../branch3')
228
self.run_bzr('merge ../branch2')
229
message = self.run_bzr('status')[0]
232
def test_conflicts(self):
233
"""Handling of merge conflicts"""
234
self.create_conflicts()
235
self.run_bzr('merge ../other --show-base', retcode=1)
236
conflict_text = file('hello').read()
237
self.assert_('<<<<<<<' in conflict_text)
238
self.assert_('>>>>>>>' in conflict_text)
239
self.assert_('=======' in conflict_text)
240
self.assert_('|||||||' in conflict_text)
241
self.assert_('hi world' in conflict_text)
242
self.run_bzr('revert')
243
self.run_bzr('resolve --all')
244
self.run_bzr('merge ../other', retcode=1)
245
conflict_text = file('hello').read()
246
self.assert_('|||||||' not in conflict_text)
247
self.assert_('hi world' not in conflict_text)
248
result = self.run_bzr('conflicts')[0]
249
self.assertEquals(result, "Text conflict in hello\nText conflict in"
251
result = self.run_bzr('status')[0]
252
self.assert_("conflicts:\n Text conflict in hello\n"
253
" Text conflict in question\n" in result, result)
254
self.run_bzr('resolve hello')
255
result = self.run_bzr('conflicts')[0]
256
self.assertEquals(result, "Text conflict in question\n")
257
self.run_bzr('commit -m conflicts', retcode=3)
258
self.run_bzr('resolve --all')
259
result = self.run_bzr('conflicts')[0]
260
self.run_bzr('commit -m conflicts')
464
self.runbzr('commit -m this')
465
self.runbzr('merge ../other')
466
result = self.runbzr('conflicts', backtick=1)
467
self.assertEquals(result, "hello\nquestion\n")
468
result = self.runbzr('status', backtick=1)
469
assert "conflicts:\n hello\n question\n" in result, result
470
self.runbzr('resolve hello')
471
result = self.runbzr('conflicts', backtick=1)
472
self.assertEquals(result, "question\n")
473
self.runbzr('commit -m conflicts', retcode=1)
474
self.runbzr('resolve --all')
475
result = self.runbzr('conflicts', backtick=1)
476
self.runbzr('commit -m conflicts')
261
477
self.assertEquals(result, "")
264
# create a source branch
265
os.mkdir('my-branch')
266
os.chdir('my-branch')
267
self.example_branch()
269
# with no push target, fail
270
self.run_bzr('push', retcode=3)
271
# with an explicit target work
272
self.run_bzr('push ../output-branch')
273
# with an implicit target work
276
self.run_bzr('missing ../output-branch')
277
# advance this branch
278
self.run_bzr('commit --unchanged -m unchanged')
280
os.chdir('../output-branch')
281
# There is no longer a difference as long as we have
282
# access to the working tree
285
# But we should be missing a revision
286
self.run_bzr('missing ../my-branch', retcode=1)
288
# diverge the branches
289
self.run_bzr('commit --unchanged -m unchanged')
290
os.chdir('../my-branch')
292
self.run_bzr('push', retcode=3)
293
# and there are difference
294
self.run_bzr('missing ../output-branch', retcode=1)
295
self.run_bzr('missing --verbose ../output-branch', retcode=1)
296
# but we can force a push
297
self.run_bzr('push --overwrite')
299
self.run_bzr('missing ../output-branch')
301
# pushing to a new dir with no parent should fail
302
self.run_bzr('push ../missing/new-branch', retcode=3)
303
# unless we provide --create-prefix
304
self.run_bzr('push --create-prefix ../missing/new-branch')
306
self.run_bzr('missing ../missing/new-branch')
308
def test_external_command(self):
309
"""Test that external commands can be run by setting the path
311
# We don't at present run bzr in a subprocess for blackbox tests, and so
312
# don't really capture stdout, only the internal python stream.
313
# Therefore we don't use a subcommand that produces any output or does
314
# anything -- we just check that it can be run successfully.
315
cmd_name = 'test-command'
316
if sys.platform == 'win32':
318
oldpath = os.environ.get('BZRPATH', None)
320
if 'BZRPATH' in os.environ:
321
del os.environ['BZRPATH']
323
f = file(cmd_name, 'wb')
324
if sys.platform == 'win32':
325
f.write('@echo off\n')
327
f.write('#!/bin/sh\n')
328
# f.write('echo Hello from test-command')
330
os.chmod(cmd_name, 0755)
332
# It should not find the command in the local
333
# directory by default, since it is not in my path
334
self.run_bzr(cmd_name, retcode=3)
336
# Now put it into my path
337
os.environ['BZRPATH'] = '.'
339
self.run_bzr(cmd_name)
341
# Make sure empty path elements are ignored
342
os.environ['BZRPATH'] = os.pathsep
344
self.run_bzr(cmd_name, retcode=3)
348
os.environ['BZRPATH'] = oldpath
482
if hasattr(os, 'symlink'):
351
487
def listdir_sorted(dir):
352
488
L = os.listdir(dir)
377
515
f.write('hello world!\n')
380
self.assertEquals(self.run_bzr('unknowns')[0], 'test.txt\n')
382
out = self.run_bzr("status")[0]
383
self.assertEquals(out, 'unknown:\n test.txt\n')
518
self.assertEquals(capture('unknowns'), 'test.txt\n')
520
out = capture("status")
521
assert out == 'unknown:\n test.txt\n'
523
out = capture("status --all")
524
assert out == "unknown:\n test.txt\n"
526
out = capture("status test.txt --all")
527
assert out == "unknown:\n test.txt\n"
385
529
f = file('test2.txt', 'wt')
386
530
f.write('goodbye cruel world...\n')
389
out = self.run_bzr("status test.txt")[0]
390
self.assertEquals(out, "unknown:\n test.txt\n")
533
out = capture("status test.txt")
534
assert out == "unknown:\n test.txt\n"
392
out = self.run_bzr("status")[0]
393
self.assertEquals(out, ("unknown:\n" " test.txt\n" " test2.txt\n"))
536
out = capture("status")
537
assert out == ("unknown:\n"
395
541
os.unlink('test2.txt')
397
543
progress("command aliases")
398
out = self.run_bzr("st")[0]
399
self.assertEquals(out, ("unknown:\n" " test.txt\n"))
544
out = capture("st --all")
545
assert out == ("unknown:\n"
401
out = self.run_bzr("stat")[0]
402
self.assertEquals(out, ("unknown:\n" " test.txt\n"))
548
out = capture("stat")
549
assert out == ("unknown:\n"
404
552
progress("command help")
405
self.run_bzr("help st")
407
self.run_bzr("help commands")
408
self.run_bzr("help slartibartfast", retcode=3)
410
out = self.run_bzr("help ci")[0]
411
out.index('Aliases: ci, checkin\n')
555
runbzr("help commands")
556
runbzr("help slartibartfast", 1)
558
out = capture("help ci")
559
out.index('aliases: ')
561
progress("can't rename unversioned file")
562
runbzr("rename test.txt new-test.txt", 1)
564
progress("adding a file")
566
runbzr("add test.txt")
567
assert capture("unknowns") == ''
568
assert capture("status --all") == ("added:\n"
571
progress("rename newly-added file")
572
runbzr("rename test.txt hello.txt")
573
assert os.path.exists("hello.txt")
574
assert not os.path.exists("test.txt")
576
assert capture("revno") == '0\n'
578
progress("add first revision")
579
runbzr(['commit', '-m', 'add first revision'])
581
progress("more complex renames")
583
runbzr("rename hello.txt sub1", 1)
584
runbzr("rename hello.txt sub1/hello.txt", 1)
585
runbzr("move hello.txt sub1", 1)
588
runbzr("rename sub1 sub2")
589
runbzr("move hello.txt sub2")
590
assert capture("relpath sub2/hello.txt") == os.path.join("sub2", "hello.txt\n")
592
assert exists("sub2")
593
assert exists("sub2/hello.txt")
594
assert not exists("sub1")
595
assert not exists("hello.txt")
597
runbzr(['commit', '-m', 'commit with some things moved to subdirs'])
601
runbzr('move sub2/hello.txt sub1')
602
assert not exists('sub2/hello.txt')
603
assert exists('sub1/hello.txt')
604
runbzr('move sub2 sub1')
605
assert not exists('sub2')
606
assert exists('sub1/sub2')
608
runbzr(['commit', '-m', 'rename nested subdirectories'])
611
self.assertEquals(capture('root')[:-1],
612
os.path.join(self.test_dir, 'branch1'))
613
runbzr('move ../hello.txt .')
614
assert exists('./hello.txt')
615
self.assertEquals(capture('relpath hello.txt'),
616
os.path.join('sub1', 'sub2', 'hello.txt') + '\n')
617
assert capture('relpath ../../sub1/sub2/hello.txt') == os.path.join('sub1', 'sub2', 'hello.txt\n')
618
runbzr(['commit', '-m', 'move to parent directory'])
620
assert capture('relpath sub2/hello.txt') == os.path.join('sub1', 'sub2', 'hello.txt\n')
622
runbzr('move sub2/hello.txt .')
623
assert exists('hello.txt')
413
625
f = file('hello.txt', 'wt')
414
626
f.write('some nice new content\n')
417
self.run_bzr("add hello.txt")
419
629
f = file('msg.tmp', 'wt')
420
f.write('this is my new commit\nand it has multiple lines, for fun')
630
f.write('this is my new commit\n')
423
self.run_bzr('commit -F msg.tmp')
425
self.assertEquals(self.run_bzr('revno')[0], '1\n')
426
self.run_bzr('export -r 1 export-1.tmp')
427
self.run_bzr('export export.tmp')
430
self.run_bzr('log -v')
431
self.run_bzr('log -v --forward')
432
self.run_bzr('log -m', retcode=3)
433
log_out = self.run_bzr('log -m commit')[0]
434
self.assert_("this is my new commit\n and" in log_out)
435
self.assert_("rename nested" not in log_out)
436
self.assert_('revision-id' not in log_out)
437
self.assert_('revision-id' in self.run_bzr('log --show-ids -m commit')[0])
439
log_out = self.run_bzr('log --line')[0]
440
# determine the widest line we want
441
max_width = osutils.terminal_width()
442
if max_width is not None:
443
for line in log_out.splitlines():
444
self.assert_(len(line) <= max_width - 1, len(line))
445
self.assert_("this is my new commit and" not in log_out)
446
self.assert_("this is my new commit" in log_out)
633
runbzr('commit -F msg.tmp')
635
assert capture('revno') == '5\n'
636
runbzr('export -r 5 export-5.tmp')
637
runbzr('export export.tmp')
641
runbzr('log -v --forward')
642
runbzr('log -m', retcode=1)
643
log_out = capture('log -m commit')
644
assert "this is my new commit" in log_out
645
assert "rename nested" not in log_out
646
assert 'revision-id' not in log_out
647
assert 'revision-id' in capture('log --show-ids -m commit')
448
650
progress("file with spaces in name")
449
651
mkdir('sub directory')
450
652
file('sub directory/file with spaces ', 'wt').write('see how this works\n')
451
self.run_bzr('add .')
452
self.run_bzr('diff', retcode=1)
453
self.run_bzr('commit -m add-spaces')
454
self.run_bzr('check')
457
self.run_bzr('log --forward')
461
if osutils.has_symlinks():
655
runbzr('commit -m add-spaces')
659
runbzr('log --forward')
462
664
progress("symlinks")
463
665
mkdir('symlinks')
464
666
chdir('symlinks')
466
668
os.symlink("NOWHERE1", "link1")
467
self.run_bzr('add link1')
468
self.assertEquals(self.run_bzr('unknowns')[0], '')
469
self.run_bzr(['commit', '-m', '1: added symlink link1'])
670
assert self.capture('unknowns') == ''
671
runbzr(['commit', '-m', '1: added symlink link1'])
472
self.run_bzr('add d1')
473
self.assertEquals(self.run_bzr('unknowns')[0], '')
675
assert self.capture('unknowns') == ''
474
676
os.symlink("NOWHERE2", "d1/link2")
475
self.assertEquals(self.run_bzr('unknowns')[0], 'd1/link2\n')
677
assert self.capture('unknowns') == 'd1/link2\n'
476
678
# is d1/link2 found when adding d1
477
self.run_bzr('add d1')
478
self.assertEquals(self.run_bzr('unknowns')[0], '')
680
assert self.capture('unknowns') == ''
479
681
os.symlink("NOWHERE3", "d1/link3")
480
self.assertEquals(self.run_bzr('unknowns')[0], 'd1/link3\n')
481
self.run_bzr(['commit', '-m', '2: added dir, symlink'])
483
self.run_bzr('rename d1 d2')
484
self.run_bzr('move d2/link2 .')
485
self.run_bzr('move link1 d2')
486
self.assertEquals(os.readlink("./link2"), "NOWHERE2")
487
self.assertEquals(os.readlink("d2/link1"), "NOWHERE1")
488
self.run_bzr('add d2/link3')
489
self.run_bzr('diff', retcode=1)
490
self.run_bzr(['commit', '-m',
491
'3: rename of dir, move symlinks, add link3'])
682
assert self.capture('unknowns') == 'd1/link3\n'
683
runbzr(['commit', '-m', '2: added dir, symlink'])
685
runbzr('rename d1 d2')
686
runbzr('move d2/link2 .')
687
runbzr('move link1 d2')
688
assert os.readlink("./link2") == "NOWHERE2"
689
assert os.readlink("d2/link1") == "NOWHERE1"
690
runbzr('add d2/link3')
692
runbzr(['commit', '-m', '3: rename of dir, move symlinks, add link3'])
493
694
os.unlink("link2")
494
695
os.symlink("TARGET 2", "link2")
495
696
os.unlink("d2/link1")
496
697
os.symlink("TARGET 1", "d2/link1")
497
self.run_bzr('diff', retcode=1)
498
self.assertEquals(self.run_bzr("relpath d2/link1")[0], "d2/link1\n")
499
self.run_bzr(['commit', '-m', '4: retarget of two links'])
501
self.run_bzr('remove --keep d2/link1')
502
self.assertEquals(self.run_bzr('unknowns')[0], 'd2/link1\n')
503
self.run_bzr(['commit', '-m', '5: remove d2/link1'])
504
# try with the rm alias
505
self.run_bzr('add d2/link1')
506
self.run_bzr(['commit', '-m', '6: add d2/link1'])
507
self.run_bzr('rm --keep d2/link1')
508
self.assertEquals(self.run_bzr('unknowns')[0], 'd2/link1\n')
509
self.run_bzr(['commit', '-m', '7: remove d2/link1'])
699
assert self.capture("relpath d2/link1") == "d2/link1\n"
700
runbzr(['commit', '-m', '4: retarget of two links'])
702
runbzr('remove d2/link1')
703
assert self.capture('unknowns') == 'd2/link1\n'
704
runbzr(['commit', '-m', '5: remove d2/link1'])
512
self.run_bzr('add d1')
513
self.run_bzr('rename d2/link3 d1/link3new')
514
self.assertEquals(self.run_bzr('unknowns')[0], 'd2/link1\n')
515
self.run_bzr(['commit', '-m',
516
'8: remove d2/link1, move/rename link3'])
518
self.run_bzr('check')
520
self.run_bzr('export -r 1 exp1.tmp')
708
runbzr('rename d2/link3 d1/link3new')
709
assert self.capture('unknowns') == 'd2/link1\n'
710
runbzr(['commit', '-m', '6: remove d2/link1, move/rename link3'])
714
runbzr(['export', '-r', '1', 'exp1.tmp'])
521
715
chdir("exp1.tmp")
522
self.assertEquals(listdir_sorted("."), [ "link1" ])
523
self.assertEquals(os.readlink("link1"), "NOWHERE1")
716
assert listdir_sorted(".") == [ "link1" ]
717
assert os.readlink("link1") == "NOWHERE1"
526
self.run_bzr('export -r 2 exp2.tmp')
720
runbzr(['export', '-r', '2', 'exp2.tmp'])
527
721
chdir("exp2.tmp")
528
self.assertEquals(listdir_sorted("."), [ "d1", "link1" ])
722
assert listdir_sorted(".") == [ "d1", "link1" ]
531
self.run_bzr('export -r 3 exp3.tmp')
725
runbzr(['export', '-r', '3', 'exp3.tmp'])
532
726
chdir("exp3.tmp")
533
self.assertEquals(listdir_sorted("."), [ "d2", "link2" ])
534
self.assertEquals(listdir_sorted("d2"), [ "link1", "link3" ])
535
self.assertEquals(os.readlink("d2/link1"), "NOWHERE1")
536
self.assertEquals(os.readlink("link2") , "NOWHERE2")
727
assert listdir_sorted(".") == [ "d2", "link2" ]
728
assert listdir_sorted("d2") == [ "link1", "link3" ]
729
assert os.readlink("d2/link1") == "NOWHERE1"
730
assert os.readlink("link2") == "NOWHERE2"
539
self.run_bzr('export -r 4 exp4.tmp')
733
runbzr(['export', '-r', '4', 'exp4.tmp'])
540
734
chdir("exp4.tmp")
541
self.assertEquals(listdir_sorted("."), [ "d2", "link2" ])
542
self.assertEquals(os.readlink("d2/link1"), "TARGET 1")
543
self.assertEquals(os.readlink("link2") , "TARGET 2")
544
self.assertEquals(listdir_sorted("d2"), [ "link1", "link3" ])
735
assert listdir_sorted(".") == [ "d2", "link2" ]
736
assert os.readlink("d2/link1") == "TARGET 1"
737
assert os.readlink("link2") == "TARGET 2"
738
assert listdir_sorted("d2") == [ "link1", "link3" ]
547
self.run_bzr('export -r 5 exp5.tmp')
741
runbzr(['export', '-r', '5', 'exp5.tmp'])
548
742
chdir("exp5.tmp")
549
self.assertEquals(listdir_sorted("."), [ "d2", "link2" ])
550
self.assert_(os.path.islink("link2"))
551
self.assert_(listdir_sorted("d2")== [ "link3" ])
743
assert listdir_sorted(".") == [ "d2", "link2" ]
744
assert os.path.islink("link2")
745
assert listdir_sorted("d2")== [ "link3" ]
554
self.run_bzr('export -r 8 exp6.tmp')
748
runbzr(['export', '-r', '6', 'exp6.tmp'])
555
749
chdir("exp6.tmp")
556
self.assertEqual(listdir_sorted("."), [ "d1", "d2", "link2"])
557
self.assertEquals(listdir_sorted("d1"), [ "link3new" ])
558
self.assertEquals(listdir_sorted("d2"), [])
559
self.assertEquals(os.readlink("d1/link3new"), "NOWHERE3")
750
assert listdir_sorted(".") == [ "d1", "d2", "link2" ]
751
assert listdir_sorted("d1") == [ "link3new" ]
752
assert listdir_sorted("d2") == []
753
assert os.readlink("d1/link3new") == "NOWHERE3"
562
756
progress("skipping symlink tests")
565
class RemoteTests(object):
566
"""Test bzr ui commands against remote branches."""
568
def test_branch(self):
570
wt = self.make_branch_and_tree('from')
572
wt.commit('empty commit for nonsense', allow_pointless=True)
573
url = self.get_readonly_url('from')
574
self.run_bzr(['branch', url, 'to'])
575
branch = Branch.open('to')
576
self.assertEqual(1, len(branch.revision_history()))
577
# the branch should be set in to to from
578
self.assertEqual(url + '/', branch.get_parent())
581
self.build_tree(['branch/', 'branch/file'])
582
self.run_bzr('init branch')[0]
583
self.run_bzr('add branch/file')[0]
584
self.run_bzr('commit -m foo branch')[0]
585
url = self.get_readonly_url('branch/file')
586
output = self.run_bzr('log %s' % url)[0]
587
self.assertEqual(8, len(output.split('\n')))
589
def test_check(self):
590
self.build_tree(['branch/', 'branch/file'])
591
self.run_bzr('init branch')[0]
592
self.run_bzr('add branch/file')[0]
593
self.run_bzr('commit -m foo branch')[0]
594
url = self.get_readonly_url('branch/')
595
self.run_bzr(['check', url])
598
# create a source branch
599
os.mkdir('my-branch')
600
os.chdir('my-branch')
602
file('hello', 'wt').write('foo')
603
self.run_bzr('add hello')
604
self.run_bzr('commit -m setup')
606
# with an explicit target work
607
self.run_bzr(['push', self.get_url('output-branch')])
610
class HTTPTests(TestCaseWithWebserver, RemoteTests):
611
"""Test various commands against a HTTP server."""
614
class SFTPTestsAbsolute(TestCaseWithSFTPServer, RemoteTests):
615
"""Test various commands against a SFTP server using abs paths."""
618
class SFTPTestsAbsoluteSibling(TestCaseWithSFTPServer, RemoteTests):
619
"""Test various commands against a SFTP server using abs paths."""
622
super(SFTPTestsAbsoluteSibling, self).setUp()
623
self._override_home = '/dev/noone/runs/tests/here'
626
class SFTPTestsRelative(TestCaseWithSFTPServer, RemoteTests):
627
"""Test various commands against a SFTP server using homedir rel paths."""
630
super(SFTPTestsRelative, self).setUp()
631
self._get_remote_is_absolute = False