1111import subprocess
1212import sys
1313import tempfile
14- from typing import Iterable , List
14+ from typing import Callable , Iterable
1515
1616reOPT = re .compile (r"^opt([0-9]+)_" ) # To detect -On tests
1717reBIN = re .compile (r"^(?:.*/)?(tzx|tap)_.*" ) # To detect tzx / tap test
4242CLOSE_STDERR = False # Whether to show compiler error or not (usually not when doing tests)
4343PRINT_DIFF = False # Will show diff on test failure
4444VIM_DIFF = False # Will show visual diff using (g?)vimdiff on test failure
45- UPDATE = False # True and test will be updated on failure
45+ UPDATE : bool = False # True and test will be updated on failure
4646FOUT = sys .stdout # Output file. By default stdout but can be captured changing this
47- TEMP_DIR = None
47+ TEMP_DIR : str = ""
4848QUIET = False # True so suppress output (useful for testing)
4949DEFAULT_STDERR = "/dev/stderr"
50- STDERR = None
50+ STDERR : str = ""
5151INLINE = True # Set to false to use system Shell
5252RAISE_EXCEPTIONS = False # True if we want the testing to abort on compiler crashes
5353TIMEOUT = 3 # Max number of seconds a test should last
@@ -61,10 +61,10 @@ class TempTestFile(object):
6161 ensures file deletion upon return.
6262 """
6363
64- def __init__ (self , func , fname , keep_file = False ):
65- """Initializes the context. The flag dont_remove will only be taken into account
66- if the System command execution was successful (returns 0)
67- :param syscmd: System command to execute
64+ def __init__ (self , func : Callable [[], int ], fname : str , * , keep_file : bool = False ):
65+ """Initializes the context. The flag keep_file will be taken into account
66+ only if the System command execution was successful (returns 0)
67+ :param func: Function to execute
6868 :param fname: Temporary file to remove
6969 :param keep_file: Don't delete the file on command success (useful for debug or updating)
7070 """
@@ -93,7 +93,7 @@ def __exit__(self, type_, value, traceback):
9393 pass # Ok. It might be that it wasn't created
9494
9595
96- def _error (msg , exit_code = None ):
96+ def _error (msg : str , exit_code : int | None = None ) -> None :
9797 """Shows an error msg to sys.stderr and optionally
9898 exits if exit code is not None
9999 """
@@ -102,20 +102,20 @@ def _error(msg, exit_code=None):
102102 exit (exit_code )
103103
104104
105- def _msg (msg , force = False ):
105+ def _msg (msg : str , * , force : bool = False ) -> None :
106106 """Shows a msg to the FOUT output if not in QUIET mode or force == True"""
107107 if not QUIET or force :
108108 FOUT .write (msg )
109109
110110
111111def get_file_lines (
112112 filename : str ,
113- ignore_regexp = None ,
114- replace_regexp = None ,
113+ ignore_regexp : str | None = None ,
114+ replace_regexp : str | None = None ,
115115 replace_what : str = "." ,
116116 replace_with : str = "." ,
117117 strip_blanks : bool = True ,
118- ) -> List [str ]:
118+ ) -> list [str ]:
119119 """Opens source file <filename> and load its lines,
120120 discarding those not important for comparison.
121121 """
@@ -139,16 +139,17 @@ def get_file_lines(
139139
140140
141141def is_same_file (
142- fname1 ,
143- fname2 ,
144- ignore_regexp = None ,
145- replace_regexp = None ,
146- replace_what = "." ,
147- replace_with = "." ,
148- diff = None ,
149- is_binary = False ,
150- strip_blanks = True ,
151- ):
142+ fname1 : str ,
143+ fname2 : str ,
144+ ignore_regexp : str | None = None ,
145+ replace_regexp : str | None = None ,
146+ replace_what : str = "." ,
147+ replace_with : str = "." ,
148+ diff : list [str ] | None = None ,
149+ * ,
150+ is_binary : bool = False ,
151+ strip_blanks : bool = True ,
152+ ) -> bool :
152153 """Test if two files are the same.
153154
154155 If ignore_regexp is passed, it must be a Regular Expression
@@ -182,19 +183,20 @@ def is_same_file(
182183 if VIM_DIFF :
183184 systemExec ("gvimdiff %s %s" % (fname1 , fname2 ))
184185 else :
185- sys .stdout .write ("\n " .join (diff ) + "\n " )
186+ sys .stdout .write ("\n " .join (diff or [] ) + "\n " )
186187
187188 return result
188189
189190
190- def systemExec (command , stdout = subprocess .PIPE , stderr = subprocess .STDOUT ):
191+ def systemExec (command : str , stdout : int = subprocess .PIPE , stderr : int = subprocess .STDOUT ) -> int :
191192 result = subprocess .Popen (command , bufsize = - 1 , shell = True , stdout = stdout , stderr = stderr )
192193 exit_code = result .wait ()
194+ assert result .stdout is not None
193195 FOUT .write (result .stdout .read ().decode ("utf-8" ))
194196 return exit_code
195197
196198
197- def getExtension (fname : str ):
199+ def getExtension (fname : str ) -> str | None :
198200 """Returns filename extension.
199201 Returns None if no extension.
200202 """
@@ -211,7 +213,7 @@ def getName(fname: str) -> str:
211213 return basename .split (os .extsep )[0 ]
212214
213215
214- def _get_testbas_options (fname : str ):
216+ def _get_testbas_options (fname : str ) -> tuple [ list [ str ], str , str ] :
215217 """Generates a command line string to be executed to
216218 get the .asm test file from a .bas one.
217219 :param str fname: .bas filename source file
@@ -229,7 +231,7 @@ def _get_testbas_options(fname: str):
229231
230232 match = reOPT .match (getName (fname ))
231233 if match :
232- options = [ "-O" + match .groups ()[0 ]]
234+ options . append ( "-O" + match .groups ()[0 ])
233235
234236 match = reBIN .match (getName (fname ))
235237 if match and match .groups ()[0 ].lower () in ("tzx" , "tap" ):
@@ -243,7 +245,7 @@ def _get_testbas_options(fname: str):
243245 return options , tfname , ext
244246
245247
246- def updateTest (tfname : str , pattern_ , strip_blanks : bool = True ):
248+ def updateTest (tfname : str , pattern_ : str | None , strip_blanks : bool = True ) -> None :
247249 if not os .path .exists (tfname ):
248250 return # was deleted -> The test is an error test and no compile file should exist
249251
@@ -262,7 +264,9 @@ def updateTest(tfname: str, pattern_, strip_blanks: bool = True):
262264
263265
264266@src .api .utils .timeout (_timeout )
265- def testPREPRO (fname , pattern_ = None , inline = None , cmdline_args = None ):
267+ def testPREPRO (
268+ fname : str , pattern_ : str | None = None , inline : bool | None = None , cmdline_args : list [str ] | None = None
269+ ) -> bool | None :
266270 """Test preprocessing file. Test is done by preprocessing the file and then
267271 comparing the output against an expected one. The output file can optionally be filtered
268272 using a filter_ regexp (see above).
@@ -304,11 +308,12 @@ def testPREPRO(fname, pattern_=None, inline=None, cmdline_args=None):
304308 func = lambda : systemExec (cmdline )
305309
306310 result = None
311+ current_path : str = os .getcwd ()
312+
307313 try :
308- current_path = os .getcwd ()
309314 os .chdir (os .path .dirname (fname ) or os .curdir )
310315
311- with TempTestFile (func , tfname , UPDATE ):
316+ with TempTestFile (func , tfname , keep_file = UPDATE ):
312317 if not UPDATE :
313318 result = is_same_file (
314319 okfile ,
@@ -362,15 +367,17 @@ def testASM(fname, inline=None, cmdline_args=None):
362367 func = lambda : systemExec (cmdline )
363368
364369 result = None
365- with TempTestFile (func , tfname , UPDATE ):
370+ with TempTestFile (func , tfname , keep_file = UPDATE ):
366371 if not UPDATE :
367372 result = is_same_file (okfile , tfname , is_binary = True )
368373
369374 return result
370375
371376
372377@src .api .utils .timeout (_timeout )
373- def testBAS (fname , filter_ = None , inline = None , cmdline_args = None ):
378+ def testBAS (
379+ fname : str , filter_ = None , inline : bool | None = None , cmdline_args : Iterable [str ] | None = None
380+ ) -> bool | None :
374381 """Test compiling a BASIC (.bas) file. Test is done by compiling the source code into asm and then
375382 comparing the output asm against an expected asm output. The output asm file can optionally be filtered
376383 using a filter_ regexp (see above).
@@ -398,8 +405,8 @@ def testBAS(fname, filter_=None, inline=None, cmdline_args=None):
398405 syscmd = "{0} {1}" .format (ZXB , " " .join (options ))
399406 func = lambda : systemExec (syscmd )
400407
401- with TempTestFile (func , tfname , UPDATE ):
402- result = is_same_file (okfile , tfname , filter_ , is_binary = reBIN .match (fname ) is not None )
408+ with TempTestFile (func , tfname , keep_file = UPDATE ):
409+ result : bool | None = is_same_file (okfile , tfname , filter_ , is_binary = reBIN .match (fname ) is not None )
403410 if UPDATE :
404411 if not result : # File changed
405412 if os .path .exists (okfile ):
@@ -457,14 +464,14 @@ def testFiles(file_list: Iterable[str], cmdline_args=None) -> None:
457464 _msg ("FAIL\n " )
458465
459466
460- def upgradeTest (fileList : Iterable [str ], f3diff : str ) -> None :
467+ def upgradeTest (filelist : Iterable [str ], f3diff : str ) -> None :
461468 """Run against the list of files, and a 3rd file containing the diff.
462469 If the diff between file1 and file2 are the same as file3, then the
463470 .asm file is patched.
464471 """
465472 global COUNTER
466473
467- def normalizeDiff (diff : List [str ]) -> List [str ]:
474+ def normalizeDiff (diff : list [str ]) -> list [str ]:
468475 diff = [x .strip (" \t " ) for x in diff ]
469476
470477 reHEADER = re .compile (r"[-+]{3}" )
@@ -484,7 +491,7 @@ def normalizeDiff(diff: List[str]) -> List[str]:
484491 match = reHUNK .match (line )
485492 if match :
486493 g = match .groups ()
487- g = [ x if x is not None else "" for x in g ]
494+ g = tuple ( x if x is not None else "" for x in g )
488495 if first :
489496 first = False
490497 O1 = int (g [0 ])
@@ -504,7 +511,7 @@ def normalizeDiff(diff: List[str]) -> List[str]:
504511
505512 fdiff = normalizeDiff (fdiff )
506513
507- for fname in fileList :
514+ for fname in filelist :
508515 ext = getExtension (fname )
509516 if ext != "bas" :
510517 continue
@@ -522,7 +529,7 @@ def normalizeDiff(diff: List[str]) -> List[str]:
522529 pass
523530 continue
524531
525- lines : List [str ] = []
532+ lines : list [str ] = []
526533 is_same_file (fname1 , tfname , ignore_regexp = FILTER , diff = lines )
527534 lines = normalizeDiff (lines )
528535
@@ -591,7 +598,7 @@ def main(argv=None):
591598 parser .add_argument ("-u" , "--update" , type = str , default = None , help = "Updates a test if the UPDATE diff matches" )
592599 parser .add_argument ("-U" , "--force-update" , action = "store_true" , help = "Updates all failed test with the new output" )
593600 parser .add_argument ("--tmp-dir" , type = str , default = TEMP_DIR , help = "Temporary directory for tests generation" )
594- parser .add_argument ("FILES" , nargs = "+" , type = str , help = "List of files to be processed" )
601+ parser .add_argument ("FILES" , nargs = "+" , type = str , help = "list of files to be processed" )
595602 parser .add_argument ("-q" , "--quiet" , action = "store_true" , help = "Run quietly, suppressing normal output" )
596603 parser .add_argument ("-e" , "--stderr" , type = str , default = None , help = "File for stderr messages" )
597604 parser .add_argument ("-S" , "--use-shell" , action = "store_true" , help = "Use system shell for test instead of inline" )
@@ -636,7 +643,7 @@ def main(argv=None):
636643 finally :
637644 if temp_dir_created :
638645 os .rmdir (TEMP_DIR )
639- TEMP_DIR = None
646+ TEMP_DIR = ""
640647
641648 return EXIT_CODE
642649
0 commit comments