/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
2225.1.1 by Aaron Bentley
Added revert change display, with tests
1
# Copyright (C) 2007 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
1551.10.6 by Aaron Bentley
Support kind changes in tree deltas
17
import os
3874.3.5 by Vincent Ladeuil
Add a 'path_filter' parameter to delta.show().
18
from cStringIO import StringIO
1551.10.6 by Aaron Bentley
Support kind changes in tree deltas
19
2225.1.1 by Aaron Bentley
Added revert change display, with tests
20
from bzrlib import (
1551.10.6 by Aaron Bentley
Support kind changes in tree deltas
21
    delta as _mod_delta,
3874.3.5 by Vincent Ladeuil
Add a 'path_filter' parameter to delta.show().
22
    revision as _mod_revision,
2225.1.1 by Aaron Bentley
Added revert change display, with tests
23
    tests,
24
    )
25
26
2225.1.2 by Aaron Bentley
Ensure that changes are detected correctly
27
class InstrumentedReporter(object):
28
    def __init__(self):
29
        self.calls = []
30
31
    def report(self, file_id, path, versioned, renamed, modified, exe_change,
32
               kind):
33
        self.calls.append((file_id, path, versioned, renamed, modified,
34
                           exe_change, kind))
35
2225.1.4 by Aaron Bentley
PEP8 cleanup
36
2225.1.1 by Aaron Bentley
Added revert change display, with tests
37
class TestReportChanges(tests.TestCase):
2225.1.4 by Aaron Bentley
PEP8 cleanup
38
    """Test the new change reporting infrastructure"""
2225.1.1 by Aaron Bentley
Added revert change display, with tests
39
2225.1.3 by Aaron Bentley
change method names to assertFoo
40
    def assertReport(self, expected, file_id='fid', path='path',
41
                     versioned_change='unchanged', renamed=False,
42
                     modified='unchanged', exe_change=False,
2255.7.97 by Robert Collins
Teach delta.report_changes about unversioned files, removing all inventory access during status --short.
43
                     kind=('file', 'file'), old_path=None,
44
                     unversioned_filter=None):
2225.1.1 by Aaron Bentley
Added revert change display, with tests
45
        result = []
46
        def result_line(format, *args):
47
            result.append(format % args)
1551.10.25 by Aaron Bentley
Make ChangeReporter private
48
        reporter = _mod_delta._ChangeReporter(result_line,
2255.7.97 by Robert Collins
Teach delta.report_changes about unversioned files, removing all inventory access during status --short.
49
            unversioned_filter=unversioned_filter)
2255.7.96 by Robert Collins
Change _iter_changes interface to yield both old and new paths.
50
        reporter.report(file_id, (old_path, path), versioned_change, renamed,
51
            modified, exe_change, kind)
2255.7.97 by Robert Collins
Teach delta.report_changes about unversioned files, removing all inventory access during status --short.
52
        if expected is not None:
53
            self.assertEqualDiff(expected, result[0])
54
        else:
55
            self.assertEqual([], result)
2225.1.1 by Aaron Bentley
Added revert change display, with tests
56
57
    def test_rename(self):
2225.1.3 by Aaron Bentley
change method names to assertFoo
58
        self.assertReport('R   old => path', renamed=True, old_path='old')
59
        self.assertReport('    path')
1551.10.12 by Aaron Bentley
Handle simultaneous creation+rename
60
        self.assertReport('RN  old => path', renamed=True, old_path='old',
61
                          modified='created', kind=(None, 'file'))
2225.1.1 by Aaron Bentley
Added revert change display, with tests
62
63
    def test_kind(self):
2225.1.3 by Aaron Bentley
change method names to assertFoo
64
        self.assertReport(' K  path => path/', modified='kind changed',
2255.7.96 by Robert Collins
Change _iter_changes interface to yield both old and new paths.
65
                          kind=('file', 'directory'), old_path='path')
2225.1.3 by Aaron Bentley
change method names to assertFoo
66
        self.assertReport(' K  path/ => path', modified='kind changed',
67
                          kind=('directory', 'file'), old_path='old')
68
        self.assertReport('RK  old => path/', renamed=True,
2225.1.5 by Aaron Bentley
Clean up whitespace changes
69
                          modified='kind changed',
2225.1.3 by Aaron Bentley
change method names to assertFoo
70
                          kind=('file', 'directory'), old_path='old')
2225.1.1 by Aaron Bentley
Added revert change display, with tests
71
    def test_new(self):
2225.1.3 by Aaron Bentley
change method names to assertFoo
72
        self.assertReport(' N  path/', modified='created',
73
                          kind=(None, 'directory'))
74
        self.assertReport('+   path/', versioned_change='added',
75
                          modified='unchanged', kind=(None, 'directory'))
1551.10.11 by Aaron Bentley
Handle case where file-id only is added
76
        self.assertReport('+   path', versioned_change='added',
77
                          modified='unchanged', kind=(None, None))
2225.1.3 by Aaron Bentley
change method names to assertFoo
78
        self.assertReport('+N  path/', versioned_change='added',
79
                          modified='created', kind=(None, 'directory'))
80
        self.assertReport('+M  path/', versioned_change='added',
81
                          modified='modified', kind=(None, 'directory'))
2225.1.1 by Aaron Bentley
Added revert change display, with tests
82
83
    def test_removal(self):
2225.1.3 by Aaron Bentley
change method names to assertFoo
84
        self.assertReport(' D  path/', modified='deleted',
85
                          kind=('directory', None), old_path='old')
86
        self.assertReport('-   path/', versioned_change='removed',
2255.2.232 by Robert Collins
Make WorkingTree4 report support for references based on the repositories capabilities.
87
                          old_path='path',
2225.1.3 by Aaron Bentley
change method names to assertFoo
88
                          kind=(None, 'directory'))
89
        self.assertReport('-D  path', versioned_change='removed',
2255.2.232 by Robert Collins
Make WorkingTree4 report support for references based on the repositories capabilities.
90
                          old_path='path',
2225.1.3 by Aaron Bentley
change method names to assertFoo
91
                          modified='deleted', kind=('file', 'directory'))
2225.1.1 by Aaron Bentley
Added revert change display, with tests
92
93
    def test_modification(self):
2225.1.3 by Aaron Bentley
change method names to assertFoo
94
        self.assertReport(' M  path', modified='modified')
95
        self.assertReport(' M* path', modified='modified', exe_change=True)
2225.1.2 by Aaron Bentley
Ensure that changes are detected correctly
96
2255.7.97 by Robert Collins
Teach delta.report_changes about unversioned files, removing all inventory access during status --short.
97
    def test_unversioned(self):
98
        # by default any unversioned file is output
99
        self.assertReport('?   subdir/foo~', file_id=None, path='subdir/foo~',
100
            old_path=None, versioned_change='unversioned',
101
            renamed=False, modified='created', exe_change=False,
102
            kind=(None, 'file'))
103
        # but we can choose to filter these. Probably that should be done 
104
        # close to the tree, but this is a reasonable starting point.
105
        self.assertReport(None, file_id=None, path='subdir/foo~',
106
            old_path=None, versioned_change='unversioned',
107
            renamed=False, modified='created', exe_change=False,
108
            kind=(None, 'file'), unversioned_filter=lambda x:True)
109
2225.1.3 by Aaron Bentley
change method names to assertFoo
110
    def assertChangesEqual(self,
111
                           file_id='fid',
2255.7.97 by Robert Collins
Teach delta.report_changes about unversioned files, removing all inventory access during status --short.
112
                           paths=('path', 'path'),
2225.1.3 by Aaron Bentley
change method names to assertFoo
113
                           content_change=False,
114
                           versioned=(True, True),
115
                           parent_id=('pid', 'pid'),
116
                           name=('name', 'name'),
117
                           kind=('file', 'file'),
118
                           executable=(False, False),
119
                           versioned_change='unchanged',
120
                           renamed=False,
121
                           modified='unchanged',
122
                           exe_change=False):
2225.1.2 by Aaron Bentley
Ensure that changes are detected correctly
123
        reporter = InstrumentedReporter()
2255.7.97 by Robert Collins
Teach delta.report_changes about unversioned files, removing all inventory access during status --short.
124
        _mod_delta.report_changes([(file_id, paths, content_change, versioned,
1551.10.6 by Aaron Bentley
Support kind changes in tree deltas
125
            parent_id, name, kind, executable)], reporter)
2225.1.2 by Aaron Bentley
Ensure that changes are detected correctly
126
        output = reporter.calls[0]
127
        self.assertEqual(file_id, output[0])
2255.7.97 by Robert Collins
Teach delta.report_changes about unversioned files, removing all inventory access during status --short.
128
        self.assertEqual(paths, output[1])
2225.1.2 by Aaron Bentley
Ensure that changes are detected correctly
129
        self.assertEqual(versioned_change, output[2])
130
        self.assertEqual(renamed, output[3])
131
        self.assertEqual(modified, output[4])
132
        self.assertEqual(exe_change, output[5])
133
        self.assertEqual(kind, output[6])
134
135
    def test_report_changes(self):
136
        """Test change detection of report_changes"""
137
        #Ensure no changes are detected by default
2225.1.3 by Aaron Bentley
change method names to assertFoo
138
        self.assertChangesEqual(modified='unchanged', renamed=False,
139
                                versioned_change='unchanged',
140
                                exe_change=False)
141
        self.assertChangesEqual(modified='kind changed',
142
                                kind=('file', 'directory'))
143
        self.assertChangesEqual(modified='created', kind=(None, 'directory'))
144
        self.assertChangesEqual(modified='deleted', kind=('directory', None))
145
        self.assertChangesEqual(content_change=True, modified='modified')
146
        self.assertChangesEqual(renamed=True, name=('old', 'new'))
147
        self.assertChangesEqual(renamed=True,
148
                                parent_id=('old-parent', 'new-parent'))
149
        self.assertChangesEqual(versioned_change='added',
150
                                versioned=(False, True))
151
        self.assertChangesEqual(versioned_change='removed',
152
                                versioned=(True, False))
2225.1.2 by Aaron Bentley
Ensure that changes are detected correctly
153
        # execute bit is only detected as "changed" if the file is and was
154
        # a regular file.
2225.1.3 by Aaron Bentley
change method names to assertFoo
155
        self.assertChangesEqual(exe_change=True, executable=(True, False))
156
        self.assertChangesEqual(exe_change=False, executable=(True, False),
157
                                kind=('directory', 'directory'))
158
        self.assertChangesEqual(exe_change=False, modified='kind changed',
159
                                executable=(False, True),
160
                                kind=('directory', 'file'))
1551.11.3 by Aaron Bentley
Use tree transform to emit upcoming change list
161
        self.assertChangesEqual(parent_id=('pid', None))
2225.1.2 by Aaron Bentley
Ensure that changes are detected correctly
162
163
        # Now make sure they all work together
2225.1.3 by Aaron Bentley
change method names to assertFoo
164
        self.assertChangesEqual(versioned_change='removed',
165
                                modified='deleted', versioned=(True, False),
166
                                kind=('directory', None))
167
        self.assertChangesEqual(versioned_change='removed',
168
                                modified='created', versioned=(True, False),
169
                                kind=(None, 'file'))
170
        self.assertChangesEqual(versioned_change='removed',
171
                                modified='modified', renamed=True,
172
                                exe_change=True, versioned=(True, False),
173
                                content_change=True, name=('old', 'new'),
174
                                executable=(False, True))
1551.10.6 by Aaron Bentley
Support kind changes in tree deltas
175
2255.7.97 by Robert Collins
Teach delta.report_changes about unversioned files, removing all inventory access during status --short.
176
    def test_report_unversioned(self):
177
        """Unversioned entries are reported well."""
178
        self.assertChangesEqual(file_id=None, paths=(None, 'full/path'),
179
                           content_change=True,
180
                           versioned=(False, False),
181
                           parent_id=(None, None),
182
                           name=(None, 'path'),
183
                           kind=(None, 'file'),
184
                           executable=(None, False),
185
                           versioned_change='unversioned',
186
                           renamed=False,
187
                           modified='created',
188
                           exe_change=False)
189
1551.10.6 by Aaron Bentley
Support kind changes in tree deltas
190
3874.3.5 by Vincent Ladeuil
Add a 'path_filter' parameter to delta.show().
191
class TestChangesFrom(tests.TestCaseWithTransport):
1551.10.6 by Aaron Bentley
Support kind changes in tree deltas
192
193
    def show_string(self, delta, *args,  **kwargs):
194
        to_file = StringIO()
195
        delta.show(to_file, *args, **kwargs)
196
        return to_file.getvalue()
197
198
    def test_kind_change(self):
199
        """Doing a status when a file has changed kind should work"""
200
        tree = self.make_branch_and_tree('.')
201
        self.build_tree(['filename'])
202
        tree.add('filename', 'file-id')
203
        tree.commit('added filename')
204
        os.unlink('filename')
205
        self.build_tree(['filename/'])
206
        delta = tree.changes_from(tree.basis_tree())
207
        self.assertEqual([('filename', 'file-id', 'file', 'directory')],
208
                         delta.kind_changed)
209
        self.assertEqual([], delta.added)
210
        self.assertEqual([], delta.removed)
211
        self.assertEqual([], delta.renamed)
212
        self.assertEqual([], delta.modified)
213
        self.assertEqual([], delta.unchanged)
214
        self.assertTrue(delta.has_changed())
215
        self.assertTrue(delta.touches_file_id('file-id'))
216
        self.assertEqual('kind changed:\n  filename (file => directory)\n',
217
                         self.show_string(delta))
218
        other_delta = _mod_delta.TreeDelta()
219
        self.assertNotEqual(other_delta, delta)
220
        other_delta.kind_changed = [('filename', 'file-id', 'file',
221
                                     'symlink')]
222
        self.assertNotEqual(other_delta, delta)
223
        other_delta.kind_changed = [('filename', 'file-id', 'file',
224
                                     'directory')]
225
        self.assertEqual(other_delta, delta)
226
        self.assertEqualDiff("TreeDelta(added=[], removed=[], renamed=[],"
227
            " kind_changed=[(u'filename', 'file-id', 'file', 'directory')],"
2255.7.90 by Robert Collins
Add unversioned path reporting to TreeDelta.
228
            " modified=[], unchanged=[], unversioned=[])", repr(delta))
1551.10.6 by Aaron Bentley
Support kind changes in tree deltas
229
        self.assertEqual('K  filename (file => directory) file-id\n',
230
                         self.show_string(delta, show_ids=True,
231
                         short_status=True))
232
233
        tree.rename_one('filename', 'dirname')
234
        delta = tree.changes_from(tree.basis_tree())
235
        self.assertEqual([], delta.kind_changed)
236
        # This loses the fact that kind changed, remembering it as a
237
        # modification
238
        self.assertEqual([('filename', 'dirname', 'file-id', 'directory',
239
                           True, False)], delta.renamed)
240
        self.assertTrue(delta.has_changed())
241
        self.assertTrue(delta.touches_file_id('file-id'))
3874.3.5 by Vincent Ladeuil
Add a 'path_filter' parameter to delta.show().
242
243
244
class TestDeltaShow(tests.TestCaseWithTransport):
245
246
    def _get_delta(self):
247
        # We build the delta from a real tree to avoid depending on internal
248
        # implementation details.
249
        wt = self.make_branch_and_tree('branch')
250
        self.build_tree_contents([('branch/f1', '1\n'),
251
                                  ('branch/f2', '2\n'),
252
                                  ('branch/f3', '3\n'),
253
                                  ('branch/f4', '4\n'),
254
                                  ('branch/dir/',),
255
                                 ])
256
        wt.add(['f1', 'f2', 'f3', 'f4', 'dir'],
257
               ['f1-id', 'f2-id', 'f3-id', 'f4-id', 'dir-id'])
258
        wt.commit('commit one', rev_id='1')
259
260
        long_status = """added:
3874.3.6 by Vincent Ladeuil
Make the filter work for paths and file ids.
261
  dir/
3874.3.5 by Vincent Ladeuil
Add a 'path_filter' parameter to delta.show().
262
  f1
263
  f2
264
  f3
265
  f4
266
"""
3874.3.6 by Vincent Ladeuil
Make the filter work for paths and file ids.
267
        short_status = """A  dir/
268
A  f1
3874.3.5 by Vincent Ladeuil
Add a 'path_filter' parameter to delta.show().
269
A  f2
270
A  f3
271
A  f4
272
"""
273
274
        repo = wt.branch.repository
275
        d = wt.changes_from(repo.revision_tree(_mod_revision.NULL_REVISION))
276
        return d, long_status, short_status
277
278
    def test_delta_show_short_status_no_filter(self):
279
        d, long_status, short_status = self._get_delta()
280
        out = StringIO()
281
        d.show(out, short_status=True)
282
        self.assertEquals(short_status, out.getvalue())
283
284
    def test_delta_show_long_status_no_filter(self):
285
        d, long_status, short_status = self._get_delta()
286
        out = StringIO()
287
        d.show(out, short_status=False)
288
        self.assertEquals(long_status, out.getvalue())
289
290
    def test_delta_show_no_filter(self):
291
        d, long_status, short_status = self._get_delta()
292
        out = StringIO()
3874.3.6 by Vincent Ladeuil
Make the filter work for paths and file ids.
293
        def not_a_filter(path, file_id):
3874.3.5 by Vincent Ladeuil
Add a 'path_filter' parameter to delta.show().
294
            return True
3874.3.6 by Vincent Ladeuil
Make the filter work for paths and file ids.
295
        d.show(out, short_status=True, filter=not_a_filter)
3874.3.5 by Vincent Ladeuil
Add a 'path_filter' parameter to delta.show().
296
        self.assertEquals(short_status, out.getvalue())
297
298
    def test_delta_show_short_status_single_file_filter(self):
299
        d, long_status, short_status = self._get_delta()
300
        out = StringIO()
3874.3.6 by Vincent Ladeuil
Make the filter work for paths and file ids.
301
        def only_f2(path, file_id):
3874.3.5 by Vincent Ladeuil
Add a 'path_filter' parameter to delta.show().
302
            return path == 'f2'
3874.3.6 by Vincent Ladeuil
Make the filter work for paths and file ids.
303
        d.show(out, short_status=True, filter=only_f2)
3874.3.5 by Vincent Ladeuil
Add a 'path_filter' parameter to delta.show().
304
        self.assertEquals("A  f2\n", out.getvalue())
305
306
    def test_delta_show_long_status_single_file_filter(self):
307
        d, long_status, short_status = self._get_delta()
308
        out = StringIO()
3874.3.6 by Vincent Ladeuil
Make the filter work for paths and file ids.
309
        def only_f2(path, file_id):
3874.3.5 by Vincent Ladeuil
Add a 'path_filter' parameter to delta.show().
310
            return path == 'f2'
3874.3.6 by Vincent Ladeuil
Make the filter work for paths and file ids.
311
        d.show(out, short_status=False, filter=only_f2)
3874.3.5 by Vincent Ladeuil
Add a 'path_filter' parameter to delta.show().
312
        self.assertEquals("added:\n  f2\n", out.getvalue())
3874.3.6 by Vincent Ladeuil
Make the filter work for paths and file ids.
313
314
    def test_delta_show_short_status_single_file_id_filter(self):
315
        d, long_status, short_status = self._get_delta()
316
        out = StringIO()
317
        def only_f2_id(path, file_id):
318
            return file_id == 'f2-id'
319
        d.show(out, short_status=True, filter=only_f2_id)
320
        self.assertEquals("A  f2\n", out.getvalue())
321