mirror of https://github.com/python/cpython
Better Python spawning primitives in test.script_helper, for
easier writing of unit tests and better error reporting.
This commit is contained in:
parent
0ee4c9f274
commit
f51d8d3a2e
|
@ -15,12 +15,27 @@ from imp import source_from_cache
|
||||||
from test.support import make_legacy_pyc
|
from test.support import make_legacy_pyc
|
||||||
|
|
||||||
# Executing the interpreter in a subprocess
|
# Executing the interpreter in a subprocess
|
||||||
def python_exit_code(*args):
|
def _assert_python(expected_success, *args):
|
||||||
cmd_line = [sys.executable, '-E']
|
cmd_line = [sys.executable, '-E']
|
||||||
cmd_line.extend(args)
|
cmd_line.extend(args)
|
||||||
with open(os.devnull, 'w') as devnull:
|
p = subprocess.Popen(cmd_line, stdin=subprocess.PIPE,
|
||||||
return subprocess.call(cmd_line, stdout=devnull,
|
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
stderr=subprocess.STDOUT)
|
try:
|
||||||
|
out, err = p.communicate()
|
||||||
|
finally:
|
||||||
|
subprocess._cleanup()
|
||||||
|
rc = p.returncode
|
||||||
|
if (rc and expected_success) or (not rc and not expected_success):
|
||||||
|
raise AssertionError(
|
||||||
|
"Process return code is %d, "
|
||||||
|
"stderr follows:\n%s" % (rc, err.decode('ascii', 'ignore')))
|
||||||
|
return rc, out, err
|
||||||
|
|
||||||
|
def assert_python_ok(*args):
|
||||||
|
return _assert_python(True, *args)
|
||||||
|
|
||||||
|
def assert_python_failure(*args):
|
||||||
|
return _assert_python(False, *args)
|
||||||
|
|
||||||
def spawn_python(*args):
|
def spawn_python(*args):
|
||||||
cmd_line = [sys.executable, '-E']
|
cmd_line = [sys.executable, '-E']
|
||||||
|
@ -38,14 +53,6 @@ def kill_python(p):
|
||||||
subprocess._cleanup()
|
subprocess._cleanup()
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def run_python(*args):
|
|
||||||
if __debug__:
|
|
||||||
p = spawn_python(*args)
|
|
||||||
else:
|
|
||||||
p = spawn_python('-O', *args)
|
|
||||||
stdout_data = kill_python(p)
|
|
||||||
return p.wait(), stdout_data
|
|
||||||
|
|
||||||
# Script creation utilities
|
# Script creation utilities
|
||||||
@contextlib.contextmanager
|
@contextlib.contextmanager
|
||||||
def temp_dir():
|
def temp_dir():
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
import test.support, unittest
|
import test.support, unittest
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
from test.script_helper import spawn_python, kill_python, python_exit_code
|
from test.script_helper import spawn_python, kill_python, assert_python_ok, assert_python_failure
|
||||||
|
|
||||||
# spawn_python normally enforces use of -E to avoid environmental effects
|
# spawn_python normally enforces use of -E to avoid environmental effects
|
||||||
# but one test checks PYTHONPATH behaviour explicitly
|
# but one test checks PYTHONPATH behaviour explicitly
|
||||||
|
@ -26,25 +26,15 @@ def _kill_python_and_exit_code(p):
|
||||||
return data, returncode
|
return data, returncode
|
||||||
|
|
||||||
class CmdLineTest(unittest.TestCase):
|
class CmdLineTest(unittest.TestCase):
|
||||||
def start_python(self, *args):
|
|
||||||
p = spawn_python(*args)
|
|
||||||
return kill_python(p)
|
|
||||||
|
|
||||||
def start_python_and_exit_code(self, *args):
|
|
||||||
p = spawn_python(*args)
|
|
||||||
return _kill_python_and_exit_code(p)
|
|
||||||
|
|
||||||
def exit_code(self, *args):
|
|
||||||
return python_exit_code(*args)
|
|
||||||
|
|
||||||
def test_directories(self):
|
def test_directories(self):
|
||||||
self.assertNotEqual(self.exit_code('.'), 0)
|
assert_python_failure('.')
|
||||||
self.assertNotEqual(self.exit_code('< .'), 0)
|
assert_python_failure('< .')
|
||||||
|
|
||||||
def verify_valid_flag(self, cmd_line):
|
def verify_valid_flag(self, cmd_line):
|
||||||
data = self.start_python(cmd_line)
|
rc, out, err = assert_python_ok(*cmd_line)
|
||||||
self.assertTrue(data == b'' or data.endswith(b'\n'))
|
self.assertTrue(out == b'' or out.endswith(b'\n'))
|
||||||
self.assertNotIn(b'Traceback', data)
|
self.assertNotIn(b'Traceback', out)
|
||||||
|
self.assertNotIn(b'Traceback', err)
|
||||||
|
|
||||||
def test_optimize(self):
|
def test_optimize(self):
|
||||||
self.verify_valid_flag('-O')
|
self.verify_valid_flag('-O')
|
||||||
|
@ -60,40 +50,34 @@ class CmdLineTest(unittest.TestCase):
|
||||||
self.verify_valid_flag('-S')
|
self.verify_valid_flag('-S')
|
||||||
|
|
||||||
def test_usage(self):
|
def test_usage(self):
|
||||||
self.assertIn(b'usage', self.start_python('-h'))
|
rc, out, err = assert_python_ok('-h')
|
||||||
|
self.assertIn(b'usage', out)
|
||||||
|
|
||||||
def test_version(self):
|
def test_version(self):
|
||||||
version = ('Python %d.%d' % sys.version_info[:2]).encode("ascii")
|
version = ('Python %d.%d' % sys.version_info[:2]).encode("ascii")
|
||||||
self.assertTrue(self.start_python('-V').startswith(version))
|
rc, out, err = assert_python_ok('-V')
|
||||||
|
self.assertTrue(err.startswith(version))
|
||||||
|
|
||||||
def test_verbose(self):
|
def test_verbose(self):
|
||||||
# -v causes imports to write to stderr. If the write to
|
# -v causes imports to write to stderr. If the write to
|
||||||
# stderr itself causes an import to happen (for the output
|
# stderr itself causes an import to happen (for the output
|
||||||
# codec), a recursion loop can occur.
|
# codec), a recursion loop can occur.
|
||||||
data, rc = self.start_python_and_exit_code('-v')
|
rc, out, err = assert_python_ok('-v')
|
||||||
self.assertEqual(rc, 0)
|
self.assertNotIn(b'stack overflow', err)
|
||||||
self.assertNotIn(b'stack overflow', data)
|
rc, out, err = assert_python_ok('-vv')
|
||||||
data, rc = self.start_python_and_exit_code('-vv')
|
self.assertNotIn(b'stack overflow', err)
|
||||||
self.assertEqual(rc, 0)
|
|
||||||
self.assertNotIn(b'stack overflow', data)
|
|
||||||
|
|
||||||
def test_run_module(self):
|
def test_run_module(self):
|
||||||
# Test expected operation of the '-m' switch
|
# Test expected operation of the '-m' switch
|
||||||
# Switch needs an argument
|
# Switch needs an argument
|
||||||
self.assertNotEqual(self.exit_code('-m'), 0)
|
assert_python_failure('-m')
|
||||||
# Check we get an error for a nonexistent module
|
# Check we get an error for a nonexistent module
|
||||||
self.assertNotEqual(
|
assert_python_failure('-m', 'fnord43520xyz')
|
||||||
self.exit_code('-m', 'fnord43520xyz'),
|
|
||||||
0)
|
|
||||||
# Check the runpy module also gives an error for
|
# Check the runpy module also gives an error for
|
||||||
# a nonexistent module
|
# a nonexistent module
|
||||||
self.assertNotEqual(
|
assert_python_failure('-m', 'runpy', 'fnord43520xyz'),
|
||||||
self.exit_code('-m', 'runpy', 'fnord43520xyz'),
|
|
||||||
0)
|
|
||||||
# All good if module is located and run successfully
|
# All good if module is located and run successfully
|
||||||
self.assertEqual(
|
assert_python_ok('-m', 'timeit', '-n', '1'),
|
||||||
self.exit_code('-m', 'timeit', '-n', '1'),
|
|
||||||
0)
|
|
||||||
|
|
||||||
def test_run_module_bug1764407(self):
|
def test_run_module_bug1764407(self):
|
||||||
# -m and -i need to play well together
|
# -m and -i need to play well together
|
||||||
|
@ -109,22 +93,16 @@ class CmdLineTest(unittest.TestCase):
|
||||||
def test_run_code(self):
|
def test_run_code(self):
|
||||||
# Test expected operation of the '-c' switch
|
# Test expected operation of the '-c' switch
|
||||||
# Switch needs an argument
|
# Switch needs an argument
|
||||||
self.assertNotEqual(self.exit_code('-c'), 0)
|
assert_python_failure('-c')
|
||||||
# Check we get an error for an uncaught exception
|
# Check we get an error for an uncaught exception
|
||||||
self.assertNotEqual(
|
assert_python_failure('-c', 'raise Exception')
|
||||||
self.exit_code('-c', 'raise Exception'),
|
|
||||||
0)
|
|
||||||
# All good if execution is successful
|
# All good if execution is successful
|
||||||
self.assertEqual(
|
assert_python_ok('-c', 'pass')
|
||||||
self.exit_code('-c', 'pass'),
|
|
||||||
0)
|
|
||||||
|
|
||||||
# Test handling of non-ascii data
|
# Test handling of non-ascii data
|
||||||
if sys.getfilesystemencoding() != 'ascii':
|
if sys.getfilesystemencoding() != 'ascii':
|
||||||
command = "assert(ord('\xe9') == 0xe9)"
|
command = "assert(ord('\xe9') == 0xe9)"
|
||||||
self.assertEqual(
|
assert_python_ok('-c', command)
|
||||||
self.exit_code('-c', command),
|
|
||||||
0)
|
|
||||||
|
|
||||||
def test_unbuffered_output(self):
|
def test_unbuffered_output(self):
|
||||||
# Test expected operation of the '-u' switch
|
# Test expected operation of the '-u' switch
|
||||||
|
@ -132,14 +110,14 @@ class CmdLineTest(unittest.TestCase):
|
||||||
# Binary is unbuffered
|
# Binary is unbuffered
|
||||||
code = ("import os, sys; sys.%s.buffer.write(b'x'); os._exit(0)"
|
code = ("import os, sys; sys.%s.buffer.write(b'x'); os._exit(0)"
|
||||||
% stream)
|
% stream)
|
||||||
data, rc = self.start_python_and_exit_code('-u', '-c', code)
|
rc, out, err = assert_python_ok('-u', '-c', code)
|
||||||
self.assertEqual(rc, 0)
|
data = err if stream == 'stderr' else out
|
||||||
self.assertEqual(data, b'x', "binary %s not unbuffered" % stream)
|
self.assertEqual(data, b'x', "binary %s not unbuffered" % stream)
|
||||||
# Text is line-buffered
|
# Text is line-buffered
|
||||||
code = ("import os, sys; sys.%s.write('x\\n'); os._exit(0)"
|
code = ("import os, sys; sys.%s.write('x\\n'); os._exit(0)"
|
||||||
% stream)
|
% stream)
|
||||||
data, rc = self.start_python_and_exit_code('-u', '-c', code)
|
rc, out, err = assert_python_ok('-u', '-c', code)
|
||||||
self.assertEqual(rc, 0)
|
data = err if stream == 'stderr' else out
|
||||||
self.assertEqual(data.strip(), b'x',
|
self.assertEqual(data.strip(), b'x',
|
||||||
"text %s not line-buffered" % stream)
|
"text %s not line-buffered" % stream)
|
||||||
|
|
||||||
|
|
|
@ -7,8 +7,8 @@ import py_compile
|
||||||
|
|
||||||
from test import support
|
from test import support
|
||||||
from test.script_helper import (
|
from test.script_helper import (
|
||||||
make_pkg, make_script, make_zip_pkg, make_zip_script, run_python,
|
make_pkg, make_script, make_zip_pkg, make_zip_script,
|
||||||
temp_dir)
|
assert_python_ok, assert_python_failure, temp_dir)
|
||||||
|
|
||||||
verbose = support.verbose
|
verbose = support.verbose
|
||||||
|
|
||||||
|
@ -98,19 +98,19 @@ class CmdLineTest(unittest.TestCase):
|
||||||
expected_package,
|
expected_package,
|
||||||
*cmd_line_switches):
|
*cmd_line_switches):
|
||||||
run_args = cmd_line_switches + (script_name,)
|
run_args = cmd_line_switches + (script_name,)
|
||||||
exit_code, data = run_python(*run_args)
|
rc, out, err = assert_python_ok(*run_args)
|
||||||
self._check_output(script_name, exit_code, data, expected_file,
|
self._check_output(script_name, rc, out + err, expected_file,
|
||||||
expected_argv0, expected_path0, expected_package)
|
expected_argv0, expected_path0, expected_package)
|
||||||
|
|
||||||
def _check_import_error(self, script_name, expected_msg,
|
def _check_import_error(self, script_name, expected_msg,
|
||||||
*cmd_line_switches):
|
*cmd_line_switches):
|
||||||
run_args = cmd_line_switches + (script_name,)
|
run_args = cmd_line_switches + (script_name,)
|
||||||
exit_code, data = run_python(*run_args)
|
rc, out, err = assert_python_failure(*run_args)
|
||||||
if verbose > 1:
|
if verbose > 1:
|
||||||
print('Output from test script %r:' % script_name)
|
print('Output from test script %r:' % script_name)
|
||||||
print(data)
|
print(err)
|
||||||
print('Expected output: %r' % expected_msg)
|
print('Expected output: %r' % expected_msg)
|
||||||
self.assertIn(expected_msg.encode('utf-8'), data)
|
self.assertIn(expected_msg.encode('utf-8'), err)
|
||||||
|
|
||||||
def test_basic_script(self):
|
def test_basic_script(self):
|
||||||
with temp_dir() as script_dir:
|
with temp_dir() as script_dir:
|
||||||
|
@ -237,13 +237,12 @@ class CmdLineTest(unittest.TestCase):
|
||||||
pkg_dir = os.path.join(script_dir, 'test_pkg')
|
pkg_dir = os.path.join(script_dir, 'test_pkg')
|
||||||
make_pkg(pkg_dir, "import sys; print('init_argv0==%r' % sys.argv[0])")
|
make_pkg(pkg_dir, "import sys; print('init_argv0==%r' % sys.argv[0])")
|
||||||
script_name = _make_test_script(pkg_dir, 'script')
|
script_name = _make_test_script(pkg_dir, 'script')
|
||||||
exit_code, data = run_python('-m', 'test_pkg.script')
|
rc, out, err = assert_python_ok('-m', 'test_pkg.script')
|
||||||
if verbose > 1:
|
if verbose > 1:
|
||||||
print(data)
|
print(data)
|
||||||
self.assertEqual(exit_code, 0)
|
|
||||||
expected = "init_argv0==%r" % '-m'
|
expected = "init_argv0==%r" % '-m'
|
||||||
self.assertIn(expected.encode('utf-8'), data)
|
self.assertIn(expected.encode('utf-8'), out)
|
||||||
self._check_output(script_name, exit_code, data,
|
self._check_output(script_name, rc, out,
|
||||||
script_name, script_name, '', 'test_pkg')
|
script_name, script_name, '', 'test_pkg')
|
||||||
|
|
||||||
def test_issue8202_dash_c_file_ignored(self):
|
def test_issue8202_dash_c_file_ignored(self):
|
||||||
|
@ -253,13 +252,12 @@ class CmdLineTest(unittest.TestCase):
|
||||||
with support.temp_cwd(path=script_dir):
|
with support.temp_cwd(path=script_dir):
|
||||||
with open("-c", "w") as f:
|
with open("-c", "w") as f:
|
||||||
f.write("data")
|
f.write("data")
|
||||||
exit_code, data = run_python('-c',
|
rc, out, err = assert_python_ok('-c',
|
||||||
'import sys; print("sys.path[0]==%r" % sys.path[0])')
|
'import sys; print("sys.path[0]==%r" % sys.path[0])')
|
||||||
if verbose > 1:
|
if verbose > 1:
|
||||||
print(data)
|
print(out)
|
||||||
self.assertEqual(exit_code, 0)
|
|
||||||
expected = "sys.path[0]==%r" % ''
|
expected = "sys.path[0]==%r" % ''
|
||||||
self.assertIn(expected.encode('utf-8'), data)
|
self.assertIn(expected.encode('utf-8'), out)
|
||||||
|
|
||||||
def test_issue8202_dash_m_file_ignored(self):
|
def test_issue8202_dash_m_file_ignored(self):
|
||||||
# Make sure a "-m" file in the current directory
|
# Make sure a "-m" file in the current directory
|
||||||
|
@ -269,8 +267,8 @@ class CmdLineTest(unittest.TestCase):
|
||||||
with support.temp_cwd(path=script_dir):
|
with support.temp_cwd(path=script_dir):
|
||||||
with open("-m", "w") as f:
|
with open("-m", "w") as f:
|
||||||
f.write("data")
|
f.write("data")
|
||||||
exit_code, data = run_python('-m', 'other')
|
rc, out, err = assert_python_ok('-m', 'other')
|
||||||
self._check_output(script_name, exit_code, data,
|
self._check_output(script_name, rc, out,
|
||||||
script_name, script_name, '', '')
|
script_name, script_name, '', '')
|
||||||
|
|
||||||
def test_main():
|
def test_main():
|
||||||
|
|
|
@ -13,7 +13,7 @@ import doctest
|
||||||
import inspect
|
import inspect
|
||||||
import linecache
|
import linecache
|
||||||
import pdb
|
import pdb
|
||||||
from test.script_helper import (spawn_python, kill_python, run_python,
|
from test.script_helper import (spawn_python, kill_python, assert_python_ok,
|
||||||
temp_dir, make_script, make_zip_script)
|
temp_dir, make_script, make_zip_script)
|
||||||
|
|
||||||
verbose = test.support.verbose
|
verbose = test.support.verbose
|
||||||
|
@ -177,22 +177,22 @@ class ZipSupportTests(ImportHooksBaseTestCase):
|
||||||
pattern = 'File "%s", line 2, in %s'
|
pattern = 'File "%s", line 2, in %s'
|
||||||
with temp_dir() as d:
|
with temp_dir() as d:
|
||||||
script_name = make_script(d, 'script', test_src)
|
script_name = make_script(d, 'script', test_src)
|
||||||
exit_code, data = run_python(script_name)
|
rc, out, err = assert_python_ok(script_name)
|
||||||
expected = pattern % (script_name, "__main__.Test")
|
expected = pattern % (script_name, "__main__.Test")
|
||||||
if verbose:
|
if verbose:
|
||||||
print ("Expected line", expected)
|
print ("Expected line", expected)
|
||||||
print ("Got stdout:")
|
print ("Got stdout:")
|
||||||
print (data)
|
print (out)
|
||||||
self.assertIn(expected.encode('utf-8'), data)
|
self.assertIn(expected.encode('utf-8'), out)
|
||||||
zip_name, run_name = make_zip_script(d, "test_zip",
|
zip_name, run_name = make_zip_script(d, "test_zip",
|
||||||
script_name, '__main__.py')
|
script_name, '__main__.py')
|
||||||
exit_code, data = run_python(zip_name)
|
rc, out, err = assert_python_ok(zip_name)
|
||||||
expected = pattern % (run_name, "__main__.Test")
|
expected = pattern % (run_name, "__main__.Test")
|
||||||
if verbose:
|
if verbose:
|
||||||
print ("Expected line", expected)
|
print ("Expected line", expected)
|
||||||
print ("Got stdout:")
|
print ("Got stdout:")
|
||||||
print (data)
|
print (out)
|
||||||
self.assertIn(expected.encode('utf-8'), data)
|
self.assertIn(expected.encode('utf-8'), out)
|
||||||
|
|
||||||
def test_pdb_issue4201(self):
|
def test_pdb_issue4201(self):
|
||||||
test_src = textwrap.dedent("""\
|
test_src = textwrap.dedent("""\
|
||||||
|
|
Loading…
Reference in New Issue