• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1import unittest
2import tkinter
3from tkinter import TclError
4import os
5from test.support import requires
6
7from tkinter.test.support import (requires_tcl,
8                                  get_tk_patchlevel, widget_eq,
9                                  AbstractDefaultRootTest)
10from tkinter.test.widget_tests import (
11    add_standard_options,
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 = False
24
25    def test_configure_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_configure_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_configure_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_configure_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_configure_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_configure_screen(self):
79        widget = self.create()
80        if widget._windowingsystem != 'x11':
81            self.skipTest('Not using Tk for X11')
82        self.assertEqual(widget['screen'], '')
83        try:
84            display = os.environ['DISPLAY']
85        except KeyError:
86            self.skipTest('No $DISPLAY set.')
87        self.checkInvalidParam(widget, 'screen', display,
88                errmsg="can't modify -screen option after widget is created")
89        widget2 = self.create(screen=display)
90        self.assertEqual(widget2['screen'], display)
91
92    def test_configure_use(self):
93        widget = self.create()
94        self.assertEqual(widget['use'], '')
95        parent = self.create(container=True)
96        wid = hex(parent.winfo_id())
97        with self.subTest(wid=wid):
98            widget2 = self.create(use=wid)
99            self.assertEqual(widget2['use'], wid)
100
101
102@add_standard_options(StandardOptionsTests)
103class FrameTest(AbstractToplevelTest, unittest.TestCase):
104    OPTIONS = (
105        'background', 'borderwidth',
106        'class', 'colormap', 'container', 'cursor', 'height',
107        'highlightbackground', 'highlightcolor', 'highlightthickness',
108        'padx', 'pady', 'relief', 'takefocus', 'visual', 'width',
109    )
110
111    def create(self, **kwargs):
112        return tkinter.Frame(self.root, **kwargs)
113
114
115@add_standard_options(StandardOptionsTests)
116class LabelFrameTest(AbstractToplevelTest, unittest.TestCase):
117    OPTIONS = (
118        'background', 'borderwidth',
119        'class', 'colormap', 'container', 'cursor',
120        'font', 'foreground', 'height',
121        'highlightbackground', 'highlightcolor', 'highlightthickness',
122        'labelanchor', 'labelwidget', 'padx', 'pady', 'relief',
123        'takefocus', 'text', 'visual', 'width',
124    )
125
126    def create(self, **kwargs):
127        return tkinter.LabelFrame(self.root, **kwargs)
128
129    def test_configure_labelanchor(self):
130        widget = self.create()
131        self.checkEnumParam(widget, 'labelanchor',
132                            'e', 'en', 'es', 'n', 'ne', 'nw',
133                            's', 'se', 'sw', 'w', 'wn', 'ws')
134        self.checkInvalidParam(widget, 'labelanchor', 'center')
135
136    def test_configure_labelwidget(self):
137        widget = self.create()
138        label = tkinter.Label(self.root, text='Mupp', name='foo')
139        self.checkParam(widget, 'labelwidget', label, expected='.foo')
140        label.destroy()
141
142
143class AbstractLabelTest(AbstractWidgetTest, IntegerSizeTests):
144    _conv_pixels = False
145
146    def test_configure_highlightthickness(self):
147        widget = self.create()
148        self.checkPixelsParam(widget, 'highlightthickness',
149                              0, 1.3, 2.6, 6, -2, '10p')
150
151
152@add_standard_options(StandardOptionsTests)
153class LabelTest(AbstractLabelTest, unittest.TestCase):
154    OPTIONS = (
155        'activebackground', 'activeforeground', 'anchor',
156        'background', 'bitmap', 'borderwidth', 'compound', 'cursor',
157        'disabledforeground', 'font', 'foreground', 'height',
158        'highlightbackground', 'highlightcolor', 'highlightthickness',
159        'image', 'justify', 'padx', 'pady', 'relief', 'state',
160        'takefocus', 'text', 'textvariable',
161        'underline', 'width', 'wraplength',
162    )
163
164    def create(self, **kwargs):
165        return tkinter.Label(self.root, **kwargs)
166
167
168@add_standard_options(StandardOptionsTests)
169class ButtonTest(AbstractLabelTest, unittest.TestCase):
170    OPTIONS = (
171        'activebackground', 'activeforeground', 'anchor',
172        'background', 'bitmap', 'borderwidth',
173        'command', 'compound', 'cursor', 'default',
174        'disabledforeground', 'font', 'foreground', 'height',
175        'highlightbackground', 'highlightcolor', 'highlightthickness',
176        'image', 'justify', 'overrelief', 'padx', 'pady', 'relief',
177        'repeatdelay', 'repeatinterval',
178        'state', 'takefocus', 'text', 'textvariable',
179        'underline', 'width', 'wraplength')
180
181    def create(self, **kwargs):
182        return tkinter.Button(self.root, **kwargs)
183
184    def test_configure_default(self):
185        widget = self.create()
186        self.checkEnumParam(widget, 'default', 'active', 'disabled', 'normal')
187
188
189@add_standard_options(StandardOptionsTests)
190class CheckbuttonTest(AbstractLabelTest, unittest.TestCase):
191    OPTIONS = (
192        'activebackground', 'activeforeground', 'anchor',
193        'background', 'bitmap', 'borderwidth',
194        'command', 'compound', 'cursor',
195        'disabledforeground', 'font', 'foreground', 'height',
196        'highlightbackground', 'highlightcolor', 'highlightthickness',
197        'image', 'indicatoron', 'justify',
198        'offrelief', 'offvalue', 'onvalue', 'overrelief',
199        'padx', 'pady', 'relief', 'selectcolor', 'selectimage', 'state',
200        'takefocus', 'text', 'textvariable',
201        'tristateimage', 'tristatevalue',
202        'underline', 'variable', 'width', 'wraplength',
203    )
204
205    def create(self, **kwargs):
206        return tkinter.Checkbutton(self.root, **kwargs)
207
208
209    def test_configure_offvalue(self):
210        widget = self.create()
211        self.checkParams(widget, 'offvalue', 1, 2.3, '', 'any string')
212
213    def test_configure_onvalue(self):
214        widget = self.create()
215        self.checkParams(widget, 'onvalue', 1, 2.3, '', 'any string')
216
217    def test_unique_variables(self):
218        frames = []
219        buttons = []
220        for i in range(2):
221            f = tkinter.Frame(self.root)
222            f.pack()
223            frames.append(f)
224            for j in 'AB':
225                b = tkinter.Checkbutton(f, text=j)
226                b.pack()
227                buttons.append(b)
228        variables = [str(b['variable']) for b in buttons]
229        self.assertEqual(len(set(variables)), 4, variables)
230
231    def test_same_name(self):
232        f1 = tkinter.Frame(self.root)
233        f2 = tkinter.Frame(self.root)
234        b1 = tkinter.Checkbutton(f1, name='test', text='Test1')
235        b2 = tkinter.Checkbutton(f2, name='test', text='Test2')
236
237        v = tkinter.IntVar(self.root, name='test')
238        b1.select()
239        self.assertEqual(v.get(), 1)
240        b2.deselect()
241        self.assertEqual(v.get(), 0)
242
243
244@add_standard_options(StandardOptionsTests)
245class RadiobuttonTest(AbstractLabelTest, unittest.TestCase):
246    OPTIONS = (
247        'activebackground', 'activeforeground', 'anchor',
248        'background', 'bitmap', 'borderwidth',
249        'command', 'compound', 'cursor',
250        'disabledforeground', 'font', 'foreground', 'height',
251        'highlightbackground', 'highlightcolor', 'highlightthickness',
252        'image', 'indicatoron', 'justify', 'offrelief', 'overrelief',
253        'padx', 'pady', 'relief', 'selectcolor', 'selectimage', 'state',
254        'takefocus', 'text', 'textvariable',
255        'tristateimage', 'tristatevalue',
256        'underline', 'value', 'variable', 'width', 'wraplength',
257    )
258
259    def create(self, **kwargs):
260        return tkinter.Radiobutton(self.root, **kwargs)
261
262    def test_configure_value(self):
263        widget = self.create()
264        self.checkParams(widget, 'value', 1, 2.3, '', 'any string')
265
266
267@add_standard_options(StandardOptionsTests)
268class MenubuttonTest(AbstractLabelTest, unittest.TestCase):
269    OPTIONS = (
270        'activebackground', 'activeforeground', 'anchor',
271        'background', 'bitmap', 'borderwidth',
272        'compound', 'cursor', 'direction',
273        'disabledforeground', 'font', 'foreground', 'height',
274        'highlightbackground', 'highlightcolor', 'highlightthickness',
275        'image', 'indicatoron', 'justify', 'menu',
276        'padx', 'pady', 'relief', 'state',
277        'takefocus', 'text', 'textvariable',
278        'underline', 'width', 'wraplength',
279    )
280    _conv_pixels = round
281
282    def create(self, **kwargs):
283        return tkinter.Menubutton(self.root, **kwargs)
284
285    def test_configure_direction(self):
286        widget = self.create()
287        self.checkEnumParam(widget, 'direction',
288                'above', 'below', 'flush', 'left', 'right')
289
290    def test_configure_height(self):
291        widget = self.create()
292        self.checkIntegerParam(widget, 'height', 100, -100, 0, conv=str)
293
294    test_configure_highlightthickness = \
295        StandardOptionsTests.test_configure_highlightthickness
296
297    def test_configure_image(self):
298        widget = self.create()
299        image = tkinter.PhotoImage(master=self.root, name='image1')
300        self.checkParam(widget, 'image', image, conv=str)
301        errmsg = 'image "spam" doesn\'t exist'
302        with self.assertRaises(tkinter.TclError) as cm:
303            widget['image'] = 'spam'
304        if errmsg is not None:
305            self.assertEqual(str(cm.exception), errmsg)
306        with self.assertRaises(tkinter.TclError) as cm:
307            widget.configure({'image': 'spam'})
308        if errmsg is not None:
309            self.assertEqual(str(cm.exception), errmsg)
310
311    def test_configure_menu(self):
312        widget = self.create()
313        menu = tkinter.Menu(widget, name='menu')
314        self.checkParam(widget, 'menu', menu, eq=widget_eq)
315        menu.destroy()
316
317    def test_configure_padx(self):
318        widget = self.create()
319        self.checkPixelsParam(widget, 'padx', 3, 4.4, 5.6, '12m')
320        self.checkParam(widget, 'padx', -2, expected=0)
321
322    def test_configure_pady(self):
323        widget = self.create()
324        self.checkPixelsParam(widget, 'pady', 3, 4.4, 5.6, '12m')
325        self.checkParam(widget, 'pady', -2, expected=0)
326
327    def test_configure_width(self):
328        widget = self.create()
329        self.checkIntegerParam(widget, 'width', 402, -402, 0, conv=str)
330
331
332class OptionMenuTest(MenubuttonTest, unittest.TestCase):
333
334    def create(self, default='b', values=('a', 'b', 'c'), **kwargs):
335        return tkinter.OptionMenu(self.root, None, default, *values, **kwargs)
336
337    def test_bad_kwarg(self):
338        with self.assertRaisesRegex(TclError, r"^unknown option -image$"):
339            tkinter.OptionMenu(self.root, None, 'b', image='')
340
341
342@add_standard_options(IntegerSizeTests, StandardOptionsTests)
343class EntryTest(AbstractWidgetTest, unittest.TestCase):
344    OPTIONS = (
345        'background', 'borderwidth', 'cursor',
346        'disabledbackground', 'disabledforeground',
347        'exportselection', 'font', 'foreground',
348        'highlightbackground', 'highlightcolor', 'highlightthickness',
349        'insertbackground', 'insertborderwidth',
350        'insertofftime', 'insertontime', 'insertwidth',
351        'invalidcommand', 'justify', 'readonlybackground', 'relief',
352        'selectbackground', 'selectborderwidth', 'selectforeground',
353        'show', 'state', 'takefocus', 'textvariable',
354        'validate', 'validatecommand', 'width', 'xscrollcommand',
355    )
356
357    def create(self, **kwargs):
358        return tkinter.Entry(self.root, **kwargs)
359
360    def test_configure_disabledbackground(self):
361        widget = self.create()
362        self.checkColorParam(widget, 'disabledbackground')
363
364    def test_configure_insertborderwidth(self):
365        widget = self.create(insertwidth=100)
366        self.checkPixelsParam(widget, 'insertborderwidth',
367                              0, 1.3, 2.6, 6, -2, '10p')
368        # insertborderwidth is bounded above by a half of insertwidth.
369        self.checkParam(widget, 'insertborderwidth', 60, expected=100//2)
370
371    def test_configure_insertwidth(self):
372        widget = self.create()
373        self.checkPixelsParam(widget, 'insertwidth', 1.3, 3.6, '10p')
374        self.checkParam(widget, 'insertwidth', 0.1, expected=2)
375        self.checkParam(widget, 'insertwidth', -2, expected=2)
376        self.checkParam(widget, 'insertwidth', 0.9, expected=1)
377
378    def test_configure_invalidcommand(self):
379        widget = self.create()
380        self.checkCommandParam(widget, 'invalidcommand')
381        self.checkCommandParam(widget, 'invcmd')
382
383    def test_configure_readonlybackground(self):
384        widget = self.create()
385        self.checkColorParam(widget, 'readonlybackground')
386
387    def test_configure_show(self):
388        widget = self.create()
389        self.checkParam(widget, 'show', '*')
390        self.checkParam(widget, 'show', '')
391        self.checkParam(widget, 'show', ' ')
392
393    def test_configure_state(self):
394        widget = self.create()
395        self.checkEnumParam(widget, 'state',
396                            'disabled', 'normal', 'readonly')
397
398    def test_configure_validate(self):
399        widget = self.create()
400        self.checkEnumParam(widget, 'validate',
401                'all', 'key', 'focus', 'focusin', 'focusout', 'none')
402
403    def test_configure_validatecommand(self):
404        widget = self.create()
405        self.checkCommandParam(widget, 'validatecommand')
406        self.checkCommandParam(widget, 'vcmd')
407
408    def test_selection_methods(self):
409        widget = self.create()
410        widget.insert(0, '12345')
411        self.assertFalse(widget.selection_present())
412        widget.selection_range(0, 'end')
413        self.assertEqual(widget.selection_get(), '12345')
414        self.assertTrue(widget.selection_present())
415        widget.selection_from(1)
416        widget.selection_to(2)
417        self.assertEqual(widget.selection_get(), '2')
418        widget.selection_range(3, 4)
419        self.assertEqual(widget.selection_get(), '4')
420        widget.selection_clear()
421        self.assertFalse(widget.selection_present())
422        widget.selection_range(0, 'end')
423        widget.selection_adjust(4)
424        self.assertEqual(widget.selection_get(), '1234')
425        widget.selection_adjust(1)
426        self.assertEqual(widget.selection_get(), '234')
427        widget.selection_adjust(5)
428        self.assertEqual(widget.selection_get(), '2345')
429        widget.selection_adjust(0)
430        self.assertEqual(widget.selection_get(), '12345')
431        widget.selection_adjust(0)
432
433
434@add_standard_options(StandardOptionsTests)
435class SpinboxTest(EntryTest, unittest.TestCase):
436    OPTIONS = (
437        'activebackground', 'background', 'borderwidth',
438        'buttonbackground', 'buttoncursor', 'buttondownrelief', 'buttonuprelief',
439        'command', 'cursor', 'disabledbackground', 'disabledforeground',
440        'exportselection', 'font', 'foreground', 'format', 'from',
441        'highlightbackground', 'highlightcolor', 'highlightthickness',
442        'increment',
443        'insertbackground', 'insertborderwidth',
444        'insertofftime', 'insertontime', 'insertwidth',
445        'invalidcommand', 'justify', 'relief', 'readonlybackground',
446        'repeatdelay', 'repeatinterval',
447        'selectbackground', 'selectborderwidth', 'selectforeground',
448        'state', 'takefocus', 'textvariable', 'to',
449        'validate', 'validatecommand', 'values',
450        'width', 'wrap', 'xscrollcommand',
451    )
452
453    def create(self, **kwargs):
454        return tkinter.Spinbox(self.root, **kwargs)
455
456    test_configure_show = None
457
458    def test_configure_buttonbackground(self):
459        widget = self.create()
460        self.checkColorParam(widget, 'buttonbackground')
461
462    def test_configure_buttoncursor(self):
463        widget = self.create()
464        self.checkCursorParam(widget, 'buttoncursor')
465
466    def test_configure_buttondownrelief(self):
467        widget = self.create()
468        self.checkReliefParam(widget, 'buttondownrelief')
469
470    def test_configure_buttonuprelief(self):
471        widget = self.create()
472        self.checkReliefParam(widget, 'buttonuprelief')
473
474    def test_configure_format(self):
475        widget = self.create()
476        self.checkParam(widget, 'format', '%2f')
477        self.checkParam(widget, 'format', '%2.2f')
478        self.checkParam(widget, 'format', '%.2f')
479        self.checkParam(widget, 'format', '%2.f')
480        self.checkInvalidParam(widget, 'format', '%2e-1f')
481        self.checkInvalidParam(widget, 'format', '2.2')
482        self.checkInvalidParam(widget, 'format', '%2.-2f')
483        self.checkParam(widget, 'format', '%-2.02f')
484        self.checkParam(widget, 'format', '% 2.02f')
485        self.checkParam(widget, 'format', '% -2.200f')
486        self.checkParam(widget, 'format', '%09.200f')
487        self.checkInvalidParam(widget, 'format', '%d')
488
489    def test_configure_from(self):
490        widget = self.create()
491        self.checkParam(widget, 'to', 100.0)
492        self.checkFloatParam(widget, 'from', -10, 10.2, 11.7)
493        self.checkInvalidParam(widget, 'from', 200,
494                errmsg='-to value must be greater than -from value')
495
496    def test_configure_increment(self):
497        widget = self.create()
498        self.checkFloatParam(widget, 'increment', -1, 1, 10.2, 12.8, 0)
499
500    def test_configure_to(self):
501        widget = self.create()
502        self.checkParam(widget, 'from', -100.0)
503        self.checkFloatParam(widget, 'to', -10, 10.2, 11.7)
504        self.checkInvalidParam(widget, 'to', -200,
505                errmsg='-to value must be greater than -from value')
506
507    def test_configure_values(self):
508        # XXX
509        widget = self.create()
510        self.assertEqual(widget['values'], '')
511        self.checkParam(widget, 'values', 'mon tue wed thur')
512        self.checkParam(widget, 'values', ('mon', 'tue', 'wed', 'thur'),
513                        expected='mon tue wed thur')
514        self.checkParam(widget, 'values', (42, 3.14, '', 'any string'),
515                        expected='42 3.14 {} {any string}')
516        self.checkParam(widget, 'values', '')
517
518    def test_configure_wrap(self):
519        widget = self.create()
520        self.checkBooleanParam(widget, 'wrap')
521
522    def test_bbox(self):
523        widget = self.create()
524        self.assertIsBoundingBox(widget.bbox(0))
525        self.assertRaises(tkinter.TclError, widget.bbox, 'noindex')
526        self.assertRaises(tkinter.TclError, widget.bbox, None)
527        self.assertRaises(TypeError, widget.bbox)
528        self.assertRaises(TypeError, widget.bbox, 0, 1)
529
530    def test_selection_methods(self):
531        widget = self.create()
532        widget.insert(0, '12345')
533        self.assertFalse(widget.selection_present())
534        widget.selection_range(0, 'end')
535        self.assertEqual(widget.selection_get(), '12345')
536        self.assertTrue(widget.selection_present())
537        widget.selection_from(1)
538        widget.selection_to(2)
539        self.assertEqual(widget.selection_get(), '2')
540        widget.selection_range(3, 4)
541        self.assertEqual(widget.selection_get(), '4')
542        widget.selection_clear()
543        self.assertFalse(widget.selection_present())
544        widget.selection_range(0, 'end')
545        widget.selection_adjust(4)
546        self.assertEqual(widget.selection_get(), '1234')
547        widget.selection_adjust(1)
548        self.assertEqual(widget.selection_get(), '234')
549        widget.selection_adjust(5)
550        self.assertEqual(widget.selection_get(), '2345')
551        widget.selection_adjust(0)
552        self.assertEqual(widget.selection_get(), '12345')
553
554    def test_selection_element(self):
555        widget = self.create()
556        self.assertEqual(widget.selection_element(), "none")
557        widget.selection_element("buttonup")
558        self.assertEqual(widget.selection_element(), "buttonup")
559        widget.selection_element("buttondown")
560        self.assertEqual(widget.selection_element(), "buttondown")
561
562
563@add_standard_options(StandardOptionsTests)
564class TextTest(AbstractWidgetTest, unittest.TestCase):
565    OPTIONS = (
566        'autoseparators', 'background', 'blockcursor', 'borderwidth',
567        'cursor', 'endline', 'exportselection',
568        'font', 'foreground', 'height',
569        'highlightbackground', 'highlightcolor', 'highlightthickness',
570        'inactiveselectbackground', 'insertbackground', 'insertborderwidth',
571        'insertofftime', 'insertontime', 'insertunfocussed', 'insertwidth',
572        'maxundo', 'padx', 'pady', 'relief',
573        'selectbackground', 'selectborderwidth', 'selectforeground',
574        'setgrid', 'spacing1', 'spacing2', 'spacing3', 'startline', 'state',
575        'tabs', 'tabstyle', 'takefocus', 'undo', 'width', 'wrap',
576        'xscrollcommand', 'yscrollcommand',
577    )
578
579    def create(self, **kwargs):
580        return tkinter.Text(self.root, **kwargs)
581
582    def test_configure_autoseparators(self):
583        widget = self.create()
584        self.checkBooleanParam(widget, 'autoseparators')
585
586    def test_configure_blockcursor(self):
587        widget = self.create()
588        self.checkBooleanParam(widget, 'blockcursor')
589
590    def test_configure_endline(self):
591        widget = self.create()
592        text = '\n'.join('Line %d' for i in range(100))
593        widget.insert('end', text)
594        self.checkParam(widget, 'endline', 200, expected='')
595        self.checkParam(widget, 'endline', -10, expected='')
596        self.checkInvalidParam(widget, 'endline', 'spam',
597                errmsg='expected integer but got "spam"')
598        self.checkParam(widget, 'endline', 50)
599        self.checkParam(widget, 'startline', 15)
600        self.checkInvalidParam(widget, 'endline', 10,
601                errmsg='-startline must be less than or equal to -endline')
602
603    def test_configure_height(self):
604        widget = self.create()
605        self.checkPixelsParam(widget, 'height', 100, 101.2, 102.6, '3c')
606        self.checkParam(widget, 'height', -100, expected=1)
607        self.checkParam(widget, 'height', 0, expected=1)
608
609    def test_configure_maxundo(self):
610        widget = self.create()
611        self.checkIntegerParam(widget, 'maxundo', 0, 5, -1)
612
613    def test_configure_inactiveselectbackground(self):
614        widget = self.create()
615        self.checkColorParam(widget, 'inactiveselectbackground')
616
617    @requires_tcl(8, 6)
618    def test_configure_insertunfocussed(self):
619        widget = self.create()
620        self.checkEnumParam(widget, 'insertunfocussed',
621                            'hollow', 'none', 'solid')
622
623    def test_configure_selectborderwidth(self):
624        widget = self.create()
625        self.checkPixelsParam(widget, 'selectborderwidth',
626                              1.3, 2.6, -2, '10p', conv=False)
627
628    def test_configure_spacing1(self):
629        widget = self.create()
630        self.checkPixelsParam(widget, 'spacing1', 20, 21.4, 22.6, '0.5c')
631        self.checkParam(widget, 'spacing1', -5, expected=0)
632
633    def test_configure_spacing2(self):
634        widget = self.create()
635        self.checkPixelsParam(widget, 'spacing2', 5, 6.4, 7.6, '0.1c')
636        self.checkParam(widget, 'spacing2', -1, expected=0)
637
638    def test_configure_spacing3(self):
639        widget = self.create()
640        self.checkPixelsParam(widget, 'spacing3', 20, 21.4, 22.6, '0.5c')
641        self.checkParam(widget, 'spacing3', -10, expected=0)
642
643    def test_configure_startline(self):
644        widget = self.create()
645        text = '\n'.join('Line %d' for i in range(100))
646        widget.insert('end', text)
647        self.checkParam(widget, 'startline', 200, expected='')
648        self.checkParam(widget, 'startline', -10, expected='')
649        self.checkInvalidParam(widget, 'startline', 'spam',
650                errmsg='expected integer but got "spam"')
651        self.checkParam(widget, 'startline', 10)
652        self.checkParam(widget, 'endline', 50)
653        self.checkInvalidParam(widget, 'startline', 70,
654                errmsg='-startline must be less than or equal to -endline')
655
656    def test_configure_state(self):
657        widget = self.create()
658        self.checkEnumParam(widget, 'state', 'disabled', 'normal')
659
660    def test_configure_tabs(self):
661        widget = self.create()
662        self.checkParam(widget, 'tabs', (10.2, 20.7, '1i', '2i'))
663        self.checkParam(widget, 'tabs', '10.2 20.7 1i 2i',
664                        expected=('10.2', '20.7', '1i', '2i'))
665        self.checkParam(widget, 'tabs', '2c left 4c 6c center',
666                        expected=('2c', 'left', '4c', '6c', 'center'))
667        self.checkInvalidParam(widget, 'tabs', 'spam',
668                               errmsg='bad screen distance "spam"')
669
670    def test_configure_tabstyle(self):
671        widget = self.create()
672        self.checkEnumParam(widget, 'tabstyle', 'tabular', 'wordprocessor')
673
674    def test_configure_undo(self):
675        widget = self.create()
676        self.checkBooleanParam(widget, 'undo')
677
678    def test_configure_width(self):
679        widget = self.create()
680        self.checkIntegerParam(widget, 'width', 402)
681        self.checkParam(widget, 'width', -402, expected=1)
682        self.checkParam(widget, 'width', 0, expected=1)
683
684    def test_configure_wrap(self):
685        widget = self.create()
686        self.checkEnumParam(widget, 'wrap', 'char', 'none', 'word')
687
688    def test_bbox(self):
689        widget = self.create()
690        self.assertIsBoundingBox(widget.bbox('1.1'))
691        self.assertIsNone(widget.bbox('end'))
692        self.assertRaises(tkinter.TclError, widget.bbox, 'noindex')
693        self.assertRaises(tkinter.TclError, widget.bbox, None)
694        self.assertRaises(TypeError, widget.bbox)
695        self.assertRaises(TypeError, widget.bbox, '1.1', 'end')
696
697
698@add_standard_options(PixelSizeTests, StandardOptionsTests)
699class CanvasTest(AbstractWidgetTest, unittest.TestCase):
700    OPTIONS = (
701        'background', 'borderwidth',
702        'closeenough', 'confine', 'cursor', 'height',
703        'highlightbackground', 'highlightcolor', 'highlightthickness',
704        'insertbackground', 'insertborderwidth',
705        'insertofftime', 'insertontime', 'insertwidth',
706        'offset', 'relief', 'scrollregion',
707        'selectbackground', 'selectborderwidth', 'selectforeground',
708        'state', 'takefocus',
709        'xscrollcommand', 'xscrollincrement',
710        'yscrollcommand', 'yscrollincrement', 'width',
711    )
712
713    _conv_pixels = round
714    _stringify = True
715
716    def create(self, **kwargs):
717        return tkinter.Canvas(self.root, **kwargs)
718
719    def test_configure_closeenough(self):
720        widget = self.create()
721        self.checkFloatParam(widget, 'closeenough', 24, 2.4, 3.6, -3,
722                             conv=float)
723
724    def test_configure_confine(self):
725        widget = self.create()
726        self.checkBooleanParam(widget, 'confine')
727
728    def test_configure_offset(self):
729        widget = self.create()
730        self.assertEqual(widget['offset'], '0,0')
731        self.checkParams(widget, 'offset',
732                'n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw', 'center')
733        self.checkParam(widget, 'offset', '10,20')
734        self.checkParam(widget, 'offset', '#5,6')
735        self.checkInvalidParam(widget, 'offset', 'spam')
736
737    def test_configure_scrollregion(self):
738        widget = self.create()
739        self.checkParam(widget, 'scrollregion', '0 0 200 150')
740        self.checkParam(widget, 'scrollregion', (0, 0, 200, 150),
741                        expected='0 0 200 150')
742        self.checkParam(widget, 'scrollregion', '')
743        self.checkInvalidParam(widget, 'scrollregion', 'spam',
744                               errmsg='bad scrollRegion "spam"')
745        self.checkInvalidParam(widget, 'scrollregion', (0, 0, 200, 'spam'))
746        self.checkInvalidParam(widget, 'scrollregion', (0, 0, 200))
747        self.checkInvalidParam(widget, 'scrollregion', (0, 0, 200, 150, 0))
748
749    def test_configure_state(self):
750        widget = self.create()
751        self.checkEnumParam(widget, 'state', 'disabled', 'normal',
752                errmsg='bad state value "{}": must be normal or disabled')
753
754    def test_configure_xscrollincrement(self):
755        widget = self.create()
756        self.checkPixelsParam(widget, 'xscrollincrement',
757                              40, 0, 41.2, 43.6, -40, '0.5i')
758
759    def test_configure_yscrollincrement(self):
760        widget = self.create()
761        self.checkPixelsParam(widget, 'yscrollincrement',
762                              10, 0, 11.2, 13.6, -10, '0.1i')
763
764    def _test_option_joinstyle(self, c, factory):
765        for joinstyle in 'bevel', 'miter', 'round':
766            i = factory(joinstyle=joinstyle)
767            self.assertEqual(c.itemcget(i, 'joinstyle'), joinstyle)
768        self.assertRaises(TclError, factory, joinstyle='spam')
769
770    def _test_option_smooth(self, c, factory):
771        for smooth in 1, True, '1', 'true', 'yes', 'on':
772            i = factory(smooth=smooth)
773            self.assertEqual(c.itemcget(i, 'smooth'), 'true')
774        for smooth in 0, False, '0', 'false', 'no', 'off':
775            i = factory(smooth=smooth)
776            self.assertEqual(c.itemcget(i, 'smooth'), '0')
777        i = factory(smooth=True, splinestep=30)
778        self.assertEqual(c.itemcget(i, 'smooth'), 'true')
779        self.assertEqual(c.itemcget(i, 'splinestep'), '30')
780        i = factory(smooth='raw', splinestep=30)
781        self.assertEqual(c.itemcget(i, 'smooth'), 'raw')
782        self.assertEqual(c.itemcget(i, 'splinestep'), '30')
783        self.assertRaises(TclError, factory, smooth='spam')
784
785    def test_create_rectangle(self):
786        c = self.create()
787        i1 = c.create_rectangle(20, 30, 60, 10)
788        self.assertEqual(c.coords(i1), [20.0, 10.0, 60.0, 30.0])
789        self.assertEqual(c.bbox(i1), (19, 9, 61, 31))
790
791        i2 = c.create_rectangle([21, 31, 61, 11])
792        self.assertEqual(c.coords(i2), [21.0, 11.0, 61.0, 31.0])
793        self.assertEqual(c.bbox(i2), (20, 10, 62, 32))
794
795        i3 = c.create_rectangle((22, 32), (62, 12))
796        self.assertEqual(c.coords(i3), [22.0, 12.0, 62.0, 32.0])
797        self.assertEqual(c.bbox(i3), (21, 11, 63, 33))
798
799        i4 = c.create_rectangle([(23, 33), (63, 13)])
800        self.assertEqual(c.coords(i4), [23.0, 13.0, 63.0, 33.0])
801        self.assertEqual(c.bbox(i4), (22, 12, 64, 34))
802
803        self.assertRaises(TclError, c.create_rectangle, 20, 30, 60)
804        self.assertRaises(TclError, c.create_rectangle, [20, 30, 60])
805        self.assertRaises(TclError, c.create_rectangle, 20, 30, 40, 50, 60, 10)
806        self.assertRaises(TclError, c.create_rectangle, [20, 30, 40, 50, 60, 10])
807        self.assertRaises(TclError, c.create_rectangle, 20, 30)
808        self.assertRaises(TclError, c.create_rectangle, [20, 30])
809        self.assertRaises(IndexError, c.create_rectangle)
810        self.assertRaises(IndexError, c.create_rectangle, [])
811
812    def test_create_line(self):
813        c = self.create()
814        i1 = c.create_line(20, 30, 40, 50, 60, 10)
815        self.assertEqual(c.coords(i1), [20.0, 30.0, 40.0, 50.0, 60.0, 10.0])
816        self.assertEqual(c.bbox(i1), (18, 8, 62, 52))
817        self.assertEqual(c.itemcget(i1, 'arrow'), 'none')
818        self.assertEqual(c.itemcget(i1, 'arrowshape'), '8 10 3')
819        self.assertEqual(c.itemcget(i1, 'capstyle'), 'butt')
820        self.assertEqual(c.itemcget(i1, 'joinstyle'), 'round')
821        self.assertEqual(c.itemcget(i1, 'smooth'), '0')
822        self.assertEqual(c.itemcget(i1, 'splinestep'), '12')
823
824        i2 = c.create_line([21, 31, 41, 51, 61, 11])
825        self.assertEqual(c.coords(i2), [21.0, 31.0, 41.0, 51.0, 61.0, 11.0])
826        self.assertEqual(c.bbox(i2), (19, 9, 63, 53))
827
828        i3 = c.create_line((22, 32), (42, 52), (62, 12))
829        self.assertEqual(c.coords(i3), [22.0, 32.0, 42.0, 52.0, 62.0, 12.0])
830        self.assertEqual(c.bbox(i3), (20, 10, 64, 54))
831
832        i4 = c.create_line([(23, 33), (43, 53), (63, 13)])
833        self.assertEqual(c.coords(i4), [23.0, 33.0, 43.0, 53.0, 63.0, 13.0])
834        self.assertEqual(c.bbox(i4), (21, 11, 65, 55))
835
836        self.assertRaises(TclError, c.create_line, 20, 30, 60)
837        self.assertRaises(TclError, c.create_line, [20, 30, 60])
838        self.assertRaises(TclError, c.create_line, 20, 30)
839        self.assertRaises(TclError, c.create_line, [20, 30])
840        self.assertRaises(IndexError, c.create_line)
841        self.assertRaises(IndexError, c.create_line, [])
842
843        for arrow in 'none', 'first', 'last', 'both':
844            i = c.create_line(20, 30, 60, 10, arrow=arrow)
845            self.assertEqual(c.itemcget(i, 'arrow'), arrow)
846        i = c.create_line(20, 30, 60, 10, arrow='first', arrowshape=[10, 15, 5])
847        self.assertEqual(c.itemcget(i, 'arrowshape'), '10 15 5')
848        self.assertRaises(TclError, c.create_line, 20, 30, 60, 10, arrow='spam')
849
850        for capstyle in 'butt', 'projecting', 'round':
851            i = c.create_line(20, 30, 60, 10, capstyle=capstyle)
852            self.assertEqual(c.itemcget(i, 'capstyle'), capstyle)
853        self.assertRaises(TclError, c.create_line, 20, 30, 60, 10, capstyle='spam')
854
855        self._test_option_joinstyle(c,
856                lambda **kwargs: c.create_line(20, 30, 40, 50, 60, 10, **kwargs))
857        self._test_option_smooth(c,
858                lambda **kwargs: c.create_line(20, 30, 60, 10, **kwargs))
859
860    def test_create_polygon(self):
861        c = self.create()
862        i1 = c.create_polygon(20, 30, 40, 50, 60, 10)
863        self.assertEqual(c.coords(i1), [20.0, 30.0, 40.0, 50.0, 60.0, 10.0])
864        self.assertEqual(c.bbox(i1), (19, 9, 61, 51))
865        self.assertEqual(c.itemcget(i1, 'joinstyle'), 'round')
866        self.assertEqual(c.itemcget(i1, 'smooth'), '0')
867        self.assertEqual(c.itemcget(i1, 'splinestep'), '12')
868
869        i2 = c.create_polygon([21, 31, 41, 51, 61, 11])
870        self.assertEqual(c.coords(i2), [21.0, 31.0, 41.0, 51.0, 61.0, 11.0])
871        self.assertEqual(c.bbox(i2), (20, 10, 62, 52))
872
873        i3 = c.create_polygon((22, 32), (42, 52), (62, 12))
874        self.assertEqual(c.coords(i3), [22.0, 32.0, 42.0, 52.0, 62.0, 12.0])
875        self.assertEqual(c.bbox(i3), (21, 11, 63, 53))
876
877        i4 = c.create_polygon([(23, 33), (43, 53), (63, 13)])
878        self.assertEqual(c.coords(i4), [23.0, 33.0, 43.0, 53.0, 63.0, 13.0])
879        self.assertEqual(c.bbox(i4), (22, 12, 64, 54))
880
881        self.assertRaises(TclError, c.create_polygon, 20, 30, 60)
882        self.assertRaises(TclError, c.create_polygon, [20, 30, 60])
883        self.assertRaises(IndexError, c.create_polygon)
884        self.assertRaises(IndexError, c.create_polygon, [])
885
886        self._test_option_joinstyle(c,
887                lambda **kwargs: c.create_polygon(20, 30, 40, 50, 60, 10, **kwargs))
888        self._test_option_smooth(c,
889                lambda **kwargs: c.create_polygon(20, 30, 40, 50, 60, 10, **kwargs))
890
891    def test_coords(self):
892        c = self.create()
893        i = c.create_line(20, 30, 40, 50, 60, 10, tags='x')
894        self.assertEqual(c.coords(i), [20.0, 30.0, 40.0, 50.0, 60.0, 10.0])
895        self.assertEqual(c.coords('x'), [20.0, 30.0, 40.0, 50.0, 60.0, 10.0])
896        self.assertEqual(c.bbox(i), (18, 8, 62, 52))
897
898        c.coords(i, 50, 60, 70, 80, 90, 40)
899        self.assertEqual(c.coords(i), [50.0, 60.0, 70.0, 80.0, 90.0, 40.0])
900        self.assertEqual(c.bbox(i), (48, 38, 92, 82))
901
902        c.coords(i, [21, 31, 41, 51, 61, 11])
903        self.assertEqual(c.coords(i), [21.0, 31.0, 41.0, 51.0, 61.0, 11.0])
904
905        c.coords(i, 20, 30, 60, 10)
906        self.assertEqual(c.coords(i), [20.0, 30.0, 60.0, 10.0])
907        self.assertEqual(c.bbox(i), (18, 8, 62, 32))
908
909        self.assertRaises(TclError, c.coords, i, 20, 30, 60)
910        self.assertRaises(TclError, c.coords, i, [20, 30, 60])
911        self.assertRaises(TclError, c.coords, i, 20, 30)
912        self.assertRaises(TclError, c.coords, i, [20, 30])
913
914        c.coords(i, '20', '30c', '60i', '10p')
915        coords = c.coords(i)
916        self.assertIsInstance(coords, list)
917        self.assertEqual(len(coords), 4)
918        self.assertEqual(coords[0], 20)
919        for i in range(4):
920            self.assertIsInstance(coords[i], float)
921
922    @requires_tcl(8, 6)
923    def test_moveto(self):
924        widget = self.create()
925        i1 = widget.create_rectangle(1, 1, 20, 20, tags='group')
926        i2 = widget.create_rectangle(30, 30, 50, 70, tags='group')
927        x1, y1, _, _ = widget.bbox(i1)
928        x2, y2, _, _ = widget.bbox(i2)
929        widget.moveto('group', 200, 100)
930        x1_2, y1_2, _, _ = widget.bbox(i1)
931        x2_2, y2_2, _, _ = widget.bbox(i2)
932        self.assertEqual(x1_2, 200)
933        self.assertEqual(y1_2, 100)
934        self.assertEqual(x2 - x1, x2_2 - x1_2)
935        self.assertEqual(y2 - y1, y2_2 - y1_2)
936        widget.tag_lower(i2, i1)
937        widget.moveto('group', y=50)
938        x1_3, y1_3, _, _ = widget.bbox(i1)
939        x2_3, y2_3, _, _ = widget.bbox(i2)
940        self.assertEqual(y2_3, 50)
941        self.assertEqual(x2_3, x2_2)
942        self.assertEqual(x2_2 - x1_2, x2_3 - x1_3)
943        self.assertEqual(y2_2 - y1_2, y2_3 - y1_3)
944
945
946@add_standard_options(IntegerSizeTests, StandardOptionsTests)
947class ListboxTest(AbstractWidgetTest, unittest.TestCase):
948    OPTIONS = (
949        'activestyle', 'background', 'borderwidth', 'cursor',
950        'disabledforeground', 'exportselection',
951        'font', 'foreground', 'height',
952        'highlightbackground', 'highlightcolor', 'highlightthickness',
953        'justify', 'listvariable', 'relief',
954        'selectbackground', 'selectborderwidth', 'selectforeground',
955        'selectmode', 'setgrid', 'state',
956        'takefocus', 'width', 'xscrollcommand', 'yscrollcommand',
957    )
958
959    def create(self, **kwargs):
960        return tkinter.Listbox(self.root, **kwargs)
961
962    def test_configure_activestyle(self):
963        widget = self.create()
964        self.checkEnumParam(widget, 'activestyle',
965                            'dotbox', 'none', 'underline')
966
967    test_configure_justify = requires_tcl(8, 6, 5)(StandardOptionsTests.test_configure_justify)
968
969    def test_configure_listvariable(self):
970        widget = self.create()
971        var = tkinter.DoubleVar(self.root)
972        self.checkVariableParam(widget, 'listvariable', var)
973
974    def test_configure_selectmode(self):
975        widget = self.create()
976        self.checkParam(widget, 'selectmode', 'single')
977        self.checkParam(widget, 'selectmode', 'browse')
978        self.checkParam(widget, 'selectmode', 'multiple')
979        self.checkParam(widget, 'selectmode', 'extended')
980
981    def test_configure_state(self):
982        widget = self.create()
983        self.checkEnumParam(widget, 'state', 'disabled', 'normal')
984
985    def test_itemconfigure(self):
986        widget = self.create()
987        with self.assertRaisesRegex(TclError, 'item number "0" out of range'):
988            widget.itemconfigure(0)
989        colors = 'red orange yellow green blue white violet'.split()
990        widget.insert('end', *colors)
991        for i, color in enumerate(colors):
992            widget.itemconfigure(i, background=color)
993        with self.assertRaises(TypeError):
994            widget.itemconfigure()
995        with self.assertRaisesRegex(TclError, 'bad listbox index "red"'):
996            widget.itemconfigure('red')
997        self.assertEqual(widget.itemconfigure(0, 'background'),
998                         ('background', 'background', 'Background', '', 'red'))
999        self.assertEqual(widget.itemconfigure('end', 'background'),
1000                         ('background', 'background', 'Background', '', 'violet'))
1001        self.assertEqual(widget.itemconfigure('@0,0', 'background'),
1002                         ('background', 'background', 'Background', '', 'red'))
1003
1004        d = widget.itemconfigure(0)
1005        self.assertIsInstance(d, dict)
1006        for k, v in d.items():
1007            self.assertIn(len(v), (2, 5))
1008            if len(v) == 5:
1009                self.assertEqual(v, widget.itemconfigure(0, k))
1010                self.assertEqual(v[4], widget.itemcget(0, k))
1011
1012    def check_itemconfigure(self, name, value):
1013        widget = self.create()
1014        widget.insert('end', 'a', 'b', 'c', 'd')
1015        widget.itemconfigure(0, **{name: value})
1016        self.assertEqual(widget.itemconfigure(0, name)[4], value)
1017        self.assertEqual(widget.itemcget(0, name), value)
1018        with self.assertRaisesRegex(TclError, 'unknown color name "spam"'):
1019            widget.itemconfigure(0, **{name: 'spam'})
1020
1021    def test_itemconfigure_background(self):
1022        self.check_itemconfigure('background', '#ff0000')
1023
1024    def test_itemconfigure_bg(self):
1025        self.check_itemconfigure('bg', '#ff0000')
1026
1027    def test_itemconfigure_fg(self):
1028        self.check_itemconfigure('fg', '#110022')
1029
1030    def test_itemconfigure_foreground(self):
1031        self.check_itemconfigure('foreground', '#110022')
1032
1033    def test_itemconfigure_selectbackground(self):
1034        self.check_itemconfigure('selectbackground', '#110022')
1035
1036    def test_itemconfigure_selectforeground(self):
1037        self.check_itemconfigure('selectforeground', '#654321')
1038
1039    def test_box(self):
1040        lb = self.create()
1041        lb.insert(0, *('el%d' % i for i in range(8)))
1042        lb.pack()
1043        self.assertIsBoundingBox(lb.bbox(0))
1044        self.assertIsNone(lb.bbox(-1))
1045        self.assertIsNone(lb.bbox(10))
1046        self.assertRaises(TclError, lb.bbox, 'noindex')
1047        self.assertRaises(TclError, lb.bbox, None)
1048        self.assertRaises(TypeError, lb.bbox)
1049        self.assertRaises(TypeError, lb.bbox, 0, 1)
1050
1051    def test_curselection(self):
1052        lb = self.create()
1053        lb.insert(0, *('el%d' % i for i in range(8)))
1054        lb.selection_clear(0, tkinter.END)
1055        lb.selection_set(2, 4)
1056        lb.selection_set(6)
1057        self.assertEqual(lb.curselection(), (2, 3, 4, 6))
1058        self.assertRaises(TypeError, lb.curselection, 0)
1059
1060    def test_get(self):
1061        lb = self.create()
1062        lb.insert(0, *('el%d' % i for i in range(8)))
1063        self.assertEqual(lb.get(0), 'el0')
1064        self.assertEqual(lb.get(3), 'el3')
1065        self.assertEqual(lb.get('end'), 'el7')
1066        self.assertEqual(lb.get(8), '')
1067        self.assertEqual(lb.get(-1), '')
1068        self.assertEqual(lb.get(3, 5), ('el3', 'el4', 'el5'))
1069        self.assertEqual(lb.get(5, 'end'), ('el5', 'el6', 'el7'))
1070        self.assertEqual(lb.get(5, 0), ())
1071        self.assertEqual(lb.get(0, 0), ('el0',))
1072        self.assertRaises(TclError, lb.get, 'noindex')
1073        self.assertRaises(TclError, lb.get, None)
1074        self.assertRaises(TypeError, lb.get)
1075        self.assertRaises(TclError, lb.get, 'end', 'noindex')
1076        self.assertRaises(TypeError, lb.get, 1, 2, 3)
1077        self.assertRaises(TclError, lb.get, 2.4)
1078
1079
1080@add_standard_options(PixelSizeTests, StandardOptionsTests)
1081class ScaleTest(AbstractWidgetTest, unittest.TestCase):
1082    OPTIONS = (
1083        'activebackground', 'background', 'bigincrement', 'borderwidth',
1084        'command', 'cursor', 'digits', 'font', 'foreground', 'from',
1085        'highlightbackground', 'highlightcolor', 'highlightthickness',
1086        'label', 'length', 'orient', 'relief',
1087        'repeatdelay', 'repeatinterval',
1088        'resolution', 'showvalue', 'sliderlength', 'sliderrelief', 'state',
1089        'takefocus', 'tickinterval', 'to', 'troughcolor', 'variable', 'width',
1090    )
1091    default_orient = 'vertical'
1092
1093    def create(self, **kwargs):
1094        return tkinter.Scale(self.root, **kwargs)
1095
1096    def test_configure_bigincrement(self):
1097        widget = self.create()
1098        self.checkFloatParam(widget, 'bigincrement', 12.4, 23.6, -5)
1099
1100    def test_configure_digits(self):
1101        widget = self.create()
1102        self.checkIntegerParam(widget, 'digits', 5, 0)
1103
1104    def test_configure_from(self):
1105        widget = self.create()
1106        conv = float if get_tk_patchlevel() >= (8, 6, 10) else float_round
1107        self.checkFloatParam(widget, 'from', 100, 14.9, 15.1, conv=conv)
1108
1109    def test_configure_label(self):
1110        widget = self.create()
1111        self.checkParam(widget, 'label', 'any string')
1112        self.checkParam(widget, 'label', '')
1113
1114    def test_configure_length(self):
1115        widget = self.create()
1116        self.checkPixelsParam(widget, 'length', 130, 131.2, 135.6, '5i')
1117
1118    def test_configure_resolution(self):
1119        widget = self.create()
1120        self.checkFloatParam(widget, 'resolution', 4.2, 0, 6.7, -2)
1121
1122    def test_configure_showvalue(self):
1123        widget = self.create()
1124        self.checkBooleanParam(widget, 'showvalue')
1125
1126    def test_configure_sliderlength(self):
1127        widget = self.create()
1128        self.checkPixelsParam(widget, 'sliderlength',
1129                              10, 11.2, 15.6, -3, '3m')
1130
1131    def test_configure_sliderrelief(self):
1132        widget = self.create()
1133        self.checkReliefParam(widget, 'sliderrelief')
1134
1135    def test_configure_tickinterval(self):
1136        widget = self.create()
1137        self.checkFloatParam(widget, 'tickinterval', 1, 4.3, 7.6, 0,
1138                             conv=float_round)
1139        self.checkParam(widget, 'tickinterval', -2, expected=2,
1140                        conv=float_round)
1141
1142    def test_configure_to(self):
1143        widget = self.create()
1144        self.checkFloatParam(widget, 'to', 300, 14.9, 15.1, -10,
1145                             conv=float_round)
1146
1147
1148@add_standard_options(PixelSizeTests, StandardOptionsTests)
1149class ScrollbarTest(AbstractWidgetTest, unittest.TestCase):
1150    OPTIONS = (
1151        'activebackground', 'activerelief',
1152        'background', 'borderwidth',
1153        'command', 'cursor', 'elementborderwidth',
1154        'highlightbackground', 'highlightcolor', 'highlightthickness',
1155        'jump', 'orient', 'relief',
1156        'repeatdelay', 'repeatinterval',
1157        'takefocus', 'troughcolor', 'width',
1158    )
1159    _conv_pixels = round
1160    _stringify = True
1161    default_orient = 'vertical'
1162
1163    def create(self, **kwargs):
1164        return tkinter.Scrollbar(self.root, **kwargs)
1165
1166    def test_configure_activerelief(self):
1167        widget = self.create()
1168        self.checkReliefParam(widget, 'activerelief')
1169
1170    def test_configure_elementborderwidth(self):
1171        widget = self.create()
1172        self.checkPixelsParam(widget, 'elementborderwidth', 4.3, 5.6, -2, '1m')
1173
1174    def test_configure_orient(self):
1175        widget = self.create()
1176        self.checkEnumParam(widget, 'orient', 'vertical', 'horizontal',
1177                errmsg='bad orientation "{}": must be vertical or horizontal')
1178
1179    def test_activate(self):
1180        sb = self.create()
1181        for e in ('arrow1', 'slider', 'arrow2'):
1182            sb.activate(e)
1183            self.assertEqual(sb.activate(), e)
1184        sb.activate('')
1185        self.assertIsNone(sb.activate())
1186        self.assertRaises(TypeError, sb.activate, 'arrow1', 'arrow2')
1187
1188    def test_set(self):
1189        sb = self.create()
1190        sb.set(0.2, 0.4)
1191        self.assertEqual(sb.get(), (0.2, 0.4))
1192        self.assertRaises(TclError, sb.set, 'abc', 'def')
1193        self.assertRaises(TclError, sb.set, 0.6, 'def')
1194        self.assertRaises(TclError, sb.set, 0.6, None)
1195        self.assertRaises(TypeError, sb.set, 0.6)
1196        self.assertRaises(TypeError, sb.set, 0.6, 0.7, 0.8)
1197
1198
1199@add_standard_options(StandardOptionsTests)
1200class PanedWindowTest(AbstractWidgetTest, unittest.TestCase):
1201    OPTIONS = (
1202        'background', 'borderwidth', 'cursor',
1203        'handlepad', 'handlesize', 'height',
1204        'opaqueresize', 'orient',
1205        'proxybackground', 'proxyborderwidth', 'proxyrelief',
1206        'relief',
1207        'sashcursor', 'sashpad', 'sashrelief', 'sashwidth',
1208        'showhandle', 'width',
1209    )
1210    default_orient = 'horizontal'
1211
1212    def create(self, **kwargs):
1213        return tkinter.PanedWindow(self.root, **kwargs)
1214
1215    def test_configure_handlepad(self):
1216        widget = self.create()
1217        self.checkPixelsParam(widget, 'handlepad', 5, 6.4, 7.6, -3, '1m')
1218
1219    def test_configure_handlesize(self):
1220        widget = self.create()
1221        self.checkPixelsParam(widget, 'handlesize', 8, 9.4, 10.6, -3, '2m',
1222                              conv=False)
1223
1224    def test_configure_height(self):
1225        widget = self.create()
1226        self.checkPixelsParam(widget, 'height', 100, 101.2, 102.6, -100, 0, '1i',
1227                              conv=False)
1228
1229    def test_configure_opaqueresize(self):
1230        widget = self.create()
1231        self.checkBooleanParam(widget, 'opaqueresize')
1232
1233    @requires_tcl(8, 6, 5)
1234    def test_configure_proxybackground(self):
1235        widget = self.create()
1236        self.checkColorParam(widget, 'proxybackground')
1237
1238    @requires_tcl(8, 6, 5)
1239    def test_configure_proxyborderwidth(self):
1240        widget = self.create()
1241        self.checkPixelsParam(widget, 'proxyborderwidth',
1242                              0, 1.3, 2.9, 6, -2, '10p',
1243                              conv=False)
1244
1245    @requires_tcl(8, 6, 5)
1246    def test_configure_proxyrelief(self):
1247        widget = self.create()
1248        self.checkReliefParam(widget, 'proxyrelief')
1249
1250    def test_configure_sashcursor(self):
1251        widget = self.create()
1252        self.checkCursorParam(widget, 'sashcursor')
1253
1254    def test_configure_sashpad(self):
1255        widget = self.create()
1256        self.checkPixelsParam(widget, 'sashpad', 8, 1.3, 2.6, -2, '2m')
1257
1258    def test_configure_sashrelief(self):
1259        widget = self.create()
1260        self.checkReliefParam(widget, 'sashrelief')
1261
1262    def test_configure_sashwidth(self):
1263        widget = self.create()
1264        self.checkPixelsParam(widget, 'sashwidth', 10, 11.1, 15.6, -3, '1m',
1265                              conv=False)
1266
1267    def test_configure_showhandle(self):
1268        widget = self.create()
1269        self.checkBooleanParam(widget, 'showhandle')
1270
1271    def test_configure_width(self):
1272        widget = self.create()
1273        self.checkPixelsParam(widget, 'width', 402, 403.4, 404.6, -402, 0, '5i',
1274                              conv=False)
1275
1276    def create2(self):
1277        p = self.create()
1278        b = tkinter.Button(p)
1279        c = tkinter.Button(p)
1280        p.add(b)
1281        p.add(c)
1282        return p, b, c
1283
1284    def test_paneconfigure(self):
1285        p, b, c = self.create2()
1286        self.assertRaises(TypeError, p.paneconfigure)
1287        d = p.paneconfigure(b)
1288        self.assertIsInstance(d, dict)
1289        for k, v in d.items():
1290            self.assertEqual(len(v), 5)
1291            self.assertEqual(v, p.paneconfigure(b, k))
1292            self.assertEqual(v[4], p.panecget(b, k))
1293
1294    def check_paneconfigure(self, p, b, name, value, expected):
1295        if not self.wantobjects:
1296            expected = str(expected)
1297        p.paneconfigure(b, **{name: value})
1298        self.assertEqual(p.paneconfigure(b, name)[4], expected)
1299        self.assertEqual(p.panecget(b, name), expected)
1300
1301    def check_paneconfigure_bad(self, p, b, name, msg):
1302        with self.assertRaisesRegex(TclError, msg):
1303            p.paneconfigure(b, **{name: 'badValue'})
1304
1305    def test_paneconfigure_after(self):
1306        p, b, c = self.create2()
1307        self.check_paneconfigure(p, b, 'after', c, str(c))
1308        self.check_paneconfigure_bad(p, b, 'after',
1309                                     'bad window path name "badValue"')
1310
1311    def test_paneconfigure_before(self):
1312        p, b, c = self.create2()
1313        self.check_paneconfigure(p, b, 'before', c, str(c))
1314        self.check_paneconfigure_bad(p, b, 'before',
1315                                     'bad window path name "badValue"')
1316
1317    def test_paneconfigure_height(self):
1318        p, b, c = self.create2()
1319        self.check_paneconfigure(p, b, 'height', 10, 10)
1320        self.check_paneconfigure_bad(p, b, 'height',
1321                                     'bad screen distance "badValue"')
1322
1323    def test_paneconfigure_hide(self):
1324        p, b, c = self.create2()
1325        self.check_paneconfigure(p, b, 'hide', False, 0)
1326        self.check_paneconfigure_bad(p, b, 'hide',
1327                                     'expected boolean value but got "badValue"')
1328
1329    def test_paneconfigure_minsize(self):
1330        p, b, c = self.create2()
1331        self.check_paneconfigure(p, b, 'minsize', 10, 10)
1332        self.check_paneconfigure_bad(p, b, 'minsize',
1333                                     'bad screen distance "badValue"')
1334
1335    def test_paneconfigure_padx(self):
1336        p, b, c = self.create2()
1337        self.check_paneconfigure(p, b, 'padx', 1.3, 1)
1338        self.check_paneconfigure_bad(p, b, 'padx',
1339                                     'bad screen distance "badValue"')
1340
1341    def test_paneconfigure_pady(self):
1342        p, b, c = self.create2()
1343        self.check_paneconfigure(p, b, 'pady', 1.3, 1)
1344        self.check_paneconfigure_bad(p, b, 'pady',
1345                                     'bad screen distance "badValue"')
1346
1347    def test_paneconfigure_sticky(self):
1348        p, b, c = self.create2()
1349        self.check_paneconfigure(p, b, 'sticky', 'nsew', 'nesw')
1350        self.check_paneconfigure_bad(p, b, 'sticky',
1351                                     'bad stickyness value "badValue": must '
1352                                     'be a string containing zero or more of '
1353                                     'n, e, s, and w')
1354
1355    def test_paneconfigure_stretch(self):
1356        p, b, c = self.create2()
1357        self.check_paneconfigure(p, b, 'stretch', 'alw', 'always')
1358        self.check_paneconfigure_bad(p, b, 'stretch',
1359                                     'bad stretch "badValue": must be '
1360                                     'always, first, last, middle, or never')
1361
1362    def test_paneconfigure_width(self):
1363        p, b, c = self.create2()
1364        self.check_paneconfigure(p, b, 'width', 10, 10)
1365        self.check_paneconfigure_bad(p, b, 'width',
1366                                     'bad screen distance "badValue"')
1367
1368
1369@add_standard_options(StandardOptionsTests)
1370class MenuTest(AbstractWidgetTest, unittest.TestCase):
1371    OPTIONS = (
1372        'activebackground', 'activeborderwidth', 'activeforeground',
1373        'background', 'borderwidth', 'cursor',
1374        'disabledforeground', 'font', 'foreground',
1375        'postcommand', 'relief', 'selectcolor', 'takefocus',
1376        'tearoff', 'tearoffcommand', 'title', 'type',
1377    )
1378    _conv_pixels = False
1379
1380    def create(self, **kwargs):
1381        return tkinter.Menu(self.root, **kwargs)
1382
1383    def test_indexcommand_none(self):
1384        widget = self.create()
1385        i = widget.index('none')
1386        self.assertIsNone(i)
1387
1388    def test_configure_postcommand(self):
1389        widget = self.create()
1390        self.checkCommandParam(widget, 'postcommand')
1391
1392    def test_configure_tearoff(self):
1393        widget = self.create()
1394        self.checkBooleanParam(widget, 'tearoff')
1395
1396    def test_configure_tearoffcommand(self):
1397        widget = self.create()
1398        self.checkCommandParam(widget, 'tearoffcommand')
1399
1400    def test_configure_title(self):
1401        widget = self.create()
1402        self.checkParam(widget, 'title', 'any string')
1403
1404    def test_configure_type(self):
1405        widget = self.create()
1406        opts = ('normal, tearoff, or menubar'
1407                if widget.info_patchlevel() < (8, 7) else
1408                'menubar, normal, or tearoff')
1409        self.checkEnumParam(
1410            widget, 'type',
1411            'normal', 'tearoff', 'menubar',
1412            errmsg='bad type "{}": must be ' + opts,
1413            )
1414
1415    def test_entryconfigure(self):
1416        m1 = self.create()
1417        m1.add_command(label='test')
1418        self.assertRaises(TypeError, m1.entryconfigure)
1419        with self.assertRaisesRegex(TclError, 'bad menu entry index "foo"'):
1420            m1.entryconfigure('foo')
1421        d = m1.entryconfigure(1)
1422        self.assertIsInstance(d, dict)
1423        for k, v in d.items():
1424            self.assertIsInstance(k, str)
1425            self.assertIsInstance(v, tuple)
1426            self.assertEqual(len(v), 5)
1427            self.assertEqual(v[0], k)
1428            self.assertEqual(m1.entrycget(1, k), v[4])
1429        m1.destroy()
1430
1431    def test_entryconfigure_label(self):
1432        m1 = self.create()
1433        m1.add_command(label='test')
1434        self.assertEqual(m1.entrycget(1, 'label'), 'test')
1435        m1.entryconfigure(1, label='changed')
1436        self.assertEqual(m1.entrycget(1, 'label'), 'changed')
1437
1438    def test_entryconfigure_variable(self):
1439        m1 = self.create()
1440        v1 = tkinter.BooleanVar(self.root)
1441        v2 = tkinter.BooleanVar(self.root)
1442        m1.add_checkbutton(variable=v1, onvalue=True, offvalue=False,
1443                           label='Nonsense')
1444        self.assertEqual(str(m1.entrycget(1, 'variable')), str(v1))
1445        m1.entryconfigure(1, variable=v2)
1446        self.assertEqual(str(m1.entrycget(1, 'variable')), str(v2))
1447
1448
1449@add_standard_options(PixelSizeTests, StandardOptionsTests)
1450class MessageTest(AbstractWidgetTest, unittest.TestCase):
1451    OPTIONS = (
1452        'anchor', 'aspect', 'background', 'borderwidth',
1453        'cursor', 'font', 'foreground',
1454        'highlightbackground', 'highlightcolor', 'highlightthickness',
1455        'justify', 'padx', 'pady', 'relief',
1456        'takefocus', 'text', 'textvariable', 'width',
1457    )
1458    _conv_pad_pixels = False
1459
1460    def create(self, **kwargs):
1461        return tkinter.Message(self.root, **kwargs)
1462
1463    def test_configure_aspect(self):
1464        widget = self.create()
1465        self.checkIntegerParam(widget, 'aspect', 250, 0, -300)
1466
1467
1468class DefaultRootTest(AbstractDefaultRootTest, unittest.TestCase):
1469
1470    def test_frame(self):
1471        self._test_widget(tkinter.Frame)
1472
1473    def test_label(self):
1474        self._test_widget(tkinter.Label)
1475
1476
1477tests_gui = (
1478        ButtonTest, CanvasTest, CheckbuttonTest, EntryTest,
1479        FrameTest, LabelFrameTest,LabelTest, ListboxTest,
1480        MenubuttonTest, MenuTest, MessageTest, OptionMenuTest,
1481        PanedWindowTest, RadiobuttonTest, ScaleTest, ScrollbarTest,
1482        SpinboxTest, TextTest, ToplevelTest, DefaultRootTest,
1483)
1484
1485if __name__ == '__main__':
1486    unittest.main()
1487