• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1import unittest
2from test import support
3
4import gc
5import tkinter
6from tkinter import (Variable, StringVar, IntVar, DoubleVar, BooleanVar, Tcl,
7                     TclError)
8from test.support import ALWAYS_EQ
9from tkinter.test.support import AbstractDefaultRootTest
10
11
12class Var(Variable):
13
14    _default = "default"
15    side_effect = False
16
17    def set(self, value):
18        self.side_effect = True
19        super().set(value)
20
21
22class TestBase(unittest.TestCase):
23
24    def setUp(self):
25        self.root = Tcl()
26
27    def tearDown(self):
28        del self.root
29
30
31class TestVariable(TestBase):
32
33    def info_exists(self, *args):
34        return self.root.getboolean(self.root.call("info", "exists", *args))
35
36    def test_default(self):
37        v = Variable(self.root)
38        self.assertEqual("", v.get())
39        self.assertRegex(str(v), r"^PY_VAR(\d+)$")
40
41    def test_name_and_value(self):
42        v = Variable(self.root, "sample string", "varname")
43        self.assertEqual("sample string", v.get())
44        self.assertEqual("varname", str(v))
45
46    def test___del__(self):
47        self.assertFalse(self.info_exists("varname"))
48        v = Variable(self.root, "sample string", "varname")
49        self.assertTrue(self.info_exists("varname"))
50        del v
51        support.gc_collect()  # For PyPy or other GCs.
52        self.assertFalse(self.info_exists("varname"))
53
54    def test_dont_unset_not_existing(self):
55        self.assertFalse(self.info_exists("varname"))
56        v1 = Variable(self.root, name="name")
57        v2 = Variable(self.root, name="name")
58        del v1
59        support.gc_collect()  # For PyPy or other GCs.
60        self.assertFalse(self.info_exists("name"))
61        # shouldn't raise exception
62        del v2
63        support.gc_collect()  # For PyPy or other GCs.
64        self.assertFalse(self.info_exists("name"))
65
66    def test_equality(self):
67        # values doesn't matter, only class and name are checked
68        v1 = Variable(self.root, name="abc")
69        v2 = Variable(self.root, name="abc")
70        self.assertIsNot(v1, v2)
71        self.assertEqual(v1, v2)
72
73        v3 = Variable(self.root, name="cba")
74        self.assertNotEqual(v1, v3)
75
76        v4 = StringVar(self.root, name="abc")
77        self.assertEqual(str(v1), str(v4))
78        self.assertNotEqual(v1, v4)
79
80        V = type('Variable', (), {})
81        self.assertNotEqual(v1, V())
82
83        self.assertNotEqual(v1, object())
84        self.assertEqual(v1, ALWAYS_EQ)
85
86        root2 = tkinter.Tk()
87        self.addCleanup(root2.destroy)
88        v5 = Variable(root2, name="abc")
89        self.assertEqual(str(v1), str(v5))
90        self.assertNotEqual(v1, v5)
91
92    def test_invalid_name(self):
93        with self.assertRaises(TypeError):
94            Variable(self.root, name=123)
95
96    def test_null_in_name(self):
97        with self.assertRaises(ValueError):
98            Variable(self.root, name='var\x00name')
99        with self.assertRaises(ValueError):
100            self.root.globalsetvar('var\x00name', "value")
101        with self.assertRaises(ValueError):
102            self.root.globalsetvar(b'var\x00name', "value")
103        with self.assertRaises(ValueError):
104            self.root.setvar('var\x00name', "value")
105        with self.assertRaises(ValueError):
106            self.root.setvar(b'var\x00name', "value")
107
108    def test_initialize(self):
109        v = Var(self.root)
110        self.assertFalse(v.side_effect)
111        v.set("value")
112        self.assertTrue(v.side_effect)
113
114    def test_trace_old(self):
115        # Old interface
116        v = Variable(self.root)
117        vname = str(v)
118        trace = []
119        def read_tracer(*args):
120            trace.append(('read',) + args)
121        def write_tracer(*args):
122            trace.append(('write',) + args)
123        cb1 = v.trace_variable('r', read_tracer)
124        cb2 = v.trace_variable('wu', write_tracer)
125        self.assertEqual(sorted(v.trace_vinfo()), [('r', cb1), ('wu', cb2)])
126        self.assertEqual(trace, [])
127
128        v.set('spam')
129        self.assertEqual(trace, [('write', vname, '', 'w')])
130
131        trace = []
132        v.get()
133        self.assertEqual(trace, [('read', vname, '', 'r')])
134
135        trace = []
136        info = sorted(v.trace_vinfo())
137        v.trace_vdelete('w', cb1)  # Wrong mode
138        self.assertEqual(sorted(v.trace_vinfo()), info)
139        with self.assertRaises(TclError):
140            v.trace_vdelete('r', 'spam')  # Wrong command name
141        self.assertEqual(sorted(v.trace_vinfo()), info)
142        v.trace_vdelete('r', (cb1, 43)) # Wrong arguments
143        self.assertEqual(sorted(v.trace_vinfo()), info)
144        v.get()
145        self.assertEqual(trace, [('read', vname, '', 'r')])
146
147        trace = []
148        v.trace_vdelete('r', cb1)
149        self.assertEqual(v.trace_vinfo(), [('wu', cb2)])
150        v.get()
151        self.assertEqual(trace, [])
152
153        trace = []
154        del write_tracer
155        gc.collect()
156        v.set('eggs')
157        self.assertEqual(trace, [('write', vname, '', 'w')])
158
159        trace = []
160        del v
161        gc.collect()
162        self.assertEqual(trace, [('write', vname, '', 'u')])
163
164    def test_trace(self):
165        v = Variable(self.root)
166        vname = str(v)
167        trace = []
168        def read_tracer(*args):
169            trace.append(('read',) + args)
170        def write_tracer(*args):
171            trace.append(('write',) + args)
172        tr1 = v.trace_add('read', read_tracer)
173        tr2 = v.trace_add(['write', 'unset'], write_tracer)
174        self.assertEqual(sorted(v.trace_info()), [
175                         (('read',), tr1),
176                         (('write', 'unset'), tr2)])
177        self.assertEqual(trace, [])
178
179        v.set('spam')
180        self.assertEqual(trace, [('write', vname, '', 'write')])
181
182        trace = []
183        v.get()
184        self.assertEqual(trace, [('read', vname, '', 'read')])
185
186        trace = []
187        info = sorted(v.trace_info())
188        v.trace_remove('write', tr1)  # Wrong mode
189        self.assertEqual(sorted(v.trace_info()), info)
190        with self.assertRaises(TclError):
191            v.trace_remove('read', 'spam')  # Wrong command name
192        self.assertEqual(sorted(v.trace_info()), info)
193        v.get()
194        self.assertEqual(trace, [('read', vname, '', 'read')])
195
196        trace = []
197        v.trace_remove('read', tr1)
198        self.assertEqual(v.trace_info(), [(('write', 'unset'), tr2)])
199        v.get()
200        self.assertEqual(trace, [])
201
202        trace = []
203        del write_tracer
204        gc.collect()
205        v.set('eggs')
206        self.assertEqual(trace, [('write', vname, '', 'write')])
207
208        trace = []
209        del v
210        gc.collect()
211        self.assertEqual(trace, [('write', vname, '', 'unset')])
212
213
214class TestStringVar(TestBase):
215
216    def test_default(self):
217        v = StringVar(self.root)
218        self.assertEqual("", v.get())
219
220    def test_get(self):
221        v = StringVar(self.root, "abc", "name")
222        self.assertEqual("abc", v.get())
223        self.root.globalsetvar("name", "value")
224        self.assertEqual("value", v.get())
225
226    def test_get_null(self):
227        v = StringVar(self.root, "abc\x00def", "name")
228        self.assertEqual("abc\x00def", v.get())
229        self.root.globalsetvar("name", "val\x00ue")
230        self.assertEqual("val\x00ue", v.get())
231
232
233class TestIntVar(TestBase):
234
235    def test_default(self):
236        v = IntVar(self.root)
237        self.assertEqual(0, v.get())
238
239    def test_get(self):
240        v = IntVar(self.root, 123, "name")
241        self.assertEqual(123, v.get())
242        self.root.globalsetvar("name", "345")
243        self.assertEqual(345, v.get())
244        self.root.globalsetvar("name", "876.5")
245        self.assertEqual(876, v.get())
246
247    def test_invalid_value(self):
248        v = IntVar(self.root, name="name")
249        self.root.globalsetvar("name", "value")
250        with self.assertRaises((ValueError, TclError)):
251            v.get()
252
253
254class TestDoubleVar(TestBase):
255
256    def test_default(self):
257        v = DoubleVar(self.root)
258        self.assertEqual(0.0, v.get())
259
260    def test_get(self):
261        v = DoubleVar(self.root, 1.23, "name")
262        self.assertAlmostEqual(1.23, v.get())
263        self.root.globalsetvar("name", "3.45")
264        self.assertAlmostEqual(3.45, v.get())
265
266    def test_get_from_int(self):
267        v = DoubleVar(self.root, 1.23, "name")
268        self.assertAlmostEqual(1.23, v.get())
269        self.root.globalsetvar("name", "3.45")
270        self.assertAlmostEqual(3.45, v.get())
271        self.root.globalsetvar("name", "456")
272        self.assertAlmostEqual(456, v.get())
273
274    def test_invalid_value(self):
275        v = DoubleVar(self.root, name="name")
276        self.root.globalsetvar("name", "value")
277        with self.assertRaises((ValueError, TclError)):
278            v.get()
279
280
281class TestBooleanVar(TestBase):
282
283    def test_default(self):
284        v = BooleanVar(self.root)
285        self.assertIs(v.get(), False)
286
287    def test_get(self):
288        v = BooleanVar(self.root, True, "name")
289        self.assertIs(v.get(), True)
290        self.root.globalsetvar("name", "0")
291        self.assertIs(v.get(), False)
292        self.root.globalsetvar("name", 42 if self.root.wantobjects() else 1)
293        self.assertIs(v.get(), True)
294        self.root.globalsetvar("name", 0)
295        self.assertIs(v.get(), False)
296        self.root.globalsetvar("name", "on")
297        self.assertIs(v.get(), True)
298
299    def test_set(self):
300        true = 1 if self.root.wantobjects() else "1"
301        false = 0 if self.root.wantobjects() else "0"
302        v = BooleanVar(self.root, name="name")
303        v.set(True)
304        self.assertEqual(self.root.globalgetvar("name"), true)
305        v.set("0")
306        self.assertEqual(self.root.globalgetvar("name"), false)
307        v.set(42)
308        self.assertEqual(self.root.globalgetvar("name"), true)
309        v.set(0)
310        self.assertEqual(self.root.globalgetvar("name"), false)
311        v.set("on")
312        self.assertEqual(self.root.globalgetvar("name"), true)
313
314    def test_invalid_value_domain(self):
315        false = 0 if self.root.wantobjects() else "0"
316        v = BooleanVar(self.root, name="name")
317        with self.assertRaises(TclError):
318            v.set("value")
319        self.assertEqual(self.root.globalgetvar("name"), false)
320        self.root.globalsetvar("name", "value")
321        with self.assertRaises(ValueError):
322            v.get()
323        self.root.globalsetvar("name", "1.0")
324        with self.assertRaises(ValueError):
325            v.get()
326
327
328class DefaultRootTest(AbstractDefaultRootTest, unittest.TestCase):
329
330    def test_variable(self):
331        self.assertRaises(RuntimeError, Variable)
332        root = tkinter.Tk()
333        v = Variable()
334        v.set("value")
335        self.assertEqual(v.get(), "value")
336        root.destroy()
337        tkinter.NoDefaultRoot()
338        self.assertRaises(RuntimeError, Variable)
339
340
341if __name__ == "__main__":
342    unittest.main()
343