Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,11 @@ def _validate_field(name: str, raw: object, required: bool) -> ConfigurationFiel
def _required_names(raw: object, properties: Mapping[object, object]) -> set[str]:
if not isinstance(raw, list) or not all(isinstance(item, str) for item in raw):
raise ConfigurationSchemaError("Configuration schema required must be a string list.")
if len(raw) > _MAX_FIELDS:
raise ConfigurationSchemaError("Configuration schema exceeds the required field limit.")
required = set(raw)
if len(required) != len(raw):
raise ConfigurationSchemaError("Configuration schema has duplicate required fields.")
if not required.issubset(properties):
raise ConfigurationSchemaError("Configuration schema requires an unknown field.")
return required
Expand All @@ -207,9 +211,13 @@ def _choices(raw: object, value_type: str, name: str) -> tuple[ConfigurationValu
return ()
if not isinstance(raw, list) or not raw or len(raw) > 100:
raise ConfigurationSchemaError(f"Configuration field {name} has invalid choices.")
choices: list[ConfigurationValue] = []
for value in raw:
_validate_typed_value(value, value_type, name)
return tuple(raw)
if value in choices:
raise ConfigurationSchemaError(f"Configuration field {name} has duplicate choices.")
choices.append(value)
return tuple(choices)


def _suggestions(
Expand Down
41 changes: 41 additions & 0 deletions tests/unit/test_configuration_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,47 @@ def test_configuration_schema_rejects_more_than_fifty_controls() -> None:
validate_configuration_schema(schema)


def test_configuration_schema_rejects_duplicate_required_names() -> None:
schema = {
"type": "object",
"properties": {"language": {"type": "string"}},
"required": ["language", "language"],
"additionalProperties": False,
}

with pytest.raises(ConfigurationSchemaError, match="duplicate required fields"):
validate_configuration_schema(schema)


def test_configuration_schema_rejects_more_than_fifty_required_names() -> None:
properties = {f"field_{index}": {"type": "string"} for index in range(50)}
schema = {
"type": "object",
"properties": properties,
"required": [*properties, "field_0"],
"additionalProperties": False,
}

with pytest.raises(ConfigurationSchemaError, match="required field limit"):
validate_configuration_schema(schema)


def test_configuration_schema_rejects_duplicate_choices() -> None:
schema = {
"type": "object",
"properties": {
"language": {
"type": "string",
"enum": ["en", "en"],
}
},
"additionalProperties": False,
}

with pytest.raises(ConfigurationSchemaError, match="duplicate choices"):
validate_configuration_schema(schema)


@pytest.mark.parametrize(
"field",
[
Expand Down
Loading