Home | History | Annotate | Download | only in test_ttk
      1 import unittest
      2 import Tkinter
      3 import ttk
      4 from test.test_support import requires, run_unittest
      5 import sys
      6 
      7 import support
      8 from test_functions import MockTclObj, MockStateSpec
      9 
     10 requires('gui')
     11 
     12 class WidgetTest(unittest.TestCase):
     13     """Tests methods available in every ttk widget."""
     14 
     15     def setUp(self):
     16         support.root_deiconify()
     17         self.widget = ttk.Button(width=0, text="Text")
     18         self.widget.pack()
     19         self.widget.wait_visibility()
     20 
     21     def tearDown(self):
     22         self.widget.destroy()
     23         support.root_withdraw()
     24 
     25 
     26     def test_identify(self):
     27         self.widget.update_idletasks()
     28         self.assertEqual(self.widget.identify(
     29             int(self.widget.winfo_width() / 2),
     30             int(self.widget.winfo_height() / 2)
     31             ), "label")
     32         self.assertEqual(self.widget.identify(-1, -1), "")
     33 
     34         self.assertRaises(Tkinter.TclError, self.widget.identify, None, 5)
     35         self.assertRaises(Tkinter.TclError, self.widget.identify, 5, None)
     36         self.assertRaises(Tkinter.TclError, self.widget.identify, 5, '')
     37 
     38 
     39     def test_widget_state(self):
     40         # XXX not sure about the portability of all these tests
     41         self.assertEqual(self.widget.state(), ())
     42         self.assertEqual(self.widget.instate(['!disabled']), True)
     43 
     44         # changing from !disabled to disabled
     45         self.assertEqual(self.widget.state(['disabled']), ('!disabled', ))
     46         # no state change
     47         self.assertEqual(self.widget.state(['disabled']), ())
     48         # change back to !disable but also active
     49         self.assertEqual(self.widget.state(['!disabled', 'active']),
     50             ('!active', 'disabled'))
     51         # no state changes, again
     52         self.assertEqual(self.widget.state(['!disabled', 'active']), ())
     53         self.assertEqual(self.widget.state(['active', '!disabled']), ())
     54 
     55         def test_cb(arg1, **kw):
     56             return arg1, kw
     57         self.assertEqual(self.widget.instate(['!disabled'],
     58             test_cb, "hi", **{"msg": "there"}),
     59             ('hi', {'msg': 'there'}))
     60 
     61         # attempt to set invalid statespec
     62         currstate = self.widget.state()
     63         self.assertRaises(Tkinter.TclError, self.widget.instate,
     64             ['badstate'])
     65         self.assertRaises(Tkinter.TclError, self.widget.instate,
     66             ['disabled', 'badstate'])
     67         # verify that widget didn't change its state
     68         self.assertEqual(currstate, self.widget.state())
     69 
     70         # ensuring that passing None as state doesn't modify current state
     71         self.widget.state(['active', '!disabled'])
     72         self.assertEqual(self.widget.state(), ('active', ))
     73 
     74 
     75 class ButtonTest(unittest.TestCase):
     76 
     77     def test_invoke(self):
     78         success = []
     79         btn = ttk.Button(command=lambda: success.append(1))
     80         btn.invoke()
     81         self.assertTrue(success)
     82 
     83 
     84 class CheckbuttonTest(unittest.TestCase):
     85 
     86     def test_invoke(self):
     87         success = []
     88         def cb_test():
     89             success.append(1)
     90             return "cb test called"
     91 
     92         cbtn = ttk.Checkbutton(command=cb_test)
     93         # the variable automatically created by ttk.Checkbutton is actually
     94         # undefined till we invoke the Checkbutton
     95         self.assertEqual(cbtn.state(), ('alternate', ))
     96         self.assertRaises(Tkinter.TclError, cbtn.tk.globalgetvar,
     97             cbtn['variable'])
     98 
     99         res = cbtn.invoke()
    100         self.assertEqual(res, "cb test called")
    101         self.assertEqual(cbtn['onvalue'],
    102             cbtn.tk.globalgetvar(cbtn['variable']))
    103         self.assertTrue(success)
    104 
    105         cbtn['command'] = ''
    106         res = cbtn.invoke()
    107         self.assertEqual(res, '')
    108         self.assertFalse(len(success) > 1)
    109         self.assertEqual(cbtn['offvalue'],
    110             cbtn.tk.globalgetvar(cbtn['variable']))
    111 
    112 
    113 class ComboboxTest(unittest.TestCase):
    114 
    115     def setUp(self):
    116         support.root_deiconify()
    117         self.combo = ttk.Combobox()
    118 
    119     def tearDown(self):
    120         self.combo.destroy()
    121         support.root_withdraw()
    122 
    123     def _show_drop_down_listbox(self):
    124         width = self.combo.winfo_width()
    125         self.combo.event_generate('<ButtonPress-1>', x=width - 5, y=5)
    126         self.combo.event_generate('<ButtonRelease-1>', x=width - 5, y=5)
    127         self.combo.update_idletasks()
    128 
    129 
    130     def test_virtual_event(self):
    131         success = []
    132 
    133         self.combo['values'] = [1]
    134         self.combo.bind('<<ComboboxSelected>>',
    135             lambda evt: success.append(True))
    136         self.combo.pack()
    137         self.combo.wait_visibility()
    138 
    139         height = self.combo.winfo_height()
    140         self._show_drop_down_listbox()
    141         self.combo.update()
    142         self.combo.event_generate('<Return>')
    143         self.combo.update()
    144 
    145         self.assertTrue(success)
    146 
    147 
    148     def test_postcommand(self):
    149         success = []
    150 
    151         self.combo['postcommand'] = lambda: success.append(True)
    152         self.combo.pack()
    153         self.combo.wait_visibility()
    154 
    155         self._show_drop_down_listbox()
    156         self.assertTrue(success)
    157 
    158         # testing postcommand removal
    159         self.combo['postcommand'] = ''
    160         self._show_drop_down_listbox()
    161         self.assertEqual(len(success), 1)
    162 
    163 
    164     def test_values(self):
    165         def check_get_current(getval, currval):
    166             self.assertEqual(self.combo.get(), getval)
    167             self.assertEqual(self.combo.current(), currval)
    168 
    169         check_get_current('', -1)
    170 
    171         self.combo['values'] = ['a', 1, 'c']
    172 
    173         self.combo.set('c')
    174         check_get_current('c', 2)
    175 
    176         self.combo.current(0)
    177         check_get_current('a', 0)
    178 
    179         self.combo.set('d')
    180         check_get_current('d', -1)
    181 
    182         # testing values with empty string
    183         self.combo.set('')
    184         self.combo['values'] = (1, 2, '', 3)
    185         check_get_current('', 2)
    186 
    187         # testing values with empty string set through configure
    188         self.combo.configure(values=[1, '', 2])
    189         self.assertEqual(self.combo['values'], ('1', '', '2'))
    190 
    191         # testing values with spaces
    192         self.combo['values'] = ['a b', 'a\tb', 'a\nb']
    193         self.assertEqual(self.combo['values'], ('a b', 'a\tb', 'a\nb'))
    194 
    195         # testing values with special characters
    196         self.combo['values'] = [r'a\tb', '"a"', '} {']
    197         self.assertEqual(self.combo['values'], (r'a\tb', '"a"', '} {'))
    198 
    199         # out of range
    200         self.assertRaises(Tkinter.TclError, self.combo.current,
    201             len(self.combo['values']))
    202         # it expects an integer (or something that can be converted to int)
    203         self.assertRaises(Tkinter.TclError, self.combo.current, '')
    204 
    205         # testing creating combobox with empty string in values
    206         combo2 = ttk.Combobox(values=[1, 2, ''])
    207         self.assertEqual(combo2['values'], ('1', '2', ''))
    208         combo2.destroy()
    209 
    210 
    211 class EntryTest(unittest.TestCase):
    212 
    213     def setUp(self):
    214         support.root_deiconify()
    215         self.entry = ttk.Entry()
    216 
    217     def tearDown(self):
    218         self.entry.destroy()
    219         support.root_withdraw()
    220 
    221 
    222     def test_bbox(self):
    223         self.assertEqual(len(self.entry.bbox(0)), 4)
    224         for item in self.entry.bbox(0):
    225             self.assertTrue(isinstance(item, int))
    226 
    227         self.assertRaises(Tkinter.TclError, self.entry.bbox, 'noindex')
    228         self.assertRaises(Tkinter.TclError, self.entry.bbox, None)
    229 
    230 
    231     def test_identify(self):
    232         self.entry.pack()
    233         self.entry.wait_visibility()
    234         self.entry.update_idletasks()
    235 
    236         self.assertEqual(self.entry.identify(5, 5), "textarea")
    237         self.assertEqual(self.entry.identify(-1, -1), "")
    238 
    239         self.assertRaises(Tkinter.TclError, self.entry.identify, None, 5)
    240         self.assertRaises(Tkinter.TclError, self.entry.identify, 5, None)
    241         self.assertRaises(Tkinter.TclError, self.entry.identify, 5, '')
    242 
    243 
    244     def test_validation_options(self):
    245         success = []
    246         test_invalid = lambda: success.append(True)
    247 
    248         self.entry['validate'] = 'none'
    249         self.entry['validatecommand'] = lambda: False
    250 
    251         self.entry['invalidcommand'] = test_invalid
    252         self.entry.validate()
    253         self.assertTrue(success)
    254 
    255         self.entry['invalidcommand'] = ''
    256         self.entry.validate()
    257         self.assertEqual(len(success), 1)
    258 
    259         self.entry['invalidcommand'] = test_invalid
    260         self.entry['validatecommand'] = lambda: True
    261         self.entry.validate()
    262         self.assertEqual(len(success), 1)
    263 
    264         self.entry['validatecommand'] = ''
    265         self.entry.validate()
    266         self.assertEqual(len(success), 1)
    267 
    268         self.entry['validatecommand'] = True
    269         self.assertRaises(Tkinter.TclError, self.entry.validate)
    270 
    271 
    272     def test_validation(self):
    273         validation = []
    274         def validate(to_insert):
    275             if not 'a' <= to_insert.lower() <= 'z':
    276                 validation.append(False)
    277                 return False
    278             validation.append(True)
    279             return True
    280 
    281         self.entry['validate'] = 'key'
    282         self.entry['validatecommand'] = self.entry.register(validate), '%S'
    283 
    284         self.entry.insert('end', 1)
    285         self.entry.insert('end', 'a')
    286         self.assertEqual(validation, [False, True])
    287         self.assertEqual(self.entry.get(), 'a')
    288 
    289 
    290     def test_revalidation(self):
    291         def validate(content):
    292             for letter in content:
    293                 if not 'a' <= letter.lower() <= 'z':
    294                     return False
    295             return True
    296 
    297         self.entry['validatecommand'] = self.entry.register(validate), '%P'
    298 
    299         self.entry.insert('end', 'avocado')
    300         self.assertEqual(self.entry.validate(), True)
    301         self.assertEqual(self.entry.state(), ())
    302 
    303         self.entry.delete(0, 'end')
    304         self.assertEqual(self.entry.get(), '')
    305 
    306         self.entry.insert('end', 'a1b')
    307         self.assertEqual(self.entry.validate(), False)
    308         self.assertEqual(self.entry.state(), ('invalid', ))
    309 
    310         self.entry.delete(1)
    311         self.assertEqual(self.entry.validate(), True)
    312         self.assertEqual(self.entry.state(), ())
    313 
    314 
    315 class PanedwindowTest(unittest.TestCase):
    316 
    317     def setUp(self):
    318         support.root_deiconify()
    319         self.paned = ttk.Panedwindow()
    320 
    321     def tearDown(self):
    322         self.paned.destroy()
    323         support.root_withdraw()
    324 
    325 
    326     def test_add(self):
    327         # attempt to add a child that is not a direct child of the paned window
    328         label = ttk.Label(self.paned)
    329         child = ttk.Label(label)
    330         self.assertRaises(Tkinter.TclError, self.paned.add, child)
    331         label.destroy()
    332         child.destroy()
    333         # another attempt
    334         label = ttk.Label()
    335         child = ttk.Label(label)
    336         self.assertRaises(Tkinter.TclError, self.paned.add, child)
    337         child.destroy()
    338         label.destroy()
    339 
    340         good_child = ttk.Label()
    341         self.paned.add(good_child)
    342         # re-adding a child is not accepted
    343         self.assertRaises(Tkinter.TclError, self.paned.add, good_child)
    344 
    345         other_child = ttk.Label(self.paned)
    346         self.paned.add(other_child)
    347         self.assertEqual(self.paned.pane(0), self.paned.pane(1))
    348         self.assertRaises(Tkinter.TclError, self.paned.pane, 2)
    349         good_child.destroy()
    350         other_child.destroy()
    351         self.assertRaises(Tkinter.TclError, self.paned.pane, 0)
    352 
    353 
    354     def test_forget(self):
    355         self.assertRaises(Tkinter.TclError, self.paned.forget, None)
    356         self.assertRaises(Tkinter.TclError, self.paned.forget, 0)
    357 
    358         self.paned.add(ttk.Label())
    359         self.paned.forget(0)
    360         self.assertRaises(Tkinter.TclError, self.paned.forget, 0)
    361 
    362 
    363     def test_insert(self):
    364         self.assertRaises(Tkinter.TclError, self.paned.insert, None, 0)
    365         self.assertRaises(Tkinter.TclError, self.paned.insert, 0, None)
    366         self.assertRaises(Tkinter.TclError, self.paned.insert, 0, 0)
    367 
    368         child = ttk.Label()
    369         child2 = ttk.Label()
    370         child3 = ttk.Label()
    371 
    372         self.assertRaises(Tkinter.TclError, self.paned.insert, 0, child)
    373 
    374         self.paned.insert('end', child2)
    375         self.paned.insert(0, child)
    376         self.assertEqual(self.paned.panes(), (str(child), str(child2)))
    377 
    378         self.paned.insert(0, child2)
    379         self.assertEqual(self.paned.panes(), (str(child2), str(child)))
    380 
    381         self.paned.insert('end', child3)
    382         self.assertEqual(self.paned.panes(),
    383             (str(child2), str(child), str(child3)))
    384 
    385         # reinserting a child should move it to its current position
    386         panes = self.paned.panes()
    387         self.paned.insert('end', child3)
    388         self.assertEqual(panes, self.paned.panes())
    389 
    390         # moving child3 to child2 position should result in child2 ending up
    391         # in previous child position and child ending up in previous child3
    392         # position
    393         self.paned.insert(child2, child3)
    394         self.assertEqual(self.paned.panes(),
    395             (str(child3), str(child2), str(child)))
    396 
    397 
    398     def test_pane(self):
    399         self.assertRaises(Tkinter.TclError, self.paned.pane, 0)
    400 
    401         child = ttk.Label()
    402         self.paned.add(child)
    403         self.assertTrue(isinstance(self.paned.pane(0), dict))
    404         self.assertEqual(self.paned.pane(0, weight=None), 0)
    405         # newer form for querying a single option
    406         self.assertEqual(self.paned.pane(0, 'weight'), 0)
    407         self.assertEqual(self.paned.pane(0), self.paned.pane(str(child)))
    408 
    409         self.assertRaises(Tkinter.TclError, self.paned.pane, 0,
    410             badoption='somevalue')
    411 
    412 
    413     def test_sashpos(self):
    414         self.assertRaises(Tkinter.TclError, self.paned.sashpos, None)
    415         self.assertRaises(Tkinter.TclError, self.paned.sashpos, '')
    416         self.assertRaises(Tkinter.TclError, self.paned.sashpos, 0)
    417 
    418         child = ttk.Label(self.paned, text='a')
    419         self.paned.add(child, weight=1)
    420         self.assertRaises(Tkinter.TclError, self.paned.sashpos, 0)
    421         child2 = ttk.Label(self.paned, text='b')
    422         self.paned.add(child2)
    423         self.assertRaises(Tkinter.TclError, self.paned.sashpos, 1)
    424 
    425         self.paned.pack(expand=True, fill='both')
    426         self.paned.wait_visibility()
    427 
    428         curr_pos = self.paned.sashpos(0)
    429         self.paned.sashpos(0, 1000)
    430         self.assertTrue(curr_pos != self.paned.sashpos(0))
    431         self.assertTrue(isinstance(self.paned.sashpos(0), int))
    432 
    433 
    434 class RadiobuttonTest(unittest.TestCase):
    435 
    436     def test_invoke(self):
    437         success = []
    438         def cb_test():
    439             success.append(1)
    440             return "cb test called"
    441 
    442         myvar = Tkinter.IntVar()
    443         cbtn = ttk.Radiobutton(command=cb_test, variable=myvar, value=0)
    444         cbtn2 = ttk.Radiobutton(command=cb_test, variable=myvar, value=1)
    445 
    446         res = cbtn.invoke()
    447         self.assertEqual(res, "cb test called")
    448         self.assertEqual(cbtn['value'], myvar.get())
    449         self.assertEqual(myvar.get(),
    450             cbtn.tk.globalgetvar(cbtn['variable']))
    451         self.assertTrue(success)
    452 
    453         cbtn2['command'] = ''
    454         res = cbtn2.invoke()
    455         self.assertEqual(res, '')
    456         self.assertFalse(len(success) > 1)
    457         self.assertEqual(cbtn2['value'], myvar.get())
    458         self.assertEqual(myvar.get(),
    459             cbtn.tk.globalgetvar(cbtn['variable']))
    460 
    461         self.assertEqual(str(cbtn['variable']), str(cbtn2['variable']))
    462 
    463 
    464 
    465 class ScaleTest(unittest.TestCase):
    466 
    467     def setUp(self):
    468         support.root_deiconify()
    469         self.scale = ttk.Scale()
    470         self.scale.pack()
    471         self.scale.update()
    472 
    473     def tearDown(self):
    474         self.scale.destroy()
    475         support.root_withdraw()
    476 
    477 
    478     def test_custom_event(self):
    479         failure = [1, 1, 1] # will need to be empty
    480 
    481         funcid = self.scale.bind('<<RangeChanged>>', lambda evt: failure.pop())
    482 
    483         self.scale['from'] = 10
    484         self.scale['from_'] = 10
    485         self.scale['to'] = 3
    486 
    487         self.assertFalse(failure)
    488 
    489         failure = [1, 1, 1]
    490         self.scale.configure(from_=2, to=5)
    491         self.scale.configure(from_=0, to=-2)
    492         self.scale.configure(to=10)
    493 
    494         self.assertFalse(failure)
    495 
    496 
    497     def test_get(self):
    498         scale_width = self.scale.winfo_width()
    499         self.assertEqual(self.scale.get(scale_width, 0), self.scale['to'])
    500 
    501         self.assertEqual(self.scale.get(0, 0), self.scale['from'])
    502         self.assertEqual(self.scale.get(), self.scale['value'])
    503         self.scale['value'] = 30
    504         self.assertEqual(self.scale.get(), self.scale['value'])
    505 
    506         self.assertRaises(Tkinter.TclError, self.scale.get, '', 0)
    507         self.assertRaises(Tkinter.TclError, self.scale.get, 0, '')
    508 
    509 
    510     def test_set(self):
    511         # set restricts the max/min values according to the current range
    512         max = self.scale['to']
    513         new_max = max + 10
    514         self.scale.set(new_max)
    515         self.assertEqual(self.scale.get(), max)
    516         min = self.scale['from']
    517         self.scale.set(min - 1)
    518         self.assertEqual(self.scale.get(), min)
    519 
    520         # changing directly the variable doesn't impose this limitation tho
    521         var = Tkinter.DoubleVar()
    522         self.scale['variable'] = var
    523         var.set(max + 5)
    524         self.assertEqual(self.scale.get(), var.get())
    525         self.assertEqual(self.scale.get(), max + 5)
    526         del var
    527 
    528         # the same happens with the value option
    529         self.scale['value'] = max + 10
    530         self.assertEqual(self.scale.get(), max + 10)
    531         self.assertEqual(self.scale.get(), self.scale['value'])
    532 
    533         # nevertheless, note that the max/min values we can get specifying
    534         # x, y coords are the ones according to the current range
    535         self.assertEqual(self.scale.get(0, 0), min)
    536         self.assertEqual(self.scale.get(self.scale.winfo_width(), 0), max)
    537 
    538         self.assertRaises(Tkinter.TclError, self.scale.set, None)
    539 
    540 
    541 class NotebookTest(unittest.TestCase):
    542 
    543     def setUp(self):
    544         support.root_deiconify()
    545         self.nb = ttk.Notebook(padding=0)
    546         self.child1 = ttk.Label()
    547         self.child2 = ttk.Label()
    548         self.nb.add(self.child1, text='a')
    549         self.nb.add(self.child2, text='b')
    550 
    551     def tearDown(self):
    552         self.child1.destroy()
    553         self.child2.destroy()
    554         self.nb.destroy()
    555         support.root_withdraw()
    556 
    557 
    558     def test_tab_identifiers(self):
    559         self.nb.forget(0)
    560         self.nb.hide(self.child2)
    561         self.assertRaises(Tkinter.TclError, self.nb.tab, self.child1)
    562         self.assertEqual(self.nb.index('end'), 1)
    563         self.nb.add(self.child2)
    564         self.assertEqual(self.nb.index('end'), 1)
    565         self.nb.select(self.child2)
    566 
    567         self.assertTrue(self.nb.tab('current'))
    568         self.nb.add(self.child1, text='a')
    569 
    570         self.nb.pack()
    571         self.nb.wait_visibility()
    572         if sys.platform == 'darwin':
    573             tb_idx = "@20,5"
    574         else:
    575             tb_idx = "@5,5"
    576         self.assertEqual(self.nb.tab(tb_idx), self.nb.tab('current'))
    577 
    578         for i in range(5, 100, 5):
    579             try:
    580                 if self.nb.tab('@%d, 5' % i, text=None) == 'a':
    581                     break
    582             except Tkinter.TclError:
    583                 pass
    584 
    585         else:
    586             self.fail("Tab with text 'a' not found")
    587 
    588 
    589     def test_add_and_hidden(self):
    590         self.assertRaises(Tkinter.TclError, self.nb.hide, -1)
    591         self.assertRaises(Tkinter.TclError, self.nb.hide, 'hi')
    592         self.assertRaises(Tkinter.TclError, self.nb.hide, None)
    593         self.assertRaises(Tkinter.TclError, self.nb.add, None)
    594         self.assertRaises(Tkinter.TclError, self.nb.add, ttk.Label(),
    595             unknown='option')
    596 
    597         tabs = self.nb.tabs()
    598         self.nb.hide(self.child1)
    599         self.nb.add(self.child1)
    600         self.assertEqual(self.nb.tabs(), tabs)
    601 
    602         child = ttk.Label()
    603         self.nb.add(child, text='c')
    604         tabs = self.nb.tabs()
    605 
    606         curr = self.nb.index('current')
    607         # verify that the tab gets readded at its previous position
    608         child2_index = self.nb.index(self.child2)
    609         self.nb.hide(self.child2)
    610         self.nb.add(self.child2)
    611         self.assertEqual(self.nb.tabs(), tabs)
    612         self.assertEqual(self.nb.index(self.child2), child2_index)
    613         self.assertTrue(str(self.child2) == self.nb.tabs()[child2_index])
    614         # but the tab next to it (not hidden) is the one selected now
    615         self.assertEqual(self.nb.index('current'), curr + 1)
    616 
    617 
    618     def test_forget(self):
    619         self.assertRaises(Tkinter.TclError, self.nb.forget, -1)
    620         self.assertRaises(Tkinter.TclError, self.nb.forget, 'hi')
    621         self.assertRaises(Tkinter.TclError, self.nb.forget, None)
    622 
    623         tabs = self.nb.tabs()
    624         child1_index = self.nb.index(self.child1)
    625         self.nb.forget(self.child1)
    626         self.assertFalse(str(self.child1) in self.nb.tabs())
    627         self.assertEqual(len(tabs) - 1, len(self.nb.tabs()))
    628 
    629         self.nb.add(self.child1)
    630         self.assertEqual(self.nb.index(self.child1), 1)
    631         self.assertFalse(child1_index == self.nb.index(self.child1))
    632 
    633 
    634     def test_index(self):
    635         self.assertRaises(Tkinter.TclError, self.nb.index, -1)
    636         self.assertRaises(Tkinter.TclError, self.nb.index, None)
    637 
    638         self.assertTrue(isinstance(self.nb.index('end'), int))
    639         self.assertEqual(self.nb.index(self.child1), 0)
    640         self.assertEqual(self.nb.index(self.child2), 1)
    641         self.assertEqual(self.nb.index('end'), 2)
    642 
    643 
    644     def test_insert(self):
    645         # moving tabs
    646         tabs = self.nb.tabs()
    647         self.nb.insert(1, tabs[0])
    648         self.assertEqual(self.nb.tabs(), (tabs[1], tabs[0]))
    649         self.nb.insert(self.child1, self.child2)
    650         self.assertEqual(self.nb.tabs(), tabs)
    651         self.nb.insert('end', self.child1)
    652         self.assertEqual(self.nb.tabs(), (tabs[1], tabs[0]))
    653         self.nb.insert('end', 0)
    654         self.assertEqual(self.nb.tabs(), tabs)
    655         # bad moves
    656         self.assertRaises(Tkinter.TclError, self.nb.insert, 2, tabs[0])
    657         self.assertRaises(Tkinter.TclError, self.nb.insert, -1, tabs[0])
    658 
    659         # new tab
    660         child3 = ttk.Label()
    661         self.nb.insert(1, child3)
    662         self.assertEqual(self.nb.tabs(), (tabs[0], str(child3), tabs[1]))
    663         self.nb.forget(child3)
    664         self.assertEqual(self.nb.tabs(), tabs)
    665         self.nb.insert(self.child1, child3)
    666         self.assertEqual(self.nb.tabs(), (str(child3), ) + tabs)
    667         self.nb.forget(child3)
    668         self.assertRaises(Tkinter.TclError, self.nb.insert, 2, child3)
    669         self.assertRaises(Tkinter.TclError, self.nb.insert, -1, child3)
    670 
    671         # bad inserts
    672         self.assertRaises(Tkinter.TclError, self.nb.insert, 'end', None)
    673         self.assertRaises(Tkinter.TclError, self.nb.insert, None, 0)
    674         self.assertRaises(Tkinter.TclError, self.nb.insert, None, None)
    675 
    676 
    677     def test_select(self):
    678         self.nb.pack()
    679         self.nb.wait_visibility()
    680 
    681         success = []
    682         tab_changed = []
    683 
    684         self.child1.bind('<Unmap>', lambda evt: success.append(True))
    685         self.nb.bind('<<NotebookTabChanged>>',
    686             lambda evt: tab_changed.append(True))
    687 
    688         self.assertEqual(self.nb.select(), str(self.child1))
    689         self.nb.select(self.child2)
    690         self.assertTrue(success)
    691         self.assertEqual(self.nb.select(), str(self.child2))
    692 
    693         self.nb.update()
    694         self.assertTrue(tab_changed)
    695 
    696 
    697     def test_tab(self):
    698         self.assertRaises(Tkinter.TclError, self.nb.tab, -1)
    699         self.assertRaises(Tkinter.TclError, self.nb.tab, 'notab')
    700         self.assertRaises(Tkinter.TclError, self.nb.tab, None)
    701 
    702         self.assertTrue(isinstance(self.nb.tab(self.child1), dict))
    703         self.assertEqual(self.nb.tab(self.child1, text=None), 'a')
    704         # newer form for querying a single option
    705         self.assertEqual(self.nb.tab(self.child1, 'text'), 'a')
    706         self.nb.tab(self.child1, text='abc')
    707         self.assertEqual(self.nb.tab(self.child1, text=None), 'abc')
    708         self.assertEqual(self.nb.tab(self.child1, 'text'), 'abc')
    709 
    710 
    711     def test_tabs(self):
    712         self.assertEqual(len(self.nb.tabs()), 2)
    713 
    714         self.nb.forget(self.child1)
    715         self.nb.forget(self.child2)
    716 
    717         self.assertEqual(self.nb.tabs(), ())
    718 
    719 
    720     def test_traversal(self):
    721         self.nb.pack()
    722         self.nb.wait_visibility()
    723 
    724         self.nb.select(0)
    725 
    726         support.simulate_mouse_click(self.nb, 5, 5)
    727         self.nb.focus_force()
    728         self.nb.event_generate('<Control-Tab>')
    729         self.assertEqual(self.nb.select(), str(self.child2))
    730         self.nb.focus_force()
    731         self.nb.event_generate('<Shift-Control-Tab>')
    732         self.assertEqual(self.nb.select(), str(self.child1))
    733         self.nb.focus_force()
    734         self.nb.event_generate('<Shift-Control-Tab>')
    735         self.assertEqual(self.nb.select(), str(self.child2))
    736 
    737         self.nb.tab(self.child1, text='a', underline=0)
    738         self.nb.enable_traversal()
    739         self.nb.focus_force()
    740         support.simulate_mouse_click(self.nb, 5, 5)
    741         if sys.platform == 'darwin':
    742             self.nb.event_generate('<Option-a>')
    743         else:
    744             self.nb.event_generate('<Alt-a>')
    745         self.assertEqual(self.nb.select(), str(self.child1))
    746 
    747 
    748 class TreeviewTest(unittest.TestCase):
    749 
    750     def setUp(self):
    751         support.root_deiconify()
    752         self.tv = ttk.Treeview(padding=0)
    753 
    754     def tearDown(self):
    755         self.tv.destroy()
    756         support.root_withdraw()
    757 
    758 
    759     def test_bbox(self):
    760         self.tv.pack()
    761         self.assertEqual(self.tv.bbox(''), '')
    762         self.tv.wait_visibility()
    763         self.tv.update()
    764 
    765         item_id = self.tv.insert('', 'end')
    766         children = self.tv.get_children()
    767         self.assertTrue(children)
    768 
    769         bbox = self.tv.bbox(children[0])
    770         self.assertEqual(len(bbox), 4)
    771         self.assertTrue(isinstance(bbox, tuple))
    772         for item in bbox:
    773             if not isinstance(item, int):
    774                 self.fail("Invalid bounding box: %s" % bbox)
    775                 break
    776 
    777         # compare width in bboxes
    778         self.tv['columns'] = ['test']
    779         self.tv.column('test', width=50)
    780         bbox_column0 = self.tv.bbox(children[0], 0)
    781         root_width = self.tv.column('#0', width=None)
    782         self.assertEqual(bbox_column0[0], bbox[0] + root_width)
    783 
    784         # verify that bbox of a closed item is the empty string
    785         child1 = self.tv.insert(item_id, 'end')
    786         self.assertEqual(self.tv.bbox(child1), '')
    787 
    788 
    789     def test_children(self):
    790         # no children yet, should get an empty tuple
    791         self.assertEqual(self.tv.get_children(), ())
    792 
    793         item_id = self.tv.insert('', 'end')
    794         self.assertTrue(isinstance(self.tv.get_children(), tuple))
    795         self.assertEqual(self.tv.get_children()[0], item_id)
    796 
    797         # add item_id and child3 as children of child2
    798         child2 = self.tv.insert('', 'end')
    799         child3 = self.tv.insert('', 'end')
    800         self.tv.set_children(child2, item_id, child3)
    801         self.assertEqual(self.tv.get_children(child2), (item_id, child3))
    802 
    803         # child3 has child2 as parent, thus trying to set child2 as a children
    804         # of child3 should result in an error
    805         self.assertRaises(Tkinter.TclError,
    806             self.tv.set_children, child3, child2)
    807 
    808         # remove child2 children
    809         self.tv.set_children(child2)
    810         self.assertEqual(self.tv.get_children(child2), ())
    811 
    812         # remove root's children
    813         self.tv.set_children('')
    814         self.assertEqual(self.tv.get_children(), ())
    815 
    816 
    817     def test_column(self):
    818         # return a dict with all options/values
    819         self.assertTrue(isinstance(self.tv.column('#0'), dict))
    820         # return a single value of the given option
    821         self.assertTrue(isinstance(self.tv.column('#0', width=None), int))
    822         # set a new value for an option
    823         self.tv.column('#0', width=10)
    824         # testing new way to get option value
    825         self.assertEqual(self.tv.column('#0', 'width'), 10)
    826         self.assertEqual(self.tv.column('#0', width=None), 10)
    827         # check read-only option
    828         self.assertRaises(Tkinter.TclError, self.tv.column, '#0', id='X')
    829 
    830         self.assertRaises(Tkinter.TclError, self.tv.column, 'invalid')
    831         invalid_kws = [
    832             {'unknown_option': 'some value'},  {'stretch': 'wrong'},
    833             {'anchor': 'wrong'}, {'width': 'wrong'}, {'minwidth': 'wrong'}
    834         ]
    835         for kw in invalid_kws:
    836             self.assertRaises(Tkinter.TclError, self.tv.column, '#0',
    837                 **kw)
    838 
    839 
    840     def test_delete(self):
    841         self.assertRaises(Tkinter.TclError, self.tv.delete, '#0')
    842 
    843         item_id = self.tv.insert('', 'end')
    844         item2 = self.tv.insert(item_id, 'end')
    845         self.assertEqual(self.tv.get_children(), (item_id, ))
    846         self.assertEqual(self.tv.get_children(item_id), (item2, ))
    847 
    848         self.tv.delete(item_id)
    849         self.assertFalse(self.tv.get_children())
    850 
    851         # reattach should fail
    852         self.assertRaises(Tkinter.TclError,
    853             self.tv.reattach, item_id, '', 'end')
    854 
    855         # test multiple item delete
    856         item1 = self.tv.insert('', 'end')
    857         item2 = self.tv.insert('', 'end')
    858         self.assertEqual(self.tv.get_children(), (item1, item2))
    859 
    860         self.tv.delete(item1, item2)
    861         self.assertFalse(self.tv.get_children())
    862 
    863 
    864     def test_detach_reattach(self):
    865         item_id = self.tv.insert('', 'end')
    866         item2 = self.tv.insert(item_id, 'end')
    867 
    868         # calling detach without items is valid, although it does nothing
    869         prev = self.tv.get_children()
    870         self.tv.detach() # this should do nothing
    871         self.assertEqual(prev, self.tv.get_children())
    872 
    873         self.assertEqual(self.tv.get_children(), (item_id, ))
    874         self.assertEqual(self.tv.get_children(item_id), (item2, ))
    875 
    876         # detach item with children
    877         self.tv.detach(item_id)
    878         self.assertFalse(self.tv.get_children())
    879 
    880         # reattach item with children
    881         self.tv.reattach(item_id, '', 'end')
    882         self.assertEqual(self.tv.get_children(), (item_id, ))
    883         self.assertEqual(self.tv.get_children(item_id), (item2, ))
    884 
    885         # move a children to the root
    886         self.tv.move(item2, '', 'end')
    887         self.assertEqual(self.tv.get_children(), (item_id, item2))
    888         self.assertEqual(self.tv.get_children(item_id), ())
    889 
    890         # bad values
    891         self.assertRaises(Tkinter.TclError,
    892             self.tv.reattach, 'nonexistent', '', 'end')
    893         self.assertRaises(Tkinter.TclError,
    894             self.tv.detach, 'nonexistent')
    895         self.assertRaises(Tkinter.TclError,
    896             self.tv.reattach, item2, 'otherparent', 'end')
    897         self.assertRaises(Tkinter.TclError,
    898             self.tv.reattach, item2, '', 'invalid')
    899 
    900         # multiple detach
    901         self.tv.detach(item_id, item2)
    902         self.assertEqual(self.tv.get_children(), ())
    903         self.assertEqual(self.tv.get_children(item_id), ())
    904 
    905 
    906     def test_exists(self):
    907         self.assertEqual(self.tv.exists('something'), False)
    908         self.assertEqual(self.tv.exists(''), True)
    909         self.assertEqual(self.tv.exists({}), False)
    910 
    911         # the following will make a tk.call equivalent to
    912         # tk.call(treeview, "exists") which should result in an error
    913         # in the tcl interpreter since tk requires an item.
    914         self.assertRaises(Tkinter.TclError, self.tv.exists, None)
    915 
    916 
    917     def test_focus(self):
    918         # nothing is focused right now
    919         self.assertEqual(self.tv.focus(), '')
    920 
    921         item1 = self.tv.insert('', 'end')
    922         self.tv.focus(item1)
    923         self.assertEqual(self.tv.focus(), item1)
    924 
    925         self.tv.delete(item1)
    926         self.assertEqual(self.tv.focus(), '')
    927 
    928         # try focusing inexistent item
    929         self.assertRaises(Tkinter.TclError, self.tv.focus, 'hi')
    930 
    931 
    932     def test_heading(self):
    933         # check a dict is returned
    934         self.assertTrue(isinstance(self.tv.heading('#0'), dict))
    935 
    936         # check a value is returned
    937         self.tv.heading('#0', text='hi')
    938         self.assertEqual(self.tv.heading('#0', 'text'), 'hi')
    939         self.assertEqual(self.tv.heading('#0', text=None), 'hi')
    940 
    941         # invalid option
    942         self.assertRaises(Tkinter.TclError, self.tv.heading, '#0',
    943             background=None)
    944         # invalid value
    945         self.assertRaises(Tkinter.TclError, self.tv.heading, '#0',
    946             anchor=1)
    947 
    948     # XXX skipping for now; should be fixed to work with newer ttk
    949     @unittest.skip("skipping pending resolution of Issue #10734")
    950     def test_heading_callback(self):
    951         def simulate_heading_click(x, y):
    952             support.simulate_mouse_click(self.tv, x, y)
    953             self.tv.update_idletasks()
    954 
    955         success = [] # no success for now
    956 
    957         self.tv.pack()
    958         self.tv.wait_visibility()
    959         self.tv.heading('#0', command=lambda: success.append(True))
    960         self.tv.column('#0', width=100)
    961         self.tv.update()
    962 
    963         # assuming that the coords (5, 5) fall into heading #0
    964         simulate_heading_click(5, 5)
    965         if not success:
    966             self.fail("The command associated to the treeview heading wasn't "
    967                 "invoked.")
    968 
    969         success = []
    970         commands = self.tv.master._tclCommands
    971         self.tv.heading('#0', command=str(self.tv.heading('#0', command=None)))
    972         self.assertEqual(commands, self.tv.master._tclCommands)
    973         simulate_heading_click(5, 5)
    974         if not success:
    975             self.fail("The command associated to the treeview heading wasn't "
    976                 "invoked.")
    977 
    978         # XXX The following raises an error in a tcl interpreter, but not in
    979         # Python
    980         #self.tv.heading('#0', command='I dont exist')
    981         #simulate_heading_click(5, 5)
    982 
    983 
    984     def test_index(self):
    985         # item 'what' doesn't exist
    986         self.assertRaises(Tkinter.TclError, self.tv.index, 'what')
    987 
    988         self.assertEqual(self.tv.index(''), 0)
    989 
    990         item1 = self.tv.insert('', 'end')
    991         item2 = self.tv.insert('', 'end')
    992         c1 = self.tv.insert(item1, 'end')
    993         c2 = self.tv.insert(item1, 'end')
    994         self.assertEqual(self.tv.index(item1), 0)
    995         self.assertEqual(self.tv.index(c1), 0)
    996         self.assertEqual(self.tv.index(c2), 1)
    997         self.assertEqual(self.tv.index(item2), 1)
    998 
    999         self.tv.move(item2, '', 0)
   1000         self.assertEqual(self.tv.index(item2), 0)
   1001         self.assertEqual(self.tv.index(item1), 1)
   1002 
   1003         # check that index still works even after its parent and siblings
   1004         # have been detached
   1005         self.tv.detach(item1)
   1006         self.assertEqual(self.tv.index(c2), 1)
   1007         self.tv.detach(c1)
   1008         self.assertEqual(self.tv.index(c2), 0)
   1009 
   1010         # but it fails after item has been deleted
   1011         self.tv.delete(item1)
   1012         self.assertRaises(Tkinter.TclError, self.tv.index, c2)
   1013 
   1014 
   1015     def test_insert_item(self):
   1016         # parent 'none' doesn't exist
   1017         self.assertRaises(Tkinter.TclError, self.tv.insert, 'none', 'end')
   1018 
   1019         # open values
   1020         self.assertRaises(Tkinter.TclError, self.tv.insert, '', 'end',
   1021             open='')
   1022         self.assertRaises(Tkinter.TclError, self.tv.insert, '', 'end',
   1023             open='please')
   1024         self.assertFalse(self.tv.delete(self.tv.insert('', 'end', open=True)))
   1025         self.assertFalse(self.tv.delete(self.tv.insert('', 'end', open=False)))
   1026 
   1027         # invalid index
   1028         self.assertRaises(Tkinter.TclError, self.tv.insert, '', 'middle')
   1029 
   1030         # trying to duplicate item id is invalid
   1031         itemid = self.tv.insert('', 'end', 'first-item')
   1032         self.assertEqual(itemid, 'first-item')
   1033         self.assertRaises(Tkinter.TclError, self.tv.insert, '', 'end',
   1034             'first-item')
   1035         self.assertRaises(Tkinter.TclError, self.tv.insert, '', 'end',
   1036             MockTclObj('first-item'))
   1037 
   1038         # unicode values
   1039         value = u'\xe1ba'
   1040         item = self.tv.insert('', 'end', values=(value, ))
   1041         self.assertEqual(self.tv.item(item, 'values'), (value, ))
   1042         self.assertEqual(self.tv.item(item, values=None), (value, ))
   1043 
   1044         self.tv.item(item, values=list(self.tv.item(item, values=None)))
   1045         self.assertEqual(self.tv.item(item, values=None), (value, ))
   1046 
   1047         self.assertTrue(isinstance(self.tv.item(item), dict))
   1048 
   1049         # erase item values
   1050         self.tv.item(item, values='')
   1051         self.assertFalse(self.tv.item(item, values=None))
   1052 
   1053         # item tags
   1054         item = self.tv.insert('', 'end', tags=[1, 2, value])
   1055         self.assertEqual(self.tv.item(item, tags=None), ('1', '2', value))
   1056         self.tv.item(item, tags=[])
   1057         self.assertFalse(self.tv.item(item, tags=None))
   1058         self.tv.item(item, tags=(1, 2))
   1059         self.assertEqual(self.tv.item(item, tags=None), ('1', '2'))
   1060 
   1061         # values with spaces
   1062         item = self.tv.insert('', 'end', values=('a b c',
   1063             '%s %s' % (value, value)))
   1064         self.assertEqual(self.tv.item(item, values=None),
   1065             ('a b c', '%s %s' % (value, value)))
   1066 
   1067         # text
   1068         self.assertEqual(self.tv.item(
   1069             self.tv.insert('', 'end', text="Label here"), text=None),
   1070             "Label here")
   1071         self.assertEqual(self.tv.item(
   1072             self.tv.insert('', 'end', text=value), text=None),
   1073             value)
   1074 
   1075 
   1076     def test_set(self):
   1077         self.tv['columns'] = ['A', 'B']
   1078         item = self.tv.insert('', 'end', values=['a', 'b'])
   1079         self.assertEqual(self.tv.set(item), {'A': 'a', 'B': 'b'})
   1080 
   1081         self.tv.set(item, 'B', 'a')
   1082         self.assertEqual(self.tv.item(item, values=None), ('a', 'a'))
   1083 
   1084         self.tv['columns'] = ['B']
   1085         self.assertEqual(self.tv.set(item), {'B': 'a'})
   1086 
   1087         self.tv.set(item, 'B', 'b')
   1088         self.assertEqual(self.tv.set(item, column='B'), 'b')
   1089         self.assertEqual(self.tv.item(item, values=None), ('b', 'a'))
   1090 
   1091         self.tv.set(item, 'B', 123)
   1092         self.assertEqual(self.tv.set(item, 'B'), 123)
   1093         self.assertEqual(self.tv.item(item, values=None), (123, 'a'))
   1094         self.assertEqual(self.tv.set(item), {'B': 123})
   1095 
   1096         # inexistent column
   1097         self.assertRaises(Tkinter.TclError, self.tv.set, item, 'A')
   1098         self.assertRaises(Tkinter.TclError, self.tv.set, item, 'A', 'b')
   1099 
   1100         # inexistent item
   1101         self.assertRaises(Tkinter.TclError, self.tv.set, 'notme')
   1102 
   1103 
   1104     def test_tag_bind(self):
   1105         events = []
   1106         item1 = self.tv.insert('', 'end', tags=['call'])
   1107         item2 = self.tv.insert('', 'end', tags=['call'])
   1108         self.tv.tag_bind('call', '<ButtonPress-1>',
   1109             lambda evt: events.append(1))
   1110         self.tv.tag_bind('call', '<ButtonRelease-1>',
   1111             lambda evt: events.append(2))
   1112 
   1113         self.tv.pack()
   1114         self.tv.wait_visibility()
   1115         self.tv.update()
   1116 
   1117         pos_y = set()
   1118         found = set()
   1119         for i in range(0, 100, 10):
   1120             if len(found) == 2: # item1 and item2 already found
   1121                 break
   1122             item_id = self.tv.identify_row(i)
   1123             if item_id and item_id not in found:
   1124                 pos_y.add(i)
   1125                 found.add(item_id)
   1126 
   1127         self.assertEqual(len(pos_y), 2) # item1 and item2 y pos
   1128         for y in pos_y:
   1129             support.simulate_mouse_click(self.tv, 0, y)
   1130 
   1131         # by now there should be 4 things in the events list, since each
   1132         # item had a bind for two events that were simulated above
   1133         self.assertEqual(len(events), 4)
   1134         for evt in zip(events[::2], events[1::2]):
   1135             self.assertEqual(evt, (1, 2))
   1136 
   1137 
   1138     def test_tag_configure(self):
   1139         # Just testing parameter passing for now
   1140         self.assertRaises(TypeError, self.tv.tag_configure)
   1141         self.assertRaises(Tkinter.TclError, self.tv.tag_configure,
   1142             'test', sky='blue')
   1143         self.tv.tag_configure('test', foreground='blue')
   1144         self.assertEqual(str(self.tv.tag_configure('test', 'foreground')),
   1145             'blue')
   1146         self.assertEqual(str(self.tv.tag_configure('test', foreground=None)),
   1147             'blue')
   1148         self.assertTrue(isinstance(self.tv.tag_configure('test'), dict))
   1149 
   1150 
   1151 tests_gui = (
   1152         WidgetTest, ButtonTest, CheckbuttonTest, RadiobuttonTest,
   1153         ComboboxTest, EntryTest, PanedwindowTest, ScaleTest, NotebookTest,
   1154         TreeviewTest
   1155         )
   1156 
   1157 if __name__ == "__main__":
   1158     run_unittest(*tests_gui)
   1159