Imported Upstream version 3.21.91
[platform/upstream/python-gobject.git] / tests / test_overrides_gtk.py
1 # -*- Mode: Python; py-indent-offset: 4 -*-
2 # coding: UTF-8
3 # vim: tabstop=4 shiftwidth=4 expandtab
4
5 import contextlib
6 import unittest
7 import time
8 import sys
9 import warnings
10
11 from compathelper import _unicode, _bytes
12 from helper import ignore_gi_deprecation_warnings, capture_glib_warnings
13
14 import gi
15 import gi.overrides
16 import gi.types
17 from gi.repository import GLib, GObject
18
19 try:
20     gi.require_version('Gtk', '3.0')
21     gi.require_version('GdkPixbuf', '2.0')
22     from gi.repository import Gtk, GdkPixbuf, Gdk
23     Gtk  # pyflakes
24     PyGTKDeprecationWarning = Gtk.PyGTKDeprecationWarning
25 except (ValueError, ImportError):
26     Gtk = None
27     PyGTKDeprecationWarning = None
28
29
30 @contextlib.contextmanager
31 def realized(widget):
32     """Makes sure the widget is realized.
33
34     view = Gtk.TreeView()
35     with realized(view):
36         do_something(view)
37     """
38
39     if isinstance(widget, Gtk.Window):
40         toplevel = widget
41     else:
42         toplevel = widget.get_parent_window()
43
44     if toplevel is None:
45         window = Gtk.Window()
46         window.add(widget)
47
48     widget.realize()
49     while Gtk.events_pending():
50         Gtk.main_iteration()
51     assert widget.get_realized()
52     yield widget
53
54     if toplevel is None:
55         window.remove(widget)
56         window.destroy()
57
58     while Gtk.events_pending():
59         Gtk.main_iteration()
60
61
62 @unittest.skipUnless(Gtk, 'Gtk not available')
63 @ignore_gi_deprecation_warnings
64 class TestGtk(unittest.TestCase):
65     def test_container(self):
66         box = Gtk.Box()
67         self.assertTrue(isinstance(box, Gtk.Box))
68         self.assertTrue(isinstance(box, Gtk.Container))
69         self.assertTrue(isinstance(box, Gtk.Widget))
70         self.assertTrue(box)
71         label = Gtk.Label()
72         label2 = Gtk.Label()
73         box.add(label)
74         box.add(label2)
75         self.assertTrue(label in box)
76         self.assertTrue(label2 in box)
77         self.assertEqual(len(box), 2)
78         self.assertTrue(box)
79         l = [x for x in box]
80         self.assertEqual(l, [label, label2])
81
82     def test_actions(self):
83         self.assertEqual(Gtk.Action, gi.overrides.Gtk.Action)
84         action = Gtk.Action(name="test", label="Test", tooltip="Test Action", stock_id=Gtk.STOCK_COPY)
85         self.assertEqual(action.get_name(), "test")
86         self.assertEqual(action.get_label(), "Test")
87         self.assertEqual(action.get_tooltip(), "Test Action")
88         self.assertEqual(action.get_stock_id(), Gtk.STOCK_COPY)
89
90         self.assertEqual(Gtk.RadioAction, gi.overrides.Gtk.RadioAction)
91         action = Gtk.RadioAction(name="test", label="Test", tooltip="Test Action", stock_id=Gtk.STOCK_COPY, value=1)
92         self.assertEqual(action.get_name(), "test")
93         self.assertEqual(action.get_label(), "Test")
94         self.assertEqual(action.get_tooltip(), "Test Action")
95         self.assertEqual(action.get_stock_id(), Gtk.STOCK_COPY)
96         self.assertEqual(action.get_current_value(), 1)
97
98     def test_actiongroup(self):
99         self.assertEqual(Gtk.ActionGroup, gi.overrides.Gtk.ActionGroup)
100
101         action_group = Gtk.ActionGroup(name='TestActionGroup')
102         callback_data = "callback data"
103
104         def test_action_callback_data(action, user_data):
105             self.assertEqual(user_data, callback_data)
106
107         def test_radio_action_callback_data(action, current, user_data):
108             self.assertEqual(user_data, callback_data)
109
110         action_group.add_actions([
111             ('test-action1', None, 'Test Action 1',
112              None, None, test_action_callback_data),
113             ('test-action2', Gtk.STOCK_COPY, 'Test Action 2',
114              None, None, test_action_callback_data)], callback_data)
115         action_group.add_toggle_actions([
116             ('test-toggle-action1', None, 'Test Toggle Action 1',
117              None, None, test_action_callback_data, False),
118             ('test-toggle-action2', Gtk.STOCK_COPY, 'Test Toggle Action 2',
119              None, None, test_action_callback_data, True)], callback_data)
120         action_group.add_radio_actions([
121             ('test-radio-action1', None, 'Test Radio Action 1'),
122             ('test-radio-action2', Gtk.STOCK_COPY, 'Test Radio Action 2')], 1,
123             test_radio_action_callback_data,
124             callback_data)
125
126         expected_results = [('test-action1', Gtk.Action),
127                             ('test-action2', Gtk.Action),
128                             ('test-toggle-action1', Gtk.ToggleAction),
129                             ('test-toggle-action2', Gtk.ToggleAction),
130                             ('test-radio-action1', Gtk.RadioAction),
131                             ('test-radio-action2', Gtk.RadioAction)]
132
133         for action in action_group.list_actions():
134             a = (action.get_name(), type(action))
135             self.assertTrue(a in expected_results)
136             expected_results.remove(a)
137             action.activate()
138
139     def test_uimanager(self):
140         self.assertEqual(Gtk.UIManager, gi.overrides.Gtk.UIManager)
141         ui = Gtk.UIManager()
142         ui.add_ui_from_string("""<ui>
143     <menubar name="menubar1"></menubar>
144 </ui>
145 """
146 )
147         menubar = ui.get_widget("/menubar1")
148         self.assertEqual(type(menubar), Gtk.MenuBar)
149
150         ag = Gtk.ActionGroup(name="ag1")
151         ui.insert_action_group(ag)
152         ag2 = Gtk.ActionGroup(name="ag2")
153         ui.insert_action_group(ag2)
154         groups = ui.get_action_groups()
155         self.assertEqual(ag, groups[-2])
156         self.assertEqual(ag2, groups[-1])
157
158     def test_uimanager_nonascii(self):
159         ui = Gtk.UIManager()
160         ui.add_ui_from_string(b'<ui><menubar name="menub\xc3\xa6r1" /></ui>'.decode('UTF-8'))
161         mi = ui.get_widget("/menubær1")
162         self.assertEqual(type(mi), Gtk.MenuBar)
163
164     def test_window(self):
165         # standard Window
166         w = Gtk.Window()
167         self.assertEqual(w.get_property('type'), Gtk.WindowType.TOPLEVEL)
168
169         # type works as keyword argument
170         w = Gtk.Window(type=Gtk.WindowType.POPUP)
171         self.assertEqual(w.get_property('type'), Gtk.WindowType.POPUP)
172
173         class TestWindow(Gtk.Window):
174             __gtype_name__ = "TestWindow"
175
176         # works from builder
177         builder = Gtk.Builder()
178         builder.add_from_string('''
179 <interface>
180   <object class="GtkWindow" id="win">
181     <property name="type">popup</property>
182   </object>
183   <object class="TestWindow" id="testwin">
184   </object>
185   <object class="TestWindow" id="testpop">
186     <property name="type">popup</property>
187   </object>
188 </interface>''')
189         self.assertEqual(builder.get_object('win').get_property('type'),
190                          Gtk.WindowType.POPUP)
191         self.assertEqual(builder.get_object('testwin').get_property('type'),
192                          Gtk.WindowType.TOPLEVEL)
193         self.assertEqual(builder.get_object('testpop').get_property('type'),
194                          Gtk.WindowType.POPUP)
195
196     def test_dialog_classes(self):
197         self.assertEqual(Gtk.Dialog, gi.overrides.Gtk.Dialog)
198         self.assertEqual(Gtk.ColorSelectionDialog, gi.overrides.Gtk.ColorSelectionDialog)
199         self.assertEqual(Gtk.FileChooserDialog, gi.overrides.Gtk.FileChooserDialog)
200         self.assertEqual(Gtk.FontSelectionDialog, gi.overrides.Gtk.FontSelectionDialog)
201         self.assertEqual(Gtk.RecentChooserDialog, gi.overrides.Gtk.RecentChooserDialog)
202
203     def test_dialog_base(self):
204         dialog = Gtk.Dialog(title='Foo', modal=True)
205         self.assertTrue(isinstance(dialog, Gtk.Dialog))
206         self.assertTrue(isinstance(dialog, Gtk.Window))
207         self.assertEqual('Foo', dialog.get_title())
208         self.assertTrue(dialog.get_modal())
209
210     def test_dialog_deprecations(self):
211         with warnings.catch_warnings(record=True) as warn:
212             warnings.simplefilter('always')
213             dialog = Gtk.Dialog(title='Foo', flags=Gtk.DialogFlags.MODAL)
214             self.assertTrue(dialog.get_modal())
215             self.assertEqual(len(warn), 1)
216             self.assertTrue(issubclass(warn[0].category, PyGTKDeprecationWarning))
217             self.assertRegexpMatches(str(warn[0].message),
218                                      '.*flags.*modal.*')
219
220         with warnings.catch_warnings(record=True) as warn:
221             warnings.simplefilter('always')
222             dialog = Gtk.Dialog(title='Foo', flags=Gtk.DialogFlags.DESTROY_WITH_PARENT)
223             self.assertTrue(dialog.get_destroy_with_parent())
224             self.assertEqual(len(warn), 1)
225             self.assertTrue(issubclass(warn[0].category, PyGTKDeprecationWarning))
226             self.assertRegexpMatches(str(warn[0].message),
227                                      '.*flags.*destroy_with_parent.*')
228
229     def test_dialog_deprecation_stacklevels(self):
230         # Test warning levels are setup to give the correct filename for
231         # deprecations in different classes in the inheritance hierarchy.
232
233         # Base class
234         self.assertEqual(Gtk.Dialog, gi.overrides.Gtk.Dialog)
235         with warnings.catch_warnings(record=True) as warn:
236             warnings.simplefilter('always')
237             Gtk.Dialog(flags=Gtk.DialogFlags.MODAL)
238             self.assertEqual(len(warn), 1)
239             self.assertRegexpMatches(warn[0].filename, '.*test_overrides_gtk.*')
240
241         # Validate overridden base with overridden sub-class.
242         self.assertEqual(Gtk.MessageDialog, gi.overrides.Gtk.MessageDialog)
243         with warnings.catch_warnings(record=True) as warn:
244             warnings.simplefilter('always')
245             Gtk.MessageDialog(flags=Gtk.DialogFlags.MODAL)
246             self.assertEqual(len(warn), 1)
247             self.assertRegexpMatches(warn[0].filename, '.*test_overrides_gtk.*')
248
249         # Validate overridden base with non-overridden sub-class.
250         self.assertEqual(Gtk.AboutDialog, gi.repository.Gtk.AboutDialog)
251         with warnings.catch_warnings(record=True) as warn:
252             warnings.simplefilter('always')
253             Gtk.AboutDialog(flags=Gtk.DialogFlags.MODAL)
254             self.assertEqual(len(warn), 1)
255             self.assertRegexpMatches(warn[0].filename, '.*test_overrides_gtk.*')
256
257     def test_dialog_add_buttons(self):
258         # The overloaded "buttons" keyword gives a warning when attempting
259         # to use it for adding buttons as was available in PyGTK.
260         with warnings.catch_warnings(record=True) as warn:
261             warnings.simplefilter('always')
262             dialog = Gtk.Dialog(title='Foo', modal=True,
263                                 buttons=('test-button1', 1))
264             self.assertEqual(len(warn), 1)
265             self.assertTrue(issubclass(warn[0].category, PyGTKDeprecationWarning))
266             self.assertRegexpMatches(str(warn[0].message),
267                                      '.*ButtonsType.*add_buttons.*')
268
269         dialog.add_buttons('test-button2', 2, Gtk.STOCK_CLOSE, Gtk.ResponseType.CLOSE)
270         button = dialog.get_widget_for_response(1)
271         self.assertEqual('test-button1', button.get_label())
272         button = dialog.get_widget_for_response(2)
273         self.assertEqual('test-button2', button.get_label())
274         button = dialog.get_widget_for_response(Gtk.ResponseType.CLOSE)
275         self.assertEqual(Gtk.STOCK_CLOSE, button.get_label())
276
277     def test_about_dialog(self):
278         dialog = Gtk.AboutDialog()
279         self.assertTrue(isinstance(dialog, Gtk.Dialog))
280         self.assertTrue(isinstance(dialog, Gtk.Window))
281
282         # AboutDialog is not sub-classed in overrides, make sure
283         # the mro still injects the base class "add_buttons" override.
284         self.assertTrue(hasattr(dialog, 'add_buttons'))
285
286     def test_message_dialog(self):
287         dialog = Gtk.MessageDialog(title='message dialog test',
288                                    modal=True,
289                                    buttons=Gtk.ButtonsType.OK,
290                                    text='dude!')
291         self.assertTrue(isinstance(dialog, Gtk.Dialog))
292         self.assertTrue(isinstance(dialog, Gtk.Window))
293
294         self.assertEqual('message dialog test', dialog.get_title())
295         self.assertTrue(dialog.get_modal())
296         text = dialog.get_property('text')
297         self.assertEqual('dude!', text)
298
299         dialog.format_secondary_text('2nd text')
300         self.assertEqual(dialog.get_property('secondary-text'), '2nd text')
301         self.assertFalse(dialog.get_property('secondary-use-markup'))
302
303         dialog.format_secondary_markup('2nd markup')
304         self.assertEqual(dialog.get_property('secondary-text'), '2nd markup')
305         self.assertTrue(dialog.get_property('secondary-use-markup'))
306
307     def test_color_selection_dialog(self):
308         dialog = Gtk.ColorSelectionDialog(title="color selection dialog test")
309         self.assertTrue(isinstance(dialog, Gtk.Dialog))
310         self.assertTrue(isinstance(dialog, Gtk.Window))
311         self.assertEqual('color selection dialog test', dialog.get_title())
312
313     def test_file_chooser_dialog(self):
314         # might cause a GVFS warning, do not break on this
315         with capture_glib_warnings(allow_warnings=True):
316             dialog = Gtk.FileChooserDialog(title='file chooser dialog test',
317                                            action=Gtk.FileChooserAction.SAVE)
318
319         self.assertTrue(isinstance(dialog, Gtk.Dialog))
320         self.assertTrue(isinstance(dialog, Gtk.Window))
321         self.assertEqual('file chooser dialog test', dialog.get_title())
322
323         action = dialog.get_property('action')
324         self.assertEqual(Gtk.FileChooserAction.SAVE, action)
325
326     def test_file_chooser_dialog_default_action(self):
327         # might cause a GVFS warning, do not break on this
328         with capture_glib_warnings(allow_warnings=True):
329             dialog = Gtk.FileChooserDialog(title='file chooser dialog test')
330
331         action = dialog.get_property('action')
332         self.assertEqual(Gtk.FileChooserAction.OPEN, action)
333
334     def test_font_selection_dialog(self):
335         dialog = Gtk.FontSelectionDialog(title="font selection dialog test")
336         self.assertTrue(isinstance(dialog, Gtk.Dialog))
337         self.assertTrue(isinstance(dialog, Gtk.Window))
338         self.assertEqual('font selection dialog test', dialog.get_title())
339
340     def test_recent_chooser_dialog(self):
341         test_manager = Gtk.RecentManager()
342         dialog = Gtk.RecentChooserDialog(title='recent chooser dialog test',
343                                          recent_manager=test_manager)
344         self.assertTrue(isinstance(dialog, Gtk.Dialog))
345         self.assertTrue(isinstance(dialog, Gtk.Window))
346         self.assertEqual('recent chooser dialog test', dialog.get_title())
347
348     class TestClass(GObject.GObject):
349         __gtype_name__ = "GIOverrideTreeAPITest"
350
351         def __init__(self, tester, int_value, string_value):
352             super(TestGtk.TestClass, self).__init__()
353             self.tester = tester
354             self.int_value = int_value
355             self.string_value = string_value
356
357         def check(self, int_value, string_value):
358             self.tester.assertEqual(int_value, self.int_value)
359             self.tester.assertEqual(string_value, self.string_value)
360
361     def test_buttons(self):
362         self.assertEqual(Gtk.Button, gi.overrides.Gtk.Button)
363
364         # test Gtk.Button
365         button = Gtk.Button()
366         self.assertTrue(isinstance(button, Gtk.Button))
367         self.assertTrue(isinstance(button, Gtk.Container))
368         self.assertTrue(isinstance(button, Gtk.Widget))
369
370         # Using stock items causes hard warning in devel versions of GTK+.
371         with capture_glib_warnings(allow_warnings=True):
372             button = Gtk.Button.new_from_stock(Gtk.STOCK_CLOSE)
373
374         self.assertEqual(Gtk.STOCK_CLOSE, button.get_label())
375         self.assertTrue(button.get_use_stock())
376         self.assertTrue(button.get_use_underline())
377
378         # test Gtk.Button use_stock
379         button = Gtk.Button(label=Gtk.STOCK_CLOSE, use_stock=True, use_underline=True)
380         self.assertEqual(Gtk.STOCK_CLOSE, button.get_label())
381         self.assertTrue(button.get_use_stock())
382         self.assertTrue(button.get_use_underline())
383
384         # test Gtk.LinkButton
385         button = Gtk.LinkButton(uri='http://www.Gtk.org', label='Gtk')
386         self.assertTrue(isinstance(button, Gtk.Button))
387         self.assertTrue(isinstance(button, Gtk.Container))
388         self.assertTrue(isinstance(button, Gtk.Widget))
389         self.assertEqual('http://www.Gtk.org', button.get_uri())
390         self.assertEqual('Gtk', button.get_label())
391
392     def test_inheritance(self):
393         for name in gi.overrides.Gtk.__all__:
394             over = getattr(gi.overrides.Gtk, name)
395             for element in dir(Gtk):
396                 try:
397                     klass = getattr(Gtk, element)
398                     info = klass.__info__
399                 except (NotImplementedError, AttributeError):
400                     continue
401
402                 # Get all parent classes and interfaces klass inherits from
403                 if isinstance(info, gi.types.ObjectInfo):
404                     classes = list(info.get_interfaces())
405                     parent = info.get_parent()
406                     while parent.get_name() != "Object":
407                         classes.append(parent)
408                         parent = parent.get_parent()
409                     classes = [kl for kl in classes if kl.get_namespace() == "Gtk"]
410                 else:
411                     continue
412
413                 for kl in classes:
414                     if kl.get_name() == name:
415                         self.assertTrue(issubclass(klass, over,),
416                                         "%r does not inherit from override %r" % (klass, over,))
417
418     def test_editable(self):
419         self.assertEqual(Gtk.Editable, gi.overrides.Gtk.Editable)
420
421         # need to use Gtk.Entry because Editable is an interface
422         entry = Gtk.Entry()
423         pos = entry.insert_text('HeWorld', 0)
424         self.assertEqual(pos, 7)
425         pos = entry.insert_text('llo ', 2)
426         self.assertEqual(pos, 6)
427         text = entry.get_chars(0, 11)
428         self.assertEqual('Hello World', text)
429
430     def test_label(self):
431         label = Gtk.Label(label='Hello')
432         self.assertTrue(isinstance(label, Gtk.Widget))
433         self.assertEqual(label.get_text(), 'Hello')
434
435     def adjustment_check(self, adjustment, value=0.0, lower=0.0, upper=0.0,
436                          step_increment=0.0, page_increment=0.0, page_size=0.0):
437         self.assertEqual(adjustment.get_value(), value)
438         self.assertEqual(adjustment.get_lower(), lower)
439         self.assertEqual(adjustment.get_upper(), upper)
440         self.assertEqual(adjustment.get_step_increment(), step_increment)
441         self.assertEqual(adjustment.get_page_increment(), page_increment)
442         self.assertEqual(adjustment.get_page_size(), page_size)
443
444     def test_adjustment(self):
445         adjustment = Gtk.Adjustment(value=1, lower=0, upper=6, step_increment=4, page_increment=5, page_size=3)
446         self.adjustment_check(adjustment, value=1, lower=0, upper=6, step_increment=4, page_increment=5, page_size=3)
447
448         adjustment = Gtk.Adjustment(value=1, lower=0, upper=6, step_increment=4, page_increment=5)
449         self.adjustment_check(adjustment, value=1, lower=0, upper=6, step_increment=4, page_increment=5)
450
451         adjustment = Gtk.Adjustment(value=1, lower=0, upper=6, step_increment=4)
452         self.adjustment_check(adjustment, value=1, lower=0, upper=6, step_increment=4)
453
454         adjustment = Gtk.Adjustment(value=1, lower=0, upper=6)
455         self.adjustment_check(adjustment, value=1, lower=0, upper=6)
456
457         adjustment = Gtk.Adjustment()
458         self.adjustment_check(adjustment)
459
460     def test_table(self):
461         table = Gtk.Table()
462         self.assertTrue(isinstance(table, Gtk.Table))
463         self.assertTrue(isinstance(table, Gtk.Container))
464         self.assertTrue(isinstance(table, Gtk.Widget))
465         self.assertEqual(table.get_size(), (1, 1))
466         self.assertEqual(table.get_homogeneous(), False)
467
468         table = Gtk.Table(n_rows=2, n_columns=3)
469         self.assertEqual(table.get_size(), (2, 3))
470         self.assertEqual(table.get_homogeneous(), False)
471
472         table = Gtk.Table(n_rows=2, n_columns=3, homogeneous=True)
473         self.assertEqual(table.get_size(), (2, 3))
474         self.assertEqual(table.get_homogeneous(), True)
475
476         label = Gtk.Label(label='Hello')
477         self.assertTrue(isinstance(label, Gtk.Widget))
478         table.attach(label, 0, 1, 0, 1)
479         self.assertEqual(label, table.get_children()[0])
480
481     def test_scrolledwindow(self):
482         sw = Gtk.ScrolledWindow()
483         self.assertTrue(isinstance(sw, Gtk.ScrolledWindow))
484         self.assertTrue(isinstance(sw, Gtk.Container))
485         self.assertTrue(isinstance(sw, Gtk.Widget))
486         sb = sw.get_hscrollbar()
487         self.assertEqual(sw.get_hadjustment(), sb.get_adjustment())
488         sb = sw.get_vscrollbar()
489         self.assertEqual(sw.get_vadjustment(), sb.get_adjustment())
490
491     def test_widget_drag_methods(self):
492         widget = Gtk.Button()
493
494         # here we are not checking functionality, only that the methods exist
495         # and except the right number of arguments
496
497         widget.drag_check_threshold(0, 0, 0, 0)
498
499         # drag_dest_ methods
500         widget.drag_dest_set(Gtk.DestDefaults.DROP, None, Gdk.DragAction.COPY)
501         widget.drag_dest_add_image_targets()
502         widget.drag_dest_add_text_targets()
503         widget.drag_dest_add_uri_targets()
504         widget.drag_dest_get_track_motion()
505         widget.drag_dest_set_track_motion(True)
506         widget.drag_dest_get_target_list()
507         widget.drag_dest_set_target_list(None)
508         widget.drag_dest_set_target_list(Gtk.TargetList.new([Gtk.TargetEntry.new('test', 0, 0)]))
509         widget.drag_dest_unset()
510
511         widget.drag_highlight()
512         widget.drag_unhighlight()
513
514         # drag_source_ methods
515         widget.drag_source_set(Gdk.ModifierType.BUTTON1_MASK, None, Gdk.DragAction.MOVE)
516         widget.drag_source_add_image_targets()
517         widget.drag_source_add_text_targets()
518         widget.drag_source_add_uri_targets()
519         widget.drag_source_set_icon_name("_About")
520         widget.drag_source_set_icon_pixbuf(GdkPixbuf.Pixbuf())
521         widget.drag_source_set_icon_stock(Gtk.STOCK_ABOUT)
522         widget.drag_source_get_target_list()
523         widget.drag_source_set_target_list(None)
524         widget.drag_source_set_target_list(Gtk.TargetList.new([Gtk.TargetEntry.new('test', 0, 0)]))
525         widget.drag_source_unset()
526
527         # these methods cannot be called because they require a valid drag on
528         # a real GdkWindow. So we only check that they exist and are callable.
529         self.assertTrue(hasattr(widget, 'drag_dest_set_proxy'))
530         self.assertTrue(hasattr(widget, 'drag_get_data'))
531
532     def test_drag_target_list(self):
533         mixed_target_list = [Gtk.TargetEntry.new('test0', 0, 0),
534                              ('test1', 1, 1),
535                              Gtk.TargetEntry.new('test2', 2, 2),
536                              ('test3', 3, 3)]
537
538         def _test_target_list(targets):
539             for i, target in enumerate(targets):
540                 self.assertTrue(isinstance(target, Gtk.TargetEntry))
541                 self.assertEqual(target.target, 'test' + str(i))
542                 self.assertEqual(target.flags, i)
543                 self.assertEqual(target.info, i)
544
545         _test_target_list(Gtk._construct_target_list(mixed_target_list))
546
547         widget = Gtk.Button()
548         widget.drag_dest_set(Gtk.DestDefaults.DROP, None, Gdk.DragAction.COPY)
549         widget.drag_dest_set_target_list(mixed_target_list)
550         widget.drag_dest_get_target_list()
551
552         widget.drag_source_set(Gdk.ModifierType.BUTTON1_MASK, None, Gdk.DragAction.MOVE)
553         widget.drag_source_set_target_list(mixed_target_list)
554         widget.drag_source_get_target_list()
555
556         treeview = Gtk.TreeView()
557         treeview.enable_model_drag_source(Gdk.ModifierType.BUTTON1_MASK,
558                                           mixed_target_list,
559                                           Gdk.DragAction.DEFAULT | Gdk.DragAction.MOVE)
560
561         treeview.enable_model_drag_dest(mixed_target_list,
562                                         Gdk.DragAction.DEFAULT | Gdk.DragAction.MOVE)
563
564     def test_scrollbar(self):
565         adjustment = Gtk.Adjustment()
566
567         hscrollbar = Gtk.HScrollbar()
568         vscrollbar = Gtk.VScrollbar()
569         self.assertNotEqual(hscrollbar.props.adjustment, adjustment)
570         self.assertNotEqual(vscrollbar.props.adjustment, adjustment)
571
572         hscrollbar = Gtk.HScrollbar(adjustment=adjustment)
573         vscrollbar = Gtk.VScrollbar(adjustment=adjustment)
574         self.assertEqual(hscrollbar.props.adjustment, adjustment)
575         self.assertEqual(vscrollbar.props.adjustment, adjustment)
576
577     def test_iconview(self):
578         # PyGTK compat
579         iconview = Gtk.IconView()
580         self.assertEqual(iconview.props.model, None)
581
582         model = Gtk.ListStore(str)
583         iconview = Gtk.IconView(model=model)
584         self.assertEqual(iconview.props.model, model)
585
586     def test_toolbutton(self):
587         # PyGTK compat
588
589         # Using stock items causes hard warning in devel versions of GTK+.
590         with capture_glib_warnings(allow_warnings=True):
591             button = Gtk.ToolButton()
592             self.assertEqual(button.props.stock_id, None)
593
594             button = Gtk.ToolButton(stock_id='gtk-new')
595             self.assertEqual(button.props.stock_id, 'gtk-new')
596
597         icon = Gtk.Image.new_from_stock(Gtk.STOCK_OPEN, Gtk.IconSize.SMALL_TOOLBAR)
598         button = Gtk.ToolButton(label='mylabel', icon_widget=icon)
599         self.assertEqual(button.props.label, 'mylabel')
600         self.assertEqual(button.props.icon_widget, icon)
601
602     def test_iconset(self):
603         Gtk.IconSet()
604         pixbuf = GdkPixbuf.Pixbuf()
605         Gtk.IconSet.new_from_pixbuf(pixbuf)
606
607     def test_viewport(self):
608         vadjustment = Gtk.Adjustment()
609         hadjustment = Gtk.Adjustment()
610
611         viewport = Gtk.Viewport(hadjustment=hadjustment,
612                                 vadjustment=vadjustment)
613
614         self.assertEqual(viewport.props.vadjustment, vadjustment)
615         self.assertEqual(viewport.props.hadjustment, hadjustment)
616
617     def test_stock_lookup(self):
618         l = Gtk.stock_lookup('gtk-ok')
619         self.assertEqual(type(l), Gtk.StockItem)
620         self.assertEqual(l.stock_id, 'gtk-ok')
621         self.assertEqual(Gtk.stock_lookup('nosuchthing'), None)
622
623     def test_gtk_main(self):
624         # with no arguments
625         GLib.timeout_add(100, Gtk.main_quit)
626         Gtk.main()
627
628         # overridden function ignores its arguments
629         GLib.timeout_add(100, Gtk.main_quit, 'hello')
630         Gtk.main()
631
632     def test_widget_render_icon(self):
633         button = Gtk.Button(label='OK')
634         pixbuf = button.render_icon(Gtk.STOCK_OK, Gtk.IconSize.BUTTON)
635         self.assertTrue(pixbuf is not None)
636
637
638 @unittest.skipUnless(Gtk, 'Gtk not available')
639 class TestWidget(unittest.TestCase):
640     def test_style_get_property_gvalue(self):
641         button = Gtk.Button()
642         value = GObject.Value(int, -42)
643         button.style_get_property('focus-padding', value)
644         # Test only that the style property changed since we can't actuall
645         # set it.
646         self.assertNotEqual(value.get_int(), -42)
647
648     def test_style_get_property_return_with_explicit_gvalue(self):
649         button = Gtk.Button()
650         value = GObject.Value(int, -42)
651         result = button.style_get_property('focus-padding', value)
652         self.assertIsInstance(result, int)
653         self.assertNotEqual(result, -42)
654
655     def test_style_get_property_return_with_implicit_gvalue(self):
656         button = Gtk.Button()
657         result = button.style_get_property('focus-padding')
658         self.assertIsInstance(result, int)
659         self.assertNotEqual(result, -42)
660
661     def test_style_get_property_error(self):
662         button = Gtk.Button()
663         with self.assertRaises(ValueError):
664             button.style_get_property('not-a-valid-style-property')
665
666
667 @unittest.skipUnless(Gtk, 'Gtk not available')
668 class TestSignals(unittest.TestCase):
669     def test_class_closure_override_with_aliased_type(self):
670         class WindowWithSizeAllocOverride(Gtk.ScrolledWindow):
671             __gsignals__ = {'size-allocate': 'override'}
672
673             def __init__(self):
674                 Gtk.ScrolledWindow.__init__(self)
675                 self._alloc_called = False
676                 self._alloc_value = None
677                 self._alloc_error = None
678
679             def do_size_allocate(self, alloc):
680                 self._alloc_called = True
681                 self._alloc_value = alloc
682
683                 try:
684                     Gtk.ScrolledWindow.do_size_allocate(self, alloc)
685                 except Exception as e:
686                     self._alloc_error = e
687
688         win = WindowWithSizeAllocOverride()
689         rect = Gdk.Rectangle()
690         rect.width = 100
691         rect.height = 100
692
693         with realized(win):
694             win.show()
695             win.get_preferred_size()
696             win.size_allocate(rect)
697             self.assertTrue(win._alloc_called)
698             self.assertIsInstance(win._alloc_value, Gdk.Rectangle)
699             self.assertTrue(win._alloc_error is None, win._alloc_error)
700
701     @unittest.expectedFailure  # https://bugzilla.gnome.org/show_bug.cgi?id=735693
702     def test_overlay_child_position(self):
703         def get_child_position(overlay, widget, rect, user_data=None):
704             rect.x = 1
705             rect.y = 2
706             rect.width = 3
707             rect.height = 4
708             return True
709
710         overlay = Gtk.Overlay()
711         overlay.connect('get-child-position', get_child_position)
712
713         rect = Gdk.Rectangle()
714         rect.x = -1
715         rect.y = -1
716         rect.width = -1
717         rect.height = -1
718
719         overlay.emit('get-child-position', None, rect)
720         self.assertEqual(rect.x, 1)
721         self.assertEqual(rect.y, 2)
722         self.assertEqual(rect.width, 3)
723         self.assertEqual(rect.height, 4)
724
725
726 @unittest.skipUnless(Gtk, 'Gtk not available')
727 class TestBuilder(unittest.TestCase):
728     class SignalTest(GObject.GObject):
729         __gtype_name__ = "GIOverrideSignalTest"
730         __gsignals__ = {
731             "test-signal": (GObject.SignalFlags.RUN_FIRST,
732                             None,
733                             []),
734         }
735
736     def test_extract_handler_and_args_object(self):
737         class Obj():
738             pass
739
740         obj = Obj()
741         obj.foo = lambda: None
742
743         handler, args = Gtk._extract_handler_and_args(obj, 'foo')
744         self.assertEqual(handler, obj.foo)
745         self.assertEqual(len(args), 0)
746
747     def test_extract_handler_and_args_dict(self):
748         obj = {'foo': lambda: None}
749
750         handler, args = Gtk._extract_handler_and_args(obj, 'foo')
751         self.assertEqual(handler, obj['foo'])
752         self.assertEqual(len(args), 0)
753
754     def test_extract_handler_and_args_with_seq(self):
755         obj = {'foo': (lambda: None, 1, 2)}
756
757         handler, args = Gtk._extract_handler_and_args(obj, 'foo')
758         self.assertEqual(handler, obj['foo'][0])
759         self.assertSequenceEqual(args, [1, 2])
760
761     def test_extract_handler_and_args_no_handler_error(self):
762         obj = dict(foo=lambda: None)
763         self.assertRaises(AttributeError,
764                           Gtk._extract_handler_and_args,
765                           obj, 'not_a_handler')
766
767     def test_builder_with_handler_and_args(self):
768         builder = Gtk.Builder()
769         builder.add_from_string("""
770             <interface>
771               <object class="GIOverrideSignalTest" id="object_sig_test">
772                   <signal name="test-signal" handler="on_signal1" />
773                   <signal name="test-signal" handler="on_signal2" after="yes" />
774               </object>
775             </interface>
776             """)
777
778         args_collector = []
779
780         def on_signal(*args):
781             args_collector.append(args)
782
783         builder.connect_signals({'on_signal1': (on_signal, 1, 2),
784                                  'on_signal2': on_signal})
785
786         objects = builder.get_objects()
787         self.assertEqual(len(objects), 1)
788         obj, = objects
789         obj.emit('test-signal')
790
791         self.assertEqual(len(args_collector), 2)
792         self.assertSequenceEqual(args_collector[0], (obj, 1, 2))
793         self.assertSequenceEqual(args_collector[1], (obj, ))
794
795     def test_builder(self):
796         self.assertEqual(Gtk.Builder, gi.overrides.Gtk.Builder)
797
798         class SignalCheck:
799             def __init__(self):
800                 self.sentinel = 0
801                 self.after_sentinel = 0
802
803             def on_signal_1(self, *args):
804                 self.sentinel += 1
805                 self.after_sentinel += 1
806
807             def on_signal_3(self, *args):
808                 self.sentinel += 3
809
810             def on_signal_after(self, *args):
811                 if self.after_sentinel == 1:
812                     self.after_sentinel += 1
813
814         signal_checker = SignalCheck()
815         builder = Gtk.Builder()
816
817         # add object1 to the builder
818         builder.add_from_string("""
819 <interface>
820   <object class="GIOverrideSignalTest" id="object1">
821       <signal name="test-signal" after="yes" handler="on_signal_after" />
822       <signal name="test-signal" handler="on_signal_1" />
823   </object>
824 </interface>
825 """)
826
827         # only add object3 to the builder
828         builder.add_objects_from_string("""
829 <interface>
830   <object class="GIOverrideSignalTest" id="object2">
831       <signal name="test-signal" handler="on_signal_2" />
832   </object>
833   <object class="GIOverrideSignalTest" id="object3">
834       <signal name="test-signal" handler="on_signal_3" />
835   </object>
836   <object class="GIOverrideSignalTest" id="object4">
837       <signal name="test-signal" handler="on_signal_4" />
838   </object>
839 </interface>
840 """, ['object3'])
841
842         # hook up signals
843         builder.connect_signals(signal_checker)
844
845         # call their notify signals and check sentinel
846         objects = builder.get_objects()
847         self.assertEqual(len(objects), 2)
848         for obj in objects:
849             obj.emit('test-signal')
850
851         self.assertEqual(signal_checker.sentinel, 4)
852         self.assertEqual(signal_checker.after_sentinel, 2)
853
854
855 @ignore_gi_deprecation_warnings
856 @unittest.skipUnless(Gtk, 'Gtk not available')
857 class TestTreeModel(unittest.TestCase):
858     def test_tree_model_sort(self):
859         self.assertEqual(Gtk.TreeModelSort, gi.overrides.Gtk.TreeModelSort)
860         model = Gtk.TreeStore(int, bool)
861         model_sort = Gtk.TreeModelSort(model=model)
862         self.assertEqual(model_sort.get_model(), model)
863
864     def test_tree_store(self):
865         self.assertEqual(Gtk.TreeStore, gi.overrides.Gtk.TreeStore)
866         self.assertEqual(Gtk.ListStore, gi.overrides.Gtk.ListStore)
867         self.assertEqual(Gtk.TreeModel, gi.overrides.Gtk.TreeModel)
868         self.assertEqual(Gtk.TreeViewColumn, gi.overrides.Gtk.TreeViewColumn)
869
870         class TestPyObject(object):
871             pass
872
873         test_pyobj = TestPyObject()
874         test_pydict = {1: 1, "2": 2, "3": "3"}
875         test_pylist = [1, "2", "3"]
876         tree_store = Gtk.TreeStore(int,
877                                    'gchararray',
878                                    TestGtk.TestClass,
879                                    GObject.TYPE_PYOBJECT,
880                                    object,
881                                    object,
882                                    object,
883                                    bool,
884                                    bool,
885                                    GObject.TYPE_UINT,
886                                    GObject.TYPE_ULONG,
887                                    GObject.TYPE_INT64,
888                                    GObject.TYPE_UINT64,
889                                    GObject.TYPE_UCHAR,
890                                    GObject.TYPE_CHAR)
891
892         parent = None
893         for i in range(97):
894             label = 'this is child #%d' % i
895             testobj = TestGtk.TestClass(self, i, label)
896             parent = tree_store.append(parent, (i,
897                                                 label,
898                                                 testobj,
899                                                 testobj,
900                                                 test_pyobj,
901                                                 test_pydict,
902                                                 test_pylist,
903                                                 i % 2,
904                                                 bool(i % 2),
905                                                 i,
906                                                 GLib.MAXULONG,
907                                                 GLib.MININT64,
908                                                 0xffffffffffffffff,
909                                                 254,
910                                                 _bytes('a')
911                                                 ))
912         # test set
913         parent = tree_store.append(parent)
914         i = 97
915         label = 'this is child #%d' % i
916         testobj = TestGtk.TestClass(self, i, label)
917         tree_store.set(parent,
918                        0, i,
919                        2, testobj,
920                        1, label,
921                        3, testobj,
922                        4, test_pyobj,
923                        5, test_pydict,
924                        6, test_pylist,
925                        7, i % 2,
926                        8, bool(i % 2),
927                        9, i,
928                        10, GLib.MAXULONG,
929                        11, GLib.MININT64,
930                        12, 0xffffffffffffffff,
931                        13, 254,
932                        14, _bytes('a'))
933
934         parent = tree_store.append(parent)
935         i = 98
936         label = 'this is child #%d' % i
937         testobj = TestGtk.TestClass(self, i, label)
938         tree_store.set(parent, {0: i,
939                                 2: testobj,
940                                 1: label,
941                                 3: testobj,
942                                 4: test_pyobj,
943                                 5: test_pydict,
944                                 6: test_pylist,
945                                 7: i % 2,
946                                 8: bool(i % 2),
947                                 9: i,
948                                 10: GLib.MAXULONG,
949                                 11: GLib.MININT64,
950                                 12: 0xffffffffffffffff,
951                                 13: 254,
952                                 14: _bytes('a')})
953
954         parent = tree_store.append(parent)
955         i = 99
956         label = 'this is child #%d' % i
957         testobj = TestGtk.TestClass(self, i, label)
958         tree_store.set(parent, (0, 2, 1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14),
959                                (i,
960                                 testobj,
961                                 label,
962                                 testobj,
963                                 test_pyobj,
964                                 test_pydict,
965                                 test_pylist,
966                                 i % 2,
967                                 bool(i % 2),
968                                 i,
969                                 GLib.MAXULONG,
970                                 GLib.MININT64,
971                                 0xffffffffffffffff,
972                                 254,
973                                 _bytes('a')))
974
975         # len gets the number of children in the root node
976         # since we kept appending to the previous node
977         # there should only be one child of the root
978         self.assertEqual(len(tree_store), 1)
979
980         # walk the tree to see if the values were stored correctly
981         parent = None
982         i = 0
983
984         treeiter = tree_store.iter_children(parent)
985         while treeiter:
986             i = tree_store.get_value(treeiter, 0)
987             s = tree_store.get_value(treeiter, 1)
988             obj = tree_store.get_value(treeiter, 2)
989             obj.check(i, s)
990             obj2 = tree_store.get_value(treeiter, 3)
991             self.assertEqual(obj, obj2)
992
993             pyobj = tree_store.get_value(treeiter, 4)
994             self.assertEqual(pyobj, test_pyobj)
995             pydict = tree_store.get_value(treeiter, 5)
996             self.assertEqual(pydict, test_pydict)
997             pylist = tree_store.get_value(treeiter, 6)
998             self.assertEqual(pylist, test_pylist)
999
1000             bool_1 = tree_store.get_value(treeiter, 7)
1001             bool_2 = tree_store.get_value(treeiter, 8)
1002             self.assertEqual(bool_1, bool_2)
1003             self.assertTrue(isinstance(bool_1, bool))
1004             self.assertTrue(isinstance(bool_2, bool))
1005
1006             uint_ = tree_store.get_value(treeiter, 9)
1007             self.assertEqual(uint_, i)
1008             ulong_ = tree_store.get_value(treeiter, 10)
1009             self.assertEqual(ulong_, GLib.MAXULONG)
1010             int64_ = tree_store.get_value(treeiter, 11)
1011             self.assertEqual(int64_, GLib.MININT64)
1012             uint64_ = tree_store.get_value(treeiter, 12)
1013             self.assertEqual(uint64_, 0xffffffffffffffff)
1014             uchar_ = tree_store.get_value(treeiter, 13)
1015             self.assertEqual(ord(uchar_), 254)
1016             char_ = tree_store.get_value(treeiter, 14)
1017             self.assertEqual(char_, 'a')
1018
1019             parent = treeiter
1020             treeiter = tree_store.iter_children(parent)
1021
1022         self.assertEqual(i, 99)
1023
1024     def test_tree_store_signals(self):
1025         tree_store = Gtk.TreeStore(int, bool)
1026
1027         def on_row_inserted(tree_store, tree_path, tree_iter, signal_list):
1028             signal_list.append('row-inserted')
1029
1030         def on_row_changed(tree_store, tree_path, tree_iter, signal_list):
1031             signal_list.append('row-changed')
1032
1033         signals = []
1034         tree_store.connect('row-inserted', on_row_inserted, signals)
1035         tree_store.connect('row-changed', on_row_changed, signals)
1036
1037         # adding rows with and without data should only call one signal
1038         tree_store.append(None, (0, False))
1039         self.assertEqual(signals, ['row-inserted'])
1040
1041         signals.pop()
1042         tree_store.append(None)
1043         self.assertEqual(signals, ['row-inserted'])
1044
1045         signals.pop()
1046         tree_store.prepend(None, (0, False))
1047         self.assertEqual(signals, ['row-inserted'])
1048
1049         signals.pop()
1050         tree_store.prepend(None)
1051         self.assertEqual(signals, ['row-inserted'])
1052
1053         signals.pop()
1054         tree_store.insert(None, 1, (0, False))
1055         self.assertEqual(signals, ['row-inserted'])
1056
1057         signals.pop()
1058         tree_store.insert(None, 1)
1059         self.assertEqual(signals, ['row-inserted'])
1060
1061     def test_list_store(self):
1062         class TestPyObject(object):
1063             pass
1064
1065         test_pyobj = TestPyObject()
1066         test_pydict = {1: 1, "2": 2, "3": "3"}
1067         test_pylist = [1, "2", "3"]
1068
1069         list_store = Gtk.ListStore(int, str, 'GIOverrideTreeAPITest', object, object, object, bool, bool)
1070         for i in range(1, 93):
1071             label = 'this is row #%d' % i
1072             testobj = TestGtk.TestClass(self, i, label)
1073             list_store.append((i,
1074                                label,
1075                                testobj,
1076                                test_pyobj,
1077                                test_pydict,
1078                                test_pylist,
1079                                i % 2,
1080                                bool(i % 2)))
1081
1082         i = 93
1083         label = _unicode('this is row #93')
1084         treeiter = list_store.append()
1085         list_store.set_value(treeiter, 0, i)
1086         list_store.set_value(treeiter, 1, label)
1087         list_store.set_value(treeiter, 2, TestGtk.TestClass(self, i, label))
1088         list_store.set_value(treeiter, 3, test_pyobj)
1089         list_store.set_value(treeiter, 4, test_pydict)
1090         list_store.set_value(treeiter, 5, test_pylist)
1091         list_store.set_value(treeiter, 6, 1)
1092         list_store.set_value(treeiter, 7, True)
1093
1094         # test prepend
1095         label = 'this is row #0'
1096         list_store.prepend((0,
1097                             label,
1098                             TestGtk.TestClass(self, 0, label),
1099                             test_pyobj,
1100                             test_pydict,
1101                             test_pylist,
1102                             0,
1103                             False))
1104
1105         # test automatic unicode->str conversion
1106         i = 94
1107         label = _unicode('this is row #94')
1108         treeiter = list_store.append((i,
1109                                       label,
1110                                       TestGtk.TestClass(self, i, label),
1111                                       test_pyobj,
1112                                       test_pydict,
1113                                       test_pylist,
1114                                       0,
1115                                       False))
1116
1117         # add sorted items out of order to test insert* apis
1118         # also test sending in None to not set a column
1119         i = 97
1120         label = 'this is row #97'
1121         treeiter = list_store.append((None,
1122                                       None,
1123                                       None,
1124                                       test_pyobj,
1125                                       None,
1126                                       test_pylist,
1127                                       1,
1128                                       None))
1129
1130         list_store.set_value(treeiter, 0, i)
1131         list_store.set_value(treeiter, 1, label)
1132         list_store.set_value(treeiter, 2, TestGtk.TestClass(self, i, label))
1133         list_store.set_value(treeiter, 4, test_pydict)
1134         list_store.set_value(treeiter, 7, True)
1135
1136         # this should append
1137         i = 99
1138         label = 'this is row #99'
1139         list_store.insert(9999, (i,
1140                                  label,
1141                                  TestGtk.TestClass(self, i, label),
1142                                  test_pyobj,
1143                                  test_pydict,
1144                                  test_pylist,
1145                                  1,
1146                                  True))
1147
1148         i = 96
1149         label = 'this is row #96'
1150         list_store.insert_before(treeiter, (i,
1151                                             label,
1152                                             TestGtk.TestClass(self, i, label),
1153                                             test_pyobj,
1154                                             test_pydict,
1155                                             test_pylist,
1156                                             0,
1157                                             False))
1158
1159         i = 98
1160         label = 'this is row #98'
1161         list_store.insert_after(treeiter, (i,
1162                                            label,
1163                                            TestGtk.TestClass(self, i, label),
1164                                            test_pyobj,
1165                                            test_pydict,
1166                                            test_pylist,
1167                                            0,
1168                                            False))
1169
1170         i = 95
1171         label = 'this is row #95'
1172         list_store.insert(95, (i,
1173                                label,
1174                                TestGtk.TestClass(self, i, label),
1175                                test_pyobj,
1176                                test_pydict,
1177                                test_pylist,
1178                                1,
1179                                True))
1180
1181         i = 100
1182         label = 'this is row #100'
1183         treeiter = list_store.append()
1184         list_store.set(treeiter,
1185                        1, label,
1186                        0, i,
1187                        2, TestGtk.TestClass(self, i, label),
1188                        3, test_pyobj,
1189                        4, test_pydict,
1190                        5, test_pylist,
1191                        6, 0,
1192                        7, False)
1193         i = 101
1194         label = 'this is row #101'
1195         treeiter = list_store.append()
1196         list_store.set(treeiter, {1: label,
1197                                   0: i,
1198                                   2: TestGtk.TestClass(self, i, label),
1199                                   3: test_pyobj,
1200                                   4: test_pydict,
1201                                   5: test_pylist,
1202                                   6: 1,
1203                                   7: True})
1204         i = 102
1205         label = 'this is row #102'
1206         treeiter = list_store.append()
1207         list_store.set(treeiter, (1, 0, 2, 3, 4, 5, 6, 7),
1208                                  (label,
1209                                   i,
1210                                   TestGtk.TestClass(self, i, label),
1211                                   test_pyobj,
1212                                   test_pydict,
1213                                   test_pylist,
1214                                   0,
1215                                   False))
1216
1217         self.assertEqual(len(list_store), 103)
1218
1219         # walk the list to see if the values were stored correctly
1220         i = 0
1221         treeiter = list_store.get_iter_first()
1222
1223         counter = 0
1224         while treeiter:
1225             i = list_store.get_value(treeiter, 0)
1226             self.assertEqual(i, counter)
1227             s = list_store.get_value(treeiter, 1)
1228             obj = list_store.get_value(treeiter, 2)
1229             obj.check(i, s)
1230
1231             pyobj = list_store.get_value(treeiter, 3)
1232             self.assertEqual(pyobj, test_pyobj)
1233             pydict = list_store.get_value(treeiter, 4)
1234             self.assertEqual(pydict, test_pydict)
1235             pylist = list_store.get_value(treeiter, 5)
1236             self.assertEqual(pylist, test_pylist)
1237
1238             bool_1 = list_store.get_value(treeiter, 6)
1239             bool_2 = list_store.get_value(treeiter, 7)
1240             self.assertEqual(bool_1, bool_2)
1241             self.assertTrue(isinstance(bool_1, bool))
1242             self.assertTrue(isinstance(bool_2, bool))
1243
1244             treeiter = list_store.iter_next(treeiter)
1245
1246             counter += 1
1247
1248         self.assertEqual(i, 102)
1249
1250     def test_list_store_sort(self):
1251         def comp1(model, row1, row2, user_data):
1252             v1 = model[row1][1]
1253             v2 = model[row2][1]
1254
1255             # make "m" smaller than anything else
1256             if v1.startswith('m') and not v2.startswith('m'):
1257                 return -1
1258             if v2.startswith('m') and not v1.startswith('m'):
1259                 return 1
1260             return (v1 > v2) - (v1 < v2)
1261
1262         list_store = Gtk.ListStore(int, str)
1263         list_store.set_sort_func(2, comp1, None)
1264         list_store.append((1, 'apples'))
1265         list_store.append((3, 'oranges'))
1266         list_store.append((2, 'mango'))
1267
1268         # not sorted yet, should be original order
1269         self.assertEqual([list(i) for i in list_store],
1270                          [[1, 'apples'], [3, 'oranges'], [2, 'mango']])
1271
1272         # sort with our custom function
1273         list_store.set_sort_column_id(2, Gtk.SortType.ASCENDING)
1274         self.assertEqual([list(i) for i in list_store],
1275                          [[2, 'mango'], [1, 'apples'], [3, 'oranges']])
1276
1277         list_store.set_sort_column_id(2, Gtk.SortType.DESCENDING)
1278         self.assertEqual([list(i) for i in list_store],
1279                          [[3, 'oranges'], [1, 'apples'], [2, 'mango']])
1280
1281     def test_list_store_signals(self):
1282         list_store = Gtk.ListStore(int, bool)
1283
1284         def on_row_inserted(list_store, tree_path, tree_iter, signal_list):
1285             signal_list.append('row-inserted')
1286
1287         def on_row_changed(list_store, tree_path, tree_iter, signal_list):
1288             signal_list.append('row-changed')
1289
1290         signals = []
1291         list_store.connect('row-inserted', on_row_inserted, signals)
1292         list_store.connect('row-changed', on_row_changed, signals)
1293
1294         # adding rows with and without data should only call one signal
1295         list_store.append((0, False))
1296         self.assertEqual(signals, ['row-inserted'])
1297
1298         signals.pop()
1299         list_store.append()
1300         self.assertEqual(signals, ['row-inserted'])
1301
1302         signals.pop()
1303         list_store.prepend((0, False))
1304         self.assertEqual(signals, ['row-inserted'])
1305
1306         signals.pop()
1307         list_store.prepend()
1308         self.assertEqual(signals, ['row-inserted'])
1309
1310         signals.pop()
1311         list_store.insert(1, (0, False))
1312         self.assertEqual(signals, ['row-inserted'])
1313
1314         signals.pop()
1315         list_store.insert(1)
1316         self.assertEqual(signals, ['row-inserted'])
1317
1318     def test_tree_path(self):
1319         p1 = Gtk.TreePath()
1320         p2 = Gtk.TreePath.new_first()
1321         self.assertEqual(p1, p2)
1322         self.assertEqual(str(p1), '0')
1323         self.assertEqual(len(p1), 1)
1324         p1 = Gtk.TreePath(2)
1325         p2 = Gtk.TreePath.new_from_string('2')
1326         self.assertEqual(p1, p2)
1327         self.assertEqual(str(p1), '2')
1328         self.assertEqual(len(p1), 1)
1329         p1 = Gtk.TreePath('1:2:3')
1330         p2 = Gtk.TreePath.new_from_string('1:2:3')
1331         self.assertEqual(p1, p2)
1332         self.assertEqual(str(p1), '1:2:3')
1333         self.assertEqual(len(p1), 3)
1334         p1 = Gtk.TreePath((1, 2, 3))
1335         p2 = Gtk.TreePath.new_from_string('1:2:3')
1336         self.assertEqual(p1, p2)
1337         self.assertEqual(str(p1), '1:2:3')
1338         self.assertEqual(len(p1), 3)
1339         self.assertNotEqual(p1, None)
1340         self.assertTrue(p1 > None)
1341         self.assertTrue(p1 >= None)
1342         self.assertFalse(p1 < None)
1343         self.assertFalse(p1 <= None)
1344
1345         self.assertEqual(tuple(p1), (1, 2, 3))
1346         self.assertEqual(p1[0], 1)
1347         self.assertEqual(p1[1], 2)
1348         self.assertEqual(p1[2], 3)
1349         self.assertRaises(IndexError, p1.__getitem__, 3)
1350
1351     def test_tree_model(self):
1352         tree_store = Gtk.TreeStore(int, str)
1353
1354         self.assertTrue(tree_store)
1355         self.assertEqual(len(tree_store), 0)
1356         self.assertEqual(tree_store.get_iter_first(), None)
1357
1358         def get_by_index(row, col=None):
1359             if col:
1360                 return tree_store[row][col]
1361             else:
1362                 return tree_store[row]
1363
1364         self.assertRaises(TypeError, get_by_index, None)
1365         self.assertRaises(TypeError, get_by_index, "")
1366         self.assertRaises(TypeError, get_by_index, ())
1367
1368         self.assertRaises(IndexError, get_by_index, "0")
1369         self.assertRaises(IndexError, get_by_index, 0)
1370         self.assertRaises(IndexError, get_by_index, (0,))
1371
1372         self.assertRaises(ValueError, tree_store.get_iter, "0")
1373         self.assertRaises(ValueError, tree_store.get_iter, 0)
1374         self.assertRaises(ValueError, tree_store.get_iter, (0,))
1375
1376         self.assertRaises(ValueError, tree_store.get_iter_from_string, "0")
1377
1378         for row in tree_store:
1379             self.fail("Should not be reached")
1380
1381         class DerivedIntType(int):
1382             pass
1383
1384         class DerivedStrType(str):
1385             pass
1386
1387         for i in range(100):
1388             label = 'this is row #%d' % i
1389             parent = tree_store.append(None, (DerivedIntType(i), DerivedStrType(label),))
1390             self.assertNotEqual(parent, None)
1391             for j in range(20):
1392                 label = 'this is child #%d of node #%d' % (j, i)
1393                 child = tree_store.append(parent, (j, label,))
1394                 self.assertNotEqual(child, None)
1395
1396         self.assertTrue(tree_store)
1397         self.assertEqual(len(tree_store), 100)
1398
1399         self.assertEqual(tree_store.iter_previous(tree_store.get_iter(0)), None)
1400
1401         for i, row in enumerate(tree_store):
1402             self.assertEqual(row.model, tree_store)
1403             self.assertEqual(row.parent, None)
1404
1405             self.assertEqual(tree_store[i].path, row.path)
1406             self.assertEqual(tree_store[str(i)].path, row.path)
1407             self.assertEqual(tree_store[(i,)].path, row.path)
1408
1409             self.assertEqual(tree_store[i][0], i)
1410             self.assertEqual(tree_store[i][1], "this is row #%d" % i)
1411
1412             aiter = tree_store.get_iter(i)
1413             self.assertEqual(tree_store.get_path(aiter), row.path)
1414
1415             aiter = tree_store.get_iter(str(i))
1416             self.assertEqual(tree_store.get_path(aiter), row.path)
1417
1418             aiter = tree_store.get_iter((i,))
1419             self.assertEqual(tree_store.get_path(aiter), row.path)
1420
1421             self.assertEqual(tree_store.iter_parent(aiter), row.parent)
1422
1423             next = tree_store.iter_next(aiter)
1424             if i < len(tree_store) - 1:
1425                 self.assertEqual(tree_store.get_path(next), row.next.path)
1426                 self.assertEqual(tree_store.get_path(tree_store.iter_previous(next)),
1427                                  tree_store.get_path(aiter))
1428             else:
1429                 self.assertEqual(next, None)
1430
1431             self.assertEqual(tree_store.iter_n_children(row.iter), 20)
1432
1433             child = tree_store.iter_children(row.iter)
1434             for j, childrow in enumerate(row.iterchildren()):
1435                 child_path = tree_store.get_path(child)
1436                 self.assertEqual(childrow.path, child_path)
1437                 self.assertEqual(childrow.parent.path, row.path)
1438                 self.assertEqual(childrow.path, tree_store[child].path)
1439                 self.assertEqual(childrow.path, tree_store[child_path].path)
1440
1441                 self.assertEqual(childrow[0], tree_store[child][0])
1442                 self.assertEqual(childrow[0], j)
1443                 self.assertEqual(childrow[1], tree_store[child][1])
1444                 self.assertEqual(childrow[1], 'this is child #%d of node #%d' % (j, i))
1445
1446                 self.assertRaises(IndexError, get_by_index, child, 2)
1447
1448                 tree_store[child][1] = 'this was child #%d of node #%d' % (j, i)
1449                 self.assertEqual(childrow[1], 'this was child #%d of node #%d' % (j, i))
1450
1451                 nth_child = tree_store.iter_nth_child(row.iter, j)
1452                 self.assertEqual(childrow.path, tree_store.get_path(nth_child))
1453
1454                 childrow2 = tree_store["%d:%d" % (i, j)]
1455                 self.assertEqual(childrow.path, childrow2.path)
1456
1457                 childrow2 = tree_store[(i, j,)]
1458                 self.assertEqual(childrow.path, childrow2.path)
1459
1460                 child = tree_store.iter_next(child)
1461                 if j < 19:
1462                     self.assertEqual(childrow.next.path, tree_store.get_path(child))
1463                 else:
1464                     self.assertEqual(child, childrow.next)
1465                     self.assertEqual(child, None)
1466
1467             self.assertEqual(j, 19)
1468
1469         self.assertEqual(i, 99)
1470
1471         # negative indices
1472         for i in range(-1, -100, -1):
1473             i_real = i + 100
1474             self.assertEqual(tree_store[i][0], i_real)
1475
1476             row = tree_store[i]
1477             for j in range(-1, -20, -1):
1478                 j_real = j + 20
1479                 path = (i_real, j_real,)
1480
1481                 self.assertEqual(tree_store[path][-2], j_real)
1482
1483                 label = 'this was child #%d of node #%d' % (j_real, i_real)
1484                 self.assertEqual(tree_store[path][-1], label)
1485
1486                 new_label = 'this still is child #%d of node #%d' % (j_real, i_real)
1487                 tree_store[path][-1] = new_label
1488                 self.assertEqual(tree_store[path][-1], new_label)
1489
1490                 self.assertRaises(IndexError, get_by_index, path, -3)
1491
1492         self.assertRaises(IndexError, get_by_index, -101)
1493
1494         last_row = tree_store[99]
1495         self.assertNotEqual(last_row, None)
1496
1497         for i, childrow in enumerate(last_row.iterchildren()):
1498             if i < 19:
1499                 self.assertTrue(tree_store.remove(childrow.iter))
1500             else:
1501                 self.assertFalse(tree_store.remove(childrow.iter))
1502
1503         self.assertEqual(i, 19)
1504
1505         self.assertEqual(tree_store.iter_n_children(last_row.iter), 0)
1506         for childrow in last_row.iterchildren():
1507             self.fail("Should not be reached")
1508
1509         aiter = tree_store.get_iter(10)
1510         self.assertRaises(TypeError, tree_store.get, aiter, 1, 'a')
1511         self.assertRaises(ValueError, tree_store.get, aiter, 1, -1)
1512         self.assertRaises(ValueError, tree_store.get, aiter, 1, 100)
1513         self.assertEqual(tree_store.get(aiter, 0, 1), (10, 'this is row #10'))
1514
1515         # check __delitem__
1516         self.assertEqual(len(tree_store), 100)
1517         aiter = tree_store.get_iter(10)
1518         del tree_store[aiter]
1519         self.assertEqual(len(tree_store), 99)
1520         self.assertRaises(TypeError, tree_store.__delitem__, None)
1521         self.assertRaises(IndexError, tree_store.__delitem__, -101)
1522         self.assertRaises(IndexError, tree_store.__delitem__, 101)
1523
1524     def test_tree_model_get_iter_fail(self):
1525         # TreeModel class with a failing get_iter()
1526         class MyTreeModel(GObject.GObject, Gtk.TreeModel):
1527             def do_get_iter(self, iter):
1528                 return (False, None)
1529
1530         tm = MyTreeModel()
1531         self.assertEqual(tm.get_iter_first(), None)
1532
1533     def test_tree_model_edit(self):
1534         model = Gtk.ListStore(int, str, float)
1535         model.append([1, "one", -0.1])
1536         model.append([2, "two", -0.2])
1537
1538         def set_row(value):
1539             model[1] = value
1540
1541         self.assertRaises(TypeError, set_row, 3)
1542         self.assertRaises(TypeError, set_row, "three")
1543         self.assertRaises(ValueError, set_row, [])
1544         self.assertRaises(ValueError, set_row, [3, "three"])
1545
1546         model[0] = (3, "three", -0.3)
1547
1548     def test_tree_row_slice(self):
1549         model = Gtk.ListStore(int, str, float)
1550         model.append([1, "one", -0.1])
1551
1552         self.assertEqual([1, "one", -0.1], model[0][:])
1553         self.assertEqual([1, "one"], model[0][:2])
1554         self.assertEqual(["one", -0.1], model[0][1:])
1555         self.assertEqual(["one"], model[0][1:-1])
1556         self.assertEqual([1], model[0][:-2])
1557         self.assertEqual([], model[0][5:])
1558         self.assertEqual([1, -0.1], model[0][0:3:2])
1559
1560         model[0][:] = (2, "two", -0.2)
1561         self.assertEqual([2, "two", -0.2], model[0][:])
1562
1563         model[0][:2] = (3, "three")
1564         self.assertEqual([3, "three", -0.2], model[0][:])
1565
1566         model[0][1:] = ("four", -0.4)
1567         self.assertEqual([3, "four", -0.4], model[0][:])
1568
1569         model[0][1:-1] = ("five",)
1570         self.assertEqual([3, "five", -0.4], model[0][:])
1571
1572         model[0][0:3:2] = (6, -0.6)
1573         self.assertEqual([6, "five", -0.6], model[0][:])
1574
1575         def set_row1():
1576             model[0][5:] = ("doesn't", "matter",)
1577
1578         self.assertRaises(ValueError, set_row1)
1579
1580         def set_row2():
1581             model[0][:1] = (0, "zero", 0)
1582
1583         self.assertRaises(ValueError, set_row2)
1584
1585         def set_row3():
1586             model[0][:2] = ("0", 0)
1587
1588         self.assertRaises(TypeError, set_row3)
1589
1590     def test_tree_row_sequence(self):
1591         model = Gtk.ListStore(int, str, float)
1592         model.append([1, "one", -0.1])
1593
1594         self.assertEqual([1, "one", -0.1], model[0][0, 1, 2])
1595         self.assertEqual([1, "one"], model[0][0, 1])
1596         self.assertEqual(["one", -0.1], model[0][1, 2])
1597         self.assertEqual("one", model[0][1])
1598         self.assertEqual([1, -0.1], model[0][0, 2])
1599         self.assertEqual([-0.1, 1], model[0][2, 0])
1600
1601         model[0][0, 1, 2] = (2, "two", -0.2)
1602         self.assertEqual([2, "two", -0.2], model[0][0, 1, 2])
1603
1604         model[0][0, 1] = (3, "three")
1605         self.assertEqual([3, "three"], model[0][0, 1])
1606
1607         model[0][1, 2] = ("four", -0.4)
1608         self.assertEqual(["four", -0.4], model[0][1, 2])
1609
1610         model[0][0, 2] = (5, -0.5)
1611         self.assertEqual([5, -0.5], model[0][0, 2])
1612
1613         model[0][0, 1, 2] = (6, "six", -0.6)
1614         self.assertEqual([-0.6, 6, "six"], model[0][2, 0, 1])
1615
1616         def set_row1():
1617             model[0][4, 5] = ("shouldn't", "work",)
1618
1619         self.assertRaises(IndexError, set_row1)
1620
1621         def set_row2():
1622             model[0][0, 1] = (0, "zero", 0)
1623
1624         self.assertRaises(ValueError, set_row2)
1625
1626         def set_row3():
1627             model[0][0, 1] = ("shouldn't", 0)
1628
1629         self.assertRaises(TypeError, set_row3)
1630
1631         def set_row4():
1632             model[0][0, "two"] = (0, "zero")
1633
1634         self.assertRaises(TypeError, set_row4)
1635
1636     def test_tree_model_set_value_to_none(self):
1637         # Tests allowing the usage of None to set an empty value on a model.
1638         store = Gtk.ListStore(str)
1639         row = store.append(['test'])
1640         self.assertSequenceEqual(store[0][:], ['test'])
1641         store.set_value(row, 0, None)
1642         self.assertSequenceEqual(store[0][:], [None])
1643
1644     def test_signal_emission_tree_path_coerce(self):
1645         class Model(GObject.Object, Gtk.TreeModel):
1646             pass
1647
1648         model = Model()
1649         tree_paths = []
1650
1651         def on_any_signal(model, path, *args):
1652             tree_paths.append(path.to_string())
1653
1654         model.connect('row-changed', on_any_signal)
1655         model.connect('row-deleted', on_any_signal)
1656         model.connect('row-has-child-toggled', on_any_signal)
1657         model.connect('row-inserted', on_any_signal)
1658
1659         model.row_changed('0', Gtk.TreeIter())
1660         self.assertEqual(tree_paths[-1], '0')
1661
1662         model.row_deleted('1')
1663         self.assertEqual(tree_paths[-1], '1')
1664
1665         model.row_has_child_toggled('2', Gtk.TreeIter())
1666         self.assertEqual(tree_paths[-1], '2')
1667
1668         model.row_inserted('3', Gtk.TreeIter())
1669         self.assertEqual(tree_paths[-1], '3')
1670
1671     def test_tree_model_filter(self):
1672         model = Gtk.ListStore(int, str, float)
1673         model.append([1, "one", -0.1])
1674         model.append([2, "two", -0.2])
1675
1676         filtered = Gtk.TreeModelFilter(child_model=model)
1677
1678         self.assertEqual(filtered[0][1], 'one')
1679         filtered[0][1] = 'ONE'
1680         self.assertEqual(filtered[0][1], 'ONE')
1681
1682     def test_list_store_performance(self):
1683         model = Gtk.ListStore(int, str)
1684
1685         iterations = 2000
1686         start = time.clock()
1687         i = iterations
1688         while i > 0:
1689             model.append([1, 'hello'])
1690             i -= 1
1691         end = time.clock()
1692         sys.stderr.write('[%.0f Âµs/append] ' % ((end - start) * 1000000 / iterations))
1693
1694     def test_filter_new_default(self):
1695         # Test filter_new accepts implicit default of None
1696         model = Gtk.ListStore(int)
1697         filt = model.filter_new()
1698         self.assertTrue(filt is not None)
1699
1700
1701 @unittest.skipUnless(Gtk, 'Gtk not available')
1702 class TestTreeView(unittest.TestCase):
1703     def test_tree_view(self):
1704         store = Gtk.ListStore(int, str)
1705         store.append((0, "foo"))
1706         store.append((1, "bar"))
1707         view = Gtk.TreeView()
1708
1709         with realized(view):
1710             view.set_cursor(store[1].path)
1711             view.set_cursor(str(store[1].path))
1712
1713             view.get_cell_area(store[1].path)
1714             view.get_cell_area(str(store[1].path))
1715
1716     def test_tree_view_column(self):
1717         cell = Gtk.CellRendererText()
1718         col = Gtk.TreeViewColumn(title='This is just a test',
1719                                  cell_renderer=cell,
1720                                  text=0,
1721                                  style=2)
1722
1723         # Regression test for: https://bugzilla.gnome.org/show_bug.cgi?id=711173
1724         col.set_cell_data_func(cell, None, None)
1725
1726     def test_tree_view_add_column_with_attributes(self):
1727         model = Gtk.ListStore(str, str, str)
1728         # deliberately use out-of-order sorting here; we assign column 0 to
1729         # model index 2, etc.
1730         model.append(['cell13', 'cell11', 'cell12'])
1731         model.append(['cell23', 'cell21', 'cell22'])
1732
1733         tree = Gtk.TreeView(model=model)
1734         cell1 = Gtk.CellRendererText()
1735         cell2 = Gtk.CellRendererText()
1736         cell3 = Gtk.CellRendererText()
1737         cell4 = Gtk.CellRendererText()
1738
1739         tree.insert_column_with_attributes(0, 'Head2', cell2, text=2)
1740         tree.insert_column_with_attributes(0, 'Head1', cell1, text=1)
1741         tree.insert_column_with_attributes(-1, 'Head3', cell3, text=0)
1742         # unconnected
1743         tree.insert_column_with_attributes(-1, 'Head4', cell4)
1744
1745         with realized(tree):
1746             tree.set_cursor(model[0].path)
1747             while Gtk.events_pending():
1748                 Gtk.main_iteration()
1749
1750             self.assertEqual(tree.get_column(0).get_title(), 'Head1')
1751             self.assertEqual(tree.get_column(1).get_title(), 'Head2')
1752             self.assertEqual(tree.get_column(2).get_title(), 'Head3')
1753             self.assertEqual(tree.get_column(3).get_title(), 'Head4')
1754
1755             # cursor should be at the first row
1756             self.assertEqual(cell1.props.text, 'cell11')
1757             self.assertEqual(cell2.props.text, 'cell12')
1758             self.assertEqual(cell3.props.text, 'cell13')
1759             self.assertEqual(cell4.props.text, None)
1760
1761     def test_tree_view_column_set_attributes(self):
1762         store = Gtk.ListStore(int, str)
1763         directors = ['Fellini', 'Tarantino', 'Tarkovskiy']
1764         for i, director in enumerate(directors):
1765             store.append([i, director])
1766
1767         treeview = Gtk.TreeView()
1768         treeview.set_model(store)
1769
1770         column = Gtk.TreeViewColumn()
1771         treeview.append_column(column)
1772
1773         cell = Gtk.CellRendererText()
1774         column.pack_start(cell, expand=True)
1775         column.set_attributes(cell, text=1)
1776
1777         with realized(treeview):
1778             self.assertTrue(cell.props.text in directors)
1779
1780     def test_tree_selection(self):
1781         store = Gtk.ListStore(int, str)
1782         for i in range(10):
1783             store.append((i, "foo"))
1784         view = Gtk.TreeView()
1785         view.set_model(store)
1786         firstpath = store.get_path(store.get_iter_first())
1787         sel = view.get_selection()
1788
1789         sel.select_path(firstpath)
1790         (m, s) = sel.get_selected()
1791         self.assertEqual(m, store)
1792         self.assertEqual(store.get_path(s), firstpath)
1793
1794         sel.select_path(0)
1795         (m, s) = sel.get_selected()
1796         self.assertEqual(m, store)
1797         self.assertEqual(store.get_path(s), firstpath)
1798
1799         sel.select_path("0:0")
1800         (m, s) = sel.get_selected()
1801         self.assertEqual(m, store)
1802         self.assertEqual(store.get_path(s), firstpath)
1803
1804         sel.select_path((0, 0))
1805         (m, s) = sel.get_selected()
1806         self.assertEqual(m, store)
1807         self.assertEqual(store.get_path(s), firstpath)
1808
1809
1810 @unittest.skipUnless(Gtk, 'Gtk not available')
1811 class TestTextBuffer(unittest.TestCase):
1812     def test_text_buffer(self):
1813         self.assertEqual(Gtk.TextBuffer, gi.overrides.Gtk.TextBuffer)
1814         buffer = Gtk.TextBuffer()
1815         tag = buffer.create_tag('title', font='Sans 18')
1816
1817         self.assertEqual(tag.props.name, 'title')
1818         self.assertEqual(tag.props.font, 'Sans 18')
1819
1820         (start, end) = buffer.get_bounds()
1821
1822         mark = buffer.create_mark(None, start)
1823         self.assertFalse(mark.get_left_gravity())
1824
1825         buffer.set_text('Hello Jane Hello Bob')
1826         (start, end) = buffer.get_bounds()
1827         text = buffer.get_text(start, end, False)
1828         self.assertEqual(text, 'Hello Jane Hello Bob')
1829
1830         buffer.set_text('')
1831         (start, end) = buffer.get_bounds()
1832         text = buffer.get_text(start, end, False)
1833         self.assertEqual(text, '')
1834
1835         buffer.insert(end, 'HelloHello')
1836         buffer.insert(end, ' Bob')
1837
1838         cursor_iter = end.copy()
1839         cursor_iter.backward_chars(9)
1840         buffer.place_cursor(cursor_iter)
1841         buffer.insert_at_cursor(' Jane ')
1842
1843         (start, end) = buffer.get_bounds()
1844         text = buffer.get_text(start, end, False)
1845         self.assertEqual(text, 'Hello Jane Hello Bob')
1846
1847         sel = buffer.get_selection_bounds()
1848         self.assertEqual(sel, ())
1849         buffer.select_range(start, end)
1850         sel = buffer.get_selection_bounds()
1851         self.assertTrue(sel[0].equal(start))
1852         self.assertTrue(sel[1].equal(end))
1853
1854         buffer.set_text('')
1855         buffer.insert_with_tags(buffer.get_start_iter(), 'HelloHello', tag)
1856         (start, end) = buffer.get_bounds()
1857         self.assertTrue(start.begins_tag(tag))
1858         self.assertTrue(start.has_tag(tag))
1859
1860         buffer.set_text('')
1861         buffer.insert_with_tags_by_name(buffer.get_start_iter(), 'HelloHello', 'title')
1862         (start, end) = buffer.get_bounds()
1863         self.assertTrue(start.begins_tag(tag))
1864         self.assertTrue(start.has_tag(tag))
1865
1866         self.assertRaises(ValueError, buffer.insert_with_tags_by_name,
1867                           buffer.get_start_iter(), 'HelloHello', 'unknowntag')
1868
1869     def test_text_iter(self):
1870         self.assertEqual(Gtk.TextIter, gi.overrides.Gtk.TextIter)
1871         buffer = Gtk.TextBuffer()
1872         buffer.set_text('Hello Jane Hello Bob')
1873         tag = buffer.create_tag('title', font='Sans 18')
1874         (start, end) = buffer.get_bounds()
1875         start.forward_chars(10)
1876         buffer.apply_tag(tag, start, end)
1877         self.assertTrue(start.begins_tag())
1878         self.assertTrue(end.ends_tag())
1879         self.assertTrue(start.toggles_tag())
1880         self.assertTrue(end.toggles_tag())
1881         start.backward_chars(1)
1882         self.assertFalse(start.begins_tag())
1883         self.assertFalse(start.ends_tag())
1884         self.assertFalse(start.toggles_tag())
1885
1886     def test_text_buffer_search(self):
1887         buffer = Gtk.TextBuffer()
1888         buffer.set_text('Hello World Hello GNOME')
1889
1890         i = buffer.get_iter_at_offset(0)
1891         self.assertTrue(isinstance(i, Gtk.TextIter))
1892
1893         self.assertEqual(i.forward_search('world', 0, None), None)
1894
1895         (start, end) = i.forward_search('World', 0, None)
1896         self.assertEqual(start.get_offset(), 6)
1897         self.assertEqual(end.get_offset(), 11)
1898
1899         (start, end) = i.forward_search('world',
1900                                         Gtk.TextSearchFlags.CASE_INSENSITIVE,
1901                                         None)
1902         self.assertEqual(start.get_offset(), 6)
1903         self.assertEqual(end.get_offset(), 11)
1904
1905     def test_insert_text_signal_location_modification(self):
1906         # Regression test for: https://bugzilla.gnome.org/show_bug.cgi?id=736175
1907
1908         def callback(buffer, location, text, length):
1909             location.assign(buffer.get_end_iter())
1910
1911         buffer = Gtk.TextBuffer()
1912         buffer.set_text('first line\n')
1913         buffer.connect('insert-text', callback)
1914
1915         # attempt insertion at the beginning of the buffer, the callback will
1916         # modify the insert location to the end.
1917         buffer.place_cursor(buffer.get_start_iter())
1918         buffer.insert_at_cursor('second line\n')
1919
1920         self.assertEqual(buffer.get_property('text'),
1921                          'first line\nsecond line\n')
1922
1923
1924 @unittest.skipUnless(Gtk, 'Gtk not available')
1925 class TestContainer(unittest.TestCase):
1926     def test_child_set_property(self):
1927         box = Gtk.Box()
1928         child = Gtk.Button()
1929         box.pack_start(child, expand=False, fill=True, padding=0)
1930
1931         box.child_set_property(child, 'padding', 42)
1932
1933         value = GObject.Value(int)
1934         box.child_get_property(child, 'padding', value)
1935         self.assertEqual(value.get_int(), 42)
1936
1937     def test_child_get_property_gvalue(self):
1938         box = Gtk.Box()
1939         child = Gtk.Button()
1940         box.pack_start(child, expand=False, fill=True, padding=42)
1941
1942         value = GObject.Value(int)
1943         box.child_get_property(child, 'padding', value)
1944         self.assertEqual(value.get_int(), 42)
1945
1946     def test_child_get_property_return_with_explicit_gvalue(self):
1947         box = Gtk.Box()
1948         child = Gtk.Button()
1949         box.pack_start(child, expand=False, fill=True, padding=42)
1950
1951         value = GObject.Value(int)
1952         result = box.child_get_property(child, 'padding', value)
1953         self.assertEqual(result, 42)
1954
1955     def test_child_get_property_return_with_implicit_gvalue(self):
1956         box = Gtk.Box()
1957         child = Gtk.Button()
1958         box.pack_start(child, expand=False, fill=True, padding=42)
1959
1960         result = box.child_get_property(child, 'padding')
1961         self.assertEqual(result, 42)
1962
1963     def test_child_get_property_error(self):
1964         box = Gtk.Box()
1965         child = Gtk.Button()
1966         box.pack_start(child, expand=False, fill=True, padding=42)
1967         with self.assertRaises(ValueError):
1968             box.child_get_property(child, 'not-a-valid-child-property')
1969
1970     def test_child_get_and_set(self):
1971         box = Gtk.Box()
1972         child = Gtk.Button()
1973         box.pack_start(child, expand=True, fill=True, padding=42)
1974
1975         expand, fill, padding = box.child_get(child, 'expand', 'fill', 'padding')
1976         self.assertEqual(expand, True)
1977         self.assertEqual(fill, True)
1978         self.assertEqual(padding, 42)
1979
1980         box.child_set(child, expand=False, fill=False, padding=21, pack_type=1)
1981         expand, fill, padding, pack_type = box.child_get(child, 'expand', 'fill', 'padding', 'pack-type')
1982         self.assertEqual(expand, False)
1983         self.assertEqual(fill, False)
1984         self.assertEqual(padding, 21)