blob: a9479a6e44e52c3a1a5f48dcc0f26832d7b3f53b [file] [log] [blame]
Larry Hastings31826802013-10-19 00:09:25 -07001# Argument Clinic
2# Copyright 2012-2013 by Larry Hastings.
3# Licensed to the PSF under a contributor agreement.
4#
5
Larry Hastings31826802013-10-19 00:09:25 -07006import clinic
7from clinic import DSLParser
8import collections
9import inspect
10from test import support
Larry Hastings1abd7082014-01-16 14:15:03 -080011import sys
Larry Hastings31826802013-10-19 00:09:25 -070012import unittest
13from unittest import TestCase
14
Larry Hastings7726ac92014-01-31 22:03:12 -080015
Larry Hastings31826802013-10-19 00:09:25 -070016class FakeConverter:
17 def __init__(self, name, args):
18 self.name = name
19 self.args = args
20
21
22class FakeConverterFactory:
23 def __init__(self, name):
24 self.name = name
25
26 def __call__(self, name, default, **kwargs):
27 return FakeConverter(self.name, kwargs)
28
29
30class FakeConvertersDict:
31 def __init__(self):
32 self.used_converters = {}
33
34 def get(self, name, default):
35 return self.used_converters.setdefault(name, FakeConverterFactory(name))
36
Larry Hastingsbebf7352014-01-17 17:47:17 -080037clinic.Clinic.presets_text = ''
38c = clinic.Clinic(language='C')
39
Larry Hastings31826802013-10-19 00:09:25 -070040class FakeClinic:
41 def __init__(self):
42 self.converters = FakeConvertersDict()
43 self.legacy_converters = FakeConvertersDict()
Larry Hastings7726ac92014-01-31 22:03:12 -080044 self.language = clinic.CLanguage(None)
Larry Hastings31826802013-10-19 00:09:25 -070045 self.filename = None
46 self.block_parser = clinic.BlockParser('', self.language)
47 self.modules = collections.OrderedDict()
Larry Hastings7726ac92014-01-31 22:03:12 -080048 self.classes = collections.OrderedDict()
Larry Hastings31826802013-10-19 00:09:25 -070049 clinic.clinic = self
50 self.name = "FakeClinic"
Larry Hastingsbebf7352014-01-17 17:47:17 -080051 self.line_prefix = self.line_suffix = ''
52 self.destinations = {}
53 self.add_destination("block", "buffer")
54 self.add_destination("file", "buffer")
55 self.add_destination("suppress", "suppress")
56 d = self.destinations.get
57 self.field_destinations = collections.OrderedDict((
58 ('docstring_prototype', d('suppress')),
59 ('docstring_definition', d('block')),
60 ('methoddef_define', d('block')),
61 ('impl_prototype', d('block')),
62 ('parser_prototype', d('suppress')),
63 ('parser_definition', d('block')),
64 ('impl_definition', d('block')),
65 ))
66
67 def get_destination(self, name):
68 d = self.destinations.get(name)
69 if not d:
70 sys.exit("Destination does not exist: " + repr(name))
71 return d
72
73 def add_destination(self, name, type, *args):
74 if name in self.destinations:
75 sys.exit("Destination already exists: " + repr(name))
76 self.destinations[name] = clinic.Destination(name, type, self, *args)
Larry Hastings31826802013-10-19 00:09:25 -070077
78 def is_directive(self, name):
79 return name == "module"
80
81 def directive(self, name, args):
82 self.called_directives[name] = args
83
84 _module_and_class = clinic.Clinic._module_and_class
85
Larry Hastings90261132014-01-07 12:21:08 -080086class ClinicWholeFileTest(TestCase):
87 def test_eol(self):
88 # regression test:
89 # clinic's block parser didn't recognize
90 # the "end line" for the block if it
91 # didn't end in "\n" (as in, the last)
92 # byte of the file was '/'.
Martin Pantereb995702016-07-28 01:11:04 +000093 # so it would spit out an end line for you.
Larry Hastings90261132014-01-07 12:21:08 -080094 # and since you really already had one,
95 # the last line of the block got corrupted.
Larry Hastings7726ac92014-01-31 22:03:12 -080096 c = clinic.Clinic(clinic.CLanguage(None))
Larry Hastings90261132014-01-07 12:21:08 -080097 raw = "/*[clinic]\nfoo\n[clinic]*/"
98 cooked = c.parse(raw).splitlines()
99 end_line = cooked[2].rstrip()
100 # this test is redundant, it's just here explicitly to catch
101 # the regression test so we don't forget what it looked like
102 self.assertNotEqual(end_line, "[clinic]*/[clinic]*/")
103 self.assertEqual(end_line, "[clinic]*/")
104
Larry Hastings31826802013-10-19 00:09:25 -0700105
106
107class ClinicGroupPermuterTest(TestCase):
108 def _test(self, l, m, r, output):
109 computed = clinic.permute_optional_groups(l, m, r)
110 self.assertEqual(output, computed)
111
112 def test_range(self):
113 self._test([['start']], ['stop'], [['step']],
114 (
115 ('stop',),
116 ('start', 'stop',),
117 ('start', 'stop', 'step',),
118 ))
119
120 def test_add_window(self):
121 self._test([['x', 'y']], ['ch'], [['attr']],
122 (
123 ('ch',),
124 ('ch', 'attr'),
125 ('x', 'y', 'ch',),
126 ('x', 'y', 'ch', 'attr'),
127 ))
128
129 def test_ludicrous(self):
130 self._test([['a1', 'a2', 'a3'], ['b1', 'b2']], ['c1'], [['d1', 'd2'], ['e1', 'e2', 'e3']],
131 (
132 ('c1',),
133 ('b1', 'b2', 'c1'),
134 ('b1', 'b2', 'c1', 'd1', 'd2'),
135 ('a1', 'a2', 'a3', 'b1', 'b2', 'c1'),
136 ('a1', 'a2', 'a3', 'b1', 'b2', 'c1', 'd1', 'd2'),
137 ('a1', 'a2', 'a3', 'b1', 'b2', 'c1', 'd1', 'd2', 'e1', 'e2', 'e3'),
138 ))
139
140 def test_right_only(self):
141 self._test([], [], [['a'],['b'],['c']],
142 (
143 (),
144 ('a',),
145 ('a', 'b'),
146 ('a', 'b', 'c')
147 ))
148
149 def test_have_left_options_but_required_is_empty(self):
150 def fn():
151 clinic.permute_optional_groups(['a'], [], [])
152 self.assertRaises(AssertionError, fn)
153
154
155class ClinicLinearFormatTest(TestCase):
156 def _test(self, input, output, **kwargs):
157 computed = clinic.linear_format(input, **kwargs)
158 self.assertEqual(output, computed)
159
160 def test_empty_strings(self):
161 self._test('', '')
162
163 def test_solo_newline(self):
164 self._test('\n', '\n')
165
166 def test_no_substitution(self):
167 self._test("""
168 abc
169 """, """
170 abc
171 """)
172
173 def test_empty_substitution(self):
174 self._test("""
175 abc
176 {name}
177 def
178 """, """
179 abc
180 def
181 """, name='')
182
183 def test_single_line_substitution(self):
184 self._test("""
185 abc
186 {name}
187 def
188 """, """
189 abc
190 GARGLE
191 def
192 """, name='GARGLE')
193
194 def test_multiline_substitution(self):
195 self._test("""
196 abc
197 {name}
198 def
199 """, """
200 abc
201 bingle
202 bungle
203
204 def
205 """, name='bingle\nbungle\n')
206
207class InertParser:
208 def __init__(self, clinic):
209 pass
210
211 def parse(self, block):
212 pass
213
214class CopyParser:
215 def __init__(self, clinic):
216 pass
217
218 def parse(self, block):
219 block.output = block.input
220
221
222class ClinicBlockParserTest(TestCase):
223 def _test(self, input, output):
Larry Hastings7726ac92014-01-31 22:03:12 -0800224 language = clinic.CLanguage(None)
Larry Hastings31826802013-10-19 00:09:25 -0700225
226 blocks = list(clinic.BlockParser(input, language))
227 writer = clinic.BlockPrinter(language)
228 for block in blocks:
229 writer.print_block(block)
230 output = writer.f.getvalue()
231 assert output == input, "output != input!\n\noutput " + repr(output) + "\n\n input " + repr(input)
232
233 def round_trip(self, input):
234 return self._test(input, input)
235
236 def test_round_trip_1(self):
237 self.round_trip("""
238 verbatim text here
239 lah dee dah
240""")
241 def test_round_trip_2(self):
242 self.round_trip("""
243 verbatim text here
244 lah dee dah
245/*[inert]
246abc
247[inert]*/
248def
249/*[inert checksum: 7b18d017f89f61cf17d47f92749ea6930a3f1deb]*/
250xyz
251""")
252
253 def _test_clinic(self, input, output):
Larry Hastings7726ac92014-01-31 22:03:12 -0800254 language = clinic.CLanguage(None)
Larry Hastings31826802013-10-19 00:09:25 -0700255 c = clinic.Clinic(language)
256 c.parsers['inert'] = InertParser(c)
257 c.parsers['copy'] = CopyParser(c)
258 computed = c.parse(input)
259 self.assertEqual(output, computed)
260
261 def test_clinic_1(self):
262 self._test_clinic("""
263 verbatim text here
264 lah dee dah
Larry Hastings2a727912014-01-16 11:32:01 -0800265/*[copy input]
Larry Hastings31826802013-10-19 00:09:25 -0700266def
Larry Hastings2a727912014-01-16 11:32:01 -0800267[copy start generated code]*/
Larry Hastings31826802013-10-19 00:09:25 -0700268abc
Larry Hastings7726ac92014-01-31 22:03:12 -0800269/*[copy end generated code: output=03cfd743661f0797 input=7b18d017f89f61cf]*/
Larry Hastings31826802013-10-19 00:09:25 -0700270xyz
271""", """
272 verbatim text here
273 lah dee dah
Larry Hastings2a727912014-01-16 11:32:01 -0800274/*[copy input]
Larry Hastings31826802013-10-19 00:09:25 -0700275def
Larry Hastings2a727912014-01-16 11:32:01 -0800276[copy start generated code]*/
Larry Hastings31826802013-10-19 00:09:25 -0700277def
Larry Hastings7726ac92014-01-31 22:03:12 -0800278/*[copy end generated code: output=7b18d017f89f61cf input=7b18d017f89f61cf]*/
Larry Hastings31826802013-10-19 00:09:25 -0700279xyz
280""")
281
282
283class ClinicParserTest(TestCase):
284 def test_trivial(self):
285 parser = DSLParser(FakeClinic())
286 block = clinic.Block("module os\nos.access")
287 parser.parse(block)
288 module, function = block.signatures
289 self.assertEqual("access", function.name)
290 self.assertEqual("os", module.name)
291
292 def test_ignore_line(self):
293 block = self.parse("#\nmodule os\nos.access")
294 module, function = block.signatures
295 self.assertEqual("access", function.name)
296 self.assertEqual("os", module.name)
297
298 def test_param(self):
299 function = self.parse_function("module os\nos.access\n path: int")
300 self.assertEqual("access", function.name)
Larry Hastings7726ac92014-01-31 22:03:12 -0800301 self.assertEqual(2, len(function.parameters))
Larry Hastings31826802013-10-19 00:09:25 -0700302 p = function.parameters['path']
303 self.assertEqual('path', p.name)
304 self.assertIsInstance(p.converter, clinic.int_converter)
305
306 def test_param_default(self):
307 function = self.parse_function("module os\nos.access\n follow_symlinks: bool = True")
308 p = function.parameters['follow_symlinks']
309 self.assertEqual(True, p.default)
310
Larry Hastings1abd7082014-01-16 14:15:03 -0800311 def test_param_with_continuations(self):
312 function = self.parse_function("module os\nos.access\n follow_symlinks: \\\n bool \\\n =\\\n True")
313 p = function.parameters['follow_symlinks']
314 self.assertEqual(True, p.default)
315
316 def test_param_default_expression(self):
317 function = self.parse_function("module os\nos.access\n follow_symlinks: int(c_default='MAXSIZE') = sys.maxsize")
318 p = function.parameters['follow_symlinks']
319 self.assertEqual(sys.maxsize, p.default)
320 self.assertEqual("MAXSIZE", p.converter.c_default)
321
322 s = self.parse_function_should_fail("module os\nos.access\n follow_symlinks: int = sys.maxsize")
323 self.assertEqual(s, "Error on line 0:\nWhen you specify a named constant ('sys.maxsize') as your default value,\nyou MUST specify a valid c_default.\n")
324
Larry Hastings31826802013-10-19 00:09:25 -0700325 def test_param_no_docstring(self):
326 function = self.parse_function("""
327module os
328os.access
329 follow_symlinks: bool = True
Larry Hastings7726ac92014-01-31 22:03:12 -0800330 something_else: str = ''""")
Larry Hastings31826802013-10-19 00:09:25 -0700331 p = function.parameters['follow_symlinks']
Larry Hastings7726ac92014-01-31 22:03:12 -0800332 self.assertEqual(3, len(function.parameters))
Larry Hastings31826802013-10-19 00:09:25 -0700333 self.assertIsInstance(function.parameters['something_else'].converter, clinic.str_converter)
334
Larry Hastings7726ac92014-01-31 22:03:12 -0800335 def test_param_default_parameters_out_of_order(self):
336 s = self.parse_function_should_fail("""
337module os
338os.access
339 follow_symlinks: bool = True
340 something_else: str""")
341 self.assertEqual(s, """Error on line 0:
342Can't have a parameter without a default ('something_else')
343after a parameter with a default!
344""")
345
Larry Hastings31826802013-10-19 00:09:25 -0700346 def disabled_test_converter_arguments(self):
347 function = self.parse_function("module os\nos.access\n path: path_t(allow_fd=1)")
348 p = function.parameters['path']
349 self.assertEqual(1, p.converter.args['allow_fd'])
350
Larry Hastings31826802013-10-19 00:09:25 -0700351 def test_function_docstring(self):
352 function = self.parse_function("""
353module os
354os.stat as os_stat_fn
355
356 path: str
357 Path to be examined
358
359Perform a stat system call on the given path.""")
360 self.assertEqual("""
Larry Hastings2623c8c2014-02-08 22:15:29 -0800361stat($module, /, path)
362--
363
Larry Hastings31826802013-10-19 00:09:25 -0700364Perform a stat system call on the given path.
365
Larry Hastings31826802013-10-19 00:09:25 -0700366 path
367 Path to be examined
368""".strip(), function.docstring)
369
370 def test_explicit_parameters_in_docstring(self):
371 function = self.parse_function("""
372module foo
373foo.bar
374 x: int
375 Documentation for x.
376 y: int
377
378This is the documentation for foo.
379
380Okay, we're done here.
381""")
382 self.assertEqual("""
Larry Hastings2623c8c2014-02-08 22:15:29 -0800383bar($module, /, x, y)
384--
385
Larry Hastings31826802013-10-19 00:09:25 -0700386This is the documentation for foo.
387
Larry Hastings31826802013-10-19 00:09:25 -0700388 x
389 Documentation for x.
390
391Okay, we're done here.
392""".strip(), function.docstring)
393
394 def test_parser_regression_special_character_in_parameter_column_of_docstring_first_line(self):
395 function = self.parse_function("""
396module os
397os.stat
398 path: str
399This/used to break Clinic!
400""")
Larry Hastings2623c8c2014-02-08 22:15:29 -0800401 self.assertEqual("stat($module, /, path)\n--\n\nThis/used to break Clinic!", function.docstring)
Larry Hastings31826802013-10-19 00:09:25 -0700402
403 def test_c_name(self):
404 function = self.parse_function("module os\nos.stat as os_stat_fn")
405 self.assertEqual("os_stat_fn", function.c_basename)
406
407 def test_return_converter(self):
408 function = self.parse_function("module os\nos.stat -> int")
409 self.assertIsInstance(function.return_converter, clinic.int_return_converter)
410
411 def test_star(self):
412 function = self.parse_function("module os\nos.access\n *\n follow_symlinks: bool = True")
413 p = function.parameters['follow_symlinks']
414 self.assertEqual(inspect.Parameter.KEYWORD_ONLY, p.kind)
415 self.assertEqual(0, p.group)
416
417 def test_group(self):
418 function = self.parse_function("module window\nwindow.border\n [\n ls : int\n ]\n /\n")
419 p = function.parameters['ls']
420 self.assertEqual(1, p.group)
421
422 def test_left_group(self):
423 function = self.parse_function("""
424module curses
Larry Hastings6d2ea212014-01-05 02:50:45 -0800425curses.addch
Larry Hastings31826802013-10-19 00:09:25 -0700426 [
427 y: int
428 Y-coordinate.
429 x: int
430 X-coordinate.
431 ]
432 ch: char
433 Character to add.
434 [
435 attr: long
436 Attributes for the character.
437 ]
438 /
439""")
440 for name, group in (
441 ('y', -1), ('x', -1),
442 ('ch', 0),
443 ('attr', 1),
444 ):
445 p = function.parameters[name]
446 self.assertEqual(p.group, group)
447 self.assertEqual(p.kind, inspect.Parameter.POSITIONAL_ONLY)
448 self.assertEqual(function.docstring.strip(), """
Larry Hastings6d2ea212014-01-05 02:50:45 -0800449addch([y, x,] ch, [attr])
450
451
Larry Hastings31826802013-10-19 00:09:25 -0700452 y
453 Y-coordinate.
454 x
455 X-coordinate.
456 ch
457 Character to add.
458 attr
459 Attributes for the character.
460 """.strip())
461
462 def test_nested_groups(self):
463 function = self.parse_function("""
464module curses
Larry Hastings6d2ea212014-01-05 02:50:45 -0800465curses.imaginary
Larry Hastings31826802013-10-19 00:09:25 -0700466 [
467 [
468 y1: int
469 Y-coordinate.
470 y2: int
471 Y-coordinate.
472 ]
473 x1: int
474 X-coordinate.
475 x2: int
476 X-coordinate.
477 ]
478 ch: char
479 Character to add.
480 [
481 attr1: long
482 Attributes for the character.
483 attr2: long
484 Attributes for the character.
485 attr3: long
486 Attributes for the character.
487 [
488 attr4: long
489 Attributes for the character.
490 attr5: long
491 Attributes for the character.
492 attr6: long
493 Attributes for the character.
494 ]
495 ]
496 /
497""")
498 for name, group in (
499 ('y1', -2), ('y2', -2),
500 ('x1', -1), ('x2', -1),
501 ('ch', 0),
502 ('attr1', 1), ('attr2', 1), ('attr3', 1),
503 ('attr4', 2), ('attr5', 2), ('attr6', 2),
504 ):
505 p = function.parameters[name]
506 self.assertEqual(p.group, group)
507 self.assertEqual(p.kind, inspect.Parameter.POSITIONAL_ONLY)
508
509 self.assertEqual(function.docstring.strip(), """
Larry Hastings2623c8c2014-02-08 22:15:29 -0800510imaginary([[y1, y2,] x1, x2,] ch, [attr1, attr2, attr3, [attr4, attr5,
511 attr6]])
Larry Hastings6d2ea212014-01-05 02:50:45 -0800512
513
Larry Hastings31826802013-10-19 00:09:25 -0700514 y1
515 Y-coordinate.
516 y2
517 Y-coordinate.
518 x1
519 X-coordinate.
520 x2
521 X-coordinate.
522 ch
523 Character to add.
524 attr1
525 Attributes for the character.
526 attr2
527 Attributes for the character.
528 attr3
529 Attributes for the character.
530 attr4
531 Attributes for the character.
532 attr5
533 Attributes for the character.
534 attr6
535 Attributes for the character.
536 """.strip())
537
538 def parse_function_should_fail(self, s):
539 with support.captured_stdout() as stdout:
540 with self.assertRaises(SystemExit):
541 self.parse_function(s)
542 return stdout.getvalue()
543
544 def test_disallowed_grouping__two_top_groups_on_left(self):
545 s = self.parse_function_should_fail("""
546module foo
547foo.two_top_groups_on_left
548 [
549 group1 : int
550 ]
551 [
552 group2 : int
553 ]
554 param: int
555 """)
556 self.assertEqual(s,
557 ('Error on line 0:\n'
Larry Hastings7726ac92014-01-31 22:03:12 -0800558 'Function two_top_groups_on_left has an unsupported group configuration. (Unexpected state 2.b)\n'))
Larry Hastings31826802013-10-19 00:09:25 -0700559
560 def test_disallowed_grouping__two_top_groups_on_right(self):
561 self.parse_function_should_fail("""
562module foo
563foo.two_top_groups_on_right
564 param: int
565 [
566 group1 : int
567 ]
568 [
569 group2 : int
570 ]
571 """)
572
573 def test_disallowed_grouping__parameter_after_group_on_right(self):
574 self.parse_function_should_fail("""
575module foo
576foo.parameter_after_group_on_right
577 param: int
578 [
579 [
580 group1 : int
581 ]
582 group2 : int
583 ]
584 """)
585
586 def test_disallowed_grouping__group_after_parameter_on_left(self):
587 self.parse_function_should_fail("""
588module foo
589foo.group_after_parameter_on_left
590 [
591 group2 : int
592 [
593 group1 : int
594 ]
595 ]
596 param: int
597 """)
598
599 def test_disallowed_grouping__empty_group_on_left(self):
600 self.parse_function_should_fail("""
601module foo
602foo.empty_group
603 [
604 [
605 ]
606 group2 : int
607 ]
608 param: int
609 """)
610
611 def test_disallowed_grouping__empty_group_on_right(self):
612 self.parse_function_should_fail("""
613module foo
614foo.empty_group
615 param: int
616 [
617 [
618 ]
619 group2 : int
620 ]
621 """)
622
623 def test_no_parameters(self):
624 function = self.parse_function("""
625module foo
626foo.bar
627
628Docstring
629
630""")
Larry Hastings2623c8c2014-02-08 22:15:29 -0800631 self.assertEqual("bar($module, /)\n--\n\nDocstring", function.docstring)
Larry Hastings7726ac92014-01-31 22:03:12 -0800632 self.assertEqual(1, len(function.parameters)) # self!
Larry Hastings31826802013-10-19 00:09:25 -0700633
Larry Hastings2623c8c2014-02-08 22:15:29 -0800634 def test_init_with_no_parameters(self):
635 function = self.parse_function("""
636module foo
637class foo.Bar "unused" "notneeded"
638foo.Bar.__init__
639
640Docstring
641
642""", signatures_in_block=3, function_index=2)
643 # self is not in the signature
644 self.assertEqual("Bar()\n--\n\nDocstring", function.docstring)
645 # but it *is* a parameter
646 self.assertEqual(1, len(function.parameters))
647
Larry Hastingsdfcd4672013-10-27 02:49:39 -0700648 def test_illegal_module_line(self):
649 self.parse_function_should_fail("""
650module foo
651foo.bar => int
652 /
653""")
654
655 def test_illegal_c_basename(self):
656 self.parse_function_should_fail("""
657module foo
658foo.bar as 935
659 /
660""")
661
Larry Hastings31826802013-10-19 00:09:25 -0700662 def test_single_star(self):
663 self.parse_function_should_fail("""
664module foo
665foo.bar
666 *
667 *
668""")
669
670 def test_parameters_required_after_star_without_initial_parameters_or_docstring(self):
671 self.parse_function_should_fail("""
672module foo
673foo.bar
674 *
675""")
676
677 def test_parameters_required_after_star_without_initial_parameters_with_docstring(self):
678 self.parse_function_should_fail("""
679module foo
680foo.bar
681 *
682Docstring here.
683""")
684
685 def test_parameters_required_after_star_with_initial_parameters_without_docstring(self):
686 self.parse_function_should_fail("""
687module foo
688foo.bar
689 this: int
690 *
691""")
692
693 def test_parameters_required_after_star_with_initial_parameters_and_docstring(self):
694 self.parse_function_should_fail("""
695module foo
696foo.bar
697 this: int
698 *
699Docstring.
700""")
701
702 def test_single_slash(self):
703 self.parse_function_should_fail("""
704module foo
705foo.bar
706 /
707 /
708""")
709
710 def test_mix_star_and_slash(self):
711 self.parse_function_should_fail("""
712module foo
713foo.bar
714 x: int
715 y: int
716 *
717 z: int
718 /
719""")
720
721 def test_parameters_not_permitted_after_slash_for_now(self):
722 self.parse_function_should_fail("""
723module foo
724foo.bar
725 /
726 x: int
727""")
728
729 def test_function_not_at_column_0(self):
730 function = self.parse_function("""
731 module foo
732 foo.bar
733 x: int
734 Nested docstring here, goeth.
735 *
736 y: str
737 Not at column 0!
738""")
739 self.assertEqual("""
Larry Hastings2623c8c2014-02-08 22:15:29 -0800740bar($module, /, x, *, y)
741--
742
Larry Hastings31826802013-10-19 00:09:25 -0700743Not at column 0!
744
Larry Hastings31826802013-10-19 00:09:25 -0700745 x
746 Nested docstring here, goeth.
747""".strip(), function.docstring)
748
Larry Hastings31826802013-10-19 00:09:25 -0700749 def test_directive(self):
750 c = FakeClinic()
751 parser = DSLParser(c)
752 parser.flag = False
753 parser.directives['setflag'] = lambda : setattr(parser, 'flag', True)
754 block = clinic.Block("setflag")
755 parser.parse(block)
756 self.assertTrue(parser.flag)
757
758 def test_legacy_converters(self):
759 block = self.parse('module os\nos.access\n path: "s"')
760 module, function = block.signatures
761 self.assertIsInstance((function.parameters['path']).converter, clinic.str_converter)
762
763 def parse(self, text):
764 c = FakeClinic()
765 parser = DSLParser(c)
766 block = clinic.Block(text)
767 parser.parse(block)
768 return block
769
Larry Hastings2623c8c2014-02-08 22:15:29 -0800770 def parse_function(self, text, signatures_in_block=2, function_index=1):
Larry Hastings31826802013-10-19 00:09:25 -0700771 block = self.parse(text)
772 s = block.signatures
Larry Hastings2623c8c2014-02-08 22:15:29 -0800773 self.assertEqual(len(s), signatures_in_block)
Larry Hastings31826802013-10-19 00:09:25 -0700774 assert isinstance(s[0], clinic.Module)
Larry Hastings2623c8c2014-02-08 22:15:29 -0800775 assert isinstance(s[function_index], clinic.Function)
776 return s[function_index]
Larry Hastings31826802013-10-19 00:09:25 -0700777
778 def test_scaffolding(self):
779 # test repr on special values
780 self.assertEqual(repr(clinic.unspecified), '<Unspecified>')
781 self.assertEqual(repr(clinic.NULL), '<Null>')
782
783 # test that fail fails
784 with support.captured_stdout() as stdout:
785 with self.assertRaises(SystemExit):
786 clinic.fail('The igloos are melting!', filename='clown.txt', line_number=69)
787 self.assertEqual(stdout.getvalue(), 'Error in file "clown.txt" on line 69:\nThe igloos are melting!\n')
788
789
790if __name__ == "__main__":
791 unittest.main()