Skip to content

Commit 5bee535

Browse files
committed
Enforce shared assertions in e2e tests
1 parent 92bdc27 commit 5bee535

8 files changed

Lines changed: 186 additions & 0 deletions

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,7 @@ verbosity_assertions = 2
232232
markers = [
233233
"perf: marks tests as performance tests (excluded from CI benchmarks)",
234234
"benchmark: marks tests as benchmark tests",
235+
"allow_direct_assert: marks e2e tests where direct assert statements are intentionally allowed",
235236
]
236237

237238
[tool.coverage]

tests/main/jsonschema/test_main_jsonschema.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
FixtureRequest = pytest.FixtureRequest
5454

5555

56+
@pytest.mark.allow_direct_assert
5657
def assert_run_main_with_args_error(args: list[str], capsys: pytest.CaptureFixture[str], expected_error: str) -> None:
5758
"""Assert that running the CLI exits with code 2 and emits the expected error."""
5859
with pytest.raises(SystemExit) as exc_info:
@@ -212,6 +213,7 @@ def test_main_keep_model_order_field_references(output_file: Path) -> None:
212213
)
213214

214215

216+
@pytest.mark.allow_direct_assert
215217
@pytest.mark.parametrize(
216218
("target_python_version", "keep_model_order", "disable_future_imports"),
217219
[
@@ -452,6 +454,7 @@ def test_main_jsonschema_multiple_files(output_dir: Path) -> None:
452454
)
453455

454456

457+
@pytest.mark.allow_direct_assert
455458
@pytest.mark.benchmark
456459
def test_main_jsonschema_no_empty_collapsed_external_model(tmp_path: Path) -> None:
457460
"""Test no empty files with collapsed external models."""
@@ -771,6 +774,7 @@ def test_main_class_name_suffix_with_class_name(output_file: Path) -> None:
771774
)
772775

773776

777+
@pytest.mark.allow_direct_assert
774778
def test_main_class_name_prefix_invalid(output_file: Path) -> None:
775779
"""Test that invalid --class-name-prefix is rejected."""
776780
return_code: Exit = main([
@@ -784,6 +788,7 @@ def test_main_class_name_prefix_invalid(output_file: Path) -> None:
784788
assert return_code == Exit.ERROR
785789

786790

791+
@pytest.mark.allow_direct_assert
787792
def test_main_class_name_suffix_invalid(output_file: Path) -> None:
788793
"""Test that invalid --class-name-suffix is rejected."""
789794
return_code: Exit = main([
@@ -1002,6 +1007,7 @@ def test_main_root_id_jsonschema_with_absolute_local_file(output_file: Path) ->
10021007
)
10031008

10041009

1010+
@pytest.mark.allow_direct_assert
10051011
def test_main_url_with_relative_root_id_resolves_relative_refs(mocker: MockerFixture, tmp_path: Path) -> None:
10061012
"""Test --url input keeps resolving relative refs remotely when root $id is path-only."""
10071013
main_response = mocker.Mock()
@@ -1909,6 +1915,7 @@ def test_main_generate_relative_input_path(output_file: Path) -> None:
19091915
)
19101916

19111917

1918+
@pytest.mark.allow_direct_assert
19121919
def test_main_generate_external_absolute_input_path(tmp_path: Path) -> None:
19131920
"""Test helper keeps absolute input paths that are outside the repository root."""
19141921
with tempfile.TemporaryDirectory() as temp_dir:
@@ -2149,6 +2156,7 @@ def test_main_generate_pydantic_v2_dataclass_enum(output_file: Path) -> None:
21492156
)
21502157

21512158

2159+
@pytest.mark.allow_direct_assert
21522160
@pytest.mark.parametrize(
21532161
("input_file", "expected_file"),
21542162
[
@@ -2174,6 +2182,7 @@ def test_main_generate_pydantic_v2_model_default_dict(input_file: str, expected_
21742182
assert_file_content(output_file, expected_file)
21752183

21762184

2185+
@pytest.mark.allow_direct_assert
21772186
def test_main_generate_from_directory(tmp_path: Path) -> None:
21782187
"""Test generation from directory input."""
21792188
input_ = (JSON_SCHEMA_DATA_PATH / "external_files_in_directory").relative_to(Path.cwd())
@@ -2240,6 +2249,7 @@ def keep_underscores(name: str) -> str:
22402249
)
22412250

22422251

2252+
@pytest.mark.allow_direct_assert
22432253
def test_main_http_jsonschema(mocker: MockerFixture, output_file: Path) -> None:
22442254
"""Test HTTP JSON Schema fetching."""
22452255
external_directory = JSON_SCHEMA_DATA_PATH / "external_files_in_directory"
@@ -2351,6 +2361,7 @@ def get_mock_response(url: str, **_: object) -> mocker.Mock:
23512361
assert httpx_get_mock.call_count == 8
23522362

23532363

2364+
@pytest.mark.allow_direct_assert
23542365
@pytest.mark.parametrize(
23552366
(
23562367
"headers_arguments",
@@ -3304,6 +3315,7 @@ def test_long_description_wrap_string_literal(output_file: Path) -> None:
33043315
)
33053316

33063317

3318+
@pytest.mark.allow_direct_assert
33073319
def test_version(capsys: pytest.CaptureFixture) -> None:
33083320
"""Test version output."""
33093321
with pytest.raises(SystemExit) as e:
@@ -9006,6 +9018,7 @@ def test_field_validators_wrap_mode(output_file: Path, tmp_path: Path) -> None:
90069018
)
90079019

90089020

9021+
@pytest.mark.allow_direct_assert
90099022
def test_field_validators_with_no_field_skipped(output_file: Path, tmp_path: Path) -> None:
90109023
"""Test that validators without fields are skipped gracefully."""
90119024
config_file = tmp_path / "no_field_validators_config.json"
@@ -9070,6 +9083,7 @@ def test_field_validators_plain_mode(output_file: Path, tmp_path: Path) -> None:
90709083
)
90719084

90729085

9086+
@pytest.mark.allow_direct_assert
90739087
def test_field_validators_all_skipped(output_file: Path, tmp_path: Path) -> None:
90749088
"""Test that when all validators have no fields, output has no validators."""
90759089
config_file = tmp_path / "all_skipped_config.json"
@@ -9267,6 +9281,7 @@ def test_main_circular_ref_external_relative_keywords(output_file: Path) -> None
92679281
)
92689282

92699283

9284+
@pytest.mark.allow_direct_assert
92709285
@pytest.mark.benchmark
92719286
def test_main_circular_ref_external_url_keywords(mocker: MockerFixture, output_file: Path) -> None:
92729287
"""Test circular external refs with relative paths and schema keywords via URL input."""

tests/main/openapi/test_main_openapi.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1727,6 +1727,7 @@ def test_main_openapi_pattern_with_lookaround_pydantic_v2(
17271727
)
17281728

17291729

1730+
@pytest.mark.allow_direct_assert
17301731
def test_main_generate_custom_class_name_generator_modular(
17311732
tmp_path: Path,
17321733
) -> None:
@@ -1795,6 +1796,7 @@ def get_mock_response(path: str) -> Mock:
17951796
])
17961797

17971798

1799+
@pytest.mark.allow_direct_assert
17981800
def test_main_http_openapi_with_custom_port(mocker: MockerFixture, output_file: Path) -> None:
17991801
"""Test OpenAPI code generation from HTTP URL with custom port preserves port in refs."""
18001802
schema_content = """\
@@ -2534,6 +2536,7 @@ def test_main_openapi_allof_with_required_inherited_edge_cases(output_file: Path
25342536
)
25352537

25362538

2539+
@pytest.mark.allow_direct_assert
25372540
@LEGACY_BLACK_SKIP
25382541
def test_main_openapi_allof_with_required_inherited_coverage(output_file: Path) -> None:
25392542
"""Test OpenAPI generation with allOf coverage for edge case branches."""
@@ -3977,6 +3980,7 @@ def test_main_openapi_external_ref_with_transitive_local_ref(output_file: Path)
39773980
)
39783981

39793982

3983+
@pytest.mark.allow_direct_assert
39803984
def _assert_external_ref_mapping_cli_parse_error(
39813985
capsys: pytest.CaptureFixture[str],
39823986
mapping: str,
@@ -4064,6 +4068,7 @@ def test_main_openapi_external_ref_mapping_nested_relative_ref(output_file: Path
40644068
)
40654069

40664070

4071+
@pytest.mark.allow_direct_assert
40674072
def test_main_openapi_external_ref_mapping_normalizes_imported_class_name(tmp_path: Path) -> None:
40684073
"""Mapped refs normalize schema keys to generated Python class names."""
40694074
output_file = tmp_path / "output.py"
@@ -4078,6 +4083,7 @@ def test_main_openapi_external_ref_mapping_normalizes_imported_class_name(tmp_pa
40784083
assert "class UserName(" not in content
40794084

40804085

4086+
@pytest.mark.allow_direct_assert
40814087
def test_main_openapi_external_ref_mapping_file_uri(tmp_path: Path) -> None:
40824088
"""Mappings accept file URI keys and refs."""
40834089
common_uri = (EXTERNAL_REF_MAPPING_DATA_PATH / "common.yaml").resolve().as_uri()
@@ -4099,6 +4105,7 @@ def test_main_openapi_external_ref_mapping_file_uri(tmp_path: Path) -> None:
40994105
assert "class User(" not in content
41004106

41014107

4108+
@pytest.mark.allow_direct_assert
41024109
def test_main_openapi_external_ref_mapping_absolute_path_ref(tmp_path: Path) -> None:
41034110
"""Mappings match absolute-path refs to external schemas."""
41044111
common_path = str((EXTERNAL_REF_MAPPING_DATA_PATH / "common.yaml").resolve())
@@ -4120,6 +4127,7 @@ def test_main_openapi_external_ref_mapping_absolute_path_ref(tmp_path: Path) ->
41204127
assert "class User(" not in content
41214128

41224129

4130+
@pytest.mark.allow_direct_assert
41234131
def test_main_openapi_external_ref_mapping_local_ref_unchanged(tmp_path: Path) -> None:
41244132
"""Local refs remain unchanged when external mapping is configured."""
41254133
output_file = tmp_path / "output.py"
@@ -4147,6 +4155,7 @@ def test_main_openapi_external_ref_mapping_ref_without_fragment_errors(tmp_path:
41474155
)
41484156

41494157

4158+
@pytest.mark.allow_direct_assert
41504159
def test_main_openapi_external_ref_mapping_no_duplicate_classes(tmp_path: Path) -> None:
41514160
"""When mapping is active, the external file's classes should not be generated."""
41524161
output_file = tmp_path / "output.py"
@@ -4162,6 +4171,7 @@ def test_main_openapi_external_ref_mapping_no_duplicate_classes(tmp_path: Path)
41624171
assert "from mypackage.shared.models import" in content
41634172

41644173

4174+
@pytest.mark.allow_direct_assert
41654175
def test_main_openapi_external_ref_mapping_without_flag_generates_classes(tmp_path: Path) -> None:
41664176
"""Without the flag, external refs generate classes (regression check)."""
41674177
output_file = tmp_path / "output.py"
@@ -4225,6 +4235,7 @@ def test_main_openapi_external_ref_mapping_invalid_empty_part_in_pyproject(
42254235
)
42264236

42274237

4238+
@pytest.mark.allow_direct_assert
42284239
def test_main_openapi_external_ref_mapping_programmatic_api(tmp_path: Path) -> None:
42294240
"""Test using GenerateConfig with external_ref_mapping."""
42304241
output_file = tmp_path / "output.py"
@@ -5194,6 +5205,7 @@ def test_main_openapi_include_paths_without_leading_slash(output_file: Path) ->
51945205
)
51955206

51965207

5208+
@pytest.mark.allow_direct_assert
51975209
def test_main_openapi_include_paths_warning_without_paths_scope() -> None:
51985210
"""Warn when --openapi-include-paths used without paths scope."""
51995211
import warnings

tests/main/test_exec_validation.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,12 +129,14 @@ def test_force_exec_with_different_target_version(output_file: Path) -> None:
129129
)
130130

131131

132+
@pytest.mark.allow_direct_assert
132133
def test_get_current_version_args_basic() -> None:
133134
"""Test that get_current_version_args returns correct args."""
134135
args = get_current_version_args()
135136
assert args == ["--target-python-version", CURRENT_PYTHON_VERSION]
136137

137138

139+
@pytest.mark.allow_direct_assert
138140
def test_get_current_version_args_with_extra() -> None:
139141
"""Test that get_current_version_args includes extra args."""
140142
args = get_current_version_args("--use-field-description", "--strict")
@@ -146,6 +148,7 @@ def test_get_current_version_args_with_extra() -> None:
146148
]
147149

148150

151+
@pytest.mark.allow_direct_assert
149152
def test_current_python_version_format() -> None:
150153
"""Test that CURRENT_PYTHON_VERSION matches expected format."""
151154
expected = f"{sys.version_info[0]}.{sys.version_info[1]}"

0 commit comments

Comments
 (0)