tenzir-test 0.9.3__tar.gz → 0.9.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/PKG-INFO +1 -1
- tenzir_test-0.9.4/example-project/tests/fail.tql +3 -0
- tenzir_test-0.9.4/example-project/tests/fail.txt +28 -0
- tenzir_test-0.9.4/example-project/tests/shell/http-fixture-check.txt +0 -0
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/pyproject.toml +1 -1
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/src/tenzir_test/cli.py +16 -0
- tenzir_test-0.9.4/src/tenzir_test/py.typed +0 -0
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/src/tenzir_test/run.py +121 -20
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/tests/test_cli.py +26 -0
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/tests/test_run.py +141 -0
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/.gitignore +0 -0
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/LICENSE +0 -0
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/README.md +0 -0
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/example-project/README.md +0 -0
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/example-project/fixtures/README.md +0 -0
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/example-project/fixtures/__init__.py +0 -0
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/example-project/fixtures/http.py +0 -0
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/example-project/fixtures/server.py +0 -0
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/example-project/inputs/events.ndjson +0 -0
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/example-project/runners/__init__.py +0 -0
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/example-project/runners/xxd.py +0 -0
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/example-project/tests/context/01-context-create.tql +0 -0
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/example-project/tests/context/01-context-create.txt +0 -0
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/example-project/tests/context/02-context-update.tql +0 -0
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/example-project/tests/context/02-context-update.txt +0 -0
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/example-project/tests/context/03-context-inspect.tql +0 -0
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/example-project/tests/context/03-context-inspect.txt +0 -0
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/example-project/tests/context/test.yaml +0 -0
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/example-project/tests/hex/hello.txt +0 -0
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/example-project/tests/hex/hello.xxd +0 -0
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/example-project/tests/http-fixture.tql +0 -0
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/example-project/tests/http-fixture.txt +0 -0
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/example-project/tests/lazy.tql +0 -0
- /tenzir_test-0.9.3/src/tenzir_test/py.typed → /tenzir_test-0.9.4/example-project/tests/lazy.txt +0 -0
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/example-project/tests/node-fixture.tql +0 -0
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/example-project/tests/node-fixture.txt +0 -0
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/example-project/tests/python/executor-only/sum.py +0 -0
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/example-project/tests/python/executor-only/sum.txt +0 -0
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/example-project/tests/python/executor-with-http-fixture/request.py +0 -0
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/example-project/tests/python/executor-with-http-fixture/request.txt +0 -0
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/example-project/tests/python/executor-with-http-fixture/test.yaml +0 -0
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/example-project/tests/python/executor-with-node-fixture/context-manager.py +0 -0
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/example-project/tests/python/executor-with-node-fixture/context-manager.txt +0 -0
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/example-project/tests/python/fixture-driving/manual_control.py +0 -0
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/example-project/tests/python/fixture-driving/manual_control.txt +0 -0
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/example-project/tests/python/pure-python/flaky_coin.py +0 -0
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/example-project/tests/python/pure-python/flaky_coin.txt +0 -0
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/example-project/tests/python/pure-python/hello_world.py +0 -0
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/example-project/tests/python/pure-python/hello_world.txt +0 -0
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/example-project/tests/read-inputs.tql +0 -0
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/example-project/tests/read-inputs.txt +0 -0
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/example-project/tests/shell/http-fixture-check.sh +0 -0
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/example-project/tests/shell/tmp-dir.sh +0 -0
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/example-project/tests/shell/tmp-dir.txt +0 -0
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/src/tenzir_test/__init__.py +0 -0
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/src/tenzir_test/_python_runner.py +0 -0
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/src/tenzir_test/checks.py +0 -0
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/src/tenzir_test/config.py +0 -0
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/src/tenzir_test/engine/__init__.py +0 -0
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/src/tenzir_test/engine/operations.py +0 -0
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/src/tenzir_test/engine/registry.py +0 -0
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/src/tenzir_test/engine/state.py +0 -0
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/src/tenzir_test/engine/worker.py +0 -0
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/src/tenzir_test/fixtures/__init__.py +0 -0
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/src/tenzir_test/fixtures/node.py +0 -0
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/src/tenzir_test/packages.py +0 -0
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/src/tenzir_test/runners/__init__.py +0 -0
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/src/tenzir_test/runners/_utils.py +0 -0
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/src/tenzir_test/runners/custom_python_fixture_runner.py +0 -0
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/src/tenzir_test/runners/diff_runner.py +0 -0
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/src/tenzir_test/runners/ext_runner.py +0 -0
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/src/tenzir_test/runners/runner.py +0 -0
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/src/tenzir_test/runners/shell_runner.py +0 -0
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/src/tenzir_test/runners/tenzir_runner.py +0 -0
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/src/tenzir_test/runners/tql_runner.py +0 -0
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/tests/test_config.py +0 -0
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/tests/test_engine_operations.py +0 -0
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/tests/test_python_runner.py +0 -0
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/tests/test_run_config.py +0 -0
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/tests/test_runner_registry.py +0 -0
- {tenzir_test-0.9.3 → tenzir_test-0.9.4}/tests/test_shell_runner.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tenzir-test
|
|
3
|
-
Version: 0.9.
|
|
3
|
+
Version: 0.9.4
|
|
4
4
|
Summary: Reusable test execution framework extracted from the Tenzir repository.
|
|
5
5
|
Project-URL: Homepage, https://github.com/tenzir/test
|
|
6
6
|
Project-URL: Repository, https://github.com/tenzir/test
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"#": 0,
|
|
3
|
+
x: "foo",
|
|
4
|
+
}
|
|
5
|
+
{
|
|
6
|
+
"#": 1,
|
|
7
|
+
x: "foo",
|
|
8
|
+
}
|
|
9
|
+
{
|
|
10
|
+
"#": -1,
|
|
11
|
+
x: "qux",
|
|
12
|
+
}
|
|
13
|
+
{
|
|
14
|
+
"#": 3,
|
|
15
|
+
x: "foo",
|
|
16
|
+
}
|
|
17
|
+
{
|
|
18
|
+
"#": 4,
|
|
19
|
+
x: "foo",
|
|
20
|
+
}
|
|
21
|
+
{
|
|
22
|
+
"#": -1,
|
|
23
|
+
x: "foo",
|
|
24
|
+
}
|
|
25
|
+
{
|
|
26
|
+
"#": -1,
|
|
27
|
+
x: "baz",
|
|
28
|
+
}
|
|
File without changes
|
|
@@ -90,6 +90,18 @@ def _normalize_exit_code(value: object) -> int:
|
|
|
90
90
|
is_flag=True,
|
|
91
91
|
help="Show an aggregate table and detailed failure summary after execution.",
|
|
92
92
|
)
|
|
93
|
+
@click.option(
|
|
94
|
+
"--diff/--no-diff",
|
|
95
|
+
"show_diff_output",
|
|
96
|
+
default=True,
|
|
97
|
+
help="Show unified diffs when expectations differ.",
|
|
98
|
+
)
|
|
99
|
+
@click.option(
|
|
100
|
+
"--diff-stat/--no-diff-stat",
|
|
101
|
+
"show_diff_stat",
|
|
102
|
+
default=True,
|
|
103
|
+
help="Include per-file diff statistics and change counters when expectations differ.",
|
|
104
|
+
)
|
|
93
105
|
@click.option(
|
|
94
106
|
"-k",
|
|
95
107
|
"--keep",
|
|
@@ -134,6 +146,8 @@ def cli(
|
|
|
134
146
|
runner_summary: bool,
|
|
135
147
|
fixture_summary: bool,
|
|
136
148
|
show_summary: bool,
|
|
149
|
+
show_diff_output: bool,
|
|
150
|
+
show_diff_stat: bool,
|
|
137
151
|
keep_tmp_dirs: bool,
|
|
138
152
|
jobs: int,
|
|
139
153
|
passthrough: bool,
|
|
@@ -157,6 +171,8 @@ def cli(
|
|
|
157
171
|
runner_summary=runner_summary,
|
|
158
172
|
fixture_summary=fixture_summary,
|
|
159
173
|
show_summary=show_summary,
|
|
174
|
+
show_diff_output=show_diff_output,
|
|
175
|
+
show_diff_stat=show_diff_stat,
|
|
160
176
|
keep_tmp_dirs=keep_tmp_dirs,
|
|
161
177
|
jobs=jobs,
|
|
162
178
|
passthrough=passthrough,
|
|
File without changes
|
|
@@ -351,6 +351,30 @@ _TMP_BASE_DIRS: set[Path] = set()
|
|
|
351
351
|
_ACTIVE_TMP_DIRS: set[Path] = set()
|
|
352
352
|
KEEP_TMP_DIRS = bool(os.environ.get(_TMP_KEEP_ENV_VAR))
|
|
353
353
|
|
|
354
|
+
SHOW_DIFF_OUTPUT = True
|
|
355
|
+
SHOW_DIFF_STAT = True
|
|
356
|
+
_BLOCK_INDENT = ""
|
|
357
|
+
_PLUS_SYMBOLS = {1: "□", 10: "▣", 100: "■"}
|
|
358
|
+
_MINUS_SYMBOLS = {1: "□", 10: "▣", 100: "■"}
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
def set_show_diff_output(enabled: bool) -> None:
|
|
362
|
+
global SHOW_DIFF_OUTPUT
|
|
363
|
+
SHOW_DIFF_OUTPUT = enabled
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
def should_show_diff_output() -> bool:
|
|
367
|
+
return SHOW_DIFF_OUTPUT
|
|
368
|
+
|
|
369
|
+
|
|
370
|
+
def set_show_diff_stat(enabled: bool) -> None:
|
|
371
|
+
global SHOW_DIFF_STAT
|
|
372
|
+
SHOW_DIFF_STAT = enabled
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
def should_show_diff_stat() -> bool:
|
|
376
|
+
return SHOW_DIFF_STAT
|
|
377
|
+
|
|
354
378
|
|
|
355
379
|
def set_harness_mode(mode: HarnessMode) -> None:
|
|
356
380
|
"""Set the global harness execution mode."""
|
|
@@ -2015,10 +2039,9 @@ def _summarize_harness_configuration(
|
|
|
2015
2039
|
runner_summary: bool,
|
|
2016
2040
|
fixture_summary: bool,
|
|
2017
2041
|
passthrough: bool,
|
|
2018
|
-
) -> tuple[int, str]:
|
|
2042
|
+
) -> tuple[int, str, str]:
|
|
2019
2043
|
enabled_flags: list[str] = []
|
|
2020
2044
|
toggles = (
|
|
2021
|
-
("update", update),
|
|
2022
2045
|
("coverage", coverage),
|
|
2023
2046
|
("debug", debug),
|
|
2024
2047
|
("summary", show_summary),
|
|
@@ -2029,9 +2052,13 @@ def _summarize_harness_configuration(
|
|
|
2029
2052
|
for name, flag in toggles:
|
|
2030
2053
|
if flag:
|
|
2031
2054
|
enabled_flags.append(name)
|
|
2032
|
-
if
|
|
2033
|
-
|
|
2034
|
-
|
|
2055
|
+
if update:
|
|
2056
|
+
verb = "updating"
|
|
2057
|
+
elif passthrough:
|
|
2058
|
+
verb = "showing"
|
|
2059
|
+
else:
|
|
2060
|
+
verb = "running"
|
|
2061
|
+
return jobs, ", ".join(enabled_flags), verb
|
|
2035
2062
|
|
|
2036
2063
|
|
|
2037
2064
|
def _relativize_path(path: Path) -> Path:
|
|
@@ -2395,7 +2422,46 @@ def last_and(items: Iterable[T]) -> Iterator[tuple[bool, T]]:
|
|
|
2395
2422
|
for item in iterator:
|
|
2396
2423
|
yield (False, previous)
|
|
2397
2424
|
previous = item
|
|
2398
|
-
|
|
2425
|
+
|
|
2426
|
+
|
|
2427
|
+
def _format_unary_symbols(count: int, symbols: dict[int, str]) -> str:
|
|
2428
|
+
if count <= 0:
|
|
2429
|
+
return ""
|
|
2430
|
+
hundreds, remainder = divmod(count, 100)
|
|
2431
|
+
tens, ones = divmod(remainder, 10)
|
|
2432
|
+
parts: list[str] = []
|
|
2433
|
+
if hundreds:
|
|
2434
|
+
parts.append(symbols[100] * hundreds)
|
|
2435
|
+
if tens:
|
|
2436
|
+
parts.append(symbols[10] * tens)
|
|
2437
|
+
if ones:
|
|
2438
|
+
parts.append(symbols[1] * ones)
|
|
2439
|
+
return "".join(parts)
|
|
2440
|
+
|
|
2441
|
+
|
|
2442
|
+
def _format_diff_counter(added: int, removed: int) -> str:
|
|
2443
|
+
plus_segment = _format_unary_symbols(added, _PLUS_SYMBOLS)
|
|
2444
|
+
minus_segment = _format_unary_symbols(removed, _MINUS_SYMBOLS)
|
|
2445
|
+
colored_plus = f"\033[32m{plus_segment}\033[0m" if plus_segment else ""
|
|
2446
|
+
colored_minus = f"\033[31m{minus_segment}\033[0m" if minus_segment else ""
|
|
2447
|
+
return f"{colored_plus}{colored_minus}"
|
|
2448
|
+
|
|
2449
|
+
|
|
2450
|
+
def _format_stat_header(path: os.PathLike[str] | str, added: int, removed: int) -> str:
|
|
2451
|
+
path_str = os.fspath(path)
|
|
2452
|
+
counter = _format_diff_counter(added, removed)
|
|
2453
|
+
plus_count = f"\033[32m{added}(+)\033[0m"
|
|
2454
|
+
minus_count = f"\033[31m{removed}(-)\033[0m"
|
|
2455
|
+
if counter:
|
|
2456
|
+
counter_segment = f" {counter}"
|
|
2457
|
+
else:
|
|
2458
|
+
counter_segment = ""
|
|
2459
|
+
return f"{_BLOCK_INDENT}┌ {path_str} {plus_count}/{minus_count}{counter_segment}"
|
|
2460
|
+
|
|
2461
|
+
|
|
2462
|
+
def _format_lines_changed(total: int) -> str:
|
|
2463
|
+
line = "line" if total == 1 else "lines"
|
|
2464
|
+
return f"{_BLOCK_INDENT}└ {total} {line} changed"
|
|
2399
2465
|
|
|
2400
2466
|
|
|
2401
2467
|
def print_diff(expected: bytes, actual: bytes, path: Path) -> None:
|
|
@@ -2409,22 +2475,51 @@ def print_diff(expected: bytes, actual: bytes, path: Path) -> None:
|
|
|
2409
2475
|
n=2,
|
|
2410
2476
|
)
|
|
2411
2477
|
)
|
|
2412
|
-
|
|
2413
|
-
|
|
2478
|
+
added = sum(
|
|
2479
|
+
1
|
|
2480
|
+
for index, line in enumerate(diff)
|
|
2481
|
+
if index >= 2 and line.startswith(b"+") and not line.startswith(b"+++")
|
|
2482
|
+
)
|
|
2483
|
+
removed = sum(
|
|
2484
|
+
1
|
|
2485
|
+
for index, line in enumerate(diff)
|
|
2486
|
+
if index >= 2 and line.startswith(b"-") and not line.startswith(b"---")
|
|
2487
|
+
)
|
|
2488
|
+
show_stat = should_show_diff_stat()
|
|
2489
|
+
show_diff = should_show_diff_output()
|
|
2490
|
+
diff_lines: list[str] = []
|
|
2491
|
+
if should_show_diff_output():
|
|
2414
2492
|
skip = 2
|
|
2415
|
-
for
|
|
2493
|
+
for raw_line in diff:
|
|
2416
2494
|
if skip > 0:
|
|
2417
2495
|
skip -= 1
|
|
2418
2496
|
continue
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2497
|
+
text = raw_line.decode("utf-8", "replace").rstrip("\r\n")
|
|
2498
|
+
if raw_line.startswith(b"+") and not raw_line.startswith(b"+++"):
|
|
2499
|
+
text = f"\033[32m{text}\033[0m"
|
|
2500
|
+
elif raw_line.startswith(b"-") and not raw_line.startswith(b"---"):
|
|
2501
|
+
text = f"\033[31m{text}\033[0m"
|
|
2502
|
+
diff_lines.append(text)
|
|
2503
|
+
rel_path = _relativize_path(path)
|
|
2504
|
+
rel_path_str = os.fspath(rel_path)
|
|
2505
|
+
lines: list[str] = []
|
|
2506
|
+
total_changed = added + removed
|
|
2507
|
+
if not show_stat and not show_diff:
|
|
2508
|
+
return
|
|
2509
|
+
header = (
|
|
2510
|
+
_format_stat_header(rel_path, added, removed)
|
|
2511
|
+
if show_stat
|
|
2512
|
+
else f"{_BLOCK_INDENT}┌ {rel_path_str}"
|
|
2513
|
+
)
|
|
2514
|
+
lines.append(header)
|
|
2515
|
+
if show_diff and diff_lines:
|
|
2516
|
+
for diff_line in diff_lines:
|
|
2517
|
+
lines.append(f"{_BLOCK_INDENT}│ {diff_line}")
|
|
2518
|
+
if show_stat or (show_diff and total_changed > 0):
|
|
2519
|
+
lines.append(_format_lines_changed(total_changed))
|
|
2520
|
+
with stdout_lock:
|
|
2521
|
+
for output_line in lines:
|
|
2522
|
+
print(output_line)
|
|
2428
2523
|
|
|
2429
2524
|
|
|
2430
2525
|
def check_group_is_empty(pgid: int) -> None:
|
|
@@ -2889,6 +2984,8 @@ def run_cli(
|
|
|
2889
2984
|
runner_summary: bool,
|
|
2890
2985
|
fixture_summary: bool,
|
|
2891
2986
|
show_summary: bool,
|
|
2987
|
+
show_diff_output: bool,
|
|
2988
|
+
show_diff_stat: bool,
|
|
2892
2989
|
jobs: int,
|
|
2893
2990
|
keep_tmp_dirs: bool,
|
|
2894
2991
|
passthrough: bool,
|
|
@@ -2937,6 +3034,8 @@ def run_cli(
|
|
|
2937
3034
|
fixture_logger.propagate = True
|
|
2938
3035
|
|
|
2939
3036
|
set_keep_tmp_dirs(bool(os.environ.get(_TMP_KEEP_ENV_VAR)) or keep_tmp_dirs)
|
|
3037
|
+
set_show_diff_output(show_diff_output)
|
|
3038
|
+
set_show_diff_stat(show_diff_stat)
|
|
2940
3039
|
if passthrough:
|
|
2941
3040
|
harness_mode = HarnessMode.PASSTHROUGH
|
|
2942
3041
|
elif update:
|
|
@@ -3122,7 +3221,7 @@ def run_cli(
|
|
|
3122
3221
|
queue = _build_queue_from_paths(collected_paths, coverage=coverage)
|
|
3123
3222
|
queue.sort(key=_queue_sort_key, reverse=True)
|
|
3124
3223
|
project_queue_size = _count_queue_tests(queue)
|
|
3125
|
-
job_count, enabled_flags = _summarize_harness_configuration(
|
|
3224
|
+
job_count, enabled_flags, verb = _summarize_harness_configuration(
|
|
3126
3225
|
jobs=jobs,
|
|
3127
3226
|
update=update,
|
|
3128
3227
|
coverage=coverage,
|
|
@@ -3159,6 +3258,7 @@ def run_cli(
|
|
|
3159
3258
|
queue_size=project_queue_size,
|
|
3160
3259
|
job_count=job_count,
|
|
3161
3260
|
enabled_flags=enabled_flags,
|
|
3261
|
+
verb=verb,
|
|
3162
3262
|
)
|
|
3163
3263
|
count_width = max((len(str(count)) for _, count, _ in runner_breakdown), default=1)
|
|
3164
3264
|
for name, count, version in runner_breakdown:
|
|
@@ -3266,6 +3366,7 @@ def _print_project_start(
|
|
|
3266
3366
|
queue_size: int,
|
|
3267
3367
|
job_count: int,
|
|
3268
3368
|
enabled_flags: str,
|
|
3369
|
+
verb: str,
|
|
3269
3370
|
) -> None:
|
|
3270
3371
|
project_name = selection.root.name or selection.root.as_posix()
|
|
3271
3372
|
if selection.kind == "root":
|
|
@@ -3284,5 +3385,5 @@ def _print_project_start(
|
|
|
3284
3385
|
toggles = f"; {enabled_flags}" if enabled_flags else ""
|
|
3285
3386
|
jobs_segment = f" ({job_count} jobs)" if job_count else ""
|
|
3286
3387
|
print(
|
|
3287
|
-
f"{INFO} {project_display}:
|
|
3388
|
+
f"{INFO} {project_display}: {verb} {queue_size} tests{jobs_segment} from {project_kind} at {location_display}{toggles}"
|
|
3288
3389
|
)
|
|
@@ -38,6 +38,7 @@ def test_cli_keep_flag(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
|
38
38
|
assert captured["jobs_overridden"] is False
|
|
39
39
|
assert captured["all_projects"] is False
|
|
40
40
|
assert captured["show_summary"] is False
|
|
41
|
+
assert captured["show_diff_stat"] is True
|
|
41
42
|
|
|
42
43
|
|
|
43
44
|
def test_cli_passthrough_flag(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
@@ -109,6 +110,31 @@ def test_cli_summary_flag(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
|
109
110
|
assert captured["show_summary"] is True
|
|
110
111
|
|
|
111
112
|
|
|
113
|
+
def test_cli_no_diff_flag(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
114
|
+
captured: dict[str, object] = {}
|
|
115
|
+
|
|
116
|
+
def fake_run_cli(**kwargs: object) -> None:
|
|
117
|
+
captured.update(kwargs)
|
|
118
|
+
|
|
119
|
+
monkeypatch.setattr(cli.runtime, "run_cli", fake_run_cli)
|
|
120
|
+
|
|
121
|
+
assert cli.main(["--no-diff"]) == 0
|
|
122
|
+
assert captured["show_diff_output"] is False
|
|
123
|
+
assert captured["show_diff_stat"] is True
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def test_cli_no_diff_stat_flag(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
127
|
+
captured: dict[str, object] = {}
|
|
128
|
+
|
|
129
|
+
def fake_run_cli(**kwargs: object) -> None:
|
|
130
|
+
captured.update(kwargs)
|
|
131
|
+
|
|
132
|
+
monkeypatch.setattr(cli.runtime, "run_cli", fake_run_cli)
|
|
133
|
+
|
|
134
|
+
assert cli.main(["--no-diff-stat"]) == 0
|
|
135
|
+
assert captured["show_diff_stat"] is False
|
|
136
|
+
|
|
137
|
+
|
|
112
138
|
def test_cli_version_flag(capsys: pytest.CaptureFixture[str]) -> None:
|
|
113
139
|
exit_code = cli.main(["--version"])
|
|
114
140
|
assert exit_code == 0
|
|
@@ -769,6 +769,8 @@ def test_cli_rejects_partial_suite_selection(
|
|
|
769
769
|
runner_summary=False,
|
|
770
770
|
fixture_summary=False,
|
|
771
771
|
show_summary=False,
|
|
772
|
+
show_diff_output=True,
|
|
773
|
+
show_diff_stat=True,
|
|
772
774
|
jobs=1,
|
|
773
775
|
keep_tmp_dirs=False,
|
|
774
776
|
passthrough=False,
|
|
@@ -793,6 +795,8 @@ def test_cli_rejects_partial_suite_selection(
|
|
|
793
795
|
runner_summary=False,
|
|
794
796
|
fixture_summary=False,
|
|
795
797
|
show_summary=False,
|
|
798
|
+
show_diff_output=True,
|
|
799
|
+
show_diff_stat=True,
|
|
796
800
|
jobs=1,
|
|
797
801
|
keep_tmp_dirs=False,
|
|
798
802
|
passthrough=False,
|
|
@@ -828,6 +832,82 @@ def test_detailed_summary_order(capsys):
|
|
|
828
832
|
assert skipped_index < failed_index < table_start
|
|
829
833
|
|
|
830
834
|
|
|
835
|
+
def test_print_diff_default_layout(capsys):
|
|
836
|
+
original_show_diff = run.should_show_diff_output()
|
|
837
|
+
original_show_stat = run.should_show_diff_stat()
|
|
838
|
+
try:
|
|
839
|
+
run.set_show_diff_output(True)
|
|
840
|
+
run.set_show_diff_stat(True)
|
|
841
|
+
run.print_diff(b"line\nbeta\n", b"line\ngamma\n", Path("tests/example.txt"))
|
|
842
|
+
finally:
|
|
843
|
+
run.set_show_diff_output(original_show_diff)
|
|
844
|
+
run.set_show_diff_stat(original_show_stat)
|
|
845
|
+
|
|
846
|
+
output = capsys.readouterr().out.splitlines()
|
|
847
|
+
assert output[0].startswith(f"{run._BLOCK_INDENT}┌ tests/example.txt")
|
|
848
|
+
expected_counter = run._format_diff_counter(1, 1)
|
|
849
|
+
assert "\033[32m1(+)\033[0m/\033[31m1(-)\033[0m" in output[0]
|
|
850
|
+
assert output[0].endswith(expected_counter)
|
|
851
|
+
assert output[1] == f"{run._BLOCK_INDENT}│ @@ -1,2 +1,2 @@"
|
|
852
|
+
assert output[2] == f"{run._BLOCK_INDENT}│ line"
|
|
853
|
+
assert output[3].startswith(f"{run._BLOCK_INDENT}│ \033[31m-beta")
|
|
854
|
+
assert output[4].startswith(f"{run._BLOCK_INDENT}│ \033[32m+gamma")
|
|
855
|
+
assert output[5] == f"{run._BLOCK_INDENT}└ 2 lines changed"
|
|
856
|
+
|
|
857
|
+
|
|
858
|
+
def test_print_diff_no_diff_outputs_stat_only(capsys):
|
|
859
|
+
original_show_diff = run.should_show_diff_output()
|
|
860
|
+
original_show_stat = run.should_show_diff_stat()
|
|
861
|
+
try:
|
|
862
|
+
run.set_show_diff_output(False)
|
|
863
|
+
run.set_show_diff_stat(True)
|
|
864
|
+
run.print_diff(b"line\nbeta\n", b"line\ngamma\n", Path("tests/example.txt"))
|
|
865
|
+
finally:
|
|
866
|
+
run.set_show_diff_output(original_show_diff)
|
|
867
|
+
run.set_show_diff_stat(original_show_stat)
|
|
868
|
+
|
|
869
|
+
output = capsys.readouterr().out.splitlines()
|
|
870
|
+
expected_header = (
|
|
871
|
+
f"{run._BLOCK_INDENT}┌ tests/example.txt "
|
|
872
|
+
f"\033[32m1(+)\033[0m/\033[31m1(-)\033[0m {run._format_diff_counter(1, 1)}"
|
|
873
|
+
)
|
|
874
|
+
assert output == [
|
|
875
|
+
expected_header,
|
|
876
|
+
f"{run._BLOCK_INDENT}└ 2 lines changed",
|
|
877
|
+
]
|
|
878
|
+
|
|
879
|
+
|
|
880
|
+
def test_print_diff_stat_disabled_shows_only_diff(capsys):
|
|
881
|
+
original_show_diff = run.should_show_diff_output()
|
|
882
|
+
original_show_stat = run.should_show_diff_stat()
|
|
883
|
+
try:
|
|
884
|
+
run.set_show_diff_output(True)
|
|
885
|
+
run.set_show_diff_stat(False)
|
|
886
|
+
run.print_diff(b"line\nbeta\n", b"line\ngamma\n", Path("tests/example.txt"))
|
|
887
|
+
finally:
|
|
888
|
+
run.set_show_diff_output(original_show_diff)
|
|
889
|
+
run.set_show_diff_stat(original_show_stat)
|
|
890
|
+
|
|
891
|
+
output = capsys.readouterr().out.splitlines()
|
|
892
|
+
assert output[0] == f"{run._BLOCK_INDENT}┌ tests/example.txt"
|
|
893
|
+
assert output[1] == f"{run._BLOCK_INDENT}│ @@ -1,2 +1,2 @@"
|
|
894
|
+
assert output[-1] == f"{run._BLOCK_INDENT}└ 2 lines changed"
|
|
895
|
+
|
|
896
|
+
|
|
897
|
+
def test_print_diff_disabled_outputs_nothing(capsys):
|
|
898
|
+
original_show_diff = run.should_show_diff_output()
|
|
899
|
+
original_show_stat = run.should_show_diff_stat()
|
|
900
|
+
try:
|
|
901
|
+
run.set_show_diff_output(False)
|
|
902
|
+
run.set_show_diff_stat(False)
|
|
903
|
+
run.print_diff(b"line\nbeta\n", b"line\ngamma\n", Path("tests/example.txt"))
|
|
904
|
+
finally:
|
|
905
|
+
run.set_show_diff_output(original_show_diff)
|
|
906
|
+
run.set_show_diff_stat(original_show_stat)
|
|
907
|
+
|
|
908
|
+
assert capsys.readouterr().out.strip() == ""
|
|
909
|
+
|
|
910
|
+
|
|
831
911
|
def test_describe_project_root_detects_standard_project(tmp_path: Path) -> None:
|
|
832
912
|
project_root = tmp_path / "proj"
|
|
833
913
|
tests_dir = project_root / "tests"
|
|
@@ -1143,6 +1223,7 @@ def test_print_project_start_reports_empty_projects(tmp_path, capsys):
|
|
|
1143
1223
|
queue_size=0,
|
|
1144
1224
|
job_count=0,
|
|
1145
1225
|
enabled_flags="",
|
|
1226
|
+
verb="running",
|
|
1146
1227
|
)
|
|
1147
1228
|
|
|
1148
1229
|
output = capsys.readouterr().out
|
|
@@ -1152,6 +1233,66 @@ def test_print_project_start_reports_empty_projects(tmp_path, capsys):
|
|
|
1152
1233
|
)
|
|
1153
1234
|
|
|
1154
1235
|
|
|
1236
|
+
def test_summarize_harness_configuration_sets_update_verb() -> None:
|
|
1237
|
+
job_count, enabled_flags, verb = run._summarize_harness_configuration(
|
|
1238
|
+
jobs=1,
|
|
1239
|
+
update=True,
|
|
1240
|
+
coverage=False,
|
|
1241
|
+
debug=False,
|
|
1242
|
+
show_summary=False,
|
|
1243
|
+
runner_summary=False,
|
|
1244
|
+
fixture_summary=False,
|
|
1245
|
+
passthrough=False,
|
|
1246
|
+
)
|
|
1247
|
+
|
|
1248
|
+
assert job_count == 1
|
|
1249
|
+
assert "update" not in enabled_flags
|
|
1250
|
+
assert verb == "updating"
|
|
1251
|
+
|
|
1252
|
+
|
|
1253
|
+
def test_summarize_harness_configuration_sets_passthrough_verb() -> None:
|
|
1254
|
+
job_count, enabled_flags, verb = run._summarize_harness_configuration(
|
|
1255
|
+
jobs=2,
|
|
1256
|
+
update=False,
|
|
1257
|
+
coverage=False,
|
|
1258
|
+
debug=False,
|
|
1259
|
+
show_summary=False,
|
|
1260
|
+
runner_summary=False,
|
|
1261
|
+
fixture_summary=False,
|
|
1262
|
+
passthrough=True,
|
|
1263
|
+
)
|
|
1264
|
+
|
|
1265
|
+
assert job_count == 2
|
|
1266
|
+
assert "passthrough" not in enabled_flags
|
|
1267
|
+
assert verb == "showing"
|
|
1268
|
+
|
|
1269
|
+
|
|
1270
|
+
def test_print_project_start_uses_custom_verb(tmp_path, capsys):
|
|
1271
|
+
project_root = tmp_path / "example"
|
|
1272
|
+
project_root.mkdir()
|
|
1273
|
+
selection = run.ProjectSelection(
|
|
1274
|
+
root=project_root,
|
|
1275
|
+
selectors=[],
|
|
1276
|
+
run_all=True,
|
|
1277
|
+
kind="root",
|
|
1278
|
+
)
|
|
1279
|
+
|
|
1280
|
+
run._print_project_start(
|
|
1281
|
+
selection=selection,
|
|
1282
|
+
display_base=tmp_path,
|
|
1283
|
+
queue_size=3,
|
|
1284
|
+
job_count=0,
|
|
1285
|
+
enabled_flags="",
|
|
1286
|
+
verb="showing",
|
|
1287
|
+
)
|
|
1288
|
+
|
|
1289
|
+
output = capsys.readouterr().out
|
|
1290
|
+
assert (
|
|
1291
|
+
output
|
|
1292
|
+
== f"{run.INFO} {run.BOLD}example{run.RESET_COLOR}: showing 3 tests from root project at ./example\n"
|
|
1293
|
+
)
|
|
1294
|
+
|
|
1295
|
+
|
|
1155
1296
|
def test_execution_plan_single_project_summary(tmp_path, monkeypatch, capsys):
|
|
1156
1297
|
root = tmp_path
|
|
1157
1298
|
plan = run.ExecutionPlan(
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tenzir_test-0.9.3 → tenzir_test-0.9.4}/example-project/tests/context/03-context-inspect.tql
RENAMED
|
File without changes
|
{tenzir_test-0.9.3 → tenzir_test-0.9.4}/example-project/tests/context/03-context-inspect.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
/tenzir_test-0.9.3/src/tenzir_test/py.typed → /tenzir_test-0.9.4/example-project/tests/lazy.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tenzir_test-0.9.3 → tenzir_test-0.9.4}/example-project/tests/python/pure-python/flaky_coin.py
RENAMED
|
File without changes
|
{tenzir_test-0.9.3 → tenzir_test-0.9.4}/example-project/tests/python/pure-python/flaky_coin.txt
RENAMED
|
File without changes
|
{tenzir_test-0.9.3 → tenzir_test-0.9.4}/example-project/tests/python/pure-python/hello_world.py
RENAMED
|
File without changes
|
{tenzir_test-0.9.3 → tenzir_test-0.9.4}/example-project/tests/python/pure-python/hello_world.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tenzir_test-0.9.3 → tenzir_test-0.9.4}/src/tenzir_test/runners/custom_python_fixture_runner.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|