diff options
| author | Charles Cabergs <me@cacharle.xyz> | 2020-10-07 18:58:12 +0200 |
|---|---|---|
| committer | Charles Cabergs <me@cacharle.xyz> | 2020-10-07 18:58:12 +0200 |
| commit | 0cf5d76836a6499de4e30c4066d8709099ff6331 (patch) | |
| tree | 65606b51f97fc88ac0953d73d760995fb759442a /src/test | |
| parent | 2a93ed69f7ee88c26b1edfb1f58a8f4d6d842bd4 (diff) | |
| download | minishell_test-0cf5d76836a6499de4e30c4066d8709099ff6331.tar.gz minishell_test-0cf5d76836a6499de4e30c4066d8709099ff6331.tar.bz2 minishell_test-0cf5d76836a6499de4e30c4066d8709099ff6331.zip | |
Added memory leak checking
Diffstat (limited to 'src/test')
| -rw-r--r-- | src/test/captured.py | 2 | ||||
| -rw-r--r-- | src/test/result.py | 101 | ||||
| -rw-r--r-- | src/test/test.py | 32 |
3 files changed, 87 insertions, 48 deletions
diff --git a/src/test/captured.py b/src/test/captured.py index f855212..4a9966d 100644 --- a/src/test/captured.py +++ b/src/test/captured.py @@ -6,7 +6,7 @@ # By: charles <me@cacharle.xyz> +#+ +:+ +#+ # # +#+#+#+#+#+ +#+ # # Created: 2020/09/11 12:16:25 by charles #+# #+# # -# Updated: 2020/09/11 20:42:05 by charles ### ########.fr # +# Updated: 2020/10/07 18:25:05 by cacharle ### ########.fr # # # # ############################################################################ # diff --git a/src/test/result.py b/src/test/result.py index 5e7c2e9..30ce31e 100644 --- a/src/test/result.py +++ b/src/test/result.py @@ -6,11 +6,12 @@ # By: charles <me@cacharle.xyz> +#+ +:+ +#+ # # +#+#+#+#+#+ +#+ # # Created: 2020/09/11 12:17:34 by charles #+# #+# # -# Updated: 2020/10/06 16:56:30 by cacharle ### ########.fr # +# Updated: 2020/10/07 18:53:27 by cacharle ### ########.fr # # # # ############################################################################ # import sys +import re import config from test.captured import Captured @@ -23,50 +24,51 @@ class Result: BOLD_CHARS = "\033[1m" CLOSE_CHARS = "\033[0m" - def __init__(self, cmd: str, file_names: [str], expected: Captured, actual: Captured): + def __init__( + self, + cmd: str, + file_names: [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 + 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 self.colored = True + self.leak_output = leak_output self.set_colors() - 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 = "" + @staticmethod + def leak(cmd: str, leak_output: str = None): + return Result(cmd, None, None, None, leak_output) - 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 + @property + def lost_bytes(self): + m = re.search( + r"definitely lost: (?P<bytes>[0-9,]+) bytes in [0-9,]+ blocks", + self.leak_output + ) + if m is None: + raise RuntimeError( + "valgrind output parsing failed for `{}`:\n{}" + .format(self.cmd, self.leak_output) + ) + return int(m.group("bytes")) @property def passed(self): """Check if the result passed""" + if self.leak_output is not None: + return self.lost_bytes == 0 return self.actual == self.expected @property @@ -153,10 +155,12 @@ class Result: def full_diff(self) -> str: """Concat all difference reports""" - return (self.indicator("WITH {}".format(self.escaped_cmd), "|>") + '\n' - + self.output_diff() - + self.files_diff() - + "=" * 80 + '\n') + 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""" @@ -176,3 +180,30 @@ class Result: .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 = "" + + 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 diff --git a/src/test/test.py b/src/test/test.py index c4e183c..52b6db3 100644 --- a/src/test/test.py +++ b/src/test/test.py @@ -6,14 +6,14 @@ # By: charles <charles.cabergs@gmail.com> +#+ +:+ +#+ # # +#+#+#+#+#+ +#+ # # Created: 2020/06/16 21:48:50 by charles #+# #+# # -# Updated: 2020/10/07 08:12:00 by charles ### ########.fr # +# Updated: 2020/10/07 18:54:13 by cacharle ### ########.fr # # # # ############################################################################ # import os import sys import subprocess -# import time +#import time import config from test.captured import Captured @@ -57,8 +57,17 @@ class Test: def run(self): """ Run the test for minishell and the reference shell and print the result out """ - expected = self._run_sandboxed(config.REFERENCE_PATH, config.REFERENCE_ARGS + ["-c"]) - actual = self._run_sandboxed(config.MINISHELL_PATH, ["-c"]) + + if config.CHECK_LEAKS: + self.hook = [] + self.hook_status = [] + captured = self._run_sandboxed([*config.VALGRIND_CMD, "-c"]) + self.result = Result.leak(self.cmd, captured.output) + self.result.put() + return + + expected = self._run_sandboxed([config.REFERENCE_PATH, *config.REFERENCE_ARGS, "-c"]) + actual = self._run_sandboxed([config.MINISHELL_PATH, "-c"]) s = self.cmd if self.setup != "": s = "[SETUP {}] {}".format(self.setup, s) @@ -68,7 +77,7 @@ class Test: self.result = Result(s, self.files, expected, actual) self.result.put() - def _run_sandboxed(self, shell_path: str, shell_options: str) -> Captured: + def _run_sandboxed(self, shell_cmd: [str]) -> Captured: """ Run the command in a sandbox environment """ with sandbox.context(): if self.setup != "": @@ -88,15 +97,15 @@ class Test: "no stderr" if e.stdout is None else e.stdout.decode().strip())) sys.exit(1) - return self._run_capture(shell_path, shell_options) + return self._run_capture(shell_cmd) - def _run_capture(self, shell_path: str, shell_options: str) -> Captured: + def _run_capture(self, shell_cmd: [str]) -> Captured: """ Capture the output (stdout and stderr) Capture the content of the watched files after the command is run """ # run the command in the sandbox process = subprocess.Popen( - [shell_path, *shell_options, self.cmd], + [*shell_cmd, self.cmd], stderr=subprocess.STDOUT, stdout=subprocess.PIPE, cwd=config.SANDBOX_PATH, @@ -107,13 +116,12 @@ class Test: }, ) # if self.signal is not None: - # time.sleep(0.2) + # time.sleep(0.1) # process.send_signal(self.signal) - # else: # https://docs.python.org/3/library/subprocess.html#subprocess.Popen.communicate try: - stdout, _ = process.communicate(timeout=self.timeout) + stdout, _ = process.communicate(timeout=(self.timeout if not config.CHECK_LEAKS else 10)) except subprocess.TimeoutExpired: process.kill() # _, _ = process.communicate(timeout=2) @@ -132,7 +140,7 @@ class Test: except FileNotFoundError: files_content.append(None) - # sandbox.remove() + # apply output/status hooks for h in self.hook: output = h(output) for h in self.hook_status: |
