Home | History | Annotate | Download | only in test_tkinter
      1 import unittest
      2 import tkinter
      3 from tkinter import TclError
      4 import os
      5 import sys
      6 from test.support import requires
      7 
      8 from tkinter.test.support import (tcl_version, requires_tcl,
      9                                   get_tk_patchlevel, widget_eq)
     10 from tkinter.test.widget_tests import (
     11     add_standard_options, noconv, pixels_round,
     12     AbstractWidgetTest, StandardOptionsTests, IntegerSizeTests, PixelSizeTests,
     13     setUpModule)
     14 
     15 requires('gui')
     16 
     17 
     18 def float_round(x):
     19     return float(round(x))
     20 
     21 
     22 class AbstractToplevelTest(AbstractWidgetTest, PixelSizeTests):
     23     _conv_pad_pixels = noconv
     24 
     25     def test_class(self):
     26         widget = self.create()
     27         self.assertEqual(widget['class'],
     28                          widget.__class__.__name__.title())
     29         self.checkInvalidParam(widget, 'class', 'Foo',
     30                 errmsg="can't modify -class option after widget is created")
     31         widget2 = self.create(class_='Foo')
     32         self.assertEqual(widget2['class'], 'Foo')
     33 
     34     def test_colormap(self):
     35         widget = self.create()
     36         self.assertEqual(widget['colormap'], '')
     37         self.checkInvalidParam(widget, 'colormap', 'new',
     38                 errmsg="can't modify -colormap option after widget is created")
     39         widget2 = self.create(colormap='new')
     40         self.assertEqual(widget2['colormap'], 'new')
     41 
     42     def test_container(self):
     43         widget = self.create()
     44         self.assertEqual(widget['container'], 0 if self.wantobjects else '0')
     45         self.checkInvalidParam(widget, 'container', 1,
     46                 errmsg="can't modify -container option after widget is created")
     47         widget2 = self.create(container=True)
     48         self.assertEqual(widget2['container'], 1 if self.wantobjects else '1')
     49 
     50     def test_visual(self):
     51         widget = self.create()
     52         self.assertEqual(widget['visual'], '')
     53         self.checkInvalidParam(widget, 'visual', 'default',
     54                 errmsg="can't modify -visual option after widget is created")
     55         widget2 = self.create(visual='default')
     56         self.assertEqual(widget2['visual'], 'default')
     57 
     58 
     59 @add_standard_options(StandardOptionsTests)
     60 class ToplevelTest(AbstractToplevelTest, unittest.TestCase):
     61     OPTIONS = (
     62         'background', 'borderwidth',
     63         'class', 'colormap', 'container', 'cursor', 'height',
     64         'highlightbackground', 'highlightcolor', 'highlightthickness',
     65         'menu', 'padx', 'pady', 'relief', 'screen',
     66         'takefocus', 'use', 'visual', 'width',
     67     )
     68 
     69     def create(self, **kwargs):
     70         return tkinter.Toplevel(self.root, **kwargs)
     71 
     72     def test_menu(self):
     73         widget = self.create()
     74         menu = tkinter.Menu(self.root)
     75         self.checkParam(widget, 'menu', menu, eq=widget_eq)
     76         self.checkParam(widget, 'menu', '')
     77 
     78     def test_screen(self):
     79         widget = self.create()
     80         self.assertEqual(widget['screen'], '')
     81         try:
     82             display = os.environ['DISPLAY']
     83         except KeyError:
     84             self.skipTest('No $DISPLAY set.')
     85         self.checkInvalidParam(widget, 'screen', display,
     86                 errmsg="can't modify -screen option after widget is created")
     87         widget2 = self.create(screen=display)
     88         self.assertEqual(widget2['screen'], display)
     89 
     90     def test_use(self):
     91         widget = self.create()
     92         self.assertEqual(widget['use'], '')
     93         parent = self.create(container=True)
     94         wid = hex(parent.winfo_id())
     95         with self.subTest(wid=wid):
     96             widget2 = self.create(use=wid)
     97             self.assertEqual(widget2['use'], wid)
     98 
     99 
    100 @add_standard_options(StandardOptionsTests)
    101 class FrameTest(AbstractToplevelTest, unittest.TestCase):
    102     OPTIONS = (
    103         'background', 'borderwidth',
    104         'class', 'colormap', 'container', 'cursor', 'height',
    105         'highlightbackground', 'highlightcolor', 'highlightthickness',
    106         'padx', 'pady', 'relief', 'takefocus', 'visual', 'width',
    107     )
    108 
    109     def create(self, **kwargs):
    110         return tkinter.Frame(self.root, **kwargs)
    111 
    112 
    113 @add_standard_options(StandardOptionsTests)
    114 class LabelFrameTest(AbstractToplevelTest, unittest.TestCase):
    115     OPTIONS = (
    116         'background', 'borderwidth',
    117         'class', 'colormap', 'container', 'cursor',
    118         'font', 'foreground', 'height',
    119         'highlightbackground', 'highlightcolor', 'highlightthickness',
    120         'labelanchor', 'labelwidget', 'padx', 'pady', 'relief',
    121         'takefocus', 'text', 'visual', 'width',
    122     )
    123 
    124     def create(self, **kwargs):
    125         return tkinter.LabelFrame(self.root, **kwargs)
    126 
    127     def test_labelanchor(self):
    128         widget = self.create()
    129         self.checkEnumParam(widget, 'labelanchor',
    130                             'e', 'en', 'es', 'n', 'ne', 'nw',
    131                             's', 'se', 'sw', 'w', 'wn', 'ws')
    132         self.checkInvalidParam(widget, 'labelanchor', 'center')
    133 
    134     def test_labelwidget(self):
    135         widget = self.create()
    136         label = tkinter.Label(self.root, text='Mupp', name='foo')
    137         self.checkParam(widget, 'labelwidget', label, expected='.foo')
    138         label.destroy()
    139 
    140 
    141 class AbstractLabelTest(AbstractWidgetTest, IntegerSizeTests):
    142     _conv_pixels = noconv
    143 
    144     def test_highlightthickness(self):
    145         widget = self.create()
    146         self.checkPixelsParam(widget, 'highlightthickness',
    147                               0, 1.3, 2.6, 6, -2, '10p')
    148 
    149 
    150 @add_standard_options(StandardOptionsTests)
    151 class LabelTest(AbstractLabelTest, unittest.TestCase):
    152     OPTIONS = (
    153         'activebackground', 'activeforeground', 'anchor',
    154         'background', 'bitmap', 'borderwidth', 'compound', 'cursor',
    155         'disabledforeground', 'font', 'foreground', 'height',
    156         'highlightbackground', 'highlightcolor', 'highlightthickness',
    157         'image', 'justify', 'padx', 'pady', 'relief', 'state',
    158         'takefocus', 'text', 'textvariable',
    159         'underline', 'width', 'wraplength',
    160     )
    161 
    162     def create(self, **kwargs):
    163         return tkinter.Label(self.root, **kwargs)
    164 
    165 
    166 @add_standard_options(StandardOptionsTests)
    167 class ButtonTest(AbstractLabelTest, unittest.TestCase):
    168     OPTIONS = (
    169         'activebackground', 'activeforeground', 'anchor',
    170         'background', 'bitmap', 'borderwidth',
    171         'command', 'compound', 'cursor', 'default',
    172         'disabledforeground', 'font', 'foreground', 'height',
    173         'highlightbackground', 'highlightcolor', 'highlightthickness',
    174         'image', 'justify', 'overrelief', 'padx', 'pady', 'relief',
    175         'repeatdelay', 'repeatinterval',
    176         'state', 'takefocus', 'text', 'textvariable',
    177         'underline', 'width', 'wraplength')
    178 
    179     def create(self, **kwargs):
    180         return tkinter.Button(self.root, **kwargs)
    181 
    182     def test_default(self):
    183         widget = self.create()
    184         self.checkEnumParam(widget, 'default', 'active', 'disabled', 'normal')
    185 
    186 
    187 @add_standard_options(StandardOptionsTests)
    188 class CheckbuttonTest(AbstractLabelTest, unittest.TestCase):
    189     OPTIONS = (
    190         'activebackground', 'activeforeground', 'anchor',
    191         'background', 'bitmap', 'borderwidth',
    192         'command', 'compound', 'cursor',
    193         'disabledforeground', 'font', 'foreground', 'height',
    194         'highlightbackground', 'highlightcolor', 'highlightthickness',
    195         'image', 'indicatoron', 'justify',
    196         'offrelief', 'offvalue', 'onvalue', 'overrelief',
    197         'padx', 'pady', 'relief', 'selectcolor', 'selectimage', 'state',
    198         'takefocus', 'text', 'textvariable',
    199         'tristateimage', 'tristatevalue',
    200         'underline', 'variable', 'width', 'wraplength',
    201     )
    202 
    203     def create(self, **kwargs):
    204         return tkinter.Checkbutton(self.root, **kwargs)
    205 
    206 
    207     def test_offvalue(self):
    208         widget = self.create()
    209         self.checkParams(widget, 'offvalue', 1, 2.3, '', 'any string')
    210 
    211     def test_onvalue(self):
    212         widget = self.create()
    213         self.checkParams(widget, 'onvalue', 1, 2.3, '', 'any string')
    214 
    215 
    216 @add_standard_options(StandardOptionsTests)
    217 class RadiobuttonTest(AbstractLabelTest, unittest.TestCase):
    218     OPTIONS = (
    219         'activebackground', 'activeforeground', 'anchor',
    220         'background', 'bitmap', 'borderwidth',
    221         'command', 'compound', 'cursor',
    222         'disabledforeground', 'font', 'foreground', 'height',
    223         'highlightbackground', 'highlightcolor', 'highlightthickness',
    224         'image', 'indicatoron', 'justify', 'offrelief', 'overrelief',
    225         'padx', 'pady', 'relief', 'selectcolor', 'selectimage', 'state',
    226         'takefocus', 'text', 'textvariable',
    227         'tristateimage', 'tristatevalue',
    228         'underline', 'value', 'variable', 'width', 'wraplength',
    229     )
    230 
    231     def create(self, **kwargs):
    232         return tkinter.Radiobutton(self.root, **kwargs)
    233 
    234     def test_value(self):
    235         widget = self.create()
    236         self.checkParams(widget, 'value', 1, 2.3, '', 'any string')
    237 
    238 
    239 @add_standard_options(StandardOptionsTests)
    240 class MenubuttonTest(AbstractLabelTest, unittest.TestCase):
    241     OPTIONS = (
    242         'activebackground', 'activeforeground', 'anchor',
    243         'background', 'bitmap', 'borderwidth',
    244         'compound', 'cursor', 'direction',
    245         'disabledforeground', 'font', 'foreground', 'height',
    246         'highlightbackground', 'highlightcolor', 'highlightthickness',
    247         'image', 'indicatoron', 'justify', 'menu',
    248         'padx', 'pady', 'relief', 'state',
    249         'takefocus', 'text', 'textvariable',
    250         'underline', 'width', 'wraplength',
    251     )
    252     _conv_pixels = staticmethod(pixels_round)
    253 
    254     def create(self, **kwargs):
    255         return tkinter.Menubutton(self.root, **kwargs)
    256 
    257     def test_direction(self):
    258         widget = self.create()
    259         self.checkEnumParam(widget, 'direction',
    260                 'above', 'below', 'flush', 'left', 'right')
    261 
    262     def test_height(self):
    263         widget = self.create()
    264         self.checkIntegerParam(widget, 'height', 100, -100, 0, conv=str)
    265 
    266     test_highlightthickness = StandardOptionsTests.test_highlightthickness
    267 
    268     @unittest.skipIf(sys.platform == 'darwin',
    269                      'crashes with Cocoa Tk (issue19733)')
    270     def test_image(self):
    271         widget = self.create()
    272         image = tkinter.PhotoImage(master=self.root, name='image1')
    273         self.checkParam(widget, 'image', image, conv=str)
    274         errmsg = 'image "spam" doesn\'t exist'
    275         with self.assertRaises(tkinter.TclError) as cm:
    276             widget['image'] = 'spam'
    277         if errmsg is not None:
    278             self.assertEqual(str(cm.exception), errmsg)
    279         with self.assertRaises(tkinter.TclError) as cm:
    280             widget.configure({'image': 'spam'})
    281         if errmsg is not None:
    282             self.assertEqual(str(cm.exception), errmsg)
    283 
    284     def test_menu(self):
    285         widget = self.create()
    286         menu = tkinter.Menu(widget, name='menu')
    287         self.checkParam(widget, 'menu', menu, eq=widget_eq)
    288         menu.destroy()
    289 
    290     def test_padx(self):
    291         widget = self.create()
    292         self.checkPixelsParam(widget, 'padx', 3, 4.4, 5.6, '12m')
    293         self.checkParam(widget, 'padx', -2, expected=0)
    294 
    295     def test_pady(self):
    296         widget = self.create()
    297         self.checkPixelsParam(widget, 'pady', 3, 4.4, 5.6, '12m')
    298         self.checkParam(widget, 'pady', -2, expected=0)
    299 
    300     def test_width(self):
    301         widget = self.create()
    302         self.checkIntegerParam(widget, 'width', 402, -402, 0, conv=str)
    303 
    304 
    305 class OptionMenuTest(MenubuttonTest, unittest.TestCase):
    306 
    307     def create(self, default='b', values=('a', 'b', 'c'), **kwargs):
    308         return tkinter.OptionMenu(self.root, None, default, *values, **kwargs)
    309 
    310 
    311 @add_standard_options(IntegerSizeTests, StandardOptionsTests)
    312 class EntryTest(AbstractWidgetTest, unittest.TestCase):
    313     OPTIONS = (
    314         'background', 'borderwidth', 'cursor',
    315         'disabledbackground', 'disabledforeground',
    316         'exportselection', 'font', 'foreground',
    317         'highlightbackground', 'highlightcolor', 'highlightthickness',
    318         'insertbackground', 'insertborderwidth',
    319         'insertofftime', 'insertontime', 'insertwidth',
    320         'invalidcommand', 'justify', 'readonlybackground', 'relief',
    321         'selectbackground', 'selectborderwidth', 'selectforeground',
    322         'show', 'state', 'takefocus', 'textvariable',
    323         'validate', 'validatecommand', 'width', 'xscrollcommand',
    324     )
    325 
    326     def create(self, **kwargs):
    327         return tkinter.Entry(self.root, **kwargs)
    328 
    329     def test_disabledbackground(self):
    330         widget = self.create()
    331         self.checkColorParam(widget, 'disabledbackground')
    332 
    333     def test_insertborderwidth(self):
    334         widget = self.create(insertwidth=100)
    335         self.checkPixelsParam(widget, 'insertborderwidth',
    336                               0, 1.3, 2.6, 6, -2, '10p')
    337         # insertborderwidth is bounded above by a half of insertwidth.
    338         self.checkParam(widget, 'insertborderwidth', 60, expected=100//2)
    339 
    340     def test_insertwidth(self):
    341         widget = self.create()
    342         self.checkPixelsParam(widget, 'insertwidth', 1.3, 3.6, '10p')
    343         self.checkParam(widget, 'insertwidth', 0.1, expected=2)
    344         self.checkParam(widget, 'insertwidth', -2, expected=2)
    345         if pixels_round(0.9) <= 0:
    346             self.checkParam(widget, 'insertwidth', 0.9, expected=2)
    347         else:
    348             self.checkParam(widget, 'insertwidth', 0.9, expected=1)
    349 
    350     def test_invalidcommand(self):
    351         widget = self.create()
    352         self.checkCommandParam(widget, 'invalidcommand')
    353         self.checkCommandParam(widget, 'invcmd')
    354 
    355     def test_readonlybackground(self):
    356         widget = self.create()
    357         self.checkColorParam(widget, 'readonlybackground')
    358 
    359     def test_show(self):
    360         widget = self.create()
    361         self.checkParam(widget, 'show', '*')
    362         self.checkParam(widget, 'show', '')
    363         self.checkParam(widget, 'show', ' ')
    364 
    365     def test_state(self):
    366         widget = self.create()
    367         self.checkEnumParam(widget, 'state',
    368                             'disabled', 'normal', 'readonly')
    369 
    370     def test_validate(self):
    371         widget = self.create()
    372         self.checkEnumParam(widget, 'validate',
    373                 'all', 'key', 'focus', 'focusin', 'focusout', 'none')
    374 
    375     def test_validatecommand(self):
    376         widget = self.create()
    377         self.checkCommandParam(widget, 'validatecommand')
    378         self.checkCommandParam(widget, 'vcmd')
    379 
    380 
    381 @add_standard_options(StandardOptionsTests)
    382 class SpinboxTest(EntryTest, unittest.TestCase):
    383     OPTIONS = (
    384         'activebackground', 'background', 'borderwidth',
    385         'buttonbackground', 'buttoncursor', 'buttondownrelief', 'buttonuprelief',
    386         'command', 'cursor', 'disabledbackground', 'disabledforeground',
    387         'exportselection', 'font', 'foreground', 'format', 'from',
    388         'highlightbackground', 'highlightcolor', 'highlightthickness',
    389         'increment',
    390         'insertbackground', 'insertborderwidth',
    391         'insertofftime', 'insertontime', 'insertwidth',
    392         'invalidcommand', 'justify', 'relief', 'readonlybackground',
    393         'repeatdelay', 'repeatinterval',
    394         'selectbackground', 'selectborderwidth', 'selectforeground',
    395         'state', 'takefocus', 'textvariable', 'to',
    396         'validate', 'validatecommand', 'values',
    397         'width', 'wrap', 'xscrollcommand',
    398     )
    399 
    400     def create(self, **kwargs):
    401         return tkinter.Spinbox(self.root, **kwargs)
    402 
    403     test_show = None
    404 
    405     def test_buttonbackground(self):
    406         widget = self.create()
    407         self.checkColorParam(widget, 'buttonbackground')
    408 
    409     def test_buttoncursor(self):
    410         widget = self.create()
    411         self.checkCursorParam(widget, 'buttoncursor')
    412 
    413     def test_buttondownrelief(self):
    414         widget = self.create()
    415         self.checkReliefParam(widget, 'buttondownrelief')
    416 
    417     def test_buttonuprelief(self):
    418         widget = self.create()
    419         self.checkReliefParam(widget, 'buttonuprelief')
    420 
    421     def test_format(self):
    422         widget = self.create()
    423         self.checkParam(widget, 'format', '%2f')
    424         self.checkParam(widget, 'format', '%2.2f')
    425         self.checkParam(widget, 'format', '%.2f')
    426         self.checkParam(widget, 'format', '%2.f')
    427         self.checkInvalidParam(widget, 'format', '%2e-1f')
    428         self.checkInvalidParam(widget, 'format', '2.2')
    429         self.checkInvalidParam(widget, 'format', '%2.-2f')
    430         self.checkParam(widget, 'format', '%-2.02f')
    431         self.checkParam(widget, 'format', '% 2.02f')
    432         self.checkParam(widget, 'format', '% -2.200f')
    433         self.checkParam(widget, 'format', '%09.200f')
    434         self.checkInvalidParam(widget, 'format', '%d')
    435 
    436     def test_from(self):
    437         widget = self.create()
    438         self.checkParam(widget, 'to', 100.0)
    439         self.checkFloatParam(widget, 'from', -10, 10.2, 11.7)
    440         self.checkInvalidParam(widget, 'from', 200,
    441                 errmsg='-to value must be greater than -from value')
    442 
    443     def test_increment(self):
    444         widget = self.create()
    445         self.checkFloatParam(widget, 'increment', -1, 1, 10.2, 12.8, 0)
    446 
    447     def test_to(self):
    448         widget = self.create()
    449         self.checkParam(widget, 'from', -100.0)
    450         self.checkFloatParam(widget, 'to', -10, 10.2, 11.7)
    451         self.checkInvalidParam(widget, 'to', -200,
    452                 errmsg='-to value must be greater than -from value')
    453 
    454     def test_values(self):
    455         # XXX
    456         widget = self.create()
    457         self.assertEqual(widget['values'], '')
    458         self.checkParam(widget, 'values', 'mon tue wed thur')
    459         self.checkParam(widget, 'values', ('mon', 'tue', 'wed', 'thur'),
    460                         expected='mon tue wed thur')
    461         self.checkParam(widget, 'values', (42, 3.14, '', 'any string'),
    462                         expected='42 3.14 {} {any string}')
    463         self.checkParam(widget, 'values', '')
    464 
    465     def test_wrap(self):
    466         widget = self.create()
    467         self.checkBooleanParam(widget, 'wrap')
    468 
    469     def test_bbox(self):
    470         widget = self.create()
    471         self.assertIsBoundingBox(widget.bbox(0))
    472         self.assertRaises(tkinter.TclError, widget.bbox, 'noindex')
    473         self.assertRaises(tkinter.TclError, widget.bbox, None)
    474         self.assertRaises(TypeError, widget.bbox)
    475         self.assertRaises(TypeError, widget.bbox, 0, 1)
    476 
    477     def test_selection_element(self):
    478         widget = self.create()
    479         self.assertEqual(widget.selection_element(), "none")
    480         widget.selection_element("buttonup")
    481         self.assertEqual(widget.selection_element(), "buttonup")
    482         widget.selection_element("buttondown")
    483         self.assertEqual(widget.selection_element(), "buttondown")
    484 
    485 
    486 @add_standard_options(StandardOptionsTests)
    487 class TextTest(AbstractWidgetTest, unittest.TestCase):
    488     OPTIONS = (
    489         'autoseparators', 'background', 'blockcursor', 'borderwidth',
    490         'cursor', 'endline', 'exportselection',
    491         'font', 'foreground', 'height',
    492         'highlightbackground', 'highlightcolor', 'highlightthickness',
    493         'inactiveselectbackground', 'insertbackground', 'insertborderwidth',
    494         'insertofftime', 'insertontime', 'insertunfocussed', 'insertwidth',
    495         'maxundo', 'padx', 'pady', 'relief',
    496         'selectbackground', 'selectborderwidth', 'selectforeground',
    497         'setgrid', 'spacing1', 'spacing2', 'spacing3', 'startline', 'state',
    498         'tabs', 'tabstyle', 'takefocus', 'undo', 'width', 'wrap',
    499         'xscrollcommand', 'yscrollcommand',
    500     )
    501     if tcl_version < (8, 5):
    502         _stringify = True
    503 
    504     def create(self, **kwargs):
    505         return tkinter.Text(self.root, **kwargs)
    506 
    507     def test_autoseparators(self):
    508         widget = self.create()
    509         self.checkBooleanParam(widget, 'autoseparators')
    510 
    511     @requires_tcl(8, 5)
    512     def test_blockcursor(self):
    513         widget = self.create()
    514         self.checkBooleanParam(widget, 'blockcursor')
    515 
    516     @requires_tcl(8, 5)
    517     def test_endline(self):
    518         widget = self.create()
    519         text = '\n'.join('Line %d' for i in range(100))
    520         widget.insert('end', text)
    521         self.checkParam(widget, 'endline', 200, expected='')
    522         self.checkParam(widget, 'endline', -10, expected='')
    523         self.checkInvalidParam(widget, 'endline', 'spam',
    524                 errmsg='expected integer but got "spam"')
    525         self.checkParam(widget, 'endline', 50)
    526         self.checkParam(widget, 'startline', 15)
    527         self.checkInvalidParam(widget, 'endline', 10,
    528                 errmsg='-startline must be less than or equal to -endline')
    529 
    530     def test_height(self):
    531         widget = self.create()
    532         self.checkPixelsParam(widget, 'height', 100, 101.2, 102.6, '3c')
    533         self.checkParam(widget, 'height', -100, expected=1)
    534         self.checkParam(widget, 'height', 0, expected=1)
    535 
    536     def test_maxundo(self):
    537         widget = self.create()
    538         self.checkIntegerParam(widget, 'maxundo', 0, 5, -1)
    539 
    540     @requires_tcl(8, 5)
    541     def test_inactiveselectbackground(self):
    542         widget = self.create()
    543         self.checkColorParam(widget, 'inactiveselectbackground')
    544 
    545     @requires_tcl(8, 6)
    546     def test_insertunfocussed(self):
    547         widget = self.create()
    548         self.checkEnumParam(widget, 'insertunfocussed',
    549                             'hollow', 'none', 'solid')
    550 
    551     def test_selectborderwidth(self):
    552         widget = self.create()
    553         self.checkPixelsParam(widget, 'selectborderwidth',
    554                               1.3, 2.6, -2, '10p', conv=noconv,
    555                               keep_orig=tcl_version >= (8, 5))
    556 
    557     def test_spacing1(self):
    558         widget = self.create()
    559         self.checkPixelsParam(widget, 'spacing1', 20, 21.4, 22.6, '0.5c')
    560         self.checkParam(widget, 'spacing1', -5, expected=0)
    561 
    562     def test_spacing2(self):
    563         widget = self.create()
    564         self.checkPixelsParam(widget, 'spacing2', 5, 6.4, 7.6, '0.1c')
    565         self.checkParam(widget, 'spacing2', -1, expected=0)
    566 
    567     def test_spacing3(self):
    568         widget = self.create()
    569         self.checkPixelsParam(widget, 'spacing3', 20, 21.4, 22.6, '0.5c')
    570         self.checkParam(widget, 'spacing3', -10, expected=0)
    571 
    572     @requires_tcl(8, 5)
    573     def test_startline(self):
    574         widget = self.create()
    575         text = '\n'.join('Line %d' for i in range(100))
    576         widget.insert('end', text)
    577         self.checkParam(widget, 'startline', 200, expected='')
    578         self.checkParam(widget, 'startline', -10, expected='')
    579         self.checkInvalidParam(widget, 'startline', 'spam',
    580                 errmsg='expected integer but got "spam"')
    581         self.checkParam(widget, 'startline', 10)
    582         self.checkParam(widget, 'endline', 50)
    583         self.checkInvalidParam(widget, 'startline', 70,
    584                 errmsg='-startline must be less than or equal to -endline')
    585 
    586     def test_state(self):
    587         widget = self.create()
    588         if tcl_version < (8, 5):
    589             self.checkParams(widget, 'state', 'disabled', 'normal')
    590         else:
    591             self.checkEnumParam(widget, 'state', 'disabled', 'normal')
    592 
    593     def test_tabs(self):
    594         widget = self.create()
    595         if get_tk_patchlevel() < (8, 5, 11):
    596             self.checkParam(widget, 'tabs', (10.2, 20.7, '1i', '2i'),
    597                             expected=('10.2', '20.7', '1i', '2i'))
    598         else:
    599             self.checkParam(widget, 'tabs', (10.2, 20.7, '1i', '2i'))
    600         self.checkParam(widget, 'tabs', '10.2 20.7 1i 2i',
    601                         expected=('10.2', '20.7', '1i', '2i'))
    602         self.checkParam(widget, 'tabs', '2c left 4c 6c center',
    603                         expected=('2c', 'left', '4c', '6c', 'center'))
    604         self.checkInvalidParam(widget, 'tabs', 'spam',
    605                                errmsg='bad screen distance "spam"',
    606                                keep_orig=tcl_version >= (8, 5))
    607 
    608     @requires_tcl(8, 5)
    609     def test_tabstyle(self):
    610         widget = self.create()
    611         self.checkEnumParam(widget, 'tabstyle', 'tabular', 'wordprocessor')
    612 
    613     def test_undo(self):
    614         widget = self.create()
    615         self.checkBooleanParam(widget, 'undo')
    616 
    617     def test_width(self):
    618         widget = self.create()
    619         self.checkIntegerParam(widget, 'width', 402)
    620         self.checkParam(widget, 'width', -402, expected=1)
    621         self.checkParam(widget, 'width', 0, expected=1)
    622 
    623     def test_wrap(self):
    624         widget = self.create()
    625         if tcl_version < (8, 5):
    626             self.checkParams(widget, 'wrap', 'char', 'none', 'word')
    627         else:
    628             self.checkEnumParam(widget, 'wrap', 'char', 'none', 'word')
    629 
    630     def test_bbox(self):
    631         widget = self.create()
    632         self.assertIsBoundingBox(widget.bbox('1.1'))
    633         self.assertIsNone(widget.bbox('end'))
    634         self.assertRaises(tkinter.TclError, widget.bbox, 'noindex')
    635         self.assertRaises(tkinter.TclError, widget.bbox, None)
    636         self.assertRaises(TypeError, widget.bbox)
    637         self.assertRaises(TypeError, widget.bbox, '1.1', 'end')
    638 
    639 
    640 @add_standard_options(PixelSizeTests, StandardOptionsTests)
    641 class CanvasTest(AbstractWidgetTest, unittest.TestCase):
    642     OPTIONS = (
    643         'background', 'borderwidth',
    644         'closeenough', 'confine', 'cursor', 'height',
    645         'highlightbackground', 'highlightcolor', 'highlightthickness',
    646         'insertbackground', 'insertborderwidth',
    647         'insertofftime', 'insertontime', 'insertwidth',
    648         'offset', 'relief', 'scrollregion',
    649         'selectbackground', 'selectborderwidth', 'selectforeground',
    650         'state', 'takefocus',
    651         'xscrollcommand', 'xscrollincrement',
    652         'yscrollcommand', 'yscrollincrement', 'width',
    653     )
    654 
    655     _conv_pixels = round
    656     _stringify = True
    657 
    658     def create(self, **kwargs):
    659         return tkinter.Canvas(self.root, **kwargs)
    660 
    661     def test_closeenough(self):
    662         widget = self.create()
    663         self.checkFloatParam(widget, 'closeenough', 24, 2.4, 3.6, -3,
    664                              conv=float)
    665 
    666     def test_confine(self):
    667         widget = self.create()
    668         self.checkBooleanParam(widget, 'confine')
    669 
    670     def test_offset(self):
    671         widget = self.create()
    672         self.assertEqual(widget['offset'], '0,0')
    673         self.checkParams(widget, 'offset',
    674                 'n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw', 'center')
    675         self.checkParam(widget, 'offset', '10,20')
    676         self.checkParam(widget, 'offset', '#5,6')
    677         self.checkInvalidParam(widget, 'offset', 'spam')
    678 
    679     def test_scrollregion(self):
    680         widget = self.create()
    681         self.checkParam(widget, 'scrollregion', '0 0 200 150')
    682         self.checkParam(widget, 'scrollregion', (0, 0, 200, 150),
    683                         expected='0 0 200 150')
    684         self.checkParam(widget, 'scrollregion', '')
    685         self.checkInvalidParam(widget, 'scrollregion', 'spam',
    686                                errmsg='bad scrollRegion "spam"')
    687         self.checkInvalidParam(widget, 'scrollregion', (0, 0, 200, 'spam'))
    688         self.checkInvalidParam(widget, 'scrollregion', (0, 0, 200))
    689         self.checkInvalidParam(widget, 'scrollregion', (0, 0, 200, 150, 0))
    690 
    691     def test_state(self):
    692         widget = self.create()
    693         self.checkEnumParam(widget, 'state', 'disabled', 'normal',
    694                 errmsg='bad state value "{}": must be normal or disabled')
    695 
    696     def test_xscrollincrement(self):
    697         widget = self.create()
    698         self.checkPixelsParam(widget, 'xscrollincrement',
    699                               40, 0, 41.2, 43.6, -40, '0.5i')
    700 
    701     def test_yscrollincrement(self):
    702         widget = self.create()
    703         self.checkPixelsParam(widget, 'yscrollincrement',
    704                               10, 0, 11.2, 13.6, -10, '0.1i')
    705 
    706 
    707 @add_standard_options(IntegerSizeTests, StandardOptionsTests)
    708 class ListboxTest(AbstractWidgetTest, unittest.TestCase):
    709     OPTIONS = (
    710         'activestyle', 'background', 'borderwidth', 'cursor',
    711         'disabledforeground', 'exportselection',
    712         'font', 'foreground', 'height',
    713         'highlightbackground', 'highlightcolor', 'highlightthickness',
    714         'justify', 'listvariable', 'relief',
    715         'selectbackground', 'selectborderwidth', 'selectforeground',
    716         'selectmode', 'setgrid', 'state',
    717         'takefocus', 'width', 'xscrollcommand', 'yscrollcommand',
    718     )
    719 
    720     def create(self, **kwargs):
    721         return tkinter.Listbox(self.root, **kwargs)
    722 
    723     def test_activestyle(self):
    724         widget = self.create()
    725         self.checkEnumParam(widget, 'activestyle',
    726                             'dotbox', 'none', 'underline')
    727 
    728     test_justify = requires_tcl(8, 6, 5)(StandardOptionsTests.test_justify)
    729 
    730     def test_listvariable(self):
    731         widget = self.create()
    732         var = tkinter.DoubleVar(self.root)
    733         self.checkVariableParam(widget, 'listvariable', var)
    734 
    735     def test_selectmode(self):
    736         widget = self.create()
    737         self.checkParam(widget, 'selectmode', 'single')
    738         self.checkParam(widget, 'selectmode', 'browse')
    739         self.checkParam(widget, 'selectmode', 'multiple')
    740         self.checkParam(widget, 'selectmode', 'extended')
    741 
    742     def test_state(self):
    743         widget = self.create()
    744         self.checkEnumParam(widget, 'state', 'disabled', 'normal')
    745 
    746     def test_itemconfigure(self):
    747         widget = self.create()
    748         with self.assertRaisesRegex(TclError, 'item number "0" out of range'):
    749             widget.itemconfigure(0)
    750         colors = 'red orange yellow green blue white violet'.split()
    751         widget.insert('end', *colors)
    752         for i, color in enumerate(colors):
    753             widget.itemconfigure(i, background=color)
    754         with self.assertRaises(TypeError):
    755             widget.itemconfigure()
    756         with self.assertRaisesRegex(TclError, 'bad listbox index "red"'):
    757             widget.itemconfigure('red')
    758         self.assertEqual(widget.itemconfigure(0, 'background'),
    759                          ('background', 'background', 'Background', '', 'red'))
    760         self.assertEqual(widget.itemconfigure('end', 'background'),
    761                          ('background', 'background', 'Background', '', 'violet'))
    762         self.assertEqual(widget.itemconfigure('@0,0', 'background'),
    763                          ('background', 'background', 'Background', '', 'red'))
    764 
    765         d = widget.itemconfigure(0)
    766         self.assertIsInstance(d, dict)
    767         for k, v in d.items():
    768             self.assertIn(len(v), (2, 5))
    769             if len(v) == 5:
    770                 self.assertEqual(v, widget.itemconfigure(0, k))
    771                 self.assertEqual(v[4], widget.itemcget(0, k))
    772 
    773     def check_itemconfigure(self, name, value):
    774         widget = self.create()
    775         widget.insert('end', 'a', 'b', 'c', 'd')
    776         widget.itemconfigure(0, **{name: value})
    777         self.assertEqual(widget.itemconfigure(0, name)[4], value)
    778         self.assertEqual(widget.itemcget(0, name), value)
    779         with self.assertRaisesRegex(TclError, 'unknown color name "spam"'):
    780             widget.itemconfigure(0, **{name: 'spam'})
    781 
    782     def test_itemconfigure_background(self):
    783         self.check_itemconfigure('background', '#ff0000')
    784 
    785     def test_itemconfigure_bg(self):
    786         self.check_itemconfigure('bg', '#ff0000')
    787 
    788     def test_itemconfigure_fg(self):
    789         self.check_itemconfigure('fg', '#110022')
    790 
    791     def test_itemconfigure_foreground(self):
    792         self.check_itemconfigure('foreground', '#110022')
    793 
    794     def test_itemconfigure_selectbackground(self):
    795         self.check_itemconfigure('selectbackground', '#110022')
    796 
    797     def test_itemconfigure_selectforeground(self):
    798         self.check_itemconfigure('selectforeground', '#654321')
    799 
    800     def test_box(self):
    801         lb = self.create()
    802         lb.insert(0, *('el%d' % i for i in range(8)))
    803         lb.pack()
    804         self.assertIsBoundingBox(lb.bbox(0))
    805         self.assertIsNone(lb.bbox(-1))
    806         self.assertIsNone(lb.bbox(10))
    807         self.assertRaises(TclError, lb.bbox, 'noindex')
    808         self.assertRaises(TclError, lb.bbox, None)
    809         self.assertRaises(TypeError, lb.bbox)
    810         self.assertRaises(TypeError, lb.bbox, 0, 1)
    811 
    812     def test_curselection(self):
    813         lb = self.create()
    814         lb.insert(0, *('el%d' % i for i in range(8)))
    815         lb.selection_clear(0, tkinter.END)
    816         lb.selection_set(2, 4)
    817         lb.selection_set(6)
    818         self.assertEqual(lb.curselection(), (2, 3, 4, 6))
    819         self.assertRaises(TypeError, lb.curselection, 0)
    820 
    821     def test_get(self):
    822         lb = self.create()
    823         lb.insert(0, *('el%d' % i for i in range(8)))
    824         self.assertEqual(lb.get(0), 'el0')
    825         self.assertEqual(lb.get(3), 'el3')
    826         self.assertEqual(lb.get('end'), 'el7')
    827         self.assertEqual(lb.get(8), '')
    828         self.assertEqual(lb.get(-1), '')
    829         self.assertEqual(lb.get(3, 5), ('el3', 'el4', 'el5'))
    830         self.assertEqual(lb.get(5, 'end'), ('el5', 'el6', 'el7'))
    831         self.assertEqual(lb.get(5, 0), ())
    832         self.assertEqual(lb.get(0, 0), ('el0',))
    833         self.assertRaises(TclError, lb.get, 'noindex')
    834         self.assertRaises(TclError, lb.get, None)
    835         self.assertRaises(TypeError, lb.get)
    836         self.assertRaises(TclError, lb.get, 'end', 'noindex')
    837         self.assertRaises(TypeError, lb.get, 1, 2, 3)
    838         self.assertRaises(TclError, lb.get, 2.4)
    839 
    840 
    841 @add_standard_options(PixelSizeTests, StandardOptionsTests)
    842 class ScaleTest(AbstractWidgetTest, unittest.TestCase):
    843     OPTIONS = (
    844         'activebackground', 'background', 'bigincrement', 'borderwidth',
    845         'command', 'cursor', 'digits', 'font', 'foreground', 'from',
    846         'highlightbackground', 'highlightcolor', 'highlightthickness',
    847         'label', 'length', 'orient', 'relief',
    848         'repeatdelay', 'repeatinterval',
    849         'resolution', 'showvalue', 'sliderlength', 'sliderrelief', 'state',
    850         'takefocus', 'tickinterval', 'to', 'troughcolor', 'variable', 'width',
    851     )
    852     default_orient = 'vertical'
    853 
    854     def create(self, **kwargs):
    855         return tkinter.Scale(self.root, **kwargs)
    856 
    857     def test_bigincrement(self):
    858         widget = self.create()
    859         self.checkFloatParam(widget, 'bigincrement', 12.4, 23.6, -5)
    860 
    861     def test_digits(self):
    862         widget = self.create()
    863         self.checkIntegerParam(widget, 'digits', 5, 0)
    864 
    865     def test_from(self):
    866         widget = self.create()
    867         self.checkFloatParam(widget, 'from', 100, 14.9, 15.1, conv=float_round)
    868 
    869     def test_label(self):
    870         widget = self.create()
    871         self.checkParam(widget, 'label', 'any string')
    872         self.checkParam(widget, 'label', '')
    873 
    874     def test_length(self):
    875         widget = self.create()
    876         self.checkPixelsParam(widget, 'length', 130, 131.2, 135.6, '5i')
    877 
    878     def test_resolution(self):
    879         widget = self.create()
    880         self.checkFloatParam(widget, 'resolution', 4.2, 0, 6.7, -2)
    881 
    882     def test_showvalue(self):
    883         widget = self.create()
    884         self.checkBooleanParam(widget, 'showvalue')
    885 
    886     def test_sliderlength(self):
    887         widget = self.create()
    888         self.checkPixelsParam(widget, 'sliderlength',
    889                               10, 11.2, 15.6, -3, '3m')
    890 
    891     def test_sliderrelief(self):
    892         widget = self.create()
    893         self.checkReliefParam(widget, 'sliderrelief')
    894 
    895     def test_tickinterval(self):
    896         widget = self.create()
    897         self.checkFloatParam(widget, 'tickinterval', 1, 4.3, 7.6, 0,
    898                              conv=float_round)
    899         self.checkParam(widget, 'tickinterval', -2, expected=2,
    900                         conv=float_round)
    901 
    902     def test_to(self):
    903         widget = self.create()
    904         self.checkFloatParam(widget, 'to', 300, 14.9, 15.1, -10,
    905                              conv=float_round)
    906 
    907 
    908 @add_standard_options(PixelSizeTests, StandardOptionsTests)
    909 class ScrollbarTest(AbstractWidgetTest, unittest.TestCase):
    910     OPTIONS = (
    911         'activebackground', 'activerelief',
    912         'background', 'borderwidth',
    913         'command', 'cursor', 'elementborderwidth',
    914         'highlightbackground', 'highlightcolor', 'highlightthickness',
    915         'jump', 'orient', 'relief',
    916         'repeatdelay', 'repeatinterval',
    917         'takefocus', 'troughcolor', 'width',
    918     )
    919     _conv_pixels = round
    920     _stringify = True
    921     default_orient = 'vertical'
    922 
    923     def create(self, **kwargs):
    924         return tkinter.Scrollbar(self.root, **kwargs)
    925 
    926     def test_activerelief(self):
    927         widget = self.create()
    928         self.checkReliefParam(widget, 'activerelief')
    929 
    930     def test_elementborderwidth(self):
    931         widget = self.create()
    932         self.checkPixelsParam(widget, 'elementborderwidth', 4.3, 5.6, -2, '1m')
    933 
    934     def test_orient(self):
    935         widget = self.create()
    936         self.checkEnumParam(widget, 'orient', 'vertical', 'horizontal',
    937                 errmsg='bad orientation "{}": must be vertical or horizontal')
    938 
    939     def test_activate(self):
    940         sb = self.create()
    941         for e in ('arrow1', 'slider', 'arrow2'):
    942             sb.activate(e)
    943             self.assertEqual(sb.activate(), e)
    944         sb.activate('')
    945         self.assertIsNone(sb.activate())
    946         self.assertRaises(TypeError, sb.activate, 'arrow1', 'arrow2')
    947 
    948     def test_set(self):
    949         sb = self.create()
    950         sb.set(0.2, 0.4)
    951         self.assertEqual(sb.get(), (0.2, 0.4))
    952         self.assertRaises(TclError, sb.set, 'abc', 'def')
    953         self.assertRaises(TclError, sb.set, 0.6, 'def')
    954         self.assertRaises(TclError, sb.set, 0.6, None)
    955         self.assertRaises(TypeError, sb.set, 0.6)
    956         self.assertRaises(TypeError, sb.set, 0.6, 0.7, 0.8)
    957 
    958 
    959 @add_standard_options(StandardOptionsTests)
    960 class PanedWindowTest(AbstractWidgetTest, unittest.TestCase):
    961     OPTIONS = (
    962         'background', 'borderwidth', 'cursor',
    963         'handlepad', 'handlesize', 'height',
    964         'opaqueresize', 'orient',
    965         'proxybackground', 'proxyborderwidth', 'proxyrelief',
    966         'relief',
    967         'sashcursor', 'sashpad', 'sashrelief', 'sashwidth',
    968         'showhandle', 'width',
    969     )
    970     default_orient = 'horizontal'
    971 
    972     def create(self, **kwargs):
    973         return tkinter.PanedWindow(self.root, **kwargs)
    974 
    975     def test_handlepad(self):
    976         widget = self.create()
    977         self.checkPixelsParam(widget, 'handlepad', 5, 6.4, 7.6, -3, '1m')
    978 
    979     def test_handlesize(self):
    980         widget = self.create()
    981         self.checkPixelsParam(widget, 'handlesize', 8, 9.4, 10.6, -3, '2m',
    982                               conv=noconv)
    983 
    984     def test_height(self):
    985         widget = self.create()
    986         self.checkPixelsParam(widget, 'height', 100, 101.2, 102.6, -100, 0, '1i',
    987                               conv=noconv)
    988 
    989     def test_opaqueresize(self):
    990         widget = self.create()
    991         self.checkBooleanParam(widget, 'opaqueresize')
    992 
    993     @requires_tcl(8, 6, 5)
    994     def test_proxybackground(self):
    995         widget = self.create()
    996         self.checkColorParam(widget, 'proxybackground')
    997 
    998     @requires_tcl(8, 6, 5)
    999     def test_proxyborderwidth(self):
   1000         widget = self.create()
   1001         self.checkPixelsParam(widget, 'proxyborderwidth',
   1002                               0, 1.3, 2.9, 6, -2, '10p',
   1003                               conv=noconv)
   1004 
   1005     @requires_tcl(8, 6, 5)
   1006     def test_proxyrelief(self):
   1007         widget = self.create()
   1008         self.checkReliefParam(widget, 'proxyrelief')
   1009 
   1010     def test_sashcursor(self):
   1011         widget = self.create()
   1012         self.checkCursorParam(widget, 'sashcursor')
   1013 
   1014     def test_sashpad(self):
   1015         widget = self.create()
   1016         self.checkPixelsParam(widget, 'sashpad', 8, 1.3, 2.6, -2, '2m')
   1017 
   1018     def test_sashrelief(self):
   1019         widget = self.create()
   1020         self.checkReliefParam(widget, 'sashrelief')
   1021 
   1022     def test_sashwidth(self):
   1023         widget = self.create()
   1024         self.checkPixelsParam(widget, 'sashwidth', 10, 11.1, 15.6, -3, '1m',
   1025                               conv=noconv)
   1026 
   1027     def test_showhandle(self):
   1028         widget = self.create()
   1029         self.checkBooleanParam(widget, 'showhandle')
   1030 
   1031     def test_width(self):
   1032         widget = self.create()
   1033         self.checkPixelsParam(widget, 'width', 402, 403.4, 404.6, -402, 0, '5i',
   1034                               conv=noconv)
   1035 
   1036     def create2(self):
   1037         p = self.create()
   1038         b = tkinter.Button(p)
   1039         c = tkinter.Button(p)
   1040         p.add(b)
   1041         p.add(c)
   1042         return p, b, c
   1043 
   1044     def test_paneconfigure(self):
   1045         p, b, c = self.create2()
   1046         self.assertRaises(TypeError, p.paneconfigure)
   1047         d = p.paneconfigure(b)
   1048         self.assertIsInstance(d, dict)
   1049         for k, v in d.items():
   1050             self.assertEqual(len(v), 5)
   1051             self.assertEqual(v, p.paneconfigure(b, k))
   1052             self.assertEqual(v[4], p.panecget(b, k))
   1053 
   1054     def check_paneconfigure(self, p, b, name, value, expected, stringify=False):
   1055         conv = lambda x: x
   1056         if not self.wantobjects or stringify:
   1057             expected = str(expected)
   1058         if self.wantobjects and stringify:
   1059             conv = str
   1060         p.paneconfigure(b, **{name: value})
   1061         self.assertEqual(conv(p.paneconfigure(b, name)[4]), expected)
   1062         self.assertEqual(conv(p.panecget(b, name)), expected)
   1063 
   1064     def check_paneconfigure_bad(self, p, b, name, msg):
   1065         with self.assertRaisesRegex(TclError, msg):
   1066             p.paneconfigure(b, **{name: 'badValue'})
   1067 
   1068     def test_paneconfigure_after(self):
   1069         p, b, c = self.create2()
   1070         self.check_paneconfigure(p, b, 'after', c, str(c))
   1071         self.check_paneconfigure_bad(p, b, 'after',
   1072                                      'bad window path name "badValue"')
   1073 
   1074     def test_paneconfigure_before(self):
   1075         p, b, c = self.create2()
   1076         self.check_paneconfigure(p, b, 'before', c, str(c))
   1077         self.check_paneconfigure_bad(p, b, 'before',
   1078                                      'bad window path name "badValue"')
   1079 
   1080     def test_paneconfigure_height(self):
   1081         p, b, c = self.create2()
   1082         self.check_paneconfigure(p, b, 'height', 10, 10,
   1083                                  stringify=get_tk_patchlevel() < (8, 5, 11))
   1084         self.check_paneconfigure_bad(p, b, 'height',
   1085                                      'bad screen distance "badValue"')
   1086 
   1087     @requires_tcl(8, 5)
   1088     def test_paneconfigure_hide(self):
   1089         p, b, c = self.create2()
   1090         self.check_paneconfigure(p, b, 'hide', False, 0)
   1091         self.check_paneconfigure_bad(p, b, 'hide',
   1092                                      'expected boolean value but got "badValue"')
   1093 
   1094     def test_paneconfigure_minsize(self):
   1095         p, b, c = self.create2()
   1096         self.check_paneconfigure(p, b, 'minsize', 10, 10)
   1097         self.check_paneconfigure_bad(p, b, 'minsize',
   1098                                      'bad screen distance "badValue"')
   1099 
   1100     def test_paneconfigure_padx(self):
   1101         p, b, c = self.create2()
   1102         self.check_paneconfigure(p, b, 'padx', 1.3, 1)
   1103         self.check_paneconfigure_bad(p, b, 'padx',
   1104                                      'bad screen distance "badValue"')
   1105 
   1106     def test_paneconfigure_pady(self):
   1107         p, b, c = self.create2()
   1108         self.check_paneconfigure(p, b, 'pady', 1.3, 1)
   1109         self.check_paneconfigure_bad(p, b, 'pady',
   1110                                      'bad screen distance "badValue"')
   1111 
   1112     def test_paneconfigure_sticky(self):
   1113         p, b, c = self.create2()
   1114         self.check_paneconfigure(p, b, 'sticky', 'nsew', 'nesw')
   1115         self.check_paneconfigure_bad(p, b, 'sticky',
   1116                                      'bad stickyness value "badValue": must '
   1117                                      'be a string containing zero or more of '
   1118                                      'n, e, s, and w')
   1119 
   1120     @requires_tcl(8, 5)
   1121     def test_paneconfigure_stretch(self):
   1122         p, b, c = self.create2()
   1123         self.check_paneconfigure(p, b, 'stretch', 'alw', 'always')
   1124         self.check_paneconfigure_bad(p, b, 'stretch',
   1125                                      'bad stretch "badValue": must be '
   1126                                      'always, first, last, middle, or never')
   1127 
   1128     def test_paneconfigure_width(self):
   1129         p, b, c = self.create2()
   1130         self.check_paneconfigure(p, b, 'width', 10, 10,
   1131                                  stringify=get_tk_patchlevel() < (8, 5, 11))
   1132         self.check_paneconfigure_bad(p, b, 'width',
   1133                                      'bad screen distance "badValue"')
   1134 
   1135 
   1136 @add_standard_options(StandardOptionsTests)
   1137 class MenuTest(AbstractWidgetTest, unittest.TestCase):
   1138     OPTIONS = (
   1139         'activebackground', 'activeborderwidth', 'activeforeground',
   1140         'background', 'borderwidth', 'cursor',
   1141         'disabledforeground', 'font', 'foreground',
   1142         'postcommand', 'relief', 'selectcolor', 'takefocus',
   1143         'tearoff', 'tearoffcommand', 'title', 'type',
   1144     )
   1145     _conv_pixels = noconv
   1146 
   1147     def create(self, **kwargs):
   1148         return tkinter.Menu(self.root, **kwargs)
   1149 
   1150     def test_postcommand(self):
   1151         widget = self.create()
   1152         self.checkCommandParam(widget, 'postcommand')
   1153 
   1154     def test_tearoff(self):
   1155         widget = self.create()
   1156         self.checkBooleanParam(widget, 'tearoff')
   1157 
   1158     def test_tearoffcommand(self):
   1159         widget = self.create()
   1160         self.checkCommandParam(widget, 'tearoffcommand')
   1161 
   1162     def test_title(self):
   1163         widget = self.create()
   1164         self.checkParam(widget, 'title', 'any string')
   1165 
   1166     def test_type(self):
   1167         widget = self.create()
   1168         self.checkEnumParam(widget, 'type',
   1169                 'normal', 'tearoff', 'menubar')
   1170 
   1171     def test_entryconfigure(self):
   1172         m1 = self.create()
   1173         m1.add_command(label='test')
   1174         self.assertRaises(TypeError, m1.entryconfigure)
   1175         with self.assertRaisesRegex(TclError, 'bad menu entry index "foo"'):
   1176             m1.entryconfigure('foo')
   1177         d = m1.entryconfigure(1)
   1178         self.assertIsInstance(d, dict)
   1179         for k, v in d.items():
   1180             self.assertIsInstance(k, str)
   1181             self.assertIsInstance(v, tuple)
   1182             self.assertEqual(len(v), 5)
   1183             self.assertEqual(v[0], k)
   1184             self.assertEqual(m1.entrycget(1, k), v[4])
   1185         m1.destroy()
   1186 
   1187     def test_entryconfigure_label(self):
   1188         m1 = self.create()
   1189         m1.add_command(label='test')
   1190         self.assertEqual(m1.entrycget(1, 'label'), 'test')
   1191         m1.entryconfigure(1, label='changed')
   1192         self.assertEqual(m1.entrycget(1, 'label'), 'changed')
   1193 
   1194     def test_entryconfigure_variable(self):
   1195         m1 = self.create()
   1196         v1 = tkinter.BooleanVar(self.root)
   1197         v2 = tkinter.BooleanVar(self.root)
   1198         m1.add_checkbutton(variable=v1, onvalue=True, offvalue=False,
   1199                            label='Nonsense')
   1200         self.assertEqual(str(m1.entrycget(1, 'variable')), str(v1))
   1201         m1.entryconfigure(1, variable=v2)
   1202         self.assertEqual(str(m1.entrycget(1, 'variable')), str(v2))
   1203 
   1204 
   1205 @add_standard_options(PixelSizeTests, StandardOptionsTests)
   1206 class MessageTest(AbstractWidgetTest, unittest.TestCase):
   1207     OPTIONS = (
   1208         'anchor', 'aspect', 'background', 'borderwidth',
   1209         'cursor', 'font', 'foreground',
   1210         'highlightbackground', 'highlightcolor', 'highlightthickness',
   1211         'justify', 'padx', 'pady', 'relief',
   1212         'takefocus', 'text', 'textvariable', 'width',
   1213     )
   1214     _conv_pad_pixels = noconv
   1215 
   1216     def create(self, **kwargs):
   1217         return tkinter.Message(self.root, **kwargs)
   1218 
   1219     def test_aspect(self):
   1220         widget = self.create()
   1221         self.checkIntegerParam(widget, 'aspect', 250, 0, -300)
   1222 
   1223 
   1224 tests_gui = (
   1225         ButtonTest, CanvasTest, CheckbuttonTest, EntryTest,
   1226         FrameTest, LabelFrameTest,LabelTest, ListboxTest,
   1227         MenubuttonTest, MenuTest, MessageTest, OptionMenuTest,
   1228         PanedWindowTest, RadiobuttonTest, ScaleTest, ScrollbarTest,
   1229         SpinboxTest, TextTest, ToplevelTest,
   1230 )
   1231 
   1232 if __name__ == '__main__':
   1233     unittest.main()
   1234