From 45aa702500fd04746b78f14b0237502b3b6b2c77 Mon Sep 17 00:00:00 2001 From: p1c2u Date: Sat, 18 Feb 2023 03:33:36 +0000 Subject: [PATCH] Formats raise error for other types fix --- openapi_schema_validator/_format.py | 39 ++++++++++++---- tests/integration/test_validators.py | 70 ++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+), 8 deletions(-) diff --git a/openapi_schema_validator/_format.py b/openapi_schema_validator/_format.py index 11fd863..373359b 100644 --- a/openapi_schema_validator/_format.py +++ b/openapi_schema_validator/_format.py @@ -1,6 +1,7 @@ import binascii from base64 import b64decode from base64 import b64encode +from numbers import Number from typing import Any from typing import Union @@ -8,41 +9,63 @@ def is_int32(instance: Any) -> bool: - return isinstance(instance, int) + # bool inherits from int, so ensure bools aren't reported as ints + if isinstance(instance, bool): + return True + if not isinstance(instance, int): + return True + return ~(1 << 31) < instance < 1 << 31 def is_int64(instance: Any) -> bool: - return isinstance(instance, int) + # bool inherits from int, so ensure bools aren't reported as ints + if isinstance(instance, bool): + return True + if not isinstance(instance, int): + return True + return ~(1 << 63) < instance < 1 << 63 def is_float(instance: Any) -> bool: + # bool inherits from int + if isinstance(instance, int): + return True + if not isinstance(instance, Number): + return True return isinstance(instance, float) def is_double(instance: Any) -> bool: + # bool inherits from int + if isinstance(instance, int): + return True + if not isinstance(instance, Number): + return True # float has double precision in Python # It's double in CPython and Jython return isinstance(instance, float) def is_binary(instance: Any) -> bool: - return isinstance(instance, bytes) + if not isinstance(instance, (str, bytes)): + return True + if isinstance(instance, str): + return False + return True def is_byte(instance: Union[str, bytes]) -> bool: + if not isinstance(instance, (str, bytes)): + return True if isinstance(instance, str): instance = instance.encode() - if not isinstance(instance, bytes): - return False encoded = b64encode(b64decode(instance)) return encoded == instance def is_password(instance: Any) -> bool: - if not isinstance(instance, (bytes, str)): - return False - + # A hint to UIs to obscure input return True diff --git a/tests/integration/test_validators.py b/tests/integration/test_validators.py index 6e78376..9fc85a1 100644 --- a/tests/integration/test_validators.py +++ b/tests/integration/test_validators.py @@ -34,6 +34,53 @@ def test_required_checkers(self, format_checker): class BaseTestOASValidatorValidate: + @pytest.mark.parametrize( + "format,value", + [ + ("int32", "test"), + ("int32", True), + ("int32", 3.12), + ("int32", ["test"]), + ("int64", "test"), + ("int64", True), + ("int64", 3.12), + ("int64", ["test"]), + ("float", "test"), + ("float", 3), + ("float", True), + ("float", ["test"]), + ("double", "test"), + ("double", 3), + ("double", True), + ("double", ["test"]), + ("password", 3.12), + ("password", True), + ("password", 3), + ("password", ["test"]), + ], + ) + def test_formats_ignored( + self, format, value, validator_class, format_checker + ): + schema = {"format": format} + validator = validator_class(schema, format_checker=format_checker) + + result = validator.validate(value) + + assert result is None + + @pytest.mark.parametrize("format", ["float", "double"]) + @pytest.mark.parametrize("value", [3, 3.14, 1.0]) + def test_number_float_and_double_valid( + self, format, value, validator_class, format_checker + ): + schema = {"type": "number", "format": format} + validator = validator_class(schema, format_checker=format_checker) + + result = validator.validate(value) + + assert result is None + @pytest.mark.parametrize("value", ["test"]) def test_string(self, validator_class, value): schema = {"type": "string"} @@ -61,6 +108,29 @@ def validator_class(self): def format_checker(self): return oas30_format_checker + @pytest.mark.parametrize( + "format,value", + [ + ("binary", True), + ("binary", 3), + ("binary", 3.12), + ("binary", ["test"]), + ("byte", True), + ("byte", 3), + ("byte", 3.12), + ("byte", ["test"]), + ], + ) + def test_oas30_formats_ignored( + self, format, value, validator_class, format_checker + ): + schema = {"format": format} + validator = validator_class(schema, format_checker=format_checker) + + result = validator.validate(value) + + assert result is None + @pytest.mark.xfail(reason="OAS 3.0 string type checker allows byte") @pytest.mark.parametrize("value", [b"test"]) def test_string_disallow_binary(self, validator_class, value):