/b-gtk/fix-viz

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/b-gtk/fix-viz
622.1.2 by John Arbash Meinel
Add tests of RevisionView that it can handle broken file-info properties.
1
# Copyright (C) 2007, 2008 John Arbash Meinel <john@arbash-meinel.com>
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
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
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
21
from gi.repository import Gtk
278.1.23 by John Arbash Meinel
Beginning to support actual commit.
22
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
23
from bzrlib import (
635.2.12 by Vincent Ladeuil
Implement commit message saving without modifying bzrlib.
24
    branch,
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
25
    tests,
635.2.8 by Vincent Ladeuil
Start testing patch behavior.
26
    uncommit,
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
27
    )
645 by Jelmer Vernooij
Fix more bencode imports.
28
try:
737 by Jelmer Vernooij
Support new location of UnicodeFilenameFeature in 2.5.
29
    from bzrlib.tests.features import UnicodeFilenameFeature
30
except ImportError: # bzr < 2.5
31
    from bzrlib.tests import UnicodeFilenameFeature
768 by Jelmer Vernooij
Drop support for old bencode location.
32
from bzrlib import bencode
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
33
747 by Jelmer Vernooij
Fix import for commitmsgs.
34
from bzrlib.plugins.gtk import (
35
    commit,
36
    commitmsgs,
37
    )
769.1.1 by Curtis Hovey
Define _last_selected_file in init so that async signal callbacks can use it.
38
from bzrlib.plugins.gtk.commitmsgs import SavedCommitMessagesManager
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
39
40
41
# TODO: All we need is basic ancestry code to test this, we shouldn't need a
42
# TestCaseWithTransport, just a TestCaseWithMemoryTransport or somesuch.
43
44
class TestPendingRevisions(tests.TestCaseWithTransport):
45
46
    def test_pending_revisions_none(self):
47
        tree = self.make_branch_and_tree('.')
48
        tree.commit('one')
49
762 by Jelmer Vernooij
Avoid call to Repository.get_ancestry.
50
        self.addCleanup(tree.lock_read().unlock)
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
51
        self.assertIs(None, commit.pending_revisions(tree))
52
53
    def test_pending_revisions_simple(self):
54
        tree = self.make_branch_and_tree('tree')
55
        rev_id1 = tree.commit('one')
56
        tree2 = tree.bzrdir.sprout('tree2').open_workingtree()
57
        rev_id2 = tree2.commit('two')
58
        tree.merge_from_branch(tree2.branch)
59
        self.assertEqual([rev_id1, rev_id2], tree.get_parent_ids())
60
762 by Jelmer Vernooij
Avoid call to Repository.get_ancestry.
61
        self.addCleanup(tree.lock_read().unlock)
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
62
        pending_revisions = commit.pending_revisions(tree)
63
        # One primary merge
64
        self.assertEqual(1, len(pending_revisions))
65
        # Revision == rev_id2
66
        self.assertEqual(rev_id2, pending_revisions[0][0].revision_id)
67
        # No children of this revision.
68
        self.assertEqual([], pending_revisions[0][1])
69
70
    def test_pending_revisions_with_children(self):
71
        tree = self.make_branch_and_tree('tree')
72
        rev_id1 = tree.commit('one')
73
        tree2 = tree.bzrdir.sprout('tree2').open_workingtree()
74
        rev_id2 = tree2.commit('two')
75
        rev_id3 = tree2.commit('three')
76
        rev_id4 = tree2.commit('four')
77
        tree.merge_from_branch(tree2.branch)
78
        self.assertEqual([rev_id1, rev_id4], tree.get_parent_ids())
79
762 by Jelmer Vernooij
Avoid call to Repository.get_ancestry.
80
        self.addCleanup(tree.lock_read().unlock)
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
81
        pending_revisions = commit.pending_revisions(tree)
82
        # One primary merge
83
        self.assertEqual(1, len(pending_revisions))
84
        # Revision == rev_id2
85
        self.assertEqual(rev_id4, pending_revisions[0][0].revision_id)
86
        # Two children for this revision
87
        self.assertEqual(2, len(pending_revisions[0][1]))
88
        self.assertEqual(rev_id3, pending_revisions[0][1][0].revision_id)
89
        self.assertEqual(rev_id2, pending_revisions[0][1][1].revision_id)
90
91
    def test_pending_revisions_multi_merge(self):
92
        tree = self.make_branch_and_tree('tree')
93
        rev_id1 = tree.commit('one')
94
        tree2 = tree.bzrdir.sprout('tree2').open_workingtree()
95
        rev_id2 = tree2.commit('two')
96
        tree3 = tree2.bzrdir.sprout('tree3').open_workingtree()
500.1.2 by Vincent Ladeuil
Fix third failing test (thanks to jam).
97
        rev_id3 = tree2.commit('three')
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
98
        rev_id4 = tree3.commit('four')
99
        rev_id5 = tree3.commit('five')
100
        tree.merge_from_branch(tree2.branch)
670 by Vincent Ladeuil
Fix regressions in tests about merge being more strict by default.
101
        tree.merge_from_branch(tree3.branch, force=True)
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
102
        self.assertEqual([rev_id1, rev_id3, rev_id5], tree.get_parent_ids())
103
762 by Jelmer Vernooij
Avoid call to Repository.get_ancestry.
104
        self.addCleanup(tree.lock_read().unlock)
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
105
        pending_revisions = commit.pending_revisions(tree)
106
        # Two primary merges
107
        self.assertEqual(2, len(pending_revisions))
108
        # Revision == rev_id2
109
        self.assertEqual(rev_id3, pending_revisions[0][0].revision_id)
110
        self.assertEqual(rev_id5, pending_revisions[1][0].revision_id)
111
        # One child for the first merge
112
        self.assertEqual(1, len(pending_revisions[0][1]))
113
        self.assertEqual(rev_id2, pending_revisions[0][1][0].revision_id)
114
        # One child for the second merge
115
        self.assertEqual(1, len(pending_revisions[1][1]))
116
        self.assertEqual(rev_id4, pending_revisions[1][1][0].revision_id)
117
118
119
class Test_RevToPendingInfo(tests.TestCaseWithTransport):
120
121
    def test_basic_info(self):
122
        tree = self.make_branch_and_tree('tree')
123
        rev_id = tree.commit('Multiline\ncommit\nmessage',
124
                             committer='Joe Foo <joe@foo.com>',
125
                             timestamp=1191012408.674,
126
                             timezone=-18000
127
                             )
128
        rev = tree.branch.repository.get_revision(rev_id)
129
        rev_dict = commit.CommitDialog._rev_to_pending_info(rev)
130
        self.assertEqual({'committer':'Joe Foo',
131
                          'summary':'Multiline',
132
                          'date':'2007-09-28',
133
                          'revision_id':rev_id,
134
                         }, rev_dict)
135
136
137
class CommitDialogNoWidgets(commit.CommitDialog):
138
139
    def construct(self):
140
        pass # Don't create any widgets here
141
278.1.14 by John Arbash Meinel
Tests that we fill out the pending list correctly.
142
    def fill_in_data(self):
143
        pass # With no widgets, there are no widgets to fill out
144
145
769.1.1 by Curtis Hovey
Define _last_selected_file in init so that async signal callbacks can use it.
146
class MockMethod():
147
148
    @classmethod
149
    def bind(klass, test_instance, obj, method_name):
150
        original_method = getattr(obj, method_name)
151
        test_instance.addCleanup(setattr, obj, method_name, original_method)
152
        setattr(obj, method_name, klass())
153
154
    def __init__(self):
155
        self.called = False
156
        self.args = None
157
        self.kwargs = None
158
159
    def __call__(self, *args, **kwargs):
160
        self.called = True
161
        self.args = args
162
        self.kwargs = kwargs
163
164
278.1.14 by John Arbash Meinel
Tests that we fill out the pending list correctly.
165
class TestCommitDialogSimple(tests.TestCaseWithTransport):
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
166
769.1.1 by Curtis Hovey
Define _last_selected_file in init so that async signal callbacks can use it.
167
    def test_init(self):
168
        MockMethod.bind(self, CommitDialogNoWidgets, 'setup_params')
169
        MockMethod.bind(self, CommitDialogNoWidgets, 'construct')
170
        MockMethod.bind(self, CommitDialogNoWidgets, 'fill_in_data')
171
172
        tree = self.make_branch_and_tree('tree')
173
        rev_id = tree.commit('first')
174
        dlg = CommitDialogNoWidgets(tree)
175
        self.assertIs(tree, dlg._wt)
176
        self.assertIs(None, dlg._selected)
177
        self.assertTrue(dlg._enable_per_file_commits)
178
        self.assertTrue(dlg._commit_all_changes)
179
        self.assertIs(None, dlg.committed_revision_id)
180
        self.assertIs(None, dlg._last_selected_file)
181
        self.assertIsInstance(
182
            dlg._saved_commit_messages_manager, SavedCommitMessagesManager)
183
        self.assertTrue(CommitDialogNoWidgets.setup_params.called)
184
        self.assertTrue(CommitDialogNoWidgets.construct.called)
185
        self.assertTrue(CommitDialogNoWidgets.fill_in_data.called)
186
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
187
    def test_setup_parameters_no_pending(self):
188
        tree = self.make_branch_and_tree('tree')
189
        rev_id = tree.commit('first')
190
191
        dlg = CommitDialogNoWidgets(tree)
192
        self.assertEqual(rev_id, dlg._basis_tree.get_revision_id())
193
        self.assertIs(None, dlg._pending)
194
        self.assertFalse(dlg._is_checkout)
195
196
    def test_setup_parameters_checkout(self):
197
        tree = self.make_branch_and_tree('tree')
198
        rev_id = tree.commit('first')
199
        tree2 = tree.bzrdir.sprout('tree2').open_workingtree()
200
        tree2.branch.bind(tree.branch)
201
202
        dlg = CommitDialogNoWidgets(tree2)
203
        self.assertEqual(rev_id, dlg._basis_tree.get_revision_id())
204
        self.assertIs(None, dlg._pending)
205
        self.assertTrue(dlg._is_checkout)
206
207
    def test_setup_parameters_pending(self):
208
        tree = self.make_branch_and_tree('tree')
209
        rev_id1 = tree.commit('one')
210
        tree2 = tree.bzrdir.sprout('tree2').open_workingtree()
211
        rev_id2 = tree2.commit('two')
212
        tree.merge_from_branch(tree2.branch)
213
214
        dlg = CommitDialogNoWidgets(tree)
215
        self.assertEqual(rev_id1, dlg._basis_tree.get_revision_id())
216
        self.assertIsNot(None, dlg._pending)
217
        self.assertEqual(1, len(dlg._pending))
218
        self.assertEqual(rev_id2, dlg._pending[0][0].revision_id)
219
220
    def test_setup_parameters_delta(self):
221
        tree = self.make_branch_and_tree('tree')
222
        self.build_tree(['tree/a'])
223
        tree.add(['a'], ['a-id'])
224
225
        dlg = CommitDialogNoWidgets(tree)
278.1.12 by John Arbash Meinel
Delay computing the delta, and clean up some of the diff view names.
226
        self.assertIs(None, dlg._delta)
227
        dlg._compute_delta()
228
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
229
        delta = dlg._delta
230
        self.assertEqual([], delta.modified)
231
        self.assertEqual([], delta.renamed)
232
        self.assertEqual([], delta.removed)
233
        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.
234
235
236
class TestCommitDialog(tests.TestCaseWithTransport):
237
278.1.25 by John Arbash Meinel
Add the 'Only Commit Locally' checkbox, we may want to put it elsewhere, though.
238
    def test_bound(self):
239
        tree = self.make_branch_and_tree('tree')
240
        rev_id = tree.commit('first')
241
        tree2 = tree.bzrdir.sprout('tree2').open_workingtree()
242
        tree2.branch.bind(tree.branch)
243
244
        # tree is not a checkout
245
        dlg = commit.CommitDialog(tree)
246
        self.assertFalse(dlg._check_local.get_property('visible'))
247
248
        # tree2 is a checkout
249
        dlg2 = commit.CommitDialog(tree2)
250
        self.assertTrue(dlg2._check_local.get_property('visible'))
251
278.1.14 by John Arbash Meinel
Tests that we fill out the pending list correctly.
252
    def test_no_pending(self):
253
        tree = self.make_branch_and_tree('tree')
254
        rev_id1 = tree.commit('one')
255
256
        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.
257
258
        self.assertFalse(dlg._pending_box.get_property('visible'))
259
278.1.17 by John Arbash Meinel
Add a * reference for why you can't change the commit selection.
260
        commit_col = dlg._treeview_files.get_column(0)
261
        self.assertEqual('Commit', commit_col.get_title())
734.1.20 by Curtis Hovey
col.get_cell_renderers => col.get_cells.
262
        renderer = commit_col.get_cells()[0]
278.1.39 by John Arbash Meinel
To disable a checkbox it is set_property('activatable', False),
263
        self.assertTrue(renderer.get_property('activatable'))
278.1.14 by John Arbash Meinel
Tests that we fill out the pending list correctly.
264
278.1.43 by John Arbash Meinel
Finish connecting the 'Commit all changes' radio buttons.
265
        self.assertEqual('Commit all changes',
266
                         dlg._commit_all_files_radio.get_label())
267
        self.assertTrue(dlg._commit_all_files_radio.get_property('sensitive'))
268
        self.assertTrue(dlg._commit_selected_radio.get_property('sensitive'))
269
278.1.14 by John Arbash Meinel
Tests that we fill out the pending list correctly.
270
    def test_pending(self):
271
        tree = self.make_branch_and_tree('tree')
272
        rev_id1 = tree.commit('one')
273
274
        tree2 = tree.bzrdir.sprout('tree2').open_workingtree()
275
        rev_id2 = tree2.commit('two',
276
                               committer='Joe Foo <joe@foo.com>',
277
                               timestamp=1191264271.05,
278
                               timezone=+7200)
279
        tree.merge_from_branch(tree2.branch)
280
281
        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.
282
283
        self.assertTrue(dlg._pending_box.get_property('visible'))
284
278.1.17 by John Arbash Meinel
Add a * reference for why you can't change the commit selection.
285
        commit_col = dlg._treeview_files.get_column(0)
286
        self.assertEqual('Commit*', commit_col.get_title())
734.1.20 by Curtis Hovey
col.get_cell_renderers => col.get_cells.
287
        renderer = commit_col.get_cells()[0]
278.1.39 by John Arbash Meinel
To disable a checkbox it is set_property('activatable', False),
288
        self.assertFalse(renderer.get_property('activatable'))
278.1.17 by John Arbash Meinel
Add a * reference for why you can't change the commit selection.
289
278.1.15 by John Arbash Meinel
Hook up the list of modified files.
290
        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.
291
        self.assertEqual([(rev_id2, '2007-10-01', 'Joe Foo', 'two')], values)
292
278.1.43 by John Arbash Meinel
Finish connecting the 'Commit all changes' radio buttons.
293
        self.assertEqual('Commit all changes*',
294
                         dlg._commit_all_files_radio.get_label())
295
        self.assertFalse(dlg._commit_all_files_radio.get_property('sensitive'))
296
        self.assertFalse(dlg._commit_selected_radio.get_property('sensitive'))
297
278.1.14 by John Arbash Meinel
Tests that we fill out the pending list correctly.
298
    def test_pending_multiple(self):
299
        tree = self.make_branch_and_tree('tree')
300
        rev_id1 = tree.commit('one')
301
302
        tree2 = tree.bzrdir.sprout('tree2').open_workingtree()
303
        rev_id2 = tree2.commit('two',
304
                               committer='Joe Foo <joe@foo.com>',
305
                               timestamp=1191264271.05,
306
                               timezone=+7200)
307
        rev_id3 = tree2.commit('three',
308
                               committer='Jerry Foo <jerry@foo.com>',
309
                               timestamp=1191264278.05,
310
                               timezone=+7200)
311
        tree.merge_from_branch(tree2.branch)
312
        tree3 = tree.bzrdir.sprout('tree3').open_workingtree()
313
        rev_id4 = tree3.commit('four',
314
                               committer='Joe Foo <joe@foo.com>',
315
                               timestamp=1191264279.05,
316
                               timezone=+7200)
317
        rev_id5 = tree3.commit('five',
318
                               committer='Jerry Foo <jerry@foo.com>',
319
                               timestamp=1191372278.05,
320
                               timezone=+7200)
670 by Vincent Ladeuil
Fix regressions in tests about merge being more strict by default.
321
        tree.merge_from_branch(tree3.branch, force=True)
278.1.14 by John Arbash Meinel
Tests that we fill out the pending list correctly.
322
323
        dlg = commit.CommitDialog(tree)
324
        # TODO: assert that the pending box is set to show
278.1.15 by John Arbash Meinel
Hook up the list of modified files.
325
        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.
326
        self.assertEqual([(rev_id3, '2007-10-01', 'Jerry Foo', 'three'),
327
                          (rev_id2, '2007-10-01', 'Joe Foo', 'two'),
328
                          (rev_id5, '2007-10-03', 'Jerry Foo', 'five'),
329
                          (rev_id4, '2007-10-01', 'Joe Foo', 'four'),
330
                         ], values)
278.1.15 by John Arbash Meinel
Hook up the list of modified files.
331
278.1.16 by John Arbash Meinel
Implement the file changes list on top of _iter_changes rather than
332
    def test_filelist_added(self):
278.1.15 by John Arbash Meinel
Hook up the list of modified files.
333
        tree = self.make_branch_and_tree('tree')
334
        self.build_tree(['tree/a', 'tree/b/', 'tree/b/c'])
335
        tree.add(['a', 'b', 'b/c'], ['a-id', 'b-id', 'c-id'])
336
337
        dlg = commit.CommitDialog(tree)
338
        values = [(r[0], r[1], r[2], r[3], r[4]) for r in dlg._files_store]
769 by Jelmer Vernooij
Cope with some strings being unicode when returned by some versions of gtk.
339
        self.assertEqual([("", "", True, 'All Files', ''),
278.1.20 by John Arbash Meinel
We always select the All Files record in the files view,
340
                          ('a-id', 'a', True, 'a', 'added'),
278.1.15 by John Arbash Meinel
Hook up the list of modified files.
341
                          ('b-id', 'b', True, 'b/', 'added'),
342
                          ('c-id', 'b/c', True, 'b/c', 'added'),
343
                         ], values)
278.1.16 by John Arbash Meinel
Implement the file changes list on top of _iter_changes rather than
344
345
    def test_filelist_renamed(self):
346
        tree = self.make_branch_and_tree('tree')
347
        self.build_tree(['tree/a', 'tree/b/', 'tree/b/c'])
348
        tree.add(['a', 'b', 'b/c'], ['a-id', 'b-id', 'c-id'])
349
        rev_id1 = tree.commit('one')
350
351
        tree.rename_one('b', 'd')
352
        tree.rename_one('a', 'd/a')
353
354
        dlg = commit.CommitDialog(tree)
355
        values = [(r[0], r[1], r[2], r[3], r[4]) for r in dlg._files_store]
769 by Jelmer Vernooij
Cope with some strings being unicode when returned by some versions of gtk.
356
        self.assertEqual([("", "", True, 'All Files', ''),
278.1.20 by John Arbash Meinel
We always select the All Files record in the files view,
357
                          ('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
358
                          ('a-id', 'd/a', True, 'a => d/a', 'renamed'),
359
                         ], values)
360
361
    def test_filelist_modified(self):
362
        tree = self.make_branch_and_tree('tree')
363
        self.build_tree(['tree/a'])
364
        tree.add(['a'], ['a-id'])
365
        rev_id1 = tree.commit('one')
366
367
        self.build_tree_contents([('tree/a', 'new contents for a\n')])
368
369
        dlg = commit.CommitDialog(tree)
370
        values = [(r[0], r[1], r[2], r[3], r[4]) for r in dlg._files_store]
769 by Jelmer Vernooij
Cope with some strings being unicode when returned by some versions of gtk.
371
        self.assertEqual([("", "", True, 'All Files', ''),
278.1.20 by John Arbash Meinel
We always select the All Files record in the files view,
372
                          ('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
373
                         ], values)
374
375
    def test_filelist_renamed_and_modified(self):
376
        tree = self.make_branch_and_tree('tree')
377
        self.build_tree(['tree/a', 'tree/b/', 'tree/b/c'])
378
        tree.add(['a', 'b', 'b/c'], ['a-id', 'b-id', 'c-id'])
379
        rev_id1 = tree.commit('one')
380
381
        tree.rename_one('b', 'd')
382
        tree.rename_one('a', 'd/a')
383
        self.build_tree_contents([('tree/d/a', 'new contents for a\n'),
384
                                  ('tree/d/c', 'new contents for c\n'),
385
                                 ])
386
        # 'c' is not considered renamed, because only its parent was moved, it
387
        # stayed in the same directory
388
389
        dlg = commit.CommitDialog(tree)
390
        values = [(r[0], r[1], r[2], r[3], r[4]) for r in dlg._files_store]
769 by Jelmer Vernooij
Cope with some strings being unicode when returned by some versions of gtk.
391
        self.assertEqual([("", "", True, 'All Files', ''),
278.1.20 by John Arbash Meinel
We always select the All Files record in the files view,
392
                          ('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
393
                          ('a-id', 'd/a', True, 'a => d/a', 'renamed and modified'),
394
                          ('c-id', 'd/c', True, 'd/c', 'modified'),
395
                         ], values)
396
397
    def test_filelist_kind_changed(self):
398
        tree = self.make_branch_and_tree('tree')
399
        self.build_tree(['tree/a', 'tree/b'])
400
        tree.add(['a', 'b'], ['a-id', 'b-id'])
401
        tree.commit('one')
402
403
        os.remove('tree/a')
404
        self.build_tree(['tree/a/'])
278.1.17 by John Arbash Meinel
Add a * reference for why you can't change the commit selection.
405
        # XXX:  This is technically valid, and the file list handles it fine,
406
        #       but 'show_diff_trees()' does not, so we skip this part of the
407
        #       test for now.
408
        # tree.rename_one('b', 'c')
409
        # os.remove('tree/c')
410
        # self.build_tree(['tree/c/'])
278.1.16 by John Arbash Meinel
Implement the file changes list on top of _iter_changes rather than
411
412
        dlg = commit.CommitDialog(tree)
413
        values = [(r[0], r[1], r[2], r[3], r[4]) for r in dlg._files_store]
769 by Jelmer Vernooij
Cope with some strings being unicode when returned by some versions of gtk.
414
        self.assertEqual([("", "", True, 'All Files', ''),
278.1.20 by John Arbash Meinel
We always select the All Files record in the files view,
415
                          ('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.
416
                          # ('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
417
                         ], values)
418
419
    def test_filelist_removed(self):
420
        tree = self.make_branch_and_tree('tree')
421
        self.build_tree(['tree/a', 'tree/b/'])
422
        tree.add(['a', 'b'], ['a-id', 'b-id'])
423
        tree.commit('one')
424
425
        os.remove('tree/a')
426
        tree.remove('b', force=True)
427
428
        dlg = commit.CommitDialog(tree)
429
        values = [(r[0], r[1], r[2], r[3], r[4]) for r in dlg._files_store]
769 by Jelmer Vernooij
Cope with some strings being unicode when returned by some versions of gtk.
430
        self.assertEqual([("", "", True, 'All Files', ''),
278.1.20 by John Arbash Meinel
We always select the All Files record in the files view,
431
                          ('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
432
                          ('b-id', 'b', True, 'b/', 'removed'),
433
                         ], values)
278.1.35 by John Arbash Meinel
Make use of the 'selected' parameter to CommitDialog.
434
        # All Files should be selected
734.1.23 by Curtis Hovey
Always pass a Gtk.TreePath instead of an int or tuple.
435
        self.assertEqual(
436
            (Gtk.TreePath(path=0), None), dlg._treeview_files.get_cursor())
278.1.35 by John Arbash Meinel
Make use of the 'selected' parameter to CommitDialog.
437
438
    def test_filelist_with_selected(self):
439
        tree = self.make_branch_and_tree('tree')
440
        self.build_tree(['tree/a', 'tree/b/'])
441
        tree.add(['a', 'b'], ['a-id', 'b-id'])
442
443
        dlg = commit.CommitDialog(tree, selected='a')
444
        values = [(r[0], r[1], r[2], r[3], r[4]) for r in dlg._files_store]
769 by Jelmer Vernooij
Cope with some strings being unicode when returned by some versions of gtk.
445
        self.assertEqual([("", "", False, 'All Files', ''),
278.1.35 by John Arbash Meinel
Make use of the 'selected' parameter to CommitDialog.
446
                          ('a-id', 'a', True, 'a', 'added'),
447
                          ('b-id', 'b', False, 'b/', 'added'),
448
                         ], values)
449
        # This file should also be selected in the file list, rather than the
450
        # 'All Files' selection
734.1.23 by Curtis Hovey
Always pass a Gtk.TreePath instead of an int or tuple.
451
        self.assertEqual(
452
            (Gtk.TreePath(path=1), None), dlg._treeview_files.get_cursor())
278.1.18 by John Arbash Meinel
Start checking the diff view is correct.
453
454
    def test_diff_view(self):
455
        tree = self.make_branch_and_tree('tree')
456
        self.build_tree(['tree/a', 'tree/b'])
457
        tree.add(['a', 'b'], ['a-id', 'b-id'])
458
        tree.commit('one')
459
460
        self.build_tree_contents([('tree/a', 'new contents for a\n')])
461
        tree.remove('b')
462
463
        dlg = commit.CommitDialog(tree)
464
        diff_buffer = dlg._diff_view.buffer
465
        text = diff_buffer.get_text(diff_buffer.get_start_iter(),
734.1.7 by Curtis Hovey
Updated buffer.getText() calls and ModifierType enums.
466
                                    diff_buffer.get_end_iter(),
467
                                    True).splitlines(True)
278.1.18 by John Arbash Meinel
Start checking the diff view is correct.
468
483 by Jelmer Vernooij
Fix diff test.
469
        self.assertEqual("=== modified file 'a'\n", text[0])
278.1.18 by John Arbash Meinel
Start checking the diff view is correct.
470
        self.assertContainsRe(text[1],
471
            r"--- a\t\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d [+-]\d\d\d\d")
483 by Jelmer Vernooij
Fix diff test.
472
        self.assertContainsRe(text[2],
473
            r"\+\+\+ a\t\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d [+-]\d\d\d\d")
474
        self.assertEqual('@@ -1,1 +1,1 @@\n', text[3])
475
        self.assertEqual('-contents of tree/a\n', text[4])
476
        self.assertEqual('+new contents for a\n', text[5])
477
        self.assertEqual('\n', text[6])
478
479
        self.assertEqual("=== removed file 'b'\n", text[7])
278.1.18 by John Arbash Meinel
Start checking the diff view is correct.
480
        self.assertContainsRe(text[8],
483 by Jelmer Vernooij
Fix diff test.
481
            r"--- b\t\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d [+-]\d\d\d\d")
482
        self.assertEqual('+++ b\t1970-01-01 00:00:00 +0000\n', text[9])
483
        self.assertEqual('@@ -1,1 +0,0 @@\n', text[10])
484
        self.assertEqual('-contents of tree/b\n', text[11])
278.1.18 by John Arbash Meinel
Start checking the diff view is correct.
485
        self.assertEqual('\n', text[12])
486
278.1.20 by John Arbash Meinel
We always select the All Files record in the files view,
487
        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.
488
278.1.43 by John Arbash Meinel
Finish connecting the 'Commit all changes' radio buttons.
489
    def test_commit_partial_toggle(self):
490
        tree = self.make_branch_and_tree('tree')
491
        self.build_tree(['tree/a', 'tree/b'])
492
        tree.add(['a', 'b'], ['a-id', 'b-id'])
493
494
        dlg = commit.CommitDialog(tree)
495
        checked_col = dlg._treeview_files.get_column(0)
496
        self.assertFalse(checked_col.get_property('visible'))
497
        self.assertTrue(dlg._commit_all_changes)
498
499
        dlg._commit_selected_radio.set_active(True)
500
        self.assertTrue(checked_col.get_property('visible'))
501
        self.assertFalse(dlg._commit_all_changes)
502
278.1.19 by John Arbash Meinel
Test what happens when a specific file is selected.
503
    def test_file_selection(self):
504
        """Several things should happen when a file has been selected."""
505
        tree = self.make_branch_and_tree('tree')
278.1.33 by John Arbash Meinel
Only enable the per-file dialog if 'per_file_commits' is enabled in the config.
506
        tree.branch.get_config().set_user_option('per_file_commits', 'true')
278.1.19 by John Arbash Meinel
Test what happens when a specific file is selected.
507
        self.build_tree(['tree/a', 'tree/b'])
508
        tree.add(['a', 'b'], ['a-id', 'b-id'])
509
510
        dlg = commit.CommitDialog(tree)
511
        diff_buffer = dlg._diff_view.buffer
278.1.20 by John Arbash Meinel
We always select the All Files record in the files view,
512
        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.
513
        self.assertEqual('File commit message',
514
                         dlg._file_message_expander.get_label())
515
        self.assertFalse(dlg._file_message_expander.get_expanded())
516
        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.
517
734.1.23 by Curtis Hovey
Always pass a Gtk.TreePath instead of an int or tuple.
518
        dlg._treeview_files.set_cursor(
519
            Gtk.TreePath(path=1), None, False)
278.1.19 by John Arbash Meinel
Test what happens when a specific file is selected.
520
        self.assertEqual('Diff for a', dlg._diff_label.get_text())
521
        text = diff_buffer.get_text(diff_buffer.get_start_iter(),
734.1.7 by Curtis Hovey
Updated buffer.getText() calls and ModifierType enums.
522
                                    diff_buffer.get_end_iter(),
523
                                    True).splitlines(True)
278.1.19 by John Arbash Meinel
Test what happens when a specific file is selected.
524
        self.assertEqual("=== added file 'a'\n", text[0])
525
        self.assertContainsRe(text[1],
526
            r"--- a\t\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d [+-]\d\d\d\d")
527
        self.assertContainsRe(text[2],
528
            r"\+\+\+ a\t\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d [+-]\d\d\d\d")
529
        self.assertEqual('@@ -0,0 +1,1 @@\n', text[3])
530
        self.assertEqual('+contents of tree/a\n', text[4])
531
        self.assertEqual('\n', text[5])
278.1.21 by John Arbash Meinel
Start tracking the per-file commit messages.
532
        self.assertEqual('Commit message for a',
533
                         dlg._file_message_expander.get_label())
534
        self.assertTrue(dlg._file_message_expander.get_expanded())
535
        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.
536
734.1.23 by Curtis Hovey
Always pass a Gtk.TreePath instead of an int or tuple.
537
        dlg._treeview_files.set_cursor(
538
            Gtk.TreePath(path=2), None, False)
278.1.19 by John Arbash Meinel
Test what happens when a specific file is selected.
539
        self.assertEqual('Diff for b', dlg._diff_label.get_text())
540
        text = diff_buffer.get_text(diff_buffer.get_start_iter(),
734.1.7 by Curtis Hovey
Updated buffer.getText() calls and ModifierType enums.
541
                                    diff_buffer.get_end_iter(),
542
                                    True).splitlines(True)
278.1.19 by John Arbash Meinel
Test what happens when a specific file is selected.
543
        self.assertEqual("=== added file 'b'\n", text[0])
544
        self.assertContainsRe(text[1],
545
            r"--- b\t\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d [+-]\d\d\d\d")
546
        self.assertContainsRe(text[2],
547
            r"\+\+\+ b\t\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d [+-]\d\d\d\d")
548
        self.assertEqual('@@ -0,0 +1,1 @@\n', text[3])
549
        self.assertEqual('+contents of tree/b\n', text[4])
550
        self.assertEqual('\n', text[5])
278.1.21 by John Arbash Meinel
Start tracking the per-file commit messages.
551
        self.assertEqual('Commit message for b',
552
                         dlg._file_message_expander.get_label())
553
        self.assertTrue(dlg._file_message_expander.get_expanded())
554
        self.assertTrue(dlg._file_message_expander.get_property('sensitive'))
555
734.1.23 by Curtis Hovey
Always pass a Gtk.TreePath instead of an int or tuple.
556
        dlg._treeview_files.set_cursor(
557
            Gtk.TreePath(path=0), None, False)
278.1.21 by John Arbash Meinel
Start tracking the per-file commit messages.
558
        self.assertEqual('Diff for All Files', dlg._diff_label.get_text())
559
        self.assertEqual('File commit message',
560
                         dlg._file_message_expander.get_label())
561
        self.assertFalse(dlg._file_message_expander.get_expanded())
562
        self.assertFalse(dlg._file_message_expander.get_property('sensitive'))
563
564
    def test_file_selection_message(self):
565
        """Selecting a file should bring up its commit message."""
566
        tree = self.make_branch_and_tree('tree')
278.1.33 by John Arbash Meinel
Only enable the per-file dialog if 'per_file_commits' is enabled in the config.
567
        tree.branch.get_config().set_user_option('per_file_commits', 'true')
278.1.21 by John Arbash Meinel
Start tracking the per-file commit messages.
568
        self.build_tree(['tree/a', 'tree/b/'])
569
        tree.add(['a', 'b'], ['a-id', 'b-id'])
570
571
        def get_file_text():
572
            buf = dlg._file_message_text_view.get_buffer()
734.1.7 by Curtis Hovey
Updated buffer.getText() calls and ModifierType enums.
573
            return buf.get_text(
574
                buf.get_start_iter(), buf.get_end_iter(), True)
278.1.21 by John Arbash Meinel
Start tracking the per-file commit messages.
575
576
        def get_saved_text(path):
577
            """Get the saved text for a given record."""
578
            return dlg._files_store.get_value(dlg._files_store.get_iter(path), 5)
579
580
        dlg = commit.CommitDialog(tree)
581
        self.assertEqual('File commit message',
582
                         dlg._file_message_expander.get_label())
583
        self.assertFalse(dlg._file_message_expander.get_expanded())
584
        self.assertFalse(dlg._file_message_expander.get_property('sensitive'))
585
        self.assertEqual('', get_file_text())
586
734.1.23 by Curtis Hovey
Always pass a Gtk.TreePath instead of an int or tuple.
587
        dlg._treeview_files.set_cursor(
588
            Gtk.TreePath(path=1), None, False)
278.1.21 by John Arbash Meinel
Start tracking the per-file commit messages.
589
        self.assertEqual('Commit message for a',
590
                         dlg._file_message_expander.get_label())
591
        self.assertTrue(dlg._file_message_expander.get_expanded())
592
        self.assertTrue(dlg._file_message_expander.get_property('sensitive'))
593
        self.assertEqual('', get_file_text())
594
595
        self.assertEqual('', get_saved_text(1))
278.1.27 by John Arbash Meinel
Add the ability to commit just specific files.
596
        dlg._set_file_commit_message('Some text\nfor a\n')
278.1.21 by John Arbash Meinel
Start tracking the per-file commit messages.
597
        dlg._save_current_file_message()
598
        # We should have updated the ListStore with the new file commit info
599
        self.assertEqual('Some text\nfor a\n', get_saved_text(1))
600
734.1.23 by Curtis Hovey
Always pass a Gtk.TreePath instead of an int or tuple.
601
        dlg._treeview_files.set_cursor(
602
            Gtk.TreePath(path=2), None, False)
278.1.21 by John Arbash Meinel
Start tracking the per-file commit messages.
603
        self.assertEqual('Commit message for b/',
604
                         dlg._file_message_expander.get_label())
605
        self.assertTrue(dlg._file_message_expander.get_expanded())
606
        self.assertTrue(dlg._file_message_expander.get_property('sensitive'))
607
        self.assertEqual('', get_file_text())
608
609
        self.assertEqual('', get_saved_text(2))
278.1.27 by John Arbash Meinel
Add the ability to commit just specific files.
610
        dlg._set_file_commit_message('More text\nfor b\n')
278.1.21 by John Arbash Meinel
Start tracking the per-file commit messages.
611
        # Now switch back to 'a'. The message should be saved, and the buffer
612
        # should be updated with the other text
734.1.23 by Curtis Hovey
Always pass a Gtk.TreePath instead of an int or tuple.
613
        dlg._treeview_files.set_cursor(
614
            Gtk.TreePath(path=1), None, False)
278.1.21 by John Arbash Meinel
Start tracking the per-file commit messages.
615
        self.assertEqual('More text\nfor b\n', get_saved_text(2))
616
        self.assertEqual('Commit message for a',
617
                         dlg._file_message_expander.get_label())
618
        self.assertTrue(dlg._file_message_expander.get_expanded())
619
        self.assertTrue(dlg._file_message_expander.get_property('sensitive'))
620
        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,
621
622
    def test_toggle_all_files(self):
623
        """When checking the All Files entry, it should toggle all fields"""
624
        tree = self.make_branch_and_tree('tree')
625
        self.build_tree(['tree/a', 'tree/b/'])
626
        tree.add(['a', 'b'], ['a-id', 'b-id'])
627
628
        dlg = commit.CommitDialog(tree)
769 by Jelmer Vernooij
Cope with some strings being unicode when returned by some versions of gtk.
629
        self.assertEqual([("", "", True),
278.1.20 by John Arbash Meinel
We always select the All Files record in the files view,
630
                          ('a-id', 'a', True),
631
                          ('b-id', 'b', True),
632
                         ], [(r[0], r[1], r[2]) for r in dlg._files_store])
633
634
        # TODO: jam 20071002 I'm not sure how to exactly trigger a toggle, it
635
        #       looks like we need to call renderer.activate() and pass an
636
        #       event and widget, and lots of other stuff I'm not sure what to
637
        #       do with. So instead, we just call toggle directly, and assume
638
        #       that toggle is hooked in correctly
639
        # column = dlg._treeview_files.get_column(0)
734.1.20 by Curtis Hovey
col.get_cell_renderers => col.get_cells.
640
        # renderer = column.get_cells()[0]
278.1.20 by John Arbash Meinel
We always select the All Files record in the files view,
641
642
        # Toggle a single entry should set just that entry to False
643
        dlg._toggle_commit(None, 1, dlg._files_store)
769 by Jelmer Vernooij
Cope with some strings being unicode when returned by some versions of gtk.
644
        self.assertEqual([("", "", True),
278.1.20 by John Arbash Meinel
We always select the All Files record in the files view,
645
                          ('a-id', 'a', False),
646
                          ('b-id', 'b', True),
647
                         ], [(r[0], r[1], r[2]) for r in dlg._files_store])
648
649
        # Toggling the main entry should set all entries
650
        dlg._toggle_commit(None, 0, dlg._files_store)
769 by Jelmer Vernooij
Cope with some strings being unicode when returned by some versions of gtk.
651
        self.assertEqual([("", "", False),
278.1.20 by John Arbash Meinel
We always select the All Files record in the files view,
652
                          ('a-id', 'a', False),
653
                          ('b-id', 'b', False),
654
                         ], [(r[0], r[1], r[2]) for r in dlg._files_store])
655
656
        dlg._toggle_commit(None, 2, dlg._files_store)
769 by Jelmer Vernooij
Cope with some strings being unicode when returned by some versions of gtk.
657
        self.assertEqual([("", "", False),
278.1.20 by John Arbash Meinel
We always select the All Files record in the files view,
658
                          ('a-id', 'a', False),
659
                          ('b-id', 'b', True),
660
                         ], [(r[0], r[1], r[2]) for r in dlg._files_store])
661
662
        dlg._toggle_commit(None, 0, dlg._files_store)
769 by Jelmer Vernooij
Cope with some strings being unicode when returned by some versions of gtk.
663
        self.assertEqual([("", "", True),
278.1.20 by John Arbash Meinel
We always select the All Files record in the files view,
664
                          ('a-id', 'a', True),
665
                          ('b-id', 'b', True),
666
                         ], [(r[0], r[1], r[2]) for r in dlg._files_store])
278.1.23 by John Arbash Meinel
Beginning to support actual commit.
667
278.1.27 by John Arbash Meinel
Add the ability to commit just specific files.
668
    def test_specific_files(self):
669
        tree = self.make_branch_and_tree('tree')
670
        self.build_tree(['tree/a', 'tree/b/'])
671
        tree.add(['a', 'b'], ['a-id', 'b-id'])
672
673
        dlg = commit.CommitDialog(tree)
674
        self.assertEqual((['a', 'b'], []), dlg._get_specific_files())
675
278.1.43 by John Arbash Meinel
Finish connecting the 'Commit all changes' radio buttons.
676
        dlg._commit_selected_radio.set_active(True)
278.1.27 by John Arbash Meinel
Add the ability to commit just specific files.
677
        dlg._toggle_commit(None, 0, dlg._files_store)
678
        self.assertEqual(([], []), dlg._get_specific_files())
679
680
        dlg._toggle_commit(None, 1, dlg._files_store)
681
        self.assertEqual((['a'], []), dlg._get_specific_files())
682
683
    def test_specific_files_with_messages(self):
684
        tree = self.make_branch_and_tree('tree')
278.1.33 by John Arbash Meinel
Only enable the per-file dialog if 'per_file_commits' is enabled in the config.
685
        tree.branch.get_config().set_user_option('per_file_commits', 'true')
278.1.27 by John Arbash Meinel
Add the ability to commit just specific files.
686
        self.build_tree(['tree/a_file', 'tree/b_dir/'])
687
        tree.add(['a_file', 'b_dir'], ['1a-id', '0b-id'])
688
689
        dlg = commit.CommitDialog(tree)
278.1.43 by John Arbash Meinel
Finish connecting the 'Commit all changes' radio buttons.
690
        dlg._commit_selected_radio.set_active(True)
278.1.27 by John Arbash Meinel
Add the ability to commit just specific files.
691
        self.assertEqual((['a_file', 'b_dir'], []), dlg._get_specific_files())
692
734.1.23 by Curtis Hovey
Always pass a Gtk.TreePath instead of an int or tuple.
693
        dlg._treeview_files.set_cursor(
694
            Gtk.TreePath(path=1), None, False)
278.1.27 by John Arbash Meinel
Add the ability to commit just specific files.
695
        dlg._set_file_commit_message('Test\nmessage\nfor a_file\n')
734.1.23 by Curtis Hovey
Always pass a Gtk.TreePath instead of an int or tuple.
696
        dlg._treeview_files.set_cursor(
697
            Gtk.TreePath(path=2), None, False)
278.1.27 by John Arbash Meinel
Add the ability to commit just specific files.
698
        dlg._set_file_commit_message('message\nfor b_dir\n')
699
700
        self.assertEqual((['a_file', 'b_dir'],
701
                          [{'path':'a_file', 'file_id':'1a-id',
702
                            'message':'Test\nmessage\nfor a_file\n'},
703
                           {'path':'b_dir', 'file_id':'0b-id',
704
                            'message':'message\nfor b_dir\n'},
705
                          ]), dlg._get_specific_files())
706
707
        dlg._toggle_commit(None, 1, dlg._files_store)
708
        self.assertEqual((['b_dir'],
709
                          [{'path':'b_dir', 'file_id':'0b-id',
710
                            'message':'message\nfor b_dir\n'},
711
                          ]), dlg._get_specific_files())
712
622.1.1 by John Arbash Meinel
Ensure that per-file commit messages and global commit messages get sanitized.
713
    def test_specific_files_sanitizes_messages(self):
714
        tree = self.make_branch_and_tree('tree')
715
        tree.branch.get_config().set_user_option('per_file_commits', 'true')
716
        self.build_tree(['tree/a_file', 'tree/b_dir/'])
717
        tree.add(['a_file', 'b_dir'], ['1a-id', '0b-id'])
718
719
        dlg = commit.CommitDialog(tree)
720
        dlg._commit_selected_radio.set_active(True)
721
        self.assertEqual((['a_file', 'b_dir'], []), dlg._get_specific_files())
722
734.1.23 by Curtis Hovey
Always pass a Gtk.TreePath instead of an int or tuple.
723
        dlg._treeview_files.set_cursor(
724
            Gtk.TreePath(path=1), None, False)
622.1.1 by John Arbash Meinel
Ensure that per-file commit messages and global commit messages get sanitized.
725
        dlg._set_file_commit_message('Test\r\nmessage\rfor a_file\n')
734.1.23 by Curtis Hovey
Always pass a Gtk.TreePath instead of an int or tuple.
726
        dlg._treeview_files.set_cursor(
727
            Gtk.TreePath(path=2), None, False)
622.1.1 by John Arbash Meinel
Ensure that per-file commit messages and global commit messages get sanitized.
728
        dlg._set_file_commit_message('message\r\nfor\nb_dir\r')
729
730
        self.assertEqual((['a_file', 'b_dir'],
731
                          [{'path':'a_file', 'file_id':'1a-id',
732
                            'message':'Test\nmessage\nfor a_file\n'},
733
                           {'path':'b_dir', 'file_id':'0b-id',
734
                            'message':'message\nfor\nb_dir\n'},
735
                          ]), dlg._get_specific_files())
736
278.1.23 by John Arbash Meinel
Beginning to support actual commit.
737
635.2.10 by Vincent Ladeuil
Complete tests around saved commit messages.
738
class QuestionHelpers(object):
278.1.23 by John Arbash Meinel
Beginning to support actual commit.
739
278.1.26 by John Arbash Meinel
Handle pointless commits and trees with unknown files.
740
    def _set_question_yes(self, dlg):
741
        """Set the dialog to answer YES to any questions."""
742
        self.questions = []
606 by Vincent Ladeuil
Fix gtk dialogs popping up and asking for input during selftest.
743
        def _question_yes(*args, **kwargs):
278.1.26 by John Arbash Meinel
Handle pointless commits and trees with unknown files.
744
            self.questions.append(args)
745
            self.questions.append('YES')
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
746
            return Gtk.ResponseType.YES
278.1.26 by John Arbash Meinel
Handle pointless commits and trees with unknown files.
747
        dlg._question_dialog = _question_yes
748
749
    def _set_question_no(self, dlg):
750
        """Set the dialog to answer NO to any questions."""
751
        self.questions = []
606 by Vincent Ladeuil
Fix gtk dialogs popping up and asking for input during selftest.
752
        def _question_no(*args, **kwargs):
278.1.26 by John Arbash Meinel
Handle pointless commits and trees with unknown files.
753
            self.questions.append(args)
754
            self.questions.append('NO')
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
755
            return Gtk.ResponseType.NO
278.1.26 by John Arbash Meinel
Handle pointless commits and trees with unknown files.
756
        dlg._question_dialog = _question_no
757
635.2.10 by Vincent Ladeuil
Complete tests around saved commit messages.
758
759
class TestCommitDialog_Commit(tests.TestCaseWithTransport, QuestionHelpers):
760
    """Tests on the actual 'commit' button being pushed."""
761
278.1.25 by John Arbash Meinel
Add the 'Only Commit Locally' checkbox, we may want to put it elsewhere, though.
762
    def test_bound_commit_local(self):
763
        tree = self.make_branch_and_tree('tree')
764
        self.build_tree(['tree/a'])
765
        tree.add(['a'], ['a-id'])
766
        rev_id1 = tree.commit('one')
767
768
        tree2 = tree.bzrdir.sprout('tree2').open_workingtree()
769
        self.build_tree(['tree2/b'])
770
        tree2.add(['b'], ['b-id'])
771
        tree2.branch.bind(tree.branch)
772
773
        dlg = commit.CommitDialog(tree2)
774
        # With the check box set, it should only effect the local branch
775
        dlg._check_local.set_active(True)
776
        dlg._set_global_commit_message('Commit message\n')
777
        dlg._do_commit()
778
779
        last_rev = tree2.last_revision()
780
        self.assertEqual(last_rev, dlg.committed_revision_id)
781
        self.assertEqual(rev_id1, tree.branch.last_revision())
782
622.1.1 by John Arbash Meinel
Ensure that per-file commit messages and global commit messages get sanitized.
783
    def test_commit_global_sanitizes_message(self):
784
        tree = self.make_branch_and_tree('tree')
785
        self.build_tree(['tree/a'])
786
        tree.add(['a'], ['a-id'])
787
        rev_id1 = tree.commit('one')
788
789
        self.build_tree(['tree/b'])
790
        tree.add(['b'], ['b-id'])
791
        dlg = commit.CommitDialog(tree)
792
        # With the check box set, it should only effect the local branch
793
        dlg._set_global_commit_message('Commit\r\nmessage\rfoo\n')
794
        dlg._do_commit()
795
        rev = tree.branch.repository.get_revision(tree.last_revision())
796
        self.assertEqual('Commit\nmessage\nfoo\n', rev.message)
797
278.1.25 by John Arbash Meinel
Add the 'Only Commit Locally' checkbox, we may want to put it elsewhere, though.
798
    def test_bound_commit_both(self):
799
        tree = self.make_branch_and_tree('tree')
800
        self.build_tree(['tree/a'])
801
        tree.add(['a'], ['a-id'])
802
        rev_id1 = tree.commit('one')
803
804
        tree2 = tree.bzrdir.sprout('tree2').open_workingtree()
805
        self.build_tree(['tree2/b'])
806
        tree2.add(['b'], ['b-id'])
807
        tree2.branch.bind(tree.branch)
808
809
        dlg = commit.CommitDialog(tree2)
810
        # With the check box set, it should only effect the local branch
811
        dlg._check_local.set_active(False)
812
        dlg._set_global_commit_message('Commit message\n')
813
        dlg._do_commit()
814
815
        last_rev = tree2.last_revision()
816
        self.assertEqual(last_rev, dlg.committed_revision_id)
817
        self.assertEqual(last_rev, tree.branch.last_revision())
818
606 by Vincent Ladeuil
Fix gtk dialogs popping up and asking for input during selftest.
819
    def test_commit_empty_message(self):
278.1.23 by John Arbash Meinel
Beginning to support actual commit.
820
        tree = self.make_branch_and_tree('tree')
821
        self.build_tree(['tree/a', 'tree/b'])
822
        tree.add(['a'], ['a-id'])
823
        rev_id = tree.commit('one')
824
825
        tree.add(['b'], ['b-id'])
826
827
        dlg = commit.CommitDialog(tree)
278.1.26 by John Arbash Meinel
Handle pointless commits and trees with unknown files.
828
        self._set_question_no(dlg)
278.1.23 by John Arbash Meinel
Beginning to support actual commit.
829
        dlg._do_commit()
830
        self.assertEqual(
831
            [('Commit with an empty message?',
832
              'You can describe your commit intent in the message.'),
833
              'NO',
278.1.26 by John Arbash Meinel
Handle pointless commits and trees with unknown files.
834
            ], self.questions)
278.1.23 by John Arbash Meinel
Beginning to support actual commit.
835
        # By saying NO, nothing should be committed.
836
        self.assertEqual(rev_id, tree.last_revision())
837
        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.
838
        self.assertTrue(dlg._global_message_text_view.get_property('is-focus'))
278.1.23 by John Arbash Meinel
Beginning to support actual commit.
839
278.1.26 by John Arbash Meinel
Handle pointless commits and trees with unknown files.
840
        self._set_question_yes(dlg)
278.1.23 by John Arbash Meinel
Beginning to support actual commit.
841
842
        dlg._do_commit()
843
        self.assertEqual(
844
            [('Commit with an empty message?',
845
              'You can describe your commit intent in the message.'),
278.1.26 by John Arbash Meinel
Handle pointless commits and trees with unknown files.
846
              'YES',
847
            ], self.questions)
278.1.23 by John Arbash Meinel
Beginning to support actual commit.
848
        committed = tree.last_revision()
849
        self.assertNotEqual(rev_id, committed)
850
        self.assertEqual(committed, dlg.committed_revision_id)
851
852
    def test_initial_commit(self):
853
        tree = self.make_branch_and_tree('tree')
854
        self.build_tree(['tree/a'])
855
        tree.add(['a'], ['a-id'])
856
857
        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.
858
        dlg._set_global_commit_message('Some text\n')
278.1.23 by John Arbash Meinel
Beginning to support actual commit.
859
        dlg._do_commit()
860
861
        last_rev = tree.last_revision()
862
        self.assertEqual(last_rev, dlg.committed_revision_id)
863
        rev = tree.branch.repository.get_revision(last_rev)
864
        self.assertEqual(last_rev, rev.revision_id)
865
        self.assertEqual('Some text\n', rev.message)
278.1.26 by John Arbash Meinel
Handle pointless commits and trees with unknown files.
866
867
    def test_pointless_commit(self):
868
        tree = self.make_branch_and_tree('tree')
869
        self.build_tree(['tree/a'])
870
        tree.add(['a'], ['a-id'])
871
        rev_id1 = tree.commit('one')
872
873
        dlg = commit.CommitDialog(tree)
874
        dlg._set_global_commit_message('Some text\n')
875
876
        self._set_question_no(dlg)
877
        dlg._do_commit()
878
879
        self.assertIs(None, dlg.committed_revision_id)
880
        self.assertEqual(rev_id1, tree.last_revision())
881
        self.assertEqual(
882
            [('Commit with no changes?',
883
              'There are no changes in the working tree.'
884
              ' Do you want to commit anyway?'),
885
              'NO',
886
            ], self.questions)
887
888
        self._set_question_yes(dlg)
889
        dlg._do_commit()
890
891
        rev_id2 = tree.last_revision()
892
        self.assertEqual(rev_id2, dlg.committed_revision_id)
893
        self.assertNotEqual(rev_id1, rev_id2)
894
        self.assertEqual(
895
            [('Commit with no changes?',
896
              'There are no changes in the working tree.'
897
              ' Do you want to commit anyway?'),
898
              'YES',
899
            ], self.questions)
900
901
    def test_unknowns(self):
902
        """We should check if there are unknown files."""
903
        tree = self.make_branch_and_tree('tree')
904
        rev_id1 = tree.commit('one')
905
        self.build_tree(['tree/a', 'tree/b'])
906
        tree.add(['a'], ['a-id'])
907
908
        dlg = commit.CommitDialog(tree)
909
        dlg._set_global_commit_message('Some text\n')
910
        self._set_question_no(dlg)
911
912
        dlg._do_commit()
913
914
        self.assertIs(None, dlg.committed_revision_id)
915
        self.assertEqual(rev_id1, tree.last_revision())
916
        self.assertEqual(
917
            [("Commit with unknowns?",
918
              "Unknown files exist in the working tree. Commit anyway?"),
919
              "NO",
920
            ], self.questions)
921
922
        self._set_question_yes(dlg)
923
        dlg._do_commit()
924
925
        rev_id2 = tree.last_revision()
926
        self.assertNotEqual(rev_id1, rev_id2)
927
        self.assertEqual(rev_id2, dlg.committed_revision_id)
928
        self.assertEqual(
929
            [("Commit with unknowns?",
930
              "Unknown files exist in the working tree. Commit anyway?"),
931
              "YES",
932
            ], self.questions)
933
278.1.27 by John Arbash Meinel
Add the ability to commit just specific files.
934
    def test_commit_specific_files(self):
935
        tree = self.make_branch_and_tree('tree')
936
        rev_id1 = tree.commit('one')
937
        self.build_tree(['tree/a', 'tree/b'])
938
        tree.add(['a', 'b'], ['a-id', 'b-id'])
939
940
        dlg = commit.CommitDialog(tree)
278.1.43 by John Arbash Meinel
Finish connecting the 'Commit all changes' radio buttons.
941
        dlg._commit_selected_radio.set_active(True) # enable partial
278.1.27 by John Arbash Meinel
Add the ability to commit just specific files.
942
        dlg._toggle_commit(None, 2, dlg._files_store) # unset 'b'
943
944
        dlg._set_global_commit_message('Committing just "a"\n')
945
        dlg._do_commit()
946
947
        rev_id2 = dlg.committed_revision_id
948
        self.assertIsNot(None, rev_id2)
949
        self.assertEqual(rev_id2, tree.last_revision())
950
951
        rt = tree.branch.repository.revision_tree(rev_id2)
952
        entries = [(path, ie.file_id) for path, ie in rt.iter_entries_by_dir()
953
                                       if path] # Ignore the root entry
954
        self.assertEqual([('a', 'a-id')], entries)
955
278.1.43 by John Arbash Meinel
Finish connecting the 'Commit all changes' radio buttons.
956
    def test_commit_partial_no_partial(self):
957
        """Ignore the checkboxes if committing all files."""
958
        tree = self.make_branch_and_tree('tree')
959
        rev_id1 = tree.commit('one')
960
        self.build_tree(['tree/a', 'tree/b'])
961
        tree.add(['a', 'b'], ['a-id', 'b-id'])
962
963
        dlg = commit.CommitDialog(tree)
964
        dlg._commit_selected_radio.set_active(True) # enable partial
965
        dlg._toggle_commit(None, 2, dlg._files_store) # unset 'b'
966
967
        # Switch back to committing all changes
968
        dlg._commit_all_files_radio.set_active(True)
969
970
        dlg._set_global_commit_message('Committing everything\n')
971
        dlg._do_commit()
972
973
        rev_id2 = dlg.committed_revision_id
974
        self.assertIsNot(None, rev_id2)
975
        self.assertEqual(rev_id2, tree.last_revision())
976
977
        rt = tree.branch.repository.revision_tree(rev_id2)
978
        entries = [(path, ie.file_id) for path, ie in rt.iter_entries_by_dir()
979
                                       if path] # Ignore the root entry
980
        self.assertEqual([('a', 'a-id'), ('b', 'b-id')], entries)
981
278.1.27 by John Arbash Meinel
Add the ability to commit just specific files.
982
    def test_commit_no_messages(self):
983
        tree = self.make_branch_and_tree('tree')
984
        rev_id1 = tree.commit('one')
985
        self.build_tree(['tree/a', 'tree/b'])
986
        tree.add(['a', 'b'], ['a-id', 'b-id'])
987
988
        dlg = commit.CommitDialog(tree)
989
        dlg._set_global_commit_message('Simple commit\n')
990
        dlg._do_commit()
991
992
        rev = tree.branch.repository.get_revision(dlg.committed_revision_id)
993
        self.failIf('file-info' in rev.properties)
994
278.1.33 by John Arbash Meinel
Only enable the per-file dialog if 'per_file_commits' is enabled in the config.
995
    def test_commit_disabled_messages(self):
996
        tree = self.make_branch_and_tree('tree')
997
        rev_id1 = tree.commit('one')
998
999
        self.build_tree(['tree/a', 'tree/b'])
1000
        tree.add(['a', 'b'], ['a-id', 'b-id'])
1001
1002
        dlg = commit.CommitDialog(tree)
1003
        self.assertFalse(dlg._file_message_expander.get_property('visible'))
278.1.38 by John Arbash Meinel
Add tests that when per-file messages are disabled
1004
        self.assertEqual('Commit Message',
1005
                         dlg._global_message_label.get_text())
278.1.33 by John Arbash Meinel
Only enable the per-file dialog if 'per_file_commits' is enabled in the config.
1006
1007
        tree.branch.get_config().set_user_option('per_file_commits', 'true')
1008
        dlg = commit.CommitDialog(tree)
1009
        self.assertTrue(dlg._file_message_expander.get_property('visible'))
278.1.38 by John Arbash Meinel
Add tests that when per-file messages are disabled
1010
        self.assertEqual('Global Commit Message',
1011
                         dlg._global_message_label.get_text())
278.1.33 by John Arbash Meinel
Only enable the per-file dialog if 'per_file_commits' is enabled in the config.
1012
1013
        tree.branch.get_config().set_user_option('per_file_commits', 'on')
1014
        dlg = commit.CommitDialog(tree)
1015
        self.assertTrue(dlg._file_message_expander.get_property('visible'))
278.1.38 by John Arbash Meinel
Add tests that when per-file messages are disabled
1016
        self.assertEqual('Global Commit Message',
1017
                         dlg._global_message_label.get_text())
278.1.33 by John Arbash Meinel
Only enable the per-file dialog if 'per_file_commits' is enabled in the config.
1018
1019
        tree.branch.get_config().set_user_option('per_file_commits', 'y')
1020
        dlg = commit.CommitDialog(tree)
1021
        self.assertTrue(dlg._file_message_expander.get_property('visible'))
278.1.38 by John Arbash Meinel
Add tests that when per-file messages are disabled
1022
        self.assertEqual('Global Commit Message',
1023
                         dlg._global_message_label.get_text())
278.1.33 by John Arbash Meinel
Only enable the per-file dialog if 'per_file_commits' is enabled in the config.
1024
1025
        tree.branch.get_config().set_user_option('per_file_commits', 'n')
1026
        dlg = commit.CommitDialog(tree)
1027
        self.assertFalse(dlg._file_message_expander.get_property('visible'))
278.1.38 by John Arbash Meinel
Add tests that when per-file messages are disabled
1028
        self.assertEqual('Commit Message',
1029
                         dlg._global_message_label.get_text())
278.1.33 by John Arbash Meinel
Only enable the per-file dialog if 'per_file_commits' is enabled in the config.
1030
278.1.27 by John Arbash Meinel
Add the ability to commit just specific files.
1031
    def test_commit_specific_files_with_messages(self):
1032
        tree = self.make_branch_and_tree('tree')
278.1.33 by John Arbash Meinel
Only enable the per-file dialog if 'per_file_commits' is enabled in the config.
1033
        tree.branch.get_config().set_user_option('per_file_commits', 'true')
278.1.27 by John Arbash Meinel
Add the ability to commit just specific files.
1034
        rev_id1 = tree.commit('one')
1035
        self.build_tree(['tree/a', 'tree/b'])
1036
        tree.add(['a', 'b'], ['a-id', 'b-id'])
1037
1038
        dlg = commit.CommitDialog(tree)
278.1.43 by John Arbash Meinel
Finish connecting the 'Commit all changes' radio buttons.
1039
        dlg._commit_selected_radio.set_active(True) # enable partial
734.1.23 by Curtis Hovey
Always pass a Gtk.TreePath instead of an int or tuple.
1040
        dlg._treeview_files.set_cursor(
1041
            Gtk.TreePath(path=1), None, False)
278.1.27 by John Arbash Meinel
Add the ability to commit just specific files.
1042
        dlg._set_file_commit_message('Message for A\n')
734.1.23 by Curtis Hovey
Always pass a Gtk.TreePath instead of an int or tuple.
1043
        dlg._treeview_files.set_cursor(
1044
            Gtk.TreePath(path=2), None, False)
278.1.27 by John Arbash Meinel
Add the ability to commit just specific files.
1045
        dlg._set_file_commit_message('Message for B\n')
1046
        dlg._toggle_commit(None, 2, dlg._files_store) # unset 'b'
1047
        dlg._set_global_commit_message('Commit just "a"')
1048
1049
        dlg._do_commit()
1050
1051
        rev_id2 = dlg.committed_revision_id
1052
        self.assertEqual(rev_id2, tree.last_revision())
1053
        rev = tree.branch.repository.get_revision(rev_id2)
1054
        self.assertEqual('Commit just "a"', rev.message)
1055
        file_info = rev.properties['file-info']
662 by Vincent Ladeuil
Fix test failures.
1056
        self.assertEqual(u'ld7:file_id4:a-id'
1057
                         '7:message14:Message for A\n'
1058
                         '4:path1:a'
1059
                         'ee',
1060
                         file_info)
278.1.27 by John Arbash Meinel
Add the ability to commit just specific files.
1061
        self.assertEqual([{'path':'a', 'file_id':'a-id',
662 by Vincent Ladeuil
Fix test failures.
1062
                           'message':'Message for A\n'},],
1063
                         bencode.bdecode(file_info.encode('UTF-8')))
278.1.28 by John Arbash Meinel
Ensure that we can set per-file messages even during a merge.
1064
1065
    def test_commit_messages_after_merge(self):
1066
        tree = self.make_branch_and_tree('tree')
278.1.33 by John Arbash Meinel
Only enable the per-file dialog if 'per_file_commits' is enabled in the config.
1067
        tree.branch.get_config().set_user_option('per_file_commits', 'true')
278.1.28 by John Arbash Meinel
Ensure that we can set per-file messages even during a merge.
1068
        rev_id1 = tree.commit('one')
1069
        tree2 = tree.bzrdir.sprout('tree2').open_workingtree()
1070
        self.build_tree(['tree2/a', 'tree2/b'])
1071
        tree2.add(['a', 'b'], ['a-id', 'b-id'])
1072
        rev_id2 = tree2.commit('two')
1073
1074
        tree.merge_from_branch(tree2.branch)
1075
1076
        dlg = commit.CommitDialog(tree)
734.1.23 by Curtis Hovey
Always pass a Gtk.TreePath instead of an int or tuple.
1077
        dlg._treeview_files.set_cursor(
1078
            Gtk.TreePath(path=1), None, False) # 'a'
278.1.28 by John Arbash Meinel
Ensure that we can set per-file messages even during a merge.
1079
        dlg._set_file_commit_message('Message for A\n')
1080
        # No message for 'B'
1081
        dlg._set_global_commit_message('Merging from "tree2"\n')
1082
1083
        dlg._do_commit()
1084
1085
        rev_id3 = dlg.committed_revision_id
1086
        self.assertEqual(rev_id3, tree.last_revision())
1087
        rev = tree.branch.repository.get_revision(rev_id3)
1088
        self.assertEqual('Merging from "tree2"\n', rev.message)
1089
        self.assertEqual([rev_id1, rev_id2], rev.parent_ids)
1090
        file_info = rev.properties['file-info']
662 by Vincent Ladeuil
Fix test failures.
1091
        self.assertEqual(u'ld7:file_id4:a-id'
1092
                         '7:message14:Message for A\n'
1093
                         '4:path1:a'
1094
                         'ee',
1095
                         file_info)
278.1.28 by John Arbash Meinel
Ensure that we can set per-file messages even during a merge.
1096
        self.assertEqual([{'path':'a', 'file_id':'a-id',
662 by Vincent Ladeuil
Fix test failures.
1097
                           'message':'Message for A\n'},],
1098
                         bencode.bdecode(file_info.encode('UTF-8')))
278.1.29 by John Arbash Meinel
Start testing with Unicode data.
1099
1100
    def test_commit_unicode_messages(self):
737 by Jelmer Vernooij
Support new location of UnicodeFilenameFeature in 2.5.
1101
        self.requireFeature(UnicodeFilenameFeature)
278.1.29 by John Arbash Meinel
Start testing with Unicode data.
1102
1103
        tree = self.make_branch_and_tree('tree')
278.1.33 by John Arbash Meinel
Only enable the per-file dialog if 'per_file_commits' is enabled in the config.
1104
        tree.branch.get_config().set_user_option('per_file_commits', 'true')
278.1.29 by John Arbash Meinel
Start testing with Unicode data.
1105
        self.build_tree(['tree/a', u'tree/\u03a9'])
1106
        tree.add(['a', u'\u03a9'], ['a-id', 'omega-id'])
1107
1108
        dlg = commit.CommitDialog(tree)
734.1.23 by Curtis Hovey
Always pass a Gtk.TreePath instead of an int or tuple.
1109
        dlg._treeview_files.set_cursor(
1110
            Gtk.TreePath(path=1), None, False) # 'a'
278.1.29 by John Arbash Meinel
Start testing with Unicode data.
1111
        dlg._set_file_commit_message(u'Test \xfan\xecc\xf6de\n')
734.1.23 by Curtis Hovey
Always pass a Gtk.TreePath instead of an int or tuple.
1112
        dlg._treeview_files.set_cursor(
1113
            Gtk.TreePath(path=2), None, False) # omega
278.1.29 by John Arbash Meinel
Start testing with Unicode data.
1114
        dlg._set_file_commit_message(u'\u03a9 is the end of all things.\n')
1115
        dlg._set_global_commit_message(u'\u03a9 and \xfan\xecc\xf6de\n')
1116
1117
        self.assertEqual(([u'a', u'\u03a9'],
1118
                          [{'path':'a', 'file_id':'a-id',
1119
                            'message':'Test \xc3\xban\xc3\xacc\xc3\xb6de\n'},
1120
                           {'path':'\xce\xa9', 'file_id':'omega-id',
1121
                            'message':'\xce\xa9 is the end of all things.\n'},
1122
                          ]), dlg._get_specific_files())
1123
1124
        dlg._do_commit()
1125
1126
        rev = tree.branch.repository.get_revision(dlg.committed_revision_id)
278.1.31 by John Arbash Meinel
We can make bencode work again by a simple decode/encode step.
1127
        file_info = rev.properties['file-info'].encode('UTF-8')
278.1.29 by John Arbash Meinel
Start testing with Unicode data.
1128
        value = ('ld7:file_id4:a-id'
1129
                   '7:message16:Test \xc3\xban\xc3\xacc\xc3\xb6de\n'
1130
                   '4:path1:a'
1131
                  'e'
1132
                  'd7:file_id8:omega-id'
1133
                   '7:message29:\xce\xa9 is the end of all things.\n'
1134
                   '4:path2:\xce\xa9'
1135
                  'e'
1136
                 'e')
1137
        self.assertEqual(value, file_info)
1138
        file_info_decoded = bencode.bdecode(file_info)
1139
        for d in file_info_decoded:
278.1.31 by John Arbash Meinel
We can make bencode work again by a simple decode/encode step.
1140
            d['path'] = d['path'].decode('UTF-8')
1141
            d['message'] = d['message'].decode('UTF-8')
278.1.29 by John Arbash Meinel
Start testing with Unicode data.
1142
1143
        self.assertEqual([{'path':u'a', 'file_id':'a-id',
1144
                           'message':u'Test \xfan\xecc\xf6de\n'},
1145
                          {'path':u'\u03a9', 'file_id':'omega-id',
1146
                           'message':u'\u03a9 is the end of all things.\n'},
1147
                         ], file_info_decoded)
622.1.1 by John Arbash Meinel
Ensure that per-file commit messages and global commit messages get sanitized.
1148
1149
1150
class TestSanitizeMessage(tests.TestCase):
1151
1152
    def assertSanitize(self, expected, original):
1153
        self.assertEqual(expected,
1154
                         commit._sanitize_and_decode_message(original))
1155
1156
    def test_untouched(self):
1157
        self.assertSanitize('foo\nbar\nbaz\n', 'foo\nbar\nbaz\n')
1158
1159
    def test_converts_cr_to_lf(self):
1160
        self.assertSanitize('foo\nbar\nbaz\n', 'foo\rbar\rbaz\r')
1161
1162
    def test_converts_crlf_to_lf(self):
1163
        self.assertSanitize('foo\nbar\nbaz\n', 'foo\r\nbar\r\nbaz\r\n')
1164
1165
    def test_converts_mixed_to_lf(self):
1166
        self.assertSanitize('foo\nbar\nbaz\n', 'foo\r\nbar\rbaz\n')
635.2.8 by Vincent Ladeuil
Start testing patch behavior.
1167
1168
635.2.10 by Vincent Ladeuil
Complete tests around saved commit messages.
1169
class TestSavedCommitMessages(tests.TestCaseWithTransport):
635.2.9 by Vincent Ladeuil
Tests completed for uncommit.
1170
635.2.12 by Vincent Ladeuil
Implement commit message saving without modifying bzrlib.
1171
    def setUp(self):
1172
        super(TestSavedCommitMessages, self).setUp()
1173
        # Install our hook
1174
        branch.Branch.hooks.install_named_hook(
747 by Jelmer Vernooij
Fix import for commitmsgs.
1175
            'post_uncommit', commitmsgs.save_commit_messages, None)
635.2.12 by Vincent Ladeuil
Implement commit message saving without modifying bzrlib.
1176
635.2.9 by Vincent Ladeuil
Tests completed for uncommit.
1177
    def _get_file_info_dict(self, rank):
1178
        file_info = [dict(path='a', file_id='a-id', message='a msg %d' % rank),
1179
                     dict(path='b', file_id='b-id', message='b msg %d' % rank)]
1180
        return file_info
1181
1182
    def _get_file_info_revprops(self, rank):
1183
        file_info_prop = self._get_file_info_dict(rank)
1184
        return {'file-info': bencode.bencode(file_info_prop).decode('UTF-8')}
1185
1186
    def _get_commit_message(self):
1187
        return self.config.get_user_option('gtk_global_commit_message')
1188
1189
    def _get_file_commit_messages(self):
1190
        return self.config.get_user_option('gtk_file_commit_messages')
1191
635.2.10 by Vincent Ladeuil
Complete tests around saved commit messages.
1192
1193
class TestUncommitHook(TestSavedCommitMessages):
1194
1195
    def setUp(self):
1196
        super(TestUncommitHook, self).setUp()
1197
        self.tree = self.make_branch_and_tree('tree')
1198
        self.config = self.tree.branch.get_config()
1199
        self.build_tree(['tree/a', 'tree/b'])
1200
        self.tree.add(['a'], ['a-id'])
1201
        self.tree.add(['b'], ['b-id'])
635.2.12 by Vincent Ladeuil
Implement commit message saving without modifying bzrlib.
1202
        rev1 = self.tree.commit('one', rev_id='one-id',
1203
                                revprops=self._get_file_info_revprops(1))
1204
        rev2 = self.tree.commit('two', rev_id='two-id',
1205
                                revprops=self._get_file_info_revprops(2))
1206
        rev3 = self.tree.commit('three', rev_id='three-id',
635.2.10 by Vincent Ladeuil
Complete tests around saved commit messages.
1207
                                revprops=self._get_file_info_revprops(3))
1208
635.2.9 by Vincent Ladeuil
Tests completed for uncommit.
1209
    def test_uncommit_one_by_one(self):
1210
        uncommit.uncommit(self.tree.branch, tree=self.tree)
1211
        self.assertEquals(u'three', self._get_commit_message())
1212
        self.assertEquals(u'd4:a-id7:a msg 34:b-id7:b msg 3e',
1213
                          self._get_file_commit_messages())
1214
1215
        uncommit.uncommit(self.tree.branch, tree=self.tree)
1216
        self.assertEquals(u'two\n******\nthree', self._get_commit_message())
1217
        self.assertEquals(u'd4:a-id22:a msg 2\n******\na msg 3'
1218
                          '4:b-id22:b msg 2\n******\nb msg 3e',
1219
                          self._get_file_commit_messages())
1220
1221
        uncommit.uncommit(self.tree.branch, tree=self.tree)
1222
        self.assertEquals(u'one\n******\ntwo\n******\nthree',
1223
                          self._get_commit_message())
1224
        self.assertEquals(u'd4:a-id37:a msg 1\n******\na msg 2\n******\na msg 3'
1225
                          '4:b-id37:b msg 1\n******\nb msg 2\n******\nb msg 3e',
1226
                          self._get_file_commit_messages())
1227
1228
    def test_uncommit_all_at_once(self):
1229
        uncommit.uncommit(self.tree.branch, tree=self.tree, revno=1)
1230
        self.assertEquals(u'one\n******\ntwo\n******\nthree',
1231
                          self._get_commit_message())
1232
        self.assertEquals(u'd4:a-id37:a msg 1\n******\na msg 2\n******\na msg 3'
1233
                          '4:b-id37:b msg 1\n******\nb msg 2\n******\nb msg 3e',
1234
                          self._get_file_commit_messages())
635.2.10 by Vincent Ladeuil
Complete tests around saved commit messages.
1235
1236
1237
class TestReusingSavedCommitMessages(TestSavedCommitMessages, QuestionHelpers):
1238
1239
    def setUp(self):
1240
        super(TestReusingSavedCommitMessages, self).setUp()
1241
        self.tree = self.make_branch_and_tree('tree')
1242
        self.config = self.tree.branch.get_config()
1243
        self.config.set_user_option('per_file_commits', 'true')
1244
        self.build_tree(['tree/a', 'tree/b'])
1245
        self.tree.add(['a'], ['a-id'])
1246
        self.tree.add(['b'], ['b-id'])
1247
        rev1 = self.tree.commit('one', revprops=self._get_file_info_revprops(1))
1248
        rev2 = self.tree.commit('two', revprops=self._get_file_info_revprops(2))
1249
        uncommit.uncommit(self.tree.branch, tree=self.tree)
1250
        self.build_tree_contents([('tree/a', 'new a content\n'),
1251
                                  ('tree/b', 'new b content'),])
1252
635.2.11 by Vincent Ladeuil
Fix a leaking dialog windows appearing during the test suite.
1253
    def _get_commit_dialog(self, tree):
1254
        # Ensure we will never use a dialog that can actually prompt the user
1255
        # during the test suite. Test *can* and *should* override with the
1256
        # correct question dialog type.
1257
        dlg = commit.CommitDialog(tree)
1258
        self._set_question_no(dlg)
1259
        return dlg
1260
635.2.10 by Vincent Ladeuil
Complete tests around saved commit messages.
1261
    def test_setup_saved_messages(self):
1262
        # Check the initial setup
1263
        self.assertEquals(u'two', self._get_commit_message())
1264
        self.assertEquals(u'd4:a-id7:a msg 24:b-id7:b msg 2e',
1265
                          self._get_file_commit_messages())
1266
1267
    def test_messages_are_reloaded(self):
635.2.11 by Vincent Ladeuil
Fix a leaking dialog windows appearing during the test suite.
1268
        dlg = self._get_commit_dialog(self.tree)
635.2.10 by Vincent Ladeuil
Complete tests around saved commit messages.
1269
        self.assertEquals(u'two', dlg._get_global_commit_message())
1270
        self.assertEquals(([u'a', u'b'],
1271
                           [{ 'path': 'a',
1272
                             'file_id': 'a-id', 'message': 'a msg 2',},
1273
                           {'path': 'b',
1274
                            'file_id': 'b-id', 'message': 'b msg 2',}],),
1275
                          dlg._get_specific_files())
1276
1277
    def test_messages_are_consumed(self):
635.2.11 by Vincent Ladeuil
Fix a leaking dialog windows appearing during the test suite.
1278
        dlg = self._get_commit_dialog(self.tree)
635.2.10 by Vincent Ladeuil
Complete tests around saved commit messages.
1279
        dlg._do_commit()
1280
        self.assertEquals(u'', self._get_commit_message())
1281
        self.assertEquals(u'de', self._get_file_commit_messages())
1282
1283
    def test_messages_are_saved_on_cancel_if_required(self):
635.2.11 by Vincent Ladeuil
Fix a leaking dialog windows appearing during the test suite.
1284
        dlg = self._get_commit_dialog(self.tree)
635.2.10 by Vincent Ladeuil
Complete tests around saved commit messages.
1285
        self._set_question_yes(dlg) # Save messages
1286
        dlg._do_cancel()
1287
        self.assertEquals(u'two', self._get_commit_message())
1288
        self.assertEquals(u'd4:a-id7:a msg 24:b-id7:b msg 2e',
1289
                          self._get_file_commit_messages())
1290
1291
    def test_messages_are_cleared_on_cancel_if_required(self):
635.2.11 by Vincent Ladeuil
Fix a leaking dialog windows appearing during the test suite.
1292
        dlg = self._get_commit_dialog(self.tree)
635.2.10 by Vincent Ladeuil
Complete tests around saved commit messages.
1293
        self._set_question_no(dlg) # Don't save messages
1294
        dlg._do_cancel()
1295
        self.assertEquals(u'', self._get_commit_message())
1296
        self.assertEquals(u'de',
1297
                          self._get_file_commit_messages())