From 361e1fe39e88788ef4173083482d520753225a3e Mon Sep 17 00:00:00 2001 From: Charles Cabergs Date: Sun, 31 Jan 2021 04:13:22 +0100 Subject: Refactoring Result into BaseResult, Result and LeakResult --- src/test/result.py | 228 ++++++++++++++++++++++++++++------------------------- 1 file changed, 122 insertions(+), 106 deletions(-) (limited to 'src/test/result.py') diff --git a/src/test/result.py b/src/test/result.py index 4d060fa..e4512ac 100644 --- a/src/test/result.py +++ b/src/test/result.py @@ -6,7 +6,7 @@ # By: charles +#+ +:+ +#+ # # +#+#+#+#+#+ +#+ # # Created: 2020/09/11 12:17:34 by charles #+# #+# # -# Updated: 2021/01/31 03:35:53 by charles ### ########.fr # +# Updated: 2021/01/31 04:10:31 by charles ### ########.fr # # # # ############################################################################ # @@ -18,73 +18,21 @@ import config from test.captured import Captured -# TODO split into BaseResult, Result and LeakResult -class Result: +class BaseResult: RED_CHARS = "\033[31m" GREEN_CHARS = "\033[32m" BLUE_CHARS = "\033[34m" BOLD_CHARS = "\033[1m" CLOSE_CHARS = "\033[0m" - def __init__( - self, - cmd: str, - file_names: List[str], - expected: Captured, - actual: Captured, - leak_output: str = None - ): - """Result class - cmd: runned command - file_names: names of watched files - expected: expected capture - actual: actual capture - leak_output: output of valgrind in check leak mode - """ - self.cmd = cmd - self.file_names = file_names - self.expected = expected - self.actual = actual + def __init__(self): self.colored = True - self.leak_output = leak_output self.set_colors() - @staticmethod - def leak(cmd: str, captured: Captured): - return Result(cmd, [], None, captured, captured.output) - - def _search_leak_kind(self, kind: str) -> Match: - match = re.search( - r"==\d+==\s+" + kind + r" lost: (?P[0-9,]+) bytes in [0-9,]+ blocks", - self.leak_output - ) - if match is None: - raise RuntimeError( - "valgrind output parsing failed for `{}`:\n{}" - .format(self.cmd, self.leak_output) - ) - return match - - @property - def lost_bytes(self): - if self.leak_output.find("All heap blocks were freed -- no leaks are possible") != -1: - definite_bytes = 0 - indirect_bytes = 0 - else: - definite_match = self._search_leak_kind("definitely") - indirect_match = self._search_leak_kind("indirectly") - definite_bytes = int(definite_match.group("bytes").replace(",", "")) - indirect_bytes = int(indirect_match.group("bytes").replace(",", "")) - return definite_bytes + indirect_bytes - @property def passed(self): """Check if the result passed""" - if self.leak_output is not None: - if self.actual.is_timeout: - return False - return self.lost_bytes == 0 - return self.actual == self.expected + raise NotImplementedError @property def failed(self): @@ -96,7 +44,7 @@ class Result: if config.VERBOSE_LEVEL == 0: return self.green('.') if self.passed else self.red('!') elif config.VERBOSE_LEVEL == 1: - printed = self.escaped_cmd[:] + printed = self._escaped_cmd[:] if config.SHOW_RANGE: printed = "{:2}: ".format(self.index) + printed if len(printed) > config.TERM_COLS - 7: @@ -119,8 +67,79 @@ class Result: else: print() + def indicator(self, title: str, prefix: str) -> str: + return self.bold(self.blue(prefix + " " + title)) + + def full_diff(self) -> str: + raise NotImplementedError + + @property + def _escaped_cmd(self): + """Escape common control characters""" + return (self.cmd + .replace("\t", "\\t") + .replace("\n", "\\n") + .replace("\v", "\\v") + .replace("\r", "\\r") + .replace("\f", "\\f")) + + @property + def _header_with(self): + return self.indicator("WITH {}".format(self._escaped_cmd), "|>") + '\n' + + def set_colors(self): + """Set colors strings on or off based on self.colored""" + if self.colored: + self.color_red = self.RED_CHARS + self.color_green = self.GREEN_CHARS + self.color_blue = self.BLUE_CHARS + self.color_bold = self.BOLD_CHARS + self.color_close = self.CLOSE_CHARS + else: + self.color_red = "" + self.color_green = "" + self.color_blue = "" + self.color_bold = "" + self.color_close = "" + + def green(self, s): + return self.color_green + s + self.color_close + + def red(self, s): + return self.color_red + s + self.color_close + + def blue(self, s): + return self.color_blue + s + self.color_close + + def bold(self, s): + return self.color_bold + s + self.color_close + + +class Result(BaseResult): + def __init__( + self, + cmd: str, + file_names: List[str], + expected: Captured, + actual: Captured, + ): + """Result class + cmd: runned command + file_names: names of watched files + expected: expected capture + actual: actual capture + """ + self.cmd = cmd + self.file_names = file_names + self.expected = expected + self.actual = actual + super().__init__() + + @property + def passed(self): + return self.actual == self.expected + def header(self, title: str) -> str: - """Create a one line header with a title""" return self.bold("|---------------------------------------{:-<40}".format(title)) @property @@ -131,8 +150,14 @@ class Result: def actual_header(self) -> str: return self.red(self.header("ACTUAL")) - def indicator(self, title: str, prefix: str) -> str: - return self.bold(self.blue(prefix + " " + title)) + def cat_e(self, s: str) -> str: + """Pass a string through a cat -e like output""" + s = s.replace("\n", "$\n") + if len(s) < 2: + return s + if s[-1] != '\n': + s += '\n' + return s def file_diff(self, file_name: str, expected: str, actual: str) -> str: """Difference between 2 files""" @@ -173,55 +198,46 @@ class Result: def full_diff(self) -> str: """Concat all difference reports""" - rest = "" - if self.leak_output is not None: - rest = self.leak_output - else: - rest = (self.output_diff() + self.files_diff() + "=" * 80 + '\n') - return (self.indicator("WITH {}".format(self.escaped_cmd), "|>") + '\n' + rest) - - def cat_e(self, s: str) -> str: - """Pass a string through a cat -e like output""" - s = s.replace("\n", "$\n") - if len(s) < 2: - return s - if s[-1] != '\n': - s += '\n' - return s + return self._header_with + self.output_diff() + self.files_diff() + "=" * 80 + '\n' - @property - def escaped_cmd(self): - """Escape common control characters""" - return (self.cmd - .replace("\t", "\\t") - .replace("\n", "\\n") - .replace("\v", "\\v") - .replace("\r", "\\r") - .replace("\f", "\\f")) - def set_colors(self): - """Set colors strings on or off based on self.colored""" - if self.colored: - self.color_red = self.RED_CHARS - self.color_green = self.GREEN_CHARS - self.color_blue = self.BLUE_CHARS - self.color_bold = self.BOLD_CHARS - self.color_close = self.CLOSE_CHARS - else: - self.color_red = "" - self.color_green = "" - self.color_blue = "" - self.color_bold = "" - self.color_close = "" +class LeakResult(BaseResult): + def __init__(self, cmd: str, captured: Captured): + self.cmd = cmd + self.captured = captured + super().__init__() - def green(self, s): - return self.color_green + s + self.color_close + def _search_leak_kind(self, kind: str) -> Match: + match = re.search( + r"==\d+==\s+" + kind + r" lost: (?P[0-9,]+) bytes in [0-9,]+ blocks", + self.captured.output + ) + if match is None: + raise RuntimeError( + "valgrind output parsing failed for `{}`:\n{}" + .format(self.cmd, self.captured.output) + ) + return match - def red(self, s): - return self.color_red + s + self.color_close + @property + def _lost_bytes(self): + if self.captured.output.find("All heap blocks were freed -- no leaks are possible") != -1: + definite_bytes = 0 + indirect_bytes = 0 + else: + definite_match = self._search_leak_kind("definitely") + indirect_match = self._search_leak_kind("indirectly") + definite_bytes = int(definite_match.group("bytes").replace(",", "")) + indirect_bytes = int(indirect_match.group("bytes").replace(",", "")) + return definite_bytes + indirect_bytes - def blue(self, s): - return self.color_blue + s + self.color_close + @property + def passed(self): + """Check if the result passed""" + if self.captured.is_timeout: + return False + return self._lost_bytes == 0 - def bold(self, s): - return self.color_bold + s + self.color_close + def full_diff(self) -> str: + """Concat all difference reports""" + return self._header_with + self.captured.output -- cgit