From: ahmedsamyh Date: Tue, 1 Apr 2025 14:41:47 +0000 (+0500) Subject: [test.py] Update X-Git-Url: https://www.git.momoyon.org/?a=commitdiff_plain;h=80cae648a3b07b6fae4965d2def75abd427560cc;p=lang.git [test.py] Update --- diff --git a/test.py b/test.py index 7d7d0ec..9cfceeb 100755 --- a/test.py +++ b/test.py @@ -3,8 +3,72 @@ import os import subprocess import sys import shlex +import coloredlogs, logging -# TODO: Use Colored logging +'''-COLORED PRINT------------''' +import sys + +colors_table = { + 'BLACK': [ '30', '40' ], + 'RED': [ '31', '41' ], + 'GREEN': [ '32', '42' ], + 'YELLOW': [ '33', '43' ], + 'BLUE': [ '34', '44' ], + 'MAGENTA': [ '35', '45' ], + 'CYAN': [ '36', '46' ], + 'WHITE': [ '37', '47' ], + 'DEFAULT': [ '39', '49' ], + 'RESET': [ '00', '00' ], +} + +def set_color(fg: str = 'DEFAULT', bg: str = 'DEFAULT', file=sys.stdout): + bg = bg.upper() + fg = fg.upper() + if bg not in colors_table: + raise ValueError(f'{bg} is not a valid color!, we only support 8 colors only!') + if fg not in colors_table: + raise ValueError(f'{fg} is not a valid color!, we only support 8 colors only!') + print(f"\033[{colors_table[fg][0]};{colors_table[bg][1]}m", file=file, end='') + + +def cprint(fg: str, bg: str, msg: str, file=sys.stdout, *args, **kwargs): + set_color(fg, bg, file) + print(msg, file=file, **kwargs) + set_color(file=file) +'''-------------------------''' + +CMD_LEVEL = 15 +logging.addLevelName(CMD_LEVEL, "CMD") + +class MyLogger(logging.Logger): + def cmd(self, msg, *args, **kwargs): + if self.isEnabledFor(CMD_LEVEL): + self._log(CMD_LEVEL, msg, args, **kwargs) + + +logging.setLoggerClass(MyLogger) + +logger = logging.getLogger('test') +logger.setLevel(logging.DEBUG) + +coloredlogs.install( + level='DEBUG', + fmt='%(name)s [%(levelname)s]: %(message)s', + level_styles={ + 'cmd': {'color': 'cyan'}, # Color for CMD level + 'debug': {'color': 'white'}, + 'info': {'color': 'green'}, + 'warning': {'color': 'yellow'}, + 'error': {'color': 'red'}, + 'critical': {'color': 'magenta'}, + }, + field_styles={ + 'name': {'color': 'cyan'}, + 'levelname': {'bold': True}, + } +) + +# TODO: Implement or Use a third-party diff-ing library ## Substitutable values; These values are substituted with the following values if found in BUILD_CMD or RUN_CMD @@ -39,9 +103,21 @@ def get_cmd_substituted(cmd, tests, current_test): def check_crucial_envvar(var, var_name): if var == "NOT SET": - print(f"[ERROR] `{var_name}` environment variable not set! please provide a value and run again!", file=sys.stderr) + logger.error(f"`{var_name}` environment variable not set! please provide a value and run again!") exit(1) + +def expect_output(expected_name: str, expected: str, got: str): + print(f"Expected {expected_name}: ") + print(">>>") + cprint("green", "default", expected) + print(">>>") + print("But got: ") + print("<<<") + cprint("red", "default", got) + print("<<<") + + class Test: stdin = '' expected_stdout = '' @@ -62,7 +138,7 @@ class Test: with open(f, "w") as file: pass # NOTE: Why do we need to log this? - # print(f"[INFO] Created empty {self.name}.{name}.expected") + # logger.info("Created empty {self.name}.{name}.expected") return "" else: with open(f, "r") as file: @@ -125,7 +201,7 @@ class Test: return input_array def usage(program: str): - print(f"Usage: {program} [flags]") + logger.info(f"Usage: {program} [flags]") # NOTE: We named this hhelp because help is a builtin python function def hhelp(): @@ -143,15 +219,11 @@ def hhelp(): -x - Stop on first error. ''') -def vlog(verbose_output, msg): - if verbose_output: - print(msg) - def main(): program = sys.argv.pop(0) if len(sys.argv) <= 0: - print("[ERROR] Please provide at least one subcommand!", file=sys.stderr) + logger.error("Please provide at least one subcommand!") usage(program) hhelp() exit(1) @@ -184,11 +256,11 @@ def main(): elif flag == 'x': stop_on_error = True else: - print(f"[ERROR] Invalid flag '{flag}'", file=sys.stderr) + logger.error(f"Invalid flag '{flag}'") exit(1) if len(subcmds) <= 0: - print("[ERROR] Please provide at least one subcommand!", file=sys.stderr) + logger.error("Please provide at least one subcommand!") usage(program) hhelp() exit(1) @@ -199,7 +271,7 @@ def main(): check_crucial_envvar(SRC_SUFFIX, "SRC_SUFFIX") os.chdir(TESTS_DIR) - vlog(verbose_output, f"[INFO] Changed cwd to {os.getcwd()}") + if verbose_output: logger.info(f"Changed cwd to {os.getcwd()}") tests = {} @@ -224,49 +296,47 @@ def main(): exit(0) elif subcmd == "build": check_crucial_envvar(BUILD_CMD, "BUILD_CMD") - print(f'----- [BUILD] -----') + cprint('green', 'default', f'----- [BUILD] -----') for test_name in tests: - print(f'+ Building {test_name} [{current_test_id+1}/{total_tests_count}]...') + cprint('green', 'default', f'+ Building {test_name}.{SRC_SUFFIX} [{current_test_id+1}/{total_tests_count}]...') current_test_id += 1 test = tests[test_name] if test.build_expected_returncode == -1: - print(f"[WARNING] Test doesn't have any expected build returncode!") - print(f"[WARNING] Please record the expected build behaviour of the test using the 'record_build' subcommand!") - print(f"[SKIPPING]...") + logger.warning(f"Test doesn't have any expected build returncode!") + logger.warning(f"Please record the expected build behaviour of the test using the 'record_build' subcommand!") + cprint('yellow', 'default', f"[SKIPPING]...") if stop_on_error: exit(1) continue cmd = shlex.split(get_cmd_substituted(BUILD_CMD, tests, test_name)) build_stdin_list = test.get_build_stdin_list() if len(build_stdin_list) > 0: cmd.extend(build_stdin_list) - vlog(verbose_output, f"[CMD] {cmd}") + # vlog(verbose_output, f"[CMD] {cmd}") res = subprocess.run(cmd, capture_output = True, text = True) if res.returncode != 0: - print("[FAILED] ", end='') + m = '' if res.stderr: - print(f"{res.stderr}") - else: - print('') + m += f"{res.stderr}" + logger.error("[FAILED] {m}") + if stop_on_error: exit(1) else: continue else: failed = False if res.stdout != test.build_expected_stdout: - print('[FAILED]', file=sys.stderr) - print(f"build_Expected: >>>{test.build_expected_stdout}>>>") - print(f"But Got: >>>{res.stdout}>>>") + cprint('red', 'default', f'[FAILED]') + expect_output("stdout", test.build_expected_stdout, res.stdout) failed = True if stop_on_error: exit(1) if res.stderr != test.build_expected_stderr: - print('[FAILED]', file=sys.stderr) - print(f"build_Expected: >>>{test.build_expected_stderr}>>>") - print(f"But Got: >>>{res.stderr}>>>") + cprint('red', 'default', f'[FAILED]') + expect_output("stderr", test.build_expected_stderr, res.stderr) failed = True if stop_on_error: exit(1) if not failed: passing_tests_count += 1 - print("[PASS] ", end='') + cprint('green', 'default', "[PASS] ") o = False if verbose_output and res.stdout: print(f"{res.stdout}") @@ -279,34 +349,33 @@ def main(): print(f"Build {passing_tests_count}/{total_tests_count} tests") elif subcmd == "run": check_crucial_envvar(RUN_CMD, "RUN_CMD") - print(f'----- [RUN] -----') + cprint('green', 'default', f'----- [RUN] -----') for test_name in tests: - print(f'+ Running {test_name} [{current_test_id+1}/{total_tests_count}]...') + cprint('green', 'default', f'+ Running {test_name} [{current_test_id+1}/{total_tests_count}]...') current_test_id += 1 test = tests[test_name] res = None try: cmd = shlex.split(get_cmd_substituted(RUN_CMD, tests, test_name)) - vlog(verbose_output, f"[CMD] {cmd}") + # vlog(verbose_output, f"[CMD] {cmd}") res = subprocess.run(cmd, capture_output = True, text = True) except Exception as e: - print(f"[ERROR] Failed to run ./{test_name}: {e}") + logger.error("Failed to run ./{test_name}: {e}") if stop_on_error: exit(1) else: continue if test.expected_returncode == -1: - print(f"[WARNING] Test doesn't have any expected returncode!") - print(f"[WARNING] Please record the expected behaviour of the test using the 'record' subcommand!") + logger.warning(f"Test doesn't have any expected returncode!") + logger.warning(f"Please record the expected behaviour of the test using the 'record' subcommand!") if res.stdout != test.expected_stdout: - print('[FAILED]', file=sys.stderr) - print(f"Expected: >>>{test.expected_stdout}>>>") - print(f"But Got: >>>{res.stdout}>>>") + cprint('red', 'default', f'[FAILED]') + expect_output("stdout", test.expected_stdout, res.stdout) if stop_on_error: exit(1) else: continue passing_tests_count += 1 - print('[PASS]') + cprint('green', 'default', '[PASS]') print(f"PASSED {passing_tests_count}/{total_tests_count}") elif subcmd == "record": @@ -319,7 +388,7 @@ def main(): cmd = shlex.split(get_cmd_substituted(RUN_CMD, tests, test_name)) stdin_list = test.get_stdin_list() if len(stdin_list) > 0: cmd.extend(stdin_list) - vlog(verbose_output, f"[CMD] {cmd}") + # vlog(verbose_output, f"[CMD] {cmd}") res = subprocess.run([f"./{test_name}"], capture_output = True, text = True) print(f"stdout: {res.stdout}") @@ -345,7 +414,7 @@ def main(): test = tests[test_name] if len(test.build_stdin) > 0: - print(f"[INFO] Test already has build_input '{test.build_stdin}'...") + logger.info("Test already has build_input '{test.build_stdin}'...") ans = input("Do you want to change the build_input? [y/N]") if ans.lower() == 'y': test.build_stdin = input("What is the input passed? ") @@ -358,7 +427,7 @@ def main(): cmd = shlex.split(get_cmd_substituted(BUILD_CMD, tests, test_name)) build_stdin_list = test.get_build_stdin_list() if len(build_stdin_list) > 0: cmd.extend(build_stdin_list) - vlog(verbose_output, f"[CMD] {cmd}") + # vlog(verbose_output, f"[CMD] {cmd}") res = subprocess.run(cmd, capture_output = True, text = True) print(f"stdout: {res.stdout}")