From b9c5e7d77b1d38808fda8f6985a2c4d02a68b487 Mon Sep 17 00:00:00 2001 From: Patrick Seewald Date: Tue, 4 Oct 2022 01:29:22 +0200 Subject: [PATCH] Unit tests: use fprettify as a module instead of relying on subprocesses --- fprettify/__init__.py | 55 +++++++++++++---------------- fprettify/tests/__init__.py | 70 +++++++++++++++++++++++-------------- 2 files changed, 69 insertions(+), 56 deletions(-) diff --git a/fprettify/__init__.py b/fprettify/__init__.py index e90cff1..20662e8 100644 --- a/fprettify/__init__.py +++ b/fprettify/__init__.py @@ -1915,23 +1915,24 @@ def log_message(message, level, filename, line_nr): logger_to_use = getattr(logger, level) logger_to_use(message, extra=logger_d) -def build_ws_dict(args): - """helper function to build whitespace dictionary""" - ws_dict = {} - ws_dict['comma'] = args.whitespace_comma - ws_dict['assignments'] = args.whitespace_assignment - ws_dict['decl'] = args.whitespace_decl - ws_dict['relational'] = args.whitespace_relational - ws_dict['logical'] = args.whitespace_logical - ws_dict['plusminus'] = args.whitespace_plusminus - ws_dict['multdiv'] = args.whitespace_multdiv - ws_dict['print'] = args.whitespace_print - ws_dict['type'] = args.whitespace_type - ws_dict['intrinsics'] = args.whitespace_intrinsics - return ws_dict def process_args(args): + def build_ws_dict(args): + """helper function to build whitespace dictionary""" + ws_dict = {} + ws_dict['comma'] = args.whitespace_comma + ws_dict['assignments'] = args.whitespace_assignment + ws_dict['decl'] = args.whitespace_decl + ws_dict['relational'] = args.whitespace_relational + ws_dict['logical'] = args.whitespace_logical + ws_dict['plusminus'] = args.whitespace_plusminus + ws_dict['multdiv'] = args.whitespace_multdiv + ws_dict['print'] = args.whitespace_print + ws_dict['type'] = args.whitespace_type + ws_dict['intrinsics'] = args.whitespace_intrinsics + return ws_dict + args_out = {} args_out['whitespace_dict'] = build_ws_dict(args) @@ -1959,18 +1960,18 @@ def process_args(args): return args_out -def str2bool(str): - """helper function to convert strings to bool""" - if str.lower() in ('yes', 'true', 't', 'y', '1'): - return True - elif str.lower() in ('no', 'false', 'f', 'n', '0'): - return False - else: - return None - - def get_arg_parser(args={}): """helper function to create the parser object""" + + def str2bool(str): + """helper function to convert strings to bool""" + if str.lower() in ('yes', 'true', 't', 'y', '1'): + return True + elif str.lower() in ('no', 'false', 'f', 'n', '0'): + return False + else: + return None + parser = argparse.ArgumentParser(**args) parser.add_argument("-i", "--indent", type=int, default=3, @@ -2046,13 +2047,9 @@ def get_arg_parser(args={}): return parser - def run(argv=sys.argv): # pragma: no cover """Command line interface""" - - - def get_config_file_list(filename): """helper function to create list of config files found in parent directories""" config_file_list = [] @@ -2075,7 +2072,6 @@ def get_config_file_list(filename): arguments['args_for_setting_config_path'] = ['-c', '--config-file'] arguments['description'] = arguments['description'] + " Config files ('.fprettify.rc') in the home (~) directory and any such files located in parent directories of the input file will be used. When the standard input is used, the search is started from the current directory." - parser = get_arg_parser(arguments) args = parser.parse_args(argv[1:]) @@ -2132,7 +2128,6 @@ def get_config_file_list(filename): filearguments['default_config_files'] = ['~/.fprettify.rc'] + get_config_file_list(os.path.abspath(filename) if filename != '-' else os.getcwd()) file_argparser = get_arg_parser(filearguments) - args_tmp = file_argparser.parse_args(argv[1:]) file_args = process_args(args_tmp) file_args['stdout'] = args_tmp.stdout or directory == '-' diff --git a/fprettify/tests/__init__.py b/fprettify/tests/__init__.py index 4fb4f3b..100afe0 100644 --- a/fprettify/tests/__init__.py +++ b/fprettify/tests/__init__.py @@ -49,20 +49,34 @@ def joinpath(path1, path2): MYPATH = os.path.dirname(os.path.abspath( inspect.getfile(inspect.currentframe()))) +TIMESTAMP = datetime.now().strftime('%Y-%m-%d_%H-%M-%S') + +# main directory for running tests TEST_MAIN_DIR = joinpath(MYPATH, r'../../fortran_tests') -TEST_DIR = joinpath(TEST_MAIN_DIR, r'test_code') +# directory for external Fortran code +TEST_EXT_DIR = joinpath(TEST_MAIN_DIR, r'test_code') + +# directory containing Fortran examples EXAMPLE_DIR = joinpath(MYPATH, r'../../examples/in') -TIMESTAMP = datetime.now().strftime('%Y-%m-%d_%H-%M-%S') -BACKUP_DIR = joinpath(MYPATH, r'../../fortran_tests/test_code_in_' + TIMESTAMP) -RESULT_DIR = joinpath(MYPATH, r'../../fortran_tests/test_results') + +# backup directory +BACKUP_DIR = joinpath(TEST_MAIN_DIR, r'test_code_in_' + TIMESTAMP) + +# where to store summarized results +RESULT_DIR = joinpath(TEST_MAIN_DIR, r'test_results') + +# expected hash-sums RESULT_FILE = joinpath(RESULT_DIR, r'expected_results') + +# test failures FAILED_FILE = joinpath(RESULT_DIR, r'failed_results') +# path to fprettify RUNSCRIPT = joinpath(MYPATH, r"../../fprettify.py") -fprettify.set_fprettify_logger(logging.ERROR) +fprettify.set_fprettify_logger(logging.ERROR) class AlienInvasion(Exception): """Should not happen""" @@ -107,7 +121,7 @@ def setUpClass(cls): eprint("recognized Fortran files") eprint(", ".join(fprettify.FORTRAN_EXTENSIONS)) eprint("-" * 70) - eprint("Applying fprettify to Fortran files in " + TEST_DIR) + eprint("Applying fprettify to Fortran files in " + TEST_EXT_DIR) eprint("Writing backup of original files to " + BACKUP_DIR) eprint("Storing expected results in " + RESULT_FILE) eprint("Storing failed results in " + FAILED_FILE) @@ -250,12 +264,17 @@ def assert_fprettify_result(self, args, instring, outstring_exp): assert that result of calling fprettify with args on instring gives outstring_exp """ - args.insert(0, RUNSCRIPT) - p1 = subprocess.Popen( - args, stdout=subprocess.PIPE, stdin=subprocess.PIPE) - outstring = p1.communicate(instring.encode( - 'UTF-8'))[0].decode('UTF-8').rstrip() - self.assertEqual(outstring_exp.rstrip(), outstring) + + parser = fprettify.get_arg_parser() + args = parser.parse_args(args) + args = fprettify.process_args(args) + + outfile = io.StringIO() + infile = io.StringIO(instring) + + fprettify.reformat_ffile(infile, outfile, orig_filename='StringIO', **args) + outstring = outfile.getvalue() + self.assertEqual(outstring_exp.rstrip(), outstring.rstrip()) def test_io(self): """simple test for io (file inplace, stdin & stdout)""" @@ -890,7 +909,7 @@ def test_label(self): self.assert_fprettify_result([], instring, outstring) -def generatesuite(suitename): +def generate_suite(suitename): config = configparser.ConfigParser() config.read(joinpath(TEST_MAIN_DIR, 'externalTestCode.config')) @@ -899,7 +918,7 @@ def generatesuite(suitename): if code['suite'] == suitename: orig = os.getcwd() try: - os.chdir(TEST_DIR) + os.chdir(TEST_EXT_DIR) if not os.path.isdir(code['path']): exec(code['obtain']) @@ -910,9 +929,9 @@ def generatesuite(suitename): def addtestcode(code_path, options): # dynamically create test cases from fortran files in test directory - for dirpath, _, filenames in os.walk(joinpath(TEST_DIR, code_path)): + for dirpath, _, filenames in os.walk(joinpath(TEST_EXT_DIR, code_path)): for example in [f for f in filenames if any(f.endswith(_) for _ in fprettify.FORTRAN_EXTENSIONS)]: - rel_dirpath = os.path.relpath(dirpath, start=TEST_DIR) + rel_dirpath = os.path.relpath(dirpath, start=TEST_EXT_DIR) addtestmethod(FPrettifyTestCase, rel_dirpath, example, options) @@ -922,7 +941,7 @@ def addtestmethod(testcase, fpath, ffile, options): def testmethod(testcase): """this is the test method invoked for each example.""" - example_path = joinpath(TEST_DIR, fpath) + example_path = joinpath(TEST_EXT_DIR, fpath) backup_path = joinpath(BACKUP_DIR, fpath) if not os.path.exists(backup_path): os.makedirs(backup_path) @@ -931,7 +950,7 @@ def testmethod(testcase): example_backup = joinpath(backup_path, ffile) def test_result(path, info): - return [os.path.relpath(path, TEST_DIR), info] + return [os.path.relpath(path, TEST_EXT_DIR), info] with io.open(example, 'r', encoding='utf-8') as infile: instring = infile.read() @@ -942,16 +961,15 @@ def test_result(path, info): # apply fprettify with io.open(example, 'r', encoding='utf-8') as infile: - outstring = io.StringIO() + outfile = io.StringIO() try: parser = fprettify.get_arg_parser() - args = parser.parse_args(options) - + args = parser.parse_args(shlex.split(options)) args = fprettify.process_args(args) - fprettify.reformat_ffile(infile, outstring, **args) - outstring = outstring.getvalue() + fprettify.reformat_ffile(infile, outfile, **args) + outstring = outfile.getvalue() m = hashlib.sha256() m.update(outstring.encode('utf-8')) @@ -1020,8 +1038,8 @@ def test_result(path, info): setattr(testcase, testmethod.__name__, testmethod) # make sure all directories exist -if not os.path.exists(TEST_DIR): # pragma: no cover - os.makedirs(TEST_DIR) +if not os.path.exists(TEST_EXT_DIR): # pragma: no cover + os.makedirs(TEST_EXT_DIR) if not os.path.exists(BACKUP_DIR): # pragma: no cover os.makedirs(BACKUP_DIR) if not os.path.exists(RESULT_DIR): # pragma: no cover @@ -1033,4 +1051,4 @@ def test_result(path, info): io.open(FAILED_FILE, 'w', encoding='utf-8').close() # ToDo: parameterize regular / cron -generatesuite('cron') +#generate_suite('cron')