Skip to content

Commit 466e3f4

Browse files
committed
Fixed validation with additionalProperties
1 parent 39cf9bf commit 466e3f4

File tree

3 files changed

+43
-20
lines changed

3 files changed

+43
-20
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fixed validation failure with `additionalProperties`.

pulp-glue/pulp_glue/common/schema.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ def _validate_object(
212212
_("'{name}' does not allow additional properties.").format(name=name)
213213
)
214214
elif isinstance(additional_properties, dict):
215-
for value in extra_values.values():
215+
for pname, pvalue in extra_values.items():
216216
validate(additional_properties, f"{name}[{pname}]", pvalue, components)
217217
if (required := schema.get("required")) is not None:
218218
if missing_keys := set(required) - set(value.keys()):
@@ -242,7 +242,7 @@ def _validate_string(
242242
if (enum := schema.get("enum")) is not None:
243243
if value not in enum:
244244
raise ValidationError(
245-
_("'{name}' is expected to be on of [{enums}].").format(
245+
_("'{name}' is expected to be one of [{enums}].").format(
246246
name=name, enums=", ".join(enum)
247247
)
248248
)

pulp-glue/tests/test_schema.py

Lines changed: 40 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -160,137 +160,159 @@ def test_validates(schema: t.Any, value: t.Any) -> None:
160160

161161

162162
@pytest.mark.parametrize(
163-
"schema,value",
163+
"schema,value,match",
164164
[
165-
pytest.param({"type": "boolean"}, 1, id="boolean_fails_int"),
166-
pytest.param({"type": "string"}, None, id="string_fails_null"),
167-
pytest.param({"type": "string"}, 1, id="string_fails_int"),
168-
pytest.param({"type": "string"}, True, id="string_fails_bool"),
169-
pytest.param({"type": "string", "nullable": False}, None, id="not_nullable_fails_null"),
170-
pytest.param({"type": "string", "format": "byte"}, "1234", id="string_bytes_fails_string"),
165+
pytest.param({"type": "boolean"}, 1, None, id="boolean_fails_int"),
166+
pytest.param({"type": "string"}, None, None, id="string_fails_null"),
167+
pytest.param({"type": "string"}, 1, None, id="string_fails_int"),
168+
pytest.param({"type": "string"}, True, None, id="string_fails_bool"),
169+
pytest.param(
170+
{"type": "string", "nullable": False}, None, None, id="not_nullable_fails_null"
171+
),
172+
pytest.param(
173+
{"type": "string", "format": "byte"}, "1234", None, id="string_bytes_fails_string"
174+
),
171175
pytest.param(
172176
{"type": "string", "format": "date"},
173177
"aritrary string",
178+
None,
174179
id="string_date_fails_string",
175180
),
176181
pytest.param(
177182
{"type": "string", "enum": ["a", "b", "c"]},
178183
"d",
184+
None,
179185
id="string_enum",
180186
),
181187
pytest.param(
182-
{"type": "integer", "exclusiveMinimum": True, "minimum": 5}, 5, id="integer_exmin"
188+
{"type": "integer", "exclusiveMinimum": True, "minimum": 5}, 5, None, id="integer_exmin"
183189
),
184190
pytest.param(
185-
{"type": "integer", "exclusiveMaximum": True, "maximum": 5}, 5, id="integer_exmax"
191+
{"type": "integer", "exclusiveMaximum": True, "maximum": 5}, 5, None, id="integer_exmax"
186192
),
187-
pytest.param({"type": "integer", "minimum": 5}, 4, id="integer_min"),
188-
pytest.param({"type": "integer", "maximum": 5}, 6, id="integer_max"),
189-
pytest.param({"type": "integer", "multipleOf": 7}, 15, id="integer_multiple_of"),
193+
pytest.param({"type": "integer", "minimum": 5}, 4, None, id="integer_min"),
194+
pytest.param({"type": "integer", "maximum": 5}, 6, None, id="integer_max"),
195+
pytest.param({"type": "integer", "multipleOf": 7}, 15, None, id="integer_multiple_of"),
190196
pytest.param(
191-
{"$ref": "#/components/schemas/aString"}, 1, id="string_reference_fails_integer"
197+
{"$ref": "#/components/schemas/aString"}, 1, None, id="string_reference_fails_integer"
198+
),
199+
pytest.param(
200+
{"type": "number", "minimum": 6.5}, 6.0, None, id="fails_if_number_is_to_small"
192201
),
193-
pytest.param({"type": "number", "minimum": 6.5}, 6.0, id="fails_if_number_is_to_small"),
194202
pytest.param(
195203
{"$ref": "#/components/schemas/aReference"},
196204
1,
205+
None,
197206
id="double_string_reference_fails_integer",
198207
),
199208
pytest.param(
200209
{
201210
"$ref": "#/components/schemas/intArray",
202211
},
203212
True,
213+
None,
204214
id="array_fails_boolean",
205215
),
206216
pytest.param(
207217
{
208218
"$ref": "#/components/schemas/intArray",
209219
},
210220
["asdf"],
221+
None,
211222
id="integer_array_fails_string_array",
212223
),
213224
pytest.param(
214225
{
215226
"$ref": "#/components/schemas/strArray",
216227
},
217228
["asdf", False, "ghjk"],
229+
None,
218230
id="string_array_fails_boolean_in_array",
219231
),
220232
pytest.param(
221233
{
222234
"$ref": "#/components/schemas/minMaxArray",
223235
},
224236
[1, 2],
237+
None,
225238
id="min_max_array_fails_too_small",
226239
),
227240
pytest.param(
228241
{
229242
"$ref": "#/components/schemas/minMaxArray",
230243
},
231244
[1, 2, 3, 4, 5, 6],
245+
None,
232246
id="min_max_array_fails_too_large",
233247
),
234248
pytest.param(
235249
{
236250
"$ref": "#/components/schemas/uniqueArray",
237251
},
238252
[1, 2, 1, 6],
253+
None,
239254
id="unique_array_fails",
240255
),
241256
pytest.param(
242257
{
243258
"$ref": "#/components/schemas/emptyObject",
244259
},
245260
[],
261+
None,
246262
id="object_fails_list",
247263
),
248264
pytest.param(
249265
{
250266
"$ref": "#/components/schemas/emptyObject",
251267
},
252268
{"a": 1},
269+
None,
253270
id="object_fails_non_empty",
254271
),
255272
pytest.param(
256273
{
257274
"$ref": "#/components/schemas/objectAInt",
258275
},
259276
{"a": "test"},
277+
None,
260278
id="object_fails_a_is_wrong_type",
261279
),
262280
pytest.param(
263281
{
264282
"$ref": "#/components/schemas/objectRequiredA",
265283
},
266-
{"z": True},
284+
{"z": "string"},
285+
r"'testvar' is missing properties \(a\).",
267286
id="object_fails_required_property_missing",
268287
),
269288
pytest.param(
270289
{
271290
"$ref": "#/components/schemas/objectRequiredA",
272291
},
273-
{"a": 1, "z": 2.5},
292+
{"a": 1, "y": 2.5, "z": True},
293+
r"'testvar\[y\]' is expected to be a string.",
274294
id="object_fails_additional_property_not_valid",
275295
),
276296
pytest.param(
277297
{
278298
"$ref": "#/components/schemas/allOfEnum",
279299
},
280300
"a",
301+
r"'testvar' is expected to be one of \[b, d, f\].",
281302
id="fails_validate_only_first_all_of",
282303
),
283304
pytest.param(
284305
{
285306
"$ref": "#/components/schemas/anyOfEnum",
286307
},
287308
"z",
309+
None,
288310
id="fails_validate_none_matched",
289311
),
290312
],
291313
)
292-
def test_validation_failed(schema: t.Any, value: t.Any) -> None:
293-
with pytest.raises(ValidationError, match=r"'testvar.*'"):
314+
def test_validation_failed(schema: t.Any, value: t.Any, match: t.Optional[str]) -> None:
315+
with pytest.raises(ValidationError, match=match or r"'testvar.*'"):
294316
validate(schema, "testvar", value, COMPONENTS)
295317

296318

0 commit comments

Comments
 (0)