1
# -*- coding: utf-8 -*-
2
# Copyright (C) 2007 Adeodato Simó <dato@net.com.org.es>
4
# This program is free software; you can redistribute it and/or modify
5
# it under the terms of the GNU General Public License as published by
6
# the Free Software Foundation; either version 2 of the License, or
7
# (at your option) any later version.
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
# GNU General Public License for more details.
14
# You should have received a copy of the GNU General Public License
15
# along with this program; if not, write to the Free Software
16
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
from cStringIO import StringIO
21
from gi.repository import Gtk
29
from bzrlib.tests.features import UnicodeFilenameFeature
30
except ImportError: # bzr < 2.5
31
from bzrlib.tests import UnicodeFilenameFeature
32
from bzrlib.merge_directive import MergeDirective2
34
from bzrlib.plugins.gtk.diff import (
39
iter_changes_to_status,
40
MergeDirectiveController,
42
from bzrlib.plugins.gtk.tests import MockMethod
46
=== modified file 'tests/test_diff.py'
47
--- tests/test_diff.py 2008-03-11 13:18:28 +0000
48
+++ tests/test_diff.py 2008-05-08 22:44:02 +0000
51
from bzrlib import tests
53
-from bzrlib.plugins.gtk.diff import DiffView, iter_changes_to_status
54
+from bzrlib.plugins.gtk.diff import (
57
+ iter_changes_to_status,
61
class TestDiffViewSimple(tests.TestCase):
64
class TestDiffViewSimple(tests.TestCase):
66
def test_parse_colordiffrc(self):
70
# now a comment and a blank line
73
# another comment preceded by whitespace
78
'diffstuff': '#ffff00',
80
parsed_colors = DiffView.parse_colordiffrc(StringIO(colordiffrc))
81
self.assertEqual(colors, parsed_colors)
84
class TestDiffView(tests.TestCaseWithTransport):
86
def test_unicode(self):
87
self.requireFeature(UnicodeFilenameFeature)
89
tree = self.make_branch_and_tree('tree')
90
self.build_tree([u'tree/\u03a9'])
91
tree.add([u'\u03a9'], ['omega-id'])
94
view.set_trees(tree, tree.basis_tree())
97
start, end = buf.get_bounds()
98
text = buf.get_text(start, end, True)
99
self.assertContainsRe(text,
100
"=== added file '\xce\xa9'\n"
101
'--- .*\t1970-01-01 00:00:00 \\+0000\n'
102
r'\+\+\+ .*\t\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d [+-]\d\d\d\d\n'
103
'@@ -0,0 \\+1,1 @@\n'
104
'\\+contents of tree/\xce\xa9\n'
110
class FakeDiffWidget(DiffWidget):
115
class TestDiffWidget(tests.TestCaseWithTransport):
117
def test_treeview_cursor_cb(self):
118
widget = FakeDiffWidget()
119
widget.set_diff_text_sections(
120
[('', None, 'patch1'), ('a', 'a', 'patch2')])
121
widget.treeview.set_cursor(Gtk.TreePath(path=1), None, False)
122
widget._treeview_cursor_cb(None)
123
self.assertTrue('patch2', widget.diff_view.buffer.props.text)
125
def test_treeview_cursor_cb_with_destroyed_treeview(self):
126
widget = FakeDiffWidget()
127
widget.set_diff_text_sections(
128
[('', None, 'patch1'), ('a', 'a', 'patch2')])
129
MockMethod.bind(self, widget.diff_view, 'show_diff')
130
widget.treeview.destroy()
131
widget._treeview_cursor_cb(None)
132
self.assertFalse(widget.diff_view.show_diff.called)
135
class FakeDiffWindow(DiffWindow):
140
class DiffWindowTestCase(tests.TestCaseWithTransport):
143
window = DiffWindow()
144
self.assertEqual('bzr diff', window.props.title)
145
self.assertEqual(0, window.props.border_width)
147
def test_init_construct_without_operations(self):
148
window = DiffWindow()
149
widgets = window.vbox.get_children()
150
self.assertEqual(2, len(widgets))
151
self.assertIsInstance(widgets[0], Gtk.MenuBar)
152
self.assertIsInstance(widgets[1], DiffWidget)
154
def test_init_construct_with_operations(self):
155
method = MockMethod()
156
window = DiffWindow(operations=[('title', method)])
157
widgets = window.vbox.get_children()
158
self.assertEqual(3, len(widgets))
159
self.assertIsInstance(widgets[0], Gtk.MenuBar)
160
self.assertIsInstance(widgets[1], Gtk.HButtonBox)
161
self.assertIsInstance(widgets[2], DiffWidget)
163
def test_get_menu_bar(self):
164
window = DiffWindow()
165
menu_bar = window._get_menu_bar()
166
self.assertIsNot(None, menu_bar)
167
menus = menu_bar.get_children()
168
self.assertEqual(1, len(menus))
169
self.assertEqual('_View', menus[0].props.label)
170
sub_menu = menus[0].get_submenu()
171
self.assertIsNot(None, sub_menu)
172
items = sub_menu.get_children()
173
self.assertEqual(1, len(items))
174
menus[0].get_submenu().get_children()[0].props.label
175
self.assertEqual('Wrap _Long Lines', items[0].props.label)
177
def test_get_button_bar_with_none(self):
178
window = DiffWindow()
179
self.assertIs(None, window._get_button_bar(None))
181
def test_get_button_bar_with_operations(self):
182
window = DiffWindow()
183
method = MockMethod()
184
button_bar = window._get_button_bar([('title', method)])
185
self.assertIsNot(None, button_bar)
186
buttons = button_bar.get_children()
187
self.assertEqual(1, len(buttons))
188
self.assertEqual('title', buttons[0].props.label)
189
buttons[0].emit('clicked')
190
self.assertIs(True, method.called)
194
class MockDiffWidget(object):
196
def set_diff_text_sections(self, sections):
197
self.sections = list(sections)
200
class MockWindow(object):
203
self.diff = MockDiffWidget()
204
self.merge_successful = False
206
def set_title(self, title):
209
def _get_save_path(self, basename):
212
def _get_merge_target(self):
218
def _merge_successful(self):
219
self.merge_successful = True
221
def _conflicts(self):
222
self.conflicts = True
224
def _handle_error(self, e):
225
self.handled_error = e
228
class TestDiffController(tests.TestCaseWithTransport):
230
def get_controller(self):
231
window = MockWindow()
232
return DiffController('load-path', eg_diff.splitlines(True), window)
234
def test_get_diff_sections(self):
235
controller = self.get_controller()
236
controller = DiffController('.', eg_diff.splitlines(True),
238
sections = list(controller.get_diff_sections())
239
self.assertEqual('Complete Diff', sections[0][0])
240
self.assertIs(None, sections[0][1])
241
self.assertEqual(eg_diff, sections[0][2])
243
self.assertEqual('tests/test_diff.py', sections[1][0])
244
self.assertEqual('tests/test_diff.py', sections[1][1])
245
self.assertEqual(''.join(eg_diff.splitlines(True)[1:]),
248
def test_initialize_window(self):
249
controller = self.get_controller()
250
controller.initialize_window(controller.window)
251
self.assertEqual(2, len(controller.window.diff.sections))
252
self.assertEqual('load-path - diff', controller.window.title)
254
def test_perform_save(self):
255
self.build_tree_contents([('load-path', 'foo')])
256
controller = self.get_controller()
257
controller.perform_save(None)
258
self.assertFileEqual('foo', 'save-path')
261
class TestMergeDirectiveController(tests.TestCaseWithTransport):
263
def make_this_other_directive(self):
264
this = self.make_branch_and_tree('this')
265
this.commit('first commit')
266
other = this.bzrdir.sprout('other').open_workingtree()
267
self.build_tree_contents([('other/foo', 'bar')])
269
other.commit('second commit')
272
directive = MergeDirective2.from_objects(other.branch.repository,
273
other.last_revision(), 0,
277
return this, other, directive
279
def make_merged_window(self, directive):
280
window = MockWindow()
281
controller = MergeDirectiveController('directive', directive, window)
282
controller.perform_merge(window)
285
def test_perform_merge_success(self):
286
this, other, directive = self.make_this_other_directive()
287
window = self.make_merged_window(directive)
288
self.assertTrue(window.merge_successful)
289
self.assertEqual(other.last_revision(), this.get_parent_ids()[1])
290
self.assertFileEqual('bar', 'this/foo')
292
def test_perform_merge_conflicts(self):
293
this, other, directive = self.make_this_other_directive()
294
self.build_tree_contents([('this/foo', 'bar')])
296
this.commit('message')
297
window = self.make_merged_window(directive)
298
self.assertFalse(window.merge_successful)
299
self.assertTrue(window.conflicts)
300
self.assertEqual(other.last_revision(), this.get_parent_ids()[1])
301
self.assertFileEqual('bar', 'this/foo')
303
def test_perform_merge_uncommitted_changes(self):
304
this, other, directive = self.make_this_other_directive()
305
self.build_tree_contents([('this/foo', 'bar')])
307
window = self.make_merged_window(directive)
308
self.assertIsInstance(window.handled_error, errors.UncommittedChanges)
311
class Test_IterChangesToStatus(tests.TestCaseWithTransport):
313
def assertStatusEqual(self, expected, tree):
314
values = iter_changes_to_status(tree.basis_tree(), tree)
315
self.assertEqual(expected, values)
317
def test_status_added(self):
318
tree = self.make_branch_and_tree('tree')
319
self.build_tree(['tree/a', 'tree/b/', 'tree/b/c'])
320
tree.add(['a', 'b', 'b/c'], ['a-id', 'b-id', 'c-id'])
322
self.assertStatusEqual(
323
[('a-id', 'a', 'added', 'a'),
324
('b-id', 'b', 'added', 'b/'),
325
('c-id', 'b/c', 'added', 'b/c'),
328
def test_status_renamed(self):
329
tree = self.make_branch_and_tree('tree')
330
self.build_tree(['tree/a', 'tree/b/', 'tree/b/c'])
331
tree.add(['a', 'b', 'b/c'], ['a-id', 'b-id', 'c-id'])
332
rev_id1 = tree.commit('one')
334
tree.rename_one('b', 'd')
335
tree.rename_one('a', 'd/a')
337
self.assertStatusEqual(
338
[('b-id', 'd', 'renamed', 'b/ => d/'),
339
('a-id', 'd/a', 'renamed', 'a => d/a'),
342
def test_status_modified(self):
343
tree = self.make_branch_and_tree('tree')
344
self.build_tree(['tree/a'])
345
tree.add(['a'], ['a-id'])
346
rev_id1 = tree.commit('one')
348
self.build_tree_contents([('tree/a', 'new contents for a\n')])
350
self.assertStatusEqual(
351
[('a-id', 'a', 'modified', 'a'),
354
def test_status_renamed_and_modified(self):
355
tree = self.make_branch_and_tree('tree')
356
self.build_tree(['tree/a', 'tree/b/', 'tree/b/c'])
357
tree.add(['a', 'b', 'b/c'], ['a-id', 'b-id', 'c-id'])
358
rev_id1 = tree.commit('one')
360
tree.rename_one('b', 'd')
361
tree.rename_one('a', 'd/a')
362
self.build_tree_contents([('tree/d/a', 'new contents for a\n'),
363
('tree/d/c', 'new contents for c\n'),
365
# 'c' is not considered renamed, because only its parent was moved, it
366
# stayed in the same directory
368
self.assertStatusEqual(
369
[('b-id', 'd', 'renamed', 'b/ => d/'),
370
('a-id', 'd/a', 'renamed and modified', 'a => d/a'),
371
('c-id', 'd/c', 'modified', 'd/c'),
374
def test_status_kind_changed(self):
375
tree = self.make_branch_and_tree('tree')
376
self.build_tree(['tree/a', 'tree/b'])
377
tree.add(['a', 'b'], ['a-id', 'b-id'])
381
self.build_tree(['tree/a/'])
382
# XXX: This is technically valid, and the file list handles it fine,
383
# but 'show_diff_trees()' does not, so we skip this part of the
385
# tree.rename_one('b', 'c')
386
# os.remove('tree/c')
387
# self.build_tree(['tree/c/'])
389
self.assertStatusEqual(
390
[('a-id', 'a', 'kind changed', 'a => a/'),
391
# ('b-id', 'c', True, 'b => c/', 'renamed and modified'),
394
def test_status_removed(self):
395
tree = self.make_branch_and_tree('tree')
396
self.build_tree(['tree/a', 'tree/b/'])
397
tree.add(['a', 'b'], ['a-id', 'b-id'])
401
tree.remove('b', force=True)
403
self.assertStatusEqual(
404
[('a-id', 'a', 'removed', 'a'),
405
('b-id', 'b', 'removed', 'b/'),
408
def test_status_missing_file(self):
409
this = self.make_branch_and_tree('this')
410
self.build_tree(['this/foo'])
411
this.add(['foo'], ['foo-id'])
414
other = this.bzrdir.sprout('other').open_workingtree()
416
os.remove('this/foo')
417
this.remove('foo', force=True)
418
this.commit('remove')
420
f = open('other/foo', 'wt')
422
f.write('Modified\n')
425
other.commit('modified')
427
this.merge_from_branch(other.branch)
428
conflicts.resolve(this)
430
self.assertStatusEqual(
431
[('foo-id', 'foo.OTHER', 'missing', 'foo.OTHER'),],
434
def test_status_missing_directory(self):
435
this = self.make_branch_and_tree('this')
436
self.build_tree(['this/foo/', 'this/foo/bar'])
437
this.add(['foo', 'foo/bar'], ['foo-id', 'bar-id'])
440
other = this.bzrdir.sprout('other').open_workingtree()
442
os.remove('this/foo/bar')
444
this.remove('foo', force=True)
445
this.commit('remove')
447
f = open('other/foo/bar', 'wt')
449
f.write('Modified\n')
452
other.commit('modified')
454
this.merge_from_branch(other.branch)
455
conflicts.resolve(this)
457
self.assertStatusEqual(
458
[('foo-id', u'foo', 'added', u'foo/'),
459
('bar-id', u'foo/bar.OTHER', 'missing', u'foo/bar.OTHER'),],