diff options
| author | Charles Cabergs <me@cacharle.xyz> | 2021-03-06 16:01:24 +0100 |
|---|---|---|
| committer | Charles Cabergs <me@cacharle.xyz> | 2021-03-06 16:01:24 +0100 |
| commit | fc7a0425a1e19807ec2819bdb73dc6aa14d0e197 (patch) | |
| tree | 142225b152d462dcf903cb45523565671a65a0b4 /minishell_test/suite | |
| parent | 2a854b36624fb1c108a56d317aa54ca630864288 (diff) | |
| download | minishell_test-fc7a0425a1e19807ec2819bdb73dc6aa14d0e197.tar.gz minishell_test-fc7a0425a1e19807ec2819bdb73dc6aa14d0e197.tar.bz2 minishell_test-fc7a0425a1e19807ec2819bdb73dc6aa14d0e197.zip | |
Added test for half of Suitedev
Diffstat (limited to 'minishell_test/suite')
| -rw-r--r-- | minishell_test/suite/decorator.py | 52 | ||||
| -rw-r--r-- | minishell_test/suite/suite.py | 236 |
2 files changed, 145 insertions, 143 deletions
diff --git a/minishell_test/suite/decorator.py b/minishell_test/suite/decorator.py index 45f96b6..7cfd29c 100644 --- a/minishell_test/suite/decorator.py +++ b/minishell_test/suite/decorator.py @@ -6,7 +6,7 @@ # By: charles <me@cacharle.xyz> +#+ +:+ +#+ # # +#+#+#+#+#+ +#+ # # Created: 2020/09/11 12:28:00 by charles #+# #+# # -# Updated: 2021/02/05 17:44:25 by charles ### ########.fr # +# Updated: 2021/03/06 11:31:33 by cacharle ### ########.fr # # # # ############################################################################ # @@ -17,31 +17,49 @@ from minishell_test.suite import Suite from minishell_test.test import Test -def suite(groups: List[str] = [], bonus: bool = False): # type: ignore +class SuiteRegistrationException(Exception): + def __init__(self, function_name: str, message: str): + self._function_name = function_name + self._message = message + + def __str__(self) -> str: + return "Error during the registration of {self._function_name} as a suite: {self._message}" + + +_SUITE_FUNCTION_PREFIX = "suite_" + + +def suite(bonus: bool = False): # type: ignore """Decorator generator for suites arguments""" def suite_wrapper(origin): """Decorator for a suite function (fmt: suite_[name]) """ - mod = inspect.getmodule(origin) - if mod is None: - raise NotImplementedError - mod_name = mod.__name__[len("minishell_test.suites."):] - name = "{}/{}".format(mod_name, origin.__name__[len("suite_"):]) + # get the function name + function_name = origin.__name__ + if not function_name.startswith(_SUITE_FUNCTION_PREFIX): + raise SuiteRegistrationException(function_name, f"Function need to start with {_SUITE_FUNCTION_PREFIX}") + function_name = function_name[len(_SUITE_FUNCTION_PREFIX):] + # get the module name + module = inspect.getmodule(origin) + if module is None: + raise SuiteRegistrationException(function_name, "Could not get function module") + module_name = module.__name__[len("minishell_test.suites."):] + # get the first line of the function docstring as the suite description description = origin.__doc__ if description is None: - print("You should had a doc string to the {} suite".format(name)) + warnings.warn(f"You should had a doc string to the {name} suite") description = "no description" - description = description.split("\n")[0].strip() - s = Suite(name, groups + [mod_name], bonus, description) + description = description.splitlines()[0].strip() - def test_generator(): - def test(*args, **kwargs): - s.add(Test(*args, **kwargs)) - origin(test) + suite = Suite(origin, function_name, module_name, bonus, description) + Suite._available.append(suite) - s.generator_func = test_generator - Suite.available.append(s) - return test_generator + # def test_generator(): + # def test(*args, **kwargs): + # suite.append_test(Test(*args, **kwargs)) + # origin(test) + # suite.generator_func = test_generator + return origin return suite_wrapper diff --git a/minishell_test/suite/suite.py b/minishell_test/suite/suite.py index 2a87fbc..842a876 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 13:17:31 by cacharle ### ########.fr # +# Updated: 2021/03/06 15:57:52 by cacharle ### ########.fr # # # # ############################################################################ # @@ -14,6 +14,7 @@ from typing import List, Tuple, Optional, Callable from minishell_test.config import Config from minishell_test.test import Test +from minishell_test import colors class SuiteException(Exception): @@ -21,173 +22,156 @@ class SuiteException(Exception): pass -class AmbiguousNameException(SuiteException): - def __init__(self, name: str, matches: List[str]): - self.name = name - self.matches = matches +class SuiteExitFirstException(SuiteException): + pass - def __str__(self) -> str: - return (("Ambiguous name `{}` match the following suites\n\t{}\n" - "Try to run with -l to see the available suites") - .format(self.name, ', '.join(self.matches))) + +# class AmbiguousNameException(SuiteException): +# def __init__(self, name: str, matches: List[str]): +# self._name = name +# self._matches = matches +# +# def __str__(self) -> str: +# return (f"Ambiguous name `{self._name}` match the following suites" +# f"\n\t{', '.join(self._matches)}\n" +# "See the --list option to list the _available test suites") class NoMatchException(SuiteException): def __init__(self, name: str): - self.name = name + self._name = name def __str__(self) -> str: - return (("Name `{}` doesn't match any suite/group name\n\t" + return (f"Name `{self._name}` doesn't match any suite/group name\n\t" "Try to run with -l to see the available suites") - .format(self.name)) class Suite: - available: List['Suite'] = [] + _available: List['Suite'] = [] @classmethod - def run_all(cls): - """Run all available suites""" - for s in cls.available: - if not s.run() and Config.exit_first: - break + def run(cls, asked_names: List[str]) -> None: + """Run all _available suites""" - @classmethod - def setup(cls, asked_names: List[str]) -> None: - """ Remove not asked suite from available suites + """ Remove not asked suite from _available suites Tries to autocomplete the asked names """ + + asked_suites = cls._asked_suites(asked_names) + for suite in asked_suites: + suite._register() + for suite in asked_suites: + try: + suite._run() + except SuiteExitFirstException: + break + + @classmethod + def _asked_suites(cls, asked_names: [str]) -> ['Suite']: + suites = cls._available if not Config.bonus: - cls.available = [s for s in cls.available if not s.bonus] + suites = [suite for suite in cls._available if not suite._bonus] if len(asked_names) == 0: - asked_names = [s.name for s in cls.available] + asked_names = [suite._name for suite in suites] - suite_names = [s.name for s in cls.available] names = [] - for i, name in enumerate(asked_names): - if name in suite_names: - names.append(name) - continue - matches = [n for n in suite_names - if n.find("/") != -1 and - n[n.find("/") + 1:].startswith(name) or - n.startswith(name)] - if len(matches) == 1: - names.append(matches[0]) - elif len(matches) != 0 and all(n.startswith(name) for n in matches): - names.extend(matches) - elif len(matches) > 2: - raise AmbiguousNameException(name, matches) - elif len(matches) == 0: + for name in asked_names: + matches = [suite._name for suite in suites if suite._name.startswith(name) or suite._group.startswith(name)] + if len(matches) == 0: raise NoMatchException(name) + names.extend(matches) - cls.available = list(set( - [s for s in cls.available if s.name in names] + - [s for s in cls.available if any(g for g in s.groups if g in names)] + suites = list(set( + [suite for suite in suites if suite._name in names] + + [suite for suite in suites if suite._group in names] )) - cls.available.sort(key=lambda s: s.name) - for s in cls.available: - if s.generator_func is not None: - s.generator_func() + return sorted(suites, key=lambda suite: suite._name) @classmethod - def available_names(cls) -> List[str]: - """List of available suites names""" - return [s.name for s in cls.available] - - @classmethod - def list(cls): - print("Groups:") - print("\n".join({" - " + ', '.join(s.groups) for s in Suite.available})) - print("The available suites are:") - max_name_width = max(len(s.name) for s in Suite.available) + 5 - lines = [ - " - {:.<{max_name_width}} {}".format( - s.name + " ", - s.description, - max_name_width=max_name_width - ) - for s in Suite.available - ] - print("\n".join(lines)) + def list(cls) -> str: + max_name_width = max(len(suite._name + suite._group) for suite in cls._available) + 5 + out = "" + for suite in cls._available: + prefixed_name = f"{suite._group}/{suite._name} " + out += f"{prefixed_name:.<{max_name_width}} {suite._description}\n" + return out def __init__( self, - name: str, - groups: List[str], - bonus: bool = False, - description: str = "no description", + origin, + name: str, + group: str, + bonus: bool = False, + description: str = "no description", ): """Suite class name: suite id groups: list of suite groups bonus: is this suite bonus """ - self.name = name - self.groups = groups - self.description = description - 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""" - self.tests.append(test) - - BLUE_CHARS = "\033[34m" - CLOSE_CHARS = "\033[0m" - - def run(self) -> bool: + self._name = name + self._group = group + self._description = description + self._bonus = bonus + self._origin = origin + self._tests: List[Test] = [] + self._results: List[Result] = [] + + def _run(self) -> None: """Run all test in the suite""" - print("{}{:#^{width}}{}".format( - self.BLUE_CHARS, - " " + self.name + " ", - self.CLOSE_CHARS, - width=Config.term_cols - )) + + title = ' ' + self._name + ' ' + print(colors.blue(f"{title:#^{Config.term_cols}}")) if Config.range is not None: - self.tests = self.test[Config.range[0] : Config.range[1] + 1] - for i, test in enumerate(self.tests): + self._tests = self._tests[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 - return True - - def total(self) -> Tuple[int, int]: - """Returns the total of passed and failed tests""" - passed_total = 0 - for result in self.results: - if result is None: - return (-1, -1) - if result.passed: - passed_total += 1 - return passed_total, len(self.tests) - passed_total + self._results.append(result) + print(result.summarize(i)) + if Config.exit_first and result.failed: + raise SuiteExitFirstException() + + def _register(self) -> None: + def test(*args, **kwargs): + self._tests.append(Test(*args, **kwargs)) + self._origin(test) @classmethod def summarize(cls): """Print a summary of all runned suites""" - pass_sum = 0 - fail_sum = 0 - print("\nSummary:") - for s in cls.available: - (pass_total, fail_total) = s.total() - if pass_total == -1: - continue - pass_sum += pass_total - fail_sum += fail_total - print("{:.<{width}} \033[32m{:4} [PASS]\033[0m \033[31m{:4} [FAIL]\033[0m" - .format(s.name + " ", pass_total, fail_total, width=Config.term_cols - 24)) - print("{:.<{width}} \033[32m{:4} [PASS]\033[0m \033[31m{:4} [FAIL]\033[0m" - .format("TOTAL ", pass_sum, fail_sum, width=Config.term_cols - 24)) + full_pass_count = sum(suite._pass_count for suite in suites) + full_fail_count = sum(suite._fail_count for suite in suites) + lines = ["Summary:"] + for suite in cls._available: + lines.append(Suite._stat_summary(suite._name, suite._pass_count, suite._fail_count)) + lines.append(Suite._stat_summary("TOTAL", full_pass_count, full_fail_count)) + return "\n".join(lines) + "\n" + + @property + def _pass_count(self) -> int: + count = 0 + for result in self._results: + if result.passed: + count += 1 + return count + + @property + def _fail_count(self) -> int: + return len(self._results) - self._pass_count + + @staticmethod + def _stat_summary(self, name: str, pass_count: int, fail_count: int) -> str: + prefix = f"{name + ' ':.<{Config.term_cols - 24}}" + pass_str = colors.green("{pass_count:4} [PASS]") + fail_str = colors.red("{fail_count:4} [FAIL]") + return f"{prefix} {pass_str} {fail_str}" @classmethod - def save_log(cls): + def save(cls): """Save the result of all suites to a file""" colors.disable() - with open(Config.log_path, "w") as log_file: - for result in self.results: - if result is not None and result.failed: - log_file.write(result.full_diff() + '\n') + with open(Config.log_path, "w") as file: + for suite in suites: + for result in suite._results: + if result.failed: + file.write(result) |
