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