forked from python/cpython
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
pythongh-117968: Add tests for the part of the PyRun family of the C …
…API (pythonGH-117982) Co-authored-by: NGRsoftlab <78017794+NGRsoftlab@users.noreply.github.com> Co-authored-by: Erlend E. Aasland <erlend.aasland@protonmail.com>
- Loading branch information
1 parent
c1d7147
commit 6078f20
Showing
7 changed files
with
235 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
import os | ||
import unittest | ||
from collections import UserDict | ||
from test.support import import_helper | ||
from test.support.os_helper import unlink, TESTFN, TESTFN_UNDECODABLE | ||
|
||
NULL = None | ||
_testcapi = import_helper.import_module('_testcapi') | ||
Py_single_input = _testcapi.Py_single_input | ||
Py_file_input = _testcapi.Py_file_input | ||
Py_eval_input = _testcapi.Py_eval_input | ||
|
||
|
||
class CAPITest(unittest.TestCase): | ||
# TODO: Test the following functions: | ||
# | ||
# PyRun_SimpleStringFlags | ||
# PyRun_AnyFileExFlags | ||
# PyRun_SimpleFileExFlags | ||
# PyRun_InteractiveOneFlags | ||
# PyRun_InteractiveOneObject | ||
# PyRun_InteractiveLoopFlags | ||
# PyRun_String (may be a macro) | ||
# PyRun_AnyFile (may be a macro) | ||
# PyRun_AnyFileEx (may be a macro) | ||
# PyRun_AnyFileFlags (may be a macro) | ||
# PyRun_SimpleString (may be a macro) | ||
# PyRun_SimpleFile (may be a macro) | ||
# PyRun_SimpleFileEx (may be a macro) | ||
# PyRun_InteractiveOne (may be a macro) | ||
# PyRun_InteractiveLoop (may be a macro) | ||
# PyRun_File (may be a macro) | ||
# PyRun_FileEx (may be a macro) | ||
# PyRun_FileFlags (may be a macro) | ||
|
||
def test_run_stringflags(self): | ||
# Test PyRun_StringFlags(). | ||
def run(s, *args): | ||
return _testcapi.run_stringflags(s, Py_file_input, *args) | ||
source = b'a\n' | ||
|
||
self.assertIsNone(run(b'a\n', dict(a=1))) | ||
self.assertIsNone(run(b'a\n', dict(a=1), {})) | ||
self.assertIsNone(run(b'a\n', {}, dict(a=1))) | ||
self.assertIsNone(run(b'a\n', {}, UserDict(a=1))) | ||
|
||
self.assertRaises(NameError, run, b'a\n', {}) | ||
self.assertRaises(NameError, run, b'a\n', {}, {}) | ||
self.assertRaises(TypeError, run, b'a\n', dict(a=1), []) | ||
self.assertRaises(TypeError, run, b'a\n', dict(a=1), 1) | ||
|
||
self.assertIsNone(run(b'\xc3\xa4\n', {'\xe4': 1})) | ||
self.assertRaises(SyntaxError, run, b'\xe4\n', {}) | ||
|
||
# CRASHES run(b'a\n', NULL) | ||
# CRASHES run(b'a\n', NULL, {}) | ||
# CRASHES run(b'a\n', NULL, dict(a=1)) | ||
# CRASHES run(b'a\n', UserDict()) | ||
# CRASHES run(b'a\n', UserDict(), {}) | ||
# CRASHES run(b'a\n', UserDict(), dict(a=1)) | ||
|
||
# CRASHES run(NULL, {}) | ||
|
||
def test_run_fileexflags(self): | ||
# Test PyRun_FileExFlags(). | ||
filename = os.fsencode(TESTFN) | ||
with open(filename, 'wb') as fp: | ||
fp.write(b'a\n') | ||
self.addCleanup(unlink, filename) | ||
def run(*args): | ||
return _testcapi.run_fileexflags(filename, Py_file_input, *args) | ||
|
||
self.assertIsNone(run(dict(a=1))) | ||
self.assertIsNone(run(dict(a=1), {})) | ||
self.assertIsNone(run({}, dict(a=1))) | ||
self.assertIsNone(run({}, UserDict(a=1))) | ||
self.assertIsNone(run(dict(a=1), {}, 1)) # closeit = True | ||
|
||
self.assertRaises(NameError, run, {}) | ||
self.assertRaises(NameError, run, {}, {}) | ||
self.assertRaises(TypeError, run, dict(a=1), []) | ||
self.assertRaises(TypeError, run, dict(a=1), 1) | ||
|
||
# CRASHES run(NULL) | ||
# CRASHES run(NULL, {}) | ||
# CRASHES run(NULL, dict(a=1)) | ||
# CRASHES run(UserDict()) | ||
# CRASHES run(UserDict(), {}) | ||
# CRASHES run(UserDict(), dict(a=1)) | ||
|
||
@unittest.skipUnless(TESTFN_UNDECODABLE, 'only works if there are undecodable paths') | ||
def test_run_fileexflags_with_undecodable_filename(self): | ||
run = _testcapi.run_fileexflags | ||
try: | ||
with open(TESTFN_UNDECODABLE, 'wb') as fp: | ||
fp.write(b'a\n') | ||
self.addCleanup(unlink, TESTFN_UNDECODABLE) | ||
except OSError: | ||
self.skipTest('undecodable paths are not supported') | ||
self.assertIsNone(run(TESTFN_UNDECODABLE, Py_file_input, dict(a=1))) | ||
|
||
|
||
if __name__ == '__main__': | ||
unittest.main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
#include "parts.h" | ||
#include "util.h" | ||
|
||
#include <stdio.h> | ||
#include <errno.h> | ||
|
||
|
||
static PyObject * | ||
run_stringflags(PyObject *mod, PyObject *pos_args) | ||
{ | ||
const char *str; | ||
Py_ssize_t size; | ||
int start; | ||
PyObject *globals = NULL; | ||
PyObject *locals = NULL; | ||
PyCompilerFlags flags = _PyCompilerFlags_INIT; | ||
PyCompilerFlags *pflags = NULL; | ||
int cf_flags = 0; | ||
int cf_feature_version = 0; | ||
|
||
if (!PyArg_ParseTuple(pos_args, "z#iO|Oii", | ||
&str, &size, &start, &globals, &locals, | ||
&cf_flags, &cf_feature_version)) { | ||
return NULL; | ||
} | ||
|
||
NULLABLE(globals); | ||
NULLABLE(locals); | ||
if (cf_flags || cf_feature_version) { | ||
flags.cf_flags = cf_flags; | ||
flags.cf_feature_version = cf_feature_version; | ||
pflags = &flags; | ||
} | ||
|
||
return PyRun_StringFlags(str, start, globals, locals, pflags); | ||
} | ||
|
||
static PyObject * | ||
run_fileexflags(PyObject *mod, PyObject *pos_args) | ||
{ | ||
PyObject *result = NULL; | ||
const char *filename = NULL; | ||
Py_ssize_t filename_size; | ||
int start; | ||
PyObject *globals = NULL; | ||
PyObject *locals = NULL; | ||
int closeit = 0; | ||
PyCompilerFlags flags = _PyCompilerFlags_INIT; | ||
PyCompilerFlags *pflags = NULL; | ||
int cf_flags = 0; | ||
int cf_feature_version = 0; | ||
|
||
FILE *fp = NULL; | ||
|
||
if (!PyArg_ParseTuple(pos_args, "z#iO|Oiii", | ||
&filename, &filename_size, &start, &globals, &locals, | ||
&closeit, &cf_flags, &cf_feature_version)) { | ||
return NULL; | ||
} | ||
|
||
NULLABLE(globals); | ||
NULLABLE(locals); | ||
if (cf_flags || cf_feature_version) { | ||
flags.cf_flags = cf_flags; | ||
flags.cf_feature_version = cf_feature_version; | ||
pflags = &flags; | ||
} | ||
|
||
fp = fopen(filename, "r"); | ||
if (fp == NULL) { | ||
PyErr_SetFromErrnoWithFilename(PyExc_OSError, filename); | ||
return NULL; | ||
} | ||
|
||
result = PyRun_FileExFlags(fp, filename, start, globals, locals, closeit, pflags); | ||
|
||
#if !defined(__wasi__) | ||
/* The behavior of fileno() after fclose() is undefined. */ | ||
if (closeit && result && fileno(fp) >= 0) { | ||
PyErr_SetString(PyExc_AssertionError, "File was not closed after excution"); | ||
Py_DECREF(result); | ||
fclose(fp); | ||
return NULL; | ||
} | ||
#endif | ||
if (!closeit && fileno(fp) < 0) { | ||
PyErr_SetString(PyExc_AssertionError, "Bad file descriptor after excution"); | ||
Py_XDECREF(result); | ||
return NULL; | ||
} | ||
|
||
if (!closeit) { | ||
fclose(fp); /* don't need open file any more*/ | ||
} | ||
|
||
return result; | ||
} | ||
|
||
static PyMethodDef test_methods[] = { | ||
{"run_stringflags", run_stringflags, METH_VARARGS}, | ||
{"run_fileexflags", run_fileexflags, METH_VARARGS}, | ||
{NULL}, | ||
}; | ||
|
||
int | ||
_PyTestCapi_Init_Run(PyObject *mod) | ||
{ | ||
if (PyModule_AddFunctions(mod, test_methods) < 0) { | ||
return -1; | ||
} | ||
return 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters