Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add live progress style and refactor output and progress styles #233

Merged
merged 18 commits into from
Jun 5, 2021
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ test:

coverage:
poetry run coverage run -m ward
poetry run coverage html -i
poetry run coverage report --skip-empty --show-missing --sort=-cover
poetry run coverage html
.PHONY: coverage

update:
Expand Down
14 changes: 0 additions & 14 deletions tests/test_cli.py

This file was deleted.

73 changes: 72 additions & 1 deletion tests/test_terminal.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,15 @@
from rich.table import Table
from rich.text import Text

from tests.utilities import example_test
from tests.utilities import example_test, testable_test
from ward import fixture, using
from ward._terminal import (
SessionPrelude,
TestProgressStyle,
TestTimingStatsPanel,
get_dot,
get_exit_code,
get_test_result_line,
outcome_to_style,
)
from ward._testing import _Timer
Expand Down Expand Up @@ -206,3 +209,71 @@ def _(timing_stats_panel=timing_stats_panel):
assert table.columns[0]._cells == expected_durations
assert len(table.columns[1]._cells) == 3
assert table.columns[2]._cells == expected_test_descriptions


@fixture
def test_result() -> TestResult:
@testable_test
def _():
assert True

return TestResult(
test=Test(
timer=_Timer(duration=4.0),
fn=_,
description="test1",
module_name="mod1",
),
outcome=TestOutcome.FAIL,
)


for idx, num_tests, expected_output in [
(0, 2, " 50%"),
(1, 2, "100%"),
(1, 3, " 67%"),
(2, 3, "100%"),
(16, 17, "100%"),
]:

@test(
"get_test_result_line with inline progress for test {idx} with {num_tests} tests emits {expected_output!r}"
)
def _(
idx=idx,
num_tests=num_tests,
expected_output=expected_output,
test_result=test_result,
):
output = get_test_result_line(
test_result=test_result,
test_index=idx,
num_tests=num_tests,
progress_styles=[TestProgressStyle.INLINE],
)

assert expected_output == list(output.columns[-1].cells)[0]


for outcome, expected_output in [
(TestOutcome.PASS, Text(".", style="pass")),
(TestOutcome.FAIL, Text("F", style="fail")),
(TestOutcome.SKIP, Text("-", style="skip")),
(TestOutcome.XPASS, Text("U", style="xpass")),
(TestOutcome.XFAIL, Text("x", style="xfail")),
(TestOutcome.DRYRUN, Text(".", style="dryrun")),
]:

@test("get_dot emits {expected_output!r} for test outcome {outcome}")
def _(outcome=outcome, expected_output=expected_output):
assert expected_output == get_dot(
TestResult(
test=Test(
timer=_Timer(duration=4.0),
fn=lambda: 1,
description="test1",
module_name="mod1",
),
outcome=outcome,
)
)
14 changes: 12 additions & 2 deletions ward/_debug.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,20 @@ def _breakpointhook(*args, **kwargs):
capture_enabled = context.params.get("capture_output")
capture_active = isinstance(sys.stdout, io.StringIO)

# Stop an active Live.
# It is the responsibility of the test executor
# to re-enable the Live.
live = console._live
if live is not None:
live.refresh()
live.stop()

if capture_enabled and capture_active:
sys.stdout = original_stdout
console.print("Entering debugger - output capturing disabled.", style="info")
return hook(*args, **kwargs)
console.print(
f"Entering debugger [bold]{hookname}[/] - output capturing disabled.",
style="info",
)

return hook(*args, **kwargs)

Expand Down
20 changes: 5 additions & 15 deletions ward/_run.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,20 +114,18 @@ def run(ctx: click.Context):
)
@click.option(
"--test-output-style",
type=click.Choice(list(TestOutputStyle), case_sensitive=False),
type=click.Choice([s.value for s in TestOutputStyle], case_sensitive=False),
default="test-per-line",
help="The style of output for displaying individual test results during the run.",
)
@click.option(
"--progress-style",
type=click.Choice(list(TestProgressStyle), case_sensitive=False),
type=click.Choice([s.value for s in TestProgressStyle], case_sensitive=False),
multiple=True,
default=["inline"],
help=f"""\
help="""\
The style of progress indicator to use during the run.
Pass multiple times to enable multiple styles.
The '{TestProgressStyle.BAR}' style is not compatible with the
'{TestOutputStyle.DOTS_GLOBAL}' and '{TestOutputStyle.DOTS_MODULE}' test output styles.
""",
)
@click.option(
Expand Down Expand Up @@ -186,17 +184,9 @@ def test(
config_params.pop("config")

config = Config(**config_params, plugin_config=config_params.get("plugins", {}))
progress_styles = [TestProgressStyle(ps) for ps in progress_style]

if TestProgressStyle.BAR in progress_styles and test_output_style in {
"dots-global",
"dots-module",
}:
raise click.BadOptionUsage(
"progress_style",
f"The '{TestProgressStyle.BAR}' progress style cannot be used with dots-based "
f"test output styles (you asked for '{test_output_style}').",
)
test_output_style = TestOutputStyle(test_output_style)
progress_styles = [TestProgressStyle(ps) for ps in progress_style]

init_breakpointhooks(pdb, sys)
start_run = default_timer()
Expand Down