/b-gtk/fix-viz

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/b-gtk/fix-viz
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
1
# Copyright (C) 2007 John Arbash Meinel <john@arbash-meinel.com>
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
17
"""Test the Commit functionality."""
18
278.1.16 by John Arbash Meinel
Implement the file changes list on top of _iter_changes rather than
19
import os
20
278.1.23 by John Arbash Meinel
Beginning to support actual commit.
21
import gtk
22
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
23
from bzrlib import (
24
    tests,
25
    revision,
26
    )
278.1.27 by John Arbash Meinel
Add the ability to commit just specific files.
27
from bzrlib.util import bencode
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
28
29
from bzrlib.plugins.gtk import commit
30
31
32
# TODO: All we need is basic ancestry code to test this, we shouldn't need a
33
# TestCaseWithTransport, just a TestCaseWithMemoryTransport or somesuch.
34
35
class TestPendingRevisions(tests.TestCaseWithTransport):
36
37
    def test_pending_revisions_none(self):
38
        tree = self.make_branch_and_tree('.')
39
        tree.commit('one')
40
41
        self.assertIs(None, commit.pending_revisions(tree))
42
43
    def test_pending_revisions_simple(self):
44
        tree = self.make_branch_and_tree('tree')
45
        rev_id1 = tree.commit('one')
46
        tree2 = tree.bzrdir.sprout('tree2').open_workingtree()
47
        rev_id2 = tree2.commit('two')
48
        tree.merge_from_branch(tree2.branch)
49
        self.assertEqual([rev_id1, rev_id2], tree.get_parent_ids())
50
51
        pending_revisions = commit.pending_revisions(tree)
52
        # One primary merge
53
        self.assertEqual(1, len(pending_revisions))
54
        # Revision == rev_id2
55
        self.assertEqual(rev_id2, pending_revisions[0][0].revision_id)
56
        # No children of this revision.
57
        self.assertEqual([], pending_revisions[0][1])
58
59
    def test_pending_revisions_with_children(self):
60
        tree = self.make_branch_and_tree('tree')
61
        rev_id1 = tree.commit('one')
62
        tree2 = tree.bzrdir.sprout('tree2').open_workingtree()
63
        rev_id2 = tree2.commit('two')
64
        rev_id3 = tree2.commit('three')
65
        rev_id4 = tree2.commit('four')
66
        tree.merge_from_branch(tree2.branch)
67
        self.assertEqual([rev_id1, rev_id4], tree.get_parent_ids())
68
69
        pending_revisions = commit.pending_revisions(tree)
70
        # One primary merge
71
        self.assertEqual(1, len(pending_revisions))
72
        # Revision == rev_id2
73
        self.assertEqual(rev_id4, pending_revisions[0][0].revision_id)
74
        # Two children for this revision
75
        self.assertEqual(2, len(pending_revisions[0][1]))
76
        self.assertEqual(rev_id3, pending_revisions[0][1][0].revision_id)
77
        self.assertEqual(rev_id2, pending_revisions[0][1][1].revision_id)
78
79
    def test_pending_revisions_multi_merge(self):
80
        tree = self.make_branch_and_tree('tree')
81
        rev_id1 = tree.commit('one')
82
        tree2 = tree.bzrdir.sprout('tree2').open_workingtree()
83
        rev_id2 = tree2.commit('two')
84
        rev_id3 = tree2.commit('three')
85
        tree3 = tree2.bzrdir.sprout('tree3').open_workingtree()
86
        rev_id4 = tree3.commit('four')
87
        rev_id5 = tree3.commit('five')
88
        tree.merge_from_branch(tree2.branch)
89
        tree.merge_from_branch(tree3.branch)
90
        self.assertEqual([rev_id1, rev_id3, rev_id5], tree.get_parent_ids())
91
92
        pending_revisions = commit.pending_revisions(tree)
93
        # Two primary merges
94
        self.assertEqual(2, len(pending_revisions))
95
        # Revision == rev_id2
96
        self.assertEqual(rev_id3, pending_revisions[0][0].revision_id)
97
        self.assertEqual(rev_id5, pending_revisions[1][0].revision_id)
98
        # One child for the first merge
99
        self.assertEqual(1, len(pending_revisions[0][1]))
100
        self.assertEqual(rev_id2, pending_revisions[0][1][0].revision_id)
101
        # One child for the second merge
102
        self.assertEqual(1, len(pending_revisions[1][1]))
103
        self.assertEqual(rev_id4, pending_revisions[1][1][0].revision_id)
104
105
106
class Test_RevToPendingInfo(tests.TestCaseWithTransport):
107
108
    def test_basic_info(self):
109
        tree = self.make_branch_and_tree('tree')
110
        rev_id = tree.commit('Multiline\ncommit\nmessage',
111
                             committer='Joe Foo <joe@foo.com>',
112
                             timestamp=1191012408.674,
113
                             timezone=-18000
114
                             )
115
        rev = tree.branch.repository.get_revision(rev_id)
116
        rev_dict = commit.CommitDialog._rev_to_pending_info(rev)
117
        self.assertEqual({'committer':'Joe Foo',
118
                          'summary':'Multiline',
119
                          'date':'2007-09-28',
120
                          'revision_id':rev_id,
121
                         }, rev_dict)
122
123
124
class CommitDialogNoWidgets(commit.CommitDialog):
125
126
    def construct(self):
127
        pass # Don't create any widgets here
128
278.1.14 by John Arbash Meinel
Tests that we fill out the pending list correctly.
129
    def fill_in_data(self):
130
        pass # With no widgets, there are no widgets to fill out
131
132
133
class TestCommitDialogSimple(tests.TestCaseWithTransport):
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
134
135
    def test_setup_parameters_no_pending(self):
136
        tree = self.make_branch_and_tree('tree')
137
        rev_id = tree.commit('first')
138
139
        dlg = CommitDialogNoWidgets(tree)
140
        self.assertEqual(rev_id, dlg._basis_tree.get_revision_id())
141
        self.assertIs(None, dlg._pending)
142
        self.assertFalse(dlg._is_checkout)
143
144
    def test_setup_parameters_checkout(self):
145
        tree = self.make_branch_and_tree('tree')
146
        rev_id = tree.commit('first')
147
        tree2 = tree.bzrdir.sprout('tree2').open_workingtree()
148
        tree2.branch.bind(tree.branch)
149
150
        dlg = CommitDialogNoWidgets(tree2)
151
        self.assertEqual(rev_id, dlg._basis_tree.get_revision_id())
152
        self.assertIs(None, dlg._pending)
153
        self.assertTrue(dlg._is_checkout)
154
155
    def test_setup_parameters_pending(self):
156
        tree = self.make_branch_and_tree('tree')
157
        rev_id1 = tree.commit('one')
158
        tree2 = tree.bzrdir.sprout('tree2').open_workingtree()
159
        rev_id2 = tree2.commit('two')
160
        tree.merge_from_branch(tree2.branch)
161
162
        dlg = CommitDialogNoWidgets(tree)
163
        self.assertEqual(rev_id1, dlg._basis_tree.get_revision_id())
164
        self.assertIsNot(None, dlg._pending)
165
        self.assertEqual(1, len(dlg._pending))
166
        self.assertEqual(rev_id2, dlg._pending[0][0].revision_id)
167
168
    def test_setup_parameters_delta(self):
169
        tree = self.make_branch_and_tree('tree')
170
        self.build_tree(['tree/a'])
171
        tree.add(['a'], ['a-id'])
172
173
        dlg = CommitDialogNoWidgets(tree)
278.1.12 by John Arbash Meinel
Delay computing the delta, and clean up some of the diff view names.
174
        self.assertIs(None, dlg._delta)
175
        dlg._compute_delta()
176
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
177
        delta = dlg._delta
178
        self.assertEqual([], delta.modified)
179
        self.assertEqual([], delta.renamed)
180
        self.assertEqual([], delta.removed)
181
        self.assertEqual([(u'a', 'a-id', 'file')], delta.added)
278.1.14 by John Arbash Meinel
Tests that we fill out the pending list correctly.
182
183
184
class TestCommitDialog(tests.TestCaseWithTransport):
185
278.1.25 by John Arbash Meinel
Add the 'Only Commit Locally' checkbox, we may want to put it elsewhere, though.
186
    def test_bound(self):
187
        tree = self.make_branch_and_tree('tree')
188
        rev_id = tree.commit('first')
189
        tree2 = tree.bzrdir.sprout('tree2').open_workingtree()
190
        tree2.branch.bind(tree.branch)
191
192
        # tree is not a checkout
193
        dlg = commit.CommitDialog(tree)
194
        self.assertFalse(dlg._check_local.get_property('visible'))
195
196
        # tree2 is a checkout
197
        dlg2 = commit.CommitDialog(tree2)
198
        self.assertTrue(dlg2._check_local.get_property('visible'))
199
278.1.14 by John Arbash Meinel
Tests that we fill out the pending list correctly.
200
    def test_no_pending(self):
201
        tree = self.make_branch_and_tree('tree')
202
        rev_id1 = tree.commit('one')
203
204
        dlg = commit.CommitDialog(tree)
278.1.25 by John Arbash Meinel
Add the 'Only Commit Locally' checkbox, we may want to put it elsewhere, though.
205
206
        self.assertFalse(dlg._pending_box.get_property('visible'))
207
278.1.17 by John Arbash Meinel
Add a * reference for why you can't change the commit selection.
208
        commit_col = dlg._treeview_files.get_column(0)
209
        self.assertEqual('Commit', commit_col.get_title())
278.1.20 by John Arbash Meinel
We always select the All Files record in the files view,
210
        renderer = commit_col.get_cell_renderers()[0]
211
        self.assertTrue(renderer.get_active())
278.1.14 by John Arbash Meinel
Tests that we fill out the pending list correctly.
212
213
    def test_pending(self):
214
        tree = self.make_branch_and_tree('tree')
215
        rev_id1 = tree.commit('one')
216
217
        tree2 = tree.bzrdir.sprout('tree2').open_workingtree()
218
        rev_id2 = tree2.commit('two',
219
                               committer='Joe Foo <joe@foo.com>',
220
                               timestamp=1191264271.05,
221
                               timezone=+7200)
222
        tree.merge_from_branch(tree2.branch)
223
224
        dlg = commit.CommitDialog(tree)
278.1.25 by John Arbash Meinel
Add the 'Only Commit Locally' checkbox, we may want to put it elsewhere, though.
225
226
        self.assertTrue(dlg._pending_box.get_property('visible'))
227
278.1.17 by John Arbash Meinel
Add a * reference for why you can't change the commit selection.
228
        commit_col = dlg._treeview_files.get_column(0)
229
        self.assertEqual('Commit*', commit_col.get_title())
278.1.20 by John Arbash Meinel
We always select the All Files record in the files view,
230
        renderer = commit_col.get_cell_renderers()[0]
231
        self.assertFalse(renderer.get_active())
278.1.17 by John Arbash Meinel
Add a * reference for why you can't change the commit selection.
232
278.1.15 by John Arbash Meinel
Hook up the list of modified files.
233
        values = [(r[0], r[1], r[2], r[3]) for r in dlg._pending_store]
278.1.14 by John Arbash Meinel
Tests that we fill out the pending list correctly.
234
        self.assertEqual([(rev_id2, '2007-10-01', 'Joe Foo', 'two')], values)
235
236
    def test_pending_multiple(self):
237
        tree = self.make_branch_and_tree('tree')
238
        rev_id1 = tree.commit('one')
239
240
        tree2 = tree.bzrdir.sprout('tree2').open_workingtree()
241
        rev_id2 = tree2.commit('two',
242
                               committer='Joe Foo <joe@foo.com>',
243
                               timestamp=1191264271.05,
244
                               timezone=+7200)
245
        rev_id3 = tree2.commit('three',
246
                               committer='Jerry Foo <jerry@foo.com>',
247
                               timestamp=1191264278.05,
248
                               timezone=+7200)
249
        tree.merge_from_branch(tree2.branch)
250
        tree3 = tree.bzrdir.sprout('tree3').open_workingtree()
251
        rev_id4 = tree3.commit('four',
252
                               committer='Joe Foo <joe@foo.com>',
253
                               timestamp=1191264279.05,
254
                               timezone=+7200)
255
        rev_id5 = tree3.commit('five',
256
                               committer='Jerry Foo <jerry@foo.com>',
257
                               timestamp=1191372278.05,
258
                               timezone=+7200)
259
        tree.merge_from_branch(tree3.branch)
260
261
        dlg = commit.CommitDialog(tree)
262
        # TODO: assert that the pending box is set to show
278.1.15 by John Arbash Meinel
Hook up the list of modified files.
263
        values = [(r[0], r[1], r[2], r[3]) for r in dlg._pending_store]
278.1.14 by John Arbash Meinel
Tests that we fill out the pending list correctly.
264
        self.assertEqual([(rev_id3, '2007-10-01', 'Jerry Foo', 'three'),
265
                          (rev_id2, '2007-10-01', 'Joe Foo', 'two'),
266
                          (rev_id5, '2007-10-03', 'Jerry Foo', 'five'),
267
                          (rev_id4, '2007-10-01', 'Joe Foo', 'four'),
268
                         ], values)
278.1.15 by John Arbash Meinel
Hook up the list of modified files.
269
278.1.16 by John Arbash Meinel
Implement the file changes list on top of _iter_changes rather than
270
    def test_filelist_added(self):
278.1.15 by John Arbash Meinel
Hook up the list of modified files.
271
        tree = self.make_branch_and_tree('tree')
272
        self.build_tree(['tree/a', 'tree/b/', 'tree/b/c'])
273
        tree.add(['a', 'b', 'b/c'], ['a-id', 'b-id', 'c-id'])
274
275
        dlg = commit.CommitDialog(tree)
276
        values = [(r[0], r[1], r[2], r[3], r[4]) for r in dlg._files_store]
278.1.20 by John Arbash Meinel
We always select the All Files record in the files view,
277
        self.assertEqual([(None, None, True, 'All Files', ''),
278
                          ('a-id', 'a', True, 'a', 'added'),
278.1.15 by John Arbash Meinel
Hook up the list of modified files.
279
                          ('b-id', 'b', True, 'b/', 'added'),
280
                          ('c-id', 'b/c', True, 'b/c', 'added'),
281
                         ], values)
278.1.16 by John Arbash Meinel
Implement the file changes list on top of _iter_changes rather than
282
283
    def test_filelist_renamed(self):
284
        tree = self.make_branch_and_tree('tree')
285
        self.build_tree(['tree/a', 'tree/b/', 'tree/b/c'])
286
        tree.add(['a', 'b', 'b/c'], ['a-id', 'b-id', 'c-id'])
287
        rev_id1 = tree.commit('one')
288
289
        tree.rename_one('b', 'd')
290
        tree.rename_one('a', 'd/a')
291
292
        dlg = commit.CommitDialog(tree)
293
        values = [(r[0], r[1], r[2], r[3], r[4]) for r in dlg._files_store]
278.1.20 by John Arbash Meinel
We always select the All Files record in the files view,
294
        self.assertEqual([(None, None, True, 'All Files', ''),
295
                          ('b-id', 'd', True, 'b/ => d/', 'renamed'),
278.1.16 by John Arbash Meinel
Implement the file changes list on top of _iter_changes rather than
296
                          ('a-id', 'd/a', True, 'a => d/a', 'renamed'),
297
                         ], values)
298
299
    def test_filelist_modified(self):
300
        tree = self.make_branch_and_tree('tree')
301
        self.build_tree(['tree/a'])
302
        tree.add(['a'], ['a-id'])
303
        rev_id1 = tree.commit('one')
304
305
        self.build_tree_contents([('tree/a', 'new contents for a\n')])
306
307
        dlg = commit.CommitDialog(tree)
308
        values = [(r[0], r[1], r[2], r[3], r[4]) for r in dlg._files_store]
278.1.20 by John Arbash Meinel
We always select the All Files record in the files view,
309
        self.assertEqual([(None, None, True, 'All Files', ''),
310
                          ('a-id', 'a', True, 'a', 'modified'),
278.1.16 by John Arbash Meinel
Implement the file changes list on top of _iter_changes rather than
311
                         ], values)
312
313
    def test_filelist_renamed_and_modified(self):
314
        tree = self.make_branch_and_tree('tree')
315
        self.build_tree(['tree/a', 'tree/b/', 'tree/b/c'])
316
        tree.add(['a', 'b', 'b/c'], ['a-id', 'b-id', 'c-id'])
317
        rev_id1 = tree.commit('one')
318
319
        tree.rename_one('b', 'd')
320
        tree.rename_one('a', 'd/a')
321
        self.build_tree_contents([('tree/d/a', 'new contents for a\n'),
322
                                  ('tree/d/c', 'new contents for c\n'),
323
                                 ])
324
        # 'c' is not considered renamed, because only its parent was moved, it
325
        # stayed in the same directory
326
327
        dlg = commit.CommitDialog(tree)
328
        values = [(r[0], r[1], r[2], r[3], r[4]) for r in dlg._files_store]
278.1.20 by John Arbash Meinel
We always select the All Files record in the files view,
329
        self.assertEqual([(None, None, True, 'All Files', ''),
330
                          ('b-id', 'd', True, 'b/ => d/', 'renamed'),
278.1.16 by John Arbash Meinel
Implement the file changes list on top of _iter_changes rather than
331
                          ('a-id', 'd/a', True, 'a => d/a', 'renamed and modified'),
332
                          ('c-id', 'd/c', True, 'd/c', 'modified'),
333
                         ], values)
334
335
    def test_filelist_kind_changed(self):
336
        tree = self.make_branch_and_tree('tree')
337
        self.build_tree(['tree/a', 'tree/b'])
338
        tree.add(['a', 'b'], ['a-id', 'b-id'])
339
        tree.commit('one')
340
341
        os.remove('tree/a')
342
        self.build_tree(['tree/a/'])
278.1.17 by John Arbash Meinel
Add a * reference for why you can't change the commit selection.
343
        # XXX:  This is technically valid, and the file list handles it fine,
344
        #       but 'show_diff_trees()' does not, so we skip this part of the
345
        #       test for now.
346
        # tree.rename_one('b', 'c')
347
        # os.remove('tree/c')
348
        # self.build_tree(['tree/c/'])
278.1.16 by John Arbash Meinel
Implement the file changes list on top of _iter_changes rather than
349
350
        dlg = commit.CommitDialog(tree)
351
        values = [(r[0], r[1], r[2], r[3], r[4]) for r in dlg._files_store]
278.1.20 by John Arbash Meinel
We always select the All Files record in the files view,
352
        self.assertEqual([(None, None, True, 'All Files', ''),
353
                          ('a-id', 'a', True, 'a => a/', 'kind changed'),
278.1.17 by John Arbash Meinel
Add a * reference for why you can't change the commit selection.
354
                          # ('b-id', 'c', True, 'b => c/', 'renamed and modified'),
278.1.16 by John Arbash Meinel
Implement the file changes list on top of _iter_changes rather than
355
                         ], values)
356
357
    def test_filelist_removed(self):
358
        tree = self.make_branch_and_tree('tree')
359
        self.build_tree(['tree/a', 'tree/b/'])
360
        tree.add(['a', 'b'], ['a-id', 'b-id'])
361
        tree.commit('one')
362
363
        os.remove('tree/a')
364
        tree.remove('b', force=True)
365
366
        dlg = commit.CommitDialog(tree)
367
        values = [(r[0], r[1], r[2], r[3], r[4]) for r in dlg._files_store]
278.1.20 by John Arbash Meinel
We always select the All Files record in the files view,
368
        self.assertEqual([(None, None, True, 'All Files', ''),
369
                          ('a-id', 'a', True, 'a', 'removed'),
278.1.16 by John Arbash Meinel
Implement the file changes list on top of _iter_changes rather than
370
                          ('b-id', 'b', True, 'b/', 'removed'),
371
                         ], values)
278.1.18 by John Arbash Meinel
Start checking the diff view is correct.
372
373
    def test_diff_view(self):
374
        tree = self.make_branch_and_tree('tree')
375
        self.build_tree(['tree/a', 'tree/b'])
376
        tree.add(['a', 'b'], ['a-id', 'b-id'])
377
        tree.commit('one')
378
379
        self.build_tree_contents([('tree/a', 'new contents for a\n')])
380
        tree.remove('b')
381
382
        dlg = commit.CommitDialog(tree)
383
        diff_buffer = dlg._diff_view.buffer
384
        text = diff_buffer.get_text(diff_buffer.get_start_iter(),
385
                                    diff_buffer.get_end_iter()).splitlines(True)
386
387
        self.assertEqual("=== removed file 'b'\n", text[0])
388
        self.assertContainsRe(text[1],
389
            r"--- b\t\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d [+-]\d\d\d\d")
390
        self.assertEqual('+++ b\t1970-01-01 00:00:00 +0000\n', text[2])
391
        self.assertEqual('@@ -1,1 +0,0 @@\n', text[3])
392
        self.assertEqual('-contents of tree/b\n', text[4])
393
        self.assertEqual('\n', text[5])
394
395
        self.assertEqual("=== modified file 'a'\n", text[6])
396
        self.assertContainsRe(text[7],
397
            r"--- a\t\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d [+-]\d\d\d\d")
398
        self.assertContainsRe(text[8],
399
            r"\+\+\+ a\t\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d [+-]\d\d\d\d")
400
        self.assertEqual('@@ -1,1 +1,1 @@\n', text[9])
401
        self.assertEqual('-contents of tree/a\n', text[10])
402
        self.assertEqual('+new contents for a\n', text[11])
403
        self.assertEqual('\n', text[12])
404
278.1.20 by John Arbash Meinel
We always select the All Files record in the files view,
405
        self.assertEqual('Diff for All Files', dlg._diff_label.get_text())
278.1.19 by John Arbash Meinel
Test what happens when a specific file is selected.
406
407
    def test_file_selection(self):
408
        """Several things should happen when a file has been selected."""
409
        tree = self.make_branch_and_tree('tree')
410
        self.build_tree(['tree/a', 'tree/b'])
411
        tree.add(['a', 'b'], ['a-id', 'b-id'])
412
413
        dlg = commit.CommitDialog(tree)
414
        diff_buffer = dlg._diff_view.buffer
278.1.20 by John Arbash Meinel
We always select the All Files record in the files view,
415
        self.assertEqual('Diff for All Files', dlg._diff_label.get_text())
278.1.21 by John Arbash Meinel
Start tracking the per-file commit messages.
416
        self.assertEqual('File commit message',
417
                         dlg._file_message_expander.get_label())
418
        self.assertFalse(dlg._file_message_expander.get_expanded())
419
        self.assertFalse(dlg._file_message_expander.get_property('sensitive'))
278.1.19 by John Arbash Meinel
Test what happens when a specific file is selected.
420
278.1.20 by John Arbash Meinel
We always select the All Files record in the files view,
421
        dlg._treeview_files.set_cursor((1,))
278.1.19 by John Arbash Meinel
Test what happens when a specific file is selected.
422
        self.assertEqual('Diff for a', dlg._diff_label.get_text())
423
        text = diff_buffer.get_text(diff_buffer.get_start_iter(),
424
                                    diff_buffer.get_end_iter()).splitlines(True)
425
        self.assertEqual("=== added file 'a'\n", text[0])
426
        self.assertContainsRe(text[1],
427
            r"--- a\t\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d [+-]\d\d\d\d")
428
        self.assertContainsRe(text[2],
429
            r"\+\+\+ a\t\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d [+-]\d\d\d\d")
430
        self.assertEqual('@@ -0,0 +1,1 @@\n', text[3])
431
        self.assertEqual('+contents of tree/a\n', text[4])
432
        self.assertEqual('\n', text[5])
278.1.21 by John Arbash Meinel
Start tracking the per-file commit messages.
433
        self.assertEqual('Commit message for a',
434
                         dlg._file_message_expander.get_label())
435
        self.assertTrue(dlg._file_message_expander.get_expanded())
436
        self.assertTrue(dlg._file_message_expander.get_property('sensitive'))
278.1.19 by John Arbash Meinel
Test what happens when a specific file is selected.
437
278.1.20 by John Arbash Meinel
We always select the All Files record in the files view,
438
        dlg._treeview_files.set_cursor((2,))
278.1.19 by John Arbash Meinel
Test what happens when a specific file is selected.
439
        self.assertEqual('Diff for b', dlg._diff_label.get_text())
440
        text = diff_buffer.get_text(diff_buffer.get_start_iter(),
441
                                    diff_buffer.get_end_iter()).splitlines(True)
442
        self.assertEqual("=== added file 'b'\n", text[0])
443
        self.assertContainsRe(text[1],
444
            r"--- b\t\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d [+-]\d\d\d\d")
445
        self.assertContainsRe(text[2],
446
            r"\+\+\+ b\t\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d [+-]\d\d\d\d")
447
        self.assertEqual('@@ -0,0 +1,1 @@\n', text[3])
448
        self.assertEqual('+contents of tree/b\n', text[4])
449
        self.assertEqual('\n', text[5])
278.1.21 by John Arbash Meinel
Start tracking the per-file commit messages.
450
        self.assertEqual('Commit message for b',
451
                         dlg._file_message_expander.get_label())
452
        self.assertTrue(dlg._file_message_expander.get_expanded())
453
        self.assertTrue(dlg._file_message_expander.get_property('sensitive'))
454
455
        dlg._treeview_files.set_cursor((0,))
456
        self.assertEqual('Diff for All Files', dlg._diff_label.get_text())
457
        self.assertEqual('File commit message',
458
                         dlg._file_message_expander.get_label())
459
        self.assertFalse(dlg._file_message_expander.get_expanded())
460
        self.assertFalse(dlg._file_message_expander.get_property('sensitive'))
461
462
    def test_file_selection_message(self):
463
        """Selecting a file should bring up its commit message."""
464
        tree = self.make_branch_and_tree('tree')
465
        self.build_tree(['tree/a', 'tree/b/'])
466
        tree.add(['a', 'b'], ['a-id', 'b-id'])
467
468
        def get_file_text():
469
            buf = dlg._file_message_text_view.get_buffer()
470
            return buf.get_text(buf.get_start_iter(), buf.get_end_iter())
471
472
        def get_saved_text(path):
473
            """Get the saved text for a given record."""
474
            return dlg._files_store.get_value(dlg._files_store.get_iter(path), 5)
475
476
        dlg = commit.CommitDialog(tree)
477
        self.assertEqual('File commit message',
478
                         dlg._file_message_expander.get_label())
479
        self.assertFalse(dlg._file_message_expander.get_expanded())
480
        self.assertFalse(dlg._file_message_expander.get_property('sensitive'))
481
        self.assertEqual('', get_file_text())
482
483
        dlg._treeview_files.set_cursor((1,))
484
        self.assertEqual('Commit message for a',
485
                         dlg._file_message_expander.get_label())
486
        self.assertTrue(dlg._file_message_expander.get_expanded())
487
        self.assertTrue(dlg._file_message_expander.get_property('sensitive'))
488
        self.assertEqual('', get_file_text())
489
490
        self.assertEqual('', get_saved_text(1))
278.1.27 by John Arbash Meinel
Add the ability to commit just specific files.
491
        dlg._set_file_commit_message('Some text\nfor a\n')
278.1.21 by John Arbash Meinel
Start tracking the per-file commit messages.
492
        dlg._save_current_file_message()
493
        # We should have updated the ListStore with the new file commit info
494
        self.assertEqual('Some text\nfor a\n', get_saved_text(1))
495
496
        dlg._treeview_files.set_cursor((2,))
497
        self.assertEqual('Commit message for b/',
498
                         dlg._file_message_expander.get_label())
499
        self.assertTrue(dlg._file_message_expander.get_expanded())
500
        self.assertTrue(dlg._file_message_expander.get_property('sensitive'))
501
        self.assertEqual('', get_file_text())
502
503
        self.assertEqual('', get_saved_text(2))
278.1.27 by John Arbash Meinel
Add the ability to commit just specific files.
504
        dlg._set_file_commit_message('More text\nfor b\n')
278.1.21 by John Arbash Meinel
Start tracking the per-file commit messages.
505
        # Now switch back to 'a'. The message should be saved, and the buffer
506
        # should be updated with the other text
507
        dlg._treeview_files.set_cursor((1,))
508
        self.assertEqual('More text\nfor b\n', get_saved_text(2))
509
        self.assertEqual('Commit message for a',
510
                         dlg._file_message_expander.get_label())
511
        self.assertTrue(dlg._file_message_expander.get_expanded())
512
        self.assertTrue(dlg._file_message_expander.get_property('sensitive'))
513
        self.assertEqual('Some text\nfor a\n', get_file_text())
278.1.20 by John Arbash Meinel
We always select the All Files record in the files view,
514
515
    def test_toggle_all_files(self):
516
        """When checking the All Files entry, it should toggle all fields"""
517
        tree = self.make_branch_and_tree('tree')
518
        self.build_tree(['tree/a', 'tree/b/'])
519
        tree.add(['a', 'b'], ['a-id', 'b-id'])
520
521
        dlg = commit.CommitDialog(tree)
522
        self.assertEqual([(None, None, True),
523
                          ('a-id', 'a', True),
524
                          ('b-id', 'b', True),
525
                         ], [(r[0], r[1], r[2]) for r in dlg._files_store])
526
527
        # TODO: jam 20071002 I'm not sure how to exactly trigger a toggle, it
528
        #       looks like we need to call renderer.activate() and pass an
529
        #       event and widget, and lots of other stuff I'm not sure what to
530
        #       do with. So instead, we just call toggle directly, and assume
531
        #       that toggle is hooked in correctly
532
        # column = dlg._treeview_files.get_column(0)
533
        # renderer = column.get_cell_renderers()[0]
534
535
        # Toggle a single entry should set just that entry to False
536
        dlg._toggle_commit(None, 1, dlg._files_store)
537
        self.assertEqual([(None, None, True),
538
                          ('a-id', 'a', False),
539
                          ('b-id', 'b', True),
540
                         ], [(r[0], r[1], r[2]) for r in dlg._files_store])
541
542
        # Toggling the main entry should set all entries
543
        dlg._toggle_commit(None, 0, dlg._files_store)
544
        self.assertEqual([(None, None, False),
545
                          ('a-id', 'a', False),
546
                          ('b-id', 'b', False),
547
                         ], [(r[0], r[1], r[2]) for r in dlg._files_store])
548
549
        dlg._toggle_commit(None, 2, dlg._files_store)
550
        self.assertEqual([(None, None, False),
551
                          ('a-id', 'a', False),
552
                          ('b-id', 'b', True),
553
                         ], [(r[0], r[1], r[2]) for r in dlg._files_store])
554
555
        dlg._toggle_commit(None, 0, dlg._files_store)
556
        self.assertEqual([(None, None, True),
557
                          ('a-id', 'a', True),
558
                          ('b-id', 'b', True),
559
                         ], [(r[0], r[1], r[2]) for r in dlg._files_store])
278.1.23 by John Arbash Meinel
Beginning to support actual commit.
560
278.1.27 by John Arbash Meinel
Add the ability to commit just specific files.
561
    def test_specific_files(self):
562
        tree = self.make_branch_and_tree('tree')
563
        self.build_tree(['tree/a', 'tree/b/'])
564
        tree.add(['a', 'b'], ['a-id', 'b-id'])
565
566
        dlg = commit.CommitDialog(tree)
567
        self.assertEqual((['a', 'b'], []), dlg._get_specific_files())
568
569
        dlg._toggle_commit(None, 0, dlg._files_store)
570
        self.assertEqual(([], []), dlg._get_specific_files())
571
572
        dlg._toggle_commit(None, 1, dlg._files_store)
573
        self.assertEqual((['a'], []), dlg._get_specific_files())
574
575
    def test_specific_files_with_messages(self):
576
        tree = self.make_branch_and_tree('tree')
577
        self.build_tree(['tree/a_file', 'tree/b_dir/'])
578
        tree.add(['a_file', 'b_dir'], ['1a-id', '0b-id'])
579
580
        dlg = commit.CommitDialog(tree)
581
        self.assertEqual((['a_file', 'b_dir'], []), dlg._get_specific_files())
582
583
        dlg._treeview_files.set_cursor((1,))
584
        dlg._set_file_commit_message('Test\nmessage\nfor a_file\n')
585
        dlg._treeview_files.set_cursor((2,))
586
        dlg._set_file_commit_message('message\nfor b_dir\n')
587
588
        self.assertEqual((['a_file', 'b_dir'],
589
                          [{'path':'a_file', 'file_id':'1a-id',
590
                            'message':'Test\nmessage\nfor a_file\n'},
591
                           {'path':'b_dir', 'file_id':'0b-id',
592
                            'message':'message\nfor b_dir\n'},
593
                          ]), dlg._get_specific_files())
594
595
        dlg._toggle_commit(None, 1, dlg._files_store)
596
        self.assertEqual((['b_dir'],
597
                          [{'path':'b_dir', 'file_id':'0b-id',
598
                            'message':'message\nfor b_dir\n'},
599
                          ]), dlg._get_specific_files())
600
278.1.23 by John Arbash Meinel
Beginning to support actual commit.
601
602
class TestCommitDialog_Commit(tests.TestCaseWithTransport):
603
    """Tests on the actual 'commit' button being pushed."""
604
278.1.26 by John Arbash Meinel
Handle pointless commits and trees with unknown files.
605
    def _set_question_yes(self, dlg):
606
        """Set the dialog to answer YES to any questions."""
607
        self.questions = []
608
        def _question_yes(*args):
609
            self.questions.append(args)
610
            self.questions.append('YES')
611
            return gtk.RESPONSE_YES
612
        dlg._question_dialog = _question_yes
613
614
    def _set_question_no(self, dlg):
615
        """Set the dialog to answer NO to any questions."""
616
        self.questions = []
617
        def _question_no(*args):
618
            self.questions.append(args)
619
            self.questions.append('NO')
620
            return gtk.RESPONSE_NO
621
        dlg._question_dialog = _question_no
622
278.1.25 by John Arbash Meinel
Add the 'Only Commit Locally' checkbox, we may want to put it elsewhere, though.
623
    def test_bound_commit_local(self):
624
        tree = self.make_branch_and_tree('tree')
625
        self.build_tree(['tree/a'])
626
        tree.add(['a'], ['a-id'])
627
        rev_id1 = tree.commit('one')
628
629
        tree2 = tree.bzrdir.sprout('tree2').open_workingtree()
630
        self.build_tree(['tree2/b'])
631
        tree2.add(['b'], ['b-id'])
632
        tree2.branch.bind(tree.branch)
633
634
        dlg = commit.CommitDialog(tree2)
635
        # With the check box set, it should only effect the local branch
636
        dlg._check_local.set_active(True)
637
        dlg._set_global_commit_message('Commit message\n')
638
        dlg._do_commit()
639
640
        last_rev = tree2.last_revision()
641
        self.assertEqual(last_rev, dlg.committed_revision_id)
642
        self.assertEqual(rev_id1, tree.branch.last_revision())
643
644
    def test_bound_commit_both(self):
645
        tree = self.make_branch_and_tree('tree')
646
        self.build_tree(['tree/a'])
647
        tree.add(['a'], ['a-id'])
648
        rev_id1 = tree.commit('one')
649
650
        tree2 = tree.bzrdir.sprout('tree2').open_workingtree()
651
        self.build_tree(['tree2/b'])
652
        tree2.add(['b'], ['b-id'])
653
        tree2.branch.bind(tree.branch)
654
655
        dlg = commit.CommitDialog(tree2)
656
        # With the check box set, it should only effect the local branch
657
        dlg._check_local.set_active(False)
658
        dlg._set_global_commit_message('Commit message\n')
659
        dlg._do_commit()
660
661
        last_rev = tree2.last_revision()
662
        self.assertEqual(last_rev, dlg.committed_revision_id)
663
        self.assertEqual(last_rev, tree.branch.last_revision())
664
278.1.23 by John Arbash Meinel
Beginning to support actual commit.
665
    def test_commit_no_message(self):
666
        tree = self.make_branch_and_tree('tree')
667
        self.build_tree(['tree/a', 'tree/b'])
668
        tree.add(['a'], ['a-id'])
669
        rev_id = tree.commit('one')
670
671
        tree.add(['b'], ['b-id'])
672
673
        dlg = commit.CommitDialog(tree)
278.1.26 by John Arbash Meinel
Handle pointless commits and trees with unknown files.
674
        self._set_question_no(dlg)
278.1.23 by John Arbash Meinel
Beginning to support actual commit.
675
        dlg._do_commit()
676
        self.assertEqual(
677
            [('Commit with an empty message?',
678
              'You can describe your commit intent in the message.'),
679
              'NO',
278.1.26 by John Arbash Meinel
Handle pointless commits and trees with unknown files.
680
            ], self.questions)
278.1.23 by John Arbash Meinel
Beginning to support actual commit.
681
        # By saying NO, nothing should be committed.
682
        self.assertEqual(rev_id, tree.last_revision())
683
        self.assertIs(None, dlg.committed_revision_id)
278.1.25 by John Arbash Meinel
Add the 'Only Commit Locally' checkbox, we may want to put it elsewhere, though.
684
        self.assertTrue(dlg._global_message_text_view.get_property('is-focus'))
278.1.23 by John Arbash Meinel
Beginning to support actual commit.
685
278.1.26 by John Arbash Meinel
Handle pointless commits and trees with unknown files.
686
        self._set_question_yes(dlg)
278.1.23 by John Arbash Meinel
Beginning to support actual commit.
687
688
        dlg._do_commit()
689
        self.assertEqual(
690
            [('Commit with an empty message?',
691
              'You can describe your commit intent in the message.'),
278.1.26 by John Arbash Meinel
Handle pointless commits and trees with unknown files.
692
              'YES',
693
            ], self.questions)
278.1.23 by John Arbash Meinel
Beginning to support actual commit.
694
        committed = tree.last_revision()
695
        self.assertNotEqual(rev_id, committed)
696
        self.assertEqual(committed, dlg.committed_revision_id)
697
698
    def test_initial_commit(self):
699
        tree = self.make_branch_and_tree('tree')
700
        self.build_tree(['tree/a'])
701
        tree.add(['a'], ['a-id'])
702
703
        dlg = commit.CommitDialog(tree)
278.1.25 by John Arbash Meinel
Add the 'Only Commit Locally' checkbox, we may want to put it elsewhere, though.
704
        dlg._set_global_commit_message('Some text\n')
278.1.23 by John Arbash Meinel
Beginning to support actual commit.
705
        dlg._do_commit()
706
707
        last_rev = tree.last_revision()
708
        self.assertEqual(last_rev, dlg.committed_revision_id)
709
        rev = tree.branch.repository.get_revision(last_rev)
710
        self.assertEqual(last_rev, rev.revision_id)
711
        self.assertEqual('Some text\n', rev.message)
278.1.26 by John Arbash Meinel
Handle pointless commits and trees with unknown files.
712
713
    def test_pointless_commit(self):
714
        tree = self.make_branch_and_tree('tree')
715
        self.build_tree(['tree/a'])
716
        tree.add(['a'], ['a-id'])
717
        rev_id1 = tree.commit('one')
718
719
        dlg = commit.CommitDialog(tree)
720
        dlg._set_global_commit_message('Some text\n')
721
722
        self._set_question_no(dlg)
723
        dlg._do_commit()
724
725
        self.assertIs(None, dlg.committed_revision_id)
726
        self.assertEqual(rev_id1, tree.last_revision())
727
        self.assertEqual(
728
            [('Commit with no changes?',
729
              'There are no changes in the working tree.'
730
              ' Do you want to commit anyway?'),
731
              'NO',
732
            ], self.questions)
733
734
        self._set_question_yes(dlg)
735
        dlg._do_commit()
736
737
        rev_id2 = tree.last_revision()
738
        self.assertEqual(rev_id2, dlg.committed_revision_id)
739
        self.assertNotEqual(rev_id1, rev_id2)
740
        self.assertEqual(
741
            [('Commit with no changes?',
742
              'There are no changes in the working tree.'
743
              ' Do you want to commit anyway?'),
744
              'YES',
745
            ], self.questions)
746
747
    def test_unknowns(self):
748
        """We should check if there are unknown files."""
749
        tree = self.make_branch_and_tree('tree')
750
        rev_id1 = tree.commit('one')
751
        self.build_tree(['tree/a', 'tree/b'])
752
        tree.add(['a'], ['a-id'])
753
754
        dlg = commit.CommitDialog(tree)
755
        dlg._set_global_commit_message('Some text\n')
756
        self._set_question_no(dlg)
757
758
        dlg._do_commit()
759
760
        self.assertIs(None, dlg.committed_revision_id)
761
        self.assertEqual(rev_id1, tree.last_revision())
762
        self.assertEqual(
763
            [("Commit with unknowns?",
764
              "Unknown files exist in the working tree. Commit anyway?"),
765
              "NO",
766
            ], self.questions)
767
768
        self._set_question_yes(dlg)
769
        dlg._do_commit()
770
771
        rev_id2 = tree.last_revision()
772
        self.assertNotEqual(rev_id1, rev_id2)
773
        self.assertEqual(rev_id2, dlg.committed_revision_id)
774
        self.assertEqual(
775
            [("Commit with unknowns?",
776
              "Unknown files exist in the working tree. Commit anyway?"),
777
              "YES",
778
            ], self.questions)
779
278.1.27 by John Arbash Meinel
Add the ability to commit just specific files.
780
    def test_commit_specific_files(self):
781
        tree = self.make_branch_and_tree('tree')
782
        rev_id1 = tree.commit('one')
783
        self.build_tree(['tree/a', 'tree/b'])
784
        tree.add(['a', 'b'], ['a-id', 'b-id'])
785
786
        dlg = commit.CommitDialog(tree)
787
        dlg._toggle_commit(None, 2, dlg._files_store) # unset 'b'
788
789
        dlg._set_global_commit_message('Committing just "a"\n')
790
        dlg._do_commit()
791
792
        rev_id2 = dlg.committed_revision_id
793
        self.assertIsNot(None, rev_id2)
794
        self.assertEqual(rev_id2, tree.last_revision())
795
796
        rt = tree.branch.repository.revision_tree(rev_id2)
797
        entries = [(path, ie.file_id) for path, ie in rt.iter_entries_by_dir()
798
                                       if path] # Ignore the root entry
799
        self.assertEqual([('a', 'a-id')], entries)
800
801
    def test_commit_no_messages(self):
802
        tree = self.make_branch_and_tree('tree')
803
        rev_id1 = tree.commit('one')
804
        self.build_tree(['tree/a', 'tree/b'])
805
        tree.add(['a', 'b'], ['a-id', 'b-id'])
806
807
        dlg = commit.CommitDialog(tree)
808
        dlg._set_global_commit_message('Simple commit\n')
809
        dlg._do_commit()
810
811
        rev = tree.branch.repository.get_revision(dlg.committed_revision_id)
812
        self.failIf('file-info' in rev.properties)
813
814
    def test_commit_specific_files_with_messages(self):
815
        tree = self.make_branch_and_tree('tree')
816
        rev_id1 = tree.commit('one')
817
        self.build_tree(['tree/a', 'tree/b'])
818
        tree.add(['a', 'b'], ['a-id', 'b-id'])
819
820
        dlg = commit.CommitDialog(tree)
821
        dlg._treeview_files.set_cursor((1,))
822
        dlg._set_file_commit_message('Message for A\n')
823
        dlg._treeview_files.set_cursor((2,))
824
        dlg._set_file_commit_message('Message for B\n')
825
        dlg._toggle_commit(None, 2, dlg._files_store) # unset 'b'
826
        dlg._set_global_commit_message('Commit just "a"')
827
828
        dlg._do_commit()
829
830
        rev_id2 = dlg.committed_revision_id
831
        self.assertEqual(rev_id2, tree.last_revision())
832
        rev = tree.branch.repository.get_revision(rev_id2)
833
        self.assertEqual('Commit just "a"', rev.message)
834
        file_info = rev.properties['file-info']
835
        self.assertEqual('ld7:file_id4:a-id'
836
                           '7:message14:Message for A\n'
837
                           '4:path1:a'
838
                         'ee', file_info)
839
        self.assertEqual([{'path':'a', 'file_id':'a-id',
840
                           'message':'Message for A\n'},
841
                         ], bencode.bdecode(file_info))
278.1.28 by John Arbash Meinel
Ensure that we can set per-file messages even during a merge.
842
843
    def test_commit_messages_after_merge(self):
844
        tree = self.make_branch_and_tree('tree')
845
        rev_id1 = tree.commit('one')
846
        tree2 = tree.bzrdir.sprout('tree2').open_workingtree()
847
        self.build_tree(['tree2/a', 'tree2/b'])
848
        tree2.add(['a', 'b'], ['a-id', 'b-id'])
849
        rev_id2 = tree2.commit('two')
850
851
        tree.merge_from_branch(tree2.branch)
852
853
        dlg = commit.CommitDialog(tree)
854
        dlg._treeview_files.set_cursor((1,)) # 'a'
855
        dlg._set_file_commit_message('Message for A\n')
856
        # No message for 'B'
857
        dlg._set_global_commit_message('Merging from "tree2"\n')
858
859
        dlg._do_commit()
860
861
        rev_id3 = dlg.committed_revision_id
862
        self.assertEqual(rev_id3, tree.last_revision())
863
        rev = tree.branch.repository.get_revision(rev_id3)
864
        self.assertEqual('Merging from "tree2"\n', rev.message)
865
        self.assertEqual([rev_id1, rev_id2], rev.parent_ids)
866
        file_info = rev.properties['file-info']
867
        self.assertEqual('ld7:file_id4:a-id'
868
                           '7:message14:Message for A\n'
869
                           '4:path1:a'
870
                         'ee', file_info)
871
        self.assertEqual([{'path':'a', 'file_id':'a-id',
872
                           'message':'Message for A\n'},
873
                         ], bencode.bdecode(file_info))
278.1.29 by John Arbash Meinel
Start testing with Unicode data.
874
875
    def test_commit_unicode_messages(self):
876
        from bzrlib.tests.test_diff import UnicodeFilename
877
        self.requireFeature(UnicodeFilename)
878
879
        tree = self.make_branch_and_tree('tree')
880
        self.build_tree(['tree/a', u'tree/\u03a9'])
881
        tree.add(['a', u'\u03a9'], ['a-id', 'omega-id'])
882
883
        dlg = commit.CommitDialog(tree)
884
        dlg._treeview_files.set_cursor((1,)) # 'a'
885
        dlg._set_file_commit_message(u'Test \xfan\xecc\xf6de\n')
886
        dlg._treeview_files.set_cursor((2,)) # omega
887
        dlg._set_file_commit_message(u'\u03a9 is the end of all things.\n')
888
        dlg._set_global_commit_message(u'\u03a9 and \xfan\xecc\xf6de\n')
889
890
        self.assertEqual(([u'a', u'\u03a9'],
891
                          [{'path':'a', 'file_id':'a-id',
892
                            'message':'Test \xc3\xban\xc3\xacc\xc3\xb6de\n'},
893
                           {'path':'\xce\xa9', 'file_id':'omega-id',
894
                            'message':'\xce\xa9 is the end of all things.\n'},
895
                          ]), dlg._get_specific_files())
896
897
        dlg._do_commit()
898
899
        rev = tree.branch.repository.get_revision(dlg.committed_revision_id)
900
        file_info = rev.properties['file-info']
901
        value = ('ld7:file_id4:a-id'
902
                   '7:message16:Test \xc3\xban\xc3\xacc\xc3\xb6de\n'
903
                   '4:path1:a'
904
                  'e'
905
                  'd7:file_id8:omega-id'
906
                   '7:message29:\xce\xa9 is the end of all things.\n'
907
                   '4:path2:\xce\xa9'
908
                  'e'
909
                 'e')
910
        self.expectFailure('bencode and unicode does not mix properly with'
911
                           ' Revision XML serialization.',
912
                           self.assertEqual, value, file_info)
913
        self.assertEqual(value, file_info)
914
        file_info_decoded = bencode.bdecode(file_info)
915
        for d in file_info_decoded:
916
            d['path'] = d['path'].decode('utf8')
917
            d['message'] = d['message'].decode('utf8')
918
919
        self.assertEqual([{'path':u'a', 'file_id':'a-id',
920
                           'message':u'Test \xfan\xecc\xf6de\n'},
921
                          {'path':u'\u03a9', 'file_id':'omega-id',
922
                           'message':u'\u03a9 is the end of all things.\n'},
923
                         ], file_info_decoded)