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