1import unittest 2import re 3import subprocess 4import sys 5import os 6from test import support 7 8# Skip this test if the _tkinter module wasn't built. 9_tkinter = support.import_module('_tkinter') 10 11import tkinter 12from tkinter import Tcl 13from _tkinter import TclError 14 15try: 16 from _testcapi import INT_MAX, PY_SSIZE_T_MAX 17except ImportError: 18 INT_MAX = PY_SSIZE_T_MAX = sys.maxsize 19 20tcl_version = tuple(map(int, _tkinter.TCL_VERSION.split('.'))) 21 22_tk_patchlevel = None 23def get_tk_patchlevel(): 24 global _tk_patchlevel 25 if _tk_patchlevel is None: 26 tcl = Tcl() 27 patchlevel = tcl.call('info', 'patchlevel') 28 m = re.fullmatch(r'(\d+)\.(\d+)([ab.])(\d+)', patchlevel) 29 major, minor, releaselevel, serial = m.groups() 30 major, minor, serial = int(major), int(minor), int(serial) 31 releaselevel = {'a': 'alpha', 'b': 'beta', '.': 'final'}[releaselevel] 32 if releaselevel == 'final': 33 _tk_patchlevel = major, minor, serial, releaselevel, 0 34 else: 35 _tk_patchlevel = major, minor, 0, releaselevel, serial 36 return _tk_patchlevel 37 38 39class TkinterTest(unittest.TestCase): 40 41 def testFlattenLen(self): 42 # flatten(<object with no length>) 43 self.assertRaises(TypeError, _tkinter._flatten, True) 44 45 46class TclTest(unittest.TestCase): 47 48 def setUp(self): 49 self.interp = Tcl() 50 self.wantobjects = self.interp.tk.wantobjects() 51 52 def testEval(self): 53 tcl = self.interp 54 tcl.eval('set a 1') 55 self.assertEqual(tcl.eval('set a'),'1') 56 57 def test_eval_null_in_result(self): 58 tcl = self.interp 59 self.assertEqual(tcl.eval('set a "a\\0b"'), 'a\x00b') 60 61 def testEvalException(self): 62 tcl = self.interp 63 self.assertRaises(TclError,tcl.eval,'set a') 64 65 def testEvalException2(self): 66 tcl = self.interp 67 self.assertRaises(TclError,tcl.eval,'this is wrong') 68 69 def testCall(self): 70 tcl = self.interp 71 tcl.call('set','a','1') 72 self.assertEqual(tcl.call('set','a'),'1') 73 74 def testCallException(self): 75 tcl = self.interp 76 self.assertRaises(TclError,tcl.call,'set','a') 77 78 def testCallException2(self): 79 tcl = self.interp 80 self.assertRaises(TclError,tcl.call,'this','is','wrong') 81 82 def testSetVar(self): 83 tcl = self.interp 84 tcl.setvar('a','1') 85 self.assertEqual(tcl.eval('set a'),'1') 86 87 def testSetVarArray(self): 88 tcl = self.interp 89 tcl.setvar('a(1)','1') 90 self.assertEqual(tcl.eval('set a(1)'),'1') 91 92 def testGetVar(self): 93 tcl = self.interp 94 tcl.eval('set a 1') 95 self.assertEqual(tcl.getvar('a'),'1') 96 97 def testGetVarArray(self): 98 tcl = self.interp 99 tcl.eval('set a(1) 1') 100 self.assertEqual(tcl.getvar('a(1)'),'1') 101 102 def testGetVarException(self): 103 tcl = self.interp 104 self.assertRaises(TclError,tcl.getvar,'a') 105 106 def testGetVarArrayException(self): 107 tcl = self.interp 108 self.assertRaises(TclError,tcl.getvar,'a(1)') 109 110 def testUnsetVar(self): 111 tcl = self.interp 112 tcl.setvar('a',1) 113 self.assertEqual(tcl.eval('info exists a'),'1') 114 tcl.unsetvar('a') 115 self.assertEqual(tcl.eval('info exists a'),'0') 116 117 def testUnsetVarArray(self): 118 tcl = self.interp 119 tcl.setvar('a(1)',1) 120 tcl.setvar('a(2)',2) 121 self.assertEqual(tcl.eval('info exists a(1)'),'1') 122 self.assertEqual(tcl.eval('info exists a(2)'),'1') 123 tcl.unsetvar('a(1)') 124 self.assertEqual(tcl.eval('info exists a(1)'),'0') 125 self.assertEqual(tcl.eval('info exists a(2)'),'1') 126 127 def testUnsetVarException(self): 128 tcl = self.interp 129 self.assertRaises(TclError,tcl.unsetvar,'a') 130 131 def get_integers(self): 132 integers = (0, 1, -1, 2**31-1, -2**31, 2**31, -2**31-1, 2**63-1, -2**63) 133 # bignum was added in Tcl 8.5, but its support is able only since 8.5.8 134 if (get_tk_patchlevel() >= (8, 6, 0, 'final') or 135 (8, 5, 8) <= get_tk_patchlevel() < (8, 6)): 136 integers += (2**63, -2**63-1, 2**1000, -2**1000) 137 return integers 138 139 def test_getint(self): 140 tcl = self.interp.tk 141 for i in self.get_integers(): 142 self.assertEqual(tcl.getint(' %d ' % i), i) 143 if tcl_version >= (8, 5): 144 self.assertEqual(tcl.getint(' %#o ' % i), i) 145 self.assertEqual(tcl.getint((' %#o ' % i).replace('o', '')), i) 146 self.assertEqual(tcl.getint(' %#x ' % i), i) 147 if tcl_version < (8, 5): # bignum was added in Tcl 8.5 148 self.assertRaises(TclError, tcl.getint, str(2**1000)) 149 self.assertEqual(tcl.getint(42), 42) 150 self.assertRaises(TypeError, tcl.getint) 151 self.assertRaises(TypeError, tcl.getint, '42', '10') 152 self.assertRaises(TypeError, tcl.getint, b'42') 153 self.assertRaises(TypeError, tcl.getint, 42.0) 154 self.assertRaises(TclError, tcl.getint, 'a') 155 self.assertRaises((TypeError, ValueError, TclError), 156 tcl.getint, '42\0') 157 self.assertRaises((UnicodeEncodeError, ValueError, TclError), 158 tcl.getint, '42\ud800') 159 160 def test_getdouble(self): 161 tcl = self.interp.tk 162 self.assertEqual(tcl.getdouble(' 42 '), 42.0) 163 self.assertEqual(tcl.getdouble(' 42.5 '), 42.5) 164 self.assertEqual(tcl.getdouble(42.5), 42.5) 165 self.assertEqual(tcl.getdouble(42), 42.0) 166 self.assertRaises(TypeError, tcl.getdouble) 167 self.assertRaises(TypeError, tcl.getdouble, '42.5', '10') 168 self.assertRaises(TypeError, tcl.getdouble, b'42.5') 169 self.assertRaises(TclError, tcl.getdouble, 'a') 170 self.assertRaises((TypeError, ValueError, TclError), 171 tcl.getdouble, '42.5\0') 172 self.assertRaises((UnicodeEncodeError, ValueError, TclError), 173 tcl.getdouble, '42.5\ud800') 174 175 def test_getboolean(self): 176 tcl = self.interp.tk 177 self.assertIs(tcl.getboolean('on'), True) 178 self.assertIs(tcl.getboolean('1'), True) 179 self.assertIs(tcl.getboolean(42), True) 180 self.assertIs(tcl.getboolean(0), False) 181 self.assertRaises(TypeError, tcl.getboolean) 182 self.assertRaises(TypeError, tcl.getboolean, 'on', '1') 183 self.assertRaises(TypeError, tcl.getboolean, b'on') 184 self.assertRaises(TypeError, tcl.getboolean, 1.0) 185 self.assertRaises(TclError, tcl.getboolean, 'a') 186 self.assertRaises((TypeError, ValueError, TclError), 187 tcl.getboolean, 'on\0') 188 self.assertRaises((UnicodeEncodeError, ValueError, TclError), 189 tcl.getboolean, 'on\ud800') 190 191 def testEvalFile(self): 192 tcl = self.interp 193 with open(support.TESTFN, 'w') as f: 194 self.addCleanup(support.unlink, support.TESTFN) 195 f.write("""set a 1 196 set b 2 197 set c [ expr $a + $b ] 198 """) 199 tcl.evalfile(support.TESTFN) 200 self.assertEqual(tcl.eval('set a'),'1') 201 self.assertEqual(tcl.eval('set b'),'2') 202 self.assertEqual(tcl.eval('set c'),'3') 203 204 def test_evalfile_null_in_result(self): 205 tcl = self.interp 206 with open(support.TESTFN, 'w') as f: 207 self.addCleanup(support.unlink, support.TESTFN) 208 f.write(""" 209 set a "a\0b" 210 set b "a\\0b" 211 """) 212 tcl.evalfile(support.TESTFN) 213 self.assertEqual(tcl.eval('set a'), 'a\x00b') 214 self.assertEqual(tcl.eval('set b'), 'a\x00b') 215 216 def testEvalFileException(self): 217 tcl = self.interp 218 filename = "doesnotexists" 219 try: 220 os.remove(filename) 221 except Exception as e: 222 pass 223 self.assertRaises(TclError,tcl.evalfile,filename) 224 225 def testPackageRequireException(self): 226 tcl = self.interp 227 self.assertRaises(TclError,tcl.eval,'package require DNE') 228 229 @unittest.skipUnless(sys.platform == 'win32', 'Requires Windows') 230 def testLoadWithUNC(self): 231 # Build a UNC path from the regular path. 232 # Something like 233 # \\%COMPUTERNAME%\c$\python27\python.exe 234 235 fullname = os.path.abspath(sys.executable) 236 if fullname[1] != ':': 237 raise unittest.SkipTest('Absolute path should have drive part') 238 unc_name = r'\\%s\%s$\%s' % (os.environ['COMPUTERNAME'], 239 fullname[0], 240 fullname[3:]) 241 if not os.path.exists(unc_name): 242 raise unittest.SkipTest('Cannot connect to UNC Path') 243 244 with support.EnvironmentVarGuard() as env: 245 env.unset("TCL_LIBRARY") 246 stdout = subprocess.check_output( 247 [unc_name, '-c', 'import tkinter; print(tkinter)']) 248 249 self.assertIn(b'tkinter', stdout) 250 251 def test_exprstring(self): 252 tcl = self.interp 253 tcl.call('set', 'a', 3) 254 tcl.call('set', 'b', 6) 255 def check(expr, expected): 256 result = tcl.exprstring(expr) 257 self.assertEqual(result, expected) 258 self.assertIsInstance(result, str) 259 260 self.assertRaises(TypeError, tcl.exprstring) 261 self.assertRaises(TypeError, tcl.exprstring, '8.2', '+6') 262 self.assertRaises(TypeError, tcl.exprstring, b'8.2 + 6') 263 self.assertRaises(TclError, tcl.exprstring, 'spam') 264 check('', '0') 265 check('8.2 + 6', '14.2') 266 check('3.1 + $a', '6.1') 267 check('2 + "$a.$b"', '5.6') 268 check('4*[llength "6 2"]', '8') 269 check('{word one} < "word $a"', '0') 270 check('4*2 < 7', '0') 271 check('hypot($a, 4)', '5.0') 272 check('5 / 4', '1') 273 check('5 / 4.0', '1.25') 274 check('5 / ( [string length "abcd"] + 0.0 )', '1.25') 275 check('20.0/5.0', '4.0') 276 check('"0x03" > "2"', '1') 277 check('[string length "a\xbd\u20ac"]', '3') 278 check(r'[string length "a\xbd\u20ac"]', '3') 279 check('"abc"', 'abc') 280 check('"a\xbd\u20ac"', 'a\xbd\u20ac') 281 check(r'"a\xbd\u20ac"', 'a\xbd\u20ac') 282 check(r'"a\0b"', 'a\x00b') 283 if tcl_version >= (8, 5): # bignum was added in Tcl 8.5 284 check('2**64', str(2**64)) 285 286 def test_exprdouble(self): 287 tcl = self.interp 288 tcl.call('set', 'a', 3) 289 tcl.call('set', 'b', 6) 290 def check(expr, expected): 291 result = tcl.exprdouble(expr) 292 self.assertEqual(result, expected) 293 self.assertIsInstance(result, float) 294 295 self.assertRaises(TypeError, tcl.exprdouble) 296 self.assertRaises(TypeError, tcl.exprdouble, '8.2', '+6') 297 self.assertRaises(TypeError, tcl.exprdouble, b'8.2 + 6') 298 self.assertRaises(TclError, tcl.exprdouble, 'spam') 299 check('', 0.0) 300 check('8.2 + 6', 14.2) 301 check('3.1 + $a', 6.1) 302 check('2 + "$a.$b"', 5.6) 303 check('4*[llength "6 2"]', 8.0) 304 check('{word one} < "word $a"', 0.0) 305 check('4*2 < 7', 0.0) 306 check('hypot($a, 4)', 5.0) 307 check('5 / 4', 1.0) 308 check('5 / 4.0', 1.25) 309 check('5 / ( [string length "abcd"] + 0.0 )', 1.25) 310 check('20.0/5.0', 4.0) 311 check('"0x03" > "2"', 1.0) 312 check('[string length "a\xbd\u20ac"]', 3.0) 313 check(r'[string length "a\xbd\u20ac"]', 3.0) 314 self.assertRaises(TclError, tcl.exprdouble, '"abc"') 315 if tcl_version >= (8, 5): # bignum was added in Tcl 8.5 316 check('2**64', float(2**64)) 317 318 def test_exprlong(self): 319 tcl = self.interp 320 tcl.call('set', 'a', 3) 321 tcl.call('set', 'b', 6) 322 def check(expr, expected): 323 result = tcl.exprlong(expr) 324 self.assertEqual(result, expected) 325 self.assertIsInstance(result, int) 326 327 self.assertRaises(TypeError, tcl.exprlong) 328 self.assertRaises(TypeError, tcl.exprlong, '8.2', '+6') 329 self.assertRaises(TypeError, tcl.exprlong, b'8.2 + 6') 330 self.assertRaises(TclError, tcl.exprlong, 'spam') 331 check('', 0) 332 check('8.2 + 6', 14) 333 check('3.1 + $a', 6) 334 check('2 + "$a.$b"', 5) 335 check('4*[llength "6 2"]', 8) 336 check('{word one} < "word $a"', 0) 337 check('4*2 < 7', 0) 338 check('hypot($a, 4)', 5) 339 check('5 / 4', 1) 340 check('5 / 4.0', 1) 341 check('5 / ( [string length "abcd"] + 0.0 )', 1) 342 check('20.0/5.0', 4) 343 check('"0x03" > "2"', 1) 344 check('[string length "a\xbd\u20ac"]', 3) 345 check(r'[string length "a\xbd\u20ac"]', 3) 346 self.assertRaises(TclError, tcl.exprlong, '"abc"') 347 if tcl_version >= (8, 5): # bignum was added in Tcl 8.5 348 self.assertRaises(TclError, tcl.exprlong, '2**64') 349 350 def test_exprboolean(self): 351 tcl = self.interp 352 tcl.call('set', 'a', 3) 353 tcl.call('set', 'b', 6) 354 def check(expr, expected): 355 result = tcl.exprboolean(expr) 356 self.assertEqual(result, expected) 357 self.assertIsInstance(result, int) 358 self.assertNotIsInstance(result, bool) 359 360 self.assertRaises(TypeError, tcl.exprboolean) 361 self.assertRaises(TypeError, tcl.exprboolean, '8.2', '+6') 362 self.assertRaises(TypeError, tcl.exprboolean, b'8.2 + 6') 363 self.assertRaises(TclError, tcl.exprboolean, 'spam') 364 check('', False) 365 for value in ('0', 'false', 'no', 'off'): 366 check(value, False) 367 check('"%s"' % value, False) 368 check('{%s}' % value, False) 369 for value in ('1', 'true', 'yes', 'on'): 370 check(value, True) 371 check('"%s"' % value, True) 372 check('{%s}' % value, True) 373 check('8.2 + 6', True) 374 check('3.1 + $a', True) 375 check('2 + "$a.$b"', True) 376 check('4*[llength "6 2"]', True) 377 check('{word one} < "word $a"', False) 378 check('4*2 < 7', False) 379 check('hypot($a, 4)', True) 380 check('5 / 4', True) 381 check('5 / 4.0', True) 382 check('5 / ( [string length "abcd"] + 0.0 )', True) 383 check('20.0/5.0', True) 384 check('"0x03" > "2"', True) 385 check('[string length "a\xbd\u20ac"]', True) 386 check(r'[string length "a\xbd\u20ac"]', True) 387 self.assertRaises(TclError, tcl.exprboolean, '"abc"') 388 if tcl_version >= (8, 5): # bignum was added in Tcl 8.5 389 check('2**64', True) 390 391 @unittest.skipUnless(tcl_version >= (8, 5), 'requires Tcl version >= 8.5') 392 def test_booleans(self): 393 tcl = self.interp 394 def check(expr, expected): 395 result = tcl.call('expr', expr) 396 if tcl.wantobjects(): 397 self.assertEqual(result, expected) 398 self.assertIsInstance(result, int) 399 else: 400 self.assertIn(result, (expr, str(int(expected)))) 401 self.assertIsInstance(result, str) 402 check('true', True) 403 check('yes', True) 404 check('on', True) 405 check('false', False) 406 check('no', False) 407 check('off', False) 408 check('1 < 2', True) 409 check('1 > 2', False) 410 411 def test_expr_bignum(self): 412 tcl = self.interp 413 for i in self.get_integers(): 414 result = tcl.call('expr', str(i)) 415 if self.wantobjects: 416 self.assertEqual(result, i) 417 self.assertIsInstance(result, int) 418 else: 419 self.assertEqual(result, str(i)) 420 self.assertIsInstance(result, str) 421 if tcl_version < (8, 5): # bignum was added in Tcl 8.5 422 self.assertRaises(TclError, tcl.call, 'expr', str(2**1000)) 423 424 def test_passing_values(self): 425 def passValue(value): 426 return self.interp.call('set', '_', value) 427 428 self.assertEqual(passValue(True), True if self.wantobjects else '1') 429 self.assertEqual(passValue(False), False if self.wantobjects else '0') 430 self.assertEqual(passValue('string'), 'string') 431 self.assertEqual(passValue('string\u20ac'), 'string\u20ac') 432 self.assertEqual(passValue('string\U0001f4bb'), 'string\U0001f4bb') 433 self.assertEqual(passValue('str\x00ing'), 'str\x00ing') 434 self.assertEqual(passValue('str\x00ing\xbd'), 'str\x00ing\xbd') 435 self.assertEqual(passValue('str\x00ing\u20ac'), 'str\x00ing\u20ac') 436 self.assertEqual(passValue('str\x00ing\U0001f4bb'), 437 'str\x00ing\U0001f4bb') 438 self.assertEqual(passValue(b'str\x00ing'), 439 b'str\x00ing' if self.wantobjects else 'str\x00ing') 440 self.assertEqual(passValue(b'str\xc0\x80ing'), 441 b'str\xc0\x80ing' if self.wantobjects else 'str\xc0\x80ing') 442 self.assertEqual(passValue(b'str\xbding'), 443 b'str\xbding' if self.wantobjects else 'str\xbding') 444 for i in self.get_integers(): 445 self.assertEqual(passValue(i), i if self.wantobjects else str(i)) 446 if tcl_version < (8, 5): # bignum was added in Tcl 8.5 447 self.assertEqual(passValue(2**1000), str(2**1000)) 448 for f in (0.0, 1.0, -1.0, 1/3, 449 sys.float_info.min, sys.float_info.max, 450 -sys.float_info.min, -sys.float_info.max): 451 if self.wantobjects: 452 self.assertEqual(passValue(f), f) 453 else: 454 self.assertEqual(float(passValue(f)), f) 455 if self.wantobjects: 456 f = passValue(float('nan')) 457 self.assertNotEqual(f, f) 458 self.assertEqual(passValue(float('inf')), float('inf')) 459 self.assertEqual(passValue(-float('inf')), -float('inf')) 460 else: 461 self.assertEqual(float(passValue(float('inf'))), float('inf')) 462 self.assertEqual(float(passValue(-float('inf'))), -float('inf')) 463 # XXX NaN representation can be not parsable by float() 464 self.assertEqual(passValue((1, '2', (3.4,))), 465 (1, '2', (3.4,)) if self.wantobjects else '1 2 3.4') 466 self.assertEqual(passValue(['a', ['b', 'c']]), 467 ('a', ('b', 'c')) if self.wantobjects else 'a {b c}') 468 469 def test_user_command(self): 470 result = None 471 def testfunc(arg): 472 nonlocal result 473 result = arg 474 return arg 475 self.interp.createcommand('testfunc', testfunc) 476 self.addCleanup(self.interp.tk.deletecommand, 'testfunc') 477 def check(value, expected=None, *, eq=self.assertEqual): 478 if expected is None: 479 expected = value 480 nonlocal result 481 result = None 482 r = self.interp.call('testfunc', value) 483 self.assertIsInstance(result, str) 484 eq(result, expected) 485 self.assertIsInstance(r, str) 486 eq(r, expected) 487 def float_eq(actual, expected): 488 self.assertAlmostEqual(float(actual), expected, 489 delta=abs(expected) * 1e-10) 490 491 check(True, '1') 492 check(False, '0') 493 check('string') 494 check('string\xbd') 495 check('string\u20ac') 496 check('string\U0001f4bb') 497 check('') 498 check(b'string', 'string') 499 check(b'string\xe2\x82\xac', 'string\xe2\x82\xac') 500 check(b'string\xbd', 'string\xbd') 501 check(b'', '') 502 check('str\x00ing') 503 check('str\x00ing\xbd') 504 check('str\x00ing\u20ac') 505 check(b'str\x00ing', 'str\x00ing') 506 check(b'str\xc0\x80ing', 'str\xc0\x80ing') 507 check(b'str\xc0\x80ing\xe2\x82\xac', 'str\xc0\x80ing\xe2\x82\xac') 508 for i in self.get_integers(): 509 check(i, str(i)) 510 if tcl_version < (8, 5): # bignum was added in Tcl 8.5 511 check(2**1000, str(2**1000)) 512 for f in (0.0, 1.0, -1.0): 513 check(f, repr(f)) 514 for f in (1/3.0, sys.float_info.min, sys.float_info.max, 515 -sys.float_info.min, -sys.float_info.max): 516 check(f, eq=float_eq) 517 check(float('inf'), eq=float_eq) 518 check(-float('inf'), eq=float_eq) 519 # XXX NaN representation can be not parsable by float() 520 check((), '') 521 check((1, (2,), (3, 4), '5 6', ()), '1 2 {3 4} {5 6} {}') 522 check([1, [2,], [3, 4], '5 6', []], '1 2 {3 4} {5 6} {}') 523 524 def test_splitlist(self): 525 splitlist = self.interp.tk.splitlist 526 call = self.interp.tk.call 527 self.assertRaises(TypeError, splitlist) 528 self.assertRaises(TypeError, splitlist, 'a', 'b') 529 self.assertRaises(TypeError, splitlist, 2) 530 testcases = [ 531 ('2', ('2',)), 532 ('', ()), 533 ('{}', ('',)), 534 ('""', ('',)), 535 ('a\n b\t\r c\n ', ('a', 'b', 'c')), 536 (b'a\n b\t\r c\n ', ('a', 'b', 'c')), 537 ('a \u20ac', ('a', '\u20ac')), 538 ('a \U0001f4bb', ('a', '\U0001f4bb')), 539 (b'a \xe2\x82\xac', ('a', '\u20ac')), 540 (b'a\xc0\x80b c\xc0\x80d', ('a\x00b', 'c\x00d')), 541 ('a {b c}', ('a', 'b c')), 542 (r'a b\ c', ('a', 'b c')), 543 (('a', 'b c'), ('a', 'b c')), 544 ('a 2', ('a', '2')), 545 (('a', 2), ('a', 2)), 546 ('a 3.4', ('a', '3.4')), 547 (('a', 3.4), ('a', 3.4)), 548 ((), ()), 549 ([], ()), 550 (['a', ['b', 'c']], ('a', ['b', 'c'])), 551 (call('list', 1, '2', (3.4,)), 552 (1, '2', (3.4,)) if self.wantobjects else 553 ('1', '2', '3.4')), 554 ] 555 tk_patchlevel = get_tk_patchlevel() 556 if tcl_version >= (8, 5): 557 if not self.wantobjects or tk_patchlevel < (8, 5, 5): 558 # Before 8.5.5 dicts were converted to lists through string 559 expected = ('12', '\u20ac', '\xe2\x82\xac', '3.4') 560 else: 561 expected = (12, '\u20ac', b'\xe2\x82\xac', (3.4,)) 562 testcases += [ 563 (call('dict', 'create', 12, '\u20ac', b'\xe2\x82\xac', (3.4,)), 564 expected), 565 ] 566 dbg_info = ('want objects? %s, Tcl version: %s, Tk patchlevel: %s' 567 % (self.wantobjects, tcl_version, tk_patchlevel)) 568 for arg, res in testcases: 569 self.assertEqual(splitlist(arg), res, 570 'arg=%a, %s' % (arg, dbg_info)) 571 self.assertRaises(TclError, splitlist, '{') 572 573 def test_split(self): 574 split = self.interp.tk.split 575 call = self.interp.tk.call 576 self.assertRaises(TypeError, split) 577 self.assertRaises(TypeError, split, 'a', 'b') 578 self.assertRaises(TypeError, split, 2) 579 testcases = [ 580 ('2', '2'), 581 ('', ''), 582 ('{}', ''), 583 ('""', ''), 584 ('{', '{'), 585 ('a\n b\t\r c\n ', ('a', 'b', 'c')), 586 (b'a\n b\t\r c\n ', ('a', 'b', 'c')), 587 ('a \u20ac', ('a', '\u20ac')), 588 (b'a \xe2\x82\xac', ('a', '\u20ac')), 589 (b'a\xc0\x80b', 'a\x00b'), 590 (b'a\xc0\x80b c\xc0\x80d', ('a\x00b', 'c\x00d')), 591 (b'{a\xc0\x80b c\xc0\x80d', '{a\x00b c\x00d'), 592 ('a {b c}', ('a', ('b', 'c'))), 593 (r'a b\ c', ('a', ('b', 'c'))), 594 (('a', b'b c'), ('a', ('b', 'c'))), 595 (('a', 'b c'), ('a', ('b', 'c'))), 596 ('a 2', ('a', '2')), 597 (('a', 2), ('a', 2)), 598 ('a 3.4', ('a', '3.4')), 599 (('a', 3.4), ('a', 3.4)), 600 (('a', (2, 3.4)), ('a', (2, 3.4))), 601 ((), ()), 602 ([], ()), 603 (['a', 'b c'], ('a', ('b', 'c'))), 604 (['a', ['b', 'c']], ('a', ('b', 'c'))), 605 (call('list', 1, '2', (3.4,)), 606 (1, '2', (3.4,)) if self.wantobjects else 607 ('1', '2', '3.4')), 608 ] 609 if tcl_version >= (8, 5): 610 if not self.wantobjects or get_tk_patchlevel() < (8, 5, 5): 611 # Before 8.5.5 dicts were converted to lists through string 612 expected = ('12', '\u20ac', '\xe2\x82\xac', '3.4') 613 else: 614 expected = (12, '\u20ac', b'\xe2\x82\xac', (3.4,)) 615 testcases += [ 616 (call('dict', 'create', 12, '\u20ac', b'\xe2\x82\xac', (3.4,)), 617 expected), 618 ] 619 for arg, res in testcases: 620 self.assertEqual(split(arg), res, msg=arg) 621 622 def test_splitdict(self): 623 splitdict = tkinter._splitdict 624 tcl = self.interp.tk 625 626 arg = '-a {1 2 3} -something foo status {}' 627 self.assertEqual(splitdict(tcl, arg, False), 628 {'-a': '1 2 3', '-something': 'foo', 'status': ''}) 629 self.assertEqual(splitdict(tcl, arg), 630 {'a': '1 2 3', 'something': 'foo', 'status': ''}) 631 632 arg = ('-a', (1, 2, 3), '-something', 'foo', 'status', '{}') 633 self.assertEqual(splitdict(tcl, arg, False), 634 {'-a': (1, 2, 3), '-something': 'foo', 'status': '{}'}) 635 self.assertEqual(splitdict(tcl, arg), 636 {'a': (1, 2, 3), 'something': 'foo', 'status': '{}'}) 637 638 self.assertRaises(RuntimeError, splitdict, tcl, '-a b -c ') 639 self.assertRaises(RuntimeError, splitdict, tcl, ('-a', 'b', '-c')) 640 641 arg = tcl.call('list', 642 '-a', (1, 2, 3), '-something', 'foo', 'status', ()) 643 self.assertEqual(splitdict(tcl, arg), 644 {'a': (1, 2, 3) if self.wantobjects else '1 2 3', 645 'something': 'foo', 'status': ''}) 646 647 if tcl_version >= (8, 5): 648 arg = tcl.call('dict', 'create', 649 '-a', (1, 2, 3), '-something', 'foo', 'status', ()) 650 if not self.wantobjects or get_tk_patchlevel() < (8, 5, 5): 651 # Before 8.5.5 dicts were converted to lists through string 652 expected = {'a': '1 2 3', 'something': 'foo', 'status': ''} 653 else: 654 expected = {'a': (1, 2, 3), 'something': 'foo', 'status': ''} 655 self.assertEqual(splitdict(tcl, arg), expected) 656 657 def test_join(self): 658 join = tkinter._join 659 tcl = self.interp.tk 660 def unpack(s): 661 return tcl.call('lindex', s, 0) 662 def check(value): 663 self.assertEqual(unpack(join([value])), value) 664 self.assertEqual(unpack(join([value, 0])), value) 665 self.assertEqual(unpack(unpack(join([[value]]))), value) 666 self.assertEqual(unpack(unpack(join([[value, 0]]))), value) 667 self.assertEqual(unpack(unpack(join([[value], 0]))), value) 668 self.assertEqual(unpack(unpack(join([[value, 0], 0]))), value) 669 check('') 670 check('spam') 671 check('sp am') 672 check('sp\tam') 673 check('sp\nam') 674 check(' \t\n') 675 check('{spam}') 676 check('{sp am}') 677 check('"spam"') 678 check('"sp am"') 679 check('{"spam"}') 680 check('"{spam}"') 681 check('sp\\am') 682 check('"sp\\am"') 683 check('"{}" "{}"') 684 check('"\\') 685 check('"{') 686 check('"}') 687 check('\n\\') 688 check('\n{') 689 check('\n}') 690 check('\\\n') 691 check('{\n') 692 check('}\n') 693 694 def test_new_tcl_obj(self): 695 self.assertRaises(TypeError, _tkinter.Tcl_Obj) 696 697class BigmemTclTest(unittest.TestCase): 698 699 def setUp(self): 700 self.interp = Tcl() 701 702 @support.cpython_only 703 @unittest.skipUnless(INT_MAX < PY_SSIZE_T_MAX, "needs UINT_MAX < SIZE_MAX") 704 @support.bigmemtest(size=INT_MAX + 1, memuse=5, dry_run=False) 705 def test_huge_string_call(self, size): 706 value = ' ' * size 707 self.assertRaises(OverflowError, self.interp.call, 'string', 'index', value, 0) 708 709 @support.cpython_only 710 @unittest.skipUnless(INT_MAX < PY_SSIZE_T_MAX, "needs UINT_MAX < SIZE_MAX") 711 @support.bigmemtest(size=INT_MAX + 1, memuse=2, dry_run=False) 712 def test_huge_string_builtins(self, size): 713 tk = self.interp.tk 714 value = '1' + ' ' * size 715 self.assertRaises(OverflowError, tk.getint, value) 716 self.assertRaises(OverflowError, tk.getdouble, value) 717 self.assertRaises(OverflowError, tk.getboolean, value) 718 self.assertRaises(OverflowError, tk.eval, value) 719 self.assertRaises(OverflowError, tk.evalfile, value) 720 self.assertRaises(OverflowError, tk.record, value) 721 self.assertRaises(OverflowError, tk.adderrorinfo, value) 722 self.assertRaises(OverflowError, tk.setvar, value, 'x', 'a') 723 self.assertRaises(OverflowError, tk.setvar, 'x', value, 'a') 724 self.assertRaises(OverflowError, tk.unsetvar, value) 725 self.assertRaises(OverflowError, tk.unsetvar, 'x', value) 726 self.assertRaises(OverflowError, tk.adderrorinfo, value) 727 self.assertRaises(OverflowError, tk.exprstring, value) 728 self.assertRaises(OverflowError, tk.exprlong, value) 729 self.assertRaises(OverflowError, tk.exprboolean, value) 730 self.assertRaises(OverflowError, tk.splitlist, value) 731 self.assertRaises(OverflowError, tk.split, value) 732 self.assertRaises(OverflowError, tk.createcommand, value, max) 733 self.assertRaises(OverflowError, tk.deletecommand, value) 734 735 @support.cpython_only 736 @unittest.skipUnless(INT_MAX < PY_SSIZE_T_MAX, "needs UINT_MAX < SIZE_MAX") 737 @support.bigmemtest(size=INT_MAX + 1, memuse=6, dry_run=False) 738 def test_huge_string_builtins2(self, size): 739 # These commands require larger memory for possible error messages 740 tk = self.interp.tk 741 value = '1' + ' ' * size 742 self.assertRaises(OverflowError, tk.evalfile, value) 743 self.assertRaises(OverflowError, tk.unsetvar, value) 744 self.assertRaises(OverflowError, tk.unsetvar, 'x', value) 745 746 747def setUpModule(): 748 if support.verbose: 749 tcl = Tcl() 750 print('patchlevel =', tcl.call('info', 'patchlevel')) 751 752 753def test_main(): 754 support.run_unittest(TclTest, TkinterTest, BigmemTclTest) 755 756if __name__ == "__main__": 757 test_main() 758