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