@@ -45,6 +45,7 @@ def _expect_failure(tc, parser, code, errmsg, *, filename=None, lineno=None):
45
45
tc .assertEqual (cm .exception .filename , filename )
46
46
if lineno is not None :
47
47
tc .assertEqual (cm .exception .lineno , lineno )
48
+ return cm .exception
48
49
49
50
50
51
class ClinicWholeFileTest (TestCase ):
@@ -222,6 +223,15 @@ def test_directive_output_print(self):
222
223
last_line .startswith ("/*[clinic end generated code: output=" )
223
224
)
224
225
226
+ def test_directive_wrong_arg_number (self ):
227
+ raw = dedent ("""
228
+ /*[clinic input]
229
+ preserve foo bar baz eggs spam ham mushrooms
230
+ [clinic start generated code]*/
231
+ """ )
232
+ err = "takes 1 positional argument but 8 were given"
233
+ self .expect_failure (raw , err )
234
+
225
235
def test_unknown_destination_command (self ):
226
236
raw = """
227
237
/*[clinic input]
@@ -600,6 +610,31 @@ def test_directive_output_invalid_command(self):
600
610
self .expect_failure (block , err , lineno = 2 )
601
611
602
612
613
+ class ParseFileUnitTest (TestCase ):
614
+ def expect_parsing_failure (
615
+ self , * , filename , expected_error , verify = True , output = None
616
+ ):
617
+ errmsg = re .escape (dedent (expected_error ).strip ())
618
+ with self .assertRaisesRegex (clinic .ClinicError , errmsg ):
619
+ clinic .parse_file (filename )
620
+
621
+ def test_parse_file_no_extension (self ) -> None :
622
+ self .expect_parsing_failure (
623
+ filename = "foo" ,
624
+ expected_error = "Can't extract file type for file 'foo'"
625
+ )
626
+
627
+ def test_parse_file_strange_extension (self ) -> None :
628
+ filenames_to_errors = {
629
+ "foo.rs" : "Can't identify file type for file 'foo.rs'" ,
630
+ "foo.hs" : "Can't identify file type for file 'foo.hs'" ,
631
+ "foo.js" : "Can't identify file type for file 'foo.js'" ,
632
+ }
633
+ for filename , errmsg in filenames_to_errors .items ():
634
+ with self .subTest (filename = filename ):
635
+ self .expect_parsing_failure (filename = filename , expected_error = errmsg )
636
+
637
+
603
638
class ClinicGroupPermuterTest (TestCase ):
604
639
def _test (self , l , m , r , output ):
605
640
computed = clinic .permute_optional_groups (l , m , r )
@@ -794,8 +829,8 @@ def parse_function(self, text, signatures_in_block=2, function_index=1):
794
829
return s [function_index ]
795
830
796
831
def expect_failure (self , block , err , * , filename = None , lineno = None ):
797
- _expect_failure (self , self .parse_function , block , err ,
798
- filename = filename , lineno = lineno )
832
+ return _expect_failure (self , self .parse_function , block , err ,
833
+ filename = filename , lineno = lineno )
799
834
800
835
def checkDocstring (self , fn , expected ):
801
836
self .assertTrue (hasattr (fn , "docstring" ))
@@ -877,6 +912,41 @@ def test_param_default_expr_named_constant(self):
877
912
"""
878
913
self .expect_failure (block , err , lineno = 2 )
879
914
915
+ def test_param_with_bizarre_default_fails_correctly (self ):
916
+ template = """
917
+ module os
918
+ os.access
919
+ follow_symlinks: int = {default}
920
+ """
921
+ err = "Unsupported expression as default value"
922
+ for bad_default_value in (
923
+ "{1, 2, 3}" ,
924
+ "3 if bool() else 4" ,
925
+ "[x for x in range(42)]"
926
+ ):
927
+ with self .subTest (bad_default = bad_default_value ):
928
+ block = template .format (default = bad_default_value )
929
+ self .expect_failure (block , err , lineno = 2 )
930
+
931
+ def test_unspecified_not_allowed_as_default_value (self ):
932
+ block = """
933
+ module os
934
+ os.access
935
+ follow_symlinks: int(c_default='MAXSIZE') = unspecified
936
+ """
937
+ err = "'unspecified' is not a legal default value!"
938
+ exc = self .expect_failure (block , err , lineno = 2 )
939
+ self .assertNotIn ('Malformed expression given as default value' , str (exc ))
940
+
941
+ def test_malformed_expression_as_default_value (self ):
942
+ block = """
943
+ module os
944
+ os.access
945
+ follow_symlinks: int(c_default='MAXSIZE') = 1/0
946
+ """
947
+ err = "Malformed expression given as default value"
948
+ self .expect_failure (block , err , lineno = 2 )
949
+
880
950
def test_param_default_expr_binop (self ):
881
951
err = (
882
952
"When you specify an expression ('a + b') as your default value, "
@@ -1041,6 +1111,28 @@ def test_c_name(self):
1041
1111
""" )
1042
1112
self .assertEqual ("os_stat_fn" , function .c_basename )
1043
1113
1114
+ def test_base_invalid_syntax (self ):
1115
+ block = """
1116
+ module os
1117
+ os.stat
1118
+ invalid syntax: int = 42
1119
+ """
1120
+ err = dedent (r"""
1121
+ Function 'stat' has an invalid parameter declaration:
1122
+ \s+'invalid syntax: int = 42'
1123
+ """ ).strip ()
1124
+ with self .assertRaisesRegex (clinic .ClinicError , err ):
1125
+ self .parse_function (block )
1126
+
1127
+ def test_param_default_invalid_syntax (self ):
1128
+ block = """
1129
+ module os
1130
+ os.stat
1131
+ x: int = invalid syntax
1132
+ """
1133
+ err = r"Syntax error: 'x = invalid syntax\n'"
1134
+ self .expect_failure (block , err , lineno = 2 )
1135
+
1044
1136
def test_cloning_nonexistent_function_correctly_fails (self ):
1045
1137
block = """
1046
1138
cloned = fooooooooooooooooo
@@ -1414,18 +1506,6 @@ def test_parameters_required_after_star(self):
1414
1506
with self .subTest (block = block ):
1415
1507
self .expect_failure (block , err )
1416
1508
1417
- def test_parameters_required_after_depr_star (self ):
1418
- dataset = (
1419
- "module foo\n foo.bar\n * [from 3.14]" ,
1420
- "module foo\n foo.bar\n * [from 3.14]\n Docstring here." ,
1421
- "module foo\n foo.bar\n this: int\n * [from 3.14]" ,
1422
- "module foo\n foo.bar\n this: int\n * [from 3.14]\n Docstring." ,
1423
- )
1424
- err = "Function 'foo.bar' specifies '* [from 3.14]' without any parameters afterwards."
1425
- for block in dataset :
1426
- with self .subTest (block = block ):
1427
- self .expect_failure (block , err )
1428
-
1429
1509
def test_depr_star_invalid_format_1 (self ):
1430
1510
block = """
1431
1511
module foo
0 commit comments