1 import unittest 2 import re 3 import subprocess 4 import sys 5 import os 6 from test import support 7 8 # Skip this test if the _tkinter module wasn't built. 9 _tkinter = support.import_module('_tkinter') 10 11 import tkinter 12 from tkinter import Tcl 13 from _tkinter import TclError 14 15 try: 16 from _testcapi import INT_MAX, PY_SSIZE_T_MAX 17 except ImportError: 18 INT_MAX = PY_SSIZE_T_MAX = sys.maxsize 19 20 tcl_version = tuple(map(int, _tkinter.TCL_VERSION.split('.'))) 21 22 _tk_patchlevel = None 23 def 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 39 class TkinterTest(unittest.TestCase): 40 41 def testFlattenLen(self): 42 # flatten(<object with no length>) 43 self.assertRaises(TypeError, _tkinter._flatten, True) 44 45 46 class 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('str\x00ing'), 'str\x00ing') 433 self.assertEqual(passValue('str\x00ing\xbd'), 'str\x00ing\xbd') 434 self.assertEqual(passValue('str\x00ing\u20ac'), 'str\x00ing\u20ac') 435 self.assertEqual(passValue(b'str\x00ing'), 436 b'str\x00ing' if self.wantobjects else 'str\x00ing') 437 self.assertEqual(passValue(b'str\xc0\x80ing'), 438 b'str\xc0\x80ing' if self.wantobjects else 'str\xc0\x80ing') 439 self.assertEqual(passValue(b'str\xbding'), 440 b'str\xbding' if self.wantobjects else 'str\xbding') 441 for i in self.get_integers(): 442 self.assertEqual(passValue(i), i if self.wantobjects else str(i)) 443 if tcl_version < (8, 5): # bignum was added in Tcl 8.5 444 self.assertEqual(passValue(2**1000), str(2**1000)) 445 for f in (0.0, 1.0, -1.0, 1/3, 446 sys.float_info.min, sys.float_info.max, 447 -sys.float_info.min, -sys.float_info.max): 448 if self.wantobjects: 449 self.assertEqual(passValue(f), f) 450 else: 451 self.assertEqual(float(passValue(f)), f) 452 if self.wantobjects: 453 f = passValue(float('nan')) 454 self.assertNotEqual(f, f) 455 self.assertEqual(passValue(float('inf')), float('inf')) 456 self.assertEqual(passValue(-float('inf')), -float('inf')) 457 else: 458 self.assertEqual(float(passValue(float('inf'))), float('inf')) 459 self.assertEqual(float(passValue(-float('inf'))), -float('inf')) 460 # XXX NaN representation can be not parsable by float() 461 self.assertEqual(passValue((1, '2', (3.4,))), 462 (1, '2', (3.4,)) if self.wantobjects else '1 2 3.4') 463 self.assertEqual(passValue(['a', ['b', 'c']]), 464 ('a', ('b', 'c')) if self.wantobjects else 'a {b c}') 465 466 def test_user_command(self): 467 result = None 468 def testfunc(arg): 469 nonlocal result 470 result = arg 471 return arg 472 self.interp.createcommand('testfunc', testfunc) 473 self.addCleanup(self.interp.tk.deletecommand, 'testfunc') 474 def check(value, expected=None, *, eq=self.assertEqual): 475 if expected is None: 476 expected = value 477 nonlocal result 478 result = None 479 r = self.interp.call('testfunc', value) 480 self.assertIsInstance(result, str) 481 eq(result, expected) 482 self.assertIsInstance(r, str) 483 eq(r, expected) 484 def float_eq(actual, expected): 485 self.assertAlmostEqual(float(actual), expected, 486 delta=abs(expected) * 1e-10) 487 488 check(True, '1') 489 check(False, '0') 490 check('string') 491 check('string\xbd') 492 check('string\u20ac') 493 check('') 494 check(b'string', 'string') 495 check(b'string\xe2\x82\xac', 'string\xe2\x82\xac') 496 check(b'string\xbd', 'string\xbd') 497 check(b'', '') 498 check('str\x00ing') 499 check('str\x00ing\xbd') 500 check('str\x00ing\u20ac') 501 check(b'str\x00ing', 'str\x00ing') 502 check(b'str\xc0\x80ing', 'str\xc0\x80ing') 503 check(b'str\xc0\x80ing\xe2\x82\xac', 'str\xc0\x80ing\xe2\x82\xac') 504 for i in self.get_integers(): 505 check(i, str(i)) 506 if tcl_version < (8, 5): # bignum was added in Tcl 8.5 507 check(2**1000, str(2**1000)) 508 for f in (0.0, 1.0, -1.0): 509 check(f, repr(f)) 510 for f in (1/3.0, sys.float_info.min, sys.float_info.max, 511 -sys.float_info.min, -sys.float_info.max): 512 check(f, eq=float_eq) 513 check(float('inf'), eq=float_eq) 514 check(-float('inf'), eq=float_eq) 515 # XXX NaN representation can be not parsable by float() 516 check((), '') 517 check((1, (2,), (3, 4), '5 6', ()), '1 2 {3 4} {5 6} {}') 518 check([1, [2,], [3, 4], '5 6', []], '1 2 {3 4} {5 6} {}') 519 520 def test_splitlist(self): 521 splitlist = self.interp.tk.splitlist 522 call = self.interp.tk.call 523 self.assertRaises(TypeError, splitlist) 524 self.assertRaises(TypeError, splitlist, 'a', 'b') 525 self.assertRaises(TypeError, splitlist, 2) 526 testcases = [ 527 ('2', ('2',)), 528 ('', ()), 529 ('{}', ('',)), 530 ('""', ('',)), 531 ('a\n b\t\r c\n ', ('a', 'b', 'c')), 532 (b'a\n b\t\r c\n ', ('a', 'b', 'c')), 533 ('a \u20ac', ('a', '\u20ac')), 534 (b'a \xe2\x82\xac', ('a', '\u20ac')), 535 (b'a\xc0\x80b c\xc0\x80d', ('a\x00b', 'c\x00d')), 536 ('a {b c}', ('a', 'b c')), 537 (r'a b\ c', ('a', 'b c')), 538 (('a', 'b c'), ('a', 'b c')), 539 ('a 2', ('a', '2')), 540 (('a', 2), ('a', 2)), 541 ('a 3.4', ('a', '3.4')), 542 (('a', 3.4), ('a', 3.4)), 543 ((), ()), 544 ([], ()), 545 (['a', ['b', 'c']], ('a', ['b', 'c'])), 546 (call('list', 1, '2', (3.4,)), 547 (1, '2', (3.4,)) if self.wantobjects else 548 ('1', '2', '3.4')), 549 ] 550 tk_patchlevel = get_tk_patchlevel() 551 if tcl_version >= (8, 5): 552 if not self.wantobjects or tk_patchlevel < (8, 5, 5): 553 # Before 8.5.5 dicts were converted to lists through string 554 expected = ('12', '\u20ac', '\xe2\x82\xac', '3.4') 555 else: 556 expected = (12, '\u20ac', b'\xe2\x82\xac', (3.4,)) 557 testcases += [ 558 (call('dict', 'create', 12, '\u20ac', b'\xe2\x82\xac', (3.4,)), 559 expected), 560 ] 561 dbg_info = ('want objects? %s, Tcl version: %s, Tk patchlevel: %s' 562 % (self.wantobjects, tcl_version, tk_patchlevel)) 563 for arg, res in testcases: 564 self.assertEqual(splitlist(arg), res, 565 'arg=%a, %s' % (arg, dbg_info)) 566 self.assertRaises(TclError, splitlist, '{') 567 568 def test_split(self): 569 split = self.interp.tk.split 570 call = self.interp.tk.call 571 self.assertRaises(TypeError, split) 572 self.assertRaises(TypeError, split, 'a', 'b') 573 self.assertRaises(TypeError, split, 2) 574 testcases = [ 575 ('2', '2'), 576 ('', ''), 577 ('{}', ''), 578 ('""', ''), 579 ('{', '{'), 580 ('a\n b\t\r c\n ', ('a', 'b', 'c')), 581 (b'a\n b\t\r c\n ', ('a', 'b', 'c')), 582 ('a \u20ac', ('a', '\u20ac')), 583 (b'a \xe2\x82\xac', ('a', '\u20ac')), 584 (b'a\xc0\x80b', 'a\x00b'), 585 (b'a\xc0\x80b c\xc0\x80d', ('a\x00b', 'c\x00d')), 586 (b'{a\xc0\x80b c\xc0\x80d', '{a\x00b c\x00d'), 587 ('a {b c}', ('a', ('b', 'c'))), 588 (r'a b\ c', ('a', ('b', 'c'))), 589 (('a', b'b c'), ('a', ('b', 'c'))), 590 (('a', 'b c'), ('a', ('b', 'c'))), 591 ('a 2', ('a', '2')), 592 (('a', 2), ('a', 2)), 593 ('a 3.4', ('a', '3.4')), 594 (('a', 3.4), ('a', 3.4)), 595 (('a', (2, 3.4)), ('a', (2, 3.4))), 596 ((), ()), 597 ([], ()), 598 (['a', 'b c'], ('a', ('b', 'c'))), 599 (['a', ['b', 'c']], ('a', ('b', 'c'))), 600 (call('list', 1, '2', (3.4,)), 601 (1, '2', (3.4,)) if self.wantobjects else 602 ('1', '2', '3.4')), 603 ] 604 if tcl_version >= (8, 5): 605 if not self.wantobjects or get_tk_patchlevel() < (8, 5, 5): 606 # Before 8.5.5 dicts were converted to lists through string 607 expected = ('12', '\u20ac', '\xe2\x82\xac', '3.4') 608 else: 609 expected = (12, '\u20ac', b'\xe2\x82\xac', (3.4,)) 610 testcases += [ 611 (call('dict', 'create', 12, '\u20ac', b'\xe2\x82\xac', (3.4,)), 612 expected), 613 ] 614 for arg, res in testcases: 615 self.assertEqual(split(arg), res, msg=arg) 616 617 def test_splitdict(self): 618 splitdict = tkinter._splitdict 619 tcl = self.interp.tk 620 621 arg = '-a {1 2 3} -something foo status {}' 622 self.assertEqual(splitdict(tcl, arg, False), 623 {'-a': '1 2 3', '-something': 'foo', 'status': ''}) 624 self.assertEqual(splitdict(tcl, arg), 625 {'a': '1 2 3', 'something': 'foo', 'status': ''}) 626 627 arg = ('-a', (1, 2, 3), '-something', 'foo', 'status', '{}') 628 self.assertEqual(splitdict(tcl, arg, False), 629 {'-a': (1, 2, 3), '-something': 'foo', 'status': '{}'}) 630 self.assertEqual(splitdict(tcl, arg), 631 {'a': (1, 2, 3), 'something': 'foo', 'status': '{}'}) 632 633 self.assertRaises(RuntimeError, splitdict, tcl, '-a b -c ') 634 self.assertRaises(RuntimeError, splitdict, tcl, ('-a', 'b', '-c')) 635 636 arg = tcl.call('list', 637 '-a', (1, 2, 3), '-something', 'foo', 'status', ()) 638 self.assertEqual(splitdict(tcl, arg), 639 {'a': (1, 2, 3) if self.wantobjects else '1 2 3', 640 'something': 'foo', 'status': ''}) 641 642 if tcl_version >= (8, 5): 643 arg = tcl.call('dict', 'create', 644 '-a', (1, 2, 3), '-something', 'foo', 'status', ()) 645 if not self.wantobjects or get_tk_patchlevel() < (8, 5, 5): 646 # Before 8.5.5 dicts were converted to lists through string 647 expected = {'a': '1 2 3', 'something': 'foo', 'status': ''} 648 else: 649 expected = {'a': (1, 2, 3), 'something': 'foo', 'status': ''} 650 self.assertEqual(splitdict(tcl, arg), expected) 651 652 def test_join(self): 653 join = tkinter._join 654 tcl = self.interp.tk 655 def unpack(s): 656 return tcl.call('lindex', s, 0) 657 def check(value): 658 self.assertEqual(unpack(join([value])), value) 659 self.assertEqual(unpack(join([value, 0])), value) 660 self.assertEqual(unpack(unpack(join([[value]]))), value) 661 self.assertEqual(unpack(unpack(join([[value, 0]]))), value) 662 self.assertEqual(unpack(unpack(join([[value], 0]))), value) 663 self.assertEqual(unpack(unpack(join([[value, 0], 0]))), value) 664 check('') 665 check('spam') 666 check('sp am') 667 check('sp\tam') 668 check('sp\nam') 669 check(' \t\n') 670 check('{spam}') 671 check('{sp am}') 672 check('"spam"') 673 check('"sp am"') 674 check('{"spam"}') 675 check('"{spam}"') 676 check('sp\\am') 677 check('"sp\\am"') 678 check('"{}" "{}"') 679 check('"\\') 680 check('"{') 681 check('"}') 682 check('\n\\') 683 check('\n{') 684 check('\n}') 685 check('\\\n') 686 check('{\n') 687 check('}\n') 688 689 def test_new_tcl_obj(self): 690 self.assertRaises(TypeError, _tkinter.Tcl_Obj) 691 692 class BigmemTclTest(unittest.TestCase): 693 694 def setUp(self): 695 self.interp = Tcl() 696 697 @support.cpython_only 698 @unittest.skipUnless(INT_MAX < PY_SSIZE_T_MAX, "needs UINT_MAX < SIZE_MAX") 699 @support.bigmemtest(size=INT_MAX + 1, memuse=5, dry_run=False) 700 def test_huge_string_call(self, size): 701 value = ' ' * size 702 self.assertRaises(OverflowError, self.interp.call, 'string', 'index', value, 0) 703 704 @support.cpython_only 705 @unittest.skipUnless(INT_MAX < PY_SSIZE_T_MAX, "needs UINT_MAX < SIZE_MAX") 706 @support.bigmemtest(size=INT_MAX + 1, memuse=2, dry_run=False) 707 def test_huge_string_builtins(self, size): 708 tk = self.interp.tk 709 value = '1' + ' ' * size 710 self.assertRaises(OverflowError, tk.getint, value) 711 self.assertRaises(OverflowError, tk.getdouble, value) 712 self.assertRaises(OverflowError, tk.getboolean, value) 713 self.assertRaises(OverflowError, tk.eval, value) 714 self.assertRaises(OverflowError, tk.evalfile, value) 715 self.assertRaises(OverflowError, tk.record, value) 716 self.assertRaises(OverflowError, tk.adderrorinfo, value) 717 self.assertRaises(OverflowError, tk.setvar, value, 'x', 'a') 718 self.assertRaises(OverflowError, tk.setvar, 'x', value, 'a') 719 self.assertRaises(OverflowError, tk.unsetvar, value) 720 self.assertRaises(OverflowError, tk.unsetvar, 'x', value) 721 self.assertRaises(OverflowError, tk.adderrorinfo, value) 722 self.assertRaises(OverflowError, tk.exprstring, value) 723 self.assertRaises(OverflowError, tk.exprlong, value) 724 self.assertRaises(OverflowError, tk.exprboolean, value) 725 self.assertRaises(OverflowError, tk.splitlist, value) 726 self.assertRaises(OverflowError, tk.split, value) 727 self.assertRaises(OverflowError, tk.createcommand, value, max) 728 self.assertRaises(OverflowError, tk.deletecommand, value) 729 730 @support.cpython_only 731 @unittest.skipUnless(INT_MAX < PY_SSIZE_T_MAX, "needs UINT_MAX < SIZE_MAX") 732 @support.bigmemtest(size=INT_MAX + 1, memuse=6, dry_run=False) 733 def test_huge_string_builtins2(self, size): 734 # These commands require larger memory for possible error messages 735 tk = self.interp.tk 736 value = '1' + ' ' * size 737 self.assertRaises(OverflowError, tk.evalfile, value) 738 self.assertRaises(OverflowError, tk.unsetvar, value) 739 self.assertRaises(OverflowError, tk.unsetvar, 'x', value) 740 741 742 def setUpModule(): 743 if support.verbose: 744 tcl = Tcl() 745 print('patchlevel =', tcl.call('info', 'patchlevel')) 746 747 748 def test_main(): 749 support.run_unittest(TclTest, TkinterTest, BigmemTclTest) 750 751 if __name__ == "__main__": 752 test_main() 753