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