python (3.12.0)
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()