diff options
Diffstat (limited to 'minishell_test')
| -rw-r--r-- | minishell_test/suite/suite.py | 20 | ||||
| -rw-r--r-- | minishell_test/test/result.py | 109 |
2 files changed, 61 insertions, 68 deletions
diff --git a/minishell_test/suite/suite.py b/minishell_test/suite/suite.py index b058569..2a87fbc 100644 --- a/minishell_test/suite/suite.py +++ b/minishell_test/suite/suite.py @@ -6,7 +6,7 @@ # By: charles <charles.cabergs@gmail.com> +#+ +:+ +#+ # # +#+#+#+#+#+ +#+ # # Created: 2020/07/15 18:24:29 by charles #+# #+# # -# Updated: 2021/03/02 11:12:35 by cacharle ### ########.fr # +# Updated: 2021/03/02 13:17:31 by cacharle ### ########.fr # # # # ############################################################################ # @@ -129,6 +129,7 @@ class Suite: self.bonus = bonus self.generator_func: Optional[Callable] = None self.tests: List[Test] = [] + self.results: List[Result] = [] def add(self, test): """Append a test to the suite""" @@ -149,6 +150,7 @@ class Suite: self.tests = self.test[Config.range[0] : Config.range[1] + 1] for i, test in enumerate(self.tests): result = test.run() + self.results.append(result) print(result.to_string(i)) if Config.exit_first and result is not None and result.failed: return False @@ -157,10 +159,10 @@ class Suite: def total(self) -> Tuple[int, int]: """Returns the total of passed and failed tests""" passed_total = 0 - for t in self.tests: - if t.result is None: + for result in self.results: + if result is None: return (-1, -1) - if t.result.passed: + if result.passed: passed_total += 1 return passed_total, len(self.tests) - passed_total @@ -184,10 +186,8 @@ class Suite: @classmethod def save_log(cls): """Save the result of all suites to a file""" + colors.disable() with open(Config.log_path, "w") as log_file: - for s in cls.available: - for t in s.tests: - if t.result is not None and t.result.failed: - t.result.colored = False - t.result.set_colors() - log_file.write(t.result.full_diff() + '\n') + for result in self.results: + if result is not None and result.failed: + log_file.write(result.full_diff() + '\n') diff --git a/minishell_test/test/result.py b/minishell_test/test/result.py index 566520a..7936fb3 100644 --- a/minishell_test/test/result.py +++ b/minishell_test/test/result.py @@ -6,15 +6,15 @@ # By: charles <me@cacharle.xyz> +#+ +:+ +#+ # # +#+#+#+#+#+ +#+ # # Created: 2020/09/11 12:17:34 by charles #+# #+# # -# Updated: 2021/03/02 14:17:01 by cacharle ### ########.fr # +# Updated: 2021/03/02 17:44:02 by cacharle ### ########.fr # # # # ############################################################################ # import re -from typing import Match, List, Optional, Union +from typing import Match, List from minishell_test.config import Config -from minishell_test.colors import green, red, blue, bold +from minishell_test.colors import green, red from minishell_test.test.captured import CapturedCommand, CapturedTimeout, CapturedType @@ -76,7 +76,6 @@ class BaseResult: return f"|> WITH {self._cmd}\n" - class Result(BaseResult): def __init__( self, @@ -96,6 +95,8 @@ class Result(BaseResult): :param actual: actual capture """ + if isinstance(expected, CapturedTimeout): + raise RuntimeError super().__init__(cmd) self.file_names = file_names self.expected = expected @@ -110,8 +111,7 @@ class Result(BaseResult): return ( self._cmd_header + self._cmd_diff() + - self._files_diff() + - "=" * 80 + '\n' + self._files_diff() ) def _cmd_diff(self) -> str: @@ -125,7 +125,7 @@ class Result(BaseResult): out += self._content_diff(self.expected.output, self.actual.output) return out - _FILE_NOT_CREATED_MESSAGE = "FROM TEST: File not created\n" + _FILE_NOT_CREATED_MESSAGE = "FROM TEST: File not created" def _files_diff(self): """Difference between watched files""" @@ -133,62 +133,57 @@ class Result(BaseResult): if isinstance(self.actual, CapturedTimeout): return "" - def diff(name, expected, actual): - expected = expected or self._FILE_NOT_CREATED_MESSAGE - actual = actual or self._FILE_NOT_CREATED_MESSAGE + def diff(file_name, expected, actual): + if expected is None: + expected = self._FILE_NOT_CREATED_MESSAGE + if actual is None: + actual = self._FILE_NOT_CREATED_MESSAGE return f"|# FILE {file_name}\n" + self._content_diff(expected, actual) - return '\n'.join([ + return ''.join([ diff(name, expected, actual) for name, expected, actual in - zip( - self.file_names, - self.expected.files_content, - self.actual.files_content - ) + zip( + self.file_names, + self.expected.files_content, + self.actual.files_content + ) if expected != actual ]) def _content_diff(self, expected: str, actual: str) -> str: - return ( - self._expected_header + - self._show_newlines(expected) + - self._actual_header + - self._show_newlines(actual) - ) - - def _header(self, title: str) -> str: - """Create a 80 characters wide header in the format ``-- title --``""" - return f"|{'-' * 40}{title:-<40}\n" - - @property - def _expected_header(self) -> str: - return self._header("EXPECTED") - - @property - def _actual_header(self) -> str: - return self._header("ACTUAL") - - def _show_newlines(self, s: str) -> str: """Add a ``$`` at the end of each newline If the string doesn't end with a newline add one but doesn't add a ``$`` to represent it. """ - s = s.replace("\n", "$\n") - if len(s) < 2: + + def header(title): + return f"|{'-' * 40}{title:-<39}\n" + + def show_newlines(s): + s = s.replace("\n", "$\n") + if len(s) < 2: + return s + if s[-1] != '\n': + s += '\n' return s - if s[-1] != '\n': - s += '\n' - return s + + return ( + header("EXPECTED") + + show_newlines(expected) + + header("ACTUAL") + + show_newlines(actual) + ) class LeakResultException(Exception): - def __init__(self, result: 'LeakResult'): - self._result = result + def __init__(self, cmd: str, captured: CapturedCommand): + self._cmd = cmd + self._captured = captured def __str__(self) -> str: - return f"valgrind output parsing failed for `{self._result._cmd}`:\n{self._result._captured.output}" + return f"valgrind output parsing failed for `{self._cmd}`:\n{self._captured.output}" class LeakResult(BaseResult): @@ -197,33 +192,31 @@ class LeakResult(BaseResult): super().__init__(cmd) def __repr__(self) -> str: - return self._cmd_header + self.captured.output - - @property - def passed(self) -> str: if isinstance(self._captured, CapturedTimeout): - return False - return self._lost_bytes == 0 + return self._cmd_header + "TIMEOUT\n" + return self._cmd_header + self._captured.output _VALGRIND_OK_MESSAGE = "All heap blocks were freed -- no leaks are possible" @property - def _lost_bytes(self): + def passed(self) -> bool: + if isinstance(self._captured, CapturedTimeout): + return False # Some versions of valgrind don't output `definitely` and `indirectly` # when no leaks are found. if self._captured.output.find(self._VALGRIND_OK_MESSAGE) != -1: - return 0 - definite_match = self._search_leak_kind("definitely") - indirect_match = self._search_leak_kind("indirectly") + return True + definite_match = self._search_leak_kind("definitely", self._captured) + indirect_match = self._search_leak_kind("indirectly", self._captured) definite_bytes = int(definite_match.group("bytes").replace(",", "")) indirect_bytes = int(indirect_match.group("bytes").replace(",", "")) - return definite_bytes + indirect_bytes + return (definite_bytes + indirect_bytes) == 0 - def _search_leak_kind(self, kind: str) -> Match: + def _search_leak_kind(self, kind: str, captured: CapturedCommand) -> Match: match = re.search( r"==\d+==\s+" + kind + r" lost: (?P<bytes>[0-9,]+) bytes in [0-9,]+ blocks", - self._captured.output + captured.output ) if match is None: - raise LeakResultException(self) + raise LeakResultException(self._cmd, captured) return match |
