• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1import unittest
2import tkinter
3from tkinter import TclError
4import os
5import sys
6from test.support import requires
7
8from tkinter.test.support import (tcl_version, requires_tcl,
9                                  get_tk_patchlevel, widget_eq)
10from tkinter.test.widget_tests import (
11    add_standard_options, noconv, pixels_round,
12    AbstractWidgetTest, StandardOptionsTests, IntegerSizeTests, PixelSizeTests,
13    setUpModule)
14
15requires('gui')
16
17
18def float_round(x):
19    return float(round(x))
20
21
22class 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)
60class 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)
101class 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)
114class 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
141class 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)
151class 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)
167class 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)
188class 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)
217class 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)
240class 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
305class 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    def test_bad_kwarg(self):
311        with self.assertRaisesRegex(TclError, r"^unknown option -image$"):
312            tkinter.OptionMenu(self.root, None, 'b', image='')
313
314
315@add_standard_options(IntegerSizeTests, StandardOptionsTests)
316class EntryTest(AbstractWidgetTest, unittest.TestCase):
317    OPTIONS = (
318        'background', 'borderwidth', 'cursor',
319        'disabledbackground', 'disabledforeground',
320        'exportselection', 'font', 'foreground',
321        'highlightbackground', 'highlightcolor', 'highlightthickness',
322        'insertbackground', 'insertborderwidth',
323        'insertofftime', 'insertontime', 'insertwidth',
324        'invalidcommand', 'justify', 'readonlybackground', 'relief',
325        'selectbackground', 'selectborderwidth', 'selectforeground',
326        'show', 'state', 'takefocus', 'textvariable',
327        'validate', 'validatecommand', 'width', 'xscrollcommand',
328    )
329
330    def create(self, **kwargs):
331        return tkinter.Entry(self.root, **kwargs)
332
333    def test_disabledbackground(self):
334        widget = self.create()
335        self.checkColorParam(widget, 'disabledbackground')
336
337    def test_insertborderwidth(self):
338        widget = self.create(insertwidth=100)
339        self.checkPixelsParam(widget, 'insertborderwidth',
340                              0, 1.3, 2.6, 6, -2, '10p')
341        # insertborderwidth is bounded above by a half of insertwidth.
342        self.checkParam(widget, 'insertborderwidth', 60, expected=100//2)
343
344    def test_insertwidth(self):
345        widget = self.create()
346        self.checkPixelsParam(widget, 'insertwidth', 1.3, 3.6, '10p')
347        self.checkParam(widget, 'insertwidth', 0.1, expected=2)
348        self.checkParam(widget, 'insertwidth', -2, expected=2)
349        if pixels_round(0.9) <= 0:
350            self.checkParam(widget, 'insertwidth', 0.9, expected=2)
351        else:
352            self.checkParam(widget, 'insertwidth', 0.9, expected=1)
353
354    def test_invalidcommand(self):
355        widget = self.create()
356        self.checkCommandParam(widget, 'invalidcommand')
357        self.checkCommandParam(widget, 'invcmd')
358
359    def test_readonlybackground(self):
360        widget = self.create()
361        self.checkColorParam(widget, 'readonlybackground')
362
363    def test_show(self):
364        widget = self.create()
365        self.checkParam(widget, 'show', '*')
366        self.checkParam(widget, 'show', '')
367        self.checkParam(widget, 'show', ' ')
368
369    def test_state(self):
370        widget = self.create()
371        self.checkEnumParam(widget, 'state',
372                            'disabled', 'normal', 'readonly')
373
374    def test_validate(self):
375        widget = self.create()
376        self.checkEnumParam(widget, 'validate',
377                'all', 'key', 'focus', 'focusin', 'focusout', 'none')
378
379    def test_validatecommand(self):
380        widget = self.create()
381        self.checkCommandParam(widget, 'validatecommand')
382        self.checkCommandParam(widget, 'vcmd')
383
384    def test_selection_methods(self):
385        widget = self.create()
386        widget.insert(0, '12345')
387        self.assertFalse(widget.selection_present())
388        widget.selection_range(0, 'end')
389        self.assertEqual(widget.selection_get(), '12345')
390        self.assertTrue(widget.selection_present())
391        widget.selection_from(1)
392        widget.selection_to(2)
393        self.assertEqual(widget.selection_get(), '2')
394        widget.selection_range(3, 4)
395        self.assertEqual(widget.selection_get(), '4')
396        widget.selection_clear()
397        self.assertFalse(widget.selection_present())
398        widget.selection_range(0, 'end')
399        widget.selection_adjust(4)
400        self.assertEqual(widget.selection_get(), '1234')
401        widget.selection_adjust(1)
402        self.assertEqual(widget.selection_get(), '234')
403        widget.selection_adjust(5)
404        self.assertEqual(widget.selection_get(), '2345')
405        widget.selection_adjust(0)
406        self.assertEqual(widget.selection_get(), '12345')
407        widget.selection_adjust(0)
408
409
410@add_standard_options(StandardOptionsTests)
411class SpinboxTest(EntryTest, unittest.TestCase):
412    OPTIONS = (
413        'activebackground', 'background', 'borderwidth',
414        'buttonbackground', 'buttoncursor', 'buttondownrelief', 'buttonuprelief',
415        'command', 'cursor', 'disabledbackground', 'disabledforeground',
416        'exportselection', 'font', 'foreground', 'format', 'from',
417        'highlightbackground', 'highlightcolor', 'highlightthickness',
418        'increment',
419        'insertbackground', 'insertborderwidth',
420        'insertofftime', 'insertontime', 'insertwidth',
421        'invalidcommand', 'justify', 'relief', 'readonlybackground',
422        'repeatdelay', 'repeatinterval',
423        'selectbackground', 'selectborderwidth', 'selectforeground',
424        'state', 'takefocus', 'textvariable', 'to',
425        'validate', 'validatecommand', 'values',
426        'width', 'wrap', 'xscrollcommand',
427    )
428
429    def create(self, **kwargs):
430        return tkinter.Spinbox(self.root, **kwargs)
431
432    test_show = None
433
434    def test_buttonbackground(self):
435        widget = self.create()
436        self.checkColorParam(widget, 'buttonbackground')
437
438    def test_buttoncursor(self):
439        widget = self.create()
440        self.checkCursorParam(widget, 'buttoncursor')
441
442    def test_buttondownrelief(self):
443        widget = self.create()
444        self.checkReliefParam(widget, 'buttondownrelief')
445
446    def test_buttonuprelief(self):
447        widget = self.create()
448        self.checkReliefParam(widget, 'buttonuprelief')
449
450    def test_format(self):
451        widget = self.create()
452        self.checkParam(widget, 'format', '%2f')
453        self.checkParam(widget, 'format', '%2.2f')
454        self.checkParam(widget, 'format', '%.2f')
455        self.checkParam(widget, 'format', '%2.f')
456        self.checkInvalidParam(widget, 'format', '%2e-1f')
457        self.checkInvalidParam(widget, 'format', '2.2')
458        self.checkInvalidParam(widget, 'format', '%2.-2f')
459        self.checkParam(widget, 'format', '%-2.02f')
460        self.checkParam(widget, 'format', '% 2.02f')
461        self.checkParam(widget, 'format', '% -2.200f')
462        self.checkParam(widget, 'format', '%09.200f')
463        self.checkInvalidParam(widget, 'format', '%d')
464
465    def test_from(self):
466        widget = self.create()
467        self.checkParam(widget, 'to', 100.0)
468        self.checkFloatParam(widget, 'from', -10, 10.2, 11.7)
469        self.checkInvalidParam(widget, 'from', 200,
470                errmsg='-to value must be greater than -from value')
471
472    def test_increment(self):
473        widget = self.create()
474        self.checkFloatParam(widget, 'increment', -1, 1, 10.2, 12.8, 0)
475
476    def test_to(self):
477        widget = self.create()
478        self.checkParam(widget, 'from', -100.0)
479        self.checkFloatParam(widget, 'to', -10, 10.2, 11.7)
480        self.checkInvalidParam(widget, 'to', -200,
481                errmsg='-to value must be greater than -from value')
482
483    def test_values(self):
484        # XXX
485        widget = self.create()
486        self.assertEqual(widget['values'], '')
487        self.checkParam(widget, 'values', 'mon tue wed thur')
488        self.checkParam(widget, 'values', ('mon', 'tue', 'wed', 'thur'),
489                        expected='mon tue wed thur')
490        self.checkParam(widget, 'values', (42, 3.14, '', 'any string'),
491                        expected='42 3.14 {} {any string}')
492        self.checkParam(widget, 'values', '')
493
494    def test_wrap(self):
495        widget = self.create()
496        self.checkBooleanParam(widget, 'wrap')
497
498    def test_bbox(self):
499        widget = self.create()
500        self.assertIsBoundingBox(widget.bbox(0))
501        self.assertRaises(tkinter.TclError, widget.bbox, 'noindex')
502        self.assertRaises(tkinter.TclError, widget.bbox, None)
503        self.assertRaises(TypeError, widget.bbox)
504        self.assertRaises(TypeError, widget.bbox, 0, 1)
505
506    def test_selection_methods(self):
507        widget = self.create()
508        widget.insert(0, '12345')
509        self.assertFalse(widget.selection_present())
510        widget.selection_range(0, 'end')
511        self.assertEqual(widget.selection_get(), '12345')
512        self.assertTrue(widget.selection_present())
513        widget.selection_from(1)
514        widget.selection_to(2)
515        self.assertEqual(widget.selection_get(), '2')
516        widget.selection_range(3, 4)
517        self.assertEqual(widget.selection_get(), '4')
518        widget.selection_clear()
519        self.assertFalse(widget.selection_present())
520        widget.selection_range(0, 'end')
521        widget.selection_adjust(4)
522        self.assertEqual(widget.selection_get(), '1234')
523        widget.selection_adjust(1)
524        self.assertEqual(widget.selection_get(), '234')
525        widget.selection_adjust(5)
526        self.assertEqual(widget.selection_get(), '2345')
527        widget.selection_adjust(0)
528        self.assertEqual(widget.selection_get(), '12345')
529
530    def test_selection_element(self):
531        widget = self.create()
532        self.assertEqual(widget.selection_element(), "none")
533        widget.selection_element("buttonup")
534        self.assertEqual(widget.selection_element(), "buttonup")
535        widget.selection_element("buttondown")
536        self.assertEqual(widget.selection_element(), "buttondown")
537
538
539@add_standard_options(StandardOptionsTests)
540class TextTest(AbstractWidgetTest, unittest.TestCase):
541    OPTIONS = (
542        'autoseparators', 'background', 'blockcursor', 'borderwidth',
543        'cursor', 'endline', 'exportselection',
544        'font', 'foreground', 'height',
545        'highlightbackground', 'highlightcolor', 'highlightthickness',
546        'inactiveselectbackground', 'insertbackground', 'insertborderwidth',
547        'insertofftime', 'insertontime', 'insertunfocussed', 'insertwidth',
548        'maxundo', 'padx', 'pady', 'relief',
549        'selectbackground', 'selectborderwidth', 'selectforeground',
550        'setgrid', 'spacing1', 'spacing2', 'spacing3', 'startline', 'state',
551        'tabs', 'tabstyle', 'takefocus', 'undo', 'width', 'wrap',
552        'xscrollcommand', 'yscrollcommand',
553    )
554    if tcl_version < (8, 5):
555        _stringify = True
556
557    def create(self, **kwargs):
558        return tkinter.Text(self.root, **kwargs)
559
560    def test_autoseparators(self):
561        widget = self.create()
562        self.checkBooleanParam(widget, 'autoseparators')
563
564    @requires_tcl(8, 5)
565    def test_blockcursor(self):
566        widget = self.create()
567        self.checkBooleanParam(widget, 'blockcursor')
568
569    @requires_tcl(8, 5)
570    def test_endline(self):
571        widget = self.create()
572        text = '\n'.join('Line %d' for i in range(100))
573        widget.insert('end', text)
574        self.checkParam(widget, 'endline', 200, expected='')
575        self.checkParam(widget, 'endline', -10, expected='')
576        self.checkInvalidParam(widget, 'endline', 'spam',
577                errmsg='expected integer but got "spam"')
578        self.checkParam(widget, 'endline', 50)
579        self.checkParam(widget, 'startline', 15)
580        self.checkInvalidParam(widget, 'endline', 10,
581                errmsg='-startline must be less than or equal to -endline')
582
583    def test_height(self):
584        widget = self.create()
585        self.checkPixelsParam(widget, 'height', 100, 101.2, 102.6, '3c')
586        self.checkParam(widget, 'height', -100, expected=1)
587        self.checkParam(widget, 'height', 0, expected=1)
588
589    def test_maxundo(self):
590        widget = self.create()
591        self.checkIntegerParam(widget, 'maxundo', 0, 5, -1)
592
593    @requires_tcl(8, 5)
594    def test_inactiveselectbackground(self):
595        widget = self.create()
596        self.checkColorParam(widget, 'inactiveselectbackground')
597
598    @requires_tcl(8, 6)
599    def test_insertunfocussed(self):
600        widget = self.create()
601        self.checkEnumParam(widget, 'insertunfocussed',
602                            'hollow', 'none', 'solid')
603
604    def test_selectborderwidth(self):
605        widget = self.create()
606        self.checkPixelsParam(widget, 'selectborderwidth',
607                              1.3, 2.6, -2, '10p', conv=noconv,
608                              keep_orig=tcl_version >= (8, 5))
609
610    def test_spacing1(self):
611        widget = self.create()
612        self.checkPixelsParam(widget, 'spacing1', 20, 21.4, 22.6, '0.5c')
613        self.checkParam(widget, 'spacing1', -5, expected=0)
614
615    def test_spacing2(self):
616        widget = self.create()
617        self.checkPixelsParam(widget, 'spacing2', 5, 6.4, 7.6, '0.1c')
618        self.checkParam(widget, 'spacing2', -1, expected=0)
619
620    def test_spacing3(self):
621        widget = self.create()
622        self.checkPixelsParam(widget, 'spacing3', 20, 21.4, 22.6, '0.5c')
623        self.checkParam(widget, 'spacing3', -10, expected=0)
624
625    @requires_tcl(8, 5)
626    def test_startline(self):
627        widget = self.create()
628        text = '\n'.join('Line %d' for i in range(100))
629        widget.insert('end', text)
630        self.checkParam(widget, 'startline', 200, expected='')
631        self.checkParam(widget, 'startline', -10, expected='')
632        self.checkInvalidParam(widget, 'startline', 'spam',
633                errmsg='expected integer but got "spam"')
634        self.checkParam(widget, 'startline', 10)
635        self.checkParam(widget, 'endline', 50)
636        self.checkInvalidParam(widget, 'startline', 70,
637                errmsg='-startline must be less than or equal to -endline')
638
639    def test_state(self):
640        widget = self.create()
641        if tcl_version < (8, 5):
642            self.checkParams(widget, 'state', 'disabled', 'normal')
643        else:
644            self.checkEnumParam(widget, 'state', 'disabled', 'normal')
645
646    def test_tabs(self):
647        widget = self.create()
648        if get_tk_patchlevel() < (8, 5, 11):
649            self.checkParam(widget, 'tabs', (10.2, 20.7, '1i', '2i'),
650                            expected=('10.2', '20.7', '1i', '2i'))
651        else:
652            self.checkParam(widget, 'tabs', (10.2, 20.7, '1i', '2i'))
653        self.checkParam(widget, 'tabs', '10.2 20.7 1i 2i',
654                        expected=('10.2', '20.7', '1i', '2i'))
655        self.checkParam(widget, 'tabs', '2c left 4c 6c center',
656                        expected=('2c', 'left', '4c', '6c', 'center'))
657        self.checkInvalidParam(widget, 'tabs', 'spam',
658                               errmsg='bad screen distance "spam"',
659                               keep_orig=tcl_version >= (8, 5))
660
661    @requires_tcl(8, 5)
662    def test_tabstyle(self):
663        widget = self.create()
664        self.checkEnumParam(widget, 'tabstyle', 'tabular', 'wordprocessor')
665
666    def test_undo(self):
667        widget = self.create()
668        self.checkBooleanParam(widget, 'undo')
669
670    def test_width(self):
671        widget = self.create()
672        self.checkIntegerParam(widget, 'width', 402)
673        self.checkParam(widget, 'width', -402, expected=1)
674        self.checkParam(widget, 'width', 0, expected=1)
675
676    def test_wrap(self):
677        widget = self.create()
678        if tcl_version < (8, 5):
679            self.checkParams(widget, 'wrap', 'char', 'none', 'word')
680        else:
681            self.checkEnumParam(widget, 'wrap', 'char', 'none', 'word')
682
683    def test_bbox(self):
684        widget = self.create()
685        self.assertIsBoundingBox(widget.bbox('1.1'))
686        self.assertIsNone(widget.bbox('end'))
687        self.assertRaises(tkinter.TclError, widget.bbox, 'noindex')
688        self.assertRaises(tkinter.TclError, widget.bbox, None)
689        self.assertRaises(TypeError, widget.bbox)
690        self.assertRaises(TypeError, widget.bbox, '1.1', 'end')
691
692
693@add_standard_options(PixelSizeTests, StandardOptionsTests)
694class CanvasTest(AbstractWidgetTest, unittest.TestCase):
695    OPTIONS = (
696        'background', 'borderwidth',
697        'closeenough', 'confine', 'cursor', 'height',
698        'highlightbackground', 'highlightcolor', 'highlightthickness',
699        'insertbackground', 'insertborderwidth',
700        'insertofftime', 'insertontime', 'insertwidth',
701        'offset', 'relief', 'scrollregion',
702        'selectbackground', 'selectborderwidth', 'selectforeground',
703        'state', 'takefocus',
704        'xscrollcommand', 'xscrollincrement',
705        'yscrollcommand', 'yscrollincrement', 'width',
706    )
707
708    _conv_pixels = round
709    _stringify = True
710
711    def create(self, **kwargs):
712        return tkinter.Canvas(self.root, **kwargs)
713
714    def test_closeenough(self):
715        widget = self.create()
716        self.checkFloatParam(widget, 'closeenough', 24, 2.4, 3.6, -3,
717                             conv=float)
718
719    def test_confine(self):
720        widget = self.create()
721        self.checkBooleanParam(widget, 'confine')
722
723    def test_offset(self):
724        widget = self.create()
725        self.assertEqual(widget['offset'], '0,0')
726        self.checkParams(widget, 'offset',
727                'n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw', 'center')
728        self.checkParam(widget, 'offset', '10,20')
729        self.checkParam(widget, 'offset', '#5,6')
730        self.checkInvalidParam(widget, 'offset', 'spam')
731
732    def test_scrollregion(self):
733        widget = self.create()
734        self.checkParam(widget, 'scrollregion', '0 0 200 150')
735        self.checkParam(widget, 'scrollregion', (0, 0, 200, 150),
736                        expected='0 0 200 150')
737        self.checkParam(widget, 'scrollregion', '')
738        self.checkInvalidParam(widget, 'scrollregion', 'spam',
739                               errmsg='bad scrollRegion "spam"')
740        self.checkInvalidParam(widget, 'scrollregion', (0, 0, 200, 'spam'))
741        self.checkInvalidParam(widget, 'scrollregion', (0, 0, 200))
742        self.checkInvalidParam(widget, 'scrollregion', (0, 0, 200, 150, 0))
743
744    def test_state(self):
745        widget = self.create()
746        self.checkEnumParam(widget, 'state', 'disabled', 'normal',
747                errmsg='bad state value "{}": must be normal or disabled')
748
749    def test_xscrollincrement(self):
750        widget = self.create()
751        self.checkPixelsParam(widget, 'xscrollincrement',
752                              40, 0, 41.2, 43.6, -40, '0.5i')
753
754    def test_yscrollincrement(self):
755        widget = self.create()
756        self.checkPixelsParam(widget, 'yscrollincrement',
757                              10, 0, 11.2, 13.6, -10, '0.1i')
758
759    @requires_tcl(8, 6)
760    def test_moveto(self):
761        widget = self.create()
762        i1 = widget.create_rectangle(1, 1, 20, 20, tags='group')
763        i2 = widget.create_rectangle(30, 30, 50, 70, tags='group')
764        x1, y1, _, _ = widget.bbox(i1)
765        x2, y2, _, _ = widget.bbox(i2)
766        widget.moveto('group', 200, 100)
767        x1_2, y1_2, _, _ = widget.bbox(i1)
768        x2_2, y2_2, _, _ = widget.bbox(i2)
769        self.assertEqual(x1_2, 200)
770        self.assertEqual(y1_2, 100)
771        self.assertEqual(x2 - x1, x2_2 - x1_2)
772        self.assertEqual(y2 - y1, y2_2 - y1_2)
773        widget.tag_lower(i2, i1)
774        widget.moveto('group', y=50)
775        x1_3, y1_3, _, _ = widget.bbox(i1)
776        x2_3, y2_3, _, _ = widget.bbox(i2)
777        self.assertEqual(y2_3, 50)
778        self.assertEqual(x2_3, x2_2)
779        self.assertEqual(x2_2 - x1_2, x2_3 - x1_3)
780        self.assertEqual(y2_2 - y1_2, y2_3 - y1_3)
781
782
783@add_standard_options(IntegerSizeTests, StandardOptionsTests)
784class ListboxTest(AbstractWidgetTest, unittest.TestCase):
785    OPTIONS = (
786        'activestyle', 'background', 'borderwidth', 'cursor',
787        'disabledforeground', 'exportselection',
788        'font', 'foreground', 'height',
789        'highlightbackground', 'highlightcolor', 'highlightthickness',
790        'justify', 'listvariable', 'relief',
791        'selectbackground', 'selectborderwidth', 'selectforeground',
792        'selectmode', 'setgrid', 'state',
793        'takefocus', 'width', 'xscrollcommand', 'yscrollcommand',
794    )
795
796    def create(self, **kwargs):
797        return tkinter.Listbox(self.root, **kwargs)
798
799    def test_activestyle(self):
800        widget = self.create()
801        self.checkEnumParam(widget, 'activestyle',
802                            'dotbox', 'none', 'underline')
803
804    test_justify = requires_tcl(8, 6, 5)(StandardOptionsTests.test_justify)
805
806    def test_listvariable(self):
807        widget = self.create()
808        var = tkinter.DoubleVar(self.root)
809        self.checkVariableParam(widget, 'listvariable', var)
810
811    def test_selectmode(self):
812        widget = self.create()
813        self.checkParam(widget, 'selectmode', 'single')
814        self.checkParam(widget, 'selectmode', 'browse')
815        self.checkParam(widget, 'selectmode', 'multiple')
816        self.checkParam(widget, 'selectmode', 'extended')
817
818    def test_state(self):
819        widget = self.create()
820        self.checkEnumParam(widget, 'state', 'disabled', 'normal')
821
822    def test_itemconfigure(self):
823        widget = self.create()
824        with self.assertRaisesRegex(TclError, 'item number "0" out of range'):
825            widget.itemconfigure(0)
826        colors = 'red orange yellow green blue white violet'.split()
827        widget.insert('end', *colors)
828        for i, color in enumerate(colors):
829            widget.itemconfigure(i, background=color)
830        with self.assertRaises(TypeError):
831            widget.itemconfigure()
832        with self.assertRaisesRegex(TclError, 'bad listbox index "red"'):
833            widget.itemconfigure('red')
834        self.assertEqual(widget.itemconfigure(0, 'background'),
835                         ('background', 'background', 'Background', '', 'red'))
836        self.assertEqual(widget.itemconfigure('end', 'background'),
837                         ('background', 'background', 'Background', '', 'violet'))
838        self.assertEqual(widget.itemconfigure('@0,0', 'background'),
839                         ('background', 'background', 'Background', '', 'red'))
840
841        d = widget.itemconfigure(0)
842        self.assertIsInstance(d, dict)
843        for k, v in d.items():
844            self.assertIn(len(v), (2, 5))
845            if len(v) == 5:
846                self.assertEqual(v, widget.itemconfigure(0, k))
847                self.assertEqual(v[4], widget.itemcget(0, k))
848
849    def check_itemconfigure(self, name, value):
850        widget = self.create()
851        widget.insert('end', 'a', 'b', 'c', 'd')
852        widget.itemconfigure(0, **{name: value})
853        self.assertEqual(widget.itemconfigure(0, name)[4], value)
854        self.assertEqual(widget.itemcget(0, name), value)
855        with self.assertRaisesRegex(TclError, 'unknown color name "spam"'):
856            widget.itemconfigure(0, **{name: 'spam'})
857
858    def test_itemconfigure_background(self):
859        self.check_itemconfigure('background', '#ff0000')
860
861    def test_itemconfigure_bg(self):
862        self.check_itemconfigure('bg', '#ff0000')
863
864    def test_itemconfigure_fg(self):
865        self.check_itemconfigure('fg', '#110022')
866
867    def test_itemconfigure_foreground(self):
868        self.check_itemconfigure('foreground', '#110022')
869
870    def test_itemconfigure_selectbackground(self):
871        self.check_itemconfigure('selectbackground', '#110022')
872
873    def test_itemconfigure_selectforeground(self):
874        self.check_itemconfigure('selectforeground', '#654321')
875
876    def test_box(self):
877        lb = self.create()
878        lb.insert(0, *('el%d' % i for i in range(8)))
879        lb.pack()
880        self.assertIsBoundingBox(lb.bbox(0))
881        self.assertIsNone(lb.bbox(-1))
882        self.assertIsNone(lb.bbox(10))
883        self.assertRaises(TclError, lb.bbox, 'noindex')
884        self.assertRaises(TclError, lb.bbox, None)
885        self.assertRaises(TypeError, lb.bbox)
886        self.assertRaises(TypeError, lb.bbox, 0, 1)
887
888    def test_curselection(self):
889        lb = self.create()
890        lb.insert(0, *('el%d' % i for i in range(8)))
891        lb.selection_clear(0, tkinter.END)
892        lb.selection_set(2, 4)
893        lb.selection_set(6)
894        self.assertEqual(lb.curselection(), (2, 3, 4, 6))
895        self.assertRaises(TypeError, lb.curselection, 0)
896
897    def test_get(self):
898        lb = self.create()
899        lb.insert(0, *('el%d' % i for i in range(8)))
900        self.assertEqual(lb.get(0), 'el0')
901        self.assertEqual(lb.get(3), 'el3')
902        self.assertEqual(lb.get('end'), 'el7')
903        self.assertEqual(lb.get(8), '')
904        self.assertEqual(lb.get(-1), '')
905        self.assertEqual(lb.get(3, 5), ('el3', 'el4', 'el5'))
906        self.assertEqual(lb.get(5, 'end'), ('el5', 'el6', 'el7'))
907        self.assertEqual(lb.get(5, 0), ())
908        self.assertEqual(lb.get(0, 0), ('el0',))
909        self.assertRaises(TclError, lb.get, 'noindex')
910        self.assertRaises(TclError, lb.get, None)
911        self.assertRaises(TypeError, lb.get)
912        self.assertRaises(TclError, lb.get, 'end', 'noindex')
913        self.assertRaises(TypeError, lb.get, 1, 2, 3)
914        self.assertRaises(TclError, lb.get, 2.4)
915
916
917@add_standard_options(PixelSizeTests, StandardOptionsTests)
918class ScaleTest(AbstractWidgetTest, unittest.TestCase):
919    OPTIONS = (
920        'activebackground', 'background', 'bigincrement', 'borderwidth',
921        'command', 'cursor', 'digits', 'font', 'foreground', 'from',
922        'highlightbackground', 'highlightcolor', 'highlightthickness',
923        'label', 'length', 'orient', 'relief',
924        'repeatdelay', 'repeatinterval',
925        'resolution', 'showvalue', 'sliderlength', 'sliderrelief', 'state',
926        'takefocus', 'tickinterval', 'to', 'troughcolor', 'variable', 'width',
927    )
928    default_orient = 'vertical'
929
930    def create(self, **kwargs):
931        return tkinter.Scale(self.root, **kwargs)
932
933    def test_bigincrement(self):
934        widget = self.create()
935        self.checkFloatParam(widget, 'bigincrement', 12.4, 23.6, -5)
936
937    def test_digits(self):
938        widget = self.create()
939        self.checkIntegerParam(widget, 'digits', 5, 0)
940
941    def test_from(self):
942        widget = self.create()
943        conv = False if get_tk_patchlevel() >= (8, 6, 10) else float_round
944        self.checkFloatParam(widget, 'from', 100, 14.9, 15.1, conv=conv)
945
946    def test_label(self):
947        widget = self.create()
948        self.checkParam(widget, 'label', 'any string')
949        self.checkParam(widget, 'label', '')
950
951    def test_length(self):
952        widget = self.create()
953        self.checkPixelsParam(widget, 'length', 130, 131.2, 135.6, '5i')
954
955    def test_resolution(self):
956        widget = self.create()
957        self.checkFloatParam(widget, 'resolution', 4.2, 0, 6.7, -2)
958
959    def test_showvalue(self):
960        widget = self.create()
961        self.checkBooleanParam(widget, 'showvalue')
962
963    def test_sliderlength(self):
964        widget = self.create()
965        self.checkPixelsParam(widget, 'sliderlength',
966                              10, 11.2, 15.6, -3, '3m')
967
968    def test_sliderrelief(self):
969        widget = self.create()
970        self.checkReliefParam(widget, 'sliderrelief')
971
972    def test_tickinterval(self):
973        widget = self.create()
974        self.checkFloatParam(widget, 'tickinterval', 1, 4.3, 7.6, 0,
975                             conv=float_round)
976        self.checkParam(widget, 'tickinterval', -2, expected=2,
977                        conv=float_round)
978
979    def test_to(self):
980        widget = self.create()
981        self.checkFloatParam(widget, 'to', 300, 14.9, 15.1, -10,
982                             conv=float_round)
983
984
985@add_standard_options(PixelSizeTests, StandardOptionsTests)
986class ScrollbarTest(AbstractWidgetTest, unittest.TestCase):
987    OPTIONS = (
988        'activebackground', 'activerelief',
989        'background', 'borderwidth',
990        'command', 'cursor', 'elementborderwidth',
991        'highlightbackground', 'highlightcolor', 'highlightthickness',
992        'jump', 'orient', 'relief',
993        'repeatdelay', 'repeatinterval',
994        'takefocus', 'troughcolor', 'width',
995    )
996    _conv_pixels = round
997    _stringify = True
998    default_orient = 'vertical'
999
1000    def create(self, **kwargs):
1001        return tkinter.Scrollbar(self.root, **kwargs)
1002
1003    def test_activerelief(self):
1004        widget = self.create()
1005        self.checkReliefParam(widget, 'activerelief')
1006
1007    def test_elementborderwidth(self):
1008        widget = self.create()
1009        self.checkPixelsParam(widget, 'elementborderwidth', 4.3, 5.6, -2, '1m')
1010
1011    def test_orient(self):
1012        widget = self.create()
1013        self.checkEnumParam(widget, 'orient', 'vertical', 'horizontal',
1014                errmsg='bad orientation "{}": must be vertical or horizontal')
1015
1016    def test_activate(self):
1017        sb = self.create()
1018        for e in ('arrow1', 'slider', 'arrow2'):
1019            sb.activate(e)
1020            self.assertEqual(sb.activate(), e)
1021        sb.activate('')
1022        self.assertIsNone(sb.activate())
1023        self.assertRaises(TypeError, sb.activate, 'arrow1', 'arrow2')
1024
1025    def test_set(self):
1026        sb = self.create()
1027        sb.set(0.2, 0.4)
1028        self.assertEqual(sb.get(), (0.2, 0.4))
1029        self.assertRaises(TclError, sb.set, 'abc', 'def')
1030        self.assertRaises(TclError, sb.set, 0.6, 'def')
1031        self.assertRaises(TclError, sb.set, 0.6, None)
1032        self.assertRaises(TypeError, sb.set, 0.6)
1033        self.assertRaises(TypeError, sb.set, 0.6, 0.7, 0.8)
1034
1035
1036@add_standard_options(StandardOptionsTests)
1037class PanedWindowTest(AbstractWidgetTest, unittest.TestCase):
1038    OPTIONS = (
1039        'background', 'borderwidth', 'cursor',
1040        'handlepad', 'handlesize', 'height',
1041        'opaqueresize', 'orient',
1042        'proxybackground', 'proxyborderwidth', 'proxyrelief',
1043        'relief',
1044        'sashcursor', 'sashpad', 'sashrelief', 'sashwidth',
1045        'showhandle', 'width',
1046    )
1047    default_orient = 'horizontal'
1048
1049    def create(self, **kwargs):
1050        return tkinter.PanedWindow(self.root, **kwargs)
1051
1052    def test_handlepad(self):
1053        widget = self.create()
1054        self.checkPixelsParam(widget, 'handlepad', 5, 6.4, 7.6, -3, '1m')
1055
1056    def test_handlesize(self):
1057        widget = self.create()
1058        self.checkPixelsParam(widget, 'handlesize', 8, 9.4, 10.6, -3, '2m',
1059                              conv=noconv)
1060
1061    def test_height(self):
1062        widget = self.create()
1063        self.checkPixelsParam(widget, 'height', 100, 101.2, 102.6, -100, 0, '1i',
1064                              conv=noconv)
1065
1066    def test_opaqueresize(self):
1067        widget = self.create()
1068        self.checkBooleanParam(widget, 'opaqueresize')
1069
1070    @requires_tcl(8, 6, 5)
1071    def test_proxybackground(self):
1072        widget = self.create()
1073        self.checkColorParam(widget, 'proxybackground')
1074
1075    @requires_tcl(8, 6, 5)
1076    def test_proxyborderwidth(self):
1077        widget = self.create()
1078        self.checkPixelsParam(widget, 'proxyborderwidth',
1079                              0, 1.3, 2.9, 6, -2, '10p',
1080                              conv=noconv)
1081
1082    @requires_tcl(8, 6, 5)
1083    def test_proxyrelief(self):
1084        widget = self.create()
1085        self.checkReliefParam(widget, 'proxyrelief')
1086
1087    def test_sashcursor(self):
1088        widget = self.create()
1089        self.checkCursorParam(widget, 'sashcursor')
1090
1091    def test_sashpad(self):
1092        widget = self.create()
1093        self.checkPixelsParam(widget, 'sashpad', 8, 1.3, 2.6, -2, '2m')
1094
1095    def test_sashrelief(self):
1096        widget = self.create()
1097        self.checkReliefParam(widget, 'sashrelief')
1098
1099    def test_sashwidth(self):
1100        widget = self.create()
1101        self.checkPixelsParam(widget, 'sashwidth', 10, 11.1, 15.6, -3, '1m',
1102                              conv=noconv)
1103
1104    def test_showhandle(self):
1105        widget = self.create()
1106        self.checkBooleanParam(widget, 'showhandle')
1107
1108    def test_width(self):
1109        widget = self.create()
1110        self.checkPixelsParam(widget, 'width', 402, 403.4, 404.6, -402, 0, '5i',
1111                              conv=noconv)
1112
1113    def create2(self):
1114        p = self.create()
1115        b = tkinter.Button(p)
1116        c = tkinter.Button(p)
1117        p.add(b)
1118        p.add(c)
1119        return p, b, c
1120
1121    def test_paneconfigure(self):
1122        p, b, c = self.create2()
1123        self.assertRaises(TypeError, p.paneconfigure)
1124        d = p.paneconfigure(b)
1125        self.assertIsInstance(d, dict)
1126        for k, v in d.items():
1127            self.assertEqual(len(v), 5)
1128            self.assertEqual(v, p.paneconfigure(b, k))
1129            self.assertEqual(v[4], p.panecget(b, k))
1130
1131    def check_paneconfigure(self, p, b, name, value, expected, stringify=False):
1132        conv = lambda x: x
1133        if not self.wantobjects or stringify:
1134            expected = str(expected)
1135        if self.wantobjects and stringify:
1136            conv = str
1137        p.paneconfigure(b, **{name: value})
1138        self.assertEqual(conv(p.paneconfigure(b, name)[4]), expected)
1139        self.assertEqual(conv(p.panecget(b, name)), expected)
1140
1141    def check_paneconfigure_bad(self, p, b, name, msg):
1142        with self.assertRaisesRegex(TclError, msg):
1143            p.paneconfigure(b, **{name: 'badValue'})
1144
1145    def test_paneconfigure_after(self):
1146        p, b, c = self.create2()
1147        self.check_paneconfigure(p, b, 'after', c, str(c))
1148        self.check_paneconfigure_bad(p, b, 'after',
1149                                     'bad window path name "badValue"')
1150
1151    def test_paneconfigure_before(self):
1152        p, b, c = self.create2()
1153        self.check_paneconfigure(p, b, 'before', c, str(c))
1154        self.check_paneconfigure_bad(p, b, 'before',
1155                                     'bad window path name "badValue"')
1156
1157    def test_paneconfigure_height(self):
1158        p, b, c = self.create2()
1159        self.check_paneconfigure(p, b, 'height', 10, 10,
1160                                 stringify=get_tk_patchlevel() < (8, 5, 11))
1161        self.check_paneconfigure_bad(p, b, 'height',
1162                                     'bad screen distance "badValue"')
1163
1164    @requires_tcl(8, 5)
1165    def test_paneconfigure_hide(self):
1166        p, b, c = self.create2()
1167        self.check_paneconfigure(p, b, 'hide', False, 0)
1168        self.check_paneconfigure_bad(p, b, 'hide',
1169                                     'expected boolean value but got "badValue"')
1170
1171    def test_paneconfigure_minsize(self):
1172        p, b, c = self.create2()
1173        self.check_paneconfigure(p, b, 'minsize', 10, 10)
1174        self.check_paneconfigure_bad(p, b, 'minsize',
1175                                     'bad screen distance "badValue"')
1176
1177    def test_paneconfigure_padx(self):
1178        p, b, c = self.create2()
1179        self.check_paneconfigure(p, b, 'padx', 1.3, 1)
1180        self.check_paneconfigure_bad(p, b, 'padx',
1181                                     'bad screen distance "badValue"')
1182
1183    def test_paneconfigure_pady(self):
1184        p, b, c = self.create2()
1185        self.check_paneconfigure(p, b, 'pady', 1.3, 1)
1186        self.check_paneconfigure_bad(p, b, 'pady',
1187                                     'bad screen distance "badValue"')
1188
1189    def test_paneconfigure_sticky(self):
1190        p, b, c = self.create2()
1191        self.check_paneconfigure(p, b, 'sticky', 'nsew', 'nesw')
1192        self.check_paneconfigure_bad(p, b, 'sticky',
1193                                     'bad stickyness value "badValue": must '
1194                                     'be a string containing zero or more of '
1195                                     'n, e, s, and w')
1196
1197    @requires_tcl(8, 5)
1198    def test_paneconfigure_stretch(self):
1199        p, b, c = self.create2()
1200        self.check_paneconfigure(p, b, 'stretch', 'alw', 'always')
1201        self.check_paneconfigure_bad(p, b, 'stretch',
1202                                     'bad stretch "badValue": must be '
1203                                     'always, first, last, middle, or never')
1204
1205    def test_paneconfigure_width(self):
1206        p, b, c = self.create2()
1207        self.check_paneconfigure(p, b, 'width', 10, 10,
1208                                 stringify=get_tk_patchlevel() < (8, 5, 11))
1209        self.check_paneconfigure_bad(p, b, 'width',
1210                                     'bad screen distance "badValue"')
1211
1212
1213@add_standard_options(StandardOptionsTests)
1214class MenuTest(AbstractWidgetTest, unittest.TestCase):
1215    OPTIONS = (
1216        'activebackground', 'activeborderwidth', 'activeforeground',
1217        'background', 'borderwidth', 'cursor',
1218        'disabledforeground', 'font', 'foreground',
1219        'postcommand', 'relief', 'selectcolor', 'takefocus',
1220        'tearoff', 'tearoffcommand', 'title', 'type',
1221    )
1222    _conv_pixels = noconv
1223
1224    def create(self, **kwargs):
1225        return tkinter.Menu(self.root, **kwargs)
1226
1227    def test_postcommand(self):
1228        widget = self.create()
1229        self.checkCommandParam(widget, 'postcommand')
1230
1231    def test_tearoff(self):
1232        widget = self.create()
1233        self.checkBooleanParam(widget, 'tearoff')
1234
1235    def test_tearoffcommand(self):
1236        widget = self.create()
1237        self.checkCommandParam(widget, 'tearoffcommand')
1238
1239    def test_title(self):
1240        widget = self.create()
1241        self.checkParam(widget, 'title', 'any string')
1242
1243    def test_type(self):
1244        widget = self.create()
1245        self.checkEnumParam(widget, 'type',
1246                'normal', 'tearoff', 'menubar')
1247
1248    def test_entryconfigure(self):
1249        m1 = self.create()
1250        m1.add_command(label='test')
1251        self.assertRaises(TypeError, m1.entryconfigure)
1252        with self.assertRaisesRegex(TclError, 'bad menu entry index "foo"'):
1253            m1.entryconfigure('foo')
1254        d = m1.entryconfigure(1)
1255        self.assertIsInstance(d, dict)
1256        for k, v in d.items():
1257            self.assertIsInstance(k, str)
1258            self.assertIsInstance(v, tuple)
1259            self.assertEqual(len(v), 5)
1260            self.assertEqual(v[0], k)
1261            self.assertEqual(m1.entrycget(1, k), v[4])
1262        m1.destroy()
1263
1264    def test_entryconfigure_label(self):
1265        m1 = self.create()
1266        m1.add_command(label='test')
1267        self.assertEqual(m1.entrycget(1, 'label'), 'test')
1268        m1.entryconfigure(1, label='changed')
1269        self.assertEqual(m1.entrycget(1, 'label'), 'changed')
1270
1271    def test_entryconfigure_variable(self):
1272        m1 = self.create()
1273        v1 = tkinter.BooleanVar(self.root)
1274        v2 = tkinter.BooleanVar(self.root)
1275        m1.add_checkbutton(variable=v1, onvalue=True, offvalue=False,
1276                           label='Nonsense')
1277        self.assertEqual(str(m1.entrycget(1, 'variable')), str(v1))
1278        m1.entryconfigure(1, variable=v2)
1279        self.assertEqual(str(m1.entrycget(1, 'variable')), str(v2))
1280
1281
1282@add_standard_options(PixelSizeTests, StandardOptionsTests)
1283class MessageTest(AbstractWidgetTest, unittest.TestCase):
1284    OPTIONS = (
1285        'anchor', 'aspect', 'background', 'borderwidth',
1286        'cursor', 'font', 'foreground',
1287        'highlightbackground', 'highlightcolor', 'highlightthickness',
1288        'justify', 'padx', 'pady', 'relief',
1289        'takefocus', 'text', 'textvariable', 'width',
1290    )
1291    _conv_pad_pixels = noconv
1292
1293    def create(self, **kwargs):
1294        return tkinter.Message(self.root, **kwargs)
1295
1296    def test_aspect(self):
1297        widget = self.create()
1298        self.checkIntegerParam(widget, 'aspect', 250, 0, -300)
1299
1300
1301tests_gui = (
1302        ButtonTest, CanvasTest, CheckbuttonTest, EntryTest,
1303        FrameTest, LabelFrameTest,LabelTest, ListboxTest,
1304        MenubuttonTest, MenuTest, MessageTest, OptionMenuTest,
1305        PanedWindowTest, RadiobuttonTest, ScaleTest, ScrollbarTest,
1306        SpinboxTest, TextTest, ToplevelTest,
1307)
1308
1309if __name__ == '__main__':
1310    unittest.main()
1311