From d6136a32fcbabc64b4dd9ab1af2f2c89b8da87a4 Mon Sep 17 00:00:00 2001 From: p1c2u Date: Fri, 3 Feb 2023 08:03:59 +0000 Subject: [PATCH] unmarshallers integration tests --- .../unmarshalling/test_unmarshallers.py | 2056 +++++++++++++++++ .../integration/validation/test_validators.py | 166 +- tests/unit/unmarshalling/test_unmarshal.py | 904 -------- tests/unit/unmarshalling/test_validate.py | 971 -------- 4 files changed, 2133 insertions(+), 1964 deletions(-) create mode 100644 tests/integration/unmarshalling/test_unmarshallers.py diff --git a/tests/integration/unmarshalling/test_unmarshallers.py b/tests/integration/unmarshalling/test_unmarshallers.py new file mode 100644 index 00000000..2c3b6b65 --- /dev/null +++ b/tests/integration/unmarshalling/test_unmarshallers.py @@ -0,0 +1,2056 @@ +from datetime import date +from datetime import datetime +from uuid import UUID +from uuid import uuid4 + +import pytest +from isodate.tzinfo import UTC +from isodate.tzinfo import FixedOffset +from jsonschema.exceptions import SchemaError +from jsonschema.exceptions import UnknownType +from jsonschema.exceptions import ValidationError + +from openapi_core import Spec +from openapi_core.unmarshalling.schemas import ( + oas30_request_schema_unmarshallers_factory, +) +from openapi_core.unmarshalling.schemas import ( + oas30_response_schema_unmarshallers_factory, +) +from openapi_core.unmarshalling.schemas import ( + oas31_schema_unmarshallers_factory, +) +from openapi_core.unmarshalling.schemas.exceptions import ( + FormatterNotFoundError, +) +from openapi_core.unmarshalling.schemas.exceptions import ( + InvalidSchemaFormatValue, +) +from openapi_core.unmarshalling.schemas.exceptions import InvalidSchemaValue +from openapi_core.unmarshalling.schemas.exceptions import UnmarshalError + + +class BaseTestOASSchemaUnmarshallersFactoryCall: + def test_create_no_schema(self, unmarshallers_factory): + with pytest.raises(TypeError): + unmarshallers_factory.create(None) + + def test_create_schema_deprecated(self, unmarshallers_factory): + schema = { + "deprecated": True, + } + spec = Spec.from_dict(schema, validator=None) + with pytest.warns(DeprecationWarning): + unmarshallers_factory.create(spec) + + def test_create_formatter_not_found(self, unmarshallers_factory): + custom_format = "custom" + schema = { + "type": "string", + "format": custom_format, + } + spec = Spec.from_dict(schema, validator=None) + + with pytest.raises( + FormatterNotFoundError, + match="Formatter not found for custom format", + ): + unmarshallers_factory.create(spec) + + @pytest.mark.parametrize( + "value", + [ + "test", + 10, + 10, + 3.12, + ["one", "two"], + True, + False, + ], + ) + def test_no_type(self, unmarshallers_factory, value): + schema = {} + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + + result = unmarshaller(value) + + assert result == value + + @pytest.mark.parametrize( + "type,value", + [ + ("string", "test"), + ("integer", 10), + ("number", 10), + ("number", 3.12), + ("array", ["one", "two"]), + ("boolean", True), + ("boolean", False), + ], + ) + def test_basic_types(self, unmarshallers_factory, type, value): + schema = { + "type": type, + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + + result = unmarshaller(value) + + assert result == value + + @pytest.mark.parametrize( + "type,value", + [ + ("string", 10), + ("string", 3.14), + ("string", True), + ("string", ["one", "two"]), + ("string", {"one": "two"}), + ("integer", 3.14), + ("integer", True), + ("integer", ""), + ("integer", "test"), + ("integer", b"test"), + ("integer", ["one", "two"]), + ("integer", {"one": "two"}), + ("number", True), + ("number", ""), + ("number", "test"), + ("number", b"test"), + ("number", ["one", "two"]), + ("number", {"one": "two"}), + ("array", 10), + ("array", 3.14), + ("array", True), + ("array", ""), + ("array", "test"), + ("array", b"test"), + ("array", {"one": "two"}), + ("boolean", 10), + ("boolean", 3.14), + ("boolean", ""), + ("boolean", "test"), + ("boolean", b"test"), + ("boolean", ["one", "two"]), + ("boolean", {"one": "two"}), + ("object", 10), + ("object", 3.14), + ("object", True), + ("object", ""), + ("object", "test"), + ("object", b"test"), + ("object", ["one", "two"]), + ], + ) + def test_basic_types_invalid(self, unmarshallers_factory, type, value): + schema = { + "type": type, + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + + with pytest.raises( + InvalidSchemaValue, + match=f"not valid for schema of type {type}", + ) as exc_info: + unmarshaller(value) + assert len(exc_info.value.schema_errors) == 1 + assert ( + f"is not of type '{type}'" + in exc_info.value.schema_errors[0].message + ) + + @pytest.mark.xfail( + reason=( + "Format assigned to type bug. " + "See https://github.com/p1c2u/openapi-core/issues/483" + ) + ) + @pytest.mark.parametrize( + "format,value,unmarshalled", + [ + ("int32", 13, 13), + ("int64", 13, 13), + ("float", 3.14, 3.14), + ("double", 3.14, 3.14), + ("password", "passwd", "passwd"), + ("date", "2018-12-13", date(2018, 12, 13)), + ( + "date-time", + "2018-12-13T13:34:59Z", + datetime(2018, 12, 13, 13, 34, 59, tzinfo=UTC), + ), + ( + "date-time", + "2018-12-13T13:34:59+02:00", + datetime(2018, 12, 13, 13, 34, 59, tzinfo=FixedOffset(2)), + ), + ( + "uuid", + "20a53f2e-0049-463d-b2b4-3fbbbb4cd8a7", + UUID("20a53f2e-0049-463d-b2b4-3fbbbb4cd8a7"), + ), + ], + ) + def test_basic_formats( + self, unmarshallers_factory, format, value, unmarshalled + ): + schema = { + "format": format, + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + + result = unmarshaller(value) + + assert result == unmarshalled + + @pytest.mark.parametrize( + "type,format,value,unmarshalled", + [ + ("integer", "int32", 13, 13), + ("integer", "int64", 13, 13), + ("number", "float", 3.14, 3.14), + ("number", "double", 3.14, 3.14), + ("string", "password", "passwd", "passwd"), + ("string", "date", "2018-12-13", date(2018, 12, 13)), + ( + "string", + "date-time", + "2018-12-13T13:34:59Z", + datetime(2018, 12, 13, 13, 34, 59, tzinfo=UTC), + ), + ( + "string", + "date-time", + "2018-12-13T13:34:59+02:00", + datetime(2018, 12, 13, 13, 34, 59, tzinfo=FixedOffset(2)), + ), + ( + "string", + "uuid", + "20a53f2e-0049-463d-b2b4-3fbbbb4cd8a7", + UUID("20a53f2e-0049-463d-b2b4-3fbbbb4cd8a7"), + ), + ], + ) + def test_basic_type_formats( + self, unmarshallers_factory, type, format, value, unmarshalled + ): + schema = { + "type": type, + "format": format, + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + + result = unmarshaller(value) + + assert result == unmarshalled + + @pytest.mark.parametrize( + "type,format,value", + [ + ("number", "float", 3), + ("number", "double", 3), + ("string", "date", "test"), + ("string", "date-time", "test"), + ("string", "uuid", "test"), + ], + ) + def test_basic_type_formats_invalid( + self, unmarshallers_factory, type, format, value + ): + schema = { + "type": type, + "format": format, + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + + with pytest.raises(InvalidSchemaValue) as exc_info: + unmarshaller(value) + assert len(exc_info.value.schema_errors) == 1 + assert ( + f"is not a '{format}'" in exc_info.value.schema_errors[0].message + ) + + @pytest.mark.parametrize( + "value,expected", + [ + ("dGVzdA==", "test"), + ], + ) + def test_string_byte(self, unmarshallers_factory, value, expected): + schema = { + "type": "string", + "format": "byte", + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + + result = unmarshaller(value) + + assert result == expected + + def test_string_date(self, unmarshallers_factory): + schema = { + "type": "string", + "format": "date", + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + value = "2018-01-02" + + result = unmarshaller(value) + + assert result == date(2018, 1, 2) + + @pytest.mark.parametrize( + "value,expected", + [ + ("2018-01-02T00:00:00Z", datetime(2018, 1, 2, 0, 0, tzinfo=UTC)), + ( + "2020-04-01T12:00:00+02:00", + datetime(2020, 4, 1, 12, 0, 0, tzinfo=FixedOffset(2)), + ), + ], + ) + def test_string_datetime(self, unmarshallers_factory, value, expected): + schema = { + "type": "string", + "format": "date-time", + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + + result = unmarshaller(value) + + assert result == expected + + def test_string_datetime_invalid(self, unmarshallers_factory): + schema = { + "type": "string", + "format": "date-time", + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + value = "2018-01-02T00:00:00" + + with pytest.raises(InvalidSchemaValue) as exc_info: + unmarshaller(value) + assert len(exc_info.value.schema_errors) == 1 + assert ( + f"is not a 'date-time'" in exc_info.value.schema_errors[0].message + ) + + def test_string_password(self, unmarshallers_factory): + schema = { + "type": "string", + "format": "password", + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + value = "passwd" + + result = unmarshaller(value) + + assert result == value + + def test_string_uuid(self, unmarshallers_factory): + schema = { + "type": "string", + "format": "uuid", + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + value = str(uuid4()) + + result = unmarshaller(value) + + assert result == UUID(value) + + def test_string_uuid_invalid(self, unmarshallers_factory): + schema = { + "type": "string", + "format": "uuid", + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + value = "test" + + with pytest.raises(InvalidSchemaValue) as exc_info: + unmarshaller(value) + assert len(exc_info.value.schema_errors) == 1 + assert f"is not a 'uuid'" in exc_info.value.schema_errors[0].message + + @pytest.mark.xfail( + reason=( + "Format assigned to type bug. " + "See https://github.com/p1c2u/openapi-core/issues/483" + ) + ) + @pytest.mark.parametrize( + "type,format,value,expected", + [ + ("string", "float", "test", "test"), + ("string", "double", "test", "test"), + ("string", "byte", "test", "test"), + ("integer", "date", "10", 10), + ("integer", "date-time", "10", 10), + ("string", "int32", "test", "test"), + ("string", "int64", "test", "test"), + ("integer", "password", "10", 10), + ], + ) + def test_formats_ignored( + self, unmarshallers_factory, type, format, value, expected + ): + schema = { + "type": type, + "format": format, + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + + result = unmarshaller(value) + + assert result == expected + + @pytest.mark.parametrize("value", ["bar", "foobar"]) + def test_string_pattern(self, unmarshallers_factory, value): + schema = { + "type": "string", + "pattern": "bar", + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + + result = unmarshaller(value) + + assert result == value + + @pytest.mark.parametrize( + "value,pattern", + [ + ("foo", "baz"), + ("bar", "baz"), + ], + ) + def test_string_pattern_invalid( + self, unmarshallers_factory, value, pattern + ): + schema = { + "type": "string", + "pattern": pattern, + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + + with pytest.raises(InvalidSchemaValue) as exc_info: + unmarshaller(value) + assert len(exc_info.value.schema_errors) == 1 + assert ( + f"'{value}' does not match '{pattern}'" + in exc_info.value.schema_errors[0].message + ) + + @pytest.mark.parametrize("value", ["abc", "abcd"]) + def test_string_min_length(self, unmarshallers_factory, value): + schema = { + "type": "string", + "minLength": 3, + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + + result = unmarshaller(value) + + assert result == value + + @pytest.mark.parametrize("value", ["", "a", "ab"]) + def test_string_min_length_invalid(self, unmarshallers_factory, value): + schema = { + "type": "string", + "minLength": 3, + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + + with pytest.raises(InvalidSchemaValue) as exc_info: + unmarshaller(value) + assert len(exc_info.value.schema_errors) == 1 + assert ( + f"'{value}' is too short" + in exc_info.value.schema_errors[0].message + ) + + @pytest.mark.parametrize("value", ["", "a"]) + def test_string_max_length(self, unmarshallers_factory, value): + schema = { + "type": "string", + "maxLength": 1, + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + + result = unmarshaller(value) + + assert result == value + + @pytest.mark.parametrize("value", ["ab", "abc"]) + def test_string_max_length_invalid(self, unmarshallers_factory, value): + schema = { + "type": "string", + "maxLength": 1, + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + + with pytest.raises(InvalidSchemaValue) as exc_info: + unmarshaller(value) + assert len(exc_info.value.schema_errors) == 1 + assert ( + f"'{value}' is too long" in exc_info.value.schema_errors[0].message + ) + + @pytest.mark.parametrize( + "value", + [ + "", + ], + ) + def test_string_max_length_invalid_schema( + self, unmarshallers_factory, value + ): + schema = { + "type": "string", + "maxLength": -1, + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + + with pytest.raises(InvalidSchemaValue): + unmarshaller(value) + + def test_integer_enum(self, unmarshallers_factory): + schema = { + "type": "integer", + "enum": [1, 2, 3], + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + value = 2 + + result = unmarshaller(value) + + assert result == int(value) + + def test_integer_enum_invalid(self, unmarshallers_factory): + enum = [1, 2, 3] + schema = { + "type": "integer", + "enum": enum, + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + value = 12 + + with pytest.raises(InvalidSchemaValue) as exc_info: + unmarshaller(value) + assert len(exc_info.value.schema_errors) == 1 + assert ( + f"{value} is not one of {enum}" + in exc_info.value.schema_errors[0].message + ) + + @pytest.mark.parametrize( + "type,value", + [ + ("string", "test"), + ("integer", 10), + ("number", 10), + ("number", 3.12), + ("array", ["one", "two"]), + ("boolean", True), + ("boolean", False), + ], + ) + def test_array(self, unmarshallers_factory, type, value): + schema = { + "type": "array", + "items": { + "type": type, + }, + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + value_list = [value] * 3 + + result = unmarshaller(value_list) + + assert result == value_list + + @pytest.mark.parametrize( + "type,value", + [ + ("integer", True), + ("integer", "123"), + ("string", 123), + ("string", True), + ("boolean", 123), + ("boolean", "123"), + ], + ) + def test_array_invalid(self, unmarshallers_factory, type, value): + schema = { + "type": "array", + "items": { + "type": type, + }, + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + + with pytest.raises(InvalidSchemaValue) as exc_info: + unmarshaller([value]) + assert len(exc_info.value.schema_errors) == 1 + assert ( + f"is not of type '{type}'" + in exc_info.value.schema_errors[0].message + ) + + @pytest.mark.parametrize("value", [[], [1], [1, 2]]) + def test_array_min_items_invalid(self, unmarshallers_factory, value): + schema = { + "type": "array", + "items": { + "type": "number", + }, + "minItems": 3, + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + + with pytest.raises(InvalidSchemaValue) as exc_info: + unmarshaller(value) + assert len(exc_info.value.schema_errors) == 1 + assert ( + f"{value} is too short" in exc_info.value.schema_errors[0].message + ) + + @pytest.mark.parametrize("value", [[], [1], [1, 2]]) + def test_array_min_items(self, unmarshallers_factory, value): + schema = { + "type": "array", + "items": { + "type": "number", + }, + "minItems": 0, + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + + result = unmarshaller(value) + + assert result == value + + @pytest.mark.parametrize( + "value", + [ + [], + ], + ) + def test_array_max_items_invalid_schema( + self, unmarshallers_factory, value + ): + schema = { + "type": "array", + "items": { + "type": "number", + }, + "maxItems": -1, + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + + with pytest.raises(InvalidSchemaValue): + unmarshaller(value) + + @pytest.mark.parametrize("value", [[1, 2], [2, 3, 4]]) + def test_array_max_items_invalid(self, unmarshallers_factory, value): + schema = { + "type": "array", + "items": { + "type": "number", + }, + "maxItems": 1, + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + + with pytest.raises(InvalidSchemaValue) as exc_info: + unmarshaller(value) + assert len(exc_info.value.schema_errors) == 1 + assert ( + f"{value} is too long" in exc_info.value.schema_errors[0].message + ) + + @pytest.mark.parametrize("value", [[1, 2, 1], [2, 2]]) + def test_array_unique_items_invalid(self, unmarshallers_factory, value): + schema = { + "type": "array", + "items": { + "type": "number", + }, + "uniqueItems": True, + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + + with pytest.raises(InvalidSchemaValue) as exc_info: + unmarshaller(value) + assert len(exc_info.value.schema_errors) == 1 + assert ( + f"{value} has non-unique elements" + in exc_info.value.schema_errors[0].message + ) + + def test_object_any_of(self, unmarshallers_factory): + schema = { + "type": "object", + "anyOf": [ + { + "type": "object", + "required": ["someint"], + "properties": {"someint": {"type": "integer"}}, + }, + { + "type": "object", + "required": ["somestr"], + "properties": {"somestr": {"type": "string"}}, + }, + ], + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + value = {"someint": 1} + + result = unmarshaller(value) + + assert result == value + + def test_object_any_of_invalid(self, unmarshallers_factory): + schema = { + "type": "object", + "anyOf": [ + { + "type": "object", + "required": ["someint"], + "properties": {"someint": {"type": "integer"}}, + }, + { + "type": "object", + "required": ["somestr"], + "properties": {"somestr": {"type": "string"}}, + }, + ], + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + + with pytest.raises(UnmarshalError): + unmarshaller({"someint": "1"}) + + def test_object_one_of_default(self, unmarshallers_factory): + schema = { + "type": "object", + "oneOf": [ + { + "type": "object", + "properties": { + "somestr": { + "type": "string", + "default": "defaultstring", + }, + }, + }, + { + "type": "object", + "required": ["otherstr"], + "properties": { + "otherstr": { + "type": "string", + }, + }, + }, + ], + "properties": { + "someint": { + "type": "integer", + }, + }, + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + + assert unmarshaller({"someint": 1}) == { + "someint": 1, + "somestr": "defaultstring", + } + + def test_object_any_of_default(self, unmarshallers_factory): + schema = { + "type": "object", + "anyOf": [ + { + "type": "object", + "properties": { + "someint": { + "type": "integer", + }, + }, + }, + { + "type": "object", + "properties": { + "somestr": { + "type": "string", + "default": "defaultstring", + }, + }, + }, + ], + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + + assert unmarshaller({"someint": "1"}) == { + "someint": "1", + "somestr": "defaultstring", + } + + def test_object_all_of_default(self, unmarshallers_factory): + schema = { + "type": "object", + "allOf": [ + { + "type": "object", + "properties": { + "somestr": { + "type": "string", + "default": "defaultstring", + }, + }, + }, + { + "type": "object", + "properties": { + "someint": { + "type": "integer", + "default": 1, + }, + }, + }, + ], + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + + assert unmarshaller({}) == { + "someint": 1, + "somestr": "defaultstring", + } + + @pytest.mark.parametrize( + "value", + [ + { + "someint": 123, + }, + { + "somestr": "content", + }, + { + "somestr": "content", + "someint": 123, + }, + ], + ) + def test_object_with_properties(self, unmarshallers_factory, value): + schema = { + "type": "object", + "properties": { + "somestr": { + "type": "string", + }, + "someint": { + "type": "integer", + }, + }, + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + + result = unmarshaller(value) + + assert result == value + + @pytest.mark.parametrize( + "value", + [ + { + "somestr": {}, + "someint": 123, + }, + { + "somestr": ["content1", "content2"], + "someint": 123, + }, + { + "somestr": 123, + "someint": 123, + }, + { + "somestr": "content", + "someint": 123, + "not_in_scheme_prop": 123, + }, + ], + ) + def test_object_with_properties_invalid( + self, unmarshallers_factory, value + ): + schema = { + "type": "object", + "properties": { + "somestr": { + "type": "string", + }, + "someint": { + "type": "integer", + }, + }, + "additionalProperties": False, + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + + with pytest.raises(InvalidSchemaValue): + unmarshaller(value) + + @pytest.mark.parametrize( + "value", + [ + {}, + ], + ) + def test_object_default_property(self, unmarshallers_factory, value): + schema = { + "type": "object", + "properties": { + "prop": { + "type": "string", + "default": "value1", + } + }, + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + + result = unmarshaller(value) + + assert result == {"prop": "value1"} + + @pytest.mark.parametrize( + "value", + [ + {"additional": 1}, + ], + ) + def test_object_additional_properties_false( + self, unmarshallers_factory, value + ): + schema = { + "type": "object", + "additionalProperties": False, + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + + with pytest.raises(InvalidSchemaValue): + unmarshaller(value) + + @pytest.mark.parametrize( + "value", + [ + {"additional": 1}, + {"foo": "bar", "bar": "foo"}, + {"additional": {"bar": 1}}, + ], + ) + @pytest.mark.parametrize("additional_properties", [True, {}]) + def test_object_additional_properties_free_form_object( + self, value, additional_properties, unmarshallers_factory + ): + schema = { + "type": "object", + "additionalProperties": additional_properties, + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + + result = unmarshaller(value) + + assert result == value + + def test_object_additional_properties_list(self, unmarshallers_factory): + schema = {"type": "object"} + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + + result = unmarshaller({"user_ids": [1, 2, 3, 4]}) + + assert result == { + "user_ids": [1, 2, 3, 4], + } + + @pytest.mark.parametrize( + "value", + [ + {"additional": 1}, + ], + ) + def test_object_additional_properties(self, unmarshallers_factory, value): + schema = { + "type": "object", + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + + result = unmarshaller(value) + + assert result == value + + @pytest.mark.parametrize( + "value", + [ + {"additional": 1}, + ], + ) + def test_object_additional_properties_object( + self, unmarshallers_factory, value + ): + additional_properties = { + "type": "integer", + } + schema = { + "type": "object", + "additionalProperties": additional_properties, + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + + result = unmarshaller(value) + + assert result == value + + @pytest.mark.parametrize( + "value", + [ + {"a": 1}, + {"a": 1, "b": 2}, + {"a": 1, "b": 2, "c": 3}, + ], + ) + def test_object_min_properties(self, unmarshallers_factory, value): + schema = { + "type": "object", + "properties": {k: {"type": "number"} for k in ["a", "b", "c"]}, + "minProperties": 1, + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + + result = unmarshaller(value) + + assert result == value + + @pytest.mark.parametrize( + "value", + [ + {"a": 1}, + {"a": 1, "b": 2}, + {"a": 1, "b": 2, "c": 3}, + ], + ) + def test_object_min_properties_invalid(self, unmarshallers_factory, value): + schema = { + "type": "object", + "properties": {k: {"type": "number"} for k in ["a", "b", "c"]}, + "minProperties": 4, + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + + with pytest.raises(InvalidSchemaValue): + unmarshaller(value) + + @pytest.mark.parametrize( + "value", + [ + {}, + ], + ) + def test_object_min_properties_invalid_schema( + self, unmarshallers_factory, value + ): + schema = { + "type": "object", + "minProperties": 2, + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + + with pytest.raises(InvalidSchemaValue): + unmarshaller(value) + + @pytest.mark.parametrize( + "value", + [ + {"a": 1}, + {"a": 1, "b": 2}, + {"a": 1, "b": 2, "c": 3}, + ], + ) + def test_object_max_properties(self, unmarshallers_factory, value): + schema = { + "type": "object", + "properties": {k: {"type": "number"} for k in ["a", "b", "c"]}, + "maxProperties": 3, + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + + result = unmarshaller(value) + + assert result == value + + @pytest.mark.parametrize( + "value", + [ + {"a": 1}, + {"a": 1, "b": 2}, + {"a": 1, "b": 2, "c": 3}, + ], + ) + def test_object_max_properties_invalid(self, unmarshallers_factory, value): + schema = { + "type": "object", + "properties": {k: {"type": "number"} for k in ["a", "b", "c"]}, + "maxProperties": 0, + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + + with pytest.raises(InvalidSchemaValue): + unmarshaller(value) + + @pytest.mark.parametrize( + "value", + [ + {}, + ], + ) + def test_object_max_properties_invalid_schema( + self, unmarshallers_factory, value + ): + schema = { + "type": "object", + "maxProperties": -1, + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + + with pytest.raises(InvalidSchemaValue): + unmarshaller(value) + + def test_any_one_of(self, unmarshallers_factory): + schema = { + "oneOf": [ + { + "type": "string", + }, + { + "type": "array", + "items": { + "type": "string", + }, + }, + ], + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + value = ["hello"] + + result = unmarshaller(value) + + assert result == value + + def test_any_any_of(self, unmarshallers_factory): + schema = { + "anyOf": [ + { + "type": "string", + }, + { + "type": "array", + "items": { + "type": "string", + }, + }, + ], + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + value = ["hello"] + + result = unmarshaller(value) + + assert result == value + + def test_any_all_of(self, unmarshallers_factory): + schema = { + "allOf": [ + { + "type": "array", + "items": { + "type": "string", + }, + } + ], + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + value = ["hello"] + + result = unmarshaller(value) + + assert result == value + + @pytest.mark.parametrize( + "value", + [ + { + "somestr": {}, + "someint": 123, + }, + { + "somestr": ["content1", "content2"], + "someint": 123, + }, + { + "somestr": 123, + "someint": 123, + }, + { + "somestr": "content", + "someint": 123, + "not_in_scheme_prop": 123, + }, + ], + ) + def test_any_all_of_invalid_properties(self, value, unmarshallers_factory): + schema = { + "allOf": [ + { + "type": "object", + "required": ["somestr"], + "properties": { + "somestr": { + "type": "string", + }, + }, + }, + { + "type": "object", + "required": ["someint"], + "properties": { + "someint": { + "type": "integer", + }, + }, + }, + ], + "additionalProperties": False, + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + + with pytest.raises(InvalidSchemaValue): + unmarshaller(value) + + @pytest.mark.xfail( + reason=( + "Format assigned to type bug. " + "See https://github.com/p1c2u/openapi-core/issues/483" + ) + ) + def test_any_format_one_of(self, unmarshallers_factory): + schema = { + "format": "date", + "oneOf": [ + {"type": "integer"}, + { + "type": "string", + }, + ], + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + value = "2018-01-02" + + result = unmarshaller(value) + + assert result == date(2018, 1, 2) + + def test_any_one_of_any(self, unmarshallers_factory): + schema = { + "oneOf": [ + {"type": "integer"}, + { + "type": "string", + "format": "date", + }, + ], + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + value = "2018-01-02" + + result = unmarshaller(value) + + assert result == date(2018, 1, 2) + + def test_any_any_of_any(self, unmarshallers_factory): + schema = { + "anyOf": [ + {}, + { + "type": "string", + "format": "date", + }, + ], + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + value = "2018-01-02" + + result = unmarshaller(value) + + assert result == date(2018, 1, 2) + + def test_any_all_of_any(self, unmarshallers_factory): + schema = { + "allOf": [ + {}, + { + "type": "string", + "format": "date", + }, + ], + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + value = "2018-01-02" + + result = unmarshaller(value) + + assert result == date(2018, 1, 2) + + @pytest.mark.parametrize( + "value", + [ + {}, + ], + ) + def test_any_of_no_valid(self, unmarshallers_factory, value): + any_of = [ + { + "type": "object", + "required": ["test1"], + "properties": { + "test1": { + "type": "string", + }, + }, + }, + { + "type": "object", + "required": ["test2"], + "properties": { + "test2": { + "type": "string", + }, + }, + }, + ] + schema = { + "anyOf": any_of, + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + + with pytest.raises(InvalidSchemaValue): + unmarshaller(value) + + @pytest.mark.parametrize( + "value", + [ + {}, + ], + ) + def test_any_one_of_no_valid(self, unmarshallers_factory, value): + one_of = [ + { + "type": "object", + "required": [ + "test1", + ], + "properties": { + "test1": { + "type": "string", + }, + }, + }, + { + "type": "object", + "required": [ + "test2", + ], + "properties": { + "test2": { + "type": "string", + }, + }, + }, + ] + schema = { + "oneOf": one_of, + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + + with pytest.raises(InvalidSchemaValue): + unmarshaller(value) + + @pytest.mark.parametrize( + "value", + [ + {}, + ], + ) + def test_any_any_of_different_type(self, unmarshallers_factory, value): + any_of = [{"type": "integer"}, {"type": "string"}] + schema = { + "anyOf": any_of, + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + + with pytest.raises(InvalidSchemaValue): + unmarshaller(value) + + @pytest.mark.parametrize( + "value", + [ + {}, + ], + ) + def test_any_one_of_different_type(self, unmarshallers_factory, value): + one_of = [ + { + "type": "integer", + }, + { + "type": "string", + }, + ] + schema = { + "oneOf": one_of, + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + + with pytest.raises(InvalidSchemaValue): + unmarshaller(value) + + @pytest.mark.parametrize( + "value", + [ + { + "foo": "FOO", + }, + { + "foo": "FOO", + "bar": "BAR", + }, + ], + ) + def test_any_any_of_unambiguous(self, unmarshallers_factory, value): + any_of = [ + { + "type": "object", + "required": ["foo"], + "properties": { + "foo": { + "type": "string", + }, + }, + "additionalProperties": False, + }, + { + "type": "object", + "required": ["foo", "bar"], + "properties": { + "foo": { + "type": "string", + }, + "bar": { + "type": "string", + }, + }, + "additionalProperties": False, + }, + ] + schema = { + "anyOf": any_of, + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + + result = unmarshaller(value) + + assert result == value + + @pytest.mark.parametrize( + "value", + [ + {}, + ], + ) + def test_object_multiple_any_of(self, unmarshallers_factory, value): + any_of = [ + { + "type": "object", + }, + { + "type": "object", + }, + ] + schema = { + "type": "object", + "anyOf": any_of, + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + + result = unmarshaller(value) + + assert result == value + + @pytest.mark.parametrize( + "value", + [ + dict(), + ], + ) + def test_object_multiple_one_of(self, unmarshallers_factory, value): + one_of = [ + { + "type": "object", + }, + { + "type": "object", + }, + ] + schema = { + "type": "object", + "oneOf": one_of, + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + + with pytest.raises(InvalidSchemaValue): + unmarshaller(value) + + @pytest.mark.parametrize( + "value", + [ + { + "foo": "FOO", + }, + { + "foo": "FOO", + "bar": "BAR", + }, + ], + ) + def test_any_one_of_unambiguous(self, unmarshallers_factory, value): + one_of = [ + { + "type": "object", + "required": [ + "foo", + ], + "properties": { + "foo": { + "type": "string", + }, + }, + "additionalProperties": False, + }, + { + "type": "object", + "required": ["foo", "bar"], + "properties": { + "foo": { + "type": "string", + }, + "bar": { + "type": "string", + }, + }, + "additionalProperties": False, + }, + ] + schema = { + "oneOf": one_of, + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + + result = unmarshaller(value) + + assert result == value + + +class BaseTestOASS30chemaUnmarshallersFactoryCall: + def test_null_undefined(self, unmarshallers_factory): + schema = {"type": "null"} + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + + with pytest.raises(UnknownType): + unmarshaller(None) + + @pytest.mark.parametrize( + "type", + [ + "boolean", + "array", + "integer", + "number", + "string", + ], + ) + def test_nullable(self, unmarshallers_factory, type): + schema = {"type": type, "nullable": True} + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + + result = unmarshaller(None) + + assert result is None + + @pytest.mark.parametrize( + "type", + [ + "boolean", + "array", + "integer", + "number", + "string", + ], + ) + def test_not_nullable(self, unmarshallers_factory, type): + schema = {"type": type} + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + + with pytest.raises( + InvalidSchemaValue, + match=f"not valid for schema of type {type}", + ) as exc_info: + unmarshaller(None) + assert len(exc_info.value.schema_errors) == 2 + assert ( + "None for not nullable" in exc_info.value.schema_errors[0].message + ) + assert ( + f"None is not of type '{type}'" + in exc_info.value.schema_errors[1].message + ) + + @pytest.mark.parametrize( + "type,format,value,unmarshalled", + [ + ("string", "byte", "dGVzdA==", "test"), + ("string", "binary", b"test", b"test"), + ], + ) + def test_basic_type_oas30_formats( + self, unmarshallers_factory, type, format, value, unmarshalled + ): + schema = { + "type": type, + "format": format, + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + + result = unmarshaller(value) + + assert result == unmarshalled + + @pytest.mark.parametrize( + "type,format,value", + [ + ("string", "byte", "passwd"), + ("string", "binary", "test"), + ], + ) + def test_basic_type_oas30_formats_invalid( + self, unmarshallers_factory, type, format, value + ): + schema = { + "type": type, + "format": format, + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + + with pytest.raises( + InvalidSchemaValue, + match=f"not valid for schema of type {type}", + ) as exc_info: + unmarshaller(value) + assert len(exc_info.value.schema_errors) == 1 + assert ( + f"is not a '{format}'" in exc_info.value.schema_errors[0].message + ) + + @pytest.mark.xfail( + reason=( + "OAS 3.0 string type checker allows byte. " + "See https://github.com/p1c2u/openapi-schema-validator/issues/64" + ) + ) + def test_string_format_binary_invalid(self, unmarshallers_factory): + schema = { + "type": "string", + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + value = b"true" + + with pytest.raises( + InvalidSchemaValue, + match=f"not valid for schema of type {type}", + ): + unmarshaller(value) + + @pytest.mark.xfail( + reason=( + "Rraises TypeError not SchemaError. " + "See ttps://github.com/p1c2u/openapi-schema-validator/issues/65" + ) + ) + @pytest.mark.parametrize( + "types,value", + [ + (["string", "null"], "string"), + (["number", "null"], 2), + (["number", "null"], 3.14), + (["boolean", "null"], True), + (["array", "null"], [1, 2]), + (["object", "null"], {}), + ], + ) + def test_nultiple_types_undefined( + self, unmarshallers_factory, types, value + ): + schema = {"type": types} + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + + with pytest.raises(SchemaError): + unmarshaller(value) + + def test_integer_default_nullable(self, unmarshallers_factory): + default_value = 123 + schema = { + "type": "integer", + "default": default_value, + "nullable": True, + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + value = None + + result = unmarshaller(value) + + assert result is None + + def test_array_nullable(self, unmarshallers_factory): + schema = { + "type": "array", + "items": { + "type": "integer", + }, + "nullable": True, + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + value = None + + result = unmarshaller(value) + + assert result is None + + def test_object_property_nullable(self, unmarshallers_factory): + schema = { + "type": "object", + "properties": { + "foo": { + "type": "object", + "nullable": True, + } + }, + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + value = {"foo": None} + + result = unmarshaller(value) + + assert result == value + + +class TestOAS30RequestSchemaUnmarshallersFactory( + BaseTestOASSchemaUnmarshallersFactoryCall, + BaseTestOASS30chemaUnmarshallersFactoryCall, +): + @pytest.fixture + def unmarshallers_factory(self): + return oas30_request_schema_unmarshallers_factory + + def test_write_only_properties(self, unmarshallers_factory): + schema = { + "type": "object", + "required": ["id"], + "properties": { + "id": { + "type": "integer", + "writeOnly": True, + } + }, + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + value = {"id": 10} + + # readOnly properties may be admitted in a Response context + result = unmarshaller(value) + + assert result == value + + def test_read_only_properties_invalid(self, unmarshallers_factory): + schema = { + "type": "object", + "required": ["id"], + "properties": { + "id": { + "type": "integer", + "readOnly": True, + } + }, + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + value = {"id": 10} + + # readOnly properties are not admitted on a Request context + with pytest.raises(InvalidSchemaValue): + unmarshaller(value) + + +class TestOAS30ResponseSchemaUnmarshallersFactory( + BaseTestOASSchemaUnmarshallersFactoryCall, + BaseTestOASS30chemaUnmarshallersFactoryCall, +): + @pytest.fixture + def unmarshallers_factory(self): + return oas30_response_schema_unmarshallers_factory + + def test_read_only_properties(self, unmarshallers_factory): + schema = { + "type": "object", + "required": ["id"], + "properties": { + "id": { + "type": "integer", + "readOnly": True, + } + }, + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + + # readOnly properties may be admitted in a Response context + result = unmarshaller({"id": 10}) + + assert result == { + "id": 10, + } + + def test_write_only_properties_invalid(self, unmarshallers_factory): + schema = { + "type": "object", + "required": ["id"], + "properties": { + "id": { + "type": "integer", + "writeOnly": True, + } + }, + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + + # readOnly properties are not admitted on a Request context + with pytest.raises(InvalidSchemaValue): + unmarshaller({"id": 10}) + + +class TestOAS31SchemaUnmarshallersFactory( + BaseTestOASSchemaUnmarshallersFactoryCall +): + @pytest.fixture + def unmarshallers_factory(self): + return oas31_schema_unmarshallers_factory + + @pytest.mark.xfail( + reason=( + "OpenAPI 3.1 schema validator uses OpenAPI 3.0 format checker." + "See https://github.com/p1c2u/openapi-core/issues/506" + ) + ) + @pytest.mark.parametrize( + "type,format", + [ + ("string", "byte"), + ("string", "binary"), + ], + ) + def test_create_oas30_formatter_not_found( + self, unmarshallers_factory, type, format + ): + schema = { + "type": type, + "format": format, + } + spec = Spec.from_dict(schema, validator=None) + + with pytest.raises(FormatterNotFoundError): + unmarshallers_factory.create(spec) + + @pytest.mark.parametrize( + "type,value", + [ + ("string", b"test"), + ("integer", b"test"), + ("number", b"test"), + ("array", b"test"), + ("boolean", b"test"), + ("object", b"test"), + ], + ) + def test_basic_types_invalid(self, unmarshallers_factory, type, value): + schema = { + "type": type, + } + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + + with pytest.raises( + InvalidSchemaValue, + match=f"not valid for schema of type {type}", + ): + unmarshaller(value) + + def test_null(self, unmarshallers_factory): + schema = {"type": "null"} + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + + result = unmarshaller(None) + + assert result is None + + @pytest.mark.parametrize("value", ["string", 2, 3.14, True, [1, 2], {}]) + def test_null_invalid(self, unmarshallers_factory, value): + schema = {"type": "null"} + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + + with pytest.raises(InvalidSchemaValue) as exc_info: + unmarshaller(value) + assert len(exc_info.value.schema_errors) == 1 + assert ( + "is not of type 'null'" in exc_info.value.schema_errors[0].message + ) + + @pytest.mark.parametrize( + "types,value", + [ + (["string", "null"], "string"), + (["number", "null"], 2), + (["number", "null"], 3.14), + (["boolean", "null"], True), + (["array", "null"], [1, 2]), + (["object", "null"], {}), + ], + ) + def test_nultiple_types(self, unmarshallers_factory, types, value): + schema = {"type": types} + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + + result = unmarshaller(value) + + assert result == value + + @pytest.mark.parametrize( + "types,value", + [ + (["string", "null"], 2), + (["number", "null"], "string"), + (["number", "null"], True), + (["boolean", "null"], 3.14), + (["array", "null"], {}), + (["object", "null"], [1, 2]), + ], + ) + def test_nultiple_types_invalid(self, unmarshallers_factory, types, value): + schema = {"type": types} + spec = Spec.from_dict(schema, validator=None) + unmarshaller = unmarshallers_factory.create(spec) + + with pytest.raises(InvalidSchemaValue) as exc_info: + unmarshaller(value) + assert len(exc_info.value.schema_errors) == 1 + assert "is not of type" in exc_info.value.schema_errors[0].message diff --git a/tests/integration/validation/test_validators.py b/tests/integration/validation/test_validators.py index 45d32719..4149f2c6 100644 --- a/tests/integration/validation/test_validators.py +++ b/tests/integration/validation/test_validators.py @@ -4,11 +4,14 @@ import pytest +from openapi_core import Spec +from openapi_core import V30RequestValidator +from openapi_core import V30ResponseValidator +from openapi_core import openapi_request_validator from openapi_core.casting.schemas.exceptions import CastError from openapi_core.deserializing.media_types.exceptions import ( MediaTypeDeserializeError, ) -from openapi_core.spec import Spec from openapi_core.templating.media_types.exceptions import MediaTypeNotFound from openapi_core.templating.paths.exceptions import OperationNotFound from openapi_core.templating.paths.exceptions import PathNotFound @@ -17,8 +20,6 @@ from openapi_core.testing import MockRequest from openapi_core.testing import MockResponse from openapi_core.unmarshalling.schemas.exceptions import InvalidSchemaValue -from openapi_core.validation import openapi_request_validator -from openapi_core.validation import openapi_response_validator from openapi_core.validation.request.datatypes import Parameters from openapi_core.validation.request.exceptions import InvalidParameter from openapi_core.validation.request.exceptions import MissingRequiredParameter @@ -54,44 +55,49 @@ def spec_dict(self, factory): def spec(self, spec_dict): return Spec.from_dict(spec_dict) - def test_request_server_error(self, spec): + @pytest.fixture(scope="session") + def request_validator(self, spec): + return V30RequestValidator(spec) + + @pytest.fixture(scope="session") + def response_validator(self, spec): + return V30ResponseValidator(spec) + + def test_request_server_error(self, request_validator): request = MockRequest("http://petstore.invalid.net/v1", "get", "/") - with pytest.warns(DeprecationWarning): - result = openapi_request_validator.validate(spec, request) + result = request_validator.validate(request) assert len(result.errors) == 1 assert type(result.errors[0]) == PathNotFound assert result.body is None assert result.parameters == Parameters() - def test_invalid_path(self, spec): + def test_invalid_path(self, request_validator): request = MockRequest(self.host_url, "get", "/v1") - with pytest.warns(DeprecationWarning): - result = openapi_request_validator.validate(spec, request) + result = request_validator.validate(request) assert len(result.errors) == 1 assert type(result.errors[0]) == PathNotFound assert result.body is None assert result.parameters == Parameters() - def test_invalid_operation(self, spec): + def test_invalid_operation(self, request_validator): request = MockRequest(self.host_url, "patch", "/v1/pets") - with pytest.warns(DeprecationWarning): - result = openapi_request_validator.validate(spec, request) + result = request_validator.validate(request) assert len(result.errors) == 1 assert type(result.errors[0]) == OperationNotFound assert result.body is None assert result.parameters == Parameters() - def test_missing_parameter(self, spec): + def test_missing_parameter(self, request_validator): request = MockRequest(self.host_url, "get", "/v1/pets") with pytest.warns(DeprecationWarning): - result = openapi_request_validator.validate(spec, request) + result = request_validator.validate(request) assert type(result.errors[0]) == MissingRequiredParameter assert result.body is None @@ -102,7 +108,7 @@ def test_missing_parameter(self, spec): }, ) - def test_get_pets(self, spec): + def test_get_pets(self, request_validator): args = {"limit": "10", "ids": ["1", "2"], "api_key": self.api_key} request = MockRequest( self.host_url, @@ -113,7 +119,7 @@ def test_get_pets(self, spec): ) with pytest.warns(DeprecationWarning): - result = openapi_request_validator.validate(spec, request) + result = request_validator.validate(request) assert result.errors == [] assert result.body is None @@ -129,7 +135,7 @@ def test_get_pets(self, spec): "api_key": self.api_key, } - def test_get_pets_webob(self, spec): + def test_get_pets_webob(self, request_validator): from webob.multidict import GetDict request = MockRequest( @@ -143,7 +149,7 @@ def test_get_pets_webob(self, spec): ) with pytest.warns(DeprecationWarning): - result = openapi_request_validator.validate(spec, request) + result = request_validator.validate(request) assert result.errors == [] assert result.body is None @@ -156,7 +162,7 @@ def test_get_pets_webob(self, spec): }, ) - def test_missing_body(self, spec): + def test_missing_body(self, request_validator): headers = { "api-key": self.api_key_encoded, } @@ -173,7 +179,7 @@ def test_missing_body(self, spec): ) with pytest.warns(DeprecationWarning): - result = openapi_request_validator.validate(spec, request) + result = request_validator.validate(request) assert len(result.errors) == 1 assert type(result.errors[0]) == MissingRequiredRequestBody @@ -187,7 +193,7 @@ def test_missing_body(self, spec): }, ) - def test_invalid_content_type(self, spec): + def test_invalid_content_type(self, request_validator): data = "csv,data" headers = { "api-key": self.api_key_encoded, @@ -207,7 +213,7 @@ def test_invalid_content_type(self, spec): ) with pytest.warns(DeprecationWarning): - result = openapi_request_validator.validate(spec, request) + result = request_validator.validate(request) assert len(result.errors) == 1 assert type(result.errors[0]) == RequestBodyError @@ -225,7 +231,7 @@ def test_invalid_content_type(self, spec): }, ) - def test_invalid_complex_parameter(self, spec, spec_dict): + def test_invalid_complex_parameter(self, request_validator, spec_dict): pet_name = "Cat" pet_tag = "cats" pet_street = "Piekna" @@ -265,7 +271,7 @@ def test_invalid_complex_parameter(self, spec, spec_dict): ) with pytest.warns(DeprecationWarning): - result = openapi_request_validator.validate(spec, request) + result = request_validator.validate(request) assert result.errors == [ InvalidParameter(name="userdata", location="cookie") @@ -291,7 +297,7 @@ def test_invalid_complex_parameter(self, spec, spec_dict): assert result.body.address.street == pet_street assert result.body.address.city == pet_city - def test_post_pets(self, spec, spec_dict): + def test_post_pets(self, request_validator, spec_dict): pet_name = "Cat" pet_tag = "cats" pet_street = "Piekna" @@ -326,7 +332,7 @@ def test_post_pets(self, spec, spec_dict): ) with pytest.warns(DeprecationWarning): - result = openapi_request_validator.validate(spec, request) + result = request_validator.validate(request) assert result.errors == [] assert result.parameters == Parameters( @@ -350,7 +356,7 @@ def test_post_pets(self, spec, spec_dict): assert result.body.address.street == pet_street assert result.body.address.city == pet_city - def test_post_pets_plain_no_schema(self, spec): + def test_post_pets_plain_no_schema(self, request_validator): data = "plain text" headers = { "api-key": self.api_key_encoded, @@ -370,7 +376,7 @@ def test_post_pets_plain_no_schema(self, spec): ) with pytest.warns(UserWarning): - result = openapi_request_validator.validate(spec, request) + result = request_validator.validate(request) assert result.errors == [] assert result.parameters == Parameters( @@ -384,7 +390,7 @@ def test_post_pets_plain_no_schema(self, spec): assert result.security == {} assert result.body == data - def test_get_pet_unauthorized(self, spec): + def test_get_pet_unauthorized(self, request_validator): request = MockRequest( self.host_url, "get", @@ -393,8 +399,7 @@ def test_get_pet_unauthorized(self, spec): view_args={"petId": "1"}, ) - with pytest.warns(DeprecationWarning): - result = openapi_request_validator.validate(spec, request) + result = request_validator.validate(request) assert len(result.errors) == 1 assert type(result.errors[0]) is SecurityError @@ -405,7 +410,7 @@ def test_get_pet_unauthorized(self, spec): assert result.parameters == Parameters() assert result.security is None - def test_get_pet(self, spec): + def test_get_pet(self, request_validator): authorization = "Basic " + self.api_key_encoded headers = { "Authorization": authorization, @@ -420,7 +425,7 @@ def test_get_pet(self, spec): ) with pytest.warns(DeprecationWarning): - result = openapi_request_validator.validate(spec, request) + result = request_validator.validate(request) assert result.errors == [] assert result.body is None @@ -468,25 +473,29 @@ def spec_dict(self): def spec(self, spec_dict): return Spec.from_dict(spec_dict) - def test_request_missing_param(self, spec): + @pytest.fixture(scope="session") + def request_validator(self, spec): + return V30RequestValidator(spec) + + def test_request_missing_param(self, request_validator): request = MockRequest("http://example.com", "get", "/resource") - with pytest.warns(DeprecationWarning): - result = openapi_request_validator.validate(spec, request) + + result = request_validator.validate(request) assert len(result.errors) == 1 assert type(result.errors[0]) == MissingRequiredParameter assert result.body is None assert result.parameters == Parameters() - def test_request_invalid_param(self, spec): + def test_request_invalid_param(self, request_validator): request = MockRequest( "http://example.com", "get", "/resource", args={"resId": "invalid"}, ) - with pytest.warns(DeprecationWarning): - result = openapi_request_validator.validate(spec, request) + + result = request_validator.validate(request) assert result.errors == [ ParameterError(name="resId", location="query") @@ -495,15 +504,16 @@ def test_request_invalid_param(self, spec): assert result.body is None assert result.parameters == Parameters() - def test_request_valid_param(self, spec): + def test_request_valid_param(self, request_validator): request = MockRequest( "http://example.com", "get", "/resource", args={"resId": "10"}, ) + with pytest.warns(DeprecationWarning): - result = openapi_request_validator.validate(spec, request) + result = request_validator.validate(request) assert len(result.errors) == 0 assert result.body is None @@ -600,92 +610,78 @@ def test_request_object_deep_object_params(self, spec, spec_dict): class TestResponseValidator: host_url = "http://petstore.swagger.io" - @pytest.fixture + @pytest.fixture(scope="session") def spec_dict(self, factory): content, _ = factory.content_from_file("data/v3.0/petstore.yaml") return content - @pytest.fixture + @pytest.fixture(scope="session") def spec(self, spec_dict): return Spec.from_dict(spec_dict) - def test_invalid_server(self, spec): + @pytest.fixture(scope="session") + def response_validator(self, spec): + return V30ResponseValidator(spec) + + def test_invalid_server(self, response_validator): request = MockRequest("http://petstore.invalid.net/v1", "get", "/") response = MockResponse("Not Found", status_code=404) - with pytest.warns(DeprecationWarning): - result = openapi_response_validator.validate( - spec, request, response - ) + result = response_validator.validate(request, response) assert len(result.errors) == 1 assert type(result.errors[0]) == PathNotFound assert result.data is None assert result.headers == {} - def test_invalid_operation(self, spec): + def test_invalid_operation(self, response_validator): request = MockRequest(self.host_url, "patch", "/v1/pets") response = MockResponse("Not Found", status_code=404) - with pytest.warns(DeprecationWarning): - result = openapi_response_validator.validate( - spec, request, response - ) + result = response_validator.validate(request, response) assert len(result.errors) == 1 assert type(result.errors[0]) == OperationNotFound assert result.data is None assert result.headers == {} - def test_invalid_response(self, spec): + def test_invalid_response(self, response_validator): request = MockRequest(self.host_url, "get", "/v1/pets") response = MockResponse("Not Found", status_code=409) - with pytest.warns(DeprecationWarning): - result = openapi_response_validator.validate( - spec, request, response - ) + result = response_validator.validate(request, response) assert len(result.errors) == 1 assert type(result.errors[0]) == ResponseNotFound assert result.data is None assert result.headers == {} - def test_invalid_content_type(self, spec): + def test_invalid_content_type(self, response_validator): request = MockRequest(self.host_url, "get", "/v1/pets") response = MockResponse("Not Found", mimetype="text/csv") - with pytest.warns(DeprecationWarning): - result = openapi_response_validator.validate( - spec, request, response - ) + result = response_validator.validate(request, response) assert result.errors == [DataError()] assert type(result.errors[0].__cause__) == MediaTypeNotFound assert result.data is None assert result.headers == {} - def test_missing_body(self, spec): + def test_missing_body(self, response_validator): request = MockRequest(self.host_url, "get", "/v1/pets") response = MockResponse(None) - with pytest.warns(DeprecationWarning): - result = openapi_response_validator.validate( - spec, request, response - ) + result = response_validator.validate(request, response) assert result.errors == [MissingData()] assert result.data is None assert result.headers == {} - def test_invalid_media_type(self, spec): + def test_invalid_media_type(self, response_validator): request = MockRequest(self.host_url, "get", "/v1/pets") response = MockResponse("abcde") - with pytest.warns(DeprecationWarning): - result = openapi_response_validator.validate( - spec, request, response - ) + result = response_validator.validate(request, response) assert result.errors == [DataError()] assert result.errors[0].__cause__ == MediaTypeDeserializeError( @@ -694,21 +690,19 @@ def test_invalid_media_type(self, spec): assert result.data is None assert result.headers == {} - def test_invalid_media_type_value(self, spec): + def test_invalid_media_type_value(self, response_validator): request = MockRequest(self.host_url, "get", "/v1/pets") response = MockResponse("{}") with pytest.warns(DeprecationWarning): - result = openapi_response_validator.validate( - spec, request, response - ) + result = response_validator.validate(request, response) assert result.errors == [InvalidData()] assert type(result.errors[0].__cause__) == InvalidSchemaValue assert result.data is None assert result.headers == {} - def test_invalid_value(self, spec): + def test_invalid_value(self, response_validator): request = MockRequest(self.host_url, "get", "/v1/tags") response_json = { "data": [ @@ -719,16 +713,14 @@ def test_invalid_value(self, spec): response = MockResponse(response_data) with pytest.warns(DeprecationWarning): - result = openapi_response_validator.validate( - spec, request, response - ) + result = response_validator.validate(request, response) assert result.errors == [InvalidData()] assert type(result.errors[0].__cause__) == InvalidSchemaValue assert result.data is None assert result.headers == {} - def test_invalid_header(self, spec): + def test_invalid_header(self, response_validator): userdata = { "name": 1, } @@ -758,15 +750,13 @@ def test_invalid_header(self, spec): response = MockResponse(response_data, headers=headers) with pytest.warns(DeprecationWarning): - result = openapi_response_validator.validate( - spec, request, response - ) + result = response_validator.validate(request, response) assert result.errors == [InvalidHeader(name="x-delete-date")] assert result.data is None assert result.headers == {"x-delete-confirm": True} - def test_get_pets(self, spec): + def test_get_pets(self, response_validator): request = MockRequest(self.host_url, "get", "/v1/pets") response_json = { "data": [ @@ -783,9 +773,7 @@ def test_get_pets(self, spec): response = MockResponse(response_data) with pytest.warns(DeprecationWarning): - result = openapi_response_validator.validate( - spec, request, response - ) + result = response_validator.validate(request, response) assert result.errors == [] assert is_dataclass(result.data) diff --git a/tests/unit/unmarshalling/test_unmarshal.py b/tests/unit/unmarshalling/test_unmarshal.py index 1151d167..a512512d 100644 --- a/tests/unit/unmarshalling/test_unmarshal.py +++ b/tests/unit/unmarshalling/test_unmarshal.py @@ -1,23 +1,15 @@ -import datetime -import uuid from functools import partial import pytest -from isodate.tzinfo import UTC -from isodate.tzinfo import FixedOffset from openapi_schema_validator import OAS30Validator -from openapi_schema_validator import OAS31Validator from openapi_core.spec.paths import Spec -from openapi_core.unmarshalling.schemas.enums import ValidationContext from openapi_core.unmarshalling.schemas.exceptions import ( FormatterNotFoundError, ) from openapi_core.unmarshalling.schemas.exceptions import ( InvalidSchemaFormatValue, ) -from openapi_core.unmarshalling.schemas.exceptions import InvalidSchemaValue -from openapi_core.unmarshalling.schemas.exceptions import UnmarshalError from openapi_core.unmarshalling.schemas.factories import ( SchemaUnmarshallersFactory, ) @@ -44,23 +36,6 @@ class TestOAS30SchemaUnmarshallerUnmarshal: def unmarshaller_factory(self, schema_unmarshaller_factory): return partial(schema_unmarshaller_factory, OAS30Validator) - def test_no_schema(self, unmarshaller_factory): - spec = None - value = "test" - - with pytest.raises(TypeError): - unmarshaller_factory(spec).unmarshal(value) - - def test_schema_type_invalid(self, unmarshaller_factory): - schema = { - "type": "integer", - } - spec = Spec.from_dict(schema, validator=None) - value = "test" - - with pytest.raises(InvalidSchemaFormatValue): - unmarshaller_factory(spec).unmarshal(value) - def test_schema_custom_format_invalid(self, unmarshaller_factory): class CustomFormatter(Formatter): def format(self, value): @@ -90,145 +65,6 @@ class TestOAS30SchemaUnmarshallerCall: def unmarshaller_factory(self, schema_unmarshaller_factory): return partial(schema_unmarshaller_factory, OAS30Validator) - def test_deprecated(self, unmarshaller_factory): - schema = { - "type": "string", - "deprecated": True, - } - spec = Spec.from_dict(schema, validator=None) - value = "test" - - with pytest.warns(DeprecationWarning): - result = unmarshaller_factory(spec)(value) - - assert result == value - - @pytest.mark.parametrize( - "schema_type", - [ - "boolean", - "array", - "integer", - "number", - ], - ) - def test_non_string_empty_value(self, schema_type, unmarshaller_factory): - schema = { - "type": schema_type, - } - spec = Spec.from_dict(schema, validator=None) - value = "" - - with pytest.raises(InvalidSchemaValue): - unmarshaller_factory(spec)(value) - - def test_string_valid(self, unmarshaller_factory): - schema = { - "type": "string", - } - spec = Spec.from_dict(schema, validator=None) - value = "test" - - result = unmarshaller_factory(spec)(value) - - assert result == value - - def test_string_format_uuid_valid(self, unmarshaller_factory): - schema = { - "type": "string", - "format": "uuid", - } - spec = Spec.from_dict(schema, validator=None) - value = str(uuid.uuid4()) - - result = unmarshaller_factory(spec)(value) - - assert result == uuid.UUID(value) - - def test_string_format_uuid_uuid_quirks_invalid( - self, unmarshaller_factory - ): - schema = { - "type": "string", - "format": "uuid", - } - spec = Spec.from_dict(schema, validator=None) - value = uuid.uuid4() - - with pytest.raises(InvalidSchemaValue): - unmarshaller_factory(spec)(value) - - def test_string_format_password(self, unmarshaller_factory): - schema = { - "type": "string", - "format": "password", - } - spec = Spec.from_dict(schema, validator=None) - value = "password" - - result = unmarshaller_factory(spec)(value) - - assert result == "password" - - def test_string_float_invalid(self, unmarshaller_factory): - schema = { - "type": "string", - } - spec = Spec.from_dict(schema, validator=None) - value = 1.23 - - with pytest.raises(InvalidSchemaValue): - unmarshaller_factory(spec)(value) - - def test_string_format_date(self, unmarshaller_factory): - schema = { - "type": "string", - "format": "date", - } - spec = Spec.from_dict(schema, validator=None) - value = "2018-01-02" - - result = unmarshaller_factory(spec)(value) - - assert result == datetime.date(2018, 1, 2) - - def test_string_format_datetime_invalid(self, unmarshaller_factory): - schema = { - "type": "string", - "format": "date-time", - } - spec = Spec.from_dict(schema, validator=None) - value = "2018-01-02T00:00:00" - - with pytest.raises(InvalidSchemaValue): - unmarshaller_factory(spec)(value) - - def test_string_format_datetime_utc(self, unmarshaller_factory): - schema = { - "type": "string", - "format": "date-time", - } - spec = Spec.from_dict(schema, validator=None) - value = "2018-01-02T00:00:00Z" - - result = unmarshaller_factory(spec)(value) - - tzinfo = UTC - assert result == datetime.datetime(2018, 1, 2, 0, 0, tzinfo=tzinfo) - - def test_string_format_datetime_tz(self, unmarshaller_factory): - schema = { - "type": "string", - "format": "date-time", - } - spec = Spec.from_dict(schema, validator=None) - value = "2020-04-01T12:00:00+02:00" - - result = unmarshaller_factory(spec)(value) - - tzinfo = FixedOffset(2) - assert result == datetime.datetime(2020, 4, 1, 12, 0, 0, tzinfo=tzinfo) - def test_string_format_custom(self, unmarshaller_factory): formatted = "x-custom" @@ -328,743 +164,3 @@ def test_string_format_invalid_value(self, unmarshaller_factory): match="Formatter not found for custom format", ): unmarshaller_factory(spec)(value) - - def test_integer_valid(self, unmarshaller_factory): - schema = { - "type": "integer", - } - spec = Spec.from_dict(schema, validator=None) - value = 123 - - result = unmarshaller_factory(spec)(value) - - assert result == int(value) - - def test_integer_string_invalid(self, unmarshaller_factory): - schema = { - "type": "integer", - } - spec = Spec.from_dict(schema, validator=None) - value = "123" - - with pytest.raises(InvalidSchemaValue): - unmarshaller_factory(spec)(value) - - def test_integer_enum_invalid(self, unmarshaller_factory): - schema = { - "type": "integer", - "enum": [1, 2, 3], - } - spec = Spec.from_dict(schema, validator=None) - value = "123" - - with pytest.raises(UnmarshalError): - unmarshaller_factory(spec)(value) - - def test_integer_enum(self, unmarshaller_factory): - schema = { - "type": "integer", - "enum": [1, 2, 3], - } - spec = Spec.from_dict(schema, validator=None) - value = 2 - - result = unmarshaller_factory(spec)(value) - - assert result == int(value) - - def test_integer_enum_string_invalid(self, unmarshaller_factory): - schema = { - "type": "integer", - "enum": [1, 2, 3], - } - spec = Spec.from_dict(schema, validator=None) - value = "2" - - with pytest.raises(UnmarshalError): - unmarshaller_factory(spec)(value) - - def test_integer_default_nullable(self, unmarshaller_factory): - default_value = 123 - schema = { - "type": "integer", - "default": default_value, - "nullable": True, - } - spec = Spec.from_dict(schema, validator=None) - value = None - - result = unmarshaller_factory(spec)(value) - - assert result is None - - def test_integer_invalid(self, unmarshaller_factory): - schema = { - "type": "integer", - } - spec = Spec.from_dict(schema, validator=None) - value = "abc" - - with pytest.raises(InvalidSchemaValue): - unmarshaller_factory(spec)(value) - - def test_array_valid(self, unmarshaller_factory): - schema = { - "type": "array", - "items": { - "type": "integer", - }, - } - spec = Spec.from_dict(schema, validator=None) - value = [1, 2, 3] - - result = unmarshaller_factory(spec)(value) - - assert result == value - - def test_array_null(self, unmarshaller_factory): - schema = { - "type": "array", - "items": { - "type": "integer", - }, - } - spec = Spec.from_dict(schema, validator=None) - value = None - - with pytest.raises(InvalidSchemaValue): - unmarshaller_factory(spec)(value) - - def test_array_nullable(self, unmarshaller_factory): - schema = { - "type": "array", - "items": { - "type": "integer", - }, - "nullable": True, - } - spec = Spec.from_dict(schema, validator=None) - value = None - result = unmarshaller_factory(spec)(value) - - assert result is None - - def test_array_of_string_string_invalid(self, unmarshaller_factory): - schema = { - "type": "array", - "items": { - "type": "string", - }, - } - spec = Spec.from_dict(schema, validator=None) - value = "123" - - with pytest.raises(InvalidSchemaValue): - unmarshaller_factory(spec)(value) - - def test_array_of_integer_string_invalid(self, unmarshaller_factory): - schema = { - "type": "array", - "items": { - "type": "integer", - }, - } - spec = Spec.from_dict(schema, validator=None) - value = "123" - - with pytest.raises(InvalidSchemaValue): - unmarshaller_factory(spec)(value) - - def test_boolean_valid(self, unmarshaller_factory): - schema = { - "type": "boolean", - } - spec = Spec.from_dict(schema, validator=None) - value = True - - result = unmarshaller_factory(spec)(value) - - assert result == value - - def test_boolean_string_invalid(self, unmarshaller_factory): - schema = { - "type": "boolean", - } - spec = Spec.from_dict(schema, validator=None) - value = "True" - - with pytest.raises(InvalidSchemaValue): - unmarshaller_factory(spec)(value) - - def test_number_valid(self, unmarshaller_factory): - schema = { - "type": "number", - } - spec = Spec.from_dict(schema, validator=None) - value = 1.23 - - result = unmarshaller_factory(spec)(value) - - assert result == value - - def test_number_string_invalid(self, unmarshaller_factory): - schema = { - "type": "number", - } - spec = Spec.from_dict(schema, validator=None) - value = "1.23" - - with pytest.raises(InvalidSchemaValue): - unmarshaller_factory(spec)(value) - - def test_number_int(self, unmarshaller_factory): - schema = { - "type": "number", - } - spec = Spec.from_dict(schema, validator=None) - value = 1 - result = unmarshaller_factory(spec)(value) - - assert result == 1 - assert type(result) == int - - def test_number_float(self, unmarshaller_factory): - schema = { - "type": "number", - } - spec = Spec.from_dict(schema, validator=None) - value = 1.2 - result = unmarshaller_factory(spec)(value) - - assert result == 1.2 - assert type(result) == float - - def test_number_format_float(self, unmarshaller_factory): - schema = { - "type": "number", - "format": "float", - } - spec = Spec.from_dict(schema, validator=None) - value = 1.2 - result = unmarshaller_factory(spec)(value) - - assert result == 1.2 - - def test_number_format_double(self, unmarshaller_factory): - schema = { - "type": "number", - "format": "double", - } - spec = Spec.from_dict(schema, validator=None) - value = 1.2 - result = unmarshaller_factory(spec)(value) - - assert result == 1.2 - - def test_object_nullable(self, unmarshaller_factory): - schema = { - "type": "object", - "properties": { - "foo": { - "type": "object", - "nullable": True, - } - }, - } - spec = Spec.from_dict(schema, validator=None) - value = {"foo": None} - result = unmarshaller_factory(spec)(value) - - assert result == { - "foo": None, - } - - def test_schema_any_one_of(self, unmarshaller_factory): - schema = { - "oneOf": [ - { - "type": "string", - }, - { - "type": "array", - "items": { - "type": "string", - }, - }, - ], - } - spec = Spec.from_dict(schema, validator=None) - assert unmarshaller_factory(spec)(["hello"]) == ["hello"] - - def test_schema_any_any_of(self, unmarshaller_factory): - schema = { - "anyOf": [ - { - "type": "string", - }, - { - "type": "array", - "items": { - "type": "string", - }, - }, - ], - } - spec = Spec.from_dict(schema, validator=None) - assert unmarshaller_factory(spec)(["hello"]) == ["hello"] - - def test_schema_object_any_of(self, unmarshaller_factory): - schema = { - "type": "object", - "anyOf": [ - { - "type": "object", - "required": ["someint"], - "properties": {"someint": {"type": "integer"}}, - }, - { - "type": "object", - "required": ["somestr"], - "properties": {"somestr": {"type": "string"}}, - }, - ], - } - spec = Spec.from_dict(schema, validator=None) - result = unmarshaller_factory(spec)({"someint": 1}) - - assert result == { - "someint": 1, - } - - def test_schema_object_any_of_invalid(self, unmarshaller_factory): - schema = { - "type": "object", - "anyOf": [ - { - "type": "object", - "required": ["someint"], - "properties": {"someint": {"type": "integer"}}, - }, - { - "type": "object", - "required": ["somestr"], - "properties": {"somestr": {"type": "string"}}, - }, - ], - } - spec = Spec.from_dict(schema, validator=None) - with pytest.raises(UnmarshalError): - unmarshaller_factory(spec)({"someint": "1"}) - - def test_schema_object_one_of_default(self, unmarshaller_factory): - schema = { - "type": "object", - "oneOf": [ - { - "type": "object", - "properties": { - "somestr": { - "type": "string", - "default": "defaultstring", - }, - }, - }, - { - "type": "object", - "required": ["otherstr"], - "properties": { - "otherstr": { - "type": "string", - }, - }, - }, - ], - "properties": { - "someint": { - "type": "integer", - }, - }, - } - spec = Spec.from_dict(schema, validator=None) - assert unmarshaller_factory(spec)({"someint": 1}) == { - "someint": 1, - "somestr": "defaultstring", - } - - def test_schema_object_any_of_default(self, unmarshaller_factory): - schema = { - "type": "object", - "anyOf": [ - { - "type": "object", - "properties": { - "someint": { - "type": "integer", - }, - }, - }, - { - "type": "object", - "properties": { - "somestr": { - "type": "string", - "default": "defaultstring", - }, - }, - }, - ], - } - spec = Spec.from_dict(schema, validator=None) - assert unmarshaller_factory(spec)({"someint": "1"}) == { - "someint": "1", - "somestr": "defaultstring", - } - - def test_schema_object_all_of_default(self, unmarshaller_factory): - schema = { - "type": "object", - "allOf": [ - { - "type": "object", - "properties": { - "somestr": { - "type": "string", - "default": "defaultstring", - }, - }, - }, - { - "type": "object", - "properties": { - "someint": { - "type": "integer", - "default": 1, - }, - }, - }, - ], - } - spec = Spec.from_dict(schema, validator=None) - assert unmarshaller_factory(spec)({}) == { - "someint": 1, - "somestr": "defaultstring", - } - - def test_schema_any_all_of(self, unmarshaller_factory): - schema = { - "allOf": [ - { - "type": "array", - "items": { - "type": "string", - }, - } - ], - } - spec = Spec.from_dict(schema, validator=None) - assert unmarshaller_factory(spec)(["hello"]) == ["hello"] - - @pytest.mark.parametrize( - "value", - [ - { - "somestr": {}, - "someint": 123, - }, - { - "somestr": ["content1", "content2"], - "someint": 123, - }, - { - "somestr": 123, - "someint": 123, - }, - { - "somestr": "content", - "someint": 123, - "not_in_scheme_prop": 123, - }, - ], - ) - def test_schema_any_all_of_invalid_properties( - self, value, unmarshaller_factory - ): - schema = { - "allOf": [ - { - "type": "object", - "required": ["somestr"], - "properties": { - "somestr": { - "type": "string", - }, - }, - }, - { - "type": "object", - "required": ["someint"], - "properties": { - "someint": { - "type": "integer", - }, - }, - }, - ], - "additionalProperties": False, - } - spec = Spec.from_dict(schema, validator=None) - - with pytest.raises(InvalidSchemaValue): - unmarshaller_factory(spec)(value) - - def test_schema_any_any_of_any(self, unmarshaller_factory): - schema = { - "anyOf": [ - {}, - { - "type": "string", - "format": "date", - }, - ], - } - spec = Spec.from_dict(schema, validator=None) - value = "2018-01-02" - - result = unmarshaller_factory(spec)(value) - - assert result == datetime.date(2018, 1, 2) - - def test_schema_any_all_of_any(self, unmarshaller_factory): - schema = { - "allOf": [ - {}, - { - "type": "string", - "format": "date", - }, - ], - } - spec = Spec.from_dict(schema, validator=None) - value = "2018-01-02" - - result = unmarshaller_factory(spec)(value) - - assert result == datetime.date(2018, 1, 2) - - def test_schema_any(self, unmarshaller_factory): - schema = {} - spec = Spec.from_dict(schema, validator=None) - assert unmarshaller_factory(spec)("string") == "string" - - @pytest.mark.parametrize( - "value", - [ - {"additional": 1}, - {"foo": "bar", "bar": "foo"}, - {"additional": {"bar": 1}}, - ], - ) - @pytest.mark.parametrize("additional_properties", [True, {}]) - def test_schema_free_form_object( - self, value, additional_properties, unmarshaller_factory - ): - schema = { - "type": "object", - "additionalProperties": additional_properties, - } - spec = Spec.from_dict(schema, validator=None) - - result = unmarshaller_factory(spec)(value) - - assert result == value - - def test_additional_properties_list(self, unmarshaller_factory): - schema = {"type": "object"} - spec = Spec.from_dict(schema, validator=None) - - result = unmarshaller_factory(spec)({"user_ids": [1, 2, 3, 4]}) - - assert result == { - "user_ids": [1, 2, 3, 4], - } - - @pytest.mark.xfail(message="None and NOTSET should be distinguished") - def test_null_not_supported(self, unmarshaller_factory): - schema = {"type": "null"} - spec = Spec.from_dict(schema, validator=None) - - with pytest.raises(InvalidSchemaValue): - unmarshaller_factory(spec)(None) - - @pytest.mark.parametrize( - "types,value", - [ - (["string", "null"], "string"), - (["number", "null"], 2), - (["number", "null"], 3.14), - (["boolean", "null"], True), - (["array", "null"], [1, 2]), - (["object", "null"], {}), - ], - ) - def test_nultiple_types_not_supported( - self, unmarshaller_factory, types, value - ): - schema = {"type": types} - spec = Spec.from_dict(schema, validator=None) - - with pytest.raises(TypeError): - unmarshaller_factory(spec)(value) - - -class TestOAS30ReadSchemaUnmarshallerCall: - @pytest.fixture - def unmarshaller_factory(self, schema_unmarshaller_factory): - return partial( - schema_unmarshaller_factory, - OAS30Validator, - context=ValidationContext.RESPONSE, - ) - - def test_read_only_properties(self, unmarshaller_factory): - schema = { - "type": "object", - "required": ["id"], - "properties": { - "id": { - "type": "integer", - "readOnly": True, - } - }, - } - spec = Spec.from_dict(schema, validator=None) - - # readOnly properties may be admitted in a Response context - result = unmarshaller_factory(spec)({"id": 10}) - - assert result == { - "id": 10, - } - - def test_write_only_properties_invalid(self, unmarshaller_factory): - schema = { - "type": "object", - "required": ["id"], - "properties": { - "id": { - "type": "integer", - "writeOnly": True, - } - }, - } - spec = Spec.from_dict(schema, validator=None) - - # readOnly properties are not admitted on a Request context - with pytest.raises(InvalidSchemaValue): - unmarshaller_factory(spec)({"id": 10}) - - -class TestOAS30WriteSchemaUnmarshallerCall: - @pytest.fixture - def unmarshaller_factory(self, schema_unmarshaller_factory): - return partial( - schema_unmarshaller_factory, - OAS30Validator, - context=ValidationContext.REQUEST, - ) - - def test_write_only_properties(self, unmarshaller_factory): - schema = { - "type": "object", - "required": ["id"], - "properties": { - "id": { - "type": "integer", - "writeOnly": True, - } - }, - } - spec = Spec.from_dict(schema, validator=None) - - # readOnly properties may be admitted in a Response context - result = unmarshaller_factory(spec)({"id": 10}) - - assert result == { - "id": 10, - } - - def test_read_only_properties_invalid(self, unmarshaller_factory): - schema = { - "type": "object", - "required": ["id"], - "properties": { - "id": { - "type": "integer", - "readOnly": True, - } - }, - } - spec = Spec.from_dict(schema, validator=None) - - # readOnly properties are not admitted on a Request context - with pytest.raises(InvalidSchemaValue): - unmarshaller_factory(spec)({"id": 10}) - - -class TestOAS31SchemaUnmarshallerCall: - @pytest.fixture - def unmarshaller_factory(self, schema_unmarshaller_factory): - return partial(schema_unmarshaller_factory, OAS31Validator) - - def test_null(self, unmarshaller_factory): - schema = {"type": "null"} - spec = Spec.from_dict(schema, validator=None) - - result = unmarshaller_factory(spec)(None) - - assert result is None - - @pytest.mark.parametrize("value", ["string", 2, 3.14, True, [1, 2], {}]) - def test_null_invalid(self, unmarshaller_factory, value): - schema = {"type": "null"} - spec = Spec.from_dict(schema, validator=None) - - with pytest.raises(InvalidSchemaValue): - unmarshaller_factory(spec)(value) - - @pytest.mark.parametrize( - "types,value", - [ - (["string", "null"], "string"), - (["number", "null"], 2), - (["number", "null"], 3.14), - (["boolean", "null"], True), - (["array", "null"], [1, 2]), - (["object", "null"], {}), - ], - ) - def test_nultiple_types(self, unmarshaller_factory, types, value): - schema = {"type": types} - spec = Spec.from_dict(schema, validator=None) - - result = unmarshaller_factory(spec)(value) - - assert result == value - - @pytest.mark.parametrize( - "types,value", - [ - (["string", "null"], 2), - (["number", "null"], "string"), - (["number", "null"], True), - (["boolean", "null"], 3.14), - (["array", "null"], {}), - (["object", "null"], [1, 2]), - ], - ) - def test_nultiple_types_invalid(self, unmarshaller_factory, types, value): - schema = {"type": types} - spec = Spec.from_dict(schema, validator=None) - - with pytest.raises(InvalidSchemaValue): - unmarshaller_factory(spec)(value) diff --git a/tests/unit/unmarshalling/test_validate.py b/tests/unit/unmarshalling/test_validate.py index f5874fb5..51875192 100644 --- a/tests/unit/unmarshalling/test_validate.py +++ b/tests/unit/unmarshalling/test_validate.py @@ -40,28 +40,6 @@ def test_null(self, schema_type, validator_factory): with pytest.raises(InvalidSchemaValue): validator_factory(spec).validate(value) - @pytest.mark.parametrize( - "schema_type", - [ - "boolean", - "array", - "integer", - "number", - "string", - ], - ) - def test_nullable(self, schema_type, validator_factory): - schema = { - "type": schema_type, - "nullable": True, - } - spec = Spec.from_dict(schema, validator=None) - value = None - - result = validator_factory(spec).validate(value) - - assert result is None - def test_string_format_custom_missing(self, validator_factory): custom_format = "custom" schema = { @@ -358,952 +336,3 @@ def test_number_multiple_of(self, value, validator_factory): result = validator_factory(spec).validate(value) assert result is None - - @pytest.mark.parametrize("value", ["true", b"test"]) - def test_string(self, value, validator_factory): - schema = { - "type": "string", - } - spec = Spec.from_dict(schema, validator=None) - - result = validator_factory(spec).validate(value) - - assert result is None - - @pytest.mark.parametrize("value", [False, 1, 3.14, [1, 3]]) - def test_string_invalid(self, value, validator_factory): - schema = { - "type": "string", - } - spec = Spec.from_dict(schema, validator=None) - - with pytest.raises(InvalidSchemaValue): - validator_factory(spec).validate(value) - - @pytest.mark.parametrize( - "value", - [ - "test", - False, - 1, - 3.14, - [1, 3], - datetime.datetime(1989, 1, 2), - ], - ) - def test_string_format_date_invalid(self, value, validator_factory): - schema = { - "type": "string", - "format": "date", - } - spec = Spec.from_dict(schema, validator=None) - - with pytest.raises(InvalidSchemaValue): - validator_factory(spec).validate(value) - - @pytest.mark.xfail( - reason="See https://github.com/p1c2u/openapi-schema-validator/issues/64" - ) - @pytest.mark.parametrize( - "format", - [ - "date", - "date-time", - "uuid", - ], - ) - def test_string_format_date_invalid2(self, format, validator_factory): - schema = { - "type": "string", - "format": format, - } - spec = Spec.from_dict(schema, validator=None) - value = b"true" - - with pytest.raises(InvalidSchemaValue): - validator_factory(spec).validate(value) - - @pytest.mark.parametrize( - "value", - [ - "1989-01-02", - "2018-01-02", - ], - ) - def test_string_format_date(self, value, validator_factory): - schema = { - "type": "string", - "format": "date", - } - spec = Spec.from_dict(schema, validator=None) - - result = validator_factory(spec).validate(value) - - assert result is None - - @pytest.mark.parametrize( - "value", - [ - "12345678-1234-5678-1234-567812345678", - ], - ) - def test_string_format_uuid(self, value, validator_factory): - schema = { - "type": "string", - "format": "uuid", - } - spec = Spec.from_dict(schema, validator=None) - - result = validator_factory(spec).validate(value) - - assert result is None - - @pytest.mark.parametrize( - "value", - [ - "true", - False, - 1, - 3.14, - [1, 3], - datetime.date(2018, 1, 2), - datetime.datetime(2018, 1, 2, 23, 59, 59), - ], - ) - def test_string_format_uuid_invalid(self, value, validator_factory): - schema = { - "type": "string", - "format": "uuid", - } - spec = Spec.from_dict(schema, validator=None) - - with pytest.raises(InvalidSchemaValue): - validator_factory(spec).validate(value) - - @pytest.mark.parametrize( - "value", - [ - "2018-01-02T00:00:00Z", - ], - ) - def test_string_format_datetime(self, value, validator_factory): - schema = { - "type": "string", - "format": "date-time", - } - spec = Spec.from_dict(schema, validator=None) - - result = validator_factory(spec).validate(value) - - assert result is None - - @pytest.mark.parametrize( - "value", - [ - "true", - False, - 1, - 3.14, - [1, 3], - "1989-01-02", - ], - ) - def test_string_format_datetime_invalid(self, value, validator_factory): - schema = { - "type": "string", - "format": "date-time", - } - spec = Spec.from_dict(schema, validator=None) - - with pytest.raises(InvalidSchemaValue): - validator_factory(spec).validate(value) - - @pytest.mark.parametrize( - "value", - [ - "true", - False, - 1, - 3.14, - [1, 3], - "1989-01-02", - "1989-01-02T00:00:00Z", - ], - ) - def test_string_format_binary_invalid(self, value, validator_factory): - schema = { - "type": "string", - "format": "binary", - } - spec = Spec.from_dict(schema, validator=None) - - with pytest.raises(InvalidSchemaValue): - validator_factory(spec).validate(value) - - @pytest.mark.parametrize( - "value", - [ - b"stream", - b"text", - ], - ) - def test_string_format_binary(self, value, validator_factory): - schema = { - "type": "string", - "format": "binary", - } - spec = Spec.from_dict(schema, validator=None) - - result = validator_factory(spec).validate(value) - - assert result is None - - @pytest.mark.parametrize( - "value", - [ - b"dGVzdA==", - "dGVzdA==", - ], - ) - def test_string_format_byte(self, value, validator_factory): - schema = { - "type": "string", - "format": "byte", - } - spec = Spec.from_dict(schema, validator=None) - - result = validator_factory(spec).validate(value) - - assert result is None - - @pytest.mark.parametrize( - "value", - [ - "tsssst", - b"tsssst", - b"tesddddsdsdst", - ], - ) - def test_string_format_byte_invalid(self, value, validator_factory): - schema = { - "type": "string", - "format": "byte", - } - spec = Spec.from_dict(schema, validator=None) - - with pytest.raises(InvalidSchemaValue): - validator_factory(spec).validate(value) - - @pytest.mark.parametrize( - "value", - [ - "test", - b"stream", - datetime.date(1989, 1, 2), - datetime.datetime(1989, 1, 2, 0, 0, 0), - ], - ) - def test_string_format_unknown(self, value, validator_factory): - unknown_format = "unknown" - schema = { - "type": "string", - "format": unknown_format, - } - spec = Spec.from_dict(schema, validator=None) - - with pytest.raises(FormatterNotFoundError): - validator_factory(spec).validate(value) - - @pytest.mark.parametrize("value", ["", "a", "ab"]) - def test_string_min_length_invalid(self, value, validator_factory): - schema = { - "type": "string", - "minLength": 3, - } - spec = Spec.from_dict(schema, validator=None) - - with pytest.raises(InvalidSchemaValue): - validator_factory(spec).validate(value) - - @pytest.mark.parametrize("value", ["abc", "abcd"]) - def test_string_min_length(self, value, validator_factory): - schema = { - "type": "string", - "minLength": 3, - } - spec = Spec.from_dict(schema, validator=None) - - result = validator_factory(spec).validate(value) - - assert result is None - - @pytest.mark.parametrize( - "value", - [ - "", - ], - ) - def test_string_max_length_invalid_schema(self, value, validator_factory): - schema = { - "type": "string", - "maxLength": -1, - } - spec = Spec.from_dict(schema, validator=None) - - with pytest.raises(InvalidSchemaValue): - validator_factory(spec).validate(value) - - @pytest.mark.parametrize("value", ["ab", "abc"]) - def test_string_max_length_invalid(self, value, validator_factory): - schema = { - "type": "string", - "maxLength": 1, - } - spec = Spec.from_dict(schema, validator=None) - - with pytest.raises(InvalidSchemaValue): - validator_factory(spec).validate(value) - - @pytest.mark.parametrize("value", ["", "a"]) - def test_string_max_length(self, value, validator_factory): - schema = { - "type": "string", - "maxLength": 1, - } - spec = Spec.from_dict(schema, validator=None) - - result = validator_factory(spec).validate(value) - - assert result is None - - @pytest.mark.parametrize("value", ["foo", "bar"]) - def test_string_pattern_invalid(self, value, validator_factory): - schema = { - "type": "string", - "pattern": "baz", - } - spec = Spec.from_dict(schema, validator=None) - - with pytest.raises(InvalidSchemaValue): - validator_factory(spec).validate(value) - - @pytest.mark.parametrize("value", ["bar", "foobar"]) - def test_string_pattern(self, value, validator_factory): - schema = { - "type": "string", - "pattern": "bar", - } - spec = Spec.from_dict(schema, validator=None) - - result = validator_factory(spec).validate(value) - - assert result is None - - @pytest.mark.parametrize("value", ["true", False, 1, 3.14, [1, 3]]) - def test_object_not_an_object(self, value, validator_factory): - schema = { - "type": "object", - } - spec = Spec.from_dict(schema, validator=None) - - with pytest.raises(InvalidSchemaValue): - validator_factory(spec).validate(value) - - @pytest.mark.parametrize( - "value", - [ - dict(), - ], - ) - def test_object_multiple_one_of(self, value, validator_factory): - one_of = [ - { - "type": "object", - }, - { - "type": "object", - }, - ] - schema = { - "type": "object", - "oneOf": one_of, - } - spec = Spec.from_dict(schema, validator=None) - - with pytest.raises(InvalidSchemaValue): - validator_factory(spec).validate(value) - - @pytest.mark.parametrize( - "value", - [ - {}, - ], - ) - def test_object_different_type_one_of(self, value, validator_factory): - one_of = [ - { - "type": "integer", - }, - { - "type": "string", - }, - ] - schema = { - "type": "object", - "oneOf": one_of, - } - spec = Spec.from_dict(schema, validator=None) - - with pytest.raises(InvalidSchemaValue): - validator_factory(spec).validate(value) - - @pytest.mark.parametrize( - "value", - [ - {}, - ], - ) - def test_object_no_one_of(self, value, validator_factory): - one_of = [ - { - "type": "object", - "required": [ - "test1", - ], - "properties": { - "test1": { - "type": "string", - }, - }, - }, - { - "type": "object", - "required": [ - "test2", - ], - "properties": { - "test2": { - "type": "string", - }, - }, - }, - ] - schema = { - "type": "object", - "oneOf": one_of, - } - spec = Spec.from_dict(schema, validator=None) - - with pytest.raises(InvalidSchemaValue): - validator_factory(spec).validate(value) - - @pytest.mark.parametrize( - "value", - [ - { - "foo": "FOO", - }, - { - "foo": "FOO", - "bar": "BAR", - }, - ], - ) - def test_unambiguous_one_of(self, value, validator_factory): - one_of = [ - { - "type": "object", - "required": [ - "foo", - ], - "properties": { - "foo": { - "type": "string", - }, - }, - "additionalProperties": False, - }, - { - "type": "object", - "required": ["foo", "bar"], - "properties": { - "foo": { - "type": "string", - }, - "bar": { - "type": "string", - }, - }, - "additionalProperties": False, - }, - ] - schema = { - "type": "object", - "oneOf": one_of, - } - spec = Spec.from_dict(schema, validator=None) - - result = validator_factory(spec).validate(value) - - assert result is None - - @pytest.mark.parametrize( - "value", - [ - {}, - ], - ) - def test_object_multiple_any_of(self, value, validator_factory): - any_of = [ - { - "type": "object", - }, - { - "type": "object", - }, - ] - schema = { - "type": "object", - "anyOf": any_of, - } - spec = Spec.from_dict(schema, validator=None) - - result = validator_factory(spec).validate(value) - - assert result is None - - @pytest.mark.parametrize( - "value", - [ - {}, - ], - ) - def test_object_different_type_any_of(self, value, validator_factory): - any_of = [{"type": "integer"}, {"type": "string"}] - schema = { - "type": "object", - "anyOf": any_of, - } - spec = Spec.from_dict(schema, validator=None) - - with pytest.raises(InvalidSchemaValue): - validator_factory(spec).validate(value) - - @pytest.mark.parametrize( - "value", - [ - {}, - ], - ) - def test_object_no_any_of(self, value, validator_factory): - any_of = [ - { - "type": "object", - "required": ["test1"], - "properties": { - "test1": { - "type": "string", - }, - }, - }, - { - "type": "object", - "required": ["test2"], - "properties": { - "test2": { - "type": "string", - }, - }, - }, - ] - schema = { - "type": "object", - "anyOf": any_of, - } - spec = Spec.from_dict(schema, validator=None) - - with pytest.raises(InvalidSchemaValue): - validator_factory(spec).validate(value) - - @pytest.mark.parametrize( - "value", - [ - { - "foo": "FOO", - }, - { - "foo": "FOO", - "bar": "BAR", - }, - ], - ) - def test_unambiguous_any_of(self, value, validator_factory): - any_of = [ - { - "type": "object", - "required": ["foo"], - "properties": { - "foo": { - "type": "string", - }, - }, - "additionalProperties": False, - }, - { - "type": "object", - "required": ["foo", "bar"], - "properties": { - "foo": { - "type": "string", - }, - "bar": { - "type": "string", - }, - }, - "additionalProperties": False, - }, - ] - schema = { - "type": "object", - "anyOf": any_of, - } - spec = Spec.from_dict(schema, validator=None) - - result = validator_factory(spec).validate(value) - - assert result is None - - @pytest.mark.parametrize( - "value", - [ - {}, - ], - ) - def test_object_default_property(self, value, validator_factory): - schema = { - "type": "object", - "default": "value1", - } - spec = Spec.from_dict(schema, validator=None) - - result = validator_factory(spec).validate(value) - - assert result is None - - @pytest.mark.parametrize( - "value", - [ - {}, - ], - ) - def test_object_min_properties_invalid_schema( - self, value, validator_factory - ): - schema = { - "type": "object", - "minProperties": 2, - } - spec = Spec.from_dict(schema, validator=None) - - with pytest.raises(InvalidSchemaValue): - validator_factory(spec).validate(value) - - @pytest.mark.parametrize( - "value", - [ - {"a": 1}, - {"a": 1, "b": 2}, - {"a": 1, "b": 2, "c": 3}, - ], - ) - def test_object_min_properties_invalid(self, value, validator_factory): - schema = { - "type": "object", - "properties": {k: {"type": "number"} for k in ["a", "b", "c"]}, - "minProperties": 4, - } - spec = Spec.from_dict(schema, validator=None) - - with pytest.raises(InvalidSchemaValue): - validator_factory(spec).validate(value) - - @pytest.mark.parametrize( - "value", - [ - {"a": 1}, - {"a": 1, "b": 2}, - {"a": 1, "b": 2, "c": 3}, - ], - ) - def test_object_min_properties(self, value, validator_factory): - schema = { - "type": "object", - "properties": {k: {"type": "number"} for k in ["a", "b", "c"]}, - "minProperties": 1, - } - spec = Spec.from_dict(schema, validator=None) - result = validator_factory(spec).validate(value) - - assert result is None - - @pytest.mark.parametrize( - "value", - [ - {}, - ], - ) - def test_object_max_properties_invalid_schema( - self, value, validator_factory - ): - schema = { - "type": "object", - "maxProperties": -1, - } - spec = Spec.from_dict(schema, validator=None) - - with pytest.raises(InvalidSchemaValue): - validator_factory(spec).validate(value) - - @pytest.mark.parametrize( - "value", - [ - {"a": 1}, - {"a": 1, "b": 2}, - {"a": 1, "b": 2, "c": 3}, - ], - ) - def test_object_max_properties_invalid(self, value, validator_factory): - schema = { - "type": "object", - "properties": {k: {"type": "number"} for k in ["a", "b", "c"]}, - "maxProperties": 0, - } - spec = Spec.from_dict(schema, validator=None) - - with pytest.raises(InvalidSchemaValue): - validator_factory(spec).validate(value) - - @pytest.mark.parametrize( - "value", - [ - {"a": 1}, - {"a": 1, "b": 2}, - {"a": 1, "b": 2, "c": 3}, - ], - ) - def test_object_max_properties(self, value, validator_factory): - schema = { - "type": "object", - "properties": {k: {"type": "number"} for k in ["a", "b", "c"]}, - "maxProperties": 3, - } - spec = Spec.from_dict(schema, validator=None) - - result = validator_factory(spec).validate(value) - - assert result is None - - @pytest.mark.parametrize( - "value", - [ - {"additional": 1}, - ], - ) - def test_object_additional_properties(self, value, validator_factory): - schema = { - "type": "object", - } - spec = Spec.from_dict(schema, validator=None) - - result = validator_factory(spec).validate(value) - - assert result is None - - @pytest.mark.parametrize( - "value", - [ - {"additional": 1}, - ], - ) - def test_object_additional_properties_false( - self, value, validator_factory - ): - schema = { - "type": "object", - "additionalProperties": False, - } - spec = Spec.from_dict(schema, validator=None) - - with pytest.raises(InvalidSchemaValue): - validator_factory(spec).validate(value) - - @pytest.mark.parametrize( - "value", - [ - {"additional": 1}, - ], - ) - def test_object_additional_properties_object( - self, value, validator_factory - ): - additional_properties = { - "type": "integer", - } - schema = { - "type": "object", - "additionalProperties": additional_properties, - } - spec = Spec.from_dict(schema, validator=None) - - result = validator_factory(spec).validate(value) - - assert result is None - - @pytest.mark.parametrize("value", [[], [1], [1, 2]]) - def test_list_min_items_invalid(self, value, validator_factory): - schema = { - "type": "array", - "items": { - "type": "number", - }, - "minItems": 3, - } - spec = Spec.from_dict(schema, validator=None) - - with pytest.raises(Exception): - validator_factory(spec).validate(value) - - @pytest.mark.parametrize("value", [[], [1], [1, 2]]) - def test_list_min_items(self, value, validator_factory): - schema = { - "type": "array", - "items": { - "type": "number", - }, - "minItems": 0, - } - spec = Spec.from_dict(schema, validator=None) - - result = validator_factory(spec).validate(value) - - assert result is None - - @pytest.mark.parametrize( - "value", - [ - [], - ], - ) - def test_list_max_items_invalid_schema(self, value, validator_factory): - schema = { - "type": "array", - "items": { - "type": "number", - }, - "maxItems": -1, - } - spec = Spec.from_dict(schema, validator=None) - - with pytest.raises(InvalidSchemaValue): - validator_factory(spec).validate(value) - - @pytest.mark.parametrize("value", [[1, 2], [2, 3, 4]]) - def test_list_max_items_invalid(self, value, validator_factory): - schema = { - "type": "array", - "items": { - "type": "number", - }, - "maxItems": 1, - } - spec = Spec.from_dict(schema, validator=None) - - with pytest.raises(Exception): - validator_factory(spec).validate(value) - - @pytest.mark.parametrize("value", [[1, 2, 1], [2, 2]]) - def test_list_unique_items_invalid(self, value, validator_factory): - schema = { - "type": "array", - "items": { - "type": "number", - }, - "uniqueItems": True, - } - spec = Spec.from_dict(schema, validator=None) - - with pytest.raises(Exception): - validator_factory(spec).validate(value) - - @pytest.mark.parametrize( - "value", - [ - { - "someint": 123, - }, - { - "somestr": "content", - }, - { - "somestr": "content", - "someint": 123, - }, - ], - ) - def test_object_with_properties(self, value, validator_factory): - schema = { - "type": "object", - "properties": { - "somestr": { - "type": "string", - }, - "someint": { - "type": "integer", - }, - }, - } - spec = Spec.from_dict(schema, validator=None) - - result = validator_factory(spec).validate(value) - - assert result is None - - @pytest.mark.parametrize( - "value", - [ - { - "somestr": {}, - "someint": 123, - }, - { - "somestr": ["content1", "content2"], - "someint": 123, - }, - { - "somestr": 123, - "someint": 123, - }, - { - "somestr": "content", - "someint": 123, - "not_in_scheme_prop": 123, - }, - ], - ) - def test_object_with_invalid_properties(self, value, validator_factory): - schema = { - "type": "object", - "properties": { - "somestr": { - "type": "string", - }, - "someint": { - "type": "integer", - }, - }, - "additionalProperties": False, - } - spec = Spec.from_dict(schema, validator=None) - - with pytest.raises(Exception): - validator_factory(spec).validate(value)