~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/blackbox/test_diff.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2009-05-06 04:07:37 UTC
  • mfrom: (4332.1.1 integration)
  • Revision ID: pqm@pqm.ubuntu.com-20090506040737-tdiqyojy2uia33qb
Make it easier to blackbox test rules (Marius Kruger)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2005, 2006 Canonical Ltd
 
2
#
 
3
# This program is free software; you can redistribute it and/or modify
 
4
# it under the terms of the GNU General Public License as published by
 
5
# the Free Software Foundation; either version 2 of the License, or
 
6
# (at your option) any later version.
 
7
#
 
8
# This program is distributed in the hope that it will be useful,
 
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
# GNU General Public License for more details.
 
12
#
 
13
# You should have received a copy of the GNU General Public License
 
14
# 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
 
 
17
 
 
18
"""Black-box tests for bzr diff.
 
19
"""
 
20
 
 
21
import os
 
22
import re
 
23
 
 
24
import bzrlib
 
25
from bzrlib import workingtree
 
26
from bzrlib.branch import Branch
 
27
from bzrlib.tests import TestSkipped
 
28
from bzrlib.tests.blackbox import ExternalBase
 
29
 
 
30
 
 
31
def subst_dates(string):
 
32
    """Replace date strings with constant values."""
 
33
    return re.sub(r'\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} [-\+]\d{4}',
 
34
                  'YYYY-MM-DD HH:MM:SS +ZZZZ', string)
 
35
 
 
36
 
 
37
class DiffBase(ExternalBase):
 
38
    """Base class with common setup method"""
 
39
 
 
40
    def make_example_branch(self):
 
41
        tree = self.make_branch_and_tree('.')
 
42
        self.build_tree_contents([
 
43
            ('hello', 'foo\n'),
 
44
            ('goodbye', 'baz\n')])
 
45
        tree.add(['hello'])
 
46
        tree.commit('setup')
 
47
        tree.add(['goodbye'])
 
48
        tree.commit('setup')
 
49
        return tree
 
50
 
 
51
 
 
52
class TestDiff(DiffBase):
 
53
 
 
54
    def test_diff(self):
 
55
        tree = self.make_example_branch()
 
56
        self.build_tree_contents([('hello', 'hello world!')])
 
57
        tree.commit(message='fixing hello')
 
58
        output = self.run_bzr('diff -r 2..3', retcode=1)[0]
 
59
        self.assert_('\n+hello world!' in output)
 
60
        output = self.run_bzr('diff -c 3', retcode=1)[0]
 
61
        self.assert_('\n+hello world!' in output)
 
62
        output = self.run_bzr('diff -r last:3..last:1', retcode=1)[0]
 
63
        self.assert_('\n+baz' in output)
 
64
        output = self.run_bzr('diff -c last:2', retcode=1)[0]
 
65
        self.assert_('\n+baz' in output)
 
66
        self.build_tree(['moo'])
 
67
        tree.add('moo')
 
68
        os.unlink('moo')
 
69
        self.run_bzr('diff')
 
70
 
 
71
    def test_diff_prefix(self):
 
72
        """diff --prefix appends to filenames in output"""
 
73
        self.make_example_branch()
 
74
        self.build_tree_contents([('hello', 'hello world!\n')])
 
75
        out, err = self.run_bzr('diff --prefix old/:new/', retcode=1)
 
76
        self.assertEquals(err, '')
 
77
        self.assertEqualDiff(subst_dates(out), '''\
 
78
=== modified file 'hello'
 
79
--- old/hello\tYYYY-MM-DD HH:MM:SS +ZZZZ
 
80
+++ new/hello\tYYYY-MM-DD HH:MM:SS +ZZZZ
 
81
@@ -1,1 +1,1 @@
 
82
-foo
 
83
+hello world!
 
84
 
 
85
''')
 
86
 
 
87
    def test_diff_illegal_prefix_value(self):
 
88
        # There was an error in error reporting for this option
 
89
        out, err = self.run_bzr('diff --prefix old/', retcode=3)
 
90
        self.assertContainsRe(err,
 
91
            '--prefix expects two values separated by a colon')
 
92
 
 
93
    def test_diff_p1(self):
 
94
        """diff -p1 produces lkml-style diffs"""
 
95
        self.make_example_branch()
 
96
        self.build_tree_contents([('hello', 'hello world!\n')])
 
97
        out, err = self.run_bzr('diff -p1', retcode=1)
 
98
        self.assertEquals(err, '')
 
99
        self.assertEqualDiff(subst_dates(out), '''\
 
100
=== modified file 'hello'
 
101
--- old/hello\tYYYY-MM-DD HH:MM:SS +ZZZZ
 
102
+++ new/hello\tYYYY-MM-DD HH:MM:SS +ZZZZ
 
103
@@ -1,1 +1,1 @@
 
104
-foo
 
105
+hello world!
 
106
 
 
107
''')
 
108
 
 
109
    def test_diff_p0(self):
 
110
        """diff -p0 produces diffs with no prefix"""
 
111
        self.make_example_branch()
 
112
        self.build_tree_contents([('hello', 'hello world!\n')])
 
113
        out, err = self.run_bzr('diff -p0', retcode=1)
 
114
        self.assertEquals(err, '')
 
115
        self.assertEqualDiff(subst_dates(out), '''\
 
116
=== modified file 'hello'
 
117
--- hello\tYYYY-MM-DD HH:MM:SS +ZZZZ
 
118
+++ hello\tYYYY-MM-DD HH:MM:SS +ZZZZ
 
119
@@ -1,1 +1,1 @@
 
120
-foo
 
121
+hello world!
 
122
 
 
123
''')
 
124
 
 
125
    def test_diff_nonexistent(self):
 
126
        # Get an error from a file that does not exist at all
 
127
        # (Malone #3619)
 
128
        self.make_example_branch()
 
129
        out, err = self.run_bzr('diff does-not-exist', retcode=3,
 
130
            error_regexes=('not versioned.*does-not-exist',))
 
131
 
 
132
    def test_diff_illegal_revision_specifiers(self):
 
133
        out, err = self.run_bzr('diff -r 1..23..123', retcode=3,
 
134
            error_regexes=('one or two revision specifiers',))
 
135
 
 
136
    def test_diff_nonexistent_revision(self):
 
137
        out, err = self.run_bzr('diff -r 123', retcode=3,
 
138
            error_regexes=("Requested revision: '123' does not "
 
139
                "exist in branch:",))
 
140
 
 
141
    def test_diff_nonexistent_dotted_revision(self):
 
142
        out, err = self.run_bzr('diff -r 1.1', retcode=3)
 
143
        self.assertContainsRe(err,
 
144
            "Requested revision: '1.1' does not exist in branch:")
 
145
 
 
146
    def test_diff_nonexistent_dotted_revision_change(self):
 
147
        out, err = self.run_bzr('diff -c 1.1', retcode=3)
 
148
        self.assertContainsRe(err,
 
149
            "Requested revision: '1.1' does not exist in branch:")
 
150
 
 
151
    def test_diff_unversioned(self):
 
152
        # Get an error when diffing a non-versioned file.
 
153
        # (Malone #3619)
 
154
        self.make_example_branch()
 
155
        self.build_tree(['unversioned-file'])
 
156
        out, err = self.run_bzr('diff unversioned-file', retcode=3)
 
157
        self.assertContainsRe(err, 'not versioned.*unversioned-file')
 
158
 
 
159
    # TODO: What should diff say for a file deleted in working tree?
 
160
 
 
161
    def example_branches(self):
 
162
        branch1_tree = self.make_branch_and_tree('branch1')
 
163
        self.build_tree(['branch1/file'], line_endings='binary')
 
164
        self.build_tree(['branch1/file2'], line_endings='binary')
 
165
        branch1_tree.add('file')
 
166
        branch1_tree.add('file2')
 
167
        branch1_tree.commit(message='add file and file2')
 
168
        branch2_tree = branch1_tree.bzrdir.sprout('branch2').open_workingtree()
 
169
        self.build_tree_contents([('branch2/file', 'new content\n')])
 
170
        branch2_tree.commit(message='update file')
 
171
        return branch1_tree, branch2_tree
 
172
 
 
173
    def check_b2_vs_b1(self, cmd):
 
174
        # Compare branch2 vs branch1 using cmd and check the result
 
175
        out, err = self.run_bzr(cmd, retcode=1)
 
176
        self.assertEquals('', err)
 
177
        self.assertEquals("=== modified file 'file'\n"
 
178
                          "--- file\tYYYY-MM-DD HH:MM:SS +ZZZZ\n"
 
179
                          "+++ file\tYYYY-MM-DD HH:MM:SS +ZZZZ\n"
 
180
                          "@@ -1,1 +1,1 @@\n"
 
181
                          "-new content\n"
 
182
                          "+contents of branch1/file\n"
 
183
                          "\n", subst_dates(out))
 
184
 
 
185
    def check_b1_vs_b2(self, cmd):
 
186
        # Compare branch1 vs branch2 using cmd and check the result
 
187
        out, err = self.run_bzr(cmd, retcode=1)
 
188
        self.assertEquals('', err)
 
189
        self.assertEqualDiff("=== modified file 'file'\n"
 
190
                              "--- file\tYYYY-MM-DD HH:MM:SS +ZZZZ\n"
 
191
                              "+++ file\tYYYY-MM-DD HH:MM:SS +ZZZZ\n"
 
192
                              "@@ -1,1 +1,1 @@\n"
 
193
                              "-contents of branch1/file\n"
 
194
                              "+new content\n"
 
195
                              "\n", subst_dates(out))
 
196
 
 
197
    def check_no_diffs(self, cmd):
 
198
        # Check that running cmd returns an empty diff
 
199
        out, err = self.run_bzr(cmd, retcode=0)
 
200
        self.assertEquals('', err)
 
201
        self.assertEquals('', out)
 
202
 
 
203
    def test_diff_branches(self):
 
204
        self.example_branches()
 
205
        # should open branch1 and diff against branch2,
 
206
        self.check_b2_vs_b1('diff -r branch:branch2 branch1')
 
207
        # Compare two working trees using various syntax forms
 
208
        self.check_b2_vs_b1('diff --old branch2 --new branch1')
 
209
        self.check_b2_vs_b1('diff --old branch2 branch1')
 
210
        self.check_b2_vs_b1('diff branch2 --new branch1')
 
211
        # Test with a selected file that was changed
 
212
        self.check_b2_vs_b1('diff --old branch2 --new branch1 file')
 
213
        self.check_b2_vs_b1('diff --old branch2 branch1/file')
 
214
        self.check_b2_vs_b1('diff branch2/file --new branch1')
 
215
        # Test with a selected file that was not changed
 
216
        self.check_no_diffs('diff --old branch2 --new branch1 file2')
 
217
        self.check_no_diffs('diff --old branch2 branch1/file2')
 
218
        self.check_no_diffs('diff branch2/file2 --new branch1')
 
219
 
 
220
    def test_diff_branches_no_working_trees(self):
 
221
        branch1_tree, branch2_tree = self.example_branches()
 
222
        # Compare a working tree to a branch without a WT
 
223
        dir1 = branch1_tree.bzrdir
 
224
        dir1.destroy_workingtree()
 
225
        self.assertFalse(dir1.has_workingtree())
 
226
        self.check_b2_vs_b1('diff --old branch2 --new branch1')
 
227
        self.check_b2_vs_b1('diff --old branch2 branch1')
 
228
        self.check_b2_vs_b1('diff branch2 --new branch1')
 
229
        # Compare a branch without a WT to one with a WT
 
230
        self.check_b1_vs_b2('diff --old branch1 --new branch2')
 
231
        self.check_b1_vs_b2('diff --old branch1 branch2')
 
232
        self.check_b1_vs_b2('diff branch1 --new branch2')
 
233
        # Compare a branch with a WT against another without a WT
 
234
        dir2 = branch2_tree.bzrdir
 
235
        dir2.destroy_workingtree()
 
236
        self.assertFalse(dir2.has_workingtree())
 
237
        self.check_b1_vs_b2('diff --old branch1 --new branch2')
 
238
        self.check_b1_vs_b2('diff --old branch1 branch2')
 
239
        self.check_b1_vs_b2('diff branch1 --new branch2')
 
240
 
 
241
    def test_diff_revno_branches(self):
 
242
        self.example_branches()
 
243
        branch2_tree = workingtree.WorkingTree.open_containing('branch2')[0]
 
244
        self.build_tree_contents([('branch2/file', 'even newer content')])
 
245
        branch2_tree.commit(message='update file once more')
 
246
 
 
247
        out, err = self.run_bzr('diff -r revno:1:branch2..revno:1:branch1',
 
248
                                )
 
249
        self.assertEquals('', err)
 
250
        self.assertEquals('', out)
 
251
        out, err = self.run_bzr('diff -r revno:2:branch2..revno:1:branch1',
 
252
                                retcode=1)
 
253
        self.assertEquals('', err)
 
254
        self.assertEqualDiff("=== modified file 'file'\n"
 
255
                              "--- file\tYYYY-MM-DD HH:MM:SS +ZZZZ\n"
 
256
                              "+++ file\tYYYY-MM-DD HH:MM:SS +ZZZZ\n"
 
257
                              "@@ -1,1 +1,1 @@\n"
 
258
                              "-new content\n"
 
259
                              "+contents of branch1/file\n"
 
260
                              "\n", subst_dates(out))
 
261
 
 
262
    def example_branch2(self):
 
263
        branch1_tree = self.make_branch_and_tree('branch1')
 
264
        self.build_tree_contents([('branch1/file1', 'original line\n')])
 
265
        branch1_tree.add('file1')
 
266
        branch1_tree.commit(message='first commit')
 
267
        self.build_tree_contents([('branch1/file1', 'repo line\n')])
 
268
        branch1_tree.commit(message='second commit')
 
269
        return branch1_tree
 
270
 
 
271
    def test_diff_to_working_tree(self):
 
272
        self.example_branch2()
 
273
        self.build_tree_contents([('branch1/file1', 'new line')])
 
274
        output = self.run_bzr('diff -r 1.. branch1', retcode=1)
 
275
        self.assertContainsRe(output[0], '\n\\-original line\n\\+new line\n')
 
276
 
 
277
    def test_diff_to_working_tree_in_subdir(self):
 
278
        self.example_branch2()
 
279
        self.build_tree_contents([('branch1/file1', 'new line')])
 
280
        os.mkdir('branch1/dir1')
 
281
        os.chdir('branch1/dir1')
 
282
        output = self.run_bzr('diff -r 1..', retcode=1)
 
283
        self.assertContainsRe(output[0], '\n\\-original line\n\\+new line\n')
 
284
 
 
285
    def test_diff_across_rename(self):
 
286
        """The working tree path should always be considered for diffing"""
 
287
        tree = self.make_example_branch()
 
288
        self.run_bzr('diff -r 0..1 hello', retcode=1)
 
289
        tree.rename_one('hello', 'hello1')
 
290
        self.run_bzr('diff hello1', retcode=1)
 
291
        self.run_bzr('diff -r 0..1 hello1', retcode=1)
 
292
 
 
293
    def test_diff_to_branch_no_working_tree(self):
 
294
        branch1_tree = self.example_branch2()
 
295
        dir1 = branch1_tree.bzrdir
 
296
        dir1.destroy_workingtree()
 
297
        self.assertFalse(dir1.has_workingtree())
 
298
        output = self.run_bzr('diff -r 1.. branch1', retcode=1)
 
299
        self.assertContainsRe(output[0], '\n\\-original line\n\\+repo line\n')
 
300
 
 
301
 
 
302
class TestCheckoutDiff(TestDiff):
 
303
 
 
304
    def make_example_branch(self):
 
305
        tree = super(TestCheckoutDiff, self).make_example_branch()
 
306
        tree = tree.branch.create_checkout('checkout')
 
307
        os.chdir('checkout')
 
308
        return tree
 
309
 
 
310
    def example_branch2(self):
 
311
        tree = super(TestCheckoutDiff, self).example_branch2()
 
312
        os.mkdir('checkouts')
 
313
        tree = tree.branch.create_checkout('checkouts/branch1')
 
314
        os.chdir('checkouts')
 
315
        return tree
 
316
 
 
317
    def example_branches(self):
 
318
        branch1_tree, branch2_tree = super(TestCheckoutDiff, self).example_branches()
 
319
        os.mkdir('checkouts')
 
320
        branch1_tree = branch1_tree.branch.create_checkout('checkouts/branch1')
 
321
        branch2_tree = branch2_tree.branch.create_checkout('checkouts/branch2')
 
322
        os.chdir('checkouts')
 
323
        return branch1_tree, branch2_tree
 
324
 
 
325
 
 
326
class TestDiffLabels(DiffBase):
 
327
 
 
328
    def test_diff_label_removed(self):
 
329
        tree = super(TestDiffLabels, self).make_example_branch()
 
330
        tree.remove('hello', keep_files=False)
 
331
        diff = self.run_bzr('diff', retcode=1)
 
332
        self.assertTrue("=== removed file 'hello'" in diff[0])
 
333
 
 
334
    def test_diff_label_added(self):
 
335
        tree = super(TestDiffLabels, self).make_example_branch()
 
336
        self.build_tree_contents([('barbar', 'barbar')])
 
337
        tree.add('barbar')
 
338
        diff = self.run_bzr('diff', retcode=1)
 
339
        self.assertTrue("=== added file 'barbar'" in diff[0])
 
340
 
 
341
    def test_diff_label_modified(self):
 
342
        super(TestDiffLabels, self).make_example_branch()
 
343
        self.build_tree_contents([('hello', 'barbar')])
 
344
        diff = self.run_bzr('diff', retcode=1)
 
345
        self.assertTrue("=== modified file 'hello'" in diff[0])
 
346
 
 
347
    def test_diff_label_renamed(self):
 
348
        tree = super(TestDiffLabels, self).make_example_branch()
 
349
        tree.rename_one('hello', 'gruezi')
 
350
        diff = self.run_bzr('diff', retcode=1)
 
351
        self.assertTrue("=== renamed file 'hello' => 'gruezi'" in diff[0])
 
352
 
 
353
 
 
354
class TestExternalDiff(DiffBase):
 
355
 
 
356
    def test_external_diff(self):
 
357
        """Test that we can spawn an external diff process"""
 
358
        # We have to use run_bzr_subprocess, because we need to
 
359
        # test writing directly to stdout, (there was a bug in
 
360
        # subprocess.py that we had to workaround).
 
361
        # However, if 'diff' may not be available
 
362
        self.make_example_branch()
 
363
        orig_progress = os.environ.get('BZR_PROGRESS_BAR')
 
364
        try:
 
365
            os.environ['BZR_PROGRESS_BAR'] = 'none'
 
366
            out, err = self.run_bzr_subprocess('diff -r 1 --diff-options -ub',
 
367
                                               universal_newlines=True,
 
368
                                               retcode=None)
 
369
        finally:
 
370
            if orig_progress is None:
 
371
                del os.environ['BZR_PROGRESS_BAR']
 
372
            else:
 
373
                os.environ['BZR_PROGRESS_BAR'] = orig_progress
 
374
 
 
375
        if 'Diff is not installed on this machine' in err:
 
376
            raise TestSkipped("No external 'diff' is available")
 
377
        self.assertEqual('', err)
 
378
        # We have to skip the stuff in the middle, because it depends
 
379
        # on time.time()
 
380
        self.assertStartsWith(out, "=== added file 'goodbye'\n"
 
381
                                   "--- goodbye\t1970-01-01 00:00:00 +0000\n"
 
382
                                   "+++ goodbye\t")
 
383
        self.assertEndsWith(out, "\n@@ -0,0 +1 @@\n"
 
384
                                 "+baz\n\n")
 
385
 
 
386
 
 
387
class TestDiffOutput(DiffBase):
 
388
 
 
389
    def test_diff_output(self):
 
390
        # check that output doesn't mangle line-endings
 
391
        self.make_example_branch()
 
392
        self.build_tree_contents([('hello', 'hello world!\n')])
 
393
        output = self.run_bzr_subprocess('diff', retcode=1)[0]
 
394
        self.assert_('\n+hello world!\n' in output)