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