python (3.12.0)

(root)/
lib/
python3.12/
test/
test_clinic.py
       1  # Argument Clinic
       2  # Copyright 2012-2013 by Larry Hastings.
       3  # Licensed to the PSF under a contributor agreement.
       4  
       5  from test import support, test_tools
       6  from test.support import os_helper
       7  from test.support import SHORT_TIMEOUT, requires_subprocess
       8  from test.support.os_helper import TESTFN, unlink
       9  from textwrap import dedent
      10  from unittest import TestCase
      11  import collections
      12  import inspect
      13  import os.path
      14  import subprocess
      15  import sys
      16  import unittest
      17  
      18  test_tools.skip_if_missing('clinic')
      19  with test_tools.imports_under_tool('clinic'):
      20      import clinic
      21      from clinic import DSLParser
      22  
      23  
      24  class ESC[4;38;5;81m_ParserBase(ESC[4;38;5;149mTestCase):
      25      maxDiff = None
      26  
      27      def expect_parser_failure(self, parser, _input):
      28          with support.captured_stdout() as stdout:
      29              with self.assertRaises(SystemExit):
      30                  parser(_input)
      31          return stdout.getvalue()
      32  
      33      def parse_function_should_fail(self, _input):
      34          return self.expect_parser_failure(self.parse_function, _input)
      35  
      36  
      37  class ESC[4;38;5;81mFakeConverter:
      38      def __init__(self, name, args):
      39          self.name = name
      40          self.args = args
      41  
      42  
      43  class ESC[4;38;5;81mFakeConverterFactory:
      44      def __init__(self, name):
      45          self.name = name
      46  
      47      def __call__(self, name, default, **kwargs):
      48          return FakeConverter(self.name, kwargs)
      49  
      50  
      51  class ESC[4;38;5;81mFakeConvertersDict:
      52      def __init__(self):
      53          self.used_converters = {}
      54  
      55      def get(self, name, default):
      56          return self.used_converters.setdefault(name, FakeConverterFactory(name))
      57  
      58  c = clinic.Clinic(language='C', filename = "file")
      59  
      60  class ESC[4;38;5;81mFakeClinic:
      61      def __init__(self):
      62          self.converters = FakeConvertersDict()
      63          self.legacy_converters = FakeConvertersDict()
      64          self.language = clinic.CLanguage(None)
      65          self.filename = None
      66          self.destination_buffers = {}
      67          self.block_parser = clinic.BlockParser('', self.language)
      68          self.modules = collections.OrderedDict()
      69          self.classes = collections.OrderedDict()
      70          clinic.clinic = self
      71          self.name = "FakeClinic"
      72          self.line_prefix = self.line_suffix = ''
      73          self.destinations = {}
      74          self.add_destination("block", "buffer")
      75          self.add_destination("file", "buffer")
      76          self.add_destination("suppress", "suppress")
      77          d = self.destinations.get
      78          self.field_destinations = collections.OrderedDict((
      79              ('docstring_prototype', d('suppress')),
      80              ('docstring_definition', d('block')),
      81              ('methoddef_define', d('block')),
      82              ('impl_prototype', d('block')),
      83              ('parser_prototype', d('suppress')),
      84              ('parser_definition', d('block')),
      85              ('impl_definition', d('block')),
      86          ))
      87  
      88      def get_destination(self, name):
      89          d = self.destinations.get(name)
      90          if not d:
      91              sys.exit("Destination does not exist: " + repr(name))
      92          return d
      93  
      94      def add_destination(self, name, type, *args):
      95          if name in self.destinations:
      96              sys.exit("Destination already exists: " + repr(name))
      97          self.destinations[name] = clinic.Destination(name, type, self, *args)
      98  
      99      def is_directive(self, name):
     100          return name == "module"
     101  
     102      def directive(self, name, args):
     103          self.called_directives[name] = args
     104  
     105      _module_and_class = clinic.Clinic._module_and_class
     106  
     107  
     108  class ESC[4;38;5;81mClinicWholeFileTest(ESC[4;38;5;149m_ParserBase):
     109      def setUp(self):
     110          self.clinic = clinic.Clinic(clinic.CLanguage(None), filename="test.c")
     111  
     112      def expect_failure(self, raw):
     113          _input = dedent(raw).strip()
     114          return self.expect_parser_failure(self.clinic.parse, _input)
     115  
     116      def test_eol(self):
     117          # regression test:
     118          # clinic's block parser didn't recognize
     119          # the "end line" for the block if it
     120          # didn't end in "\n" (as in, the last)
     121          # byte of the file was '/'.
     122          # so it would spit out an end line for you.
     123          # and since you really already had one,
     124          # the last line of the block got corrupted.
     125          raw = "/*[clinic]\nfoo\n[clinic]*/"
     126          cooked = self.clinic.parse(raw).splitlines()
     127          end_line = cooked[2].rstrip()
     128          # this test is redundant, it's just here explicitly to catch
     129          # the regression test so we don't forget what it looked like
     130          self.assertNotEqual(end_line, "[clinic]*/[clinic]*/")
     131          self.assertEqual(end_line, "[clinic]*/")
     132  
     133      def test_mangled_marker_line(self):
     134          raw = """
     135              /*[clinic input]
     136              [clinic start generated code]*/
     137              /*[clinic end generated code: foo]*/
     138          """
     139          msg = (
     140              'Error in file "test.c" on line 3:\n'
     141              "Mangled Argument Clinic marker line: '/*[clinic end generated code: foo]*/'\n"
     142          )
     143          out = self.expect_failure(raw)
     144          self.assertEqual(out, msg)
     145  
     146      def test_checksum_mismatch(self):
     147          raw = """
     148              /*[clinic input]
     149              [clinic start generated code]*/
     150              /*[clinic end generated code: output=0123456789abcdef input=fedcba9876543210]*/
     151          """
     152          msg = (
     153              'Error in file "test.c" on line 3:\n'
     154              'Checksum mismatch!\n'
     155              'Expected: 0123456789abcdef\n'
     156              'Computed: da39a3ee5e6b4b0d\n'
     157          )
     158          out = self.expect_failure(raw)
     159          self.assertIn(msg, out)
     160  
     161      def test_garbage_after_stop_line(self):
     162          raw = """
     163              /*[clinic input]
     164              [clinic start generated code]*/foobarfoobar!
     165          """
     166          msg = (
     167              'Error in file "test.c" on line 2:\n'
     168              "Garbage after stop line: 'foobarfoobar!'\n"
     169          )
     170          out = self.expect_failure(raw)
     171          self.assertEqual(out, msg)
     172  
     173      def test_whitespace_before_stop_line(self):
     174          raw = """
     175              /*[clinic input]
     176               [clinic start generated code]*/
     177          """
     178          msg = (
     179              'Error in file "test.c" on line 2:\n'
     180              "Whitespace is not allowed before the stop line: ' [clinic start generated code]*/'\n"
     181          )
     182          out = self.expect_failure(raw)
     183          self.assertEqual(out, msg)
     184  
     185      def test_parse_with_body_prefix(self):
     186          clang = clinic.CLanguage(None)
     187          clang.body_prefix = "//"
     188          clang.start_line = "//[{dsl_name} start]"
     189          clang.stop_line = "//[{dsl_name} stop]"
     190          cl = clinic.Clinic(clang, filename="test.c")
     191          raw = dedent("""
     192              //[clinic start]
     193              //module test
     194              //[clinic stop]
     195          """).strip()
     196          out = cl.parse(raw)
     197          expected = dedent("""
     198              //[clinic start]
     199              //module test
     200              //
     201              //[clinic stop]
     202              /*[clinic end generated code: output=da39a3ee5e6b4b0d input=65fab8adff58cf08]*/
     203          """).lstrip()  # Note, lstrip() because of the newline
     204          self.assertEqual(out, expected)
     205  
     206      def test_cpp_monitor_fail_nested_block_comment(self):
     207          raw = """
     208              /* start
     209              /* nested
     210              */
     211              */
     212          """
     213          msg = (
     214              'Error in file "test.c" on line 2:\n'
     215              'Nested block comment!\n'
     216          )
     217          out = self.expect_failure(raw)
     218          self.assertEqual(out, msg)
     219  
     220      def test_cpp_monitor_fail_invalid_format_noarg(self):
     221          raw = """
     222              #if
     223              a()
     224              #endif
     225          """
     226          msg = (
     227              'Error in file "test.c" on line 1:\n'
     228              'Invalid format for #if line: no argument!\n'
     229          )
     230          out = self.expect_failure(raw)
     231          self.assertEqual(out, msg)
     232  
     233      def test_cpp_monitor_fail_invalid_format_toomanyargs(self):
     234          raw = """
     235              #ifdef A B
     236              a()
     237              #endif
     238          """
     239          msg = (
     240              'Error in file "test.c" on line 1:\n'
     241              'Invalid format for #ifdef line: should be exactly one argument!\n'
     242          )
     243          out = self.expect_failure(raw)
     244          self.assertEqual(out, msg)
     245  
     246      def test_cpp_monitor_fail_no_matching_if(self):
     247          raw = '#else'
     248          msg = (
     249              'Error in file "test.c" on line 1:\n'
     250              '#else without matching #if / #ifdef / #ifndef!\n'
     251          )
     252          out = self.expect_failure(raw)
     253          self.assertEqual(out, msg)
     254  
     255      def test_directive_output_unknown_preset(self):
     256          out = self.expect_failure("""
     257              /*[clinic input]
     258              output preset nosuchpreset
     259              [clinic start generated code]*/
     260          """)
     261          msg = "Unknown preset 'nosuchpreset'"
     262          self.assertIn(msg, out)
     263  
     264      def test_directive_output_cant_pop(self):
     265          out = self.expect_failure("""
     266              /*[clinic input]
     267              output pop
     268              [clinic start generated code]*/
     269          """)
     270          msg = "Can't 'output pop', stack is empty"
     271          self.assertIn(msg, out)
     272  
     273      def test_directive_output_print(self):
     274          raw = dedent("""
     275              /*[clinic input]
     276              output print 'I told you once.'
     277              [clinic start generated code]*/
     278          """)
     279          out = self.clinic.parse(raw)
     280          # The generated output will differ for every run, but we can check that
     281          # it starts with the clinic block, we check that it contains all the
     282          # expected fields, and we check that it contains the checksum line.
     283          self.assertTrue(out.startswith(dedent("""
     284              /*[clinic input]
     285              output print 'I told you once.'
     286              [clinic start generated code]*/
     287          """)))
     288          fields = {
     289              "cpp_endif",
     290              "cpp_if",
     291              "docstring_definition",
     292              "docstring_prototype",
     293              "impl_definition",
     294              "impl_prototype",
     295              "methoddef_define",
     296              "methoddef_ifndef",
     297              "parser_definition",
     298              "parser_prototype",
     299          }
     300          for field in fields:
     301              with self.subTest(field=field):
     302                  self.assertIn(field, out)
     303          last_line = out.rstrip().split("\n")[-1]
     304          self.assertTrue(
     305              last_line.startswith("/*[clinic end generated code: output=")
     306          )
     307  
     308      def test_unknown_destination_command(self):
     309          out = self.expect_failure("""
     310              /*[clinic input]
     311              destination buffer nosuchcommand
     312              [clinic start generated code]*/
     313          """)
     314          msg = "unknown destination command 'nosuchcommand'"
     315          self.assertIn(msg, out)
     316  
     317      def test_no_access_to_members_in_converter_init(self):
     318          out = self.expect_failure("""
     319              /*[python input]
     320              class Custom_converter(CConverter):
     321                  converter = "some_c_function"
     322                  def converter_init(self):
     323                      self.function.noaccess
     324              [python start generated code]*/
     325              /*[clinic input]
     326              module test
     327              test.fn
     328                  a: Custom
     329              [clinic start generated code]*/
     330          """)
     331          msg = (
     332              "Stepped on a land mine, trying to access attribute 'noaccess':\n"
     333              "Don't access members of self.function inside converter_init!"
     334          )
     335          self.assertIn(msg, out)
     336  
     337  
     338  class ESC[4;38;5;81mClinicGroupPermuterTest(ESC[4;38;5;149mTestCase):
     339      def _test(self, l, m, r, output):
     340          computed = clinic.permute_optional_groups(l, m, r)
     341          self.assertEqual(output, computed)
     342  
     343      def test_range(self):
     344          self._test([['start']], ['stop'], [['step']],
     345            (
     346              ('stop',),
     347              ('start', 'stop',),
     348              ('start', 'stop', 'step',),
     349            ))
     350  
     351      def test_add_window(self):
     352          self._test([['x', 'y']], ['ch'], [['attr']],
     353            (
     354              ('ch',),
     355              ('ch', 'attr'),
     356              ('x', 'y', 'ch',),
     357              ('x', 'y', 'ch', 'attr'),
     358            ))
     359  
     360      def test_ludicrous(self):
     361          self._test([['a1', 'a2', 'a3'], ['b1', 'b2']], ['c1'], [['d1', 'd2'], ['e1', 'e2', 'e3']],
     362            (
     363            ('c1',),
     364            ('b1', 'b2', 'c1'),
     365            ('b1', 'b2', 'c1', 'd1', 'd2'),
     366            ('a1', 'a2', 'a3', 'b1', 'b2', 'c1'),
     367            ('a1', 'a2', 'a3', 'b1', 'b2', 'c1', 'd1', 'd2'),
     368            ('a1', 'a2', 'a3', 'b1', 'b2', 'c1', 'd1', 'd2', 'e1', 'e2', 'e3'),
     369            ))
     370  
     371      def test_right_only(self):
     372          self._test([], [], [['a'],['b'],['c']],
     373            (
     374            (),
     375            ('a',),
     376            ('a', 'b'),
     377            ('a', 'b', 'c')
     378            ))
     379  
     380      def test_have_left_options_but_required_is_empty(self):
     381          def fn():
     382              clinic.permute_optional_groups(['a'], [], [])
     383          self.assertRaises(ValueError, fn)
     384  
     385  
     386  class ESC[4;38;5;81mClinicLinearFormatTest(ESC[4;38;5;149mTestCase):
     387      def _test(self, input, output, **kwargs):
     388          computed = clinic.linear_format(input, **kwargs)
     389          self.assertEqual(output, computed)
     390  
     391      def test_empty_strings(self):
     392          self._test('', '')
     393  
     394      def test_solo_newline(self):
     395          self._test('\n', '\n')
     396  
     397      def test_no_substitution(self):
     398          self._test("""
     399            abc
     400          """, """
     401            abc
     402          """)
     403  
     404      def test_empty_substitution(self):
     405          self._test("""
     406            abc
     407            {name}
     408            def
     409          """, """
     410            abc
     411            def
     412          """, name='')
     413  
     414      def test_single_line_substitution(self):
     415          self._test("""
     416            abc
     417            {name}
     418            def
     419          """, """
     420            abc
     421            GARGLE
     422            def
     423          """, name='GARGLE')
     424  
     425      def test_multiline_substitution(self):
     426          self._test("""
     427            abc
     428            {name}
     429            def
     430          """, """
     431            abc
     432            bingle
     433            bungle
     434  
     435            def
     436          """, name='bingle\nbungle\n')
     437  
     438  class ESC[4;38;5;81mInertParser:
     439      def __init__(self, clinic):
     440          pass
     441  
     442      def parse(self, block):
     443          pass
     444  
     445  class ESC[4;38;5;81mCopyParser:
     446      def __init__(self, clinic):
     447          pass
     448  
     449      def parse(self, block):
     450          block.output = block.input
     451  
     452  
     453  class ESC[4;38;5;81mClinicBlockParserTest(ESC[4;38;5;149mTestCase):
     454      def _test(self, input, output):
     455          language = clinic.CLanguage(None)
     456  
     457          blocks = list(clinic.BlockParser(input, language))
     458          writer = clinic.BlockPrinter(language)
     459          for block in blocks:
     460              writer.print_block(block)
     461          output = writer.f.getvalue()
     462          assert output == input, "output != input!\n\noutput " + repr(output) + "\n\n input " + repr(input)
     463  
     464      def round_trip(self, input):
     465          return self._test(input, input)
     466  
     467      def test_round_trip_1(self):
     468          self.round_trip("""
     469              verbatim text here
     470              lah dee dah
     471          """)
     472      def test_round_trip_2(self):
     473          self.round_trip("""
     474      verbatim text here
     475      lah dee dah
     476  /*[inert]
     477  abc
     478  [inert]*/
     479  def
     480  /*[inert checksum: 7b18d017f89f61cf17d47f92749ea6930a3f1deb]*/
     481  xyz
     482  """)
     483  
     484      def _test_clinic(self, input, output):
     485          language = clinic.CLanguage(None)
     486          c = clinic.Clinic(language, filename="file")
     487          c.parsers['inert'] = InertParser(c)
     488          c.parsers['copy'] = CopyParser(c)
     489          computed = c.parse(input)
     490          self.assertEqual(output, computed)
     491  
     492      def test_clinic_1(self):
     493          self._test_clinic("""
     494      verbatim text here
     495      lah dee dah
     496  /*[copy input]
     497  def
     498  [copy start generated code]*/
     499  abc
     500  /*[copy end generated code: output=03cfd743661f0797 input=7b18d017f89f61cf]*/
     501  xyz
     502  """, """
     503      verbatim text here
     504      lah dee dah
     505  /*[copy input]
     506  def
     507  [copy start generated code]*/
     508  def
     509  /*[copy end generated code: output=7b18d017f89f61cf input=7b18d017f89f61cf]*/
     510  xyz
     511  """)
     512  
     513  
     514  class ESC[4;38;5;81mClinicParserTest(ESC[4;38;5;149m_ParserBase):
     515      def checkDocstring(self, fn, expected):
     516          self.assertTrue(hasattr(fn, "docstring"))
     517          self.assertEqual(fn.docstring.strip(),
     518                           dedent(expected).strip())
     519  
     520      def test_trivial(self):
     521          parser = DSLParser(FakeClinic())
     522          block = clinic.Block("""
     523              module os
     524              os.access
     525          """)
     526          parser.parse(block)
     527          module, function = block.signatures
     528          self.assertEqual("access", function.name)
     529          self.assertEqual("os", module.name)
     530  
     531      def test_ignore_line(self):
     532          block = self.parse(dedent("""
     533              #
     534              module os
     535              os.access
     536          """))
     537          module, function = block.signatures
     538          self.assertEqual("access", function.name)
     539          self.assertEqual("os", module.name)
     540  
     541      def test_param(self):
     542          function = self.parse_function("""
     543              module os
     544              os.access
     545                  path: int
     546          """)
     547          self.assertEqual("access", function.name)
     548          self.assertEqual(2, len(function.parameters))
     549          p = function.parameters['path']
     550          self.assertEqual('path', p.name)
     551          self.assertIsInstance(p.converter, clinic.int_converter)
     552  
     553      def test_param_default(self):
     554          function = self.parse_function("""
     555              module os
     556              os.access
     557                  follow_symlinks: bool = True
     558          """)
     559          p = function.parameters['follow_symlinks']
     560          self.assertEqual(True, p.default)
     561  
     562      def test_param_with_continuations(self):
     563          function = self.parse_function(r"""
     564              module os
     565              os.access
     566                  follow_symlinks: \
     567                  bool \
     568                  = \
     569                  True
     570          """)
     571          p = function.parameters['follow_symlinks']
     572          self.assertEqual(True, p.default)
     573  
     574      def test_param_default_expression(self):
     575          function = self.parse_function("""
     576              module os
     577              os.access
     578                  follow_symlinks: int(c_default='MAXSIZE') = sys.maxsize
     579              """)
     580          p = function.parameters['follow_symlinks']
     581          self.assertEqual(sys.maxsize, p.default)
     582          self.assertEqual("MAXSIZE", p.converter.c_default)
     583  
     584          expected_msg = (
     585              "Error on line 0:\n"
     586              "When you specify a named constant ('sys.maxsize') as your default value,\n"
     587              "you MUST specify a valid c_default.\n"
     588          )
     589          out = self.parse_function_should_fail("""
     590              module os
     591              os.access
     592                  follow_symlinks: int = sys.maxsize
     593          """)
     594          self.assertEqual(out, expected_msg)
     595  
     596      def test_param_no_docstring(self):
     597          function = self.parse_function("""
     598              module os
     599              os.access
     600                  follow_symlinks: bool = True
     601                  something_else: str = ''
     602          """)
     603          p = function.parameters['follow_symlinks']
     604          self.assertEqual(3, len(function.parameters))
     605          conv = function.parameters['something_else'].converter
     606          self.assertIsInstance(conv, clinic.str_converter)
     607  
     608      def test_param_default_parameters_out_of_order(self):
     609          expected_msg = (
     610              "Error on line 0:\n"
     611              "Can't have a parameter without a default ('something_else')\n"
     612              "after a parameter with a default!\n"
     613          )
     614          out = self.parse_function_should_fail("""
     615              module os
     616              os.access
     617                  follow_symlinks: bool = True
     618                  something_else: str""")
     619          self.assertEqual(out, expected_msg)
     620  
     621      def disabled_test_converter_arguments(self):
     622          function = self.parse_function("""
     623              module os
     624              os.access
     625                  path: path_t(allow_fd=1)
     626          """)
     627          p = function.parameters['path']
     628          self.assertEqual(1, p.converter.args['allow_fd'])
     629  
     630      def test_function_docstring(self):
     631          function = self.parse_function("""
     632              module os
     633              os.stat as os_stat_fn
     634  
     635                 path: str
     636                     Path to be examined
     637  
     638              Perform a stat system call on the given path.
     639          """)
     640          self.checkDocstring(function, """
     641              stat($module, /, path)
     642              --
     643  
     644              Perform a stat system call on the given path.
     645  
     646                path
     647                  Path to be examined
     648          """)
     649  
     650      def test_explicit_parameters_in_docstring(self):
     651          function = self.parse_function(dedent("""
     652              module foo
     653              foo.bar
     654                x: int
     655                   Documentation for x.
     656                y: int
     657  
     658              This is the documentation for foo.
     659  
     660              Okay, we're done here.
     661          """))
     662          self.checkDocstring(function, """
     663              bar($module, /, x, y)
     664              --
     665  
     666              This is the documentation for foo.
     667  
     668                x
     669                  Documentation for x.
     670  
     671              Okay, we're done here.
     672          """)
     673  
     674      def test_parser_regression_special_character_in_parameter_column_of_docstring_first_line(self):
     675          function = self.parse_function(dedent("""
     676              module os
     677              os.stat
     678                  path: str
     679              This/used to break Clinic!
     680          """))
     681          self.checkDocstring(function, """
     682              stat($module, /, path)
     683              --
     684  
     685              This/used to break Clinic!
     686          """)
     687  
     688      def test_c_name(self):
     689          function = self.parse_function("""
     690              module os
     691              os.stat as os_stat_fn
     692          """)
     693          self.assertEqual("os_stat_fn", function.c_basename)
     694  
     695      def test_return_converter(self):
     696          function = self.parse_function("""
     697              module os
     698              os.stat -> int
     699          """)
     700          self.assertIsInstance(function.return_converter, clinic.int_return_converter)
     701  
     702      def test_star(self):
     703          function = self.parse_function("""
     704              module os
     705              os.access
     706                  *
     707                  follow_symlinks: bool = True
     708          """)
     709          p = function.parameters['follow_symlinks']
     710          self.assertEqual(inspect.Parameter.KEYWORD_ONLY, p.kind)
     711          self.assertEqual(0, p.group)
     712  
     713      def test_group(self):
     714          function = self.parse_function("""
     715              module window
     716              window.border
     717                  [
     718                  ls: int
     719                  ]
     720                  /
     721          """)
     722          p = function.parameters['ls']
     723          self.assertEqual(1, p.group)
     724  
     725      def test_left_group(self):
     726          function = self.parse_function("""
     727              module curses
     728              curses.addch
     729                  [
     730                  y: int
     731                      Y-coordinate.
     732                  x: int
     733                      X-coordinate.
     734                  ]
     735                  ch: char
     736                      Character to add.
     737                  [
     738                  attr: long
     739                      Attributes for the character.
     740                  ]
     741                  /
     742          """)
     743          dataset = (
     744              ('y', -1), ('x', -1),
     745              ('ch', 0),
     746              ('attr', 1),
     747          )
     748          for name, group in dataset:
     749              with self.subTest(name=name, group=group):
     750                  p = function.parameters[name]
     751                  self.assertEqual(p.group, group)
     752                  self.assertEqual(p.kind, inspect.Parameter.POSITIONAL_ONLY)
     753          self.checkDocstring(function, """
     754              addch([y, x,] ch, [attr])
     755  
     756  
     757                y
     758                  Y-coordinate.
     759                x
     760                  X-coordinate.
     761                ch
     762                  Character to add.
     763                attr
     764                  Attributes for the character.
     765          """)
     766  
     767      def test_nested_groups(self):
     768          function = self.parse_function("""
     769              module curses
     770              curses.imaginary
     771                 [
     772                 [
     773                 y1: int
     774                   Y-coordinate.
     775                 y2: int
     776                   Y-coordinate.
     777                 ]
     778                 x1: int
     779                   X-coordinate.
     780                 x2: int
     781                   X-coordinate.
     782                 ]
     783                 ch: char
     784                   Character to add.
     785                 [
     786                 attr1: long
     787                   Attributes for the character.
     788                 attr2: long
     789                   Attributes for the character.
     790                 attr3: long
     791                   Attributes for the character.
     792                 [
     793                 attr4: long
     794                   Attributes for the character.
     795                 attr5: long
     796                   Attributes for the character.
     797                 attr6: long
     798                   Attributes for the character.
     799                 ]
     800                 ]
     801                 /
     802          """)
     803          dataset = (
     804              ('y1', -2), ('y2', -2),
     805              ('x1', -1), ('x2', -1),
     806              ('ch', 0),
     807              ('attr1', 1), ('attr2', 1), ('attr3', 1),
     808              ('attr4', 2), ('attr5', 2), ('attr6', 2),
     809          )
     810          for name, group in dataset:
     811              with self.subTest(name=name, group=group):
     812                  p = function.parameters[name]
     813                  self.assertEqual(p.group, group)
     814                  self.assertEqual(p.kind, inspect.Parameter.POSITIONAL_ONLY)
     815  
     816          self.checkDocstring(function, """
     817              imaginary([[y1, y2,] x1, x2,] ch, [attr1, attr2, attr3, [attr4, attr5,
     818                        attr6]])
     819  
     820  
     821                y1
     822                  Y-coordinate.
     823                y2
     824                  Y-coordinate.
     825                x1
     826                  X-coordinate.
     827                x2
     828                  X-coordinate.
     829                ch
     830                  Character to add.
     831                attr1
     832                  Attributes for the character.
     833                attr2
     834                  Attributes for the character.
     835                attr3
     836                  Attributes for the character.
     837                attr4
     838                  Attributes for the character.
     839                attr5
     840                  Attributes for the character.
     841                attr6
     842                  Attributes for the character.
     843          """)
     844  
     845      def parse_function_should_fail(self, s):
     846          with support.captured_stdout() as stdout:
     847              with self.assertRaises(SystemExit):
     848                  self.parse_function(s)
     849          return stdout.getvalue()
     850  
     851      def test_disallowed_grouping__two_top_groups_on_left(self):
     852          expected_msg = (
     853              'Error on line 0:\n'
     854              'Function two_top_groups_on_left has an unsupported group '
     855              'configuration. (Unexpected state 2.b)\n'
     856          )
     857          out = self.parse_function_should_fail("""
     858              module foo
     859              foo.two_top_groups_on_left
     860                  [
     861                  group1 : int
     862                  ]
     863                  [
     864                  group2 : int
     865                  ]
     866                  param: int
     867          """)
     868          self.assertEqual(out, expected_msg)
     869  
     870      def test_disallowed_grouping__two_top_groups_on_right(self):
     871          out = self.parse_function_should_fail("""
     872              module foo
     873              foo.two_top_groups_on_right
     874                  param: int
     875                  [
     876                  group1 : int
     877                  ]
     878                  [
     879                  group2 : int
     880                  ]
     881          """)
     882          msg = (
     883              "Function two_top_groups_on_right has an unsupported group "
     884              "configuration. (Unexpected state 6.b)"
     885          )
     886          self.assertIn(msg, out)
     887  
     888      def test_disallowed_grouping__parameter_after_group_on_right(self):
     889          out = self.parse_function_should_fail("""
     890              module foo
     891              foo.parameter_after_group_on_right
     892                  param: int
     893                  [
     894                  [
     895                  group1 : int
     896                  ]
     897                  group2 : int
     898                  ]
     899          """)
     900          msg = (
     901              "Function parameter_after_group_on_right has an unsupported group "
     902              "configuration. (Unexpected state 6.a)"
     903          )
     904          self.assertIn(msg, out)
     905  
     906      def test_disallowed_grouping__group_after_parameter_on_left(self):
     907          out = self.parse_function_should_fail("""
     908              module foo
     909              foo.group_after_parameter_on_left
     910                  [
     911                  group2 : int
     912                  [
     913                  group1 : int
     914                  ]
     915                  ]
     916                  param: int
     917          """)
     918          msg = (
     919              "Function group_after_parameter_on_left has an unsupported group "
     920              "configuration. (Unexpected state 2.b)"
     921          )
     922          self.assertIn(msg, out)
     923  
     924      def test_disallowed_grouping__empty_group_on_left(self):
     925          out = self.parse_function_should_fail("""
     926              module foo
     927              foo.empty_group
     928                  [
     929                  [
     930                  ]
     931                  group2 : int
     932                  ]
     933                  param: int
     934          """)
     935          msg = (
     936              "Function empty_group has an empty group.\n"
     937              "All groups must contain at least one parameter."
     938          )
     939          self.assertIn(msg, out)
     940  
     941      def test_disallowed_grouping__empty_group_on_right(self):
     942          out = self.parse_function_should_fail("""
     943              module foo
     944              foo.empty_group
     945                  param: int
     946                  [
     947                  [
     948                  ]
     949                  group2 : int
     950                  ]
     951          """)
     952          msg = (
     953              "Function empty_group has an empty group.\n"
     954              "All groups must contain at least one parameter."
     955          )
     956          self.assertIn(msg, out)
     957  
     958      def test_disallowed_grouping__no_matching_bracket(self):
     959          out = self.parse_function_should_fail("""
     960              module foo
     961              foo.empty_group
     962                  param: int
     963                  ]
     964                  group2: int
     965                  ]
     966          """)
     967          msg = "Function empty_group has a ] without a matching [."
     968          self.assertIn(msg, out)
     969  
     970      def test_no_parameters(self):
     971          function = self.parse_function("""
     972              module foo
     973              foo.bar
     974  
     975              Docstring
     976  
     977          """)
     978          self.assertEqual("bar($module, /)\n--\n\nDocstring", function.docstring)
     979          self.assertEqual(1, len(function.parameters)) # self!
     980  
     981      def test_init_with_no_parameters(self):
     982          function = self.parse_function("""
     983              module foo
     984              class foo.Bar "unused" "notneeded"
     985              foo.Bar.__init__
     986  
     987              Docstring
     988  
     989          """, signatures_in_block=3, function_index=2)
     990  
     991          # self is not in the signature
     992          self.assertEqual("Bar()\n--\n\nDocstring", function.docstring)
     993          # but it *is* a parameter
     994          self.assertEqual(1, len(function.parameters))
     995  
     996      def test_illegal_module_line(self):
     997          out = self.parse_function_should_fail("""
     998              module foo
     999              foo.bar => int
    1000                  /
    1001          """)
    1002          msg = "Illegal function name: foo.bar => int"
    1003          self.assertIn(msg, out)
    1004  
    1005      def test_illegal_c_basename(self):
    1006          out = self.parse_function_should_fail("""
    1007              module foo
    1008              foo.bar as 935
    1009                  /
    1010          """)
    1011          msg = "Illegal C basename: 935"
    1012          self.assertIn(msg, out)
    1013  
    1014      def test_single_star(self):
    1015          out = self.parse_function_should_fail("""
    1016              module foo
    1017              foo.bar
    1018                  *
    1019                  *
    1020          """)
    1021          self.assertIn("Function bar uses '*' more than once.", out)
    1022  
    1023      def test_parameters_required_after_star(self):
    1024          dataset = (
    1025              "module foo\nfoo.bar\n  *",
    1026              "module foo\nfoo.bar\n  *\nDocstring here.",
    1027              "module foo\nfoo.bar\n  this: int\n  *",
    1028              "module foo\nfoo.bar\n  this: int\n  *\nDocstring.",
    1029          )
    1030          msg = "Function bar specifies '*' without any parameters afterwards."
    1031          for block in dataset:
    1032              with self.subTest(block=block):
    1033                  out = self.parse_function_should_fail(block)
    1034                  self.assertIn(msg, out)
    1035  
    1036      def test_single_slash(self):
    1037          out = self.parse_function_should_fail("""
    1038              module foo
    1039              foo.bar
    1040                  /
    1041                  /
    1042          """)
    1043          msg = (
    1044              "Function bar has an unsupported group configuration. "
    1045              "(Unexpected state 0.d)"
    1046          )
    1047          self.assertIn(msg, out)
    1048  
    1049      def test_double_slash(self):
    1050          out = self.parse_function_should_fail("""
    1051              module foo
    1052              foo.bar
    1053                  a: int
    1054                  /
    1055                  b: int
    1056                  /
    1057          """)
    1058          msg = "Function bar uses '/' more than once."
    1059          self.assertIn(msg, out)
    1060  
    1061      def test_mix_star_and_slash(self):
    1062          out = self.parse_function_should_fail("""
    1063              module foo
    1064              foo.bar
    1065                 x: int
    1066                 y: int
    1067                 *
    1068                 z: int
    1069                 /
    1070          """)
    1071          msg = (
    1072              "Function bar mixes keyword-only and positional-only parameters, "
    1073              "which is unsupported."
    1074          )
    1075          self.assertIn(msg, out)
    1076  
    1077      def test_parameters_not_permitted_after_slash_for_now(self):
    1078          out = self.parse_function_should_fail("""
    1079              module foo
    1080              foo.bar
    1081                  /
    1082                  x: int
    1083          """)
    1084          msg = (
    1085              "Function bar has an unsupported group configuration. "
    1086              "(Unexpected state 0.d)"
    1087          )
    1088          self.assertIn(msg, out)
    1089  
    1090      def test_parameters_no_more_than_one_vararg(self):
    1091          expected_msg = (
    1092              "Error on line 0:\n"
    1093              "Too many var args\n"
    1094          )
    1095          out = self.parse_function_should_fail("""
    1096              module foo
    1097              foo.bar
    1098                 *vararg1: object
    1099                 *vararg2: object
    1100          """)
    1101          self.assertEqual(out, expected_msg)
    1102  
    1103      def test_function_not_at_column_0(self):
    1104          function = self.parse_function("""
    1105                module foo
    1106                foo.bar
    1107                  x: int
    1108                    Nested docstring here, goeth.
    1109                  *
    1110                  y: str
    1111                Not at column 0!
    1112          """)
    1113          self.checkDocstring(function, """
    1114              bar($module, /, x, *, y)
    1115              --
    1116  
    1117              Not at column 0!
    1118  
    1119                x
    1120                  Nested docstring here, goeth.
    1121          """)
    1122  
    1123      def test_indent_stack_no_tabs(self):
    1124          out = self.parse_function_should_fail("""
    1125              module foo
    1126              foo.bar
    1127                 *vararg1: object
    1128              \t*vararg2: object
    1129          """)
    1130          msg = "Tab characters are illegal in the Clinic DSL."
    1131          self.assertIn(msg, out)
    1132  
    1133      def test_indent_stack_illegal_outdent(self):
    1134          out = self.parse_function_should_fail("""
    1135              module foo
    1136              foo.bar
    1137                a: object
    1138               b: object
    1139          """)
    1140          self.assertIn("Illegal outdent", out)
    1141  
    1142      def test_directive(self):
    1143          c = FakeClinic()
    1144          parser = DSLParser(c)
    1145          parser.flag = False
    1146          parser.directives['setflag'] = lambda : setattr(parser, 'flag', True)
    1147          block = clinic.Block("setflag")
    1148          parser.parse(block)
    1149          self.assertTrue(parser.flag)
    1150  
    1151      def test_legacy_converters(self):
    1152          block = self.parse('module os\nos.access\n   path: "s"')
    1153          module, function = block.signatures
    1154          conv = (function.parameters['path']).converter
    1155          self.assertIsInstance(conv, clinic.str_converter)
    1156  
    1157      def test_legacy_converters_non_string_constant_annotation(self):
    1158          expected_failure_message = (
    1159              "Error on line 0:\n"
    1160              "Annotations must be either a name, a function call, or a string.\n"
    1161          )
    1162          dataset = (
    1163              'module os\nos.access\n   path: 42',
    1164              'module os\nos.access\n   path: 42.42',
    1165              'module os\nos.access\n   path: 42j',
    1166              'module os\nos.access\n   path: b"42"',
    1167          )
    1168          for block in dataset:
    1169              with self.subTest(block=block):
    1170                  out = self.parse_function_should_fail(block)
    1171                  self.assertEqual(out, expected_failure_message)
    1172  
    1173      def test_other_bizarre_things_in_annotations_fail(self):
    1174          expected_failure_message = (
    1175              "Error on line 0:\n"
    1176              "Annotations must be either a name, a function call, or a string.\n"
    1177          )
    1178          dataset = (
    1179              'module os\nos.access\n   path: {"some": "dictionary"}',
    1180              'module os\nos.access\n   path: ["list", "of", "strings"]',
    1181              'module os\nos.access\n   path: (x for x in range(42))',
    1182          )
    1183          for block in dataset:
    1184              with self.subTest(block=block):
    1185                  out = self.parse_function_should_fail(block)
    1186                  self.assertEqual(out, expected_failure_message)
    1187  
    1188      def test_kwarg_splats_disallowed_in_function_call_annotations(self):
    1189          expected_error_msg = (
    1190              "Error on line 0:\n"
    1191              "Cannot use a kwarg splat in a function-call annotation\n"
    1192          )
    1193          dataset = (
    1194              'module fo\nfo.barbaz\n   o: bool(**{None: "bang!"})',
    1195              'module fo\nfo.barbaz -> bool(**{None: "bang!"})',
    1196              'module fo\nfo.barbaz -> bool(**{"bang": 42})',
    1197              'module fo\nfo.barbaz\n   o: bool(**{"bang": None})',
    1198          )
    1199          for fn in dataset:
    1200              with self.subTest(fn=fn):
    1201                  out = self.parse_function_should_fail(fn)
    1202                  self.assertEqual(out, expected_error_msg)
    1203  
    1204      def test_self_param_placement(self):
    1205          expected_error_msg = (
    1206              "Error on line 0:\n"
    1207              "A 'self' parameter, if specified, must be the very first thing "
    1208              "in the parameter block.\n"
    1209          )
    1210          block = """
    1211              module foo
    1212              foo.func
    1213                  a: int
    1214                  self: self(type="PyObject *")
    1215          """
    1216          out = self.parse_function_should_fail(block)
    1217          self.assertEqual(out, expected_error_msg)
    1218  
    1219      def test_self_param_cannot_be_optional(self):
    1220          expected_error_msg = (
    1221              "Error on line 0:\n"
    1222              "A 'self' parameter cannot be marked optional.\n"
    1223          )
    1224          block = """
    1225              module foo
    1226              foo.func
    1227                  self: self(type="PyObject *") = None
    1228          """
    1229          out = self.parse_function_should_fail(block)
    1230          self.assertEqual(out, expected_error_msg)
    1231  
    1232      def test_defining_class_param_placement(self):
    1233          expected_error_msg = (
    1234              "Error on line 0:\n"
    1235              "A 'defining_class' parameter, if specified, must either be the "
    1236              "first thing in the parameter block, or come just after 'self'.\n"
    1237          )
    1238          block = """
    1239              module foo
    1240              foo.func
    1241                  self: self(type="PyObject *")
    1242                  a: int
    1243                  cls: defining_class
    1244          """
    1245          out = self.parse_function_should_fail(block)
    1246          self.assertEqual(out, expected_error_msg)
    1247  
    1248      def test_defining_class_param_cannot_be_optional(self):
    1249          expected_error_msg = (
    1250              "Error on line 0:\n"
    1251              "A 'defining_class' parameter cannot be marked optional.\n"
    1252          )
    1253          block = """
    1254              module foo
    1255              foo.func
    1256                  cls: defining_class(type="PyObject *") = None
    1257          """
    1258          out = self.parse_function_should_fail(block)
    1259          self.assertEqual(out, expected_error_msg)
    1260  
    1261      def test_slot_methods_cannot_access_defining_class(self):
    1262          block = """
    1263              module foo
    1264              class Foo "" ""
    1265              Foo.__init__
    1266                  cls: defining_class
    1267                  a: object
    1268          """
    1269          msg = "Slot methods cannot access their defining class."
    1270          with self.assertRaisesRegex(ValueError, msg):
    1271              self.parse_function(block)
    1272  
    1273      def test_new_must_be_a_class_method(self):
    1274          expected_error_msg = (
    1275              "Error on line 0:\n"
    1276              "__new__ must be a class method!\n"
    1277          )
    1278          out = self.parse_function_should_fail("""
    1279              module foo
    1280              class Foo "" ""
    1281              Foo.__new__
    1282          """)
    1283          self.assertEqual(out, expected_error_msg)
    1284  
    1285      def test_init_must_be_a_normal_method(self):
    1286          expected_error_msg = (
    1287              "Error on line 0:\n"
    1288              "__init__ must be a normal method, not a class or static method!\n"
    1289          )
    1290          out = self.parse_function_should_fail("""
    1291              module foo
    1292              class Foo "" ""
    1293              @classmethod
    1294              Foo.__init__
    1295          """)
    1296          self.assertEqual(out, expected_error_msg)
    1297  
    1298      def test_unused_param(self):
    1299          block = self.parse("""
    1300              module foo
    1301              foo.func
    1302                  fn: object
    1303                  k: float
    1304                  i: float(unused=True)
    1305                  /
    1306                  *
    1307                  flag: bool(unused=True) = False
    1308          """)
    1309          sig = block.signatures[1]  # Function index == 1
    1310          params = sig.parameters
    1311          conv = lambda fn: params[fn].converter
    1312          dataset = (
    1313              {"name": "fn", "unused": False},
    1314              {"name": "k", "unused": False},
    1315              {"name": "i", "unused": True},
    1316              {"name": "flag", "unused": True},
    1317          )
    1318          for param in dataset:
    1319              name, unused = param.values()
    1320              with self.subTest(name=name, unused=unused):
    1321                  p = conv(name)
    1322                  # Verify that the unused flag is parsed correctly.
    1323                  self.assertEqual(unused, p.unused)
    1324  
    1325                  # Now, check that we'll produce correct code.
    1326                  decl = p.simple_declaration(in_parser=False)
    1327                  if unused:
    1328                      self.assertIn("Py_UNUSED", decl)
    1329                  else:
    1330                      self.assertNotIn("Py_UNUSED", decl)
    1331  
    1332                  # Make sure the Py_UNUSED macro is not used in the parser body.
    1333                  parser_decl = p.simple_declaration(in_parser=True)
    1334                  self.assertNotIn("Py_UNUSED", parser_decl)
    1335  
    1336      def parse(self, text):
    1337          c = FakeClinic()
    1338          parser = DSLParser(c)
    1339          block = clinic.Block(text)
    1340          parser.parse(block)
    1341          return block
    1342  
    1343      def parse_function(self, text, signatures_in_block=2, function_index=1):
    1344          block = self.parse(text)
    1345          s = block.signatures
    1346          self.assertEqual(len(s), signatures_in_block)
    1347          assert isinstance(s[0], clinic.Module)
    1348          assert isinstance(s[function_index], clinic.Function)
    1349          return s[function_index]
    1350  
    1351      def test_scaffolding(self):
    1352          # test repr on special values
    1353          self.assertEqual(repr(clinic.unspecified), '<Unspecified>')
    1354          self.assertEqual(repr(clinic.NULL), '<Null>')
    1355  
    1356          # test that fail fails
    1357          expected = (
    1358              'Error in file "clown.txt" on line 69:\n'
    1359              'The igloos are melting!\n'
    1360          )
    1361          with support.captured_stdout() as stdout:
    1362              with self.assertRaises(SystemExit):
    1363                  clinic.fail('The igloos are melting!',
    1364                              filename='clown.txt', line_number=69)
    1365          actual = stdout.getvalue()
    1366          self.assertEqual(actual, expected)
    1367  
    1368  
    1369  class ESC[4;38;5;81mClinicExternalTest(ESC[4;38;5;149mTestCase):
    1370      maxDiff = None
    1371      clinic_py = os.path.join(test_tools.toolsdir, "clinic", "clinic.py")
    1372  
    1373      def _do_test(self, *args, expect_success=True):
    1374          with subprocess.Popen(
    1375              [sys.executable, "-Xutf8", self.clinic_py, *args],
    1376              encoding="utf-8",
    1377              bufsize=0,
    1378              stdout=subprocess.PIPE,
    1379              stderr=subprocess.PIPE,
    1380          ) as proc:
    1381              proc.wait()
    1382              if expect_success and proc.returncode:
    1383                  self.fail("".join([*proc.stdout, *proc.stderr]))
    1384              stdout = proc.stdout.read()
    1385              stderr = proc.stderr.read()
    1386              # Clinic never writes to stderr.
    1387              self.assertEqual(stderr, "")
    1388              return stdout
    1389  
    1390      def expect_success(self, *args):
    1391          return self._do_test(*args)
    1392  
    1393      def expect_failure(self, *args):
    1394          return self._do_test(*args, expect_success=False)
    1395  
    1396      def test_external(self):
    1397          CLINIC_TEST = 'clinic.test.c'
    1398          source = support.findfile(CLINIC_TEST)
    1399          with open(source, 'r', encoding='utf-8') as f:
    1400              orig_contents = f.read()
    1401  
    1402          # Run clinic CLI and verify that it does not complain.
    1403          self.addCleanup(unlink, TESTFN)
    1404          out = self.expect_success("-f", "-o", TESTFN, source)
    1405          self.assertEqual(out, "")
    1406  
    1407          with open(TESTFN, 'r', encoding='utf-8') as f:
    1408              new_contents = f.read()
    1409  
    1410          self.assertEqual(new_contents, orig_contents)
    1411  
    1412      def test_no_change(self):
    1413          # bpo-42398: Test that the destination file is left unchanged if the
    1414          # content does not change. Moreover, check also that the file
    1415          # modification time does not change in this case.
    1416          code = dedent("""
    1417              /*[clinic input]
    1418              [clinic start generated code]*/
    1419              /*[clinic end generated code: output=da39a3ee5e6b4b0d input=da39a3ee5e6b4b0d]*/
    1420          """)
    1421          with os_helper.temp_dir() as tmp_dir:
    1422              fn = os.path.join(tmp_dir, "test.c")
    1423              with open(fn, "w", encoding="utf-8") as f:
    1424                  f.write(code)
    1425              pre_mtime = os.stat(fn).st_mtime_ns
    1426              self.expect_success(fn)
    1427              post_mtime = os.stat(fn).st_mtime_ns
    1428          # Don't change the file modification time
    1429          # if the content does not change
    1430          self.assertEqual(pre_mtime, post_mtime)
    1431  
    1432      def test_cli_force(self):
    1433          invalid_input = dedent("""
    1434              /*[clinic input]
    1435              output preset block
    1436              module test
    1437              test.fn
    1438                  a: int
    1439              [clinic start generated code]*/
    1440  
    1441              const char *hand_edited = "output block is overwritten";
    1442              /*[clinic end generated code: output=bogus input=bogus]*/
    1443          """)
    1444          fail_msg = dedent("""
    1445              Checksum mismatch!
    1446              Expected: bogus
    1447              Computed: 2ed19
    1448              Suggested fix: remove all generated code including the end marker,
    1449              or use the '-f' option.
    1450          """)
    1451          with os_helper.temp_dir() as tmp_dir:
    1452              fn = os.path.join(tmp_dir, "test.c")
    1453              with open(fn, "w", encoding="utf-8") as f:
    1454                  f.write(invalid_input)
    1455              # First, run the CLI without -f and expect failure.
    1456              # Note, we cannot check the entire fail msg, because the path to
    1457              # the tmp file will change for every run.
    1458              out = self.expect_failure(fn)
    1459              self.assertTrue(out.endswith(fail_msg))
    1460              # Then, force regeneration; success expected.
    1461              out = self.expect_success("-f", fn)
    1462              self.assertEqual(out, "")
    1463              # Verify by checking the checksum.
    1464              checksum = (
    1465                  "/*[clinic end generated code: "
    1466                  "output=2124c291eb067d76 input=9543a8d2da235301]*/\n"
    1467              )
    1468              with open(fn, 'r', encoding='utf-8') as f:
    1469                  generated = f.read()
    1470              self.assertTrue(generated.endswith(checksum))
    1471  
    1472      def test_cli_make(self):
    1473          c_code = dedent("""
    1474              /*[clinic input]
    1475              [clinic start generated code]*/
    1476          """)
    1477          py_code = "pass"
    1478          c_files = "file1.c", "file2.c"
    1479          py_files = "file1.py", "file2.py"
    1480  
    1481          def create_files(files, srcdir, code):
    1482              for fn in files:
    1483                  path = os.path.join(srcdir, fn)
    1484                  with open(path, "w", encoding="utf-8") as f:
    1485                      f.write(code)
    1486  
    1487          with os_helper.temp_dir() as tmp_dir:
    1488              # add some folders, some C files and a Python file
    1489              create_files(c_files, tmp_dir, c_code)
    1490              create_files(py_files, tmp_dir, py_code)
    1491  
    1492              # create C files in externals/ dir
    1493              ext_path = os.path.join(tmp_dir, "externals")
    1494              with os_helper.temp_dir(path=ext_path) as externals:
    1495                  create_files(c_files, externals, c_code)
    1496  
    1497                  # run clinic in verbose mode with --make on tmpdir
    1498                  out = self.expect_success("-v", "--make", "--srcdir", tmp_dir)
    1499  
    1500              # expect verbose mode to only mention the C files in tmp_dir
    1501              for filename in c_files:
    1502                  with self.subTest(filename=filename):
    1503                      path = os.path.join(tmp_dir, filename)
    1504                      self.assertIn(path, out)
    1505              for filename in py_files:
    1506                  with self.subTest(filename=filename):
    1507                      path = os.path.join(tmp_dir, filename)
    1508                      self.assertNotIn(path, out)
    1509              # don't expect C files from the externals dir
    1510              for filename in c_files:
    1511                  with self.subTest(filename=filename):
    1512                      path = os.path.join(ext_path, filename)
    1513                      self.assertNotIn(path, out)
    1514  
    1515      def test_cli_verbose(self):
    1516          with os_helper.temp_dir() as tmp_dir:
    1517              fn = os.path.join(tmp_dir, "test.c")
    1518              with open(fn, "w", encoding="utf-8") as f:
    1519                  f.write("")
    1520              out = self.expect_success("-v", fn)
    1521              self.assertEqual(out.strip(), fn)
    1522  
    1523      def test_cli_help(self):
    1524          out = self.expect_success("-h")
    1525          self.assertIn("usage: clinic.py", out)
    1526  
    1527      def test_cli_converters(self):
    1528          prelude = dedent("""
    1529              Legacy converters:
    1530                  B C D L O S U Y Z Z#
    1531                  b c d f h i l p s s# s* u u# w* y y# y* z z# z*
    1532  
    1533              Converters:
    1534          """)
    1535          expected_converters = (
    1536              "bool",
    1537              "byte",
    1538              "char",
    1539              "defining_class",
    1540              "double",
    1541              "fildes",
    1542              "float",
    1543              "int",
    1544              "long",
    1545              "long_long",
    1546              "object",
    1547              "Py_buffer",
    1548              "Py_complex",
    1549              "Py_ssize_t",
    1550              "Py_UNICODE",
    1551              "PyByteArrayObject",
    1552              "PyBytesObject",
    1553              "self",
    1554              "short",
    1555              "size_t",
    1556              "slice_index",
    1557              "str",
    1558              "unicode",
    1559              "unsigned_char",
    1560              "unsigned_int",
    1561              "unsigned_long",
    1562              "unsigned_long_long",
    1563              "unsigned_short",
    1564          )
    1565          finale = dedent("""
    1566              Return converters:
    1567                  bool()
    1568                  double()
    1569                  float()
    1570                  init()
    1571                  int()
    1572                  long()
    1573                  Py_ssize_t()
    1574                  size_t()
    1575                  unsigned_int()
    1576                  unsigned_long()
    1577  
    1578              All converters also accept (c_default=None, py_default=None, annotation=None).
    1579              All return converters also accept (py_default=None).
    1580          """)
    1581          out = self.expect_success("--converters")
    1582          # We cannot simply compare the output, because the repr of the *accept*
    1583          # param may change (it's a set, thus unordered). So, let's compare the
    1584          # start and end of the expected output, and then assert that the
    1585          # converters appear lined up in alphabetical order.
    1586          self.assertTrue(out.startswith(prelude), out)
    1587          self.assertTrue(out.endswith(finale), out)
    1588  
    1589          out = out.removeprefix(prelude)
    1590          out = out.removesuffix(finale)
    1591          lines = out.split("\n")
    1592          for converter, line in zip(expected_converters, lines):
    1593              line = line.lstrip()
    1594              with self.subTest(converter=converter):
    1595                  self.assertTrue(
    1596                      line.startswith(converter),
    1597                      f"expected converter {converter!r}, got {line!r}"
    1598                  )
    1599  
    1600      def test_cli_fail_converters_and_filename(self):
    1601          out = self.expect_failure("--converters", "test.c")
    1602          msg = (
    1603              "Usage error: can't specify --converters "
    1604              "and a filename at the same time"
    1605          )
    1606          self.assertIn(msg, out)
    1607  
    1608      def test_cli_fail_no_filename(self):
    1609          out = self.expect_failure()
    1610          self.assertIn("usage: clinic.py", out)
    1611  
    1612      def test_cli_fail_output_and_multiple_files(self):
    1613          out = self.expect_failure("-o", "out.c", "input.c", "moreinput.c")
    1614          msg = "Usage error: can't use -o with multiple filenames"
    1615          self.assertIn(msg, out)
    1616  
    1617      def test_cli_fail_filename_or_output_and_make(self):
    1618          for opts in ("-o", "out.c"), ("filename.c",):
    1619              with self.subTest(opts=opts):
    1620                  out = self.expect_failure("--make", *opts)
    1621                  msg = "Usage error: can't use -o or filenames with --make"
    1622                  self.assertIn(msg, out)
    1623  
    1624      def test_cli_fail_make_without_srcdir(self):
    1625          out = self.expect_failure("--make", "--srcdir", "")
    1626          msg = "Usage error: --srcdir must not be empty with --make"
    1627          self.assertIn(msg, out)
    1628  
    1629  
    1630  try:
    1631      import _testclinic as ac_tester
    1632  except ImportError:
    1633      ac_tester = None
    1634  
    1635  @unittest.skipIf(ac_tester is None, "_testclinic is missing")
    1636  class ESC[4;38;5;81mClinicFunctionalTest(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
    1637      locals().update((name, getattr(ac_tester, name))
    1638                      for name in dir(ac_tester) if name.startswith('test_'))
    1639  
    1640      def test_objects_converter(self):
    1641          with self.assertRaises(TypeError):
    1642              ac_tester.objects_converter()
    1643          self.assertEqual(ac_tester.objects_converter(1, 2), (1, 2))
    1644          self.assertEqual(ac_tester.objects_converter([], 'whatever class'), ([], 'whatever class'))
    1645          self.assertEqual(ac_tester.objects_converter(1), (1, None))
    1646  
    1647      def test_bytes_object_converter(self):
    1648          with self.assertRaises(TypeError):
    1649              ac_tester.bytes_object_converter(1)
    1650          self.assertEqual(ac_tester.bytes_object_converter(b'BytesObject'), (b'BytesObject',))
    1651  
    1652      def test_byte_array_object_converter(self):
    1653          with self.assertRaises(TypeError):
    1654              ac_tester.byte_array_object_converter(1)
    1655          byte_arr = bytearray(b'ByteArrayObject')
    1656          self.assertEqual(ac_tester.byte_array_object_converter(byte_arr), (byte_arr,))
    1657  
    1658      def test_unicode_converter(self):
    1659          with self.assertRaises(TypeError):
    1660              ac_tester.unicode_converter(1)
    1661          self.assertEqual(ac_tester.unicode_converter('unicode'), ('unicode',))
    1662  
    1663      def test_bool_converter(self):
    1664          with self.assertRaises(TypeError):
    1665              ac_tester.bool_converter(False, False, 'not a int')
    1666          self.assertEqual(ac_tester.bool_converter(), (True, True, True))
    1667          self.assertEqual(ac_tester.bool_converter('', [], 5), (False, False, True))
    1668          self.assertEqual(ac_tester.bool_converter(('not empty',), {1: 2}, 0), (True, True, False))
    1669  
    1670      def test_char_converter(self):
    1671          with self.assertRaises(TypeError):
    1672              ac_tester.char_converter(1)
    1673          with self.assertRaises(TypeError):
    1674              ac_tester.char_converter(b'ab')
    1675          chars = [b'A', b'\a', b'\b', b'\t', b'\n', b'\v', b'\f', b'\r', b'"', b"'", b'?', b'\\', b'\000', b'\377']
    1676          expected = tuple(ord(c) for c in chars)
    1677          self.assertEqual(ac_tester.char_converter(), expected)
    1678          chars = [b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b'0', b'a', b'b', b'c', b'd']
    1679          expected = tuple(ord(c) for c in chars)
    1680          self.assertEqual(ac_tester.char_converter(*chars), expected)
    1681  
    1682      def test_unsigned_char_converter(self):
    1683          from _testcapi import UCHAR_MAX
    1684          with self.assertRaises(OverflowError):
    1685              ac_tester.unsigned_char_converter(-1)
    1686          with self.assertRaises(OverflowError):
    1687              ac_tester.unsigned_char_converter(UCHAR_MAX + 1)
    1688          with self.assertRaises(OverflowError):
    1689              ac_tester.unsigned_char_converter(0, UCHAR_MAX + 1)
    1690          with self.assertRaises(TypeError):
    1691              ac_tester.unsigned_char_converter([])
    1692          self.assertEqual(ac_tester.unsigned_char_converter(), (12, 34, 56))
    1693          self.assertEqual(ac_tester.unsigned_char_converter(0, 0, UCHAR_MAX + 1), (0, 0, 0))
    1694          self.assertEqual(ac_tester.unsigned_char_converter(0, 0, (UCHAR_MAX + 1) * 3 + 123), (0, 0, 123))
    1695  
    1696      def test_short_converter(self):
    1697          from _testcapi import SHRT_MIN, SHRT_MAX
    1698          with self.assertRaises(OverflowError):
    1699              ac_tester.short_converter(SHRT_MIN - 1)
    1700          with self.assertRaises(OverflowError):
    1701              ac_tester.short_converter(SHRT_MAX + 1)
    1702          with self.assertRaises(TypeError):
    1703              ac_tester.short_converter([])
    1704          self.assertEqual(ac_tester.short_converter(-1234), (-1234,))
    1705          self.assertEqual(ac_tester.short_converter(4321), (4321,))
    1706  
    1707      def test_unsigned_short_converter(self):
    1708          from _testcapi import USHRT_MAX
    1709          with self.assertRaises(ValueError):
    1710              ac_tester.unsigned_short_converter(-1)
    1711          with self.assertRaises(OverflowError):
    1712              ac_tester.unsigned_short_converter(USHRT_MAX + 1)
    1713          with self.assertRaises(OverflowError):
    1714              ac_tester.unsigned_short_converter(0, USHRT_MAX + 1)
    1715          with self.assertRaises(TypeError):
    1716              ac_tester.unsigned_short_converter([])
    1717          self.assertEqual(ac_tester.unsigned_short_converter(), (12, 34, 56))
    1718          self.assertEqual(ac_tester.unsigned_short_converter(0, 0, USHRT_MAX + 1), (0, 0, 0))
    1719          self.assertEqual(ac_tester.unsigned_short_converter(0, 0, (USHRT_MAX + 1) * 3 + 123), (0, 0, 123))
    1720  
    1721      def test_int_converter(self):
    1722          from _testcapi import INT_MIN, INT_MAX
    1723          with self.assertRaises(OverflowError):
    1724              ac_tester.int_converter(INT_MIN - 1)
    1725          with self.assertRaises(OverflowError):
    1726              ac_tester.int_converter(INT_MAX + 1)
    1727          with self.assertRaises(TypeError):
    1728              ac_tester.int_converter(1, 2, 3)
    1729          with self.assertRaises(TypeError):
    1730              ac_tester.int_converter([])
    1731          self.assertEqual(ac_tester.int_converter(), (12, 34, 45))
    1732          self.assertEqual(ac_tester.int_converter(1, 2, '3'), (1, 2, ord('3')))
    1733  
    1734      def test_unsigned_int_converter(self):
    1735          from _testcapi import UINT_MAX
    1736          with self.assertRaises(ValueError):
    1737              ac_tester.unsigned_int_converter(-1)
    1738          with self.assertRaises(OverflowError):
    1739              ac_tester.unsigned_int_converter(UINT_MAX + 1)
    1740          with self.assertRaises(OverflowError):
    1741              ac_tester.unsigned_int_converter(0, UINT_MAX + 1)
    1742          with self.assertRaises(TypeError):
    1743              ac_tester.unsigned_int_converter([])
    1744          self.assertEqual(ac_tester.unsigned_int_converter(), (12, 34, 56))
    1745          self.assertEqual(ac_tester.unsigned_int_converter(0, 0, UINT_MAX + 1), (0, 0, 0))
    1746          self.assertEqual(ac_tester.unsigned_int_converter(0, 0, (UINT_MAX + 1) * 3 + 123), (0, 0, 123))
    1747  
    1748      def test_long_converter(self):
    1749          from _testcapi import LONG_MIN, LONG_MAX
    1750          with self.assertRaises(OverflowError):
    1751              ac_tester.long_converter(LONG_MIN - 1)
    1752          with self.assertRaises(OverflowError):
    1753              ac_tester.long_converter(LONG_MAX + 1)
    1754          with self.assertRaises(TypeError):
    1755              ac_tester.long_converter([])
    1756          self.assertEqual(ac_tester.long_converter(), (12,))
    1757          self.assertEqual(ac_tester.long_converter(-1234), (-1234,))
    1758  
    1759      def test_unsigned_long_converter(self):
    1760          from _testcapi import ULONG_MAX
    1761          with self.assertRaises(ValueError):
    1762              ac_tester.unsigned_long_converter(-1)
    1763          with self.assertRaises(OverflowError):
    1764              ac_tester.unsigned_long_converter(ULONG_MAX + 1)
    1765          with self.assertRaises(OverflowError):
    1766              ac_tester.unsigned_long_converter(0, ULONG_MAX + 1)
    1767          with self.assertRaises(TypeError):
    1768              ac_tester.unsigned_long_converter([])
    1769          self.assertEqual(ac_tester.unsigned_long_converter(), (12, 34, 56))
    1770          self.assertEqual(ac_tester.unsigned_long_converter(0, 0, ULONG_MAX + 1), (0, 0, 0))
    1771          self.assertEqual(ac_tester.unsigned_long_converter(0, 0, (ULONG_MAX + 1) * 3 + 123), (0, 0, 123))
    1772  
    1773      def test_long_long_converter(self):
    1774          from _testcapi import LLONG_MIN, LLONG_MAX
    1775          with self.assertRaises(OverflowError):
    1776              ac_tester.long_long_converter(LLONG_MIN - 1)
    1777          with self.assertRaises(OverflowError):
    1778              ac_tester.long_long_converter(LLONG_MAX + 1)
    1779          with self.assertRaises(TypeError):
    1780              ac_tester.long_long_converter([])
    1781          self.assertEqual(ac_tester.long_long_converter(), (12,))
    1782          self.assertEqual(ac_tester.long_long_converter(-1234), (-1234,))
    1783  
    1784      def test_unsigned_long_long_converter(self):
    1785          from _testcapi import ULLONG_MAX
    1786          with self.assertRaises(ValueError):
    1787              ac_tester.unsigned_long_long_converter(-1)
    1788          with self.assertRaises(OverflowError):
    1789              ac_tester.unsigned_long_long_converter(ULLONG_MAX + 1)
    1790          with self.assertRaises(OverflowError):
    1791              ac_tester.unsigned_long_long_converter(0, ULLONG_MAX + 1)
    1792          with self.assertRaises(TypeError):
    1793              ac_tester.unsigned_long_long_converter([])
    1794          self.assertEqual(ac_tester.unsigned_long_long_converter(), (12, 34, 56))
    1795          self.assertEqual(ac_tester.unsigned_long_long_converter(0, 0, ULLONG_MAX + 1), (0, 0, 0))
    1796          self.assertEqual(ac_tester.unsigned_long_long_converter(0, 0, (ULLONG_MAX + 1) * 3 + 123), (0, 0, 123))
    1797  
    1798      def test_py_ssize_t_converter(self):
    1799          from _testcapi import PY_SSIZE_T_MIN, PY_SSIZE_T_MAX
    1800          with self.assertRaises(OverflowError):
    1801              ac_tester.py_ssize_t_converter(PY_SSIZE_T_MIN - 1)
    1802          with self.assertRaises(OverflowError):
    1803              ac_tester.py_ssize_t_converter(PY_SSIZE_T_MAX + 1)
    1804          with self.assertRaises(TypeError):
    1805              ac_tester.py_ssize_t_converter([])
    1806          self.assertEqual(ac_tester.py_ssize_t_converter(), (12, 34, 56))
    1807          self.assertEqual(ac_tester.py_ssize_t_converter(1, 2, None), (1, 2, 56))
    1808  
    1809      def test_slice_index_converter(self):
    1810          from _testcapi import PY_SSIZE_T_MIN, PY_SSIZE_T_MAX
    1811          with self.assertRaises(TypeError):
    1812              ac_tester.slice_index_converter([])
    1813          self.assertEqual(ac_tester.slice_index_converter(), (12, 34, 56))
    1814          self.assertEqual(ac_tester.slice_index_converter(1, 2, None), (1, 2, 56))
    1815          self.assertEqual(ac_tester.slice_index_converter(PY_SSIZE_T_MAX, PY_SSIZE_T_MAX + 1, PY_SSIZE_T_MAX + 1234),
    1816                           (PY_SSIZE_T_MAX, PY_SSIZE_T_MAX, PY_SSIZE_T_MAX))
    1817          self.assertEqual(ac_tester.slice_index_converter(PY_SSIZE_T_MIN, PY_SSIZE_T_MIN - 1, PY_SSIZE_T_MIN - 1234),
    1818                           (PY_SSIZE_T_MIN, PY_SSIZE_T_MIN, PY_SSIZE_T_MIN))
    1819  
    1820      def test_size_t_converter(self):
    1821          with self.assertRaises(ValueError):
    1822              ac_tester.size_t_converter(-1)
    1823          with self.assertRaises(TypeError):
    1824              ac_tester.size_t_converter([])
    1825          self.assertEqual(ac_tester.size_t_converter(), (12,))
    1826  
    1827      def test_float_converter(self):
    1828          with self.assertRaises(TypeError):
    1829              ac_tester.float_converter([])
    1830          self.assertEqual(ac_tester.float_converter(), (12.5,))
    1831          self.assertEqual(ac_tester.float_converter(-0.5), (-0.5,))
    1832  
    1833      def test_double_converter(self):
    1834          with self.assertRaises(TypeError):
    1835              ac_tester.double_converter([])
    1836          self.assertEqual(ac_tester.double_converter(), (12.5,))
    1837          self.assertEqual(ac_tester.double_converter(-0.5), (-0.5,))
    1838  
    1839      def test_py_complex_converter(self):
    1840          with self.assertRaises(TypeError):
    1841              ac_tester.py_complex_converter([])
    1842          self.assertEqual(ac_tester.py_complex_converter(complex(1, 2)), (complex(1, 2),))
    1843          self.assertEqual(ac_tester.py_complex_converter(complex('-1-2j')), (complex('-1-2j'),))
    1844          self.assertEqual(ac_tester.py_complex_converter(-0.5), (-0.5,))
    1845          self.assertEqual(ac_tester.py_complex_converter(10), (10,))
    1846  
    1847      def test_str_converter(self):
    1848          with self.assertRaises(TypeError):
    1849              ac_tester.str_converter(1)
    1850          with self.assertRaises(TypeError):
    1851              ac_tester.str_converter('a', 'b', 'c')
    1852          with self.assertRaises(ValueError):
    1853              ac_tester.str_converter('a', b'b\0b', 'c')
    1854          self.assertEqual(ac_tester.str_converter('a', b'b', 'c'), ('a', 'b', 'c'))
    1855          self.assertEqual(ac_tester.str_converter('a', b'b', b'c'), ('a', 'b', 'c'))
    1856          self.assertEqual(ac_tester.str_converter('a', b'b', 'c\0c'), ('a', 'b', 'c\0c'))
    1857  
    1858      def test_str_converter_encoding(self):
    1859          with self.assertRaises(TypeError):
    1860              ac_tester.str_converter_encoding(1)
    1861          self.assertEqual(ac_tester.str_converter_encoding('a', 'b', 'c'), ('a', 'b', 'c'))
    1862          with self.assertRaises(TypeError):
    1863              ac_tester.str_converter_encoding('a', b'b\0b', 'c')
    1864          self.assertEqual(ac_tester.str_converter_encoding('a', b'b', bytearray([ord('c')])), ('a', 'b', 'c'))
    1865          self.assertEqual(ac_tester.str_converter_encoding('a', b'b', bytearray([ord('c'), 0, ord('c')])),
    1866                           ('a', 'b', 'c\x00c'))
    1867          self.assertEqual(ac_tester.str_converter_encoding('a', b'b', b'c\x00c'), ('a', 'b', 'c\x00c'))
    1868  
    1869      def test_py_buffer_converter(self):
    1870          with self.assertRaises(TypeError):
    1871              ac_tester.py_buffer_converter('a', 'b')
    1872          self.assertEqual(ac_tester.py_buffer_converter('abc', bytearray([1, 2, 3])), (b'abc', b'\x01\x02\x03'))
    1873  
    1874      def test_keywords(self):
    1875          self.assertEqual(ac_tester.keywords(1, 2), (1, 2))
    1876          self.assertEqual(ac_tester.keywords(1, b=2), (1, 2))
    1877          self.assertEqual(ac_tester.keywords(a=1, b=2), (1, 2))
    1878  
    1879      def test_keywords_kwonly(self):
    1880          with self.assertRaises(TypeError):
    1881              ac_tester.keywords_kwonly(1, 2)
    1882          self.assertEqual(ac_tester.keywords_kwonly(1, b=2), (1, 2))
    1883          self.assertEqual(ac_tester.keywords_kwonly(a=1, b=2), (1, 2))
    1884  
    1885      def test_keywords_opt(self):
    1886          self.assertEqual(ac_tester.keywords_opt(1), (1, None, None))
    1887          self.assertEqual(ac_tester.keywords_opt(1, 2), (1, 2, None))
    1888          self.assertEqual(ac_tester.keywords_opt(1, 2, 3), (1, 2, 3))
    1889          self.assertEqual(ac_tester.keywords_opt(1, b=2), (1, 2, None))
    1890          self.assertEqual(ac_tester.keywords_opt(1, 2, c=3), (1, 2, 3))
    1891          self.assertEqual(ac_tester.keywords_opt(a=1, c=3), (1, None, 3))
    1892          self.assertEqual(ac_tester.keywords_opt(a=1, b=2, c=3), (1, 2, 3))
    1893  
    1894      def test_keywords_opt_kwonly(self):
    1895          self.assertEqual(ac_tester.keywords_opt_kwonly(1), (1, None, None, None))
    1896          self.assertEqual(ac_tester.keywords_opt_kwonly(1, 2), (1, 2, None, None))
    1897          with self.assertRaises(TypeError):
    1898              ac_tester.keywords_opt_kwonly(1, 2, 3)
    1899          self.assertEqual(ac_tester.keywords_opt_kwonly(1, b=2), (1, 2, None, None))
    1900          self.assertEqual(ac_tester.keywords_opt_kwonly(1, 2, c=3), (1, 2, 3, None))
    1901          self.assertEqual(ac_tester.keywords_opt_kwonly(a=1, c=3), (1, None, 3, None))
    1902          self.assertEqual(ac_tester.keywords_opt_kwonly(a=1, b=2, c=3, d=4), (1, 2, 3, 4))
    1903  
    1904      def test_keywords_kwonly_opt(self):
    1905          self.assertEqual(ac_tester.keywords_kwonly_opt(1), (1, None, None))
    1906          with self.assertRaises(TypeError):
    1907              ac_tester.keywords_kwonly_opt(1, 2)
    1908          self.assertEqual(ac_tester.keywords_kwonly_opt(1, b=2), (1, 2, None))
    1909          self.assertEqual(ac_tester.keywords_kwonly_opt(a=1, c=3), (1, None, 3))
    1910          self.assertEqual(ac_tester.keywords_kwonly_opt(a=1, b=2, c=3), (1, 2, 3))
    1911  
    1912      def test_posonly_keywords(self):
    1913          with self.assertRaises(TypeError):
    1914              ac_tester.posonly_keywords(1)
    1915          with self.assertRaises(TypeError):
    1916              ac_tester.posonly_keywords(a=1, b=2)
    1917          self.assertEqual(ac_tester.posonly_keywords(1, 2), (1, 2))
    1918          self.assertEqual(ac_tester.posonly_keywords(1, b=2), (1, 2))
    1919  
    1920      def test_posonly_kwonly(self):
    1921          with self.assertRaises(TypeError):
    1922              ac_tester.posonly_kwonly(1)
    1923          with self.assertRaises(TypeError):
    1924              ac_tester.posonly_kwonly(1, 2)
    1925          with self.assertRaises(TypeError):
    1926              ac_tester.posonly_kwonly(a=1, b=2)
    1927          self.assertEqual(ac_tester.posonly_kwonly(1, b=2), (1, 2))
    1928  
    1929      def test_posonly_keywords_kwonly(self):
    1930          with self.assertRaises(TypeError):
    1931              ac_tester.posonly_keywords_kwonly(1)
    1932          with self.assertRaises(TypeError):
    1933              ac_tester.posonly_keywords_kwonly(1, 2, 3)
    1934          with self.assertRaises(TypeError):
    1935              ac_tester.posonly_keywords_kwonly(a=1, b=2, c=3)
    1936          self.assertEqual(ac_tester.posonly_keywords_kwonly(1, 2, c=3), (1, 2, 3))
    1937          self.assertEqual(ac_tester.posonly_keywords_kwonly(1, b=2, c=3), (1, 2, 3))
    1938  
    1939      def test_posonly_keywords_opt(self):
    1940          with self.assertRaises(TypeError):
    1941              ac_tester.posonly_keywords_opt(1)
    1942          self.assertEqual(ac_tester.posonly_keywords_opt(1, 2), (1, 2, None, None))
    1943          self.assertEqual(ac_tester.posonly_keywords_opt(1, 2, 3), (1, 2, 3, None))
    1944          self.assertEqual(ac_tester.posonly_keywords_opt(1, 2, 3, 4), (1, 2, 3, 4))
    1945          self.assertEqual(ac_tester.posonly_keywords_opt(1, b=2), (1, 2, None, None))
    1946          self.assertEqual(ac_tester.posonly_keywords_opt(1, 2, c=3), (1, 2, 3, None))
    1947          with self.assertRaises(TypeError):
    1948              ac_tester.posonly_keywords_opt(a=1, b=2, c=3, d=4)
    1949          self.assertEqual(ac_tester.posonly_keywords_opt(1, b=2, c=3, d=4), (1, 2, 3, 4))
    1950  
    1951      def test_posonly_opt_keywords_opt(self):
    1952          self.assertEqual(ac_tester.posonly_opt_keywords_opt(1), (1, None, None, None))
    1953          self.assertEqual(ac_tester.posonly_opt_keywords_opt(1, 2), (1, 2, None, None))
    1954          self.assertEqual(ac_tester.posonly_opt_keywords_opt(1, 2, 3), (1, 2, 3, None))
    1955          self.assertEqual(ac_tester.posonly_opt_keywords_opt(1, 2, 3, 4), (1, 2, 3, 4))
    1956          with self.assertRaises(TypeError):
    1957              ac_tester.posonly_opt_keywords_opt(1, b=2)
    1958          self.assertEqual(ac_tester.posonly_opt_keywords_opt(1, 2, c=3), (1, 2, 3, None))
    1959          self.assertEqual(ac_tester.posonly_opt_keywords_opt(1, 2, c=3, d=4), (1, 2, 3, 4))
    1960          with self.assertRaises(TypeError):
    1961              ac_tester.posonly_opt_keywords_opt(a=1, b=2, c=3, d=4)
    1962  
    1963      def test_posonly_kwonly_opt(self):
    1964          with self.assertRaises(TypeError):
    1965              ac_tester.posonly_kwonly_opt(1)
    1966          with self.assertRaises(TypeError):
    1967              ac_tester.posonly_kwonly_opt(1, 2)
    1968          self.assertEqual(ac_tester.posonly_kwonly_opt(1, b=2), (1, 2, None, None))
    1969          self.assertEqual(ac_tester.posonly_kwonly_opt(1, b=2, c=3), (1, 2, 3, None))
    1970          self.assertEqual(ac_tester.posonly_kwonly_opt(1, b=2, c=3, d=4), (1, 2, 3, 4))
    1971          with self.assertRaises(TypeError):
    1972              ac_tester.posonly_kwonly_opt(a=1, b=2, c=3, d=4)
    1973  
    1974      def test_posonly_opt_kwonly_opt(self):
    1975          self.assertEqual(ac_tester.posonly_opt_kwonly_opt(1), (1, None, None, None))
    1976          self.assertEqual(ac_tester.posonly_opt_kwonly_opt(1, 2), (1, 2, None, None))
    1977          with self.assertRaises(TypeError):
    1978              ac_tester.posonly_opt_kwonly_opt(1, 2, 3)
    1979          with self.assertRaises(TypeError):
    1980              ac_tester.posonly_opt_kwonly_opt(1, b=2)
    1981          self.assertEqual(ac_tester.posonly_opt_kwonly_opt(1, 2, c=3), (1, 2, 3, None))
    1982          self.assertEqual(ac_tester.posonly_opt_kwonly_opt(1, 2, c=3, d=4), (1, 2, 3, 4))
    1983  
    1984      def test_posonly_keywords_kwonly_opt(self):
    1985          with self.assertRaises(TypeError):
    1986              ac_tester.posonly_keywords_kwonly_opt(1)
    1987          with self.assertRaises(TypeError):
    1988              ac_tester.posonly_keywords_kwonly_opt(1, 2)
    1989          with self.assertRaises(TypeError):
    1990              ac_tester.posonly_keywords_kwonly_opt(1, b=2)
    1991          with self.assertRaises(TypeError):
    1992              ac_tester.posonly_keywords_kwonly_opt(1, 2, 3)
    1993          with self.assertRaises(TypeError):
    1994              ac_tester.posonly_keywords_kwonly_opt(a=1, b=2, c=3)
    1995          self.assertEqual(ac_tester.posonly_keywords_kwonly_opt(1, 2, c=3), (1, 2, 3, None, None))
    1996          self.assertEqual(ac_tester.posonly_keywords_kwonly_opt(1, b=2, c=3), (1, 2, 3, None, None))
    1997          self.assertEqual(ac_tester.posonly_keywords_kwonly_opt(1, 2, c=3, d=4), (1, 2, 3, 4, None))
    1998          self.assertEqual(ac_tester.posonly_keywords_kwonly_opt(1, 2, c=3, d=4, e=5), (1, 2, 3, 4, 5))
    1999  
    2000      def test_posonly_keywords_opt_kwonly_opt(self):
    2001          with self.assertRaises(TypeError):
    2002              ac_tester.posonly_keywords_opt_kwonly_opt(1)
    2003          self.assertEqual(ac_tester.posonly_keywords_opt_kwonly_opt(1, 2), (1, 2, None, None, None))
    2004          self.assertEqual(ac_tester.posonly_keywords_opt_kwonly_opt(1, b=2), (1, 2, None, None, None))
    2005          with self.assertRaises(TypeError):
    2006              ac_tester.posonly_keywords_opt_kwonly_opt(1, 2, 3, 4)
    2007          with self.assertRaises(TypeError):
    2008              ac_tester.posonly_keywords_opt_kwonly_opt(a=1, b=2)
    2009          self.assertEqual(ac_tester.posonly_keywords_opt_kwonly_opt(1, 2, c=3), (1, 2, 3, None, None))
    2010          self.assertEqual(ac_tester.posonly_keywords_opt_kwonly_opt(1, b=2, c=3), (1, 2, 3, None, None))
    2011          self.assertEqual(ac_tester.posonly_keywords_opt_kwonly_opt(1, 2, 3, d=4), (1, 2, 3, 4, None))
    2012          self.assertEqual(ac_tester.posonly_keywords_opt_kwonly_opt(1, 2, c=3, d=4), (1, 2, 3, 4, None))
    2013          self.assertEqual(ac_tester.posonly_keywords_opt_kwonly_opt(1, 2, 3, d=4, e=5), (1, 2, 3, 4, 5))
    2014          self.assertEqual(ac_tester.posonly_keywords_opt_kwonly_opt(1, 2, c=3, d=4, e=5), (1, 2, 3, 4, 5))
    2015  
    2016      def test_posonly_opt_keywords_opt_kwonly_opt(self):
    2017          self.assertEqual(ac_tester.posonly_opt_keywords_opt_kwonly_opt(1), (1, None, None, None))
    2018          self.assertEqual(ac_tester.posonly_opt_keywords_opt_kwonly_opt(1, 2), (1, 2, None, None))
    2019          with self.assertRaises(TypeError):
    2020              ac_tester.posonly_opt_keywords_opt_kwonly_opt(1, b=2)
    2021          self.assertEqual(ac_tester.posonly_opt_keywords_opt_kwonly_opt(1, 2, 3), (1, 2, 3, None))
    2022          self.assertEqual(ac_tester.posonly_opt_keywords_opt_kwonly_opt(1, 2, c=3), (1, 2, 3, None))
    2023          self.assertEqual(ac_tester.posonly_opt_keywords_opt_kwonly_opt(1, 2, 3, d=4), (1, 2, 3, 4))
    2024          self.assertEqual(ac_tester.posonly_opt_keywords_opt_kwonly_opt(1, 2, c=3, d=4), (1, 2, 3, 4))
    2025          with self.assertRaises(TypeError):
    2026              ac_tester.posonly_opt_keywords_opt_kwonly_opt(1, 2, 3, 4)
    2027  
    2028      def test_keyword_only_parameter(self):
    2029          with self.assertRaises(TypeError):
    2030              ac_tester.keyword_only_parameter()
    2031          with self.assertRaises(TypeError):
    2032              ac_tester.keyword_only_parameter(1)
    2033          self.assertEqual(ac_tester.keyword_only_parameter(a=1), (1,))
    2034  
    2035      def test_posonly_vararg(self):
    2036          with self.assertRaises(TypeError):
    2037              ac_tester.posonly_vararg()
    2038          self.assertEqual(ac_tester.posonly_vararg(1, 2), (1, 2, ()))
    2039          self.assertEqual(ac_tester.posonly_vararg(1, b=2), (1, 2, ()))
    2040          self.assertEqual(ac_tester.posonly_vararg(1, 2, 3, 4), (1, 2, (3, 4)))
    2041  
    2042      def test_vararg_and_posonly(self):
    2043          with self.assertRaises(TypeError):
    2044              ac_tester.vararg_and_posonly()
    2045          with self.assertRaises(TypeError):
    2046              ac_tester.vararg_and_posonly(1, b=2)
    2047          self.assertEqual(ac_tester.vararg_and_posonly(1, 2, 3, 4), (1, (2, 3, 4)))
    2048  
    2049      def test_vararg(self):
    2050          with self.assertRaises(TypeError):
    2051              ac_tester.vararg()
    2052          with self.assertRaises(TypeError):
    2053              ac_tester.vararg(1, b=2)
    2054          self.assertEqual(ac_tester.vararg(1, 2, 3, 4), (1, (2, 3, 4)))
    2055  
    2056      def test_vararg_with_default(self):
    2057          with self.assertRaises(TypeError):
    2058              ac_tester.vararg_with_default()
    2059          self.assertEqual(ac_tester.vararg_with_default(1, b=False), (1, (), False))
    2060          self.assertEqual(ac_tester.vararg_with_default(1, 2, 3, 4), (1, (2, 3, 4), False))
    2061          self.assertEqual(ac_tester.vararg_with_default(1, 2, 3, 4, b=True), (1, (2, 3, 4), True))
    2062  
    2063      def test_vararg_with_only_defaults(self):
    2064          self.assertEqual(ac_tester.vararg_with_only_defaults(), ((), None))
    2065          self.assertEqual(ac_tester.vararg_with_only_defaults(b=2), ((), 2))
    2066          self.assertEqual(ac_tester.vararg_with_only_defaults(1, b=2), ((1, ), 2))
    2067          self.assertEqual(ac_tester.vararg_with_only_defaults(1, 2, 3, 4), ((1, 2, 3, 4), None))
    2068          self.assertEqual(ac_tester.vararg_with_only_defaults(1, 2, 3, 4, b=5), ((1, 2, 3, 4), 5))
    2069  
    2070      def test_gh_32092_oob(self):
    2071          ac_tester.gh_32092_oob(1, 2, 3, 4, kw1=5, kw2=6)
    2072  
    2073      def test_gh_32092_kw_pass(self):
    2074          ac_tester.gh_32092_kw_pass(1, 2, 3)
    2075  
    2076      def test_gh_99233_refcount(self):
    2077          arg = '*A unique string is not referenced by anywhere else.*'
    2078          arg_refcount_origin = sys.getrefcount(arg)
    2079          ac_tester.gh_99233_refcount(arg)
    2080          arg_refcount_after = sys.getrefcount(arg)
    2081          self.assertEqual(arg_refcount_origin, arg_refcount_after)
    2082  
    2083      def test_gh_99240_double_free(self):
    2084          expected_error = r'gh_99240_double_free\(\) argument 2 must be encoded string without null bytes, not str'
    2085          with self.assertRaisesRegex(TypeError, expected_error):
    2086              ac_tester.gh_99240_double_free('a', '\0b')
    2087  
    2088      def test_cloned_func_exception_message(self):
    2089          incorrect_arg = -1  # f1() and f2() accept a single str
    2090          with self.assertRaisesRegex(TypeError, "clone_f1"):
    2091              ac_tester.clone_f1(incorrect_arg)
    2092          with self.assertRaisesRegex(TypeError, "clone_f2"):
    2093              ac_tester.clone_f2(incorrect_arg)
    2094  
    2095      def test_cloned_func_with_converter_exception_message(self):
    2096          for name in "clone_with_conv_f1", "clone_with_conv_f2":
    2097              with self.subTest(name=name):
    2098                  func = getattr(ac_tester, name)
    2099                  self.assertEqual(func(), name)
    2100  
    2101  
    2102  class ESC[4;38;5;81mPermutationTests(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
    2103      """Test permutation support functions."""
    2104  
    2105      def test_permute_left_option_groups(self):
    2106          expected = (
    2107              (),
    2108              (3,),
    2109              (2, 3),
    2110              (1, 2, 3),
    2111          )
    2112          data = list(zip([1, 2, 3]))  # Generate a list of 1-tuples.
    2113          actual = tuple(clinic.permute_left_option_groups(data))
    2114          self.assertEqual(actual, expected)
    2115  
    2116      def test_permute_right_option_groups(self):
    2117          expected = (
    2118              (),
    2119              (1,),
    2120              (1, 2),
    2121              (1, 2, 3),
    2122          )
    2123          data = list(zip([1, 2, 3]))  # Generate a list of 1-tuples.
    2124          actual = tuple(clinic.permute_right_option_groups(data))
    2125          self.assertEqual(actual, expected)
    2126  
    2127      def test_permute_optional_groups(self):
    2128          empty = {
    2129              "left": (), "required": (), "right": (),
    2130              "expected": ((),),
    2131          }
    2132          noleft1 = {
    2133              "left": (), "required": ("b",), "right": ("c",),
    2134              "expected": (
    2135                  ("b",),
    2136                  ("b", "c"),
    2137              ),
    2138          }
    2139          noleft2 = {
    2140              "left": (), "required": ("b", "c",), "right": ("d",),
    2141              "expected": (
    2142                  ("b", "c"),
    2143                  ("b", "c", "d"),
    2144              ),
    2145          }
    2146          noleft3 = {
    2147              "left": (), "required": ("b", "c",), "right": ("d", "e"),
    2148              "expected": (
    2149                  ("b", "c"),
    2150                  ("b", "c", "d"),
    2151                  ("b", "c", "d", "e"),
    2152              ),
    2153          }
    2154          noright1 = {
    2155              "left": ("a",), "required": ("b",), "right": (),
    2156              "expected": (
    2157                  ("b",),
    2158                  ("a", "b"),
    2159              ),
    2160          }
    2161          noright2 = {
    2162              "left": ("a",), "required": ("b", "c"), "right": (),
    2163              "expected": (
    2164                  ("b", "c"),
    2165                  ("a", "b", "c"),
    2166              ),
    2167          }
    2168          noright3 = {
    2169              "left": ("a", "b"), "required": ("c",), "right": (),
    2170              "expected": (
    2171                  ("c",),
    2172                  ("b", "c"),
    2173                  ("a", "b", "c"),
    2174              ),
    2175          }
    2176          leftandright1 = {
    2177              "left": ("a",), "required": ("b",), "right": ("c",),
    2178              "expected": (
    2179                  ("b",),
    2180                  ("a", "b"),  # Prefer left.
    2181                  ("a", "b", "c"),
    2182              ),
    2183          }
    2184          leftandright2 = {
    2185              "left": ("a", "b"), "required": ("c", "d"), "right": ("e", "f"),
    2186              "expected": (
    2187                  ("c", "d"),
    2188                  ("b", "c", "d"),       # Prefer left.
    2189                  ("a", "b", "c", "d"),  # Prefer left.
    2190                  ("a", "b", "c", "d", "e"),
    2191                  ("a", "b", "c", "d", "e", "f"),
    2192              ),
    2193          }
    2194          dataset = (
    2195              empty,
    2196              noleft1, noleft2, noleft3,
    2197              noright1, noright2, noright3,
    2198              leftandright1, leftandright2,
    2199          )
    2200          for params in dataset:
    2201              with self.subTest(**params):
    2202                  left, required, right, expected = params.values()
    2203                  permutations = clinic.permute_optional_groups(left, required, right)
    2204                  actual = tuple(permutations)
    2205                  self.assertEqual(actual, expected)
    2206  
    2207  
    2208  class ESC[4;38;5;81mFormatHelperTests(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
    2209  
    2210      def test_strip_leading_and_trailing_blank_lines(self):
    2211          dataset = (
    2212              # Input lines, expected output.
    2213              ("a\nb",            "a\nb"),
    2214              ("a\nb\n",          "a\nb"),
    2215              ("a\nb ",           "a\nb"),
    2216              ("\na\nb\n\n",      "a\nb"),
    2217              ("\n\na\nb\n\n",    "a\nb"),
    2218              ("\n\na\n\nb\n\n",  "a\n\nb"),
    2219              # Note, leading whitespace is preserved:
    2220              (" a\nb",               " a\nb"),
    2221              (" a\nb ",              " a\nb"),
    2222              (" \n \n a\nb \n \n ",  " a\nb"),
    2223          )
    2224          for lines, expected in dataset:
    2225              with self.subTest(lines=lines, expected=expected):
    2226                  out = clinic.strip_leading_and_trailing_blank_lines(lines)
    2227                  self.assertEqual(out, expected)
    2228  
    2229      def test_normalize_snippet(self):
    2230          snippet = """
    2231              one
    2232              two
    2233              three
    2234          """
    2235  
    2236          # Expected outputs:
    2237          zero_indent = (
    2238              "one\n"
    2239              "two\n"
    2240              "three"
    2241          )
    2242          four_indent = (
    2243              "    one\n"
    2244              "    two\n"
    2245              "    three"
    2246          )
    2247          eight_indent = (
    2248              "        one\n"
    2249              "        two\n"
    2250              "        three"
    2251          )
    2252          expected_outputs = {0: zero_indent, 4: four_indent, 8: eight_indent}
    2253          for indent, expected in expected_outputs.items():
    2254              with self.subTest(indent=indent):
    2255                  actual = clinic.normalize_snippet(snippet, indent=indent)
    2256                  self.assertEqual(actual, expected)
    2257  
    2258      def test_accumulator(self):
    2259          acc = clinic.text_accumulator()
    2260          self.assertEqual(acc.output(), "")
    2261          acc.append("a")
    2262          self.assertEqual(acc.output(), "a")
    2263          self.assertEqual(acc.output(), "")
    2264          acc.append("b")
    2265          self.assertEqual(acc.output(), "b")
    2266          self.assertEqual(acc.output(), "")
    2267          acc.append("c")
    2268          acc.append("d")
    2269          self.assertEqual(acc.output(), "cd")
    2270          self.assertEqual(acc.output(), "")
    2271  
    2272      def test_quoted_for_c_string(self):
    2273          dataset = (
    2274              # input,    expected
    2275              (r"abc",    r"abc"),
    2276              (r"\abc",   r"\\abc"),
    2277              (r"\a\bc",  r"\\a\\bc"),
    2278              (r"\a\\bc", r"\\a\\\\bc"),
    2279              (r'"abc"',  r'\"abc\"'),
    2280              (r"'a'",    r"\'a\'"),
    2281          )
    2282          for line, expected in dataset:
    2283              with self.subTest(line=line, expected=expected):
    2284                  out = clinic.quoted_for_c_string(line)
    2285                  self.assertEqual(out, expected)
    2286  
    2287      def test_rstrip_lines(self):
    2288          lines = (
    2289              "a \n"
    2290              "b\n"
    2291              " c\n"
    2292              " d \n"
    2293          )
    2294          expected = (
    2295              "a\n"
    2296              "b\n"
    2297              " c\n"
    2298              " d\n"
    2299          )
    2300          out = clinic.rstrip_lines(lines)
    2301          self.assertEqual(out, expected)
    2302  
    2303      def test_format_escape(self):
    2304          line = "{}, {a}"
    2305          expected = "{{}}, {{a}}"
    2306          out = clinic.format_escape(line)
    2307          self.assertEqual(out, expected)
    2308  
    2309      def test_indent_all_lines(self):
    2310          # Blank lines are expected to be unchanged.
    2311          self.assertEqual(clinic.indent_all_lines("", prefix="bar"), "")
    2312  
    2313          lines = (
    2314              "one\n"
    2315              "two"  # The missing newline is deliberate.
    2316          )
    2317          expected = (
    2318              "barone\n"
    2319              "bartwo"
    2320          )
    2321          out = clinic.indent_all_lines(lines, prefix="bar")
    2322          self.assertEqual(out, expected)
    2323  
    2324          # If last line is empty, expect it to be unchanged.
    2325          lines = (
    2326              "\n"
    2327              "one\n"
    2328              "two\n"
    2329              ""
    2330          )
    2331          expected = (
    2332              "bar\n"
    2333              "barone\n"
    2334              "bartwo\n"
    2335              ""
    2336          )
    2337          out = clinic.indent_all_lines(lines, prefix="bar")
    2338          self.assertEqual(out, expected)
    2339  
    2340      def test_suffix_all_lines(self):
    2341          # Blank lines are expected to be unchanged.
    2342          self.assertEqual(clinic.suffix_all_lines("", suffix="foo"), "")
    2343  
    2344          lines = (
    2345              "one\n"
    2346              "two"  # The missing newline is deliberate.
    2347          )
    2348          expected = (
    2349              "onefoo\n"
    2350              "twofoo"
    2351          )
    2352          out = clinic.suffix_all_lines(lines, suffix="foo")
    2353          self.assertEqual(out, expected)
    2354  
    2355          # If last line is empty, expect it to be unchanged.
    2356          lines = (
    2357              "\n"
    2358              "one\n"
    2359              "two\n"
    2360              ""
    2361          )
    2362          expected = (
    2363              "foo\n"
    2364              "onefoo\n"
    2365              "twofoo\n"
    2366              ""
    2367          )
    2368          out = clinic.suffix_all_lines(lines, suffix="foo")
    2369          self.assertEqual(out, expected)
    2370  
    2371  
    2372  if __name__ == "__main__":
    2373      unittest.main()