blob: 1c5b9cf2bd2a8367d24e134f234a5c0691120944 [file] [log] [blame]
David Aschere2b4b322004-02-18 05:59:53 +00001import unittest
Serhiy Storchaka462c3572015-04-22 08:36:03 +03002import re
Zachary Ware83fd0a82015-10-12 23:27:58 -05003import subprocess
Hirokazu Yamamotodda7fdf2010-09-23 15:28:35 +00004import sys
David Aschere2b4b322004-02-18 05:59:53 +00005import os
Serhiy Storchakad05b0002019-10-08 14:31:35 +03006import warnings
Benjamin Petersonee8712c2008-05-20 21:35:26 +00007from test import support
R. David Murraya21e4ca2009-03-31 23:16:50 +00008
9# Skip this test if the _tkinter module wasn't built.
10_tkinter = support.import_module('_tkinter')
11
Zachary Ware7dc9dea2015-05-22 11:36:53 -050012import tkinter
Guilherme Polofa8fba92009-02-07 02:33:47 +000013from tkinter import Tcl
David Aschere2b4b322004-02-18 05:59:53 +000014from _tkinter import TclError
15
Serhiy Storchaka5cfc79d2014-02-07 10:06:39 +020016try:
17 from _testcapi import INT_MAX, PY_SSIZE_T_MAX
18except ImportError:
19 INT_MAX = PY_SSIZE_T_MAX = sys.maxsize
20
Serhiy Storchaka462c3572015-04-22 08:36:03 +030021tcl_version = tuple(map(int, _tkinter.TCL_VERSION.split('.')))
Serhiy Storchakadfa689b2013-09-08 20:29:37 +030022
Serhiy Storchaka92af06b2014-02-02 23:04:24 +020023_tk_patchlevel = None
24def get_tk_patchlevel():
25 global _tk_patchlevel
26 if _tk_patchlevel is None:
27 tcl = Tcl()
Serhiy Storchaka462c3572015-04-22 08:36:03 +030028 patchlevel = tcl.call('info', 'patchlevel')
29 m = re.fullmatch(r'(\d+)\.(\d+)([ab.])(\d+)', patchlevel)
30 major, minor, releaselevel, serial = m.groups()
31 major, minor, serial = int(major), int(minor), int(serial)
32 releaselevel = {'a': 'alpha', 'b': 'beta', '.': 'final'}[releaselevel]
33 if releaselevel == 'final':
34 _tk_patchlevel = major, minor, serial, releaselevel, 0
35 else:
36 _tk_patchlevel = major, minor, 0, releaselevel, serial
Serhiy Storchaka92af06b2014-02-02 23:04:24 +020037 return _tk_patchlevel
38
Benjamin Petersonc4bbc8d2009-01-30 03:39:35 +000039
40class TkinterTest(unittest.TestCase):
41
42 def testFlattenLen(self):
43 # flatten(<object with no length>)
44 self.assertRaises(TypeError, _tkinter._flatten, True)
45
46
David Aschere2b4b322004-02-18 05:59:53 +000047class TclTest(unittest.TestCase):
48
49 def setUp(self):
50 self.interp = Tcl()
Serhiy Storchakacc4290b2013-12-25 17:29:01 +020051 self.wantobjects = self.interp.tk.wantobjects()
David Aschere2b4b322004-02-18 05:59:53 +000052
53 def testEval(self):
54 tcl = self.interp
55 tcl.eval('set a 1')
56 self.assertEqual(tcl.eval('set a'),'1')
57
Serhiy Storchaka1317e142014-02-03 21:24:07 +020058 def test_eval_null_in_result(self):
59 tcl = self.interp
60 self.assertEqual(tcl.eval('set a "a\\0b"'), 'a\x00b')
61
David Aschere2b4b322004-02-18 05:59:53 +000062 def testEvalException(self):
63 tcl = self.interp
64 self.assertRaises(TclError,tcl.eval,'set a')
65
66 def testEvalException2(self):
67 tcl = self.interp
68 self.assertRaises(TclError,tcl.eval,'this is wrong')
69
70 def testCall(self):
71 tcl = self.interp
72 tcl.call('set','a','1')
73 self.assertEqual(tcl.call('set','a'),'1')
74
75 def testCallException(self):
76 tcl = self.interp
77 self.assertRaises(TclError,tcl.call,'set','a')
78
79 def testCallException2(self):
80 tcl = self.interp
81 self.assertRaises(TclError,tcl.call,'this','is','wrong')
82
83 def testSetVar(self):
84 tcl = self.interp
85 tcl.setvar('a','1')
86 self.assertEqual(tcl.eval('set a'),'1')
87
88 def testSetVarArray(self):
89 tcl = self.interp
90 tcl.setvar('a(1)','1')
91 self.assertEqual(tcl.eval('set a(1)'),'1')
92
93 def testGetVar(self):
94 tcl = self.interp
95 tcl.eval('set a 1')
96 self.assertEqual(tcl.getvar('a'),'1')
97
98 def testGetVarArray(self):
99 tcl = self.interp
100 tcl.eval('set a(1) 1')
101 self.assertEqual(tcl.getvar('a(1)'),'1')
102
103 def testGetVarException(self):
104 tcl = self.interp
105 self.assertRaises(TclError,tcl.getvar,'a')
106
107 def testGetVarArrayException(self):
108 tcl = self.interp
109 self.assertRaises(TclError,tcl.getvar,'a(1)')
110
111 def testUnsetVar(self):
112 tcl = self.interp
113 tcl.setvar('a',1)
114 self.assertEqual(tcl.eval('info exists a'),'1')
115 tcl.unsetvar('a')
116 self.assertEqual(tcl.eval('info exists a'),'0')
117
118 def testUnsetVarArray(self):
119 tcl = self.interp
120 tcl.setvar('a(1)',1)
121 tcl.setvar('a(2)',2)
122 self.assertEqual(tcl.eval('info exists a(1)'),'1')
123 self.assertEqual(tcl.eval('info exists a(2)'),'1')
124 tcl.unsetvar('a(1)')
125 self.assertEqual(tcl.eval('info exists a(1)'),'0')
126 self.assertEqual(tcl.eval('info exists a(2)'),'1')
127
128 def testUnsetVarException(self):
129 tcl = self.interp
130 self.assertRaises(TclError,tcl.unsetvar,'a')
Tim Peters27f88362004-07-08 04:22:35 +0000131
Serhiy Storchakaea134da2015-04-02 18:46:50 +0300132 def get_integers(self):
Serhiy Storchaka4c7dc482015-04-02 18:49:14 +0300133 integers = (0, 1, -1, 2**31-1, -2**31, 2**31, -2**31-1, 2**63-1, -2**63)
Serhiy Storchaka3af7a382015-04-22 10:53:08 +0300134 # bignum was added in Tcl 8.5, but its support is able only since 8.5.8
135 if (get_tk_patchlevel() >= (8, 6, 0, 'final') or
136 (8, 5, 8) <= get_tk_patchlevel() < (8, 6)):
Serhiy Storchakaea134da2015-04-02 18:46:50 +0300137 integers += (2**63, -2**63-1, 2**1000, -2**1000)
138 return integers
139
Serhiy Storchaka9f1f4f42014-05-30 14:07:38 +0300140 def test_getint(self):
141 tcl = self.interp.tk
Serhiy Storchakaea134da2015-04-02 18:46:50 +0300142 for i in self.get_integers():
143 self.assertEqual(tcl.getint(' %d ' % i), i)
Serhiy Storchaka2379d542015-04-02 20:07:09 +0300144 if tcl_version >= (8, 5):
145 self.assertEqual(tcl.getint(' %#o ' % i), i)
146 self.assertEqual(tcl.getint((' %#o ' % i).replace('o', '')), i)
Serhiy Storchakaea134da2015-04-02 18:46:50 +0300147 self.assertEqual(tcl.getint(' %#x ' % i), i)
148 if tcl_version < (8, 5): # bignum was added in Tcl 8.5
149 self.assertRaises(TclError, tcl.getint, str(2**1000))
Serhiy Storchaka9f1f4f42014-05-30 14:07:38 +0300150 self.assertEqual(tcl.getint(42), 42)
151 self.assertRaises(TypeError, tcl.getint)
152 self.assertRaises(TypeError, tcl.getint, '42', '10')
153 self.assertRaises(TypeError, tcl.getint, b'42')
154 self.assertRaises(TypeError, tcl.getint, 42.0)
155 self.assertRaises(TclError, tcl.getint, 'a')
156 self.assertRaises((TypeError, ValueError, TclError),
157 tcl.getint, '42\0')
158 self.assertRaises((UnicodeEncodeError, ValueError, TclError),
159 tcl.getint, '42\ud800')
160
161 def test_getdouble(self):
162 tcl = self.interp.tk
163 self.assertEqual(tcl.getdouble(' 42 '), 42.0)
164 self.assertEqual(tcl.getdouble(' 42.5 '), 42.5)
165 self.assertEqual(tcl.getdouble(42.5), 42.5)
Serhiy Storchaka645058d2015-05-06 14:00:04 +0300166 self.assertEqual(tcl.getdouble(42), 42.0)
Serhiy Storchaka9f1f4f42014-05-30 14:07:38 +0300167 self.assertRaises(TypeError, tcl.getdouble)
168 self.assertRaises(TypeError, tcl.getdouble, '42.5', '10')
169 self.assertRaises(TypeError, tcl.getdouble, b'42.5')
Serhiy Storchaka9f1f4f42014-05-30 14:07:38 +0300170 self.assertRaises(TclError, tcl.getdouble, 'a')
171 self.assertRaises((TypeError, ValueError, TclError),
172 tcl.getdouble, '42.5\0')
173 self.assertRaises((UnicodeEncodeError, ValueError, TclError),
174 tcl.getdouble, '42.5\ud800')
175
176 def test_getboolean(self):
177 tcl = self.interp.tk
178 self.assertIs(tcl.getboolean('on'), True)
179 self.assertIs(tcl.getboolean('1'), True)
Serhiy Storchaka9a6e2012015-04-04 12:43:01 +0300180 self.assertIs(tcl.getboolean(42), True)
181 self.assertIs(tcl.getboolean(0), False)
Serhiy Storchaka9f1f4f42014-05-30 14:07:38 +0300182 self.assertRaises(TypeError, tcl.getboolean)
183 self.assertRaises(TypeError, tcl.getboolean, 'on', '1')
184 self.assertRaises(TypeError, tcl.getboolean, b'on')
185 self.assertRaises(TypeError, tcl.getboolean, 1.0)
186 self.assertRaises(TclError, tcl.getboolean, 'a')
187 self.assertRaises((TypeError, ValueError, TclError),
188 tcl.getboolean, 'on\0')
189 self.assertRaises((UnicodeEncodeError, ValueError, TclError),
190 tcl.getboolean, 'on\ud800')
191
David Aschere2b4b322004-02-18 05:59:53 +0000192 def testEvalFile(self):
193 tcl = self.interp
Serhiy Storchaka1317e142014-02-03 21:24:07 +0200194 with open(support.TESTFN, 'w') as f:
195 self.addCleanup(support.unlink, support.TESTFN)
196 f.write("""set a 1
197 set b 2
198 set c [ expr $a + $b ]
199 """)
200 tcl.evalfile(support.TESTFN)
David Aschere2b4b322004-02-18 05:59:53 +0000201 self.assertEqual(tcl.eval('set a'),'1')
202 self.assertEqual(tcl.eval('set b'),'2')
203 self.assertEqual(tcl.eval('set c'),'3')
204
Serhiy Storchaka1317e142014-02-03 21:24:07 +0200205 def test_evalfile_null_in_result(self):
206 tcl = self.interp
207 with open(support.TESTFN, 'w') as f:
208 self.addCleanup(support.unlink, support.TESTFN)
209 f.write("""
210 set a "a\0b"
211 set b "a\\0b"
212 """)
213 tcl.evalfile(support.TESTFN)
214 self.assertEqual(tcl.eval('set a'), 'a\x00b')
215 self.assertEqual(tcl.eval('set b'), 'a\x00b')
216
David Aschere2b4b322004-02-18 05:59:53 +0000217 def testEvalFileException(self):
218 tcl = self.interp
219 filename = "doesnotexists"
220 try:
221 os.remove(filename)
Guido van Rossumb940e112007-01-10 16:19:56 +0000222 except Exception as e:
David Aschere2b4b322004-02-18 05:59:53 +0000223 pass
224 self.assertRaises(TclError,tcl.evalfile,filename)
225
David Aschere2b4b322004-02-18 05:59:53 +0000226 def testPackageRequireException(self):
227 tcl = self.interp
228 self.assertRaises(TclError,tcl.eval,'package require DNE')
229
Hirokazu Yamamotodda7fdf2010-09-23 15:28:35 +0000230 @unittest.skipUnless(sys.platform == 'win32', 'Requires Windows')
Martin v. Löwis2d5157e2010-06-04 19:50:26 +0000231 def testLoadWithUNC(self):
Martin v. Löwis2d5157e2010-06-04 19:50:26 +0000232 # Build a UNC path from the regular path.
233 # Something like
234 # \\%COMPUTERNAME%\c$\python27\python.exe
235
236 fullname = os.path.abspath(sys.executable)
237 if fullname[1] != ':':
Hirokazu Yamamotodda7fdf2010-09-23 15:28:35 +0000238 raise unittest.SkipTest('Absolute path should have drive part')
Martin v. Löwis2d5157e2010-06-04 19:50:26 +0000239 unc_name = r'\\%s\%s$\%s' % (os.environ['COMPUTERNAME'],
240 fullname[0],
241 fullname[3:])
Hirokazu Yamamotodda7fdf2010-09-23 15:28:35 +0000242 if not os.path.exists(unc_name):
243 raise unittest.SkipTest('Cannot connect to UNC Path')
Martin v. Löwis2d5157e2010-06-04 19:50:26 +0000244
Georg Brandlec5ae3b2010-07-31 19:17:11 +0000245 with support.EnvironmentVarGuard() as env:
Martin v. Löwis2d5157e2010-06-04 19:50:26 +0000246 env.unset("TCL_LIBRARY")
Zachary Ware83fd0a82015-10-12 23:27:58 -0500247 stdout = subprocess.check_output(
248 [unc_name, '-c', 'import tkinter; print(tkinter)'])
Martin v. Löwis2d5157e2010-06-04 19:50:26 +0000249
Zachary Ware83fd0a82015-10-12 23:27:58 -0500250 self.assertIn(b'tkinter', stdout)
Martin v. Löwis2d5157e2010-06-04 19:50:26 +0000251
Serhiy Storchakafc055252014-02-03 20:41:34 +0200252 def test_exprstring(self):
253 tcl = self.interp
254 tcl.call('set', 'a', 3)
255 tcl.call('set', 'b', 6)
256 def check(expr, expected):
257 result = tcl.exprstring(expr)
258 self.assertEqual(result, expected)
259 self.assertIsInstance(result, str)
260
261 self.assertRaises(TypeError, tcl.exprstring)
262 self.assertRaises(TypeError, tcl.exprstring, '8.2', '+6')
263 self.assertRaises(TypeError, tcl.exprstring, b'8.2 + 6')
264 self.assertRaises(TclError, tcl.exprstring, 'spam')
265 check('', '0')
266 check('8.2 + 6', '14.2')
Serhiy Storchakafc055252014-02-03 20:41:34 +0200267 check('3.1 + $a', '6.1')
268 check('2 + "$a.$b"', '5.6')
269 check('4*[llength "6 2"]', '8')
270 check('{word one} < "word $a"', '0')
271 check('4*2 < 7', '0')
272 check('hypot($a, 4)', '5.0')
273 check('5 / 4', '1')
274 check('5 / 4.0', '1.25')
275 check('5 / ( [string length "abcd"] + 0.0 )', '1.25')
276 check('20.0/5.0', '4.0')
277 check('"0x03" > "2"', '1')
278 check('[string length "a\xbd\u20ac"]', '3')
279 check(r'[string length "a\xbd\u20ac"]', '3')
280 check('"abc"', 'abc')
281 check('"a\xbd\u20ac"', 'a\xbd\u20ac')
282 check(r'"a\xbd\u20ac"', 'a\xbd\u20ac')
Serhiy Storchaka1317e142014-02-03 21:24:07 +0200283 check(r'"a\0b"', 'a\x00b')
Serhiy Storchakaea134da2015-04-02 18:46:50 +0300284 if tcl_version >= (8, 5): # bignum was added in Tcl 8.5
Serhiy Storchaka160f8922014-02-03 22:31:09 +0200285 check('2**64', str(2**64))
Serhiy Storchakafc055252014-02-03 20:41:34 +0200286
287 def test_exprdouble(self):
288 tcl = self.interp
289 tcl.call('set', 'a', 3)
290 tcl.call('set', 'b', 6)
291 def check(expr, expected):
292 result = tcl.exprdouble(expr)
293 self.assertEqual(result, expected)
294 self.assertIsInstance(result, float)
295
296 self.assertRaises(TypeError, tcl.exprdouble)
297 self.assertRaises(TypeError, tcl.exprdouble, '8.2', '+6')
298 self.assertRaises(TypeError, tcl.exprdouble, b'8.2 + 6')
299 self.assertRaises(TclError, tcl.exprdouble, 'spam')
300 check('', 0.0)
301 check('8.2 + 6', 14.2)
Serhiy Storchakafc055252014-02-03 20:41:34 +0200302 check('3.1 + $a', 6.1)
303 check('2 + "$a.$b"', 5.6)
304 check('4*[llength "6 2"]', 8.0)
305 check('{word one} < "word $a"', 0.0)
306 check('4*2 < 7', 0.0)
307 check('hypot($a, 4)', 5.0)
308 check('5 / 4', 1.0)
309 check('5 / 4.0', 1.25)
310 check('5 / ( [string length "abcd"] + 0.0 )', 1.25)
311 check('20.0/5.0', 4.0)
312 check('"0x03" > "2"', 1.0)
313 check('[string length "a\xbd\u20ac"]', 3.0)
314 check(r'[string length "a\xbd\u20ac"]', 3.0)
315 self.assertRaises(TclError, tcl.exprdouble, '"abc"')
Serhiy Storchakaea134da2015-04-02 18:46:50 +0300316 if tcl_version >= (8, 5): # bignum was added in Tcl 8.5
Serhiy Storchaka160f8922014-02-03 22:31:09 +0200317 check('2**64', float(2**64))
Serhiy Storchakafc055252014-02-03 20:41:34 +0200318
319 def test_exprlong(self):
320 tcl = self.interp
321 tcl.call('set', 'a', 3)
322 tcl.call('set', 'b', 6)
323 def check(expr, expected):
324 result = tcl.exprlong(expr)
325 self.assertEqual(result, expected)
326 self.assertIsInstance(result, int)
327
328 self.assertRaises(TypeError, tcl.exprlong)
329 self.assertRaises(TypeError, tcl.exprlong, '8.2', '+6')
330 self.assertRaises(TypeError, tcl.exprlong, b'8.2 + 6')
331 self.assertRaises(TclError, tcl.exprlong, 'spam')
332 check('', 0)
333 check('8.2 + 6', 14)
Serhiy Storchakafc055252014-02-03 20:41:34 +0200334 check('3.1 + $a', 6)
335 check('2 + "$a.$b"', 5)
336 check('4*[llength "6 2"]', 8)
337 check('{word one} < "word $a"', 0)
338 check('4*2 < 7', 0)
339 check('hypot($a, 4)', 5)
340 check('5 / 4', 1)
341 check('5 / 4.0', 1)
342 check('5 / ( [string length "abcd"] + 0.0 )', 1)
343 check('20.0/5.0', 4)
344 check('"0x03" > "2"', 1)
345 check('[string length "a\xbd\u20ac"]', 3)
346 check(r'[string length "a\xbd\u20ac"]', 3)
347 self.assertRaises(TclError, tcl.exprlong, '"abc"')
Serhiy Storchakaea134da2015-04-02 18:46:50 +0300348 if tcl_version >= (8, 5): # bignum was added in Tcl 8.5
Serhiy Storchaka160f8922014-02-03 22:31:09 +0200349 self.assertRaises(TclError, tcl.exprlong, '2**64')
Serhiy Storchakafc055252014-02-03 20:41:34 +0200350
351 def test_exprboolean(self):
352 tcl = self.interp
353 tcl.call('set', 'a', 3)
354 tcl.call('set', 'b', 6)
355 def check(expr, expected):
356 result = tcl.exprboolean(expr)
357 self.assertEqual(result, expected)
358 self.assertIsInstance(result, int)
359 self.assertNotIsInstance(result, bool)
360
361 self.assertRaises(TypeError, tcl.exprboolean)
362 self.assertRaises(TypeError, tcl.exprboolean, '8.2', '+6')
363 self.assertRaises(TypeError, tcl.exprboolean, b'8.2 + 6')
364 self.assertRaises(TclError, tcl.exprboolean, 'spam')
365 check('', False)
366 for value in ('0', 'false', 'no', 'off'):
367 check(value, False)
368 check('"%s"' % value, False)
369 check('{%s}' % value, False)
370 for value in ('1', 'true', 'yes', 'on'):
371 check(value, True)
372 check('"%s"' % value, True)
373 check('{%s}' % value, True)
374 check('8.2 + 6', True)
Serhiy Storchakafc055252014-02-03 20:41:34 +0200375 check('3.1 + $a', True)
376 check('2 + "$a.$b"', True)
377 check('4*[llength "6 2"]', True)
378 check('{word one} < "word $a"', False)
379 check('4*2 < 7', False)
380 check('hypot($a, 4)', True)
381 check('5 / 4', True)
382 check('5 / 4.0', True)
383 check('5 / ( [string length "abcd"] + 0.0 )', True)
384 check('20.0/5.0', True)
385 check('"0x03" > "2"', True)
386 check('[string length "a\xbd\u20ac"]', True)
387 check(r'[string length "a\xbd\u20ac"]', True)
388 self.assertRaises(TclError, tcl.exprboolean, '"abc"')
Serhiy Storchakaea134da2015-04-02 18:46:50 +0300389 if tcl_version >= (8, 5): # bignum was added in Tcl 8.5
Serhiy Storchaka160f8922014-02-03 22:31:09 +0200390 check('2**64', True)
Serhiy Storchakafc055252014-02-03 20:41:34 +0200391
Serhiy Storchakaa5a4bd72015-04-02 19:57:52 +0300392 @unittest.skipUnless(tcl_version >= (8, 5), 'requires Tcl version >= 8.5')
Serhiy Storchakaf7de3dd2015-04-02 10:35:57 +0300393 def test_booleans(self):
394 tcl = self.interp
395 def check(expr, expected):
396 result = tcl.call('expr', expr)
Serhiy Storchaka9171fe52015-04-02 11:46:07 +0300397 if tcl.wantobjects():
398 self.assertEqual(result, expected)
399 self.assertIsInstance(result, int)
400 else:
401 self.assertIn(result, (expr, str(int(expected))))
402 self.assertIsInstance(result, str)
Serhiy Storchakaf7de3dd2015-04-02 10:35:57 +0300403 check('true', True)
404 check('yes', True)
405 check('on', True)
406 check('false', False)
407 check('no', False)
408 check('off', False)
409 check('1 < 2', True)
410 check('1 > 2', False)
411
Serhiy Storchakaea134da2015-04-02 18:46:50 +0300412 def test_expr_bignum(self):
413 tcl = self.interp
414 for i in self.get_integers():
415 result = tcl.call('expr', str(i))
416 if self.wantobjects:
417 self.assertEqual(result, i)
418 self.assertIsInstance(result, int)
419 else:
420 self.assertEqual(result, str(i))
421 self.assertIsInstance(result, str)
422 if tcl_version < (8, 5): # bignum was added in Tcl 8.5
Serhiy Storchaka2379d542015-04-02 20:07:09 +0300423 self.assertRaises(TclError, tcl.call, 'expr', str(2**1000))
Serhiy Storchakaea134da2015-04-02 18:46:50 +0300424
Serhiy Storchakadf4bb462013-02-07 15:40:03 +0200425 def test_passing_values(self):
426 def passValue(value):
427 return self.interp.call('set', '_', value)
428
Serhiy Storchakacc4290b2013-12-25 17:29:01 +0200429 self.assertEqual(passValue(True), True if self.wantobjects else '1')
430 self.assertEqual(passValue(False), False if self.wantobjects else '0')
Serhiy Storchakadf4bb462013-02-07 15:40:03 +0200431 self.assertEqual(passValue('string'), 'string')
432 self.assertEqual(passValue('string\u20ac'), 'string\u20ac')
Serhiy Storchaka06cb94b2019-10-04 13:09:52 +0300433 self.assertEqual(passValue('string\U0001f4bb'), 'string\U0001f4bb')
Serhiy Storchaka1317e142014-02-03 21:24:07 +0200434 self.assertEqual(passValue('str\x00ing'), 'str\x00ing')
435 self.assertEqual(passValue('str\x00ing\xbd'), 'str\x00ing\xbd')
436 self.assertEqual(passValue('str\x00ing\u20ac'), 'str\x00ing\u20ac')
Serhiy Storchaka06cb94b2019-10-04 13:09:52 +0300437 self.assertEqual(passValue('str\x00ing\U0001f4bb'),
438 'str\x00ing\U0001f4bb')
Serhiy Storchaka74596a82014-07-30 18:33:13 +0300439 self.assertEqual(passValue(b'str\x00ing'),
440 b'str\x00ing' if self.wantobjects else 'str\x00ing')
441 self.assertEqual(passValue(b'str\xc0\x80ing'),
442 b'str\xc0\x80ing' if self.wantobjects else 'str\xc0\x80ing')
443 self.assertEqual(passValue(b'str\xbding'),
444 b'str\xbding' if self.wantobjects else 'str\xbding')
Serhiy Storchakaea134da2015-04-02 18:46:50 +0300445 for i in self.get_integers():
Serhiy Storchakacc4290b2013-12-25 17:29:01 +0200446 self.assertEqual(passValue(i), i if self.wantobjects else str(i))
Serhiy Storchakaea134da2015-04-02 18:46:50 +0300447 if tcl_version < (8, 5): # bignum was added in Tcl 8.5
448 self.assertEqual(passValue(2**1000), str(2**1000))
Serhiy Storchakadf4bb462013-02-07 15:40:03 +0200449 for f in (0.0, 1.0, -1.0, 1/3,
450 sys.float_info.min, sys.float_info.max,
451 -sys.float_info.min, -sys.float_info.max):
Serhiy Storchakacc4290b2013-12-25 17:29:01 +0200452 if self.wantobjects:
Serhiy Storchakadf4bb462013-02-07 15:40:03 +0200453 self.assertEqual(passValue(f), f)
Serhiy Storchakacc4290b2013-12-25 17:29:01 +0200454 else:
455 self.assertEqual(float(passValue(f)), f)
456 if self.wantobjects:
457 f = passValue(float('nan'))
458 self.assertNotEqual(f, f)
459 self.assertEqual(passValue(float('inf')), float('inf'))
460 self.assertEqual(passValue(-float('inf')), -float('inf'))
461 else:
Serhiy Storchakacc4290b2013-12-25 17:29:01 +0200462 self.assertEqual(float(passValue(float('inf'))), float('inf'))
463 self.assertEqual(float(passValue(-float('inf'))), -float('inf'))
Serhiy Storchaka6f1435c2014-07-07 14:57:08 +0300464 # XXX NaN representation can be not parsable by float()
Serhiy Storchakacc4290b2013-12-25 17:29:01 +0200465 self.assertEqual(passValue((1, '2', (3.4,))),
466 (1, '2', (3.4,)) if self.wantobjects else '1 2 3.4')
Serhiy Storchaka2b00c492014-05-21 17:12:21 +0300467 self.assertEqual(passValue(['a', ['b', 'c']]),
468 ('a', ('b', 'c')) if self.wantobjects else 'a {b c}')
Martin v. Löwis2d5157e2010-06-04 19:50:26 +0000469
Serhiy Storchaka4b730162014-01-23 09:44:05 +0200470 def test_user_command(self):
471 result = None
472 def testfunc(arg):
473 nonlocal result
474 result = arg
475 return arg
476 self.interp.createcommand('testfunc', testfunc)
Antoine Pitrou220cc212014-02-23 19:39:06 +0100477 self.addCleanup(self.interp.tk.deletecommand, 'testfunc')
Serhiy Storchakad6ec3092014-08-18 17:47:29 +0300478 def check(value, expected=None, *, eq=self.assertEqual):
479 if expected is None:
480 expected = value
481 nonlocal result
482 result = None
Serhiy Storchakabdf0cb52014-01-23 16:48:44 +0200483 r = self.interp.call('testfunc', value)
484 self.assertIsInstance(result, str)
485 eq(result, expected)
486 self.assertIsInstance(r, str)
487 eq(r, expected)
488 def float_eq(actual, expected):
Serhiy Storchakabdf0cb52014-01-23 16:48:44 +0200489 self.assertAlmostEqual(float(actual), expected,
490 delta=abs(expected) * 1e-10)
Serhiy Storchaka4b730162014-01-23 09:44:05 +0200491
492 check(True, '1')
493 check(False, '0')
Serhiy Storchakad6ec3092014-08-18 17:47:29 +0300494 check('string')
495 check('string\xbd')
496 check('string\u20ac')
Serhiy Storchaka06cb94b2019-10-04 13:09:52 +0300497 check('string\U0001f4bb')
Serhiy Storchakaabf68ce2014-09-11 10:57:13 +0300498 check('')
Serhiy Storchaka1317e142014-02-03 21:24:07 +0200499 check(b'string', 'string')
Serhiy Storchaka74596a82014-07-30 18:33:13 +0300500 check(b'string\xe2\x82\xac', 'string\xe2\x82\xac')
501 check(b'string\xbd', 'string\xbd')
Serhiy Storchakaabf68ce2014-09-11 10:57:13 +0300502 check(b'', '')
Serhiy Storchakad6ec3092014-08-18 17:47:29 +0300503 check('str\x00ing')
504 check('str\x00ing\xbd')
505 check('str\x00ing\u20ac')
Serhiy Storchaka74596a82014-07-30 18:33:13 +0300506 check(b'str\x00ing', 'str\x00ing')
507 check(b'str\xc0\x80ing', 'str\xc0\x80ing')
508 check(b'str\xc0\x80ing\xe2\x82\xac', 'str\xc0\x80ing\xe2\x82\xac')
Serhiy Storchakaea134da2015-04-02 18:46:50 +0300509 for i in self.get_integers():
Serhiy Storchaka4b730162014-01-23 09:44:05 +0200510 check(i, str(i))
Serhiy Storchakaea134da2015-04-02 18:46:50 +0300511 if tcl_version < (8, 5): # bignum was added in Tcl 8.5
512 check(2**1000, str(2**1000))
Serhiy Storchakabdf0cb52014-01-23 16:48:44 +0200513 for f in (0.0, 1.0, -1.0):
514 check(f, repr(f))
515 for f in (1/3.0, sys.float_info.min, sys.float_info.max,
Serhiy Storchaka4b730162014-01-23 09:44:05 +0200516 -sys.float_info.min, -sys.float_info.max):
Serhiy Storchakad6ec3092014-08-18 17:47:29 +0300517 check(f, eq=float_eq)
518 check(float('inf'), eq=float_eq)
519 check(-float('inf'), eq=float_eq)
Serhiy Storchaka6f1435c2014-07-07 14:57:08 +0300520 # XXX NaN representation can be not parsable by float()
Serhiy Storchaka4b730162014-01-23 09:44:05 +0200521 check((), '')
522 check((1, (2,), (3, 4), '5 6', ()), '1 2 {3 4} {5 6} {}')
Serhiy Storchaka2b00c492014-05-21 17:12:21 +0300523 check([1, [2,], [3, 4], '5 6', []], '1 2 {3 4} {5 6} {}')
Serhiy Storchaka4b730162014-01-23 09:44:05 +0200524
Serhiy Storchaka275d5fd2013-07-11 20:34:47 +0300525 def test_splitlist(self):
526 splitlist = self.interp.tk.splitlist
527 call = self.interp.tk.call
528 self.assertRaises(TypeError, splitlist)
529 self.assertRaises(TypeError, splitlist, 'a', 'b')
530 self.assertRaises(TypeError, splitlist, 2)
531 testcases = [
532 ('2', ('2',)),
533 ('', ()),
534 ('{}', ('',)),
535 ('""', ('',)),
536 ('a\n b\t\r c\n ', ('a', 'b', 'c')),
537 (b'a\n b\t\r c\n ', ('a', 'b', 'c')),
538 ('a \u20ac', ('a', '\u20ac')),
Serhiy Storchaka06cb94b2019-10-04 13:09:52 +0300539 ('a \U0001f4bb', ('a', '\U0001f4bb')),
Serhiy Storchaka275d5fd2013-07-11 20:34:47 +0300540 (b'a \xe2\x82\xac', ('a', '\u20ac')),
Serhiy Storchaka1317e142014-02-03 21:24:07 +0200541 (b'a\xc0\x80b c\xc0\x80d', ('a\x00b', 'c\x00d')),
Serhiy Storchaka275d5fd2013-07-11 20:34:47 +0300542 ('a {b c}', ('a', 'b c')),
543 (r'a b\ c', ('a', 'b c')),
544 (('a', 'b c'), ('a', 'b c')),
545 ('a 2', ('a', '2')),
546 (('a', 2), ('a', 2)),
547 ('a 3.4', ('a', '3.4')),
548 (('a', 3.4), ('a', 3.4)),
549 ((), ()),
Serhiy Storchaka2b00c492014-05-21 17:12:21 +0300550 ([], ()),
551 (['a', ['b', 'c']], ('a', ['b', 'c'])),
Serhiy Storchakacc4290b2013-12-25 17:29:01 +0200552 (call('list', 1, '2', (3.4,)),
553 (1, '2', (3.4,)) if self.wantobjects else
554 ('1', '2', '3.4')),
Serhiy Storchaka275d5fd2013-07-11 20:34:47 +0300555 ]
Victor Stinnerece38d92014-09-04 09:53:16 +0200556 tk_patchlevel = get_tk_patchlevel()
Serhiy Storchakadfa689b2013-09-08 20:29:37 +0300557 if tcl_version >= (8, 5):
Victor Stinnerece38d92014-09-04 09:53:16 +0200558 if not self.wantobjects or tk_patchlevel < (8, 5, 5):
Serhiy Storchaka92af06b2014-02-02 23:04:24 +0200559 # Before 8.5.5 dicts were converted to lists through string
Serhiy Storchaka74596a82014-07-30 18:33:13 +0300560 expected = ('12', '\u20ac', '\xe2\x82\xac', '3.4')
Serhiy Storchaka92af06b2014-02-02 23:04:24 +0200561 else:
Serhiy Storchaka74596a82014-07-30 18:33:13 +0300562 expected = (12, '\u20ac', b'\xe2\x82\xac', (3.4,))
Serhiy Storchakadfa689b2013-09-08 20:29:37 +0300563 testcases += [
Serhiy Storchaka92af06b2014-02-02 23:04:24 +0200564 (call('dict', 'create', 12, '\u20ac', b'\xe2\x82\xac', (3.4,)),
565 expected),
Serhiy Storchakadfa689b2013-09-08 20:29:37 +0300566 ]
Victor Stinnerece38d92014-09-04 09:53:16 +0200567 dbg_info = ('want objects? %s, Tcl version: %s, Tk patchlevel: %s'
568 % (self.wantobjects, tcl_version, tk_patchlevel))
Serhiy Storchaka275d5fd2013-07-11 20:34:47 +0300569 for arg, res in testcases:
Victor Stinnerece38d92014-09-04 09:53:16 +0200570 self.assertEqual(splitlist(arg), res,
571 'arg=%a, %s' % (arg, dbg_info))
Serhiy Storchaka275d5fd2013-07-11 20:34:47 +0300572 self.assertRaises(TclError, splitlist, '{')
573
574 def test_split(self):
575 split = self.interp.tk.split
576 call = self.interp.tk.call
Serhiy Storchakad05b0002019-10-08 14:31:35 +0300577 with warnings.catch_warnings():
578 warnings.filterwarnings('ignore', r'\bsplit\b.*\bsplitlist\b',
579 DeprecationWarning)
580 self.assertRaises(TypeError, split)
581 self.assertRaises(TypeError, split, 'a', 'b')
582 self.assertRaises(TypeError, split, 2)
Serhiy Storchaka275d5fd2013-07-11 20:34:47 +0300583 testcases = [
584 ('2', '2'),
585 ('', ''),
586 ('{}', ''),
587 ('""', ''),
588 ('{', '{'),
589 ('a\n b\t\r c\n ', ('a', 'b', 'c')),
590 (b'a\n b\t\r c\n ', ('a', 'b', 'c')),
591 ('a \u20ac', ('a', '\u20ac')),
592 (b'a \xe2\x82\xac', ('a', '\u20ac')),
Serhiy Storchaka1317e142014-02-03 21:24:07 +0200593 (b'a\xc0\x80b', 'a\x00b'),
594 (b'a\xc0\x80b c\xc0\x80d', ('a\x00b', 'c\x00d')),
595 (b'{a\xc0\x80b c\xc0\x80d', '{a\x00b c\x00d'),
Serhiy Storchaka275d5fd2013-07-11 20:34:47 +0300596 ('a {b c}', ('a', ('b', 'c'))),
597 (r'a b\ c', ('a', ('b', 'c'))),
598 (('a', b'b c'), ('a', ('b', 'c'))),
599 (('a', 'b c'), ('a', ('b', 'c'))),
600 ('a 2', ('a', '2')),
601 (('a', 2), ('a', 2)),
602 ('a 3.4', ('a', '3.4')),
603 (('a', 3.4), ('a', 3.4)),
604 (('a', (2, 3.4)), ('a', (2, 3.4))),
605 ((), ()),
Serhiy Storchaka2b00c492014-05-21 17:12:21 +0300606 ([], ()),
607 (['a', 'b c'], ('a', ('b', 'c'))),
608 (['a', ['b', 'c']], ('a', ('b', 'c'))),
Serhiy Storchakacc4290b2013-12-25 17:29:01 +0200609 (call('list', 1, '2', (3.4,)),
610 (1, '2', (3.4,)) if self.wantobjects else
611 ('1', '2', '3.4')),
Serhiy Storchaka275d5fd2013-07-11 20:34:47 +0300612 ]
Serhiy Storchakadfa689b2013-09-08 20:29:37 +0300613 if tcl_version >= (8, 5):
Serhiy Storchaka92af06b2014-02-02 23:04:24 +0200614 if not self.wantobjects or get_tk_patchlevel() < (8, 5, 5):
615 # Before 8.5.5 dicts were converted to lists through string
Serhiy Storchaka74596a82014-07-30 18:33:13 +0300616 expected = ('12', '\u20ac', '\xe2\x82\xac', '3.4')
Serhiy Storchaka92af06b2014-02-02 23:04:24 +0200617 else:
Serhiy Storchaka74596a82014-07-30 18:33:13 +0300618 expected = (12, '\u20ac', b'\xe2\x82\xac', (3.4,))
Serhiy Storchakadfa689b2013-09-08 20:29:37 +0300619 testcases += [
620 (call('dict', 'create', 12, '\u20ac', b'\xe2\x82\xac', (3.4,)),
Serhiy Storchaka92af06b2014-02-02 23:04:24 +0200621 expected),
Serhiy Storchakadfa689b2013-09-08 20:29:37 +0300622 ]
Serhiy Storchaka275d5fd2013-07-11 20:34:47 +0300623 for arg, res in testcases:
Serhiy Storchakad05b0002019-10-08 14:31:35 +0300624 with self.assertWarns(DeprecationWarning):
625 self.assertEqual(split(arg), res, msg=arg)
Serhiy Storchaka275d5fd2013-07-11 20:34:47 +0300626
Serhiy Storchaka8f0a1d02014-09-06 22:47:58 +0300627 def test_splitdict(self):
628 splitdict = tkinter._splitdict
629 tcl = self.interp.tk
630
631 arg = '-a {1 2 3} -something foo status {}'
632 self.assertEqual(splitdict(tcl, arg, False),
633 {'-a': '1 2 3', '-something': 'foo', 'status': ''})
634 self.assertEqual(splitdict(tcl, arg),
635 {'a': '1 2 3', 'something': 'foo', 'status': ''})
636
637 arg = ('-a', (1, 2, 3), '-something', 'foo', 'status', '{}')
638 self.assertEqual(splitdict(tcl, arg, False),
639 {'-a': (1, 2, 3), '-something': 'foo', 'status': '{}'})
640 self.assertEqual(splitdict(tcl, arg),
641 {'a': (1, 2, 3), 'something': 'foo', 'status': '{}'})
642
643 self.assertRaises(RuntimeError, splitdict, tcl, '-a b -c ')
644 self.assertRaises(RuntimeError, splitdict, tcl, ('-a', 'b', '-c'))
645
646 arg = tcl.call('list',
647 '-a', (1, 2, 3), '-something', 'foo', 'status', ())
648 self.assertEqual(splitdict(tcl, arg),
649 {'a': (1, 2, 3) if self.wantobjects else '1 2 3',
650 'something': 'foo', 'status': ''})
651
652 if tcl_version >= (8, 5):
653 arg = tcl.call('dict', 'create',
654 '-a', (1, 2, 3), '-something', 'foo', 'status', ())
655 if not self.wantobjects or get_tk_patchlevel() < (8, 5, 5):
656 # Before 8.5.5 dicts were converted to lists through string
657 expected = {'a': '1 2 3', 'something': 'foo', 'status': ''}
658 else:
659 expected = {'a': (1, 2, 3), 'something': 'foo', 'status': ''}
660 self.assertEqual(splitdict(tcl, arg), expected)
661
Serhiy Storchaka5bb5bbf2018-06-30 09:20:28 +0300662 def test_join(self):
663 join = tkinter._join
664 tcl = self.interp.tk
665 def unpack(s):
666 return tcl.call('lindex', s, 0)
667 def check(value):
668 self.assertEqual(unpack(join([value])), value)
669 self.assertEqual(unpack(join([value, 0])), value)
670 self.assertEqual(unpack(unpack(join([[value]]))), value)
671 self.assertEqual(unpack(unpack(join([[value, 0]]))), value)
672 self.assertEqual(unpack(unpack(join([[value], 0]))), value)
673 self.assertEqual(unpack(unpack(join([[value, 0], 0]))), value)
674 check('')
675 check('spam')
676 check('sp am')
677 check('sp\tam')
678 check('sp\nam')
679 check(' \t\n')
680 check('{spam}')
681 check('{sp am}')
682 check('"spam"')
683 check('"sp am"')
684 check('{"spam"}')
685 check('"{spam}"')
686 check('sp\\am')
687 check('"sp\\am"')
688 check('"{}" "{}"')
689 check('"\\')
690 check('"{')
691 check('"}')
692 check('\n\\')
693 check('\n{')
694 check('\n}')
695 check('\\\n')
696 check('{\n')
697 check('}\n')
698
Serhiy Storchakae3f1b092016-05-08 20:46:22 +0300699 def test_new_tcl_obj(self):
700 self.assertRaises(TypeError, _tkinter.Tcl_Obj)
Neal Norwitz63dfece2004-02-19 02:37:29 +0000701
Serhiy Storchaka9e6b9752013-08-21 21:38:21 +0300702class BigmemTclTest(unittest.TestCase):
703
704 def setUp(self):
705 self.interp = Tcl()
706
Serhiy Storchaka5cfc79d2014-02-07 10:06:39 +0200707 @support.cpython_only
708 @unittest.skipUnless(INT_MAX < PY_SSIZE_T_MAX, "needs UINT_MAX < SIZE_MAX")
709 @support.bigmemtest(size=INT_MAX + 1, memuse=5, dry_run=False)
Serhiy Storchaka79851d72014-05-30 14:24:03 +0300710 def test_huge_string_call(self, size):
Serhiy Storchaka9e6b9752013-08-21 21:38:21 +0300711 value = ' ' * size
Serhiy Storchaka27c623c2017-10-03 22:39:55 +0300712 self.assertRaises(OverflowError, self.interp.call, 'string', 'index', value, 0)
Serhiy Storchaka9e6b9752013-08-21 21:38:21 +0300713
Serhiy Storchaka79851d72014-05-30 14:24:03 +0300714 @support.cpython_only
715 @unittest.skipUnless(INT_MAX < PY_SSIZE_T_MAX, "needs UINT_MAX < SIZE_MAX")
Serhiy Storchaka27c623c2017-10-03 22:39:55 +0300716 @support.bigmemtest(size=INT_MAX + 1, memuse=2, dry_run=False)
Serhiy Storchaka79851d72014-05-30 14:24:03 +0300717 def test_huge_string_builtins(self, size):
Serhiy Storchaka27c623c2017-10-03 22:39:55 +0300718 tk = self.interp.tk
Serhiy Storchaka79851d72014-05-30 14:24:03 +0300719 value = '1' + ' ' * size
Serhiy Storchaka27c623c2017-10-03 22:39:55 +0300720 self.assertRaises(OverflowError, tk.getint, value)
721 self.assertRaises(OverflowError, tk.getdouble, value)
722 self.assertRaises(OverflowError, tk.getboolean, value)
723 self.assertRaises(OverflowError, tk.eval, value)
724 self.assertRaises(OverflowError, tk.evalfile, value)
725 self.assertRaises(OverflowError, tk.record, value)
726 self.assertRaises(OverflowError, tk.adderrorinfo, value)
727 self.assertRaises(OverflowError, tk.setvar, value, 'x', 'a')
728 self.assertRaises(OverflowError, tk.setvar, 'x', value, 'a')
729 self.assertRaises(OverflowError, tk.unsetvar, value)
730 self.assertRaises(OverflowError, tk.unsetvar, 'x', value)
731 self.assertRaises(OverflowError, tk.adderrorinfo, value)
732 self.assertRaises(OverflowError, tk.exprstring, value)
733 self.assertRaises(OverflowError, tk.exprlong, value)
734 self.assertRaises(OverflowError, tk.exprboolean, value)
735 self.assertRaises(OverflowError, tk.splitlist, value)
736 self.assertRaises(OverflowError, tk.split, value)
737 self.assertRaises(OverflowError, tk.createcommand, value, max)
738 self.assertRaises(OverflowError, tk.deletecommand, value)
739
740 @support.cpython_only
741 @unittest.skipUnless(INT_MAX < PY_SSIZE_T_MAX, "needs UINT_MAX < SIZE_MAX")
742 @support.bigmemtest(size=INT_MAX + 1, memuse=6, dry_run=False)
743 def test_huge_string_builtins2(self, size):
744 # These commands require larger memory for possible error messages
745 tk = self.interp.tk
746 value = '1' + ' ' * size
747 self.assertRaises(OverflowError, tk.evalfile, value)
748 self.assertRaises(OverflowError, tk.unsetvar, value)
749 self.assertRaises(OverflowError, tk.unsetvar, 'x', value)
Serhiy Storchaka79851d72014-05-30 14:24:03 +0300750
Serhiy Storchaka9e6b9752013-08-21 21:38:21 +0300751
Serhiy Storchaka8db18232013-11-20 17:43:49 +0200752def setUpModule():
753 if support.verbose:
754 tcl = Tcl()
755 print('patchlevel =', tcl.call('info', 'patchlevel'))
756
757
Neal Norwitz63dfece2004-02-19 02:37:29 +0000758def test_main():
Serhiy Storchaka9e6b9752013-08-21 21:38:21 +0300759 support.run_unittest(TclTest, TkinterTest, BigmemTclTest)
Neal Norwitz63dfece2004-02-19 02:37:29 +0000760
David Aschere2b4b322004-02-18 05:59:53 +0000761if __name__ == "__main__":
Neal Norwitz63dfece2004-02-19 02:37:29 +0000762 test_main()