From 07ed2de9d0f4747d5ff0a231b2f72d48d2c9bf42 Mon Sep 17 00:00:00 2001 From: Darren Burns Date: Sat, 9 Nov 2019 18:42:40 +0000 Subject: [PATCH] Formatting descriptions, displaying parameterised tests in output --- tests/test_util.py | 21 ++++++++++++++++++--- ward/suite.py | 1 + ward/terminal.py | 26 ++++++++++++-------------- ward/testing.py | 25 +++++++++++++++++++++++++ ward/util.py | 5 +++++ 5 files changed, 61 insertions(+), 17 deletions(-) diff --git a/tests/test_util.py b/tests/test_util.py index 597e1926..bdff864e 100644 --- a/tests/test_util.py +++ b/tests/test_util.py @@ -1,7 +1,7 @@ from tests.test_suite import example_test -from ward import expect, test, using -from ward.testing import TestOutcome, TestResult -from ward.util import ExitCode, get_exit_code +from ward import expect, test, using, fixture +from ward.testing import TestOutcome, TestResult, each +from ward.util import ExitCode, get_exit_code, truncate @test( @@ -37,3 +37,18 @@ def _(example=example_test): exit_code = get_exit_code(test_results) expect(exit_code).equals(ExitCode.FAILED) + + +@fixture +def s(): + return "hello world" + + +@test("truncate('{input}', num_chars={num_chars}) returns '{expected}'") +def _( + input=s, + num_chars=each(20, 11, 10, 5), + expected=each(s, s, "hello w...", "he..."), +): + result = truncate(input, num_chars) + expect(result).equals(expected) diff --git a/ward/suite.py b/ward/suite.py index 7ab15cc2..eb8fd03f 100644 --- a/ward/suite.py +++ b/ward/suite.py @@ -37,6 +37,7 @@ def generate_test_runs(self) -> Generator[TestResult, None, None]: try: resolved_vals = generated_test.resolve_args(self.cache, iteration=i) + generated_test.format_description(resolved_vals) generated_test(**resolved_vals) outcome = ( TestOutcome.XPASS if marker == "XFAIL" else TestOutcome.PASS diff --git a/ward/terminal.py b/ward/terminal.py index ee1e84c5..817fed61 100644 --- a/ward/terminal.py +++ b/ward/terminal.py @@ -11,12 +11,7 @@ from ward.expect import ExpectationFailed, Expected from ward.suite import Suite from ward.testing import TestOutcome, TestResult -from ward.util import ExitCode, get_exit_code - - -def truncate(s: str, num_chars: int) -> str: - suffix = "..." if len(s) > num_chars - 3 else "" - return s[:num_chars] + suffix +from ward.util import ExitCode, get_exit_code, truncate class TestResultWriterBase: @@ -120,11 +115,17 @@ def output_single_test_result(self, test_result: TestResult): colour = outcome_to_colour[test_result.outcome] bg = f"on_{colour}" padded_outcome = f" {test_result.outcome.name[:4]} " - if test_result.test.description: - sep = f":{test_result.test.line_number}: " + + # If we're executing a parameterised test + param_meta = test_result.test.param_meta + if param_meta.group_size > 1: + iter_indicator = f" [{param_meta.instance_index + 1} of {param_meta.group_size}]" else: - sep = "." - mod_name = lightblack(f"{test_result.test.module_name}{sep}") + iter_indicator = "" + + mod_name = lightblack(f"{test_result.test.module_name}:" + f"{test_result.test.line_number}" + f"{iter_indicator}: ") if ( test_result.outcome == TestOutcome.SKIP or test_result.outcome == TestOutcome.XFAIL @@ -135,10 +136,7 @@ def output_single_test_result(self, test_result: TestResult): else: reason = "" - if test_result.test.description: - name_or_desc = test_result.test.description - else: - name_or_desc = test_result.test.name + name_or_desc = test_result.test.description print( colored(padded_outcome, color="grey", on_color=bg), mod_name + name_or_desc, diff --git a/ward/testing.py b/ward/testing.py index 4b4ed3df..ef80b8d5 100644 --- a/ward/testing.py +++ b/ward/testing.py @@ -76,6 +76,11 @@ def generate_id(): return uuid.uuid4().hex +class FormatDict(dict): + def __missing__(self, key): + return "{" + key + "}" + + @dataclass class ParamMeta: instance_index: int = 0 @@ -312,6 +317,26 @@ def _unpack_resolved(self, fixture_dict: Dict[str, Any]) -> Dict[str, Any]: resolved_vals[k] = arg return resolved_vals + def format_description(self, arg_map: Dict[str, Any]) -> str: + """ + Applies any necessary string formatting to the description, + given a dictionary `arg_map` of values that will be injected + into the test. + + This method will mutate the Test by updating the description. + Returns the newly updated description. + """ + format_dict = FormatDict(**arg_map) + if not self.description: + self.description = "" + + try: + self.description = self.description.format_map(format_dict) + except ValueError: + pass + + return self.description + # Tests declared with the name _, and with the @test decorator # have to be stored in here, so that they can later be retrieved. diff --git a/ward/util.py b/ward/util.py index afeb8563..6cd42a83 100644 --- a/ward/util.py +++ b/ward/util.py @@ -18,3 +18,8 @@ def get_exit_code(results: Iterable[TestResult]) -> ExitCode: else: exit_code = ExitCode.SUCCESS return exit_code + + +def truncate(s: str, num_chars: int) -> str: + suffix = "..." if len(s) > num_chars else "" + return s[:num_chars - len(suffix)] + suffix