aboutsummaryrefslogtreecommitdiff
path: root/minishell_test/suite/suite.py
diff options
context:
space:
mode:
authorCharles Cabergs <me@cacharle.xyz>2021-03-06 16:01:24 +0100
committerCharles Cabergs <me@cacharle.xyz>2021-03-06 16:01:24 +0100
commitfc7a0425a1e19807ec2819bdb73dc6aa14d0e197 (patch)
tree142225b152d462dcf903cb45523565671a65a0b4 /minishell_test/suite/suite.py
parent2a854b36624fb1c108a56d317aa54ca630864288 (diff)
downloadminishell_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/suite.py')
-rw-r--r--minishell_test/suite/suite.py236
1 files changed, 110 insertions, 126 deletions
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)