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