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