test: cover manifest validation errors
This commit is contained in:
@@ -1,10 +1,25 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from wf_contract_manifest import manifest_from_openrpc
|
||||
from typing import Any
|
||||
|
||||
import pytest
|
||||
|
||||
from wf_contract_manifest import ManifestError, manifest_from_openrpc
|
||||
|
||||
from .fixtures import synthetic_openrpc_document
|
||||
|
||||
|
||||
def assert_manifest_error(
|
||||
document: dict[str, Any], path: str, message: str
|
||||
) -> None:
|
||||
with pytest.raises(ManifestError) as error_info:
|
||||
manifest_from_openrpc(document)
|
||||
|
||||
assert error_info.value.path == path
|
||||
assert error_info.value.message == message
|
||||
assert str(error_info.value) == f"{path}: {message}"
|
||||
|
||||
|
||||
def test_normalizes_operations_and_components_deterministically() -> None:
|
||||
manifest = manifest_from_openrpc(synthetic_openrpc_document())
|
||||
|
||||
@@ -76,3 +91,134 @@ def test_preserves_conditional_schema_keywords() -> None:
|
||||
assert alpha["if"] == {"properties": {"mode": {"const": "alpha"}}}
|
||||
assert alpha["then"] == {"required": ["payload"]}
|
||||
assert alpha["not"] == {"required": ["forbidden"]}
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("field", "value", "missing", "path", "message"),
|
||||
[
|
||||
("openrpc", None, True, "$.openrpc", "expected a non-empty string"),
|
||||
("openrpc", 1.2, False, "$.openrpc", "expected a non-empty string"),
|
||||
("methods", None, True, "$.methods", "expected an array"),
|
||||
("methods", {}, False, "$.methods", "expected an array"),
|
||||
("components", None, True, "$.components", "expected an object"),
|
||||
("components", [], False, "$.components", "expected an object"),
|
||||
(
|
||||
"schemas",
|
||||
None,
|
||||
True,
|
||||
"$.components.schemas",
|
||||
"expected an object",
|
||||
),
|
||||
(
|
||||
"schemas",
|
||||
[],
|
||||
False,
|
||||
"$.components.schemas",
|
||||
"expected an object",
|
||||
),
|
||||
(
|
||||
"errors",
|
||||
None,
|
||||
True,
|
||||
"$.components.errors",
|
||||
"expected an object",
|
||||
),
|
||||
("errors", [], False, "$.components.errors", "expected an object"),
|
||||
],
|
||||
)
|
||||
def test_rejects_invalid_or_missing_top_level_envelope_values(
|
||||
field: str,
|
||||
value: object,
|
||||
missing: bool,
|
||||
path: str,
|
||||
message: str,
|
||||
) -> None:
|
||||
document = synthetic_openrpc_document()
|
||||
if field in {"schemas", "errors"}:
|
||||
components = document["components"]
|
||||
if missing:
|
||||
components.pop(field)
|
||||
else:
|
||||
components[field] = value
|
||||
elif missing:
|
||||
document.pop(field)
|
||||
else:
|
||||
document[field] = value
|
||||
|
||||
assert_manifest_error(document, path, message)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("name", "message"),
|
||||
[
|
||||
("", "expected a non-empty string"),
|
||||
("workflow", "expected a method name with non-empty dot-separated segments"),
|
||||
(
|
||||
"workflow..run",
|
||||
"expected a method name with non-empty dot-separated segments",
|
||||
),
|
||||
(
|
||||
".workflow.run",
|
||||
"expected a method name with non-empty dot-separated segments",
|
||||
),
|
||||
(
|
||||
"workflow.run.",
|
||||
"expected a method name with non-empty dot-separated segments",
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_rejects_empty_or_malformed_dotted_method_names(
|
||||
name: str, message: str
|
||||
) -> None:
|
||||
document = synthetic_openrpc_document()
|
||||
document["methods"][0]["name"] = name
|
||||
|
||||
assert_manifest_error(document, "$.methods[0].name", message)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("field", "value", "missing", "message"),
|
||||
[
|
||||
("required", "yes", False, "expected a boolean"),
|
||||
("required", None, True, "expected a boolean"),
|
||||
("schema", [], False, "expected a schema object"),
|
||||
("schema", None, True, "expected a schema object"),
|
||||
],
|
||||
)
|
||||
def test_rejects_invalid_or_missing_parameter_fields(
|
||||
field: str, value: object, missing: bool, message: str
|
||||
) -> None:
|
||||
document = synthetic_openrpc_document()
|
||||
parameter = document["methods"][1]["params"][0]
|
||||
if missing:
|
||||
parameter.pop(field)
|
||||
else:
|
||||
parameter[field] = value
|
||||
|
||||
assert_manifest_error(
|
||||
document,
|
||||
f"$.methods[1].params[0].{field}",
|
||||
message,
|
||||
)
|
||||
|
||||
|
||||
def test_rejects_invalid_result_schema_shape() -> None:
|
||||
document = synthetic_openrpc_document()
|
||||
document["methods"][1]["result"]["schema"] = []
|
||||
|
||||
assert_manifest_error(
|
||||
document,
|
||||
"$.methods[1].result.schema",
|
||||
"expected a schema object",
|
||||
)
|
||||
|
||||
|
||||
def test_rejects_invalid_method_error_schema_shape() -> None:
|
||||
document = synthetic_openrpc_document()
|
||||
document["methods"][1]["errors"][0] = []
|
||||
|
||||
assert_manifest_error(
|
||||
document,
|
||||
"$.methods[1].errors[0]",
|
||||
"expected a schema object",
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user