|
13 | 13 | import subprocess |
14 | 14 | import sys |
15 | 15 | import tempfile |
| 16 | +import shlex |
| 17 | +import shutil |
16 | 18 | from test.support import (captured_stdout, captured_stderr, requires_zlib, |
17 | 19 | can_symlink, EnvironmentVarGuard, rmtree) |
18 | 20 | import unittest |
@@ -80,6 +82,10 @@ def get_text_file_contents(self, *args): |
80 | 82 | result = f.read() |
81 | 83 | return result |
82 | 84 |
|
| 85 | + def assertEndsWith(self, string, tail): |
| 86 | + if not string.endswith(tail): |
| 87 | + self.fail(f"String {string!r} does not end with {tail!r}") |
| 88 | + |
83 | 89 | class BasicTest(BaseTest): |
84 | 90 | """Test venv module functionality.""" |
85 | 91 |
|
@@ -293,6 +299,82 @@ def test_executable_symlinks(self): |
293 | 299 | 'import sys; print(sys.executable)']) |
294 | 300 | self.assertEqual(out.strip(), envpy.encode()) |
295 | 301 |
|
| 302 | + # gh-124651: test quoted strings |
| 303 | + @unittest.skipIf(os.name == 'nt', 'contains invalid characters on Windows') |
| 304 | + def test_special_chars_bash(self): |
| 305 | + """ |
| 306 | + Test that the template strings are quoted properly (bash) |
| 307 | + """ |
| 308 | + rmtree(self.env_dir) |
| 309 | + bash = shutil.which('bash') |
| 310 | + if bash is None: |
| 311 | + self.skipTest('bash required for this test') |
| 312 | + env_name = '"\';&&$e|\'"' |
| 313 | + env_dir = os.path.join(os.path.realpath(self.env_dir), env_name) |
| 314 | + builder = venv.EnvBuilder(clear=True) |
| 315 | + builder.create(env_dir) |
| 316 | + activate = os.path.join(env_dir, self.bindir, 'activate') |
| 317 | + test_script = os.path.join(self.env_dir, 'test_special_chars.sh') |
| 318 | + with open(test_script, "w") as f: |
| 319 | + f.write(f'source {shlex.quote(activate)}\n' |
| 320 | + 'python -c \'import sys; print(sys.executable)\'\n' |
| 321 | + 'python -c \'import os; print(os.environ["VIRTUAL_ENV"])\'\n' |
| 322 | + 'deactivate\n') |
| 323 | + out, err = check_output([bash, test_script]) |
| 324 | + lines = out.splitlines() |
| 325 | + self.assertTrue(env_name.encode() in lines[0]) |
| 326 | + self.assertEndsWith(lines[1], env_name.encode()) |
| 327 | + |
| 328 | + # gh-124651: test quoted strings |
| 329 | + @unittest.skipIf(os.name == 'nt', 'contains invalid characters on Windows') |
| 330 | + def test_special_chars_csh(self): |
| 331 | + """ |
| 332 | + Test that the template strings are quoted properly (csh) |
| 333 | + """ |
| 334 | + rmtree(self.env_dir) |
| 335 | + csh = shutil.which('tcsh') or shutil.which('csh') |
| 336 | + if csh is None: |
| 337 | + self.skipTest('csh required for this test') |
| 338 | + env_name = '"\';&&$e|\'"' |
| 339 | + env_dir = os.path.join(os.path.realpath(self.env_dir), env_name) |
| 340 | + builder = venv.EnvBuilder(clear=True) |
| 341 | + builder.create(env_dir) |
| 342 | + activate = os.path.join(env_dir, self.bindir, 'activate.csh') |
| 343 | + test_script = os.path.join(self.env_dir, 'test_special_chars.csh') |
| 344 | + with open(test_script, "w") as f: |
| 345 | + f.write(f'source {shlex.quote(activate)}\n' |
| 346 | + 'python -c \'import sys; print(sys.executable)\'\n' |
| 347 | + 'python -c \'import os; print(os.environ["VIRTUAL_ENV"])\'\n' |
| 348 | + 'deactivate\n') |
| 349 | + out, err = check_output([csh, test_script]) |
| 350 | + lines = out.splitlines() |
| 351 | + self.assertTrue(env_name.encode() in lines[0]) |
| 352 | + self.assertEndsWith(lines[1], env_name.encode()) |
| 353 | + |
| 354 | + # gh-124651: test quoted strings on Windows |
| 355 | + @unittest.skipUnless(os.name == 'nt', 'only relevant on Windows') |
| 356 | + def test_special_chars_windows(self): |
| 357 | + """ |
| 358 | + Test that the template strings are quoted properly on Windows |
| 359 | + """ |
| 360 | + rmtree(self.env_dir) |
| 361 | + env_name = "'&&^$e" |
| 362 | + env_dir = os.path.join(os.path.realpath(self.env_dir), env_name) |
| 363 | + builder = venv.EnvBuilder(clear=True) |
| 364 | + builder.create(env_dir) |
| 365 | + activate = os.path.join(env_dir, self.bindir, 'activate.bat') |
| 366 | + test_batch = os.path.join(self.env_dir, 'test_special_chars.bat') |
| 367 | + with open(test_batch, "w") as f: |
| 368 | + f.write('@echo off\n' |
| 369 | + f'"{activate}" & ' |
| 370 | + f'{self.exe} -c "import sys; print(sys.executable)" & ' |
| 371 | + f'{self.exe} -c "import os; print(os.environ[\'VIRTUAL_ENV\'])" & ' |
| 372 | + 'deactivate') |
| 373 | + out, err = check_output([test_batch]) |
| 374 | + lines = out.splitlines() |
| 375 | + self.assertTrue(env_name.encode() in lines[0]) |
| 376 | + self.assertEndsWith(lines[1], env_name.encode()) |
| 377 | + |
296 | 378 | @unittest.skipUnless(os.name == 'nt', 'only relevant on Windows') |
297 | 379 | def test_unicode_in_batch_file(self): |
298 | 380 | """ |
|
0 commit comments