pl-e2e-test 0.1.0__tar.gz → 0.1.1__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.
- {pl_e2e_test-0.1.0/src/pl_e2e_test.egg-info → pl_e2e_test-0.1.1}/PKG-INFO +18 -5
- {pl_e2e_test-0.1.0 → pl_e2e_test-0.1.1}/README.md +17 -4
- {pl_e2e_test-0.1.0 → pl_e2e_test-0.1.1}/pyproject.toml +1 -1
- {pl_e2e_test-0.1.0 → pl_e2e_test-0.1.1/src/pl_e2e_test.egg-info}/PKG-INFO +18 -5
- {pl_e2e_test-0.1.0 → pl_e2e_test-0.1.1}/src/prairielearn_e2e/fuzz.py +35 -19
- {pl_e2e_test-0.1.0 → pl_e2e_test-0.1.1}/tests/test_fuzz.py +103 -7
- {pl_e2e_test-0.1.0 → pl_e2e_test-0.1.1}/LICENSE +0 -0
- {pl_e2e_test-0.1.0 → pl_e2e_test-0.1.1}/MANIFEST.in +0 -0
- {pl_e2e_test-0.1.0 → pl_e2e_test-0.1.1}/setup.cfg +0 -0
- {pl_e2e_test-0.1.0 → pl_e2e_test-0.1.1}/src/pl_e2e_test.egg-info/SOURCES.txt +0 -0
- {pl_e2e_test-0.1.0 → pl_e2e_test-0.1.1}/src/pl_e2e_test.egg-info/dependency_links.txt +0 -0
- {pl_e2e_test-0.1.0 → pl_e2e_test-0.1.1}/src/pl_e2e_test.egg-info/entry_points.txt +0 -0
- {pl_e2e_test-0.1.0 → pl_e2e_test-0.1.1}/src/pl_e2e_test.egg-info/requires.txt +0 -0
- {pl_e2e_test-0.1.0 → pl_e2e_test-0.1.1}/src/pl_e2e_test.egg-info/top_level.txt +0 -0
- {pl_e2e_test-0.1.0 → pl_e2e_test-0.1.1}/src/prairielearn_e2e/__init__.py +0 -0
- {pl_e2e_test-0.1.0 → pl_e2e_test-0.1.1}/src/prairielearn_e2e/__main__.py +0 -0
- {pl_e2e_test-0.1.0 → pl_e2e_test-0.1.1}/src/prairielearn_e2e/_git.py +0 -0
- {pl_e2e_test-0.1.0 → pl_e2e_test-0.1.1}/src/prairielearn_e2e/backend.py +0 -0
- {pl_e2e_test-0.1.0 → pl_e2e_test-0.1.1}/src/prairielearn_e2e/config.json +0 -0
- {pl_e2e_test-0.1.0 → pl_e2e_test-0.1.1}/src/prairielearn_e2e/config.py +0 -0
- {pl_e2e_test-0.1.0 → pl_e2e_test-0.1.1}/src/prairielearn_e2e/contract.py +0 -0
- {pl_e2e_test-0.1.0 → pl_e2e_test-0.1.1}/src/prairielearn_e2e/discovery.py +0 -0
- {pl_e2e_test-0.1.0 → pl_e2e_test-0.1.1}/src/prairielearn_e2e/errors.py +0 -0
- {pl_e2e_test-0.1.0 → pl_e2e_test-0.1.1}/src/prairielearn_e2e/harness.py +0 -0
- {pl_e2e_test-0.1.0 → pl_e2e_test-0.1.1}/src/prairielearn_e2e/html_checks.py +0 -0
- {pl_e2e_test-0.1.0 → pl_e2e_test-0.1.1}/src/prairielearn_e2e/metadata.py +0 -0
- {pl_e2e_test-0.1.0 → pl_e2e_test-0.1.1}/src/prairielearn_e2e/pytest_plugin.py +0 -0
- {pl_e2e_test-0.1.0 → pl_e2e_test-0.1.1}/src/prairielearn_e2e/question_tests.py +0 -0
- {pl_e2e_test-0.1.0 → pl_e2e_test-0.1.1}/src/prairielearn_e2e/regression.py +0 -0
- {pl_e2e_test-0.1.0 → pl_e2e_test-0.1.1}/src/prairielearn_e2e/reporting.py +0 -0
- {pl_e2e_test-0.1.0 → pl_e2e_test-0.1.1}/src/prairielearn_e2e/repository.py +0 -0
- {pl_e2e_test-0.1.0 → pl_e2e_test-0.1.1}/src/prairielearn_e2e/runner.py +0 -0
- {pl_e2e_test-0.1.0 → pl_e2e_test-0.1.1}/src/prairielearn_e2e/server.py +0 -0
- {pl_e2e_test-0.1.0 → pl_e2e_test-0.1.1}/src/prairielearn_e2e/sharding.py +0 -0
- {pl_e2e_test-0.1.0 → pl_e2e_test-0.1.1}/tests/__init__.py +0 -0
- {pl_e2e_test-0.1.0 → pl_e2e_test-0.1.1}/tests/conftest.py +0 -0
- {pl_e2e_test-0.1.0 → pl_e2e_test-0.1.1}/tests/stub_git.py +0 -0
- {pl_e2e_test-0.1.0 → pl_e2e_test-0.1.1}/tests/test_contract.py +0 -0
- {pl_e2e_test-0.1.0 → pl_e2e_test-0.1.1}/tests/test_discovery.py +0 -0
- {pl_e2e_test-0.1.0 → pl_e2e_test-0.1.1}/tests/test_git.py +0 -0
- {pl_e2e_test-0.1.0 → pl_e2e_test-0.1.1}/tests/test_harness.py +0 -0
- {pl_e2e_test-0.1.0 → pl_e2e_test-0.1.1}/tests/test_html_checks.py +0 -0
- {pl_e2e_test-0.1.0 → pl_e2e_test-0.1.1}/tests/test_metadata.py +0 -0
- {pl_e2e_test-0.1.0 → pl_e2e_test-0.1.1}/tests/test_publish_version.py +0 -0
- {pl_e2e_test-0.1.0 → pl_e2e_test-0.1.1}/tests/test_pytest_plugin.py +0 -0
- {pl_e2e_test-0.1.0 → pl_e2e_test-0.1.1}/tests/test_regression.py +0 -0
- {pl_e2e_test-0.1.0 → pl_e2e_test-0.1.1}/tests/test_reporting.py +0 -0
- {pl_e2e_test-0.1.0 → pl_e2e_test-0.1.1}/tests/test_repository.py +0 -0
- {pl_e2e_test-0.1.0 → pl_e2e_test-0.1.1}/tests/test_server.py +0 -0
- {pl_e2e_test-0.1.0 → pl_e2e_test-0.1.1}/tests/test_sharding.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pl-e2e-test
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.1
|
|
4
4
|
Summary: Fuzz PrairieLearn question lifecycles against the real Python element runtime
|
|
5
5
|
License-Expression: MIT
|
|
6
6
|
Project-URL: Homepage, https://github.com/PrairieLearn/pl-e2e-test
|
|
@@ -227,10 +227,23 @@ uv run pl-e2e-test-diff \
|
|
|
227
227
|
--seed-count 10
|
|
228
228
|
```
|
|
229
229
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
230
|
+
Configure optional repository-relative ignore rules in the course's `pyproject.toml`:
|
|
231
|
+
|
|
232
|
+
```toml
|
|
233
|
+
[tool.pl-e2e-test]
|
|
234
|
+
diffignore = [
|
|
235
|
+
".github",
|
|
236
|
+
"README.md",
|
|
237
|
+
"*lock.yaml",
|
|
238
|
+
]
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
Rules use Git's native ignore syntax and are evaluated in order, so later rules may
|
|
242
|
+
negate earlier ones with `!`. A missing `pyproject.toml`, tool table, or `diffignore`
|
|
243
|
+
entry means that no paths are ignored. Additional arguments are forwarded to pytest.
|
|
244
|
+
|
|
245
|
+
To migrate from `.question-e2e.diffignore`, copy its non-comment rules into the
|
|
246
|
+
`diffignore` array. The former file and `--e2ediffignore` option are no longer used.
|
|
234
247
|
|
|
235
248
|
In pull-request CI, fetch the base commit before running the command and pass the
|
|
236
249
|
appropriate base and head SHAs. Set `--fuzz-seed` to replay a reported run.
|
|
@@ -204,10 +204,23 @@ uv run pl-e2e-test-diff \
|
|
|
204
204
|
--seed-count 10
|
|
205
205
|
```
|
|
206
206
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
207
|
+
Configure optional repository-relative ignore rules in the course's `pyproject.toml`:
|
|
208
|
+
|
|
209
|
+
```toml
|
|
210
|
+
[tool.pl-e2e-test]
|
|
211
|
+
diffignore = [
|
|
212
|
+
".github",
|
|
213
|
+
"README.md",
|
|
214
|
+
"*lock.yaml",
|
|
215
|
+
]
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
Rules use Git's native ignore syntax and are evaluated in order, so later rules may
|
|
219
|
+
negate earlier ones with `!`. A missing `pyproject.toml`, tool table, or `diffignore`
|
|
220
|
+
entry means that no paths are ignored. Additional arguments are forwarded to pytest.
|
|
221
|
+
|
|
222
|
+
To migrate from `.question-e2e.diffignore`, copy its non-comment rules into the
|
|
223
|
+
`diffignore` array. The former file and `--e2ediffignore` option are no longer used.
|
|
211
224
|
|
|
212
225
|
In pull-request CI, fetch the base commit before running the command and pass the
|
|
213
226
|
appropriate base and head SHAs. Set `--fuzz-seed` to replay a reported run.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pl-e2e-test
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.1
|
|
4
4
|
Summary: Fuzz PrairieLearn question lifecycles against the real Python element runtime
|
|
5
5
|
License-Expression: MIT
|
|
6
6
|
Project-URL: Homepage, https://github.com/PrairieLearn/pl-e2e-test
|
|
@@ -227,10 +227,23 @@ uv run pl-e2e-test-diff \
|
|
|
227
227
|
--seed-count 10
|
|
228
228
|
```
|
|
229
229
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
230
|
+
Configure optional repository-relative ignore rules in the course's `pyproject.toml`:
|
|
231
|
+
|
|
232
|
+
```toml
|
|
233
|
+
[tool.pl-e2e-test]
|
|
234
|
+
diffignore = [
|
|
235
|
+
".github",
|
|
236
|
+
"README.md",
|
|
237
|
+
"*lock.yaml",
|
|
238
|
+
]
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
Rules use Git's native ignore syntax and are evaluated in order, so later rules may
|
|
242
|
+
negate earlier ones with `!`. A missing `pyproject.toml`, tool table, or `diffignore`
|
|
243
|
+
entry means that no paths are ignored. Additional arguments are forwarded to pytest.
|
|
244
|
+
|
|
245
|
+
To migrate from `.question-e2e.diffignore`, copy its non-comment rules into the
|
|
246
|
+
`diffignore` array. The former file and `--e2ediffignore` option are no longer used.
|
|
234
247
|
|
|
235
248
|
In pull-request CI, fetch the base commit before running the command and pass the
|
|
236
249
|
appropriate base and head SHAs. Set `--fuzz-seed` to replay a reported run.
|
|
@@ -7,6 +7,7 @@ import os
|
|
|
7
7
|
import secrets
|
|
8
8
|
import shlex
|
|
9
9
|
import subprocess
|
|
10
|
+
import tomllib
|
|
10
11
|
from collections.abc import Sequence
|
|
11
12
|
from pathlib import Path
|
|
12
13
|
from tempfile import TemporaryDirectory
|
|
@@ -17,7 +18,7 @@ from .runner import run_tests
|
|
|
17
18
|
from .sharding import Shard, parse_shard
|
|
18
19
|
|
|
19
20
|
QUESTIONS_ROOT = Path("questions")
|
|
20
|
-
|
|
21
|
+
PYPROJECT_CONFIG = Path("pyproject.toml")
|
|
21
22
|
|
|
22
23
|
|
|
23
24
|
def git_repository_root(start: Path) -> Path:
|
|
@@ -32,18 +33,37 @@ def git_repository_root(start: Path) -> Path:
|
|
|
32
33
|
return Path(result.stdout.strip()).resolve()
|
|
33
34
|
|
|
34
35
|
|
|
35
|
-
def load_e2e_diff_ignore(config_path: Path
|
|
36
|
-
"""Load Git-style ignore rules
|
|
36
|
+
def load_e2e_diff_ignore(config_path: Path) -> list[str]:
|
|
37
|
+
"""Load Git-style ignore rules from a course's pyproject.toml."""
|
|
37
38
|
|
|
38
39
|
try:
|
|
39
|
-
|
|
40
|
+
with config_path.open("rb") as config_file:
|
|
41
|
+
config = tomllib.load(config_file)
|
|
40
42
|
except FileNotFoundError:
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
raise ValueError(f"Unable to read {config_path}:
|
|
43
|
+
return []
|
|
44
|
+
except tomllib.TOMLDecodeError as exc:
|
|
45
|
+
raise ValueError(f"Unable to read {config_path}: invalid TOML: {exc}") from exc
|
|
44
46
|
except OSError as exc:
|
|
45
47
|
raise ValueError(f"Unable to read {config_path}: {exc}") from exc
|
|
46
48
|
|
|
49
|
+
tool_config = config.get("tool", {})
|
|
50
|
+
if not isinstance(tool_config, dict):
|
|
51
|
+
raise TypeError(f"Invalid configuration in {config_path}: tool must be a table")
|
|
52
|
+
e2e_config = tool_config.get("pl-e2e-test", {})
|
|
53
|
+
if not isinstance(e2e_config, dict):
|
|
54
|
+
raise TypeError(
|
|
55
|
+
f"Invalid configuration in {config_path}: tool.pl-e2e-test must be a table"
|
|
56
|
+
)
|
|
57
|
+
ignore_rules = e2e_config.get("diffignore", [])
|
|
58
|
+
if not isinstance(ignore_rules, list) or not all(
|
|
59
|
+
isinstance(rule, str) for rule in ignore_rules
|
|
60
|
+
):
|
|
61
|
+
raise TypeError(
|
|
62
|
+
f"Invalid configuration in {config_path}: "
|
|
63
|
+
"tool.pl-e2e-test.diffignore must be an array of strings"
|
|
64
|
+
)
|
|
65
|
+
return ignore_rules
|
|
66
|
+
|
|
47
67
|
|
|
48
68
|
def e2e_diff_ignored_files(
|
|
49
69
|
changed_files: Sequence[Path], ignore_rules: Sequence[str]
|
|
@@ -195,8 +215,7 @@ def main(argv: Sequence[str] | None = None) -> int:
|
|
|
195
215
|
)
|
|
196
216
|
parser.add_argument(
|
|
197
217
|
"--e2ediffignore",
|
|
198
|
-
|
|
199
|
-
help="E2E change-detection ignore file (default: COURSE_ROOT/.question-e2e.diffignore)",
|
|
218
|
+
help=argparse.SUPPRESS,
|
|
200
219
|
)
|
|
201
220
|
parser.add_argument(
|
|
202
221
|
"--shard",
|
|
@@ -211,6 +230,11 @@ def main(argv: Sequence[str] | None = None) -> int:
|
|
|
211
230
|
help="write a mergeable JSON result blob for this shard",
|
|
212
231
|
)
|
|
213
232
|
args, pytest_args = parser.parse_known_args(argv)
|
|
233
|
+
if args.e2ediffignore is not None:
|
|
234
|
+
parser.error(
|
|
235
|
+
"--e2ediffignore has been removed; configure "
|
|
236
|
+
"tool.pl-e2e-test.diffignore in COURSE_ROOT/pyproject.toml"
|
|
237
|
+
)
|
|
214
238
|
shard: Shard | None = args.shard
|
|
215
239
|
if args.shard_report is not None and shard is None:
|
|
216
240
|
parser.error("--shard-report requires --shard")
|
|
@@ -226,17 +250,9 @@ def main(argv: Sequence[str] | None = None) -> int:
|
|
|
226
250
|
except (OSError, subprocess.CalledProcessError) as exc:
|
|
227
251
|
parser.error(f"could not find the course Git repository: {exc}")
|
|
228
252
|
|
|
229
|
-
ignore_path = args.e2ediffignore
|
|
230
|
-
if ignore_path is None:
|
|
231
|
-
ignore_path = repository_root / DEFAULT_E2E_DIFF_IGNORE
|
|
232
|
-
missing_ok = True
|
|
233
|
-
else:
|
|
234
|
-
if not ignore_path.is_absolute():
|
|
235
|
-
ignore_path = repository_root / ignore_path
|
|
236
|
-
missing_ok = False
|
|
237
253
|
try:
|
|
238
|
-
ignored_patterns = load_e2e_diff_ignore(
|
|
239
|
-
except ValueError as exc:
|
|
254
|
+
ignored_patterns = load_e2e_diff_ignore(repository_root / PYPROJECT_CONFIG)
|
|
255
|
+
except (TypeError, ValueError) as exc:
|
|
240
256
|
parser.error(str(exc))
|
|
241
257
|
|
|
242
258
|
changed_files = changed_files_between(args.base, args.head, repository_root)
|
|
@@ -65,14 +65,83 @@ def test_root_anchored_gitignore_pattern() -> None:
|
|
|
65
65
|
) == {Path("README.md")}
|
|
66
66
|
|
|
67
67
|
|
|
68
|
-
def
|
|
69
|
-
assert (
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
68
|
+
def test_later_gitignore_pattern_can_negate_earlier_pattern() -> None:
|
|
69
|
+
assert fuzz.e2e_diff_ignored_files(
|
|
70
|
+
[Path("uv.lock"), Path("required.lock")], ["*.lock", "!required.lock"]
|
|
71
|
+
) == {Path("uv.lock")}
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def test_loads_diff_ignore_from_pyproject(tmp_path: Path) -> None:
|
|
75
|
+
config_path = tmp_path / "pyproject.toml"
|
|
76
|
+
config_path.write_text(
|
|
77
|
+
"""
|
|
78
|
+
[tool.pl-e2e-test]
|
|
79
|
+
diffignore = ["/README.md", "*.lock", "!required.lock"]
|
|
80
|
+
""",
|
|
81
|
+
encoding="utf-8",
|
|
74
82
|
)
|
|
75
83
|
|
|
84
|
+
assert fuzz.load_e2e_diff_ignore(config_path) == [
|
|
85
|
+
"/README.md",
|
|
86
|
+
"*.lock",
|
|
87
|
+
"!required.lock",
|
|
88
|
+
]
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
@pytest.mark.parametrize(
|
|
92
|
+
"contents",
|
|
93
|
+
[
|
|
94
|
+
"",
|
|
95
|
+
"[tool.pytest.ini_options]\n",
|
|
96
|
+
"[tool.pl-e2e-test]\n",
|
|
97
|
+
"[tool.pl-e2e-test]\ndiffignore = []\n",
|
|
98
|
+
],
|
|
99
|
+
)
|
|
100
|
+
def test_missing_or_empty_diff_ignore_configuration_is_empty(
|
|
101
|
+
tmp_path: Path, contents: str
|
|
102
|
+
) -> None:
|
|
103
|
+
config_path = tmp_path / "pyproject.toml"
|
|
104
|
+
config_path.write_text(contents, encoding="utf-8")
|
|
105
|
+
|
|
106
|
+
assert fuzz.load_e2e_diff_ignore(config_path) == []
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def test_missing_pyproject_is_empty(tmp_path: Path) -> None:
|
|
110
|
+
assert fuzz.load_e2e_diff_ignore(tmp_path / "pyproject.toml") == []
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def test_invalid_pyproject_is_rejected(tmp_path: Path) -> None:
|
|
114
|
+
config_path = tmp_path / "pyproject.toml"
|
|
115
|
+
config_path.write_text("[tool.pl-e2e-test\n", encoding="utf-8")
|
|
116
|
+
|
|
117
|
+
with pytest.raises(ValueError, match="invalid TOML"):
|
|
118
|
+
fuzz.load_e2e_diff_ignore(config_path)
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def test_unreadable_pyproject_is_rejected(tmp_path: Path) -> None:
|
|
122
|
+
config_path = tmp_path / "pyproject.toml"
|
|
123
|
+
config_path.mkdir()
|
|
124
|
+
|
|
125
|
+
with pytest.raises(ValueError, match="Unable to read"):
|
|
126
|
+
fuzz.load_e2e_diff_ignore(config_path)
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
@pytest.mark.parametrize(
|
|
130
|
+
"configured_value",
|
|
131
|
+
['"README.md"', '["README.md", 1]'],
|
|
132
|
+
)
|
|
133
|
+
def test_diff_ignore_must_be_an_array_of_strings(
|
|
134
|
+
tmp_path: Path, configured_value: str
|
|
135
|
+
) -> None:
|
|
136
|
+
config_path = tmp_path / "pyproject.toml"
|
|
137
|
+
config_path.write_text(
|
|
138
|
+
f"[tool.pl-e2e-test]\ndiffignore = {configured_value}\n",
|
|
139
|
+
encoding="utf-8",
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
with pytest.raises(TypeError, match="must be an array of strings"):
|
|
143
|
+
fuzz.load_e2e_diff_ignore(config_path)
|
|
144
|
+
|
|
76
145
|
|
|
77
146
|
def test_main_forwards_selected_questions_and_seed(
|
|
78
147
|
monkeypatch: pytest.MonkeyPatch,
|
|
@@ -82,11 +151,16 @@ def test_main_forwards_selected_questions_and_seed(
|
|
|
82
151
|
question = tmp_path / "questions" / "chapter" / "example"
|
|
83
152
|
question.mkdir(parents=True)
|
|
84
153
|
(question / "info.json").write_text("{}", encoding="utf-8")
|
|
154
|
+
(tmp_path / "pyproject.toml").write_text(
|
|
155
|
+
'[tool.pl-e2e-test]\ndiffignore = ["README.md"]\n',
|
|
156
|
+
encoding="utf-8",
|
|
157
|
+
)
|
|
85
158
|
monkeypatch.setattr(
|
|
86
159
|
fuzz,
|
|
87
160
|
"changed_files_between",
|
|
88
161
|
lambda base, head, repository_root: [
|
|
89
|
-
Path("
|
|
162
|
+
Path("README.md"),
|
|
163
|
+
Path("questions/chapter/example/server.py"),
|
|
90
164
|
],
|
|
91
165
|
)
|
|
92
166
|
calls: list[tuple[list[str], Path]] = []
|
|
@@ -131,6 +205,28 @@ def test_main_forwards_selected_questions_and_seed(
|
|
|
131
205
|
assert "E2E fuzz seed: 12345" in capsys.readouterr().out
|
|
132
206
|
|
|
133
207
|
|
|
208
|
+
def test_main_reports_invalid_pyproject(
|
|
209
|
+
tmp_path: Path, capsys: pytest.CaptureFixture[str]
|
|
210
|
+
) -> None:
|
|
211
|
+
(tmp_path / "pyproject.toml").write_text("[tool.pl-e2e-test\n", encoding="utf-8")
|
|
212
|
+
|
|
213
|
+
with pytest.raises(SystemExit, match="2"):
|
|
214
|
+
fuzz.main(["--course-root", str(tmp_path)])
|
|
215
|
+
|
|
216
|
+
assert "invalid TOML" in capsys.readouterr().err
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
def test_removed_diff_ignore_option_reports_migration(
|
|
220
|
+
capsys: pytest.CaptureFixture[str],
|
|
221
|
+
) -> None:
|
|
222
|
+
with pytest.raises(SystemExit, match="2"):
|
|
223
|
+
fuzz.main(["--e2ediffignore", ".question-e2e.diffignore"])
|
|
224
|
+
|
|
225
|
+
error = capsys.readouterr().err
|
|
226
|
+
assert "--e2ediffignore has been removed" in error
|
|
227
|
+
assert "tool.pl-e2e-test.diffignore" in error
|
|
228
|
+
|
|
229
|
+
|
|
134
230
|
def test_main_uses_managed_cache_when_prairielearn_path_is_omitted(
|
|
135
231
|
monkeypatch: pytest.MonkeyPatch,
|
|
136
232
|
tmp_path: Path,
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|