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