summaryrefslogtreecommitdiffstats
path: root/Lib
diff options
context:
space:
mode:
authorErlend E. Aasland <erlend@python.org>2023-08-04 07:48:32 (GMT)
committerGitHub <noreply@github.com>2023-08-04 07:48:32 (GMT)
commit0bd784b355edf0d1911a7830db5d41c84171e367 (patch)
tree97e91d08e86ed1ecff470861f3a4d58b52020c69 /Lib
parenta443c310ac87f214164cb1e3f8af3f799668c867 (diff)
downloadcpython-0bd784b355edf0d1911a7830db5d41c84171e367.zip
cpython-0bd784b355edf0d1911a7830db5d41c84171e367.tar.gz
cpython-0bd784b355edf0d1911a7830db5d41c84171e367.tar.bz2
gh-106368: Increase Argument Clinic test coverage (#107611)
Add tests for directives and destinations
Diffstat (limited to 'Lib')
-rw-r--r--Lib/test/test_clinic.py296
1 files changed, 296 insertions, 0 deletions
diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py
index 59669d6..562c66a 100644
--- a/Lib/test/test_clinic.py
+++ b/Lib/test/test_clinic.py
@@ -117,6 +117,7 @@ class FakeClinic:
class ClinicWholeFileTest(TestCase):
+ maxDiff = None
def expect_failure(self, raw, errmsg, *, filename=None, lineno=None):
_expect_failure(self, self.clinic.parse, raw, errmsg,
@@ -426,6 +427,230 @@ class ClinicWholeFileTest(TestCase):
"""
self.expect_failure(block, err, lineno=3)
+ def test_destination_already_got_one(self):
+ err = "Destination already exists: 'test'"
+ block = """
+ /*[clinic input]
+ destination test new buffer
+ destination test new buffer
+ [clinic start generated code]*/
+ """
+ self.expect_failure(block, err, lineno=3)
+
+ def test_destination_does_not_exist(self):
+ err = "Destination does not exist: '/dev/null'"
+ block = """
+ /*[clinic input]
+ output everything /dev/null
+ [clinic start generated code]*/
+ """
+ self.expect_failure(block, err, lineno=2)
+
+ def test_class_already_got_one(self):
+ err = "Already defined class 'C'!"
+ block = """
+ /*[clinic input]
+ class C "" ""
+ class C "" ""
+ [clinic start generated code]*/
+ """
+ self.expect_failure(block, err, lineno=3)
+
+ def test_cant_nest_module_inside_class(self):
+ err = "Can't nest a module inside a class!"
+ block = """
+ /*[clinic input]
+ class C "" ""
+ module C.m
+ [clinic start generated code]*/
+ """
+ self.expect_failure(block, err, lineno=3)
+
+ def test_dest_buffer_not_empty_at_eof(self):
+ expected_warning = ("Destination buffer 'buffer' not empty at "
+ "end of file, emptying.")
+ expected_generated = dedent("""
+ /*[clinic input]
+ output everything buffer
+ fn
+ a: object
+ /
+ [clinic start generated code]*/
+ /*[clinic end generated code: output=da39a3ee5e6b4b0d input=1c4668687f5fd002]*/
+
+ /*[clinic input]
+ dump buffer
+ [clinic start generated code]*/
+
+ PyDoc_VAR(fn__doc__);
+
+ PyDoc_STRVAR(fn__doc__,
+ "fn($module, a, /)\\n"
+ "--\\n"
+ "\\n");
+
+ #define FN_METHODDEF \\
+ {"fn", (PyCFunction)fn, METH_O, fn__doc__},
+
+ static PyObject *
+ fn(PyObject *module, PyObject *a)
+ /*[clinic end generated code: output=be6798b148ab4e53 input=524ce2e021e4eba6]*/
+ """)
+ block = dedent("""
+ /*[clinic input]
+ output everything buffer
+ fn
+ a: object
+ /
+ [clinic start generated code]*/
+ """)
+ with support.captured_stdout() as stdout:
+ generated = self.clinic.parse(block)
+ self.assertIn(expected_warning, stdout.getvalue())
+ self.assertEqual(generated, expected_generated)
+
+ def test_directive_set_misuse(self):
+ err = "unknown variable 'ets'"
+ block = """
+ /*[clinic input]
+ set ets tse
+ [clinic start generated code]*/
+ """
+ self.expect_failure(block, err, lineno=2)
+
+ def test_directive_set_prefix(self):
+ block = dedent("""
+ /*[clinic input]
+ set line_prefix '// '
+ output everything suppress
+ output docstring_prototype buffer
+ fn
+ a: object
+ /
+ [clinic start generated code]*/
+ /* We need to dump the buffer.
+ * If not, Argument Clinic will emit a warning */
+ /*[clinic input]
+ dump buffer
+ [clinic start generated code]*/
+ """)
+ generated = self.clinic.parse(block)
+ expected_docstring_prototype = "// PyDoc_VAR(fn__doc__);"
+ self.assertIn(expected_docstring_prototype, generated)
+
+ def test_directive_set_suffix(self):
+ block = dedent("""
+ /*[clinic input]
+ set line_suffix ' // test'
+ output everything suppress
+ output docstring_prototype buffer
+ fn
+ a: object
+ /
+ [clinic start generated code]*/
+ /* We need to dump the buffer.
+ * If not, Argument Clinic will emit a warning */
+ /*[clinic input]
+ dump buffer
+ [clinic start generated code]*/
+ """)
+ generated = self.clinic.parse(block)
+ expected_docstring_prototype = "PyDoc_VAR(fn__doc__); // test"
+ self.assertIn(expected_docstring_prototype, generated)
+
+ def test_directive_set_prefix_and_suffix(self):
+ block = dedent("""
+ /*[clinic input]
+ set line_prefix '{block comment start} '
+ set line_suffix ' {block comment end}'
+ output everything suppress
+ output docstring_prototype buffer
+ fn
+ a: object
+ /
+ [clinic start generated code]*/
+ /* We need to dump the buffer.
+ * If not, Argument Clinic will emit a warning */
+ /*[clinic input]
+ dump buffer
+ [clinic start generated code]*/
+ """)
+ generated = self.clinic.parse(block)
+ expected_docstring_prototype = "/* PyDoc_VAR(fn__doc__); */"
+ self.assertIn(expected_docstring_prototype, generated)
+
+ def test_directive_printout(self):
+ block = dedent("""
+ /*[clinic input]
+ output everything buffer
+ printout test
+ [clinic start generated code]*/
+ """)
+ expected = dedent("""
+ /*[clinic input]
+ output everything buffer
+ printout test
+ [clinic start generated code]*/
+ test
+ /*[clinic end generated code: output=4e1243bd22c66e76 input=898f1a32965d44ca]*/
+ """)
+ generated = self.clinic.parse(block)
+ self.assertEqual(generated, expected)
+
+ def test_directive_preserve_twice(self):
+ err = "Can't have preserve twice in one block!"
+ block = """
+ /*[clinic input]
+ preserve
+ preserve
+ [clinic start generated code]*/
+ """
+ self.expect_failure(block, err, lineno=3)
+
+ def test_directive_preserve_input(self):
+ err = "'preserve' only works for blocks that don't produce any output!"
+ block = """
+ /*[clinic input]
+ preserve
+ fn
+ a: object
+ /
+ [clinic start generated code]*/
+ """
+ self.expect_failure(block, err, lineno=6)
+
+ def test_directive_preserve_output(self):
+ err = "'preserve' only works for blocks that don't produce any output!"
+ block = dedent("""
+ /*[clinic input]
+ output everything buffer
+ preserve
+ [clinic start generated code]*/
+ // Preserve this
+ /*[clinic end generated code: output=eaa49677ae4c1f7d input=559b5db18fddae6a]*/
+ /*[clinic input]
+ dump buffer
+ [clinic start generated code]*/
+ /*[clinic end generated code: output=da39a3ee5e6b4b0d input=524ce2e021e4eba6]*/
+ """)
+ generated = self.clinic.parse(block)
+ self.assertEqual(generated, block)
+
+ def test_directive_output_invalid_command(self):
+ err = (
+ "Invalid command / destination name 'cmd', must be one of:\n"
+ " preset push pop print everything cpp_if docstring_prototype "
+ "docstring_definition methoddef_define impl_prototype "
+ "parser_prototype parser_definition cpp_endif methoddef_ifndef "
+ "impl_definition"
+ )
+ block = """
+ /*[clinic input]
+ output cmd buffer
+ [clinic start generated code]*/
+ """
+ self.expect_failure(block, err, lineno=2)
+
class ClinicGroupPermuterTest(TestCase):
def _test(self, l, m, r, output):
@@ -1496,6 +1721,16 @@ class ClinicParserTest(TestCase):
"""
self.expect_failure(block, err, lineno=3)
+ def test_duplicate_coexist(self):
+ err = "Called @coexist twice"
+ block = """
+ module m
+ @coexist
+ @coexist
+ m.fn
+ """
+ self.expect_failure(block, err, lineno=2)
+
def test_unused_param(self):
block = self.parse("""
module foo
@@ -1931,6 +2166,67 @@ class ClinicExternalTest(TestCase):
msg = "error: --srcdir must not be empty with --make"
self.assertIn(msg, err)
+ def test_file_dest(self):
+ block = dedent("""
+ /*[clinic input]
+ destination test new file {path}.h
+ output everything test
+ func
+ a: object
+ /
+ [clinic start generated code]*/
+ """)
+ expected_checksum_line = (
+ "/*[clinic end generated code: "
+ "output=da39a3ee5e6b4b0d input=b602ab8e173ac3bd]*/\n"
+ )
+ expected_output = dedent("""\
+ /*[clinic input]
+ preserve
+ [clinic start generated code]*/
+
+ #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
+ # include "pycore_gc.h" // PyGC_Head
+ # include "pycore_runtime.h" // _Py_ID()
+ #endif
+
+
+ PyDoc_VAR(func__doc__);
+
+ PyDoc_STRVAR(func__doc__,
+ "func($module, a, /)\\n"
+ "--\\n"
+ "\\n");
+
+ #define FUNC_METHODDEF \\
+ {"func", (PyCFunction)func, METH_O, func__doc__},
+
+ static PyObject *
+ func(PyObject *module, PyObject *a)
+ /*[clinic end generated code: output=56c09670e89a0d9a input=a9049054013a1b77]*/
+ """)
+ with os_helper.temp_dir() as tmp_dir:
+ in_fn = os.path.join(tmp_dir, "test.c")
+ out_fn = os.path.join(tmp_dir, "test.c.h")
+ with open(in_fn, "w", encoding="utf-8") as f:
+ f.write(block)
+ with open(out_fn, "w", encoding="utf-8") as f:
+ f.write("") # Write an empty output file!
+ # Clinic should complain about the empty output file.
+ _, err = self.expect_failure(in_fn)
+ expected_err = (f"Modified destination file {out_fn!r}, "
+ "not overwriting!")
+ self.assertIn(expected_err, err)
+ # Run clinic again, this time with the -f option.
+ out = self.expect_success("-f", in_fn)
+ # Read back the generated output.
+ with open(in_fn, encoding="utf-8") as f:
+ data = f.read()
+ expected_block = f"{block}{expected_checksum_line}"
+ self.assertEqual(data, expected_block)
+ with open(out_fn, encoding="utf-8") as f:
+ data = f.read()
+ self.assertEqual(data, expected_output)
try:
import _testclinic as ac_tester