@@ -69,7 +69,7 @@ def getCharFromStdin() -> str:
69
69
re .compile (R'^// -> (?P<method>[\w\/]+) {' ),
70
70
re .compile (R'(?P<tag>"@\w+")' ),
71
71
re .compile (R'(?P<tag>@\w+)' ),
72
- re .compile (R'// (?P<testname>\w +):[ ]? (?P<diagnostics>[\w @]*)' ),
72
+ re .compile (R'// (?P<testname>\S +):( [ ](?P<diagnostics>[\w @]*))? ' ),
73
73
re .compile (R'(?P<tag>@\w+) (?P<code>\d\d\d\d)' )
74
74
)
75
75
@@ -86,7 +86,7 @@ def split_path(path):
86
86
"""
87
87
Return the test name and the subdir path of the given path.
88
88
"""
89
- sub_dir_separator = path .find ("/" )
89
+ sub_dir_separator = path .rfind ("/" )
90
90
91
91
if sub_dir_separator == - 1 :
92
92
return (path , None )
@@ -105,7 +105,8 @@ def count_index(lines, start=0):
105
105
106
106
def tags_only (lines , start = 0 ):
107
107
"""
108
- Filter the lines for tag comments and report line number that tags refer to.
108
+ Filter the lines for tag comments and report the line number that the tags
109
+ _refer_ to (which is not the line they are on!).
109
110
"""
110
111
n = start
111
112
numCommentLines = 0
@@ -272,27 +273,34 @@ def create_cli_parser() -> argparse.ArgumentParser:
272
273
parser = argparse .ArgumentParser (description = "Solidity LSP Test suite" )
273
274
parser .set_defaults (fail_fast = False )
274
275
parser .add_argument (
275
- "-f, --fail-fast" ,
276
+ "-f" , " --fail-fast" ,
276
277
dest = "fail_fast" ,
277
278
action = "store_true" ,
278
279
help = "Terminates the running tests on first failure."
279
280
)
281
+ parser .set_defaults (non_interactive = False )
282
+ parser .add_argument (
283
+ "-n" , "--non-interactive" ,
284
+ dest = "non_interactive" ,
285
+ action = "store_true" ,
286
+ help = "Prevent interactive queries and just fail instead."
287
+ )
280
288
parser .set_defaults (trace_io = False )
281
289
parser .add_argument (
282
- "-T, --trace-io" ,
290
+ "-T" , " --trace-io" ,
283
291
dest = "trace_io" ,
284
292
action = "store_true" ,
285
293
help = "Be more verbose by also printing assertions."
286
294
)
287
295
parser .set_defaults (print_assertions = False )
288
296
parser .add_argument (
289
- "-v, --print-assertions" ,
297
+ "-v" , " --print-assertions" ,
290
298
dest = "print_assertions" ,
291
299
action = "store_true" ,
292
300
help = "Be more verbose by also printing assertions."
293
301
)
294
302
parser .add_argument (
295
- "-t, --test-pattern" ,
303
+ "-t" , " --test-pattern" ,
296
304
dest = "test_pattern" ,
297
305
type = str ,
298
306
default = "*" ,
@@ -405,11 +413,13 @@ def parseDiagnostics(self):
405
413
406
414
testDiagnostics = []
407
415
408
- for diagnosticMatch in TEST_REGEXES .diagnostic .finditer (fileDiagMatch .group ("diagnostics" )):
409
- testDiagnostics .append (self .Diagnostic (
410
- diagnosticMatch .group ("tag" ),
411
- int (diagnosticMatch .group ("code" ))
412
- ))
416
+ diagnostics_string = fileDiagMatch .group ("diagnostics" )
417
+ if diagnostics_string is not None :
418
+ for diagnosticMatch in TEST_REGEXES .diagnostic .finditer (diagnostics_string ):
419
+ testDiagnostics .append (self .Diagnostic (
420
+ diagnosticMatch .group ("tag" ),
421
+ int (diagnosticMatch .group ("code" ))
422
+ ))
413
423
414
424
diagnostics ["tests" ][fileDiagMatch .group ("testname" )] = testDiagnostics
415
425
@@ -537,11 +547,11 @@ def test_diagnostics(self):
537
547
self .expected_diagnostics = next (self .parsed_testcases )
538
548
assert isinstance (self .expected_diagnostics , TestParser .Diagnostics ) is True
539
549
540
- tests = self .expected_diagnostics .tests
550
+ expected_diagnostics_per_file = self .expected_diagnostics .tests
541
551
542
552
# Add our own test diagnostics if they didn't exist
543
- if self .test_name not in tests :
544
- tests [self .test_name ] = []
553
+ if self .test_name not in expected_diagnostics_per_file :
554
+ expected_diagnostics_per_file [self .test_name ] = []
545
555
546
556
published_diagnostics = \
547
557
self .suite .open_file_and_wait_for_diagnostics (self .solc , self .test_name , self .sub_dir )
@@ -551,25 +561,27 @@ def test_diagnostics(self):
551
561
raise Exception (
552
562
f"'{ self .test_name } .sol' imported file outside of test directory: '{ diagnostics ['uri' ]} '"
553
563
)
554
- self .open_tests .append (diagnostics [ "uri" ]. replace ( self .suite .project_root_uri + "/" , "" )[: - len ( ".sol" )] )
564
+ self .open_tests .append (self .suite .normalizeUri ( diagnostics [ "uri" ]) )
555
565
556
566
self .suite .expect_equal (
557
567
len (published_diagnostics ),
558
- len (tests ),
568
+ len (expected_diagnostics_per_file ),
559
569
description = "Amount of reports does not match!" )
560
570
561
- for diagnostics in published_diagnostics :
562
- testname_and_subdir = diagnostics ["uri" ].replace (self .suite .project_root_uri + "/" , "" )[:- len (".sol" )]
563
- testname , sub_dir = split_path (testname_and_subdir )
571
+ for diagnostics_per_file in published_diagnostics :
572
+ testname , sub_dir = split_path (self .suite .normalizeUri (diagnostics_per_file ['uri' ]))
573
+
574
+ # Clear all processed expectations so we can check at the end
575
+ # what's missing
576
+ expected_diagnostics = expected_diagnostics_per_file .pop (testname , {})
564
577
565
- expected_diagnostics = tests [testname ]
566
578
self .suite .expect_equal (
567
- len (diagnostics ["diagnostics" ]),
579
+ len (diagnostics_per_file ["diagnostics" ]),
568
580
len (expected_diagnostics ),
569
581
description = "Unexpected amount of diagnostics"
570
582
)
571
583
markers = self .suite .get_file_tags (testname , sub_dir )
572
- for actual_diagnostic in diagnostics ["diagnostics" ]:
584
+ for actual_diagnostic in diagnostics_per_file ["diagnostics" ]:
573
585
expected_diagnostic = next ((diagnostic for diagnostic in
574
586
expected_diagnostics if actual_diagnostic ['range' ] ==
575
587
markers [diagnostic .marker ]), None )
@@ -586,6 +598,12 @@ def test_diagnostics(self):
586
598
marker = markers [expected_diagnostic .marker ]
587
599
)
588
600
601
+ if len (expected_diagnostics_per_file ) > 0 :
602
+ raise ExpectationFailed (
603
+ f"Expected diagnostics but received none for { expected_diagnostics_per_file } " ,
604
+ ExpectationFailed .Part .Diagnostics
605
+ )
606
+
589
607
except Exception :
590
608
self .close_all_open_files ()
591
609
raise
@@ -759,6 +777,7 @@ def __init__(self):
759
777
self .trace_io = args .trace_io
760
778
self .test_pattern = args .test_pattern
761
779
self .fail_fast = args .fail_fast
780
+ self .non_interactive = args .non_interactive
762
781
763
782
print (f"{ SGR_NOTICE } test pattern: { self .test_pattern } { SGR_RESET } " )
764
783
@@ -773,6 +792,9 @@ def main(self) -> int:
773
792
if callable (getattr (SolidityLSPTestSuite , name )) and name .startswith ("test_" )
774
793
])
775
794
filtered_tests = fnmatch .filter (all_tests , self .test_pattern )
795
+ if filtered_tests .count ("generic" ) == 0 :
796
+ filtered_tests .append ("generic" )
797
+
776
798
for method_name in filtered_tests :
777
799
test_fn = getattr (self , 'test_' + method_name )
778
800
title : str = test_fn .__name__ [5 :]
@@ -889,22 +911,25 @@ def wait_for_diagnostics(self, solc: JsonRpcProcess) -> List[dict]:
889
911
890
912
return sorted (reports , key = lambda x : x ['uri' ])
891
913
914
+ def normalizeUri (self , uri ):
915
+ return uri .replace (self .project_root_uri + "/" , "" )[:- len (".sol" )]
916
+
892
917
def fetch_and_format_diagnostics (self , solc : JsonRpcProcess , test , sub_dir = None ):
893
918
expectations = ""
894
919
895
920
published_diagnostics = self .open_file_and_wait_for_diagnostics (solc , test , sub_dir )
896
921
897
- for diagnostics in published_diagnostics :
898
- testname = diagnostics [ "uri" ]. replace ( f" { self .project_root_uri } / { sub_dir } /" , "" )[: - len ( ".sol" )]
922
+ for file_diagnostics in published_diagnostics :
923
+ testname , local_sub_dir = split_path ( self .normalizeUri ( file_diagnostics [ "uri" ]))
899
924
900
925
# Skip empty diagnostics within the same file
901
- if len (diagnostics ["diagnostics" ]) == 0 and testname == test :
926
+ if len (file_diagnostics ["diagnostics" ]) == 0 and testname == test :
902
927
continue
903
928
904
929
expectations += f"// { testname } :"
905
930
906
- for diagnostic in diagnostics ["diagnostics" ]:
907
- tag = self .find_tag_with_range (testname , sub_dir , diagnostic ['range' ])
931
+ for diagnostic in file_diagnostics ["diagnostics" ]:
932
+ tag = self .find_tag_with_range (testname , local_sub_dir , diagnostic ['range' ])
908
933
909
934
if tag is None :
910
935
raise Exception (f"No tag found for diagnostic range { diagnostic ['range' ]} " )
@@ -1121,6 +1146,11 @@ def user_interaction_failed_diagnostics(
1121
1146
Asks the user how to proceed after an error.
1122
1147
Returns True if the test/file should be ignored, otherwise False
1123
1148
"""
1149
+
1150
+ # Prevent user interaction when in non-interactive mode
1151
+ if self .non_interactive :
1152
+ return False
1153
+
1124
1154
while True :
1125
1155
print ("(u)pdate/(r)etry/(s)kip file?" )
1126
1156
user_response = getCharFromStdin ()
@@ -1324,10 +1354,15 @@ def test_generic(self, solc: JsonRpcProcess) -> None:
1324
1354
1325
1355
for sub_dir in map (lambda filepath : filepath .name , sub_dirs ):
1326
1356
tests = map (
1327
- lambda filename : filename [:- len (".sol" )],
1357
+ lambda filename , sd = sub_dir : sd + "/" + filename [:- len (".sol" )],
1328
1358
os .listdir (f"{ self .project_root_dir } /{ sub_dir } " )
1329
1359
)
1330
1360
1361
+ tests = map (
1362
+ lambda path , sd = sub_dir : path [len (sd )+ 1 :],
1363
+ fnmatch .filter (tests , self .test_pattern )
1364
+ )
1365
+
1331
1366
print (f"Running tests in subdirectory '{ sub_dir } '..." )
1332
1367
for test in tests :
1333
1368
try_again = True
0 commit comments