Skip to content

Commit

Permalink
Merge pull request #37 from maticardenas/36-support-numeric-format-fo…
Browse files Browse the repository at this point in the history
…r-string-type

Support numeric format for string type
  • Loading branch information
maticardenas authored and Matias Cardenas committed May 5, 2024
2 parents 750743b + 22ec239 commit eae1eee
Show file tree
Hide file tree
Showing 5 changed files with 318 additions and 271 deletions.
6 changes: 5 additions & 1 deletion openapi_tester/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,13 @@
"number": f"{int.__name__} or {float.__name__}",
}

NUMERIC_FORMATS = ["number", "float", "double"]

INTERNET_PROTOCOLS = ["ipv4", "ipv6", "email"]

# Validation errors
VALIDATE_FORMAT_ERROR = (
'Expected: {article} "{format}" formatted value\n\nReceived: {received}'
'Expected: {article} "{format}" formatted "{type}" value\n\nReceived: {received}'
)
VALIDATE_PATTERN_ERROR = (
'The string "{data}" does not match the specified pattern: {pattern}'
Expand Down
31 changes: 25 additions & 6 deletions openapi_tester/validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@
from django.utils.dateparse import parse_date, parse_datetime, parse_time

from openapi_tester.constants import (
INTERNET_PROTOCOLS,
INVALID_PATTERN_ERROR,
NUMERIC_FORMATS,
VALIDATE_ENUM_ERROR,
VALIDATE_FORMAT_ERROR,
VALIDATE_MAX_ARRAY_LENGTH_ERROR,
Expand Down Expand Up @@ -114,13 +116,30 @@ def validate_type(schema_section: dict[str, Any], data: Any) -> str | None:


def validate_format(schema_section: dict[str, Any], data: Any) -> str | None:
value = data
schema_format: str = schema_section.get("format", "")
if schema_format in VALIDATOR_MAP and not VALIDATOR_MAP[schema_format](data):
return VALIDATE_FORMAT_ERROR.format(
article="an" if format in ["ipv4", "ipv6", "email"] else "a",
format=schema_format,
received=f'"{data}"',
)
schema_type: str = schema_section.get("type", "object")
if schema_format in VALIDATOR_MAP:
if not isinstance(schema_type, list) and schema_type == "string":
try:
if schema_format == "integer":
value = int(data)
if schema_format in NUMERIC_FORMATS:
value = float(data)
except ValueError:
return VALIDATE_FORMAT_ERROR.format(
article="an" if format in INTERNET_PROTOCOLS else "a",
format=schema_format,
type=schema_type,
received=f'"{value}"',
)
if not VALIDATOR_MAP[schema_format](value):
return VALIDATE_FORMAT_ERROR.format(
article="an" if format in INTERNET_PROTOCOLS else "a",
format=schema_format,
type=schema_type,
received=f'"{value}"',
)
return None


Expand Down
264 changes: 0 additions & 264 deletions tests/test_errors.py

This file was deleted.

58 changes: 58 additions & 0 deletions tests/test_openapi_object_errors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import pytest

from openapi_tester import SchemaTester
from openapi_tester.config import OpenAPITestConfig
from openapi_tester.exceptions import DocumentationError


def test_missing_response_key_error():
expected_error_message = (
'The following property was found in the schema definition, but is missing from the response data: "one"'
"\n\nReference:\n\nPOST /endpoint > response > one"
'\n\nResponse body:\n {\n "two": 2\n}'
'\nSchema section:\n {\n "one": {\n "type": "int"\n }\n}'
"\n\nHint: Remove the key from your OpenAPI docs, or include it in your API response"
)
tester = SchemaTester()
with pytest.raises(DocumentationError, match=expected_error_message):
tester.test_openapi_object(
{"required": ["one"], "properties": {"one": {"type": "int"}}},
{"two": 2},
OpenAPITestConfig(reference="POST /endpoint > response"),
)


def test_missing_schema_key_error():
expected_error_message = (
'The following property was found in the response data, but is missing from the schema definition: "two"'
"\n\nReference:"
"\n\nPOST /endpoint > response > two"
'\n\nResponse body:\n {\n "one": 1,\n "two": 2\n}'
'\n\nSchema section:\n {\n "one": {\n "type": "int"\n }\n}'
"\n\nHint: Remove the key from your API response, or include it in your OpenAPI docs"
)
tester = SchemaTester()
with pytest.raises(DocumentationError, match=expected_error_message):
tester.test_openapi_object(
{"required": ["one"], "properties": {"one": {"type": "int"}}},
{"one": 1, "two": 2},
OpenAPITestConfig(reference="POST /endpoint > response"),
)


def test_key_in_write_only_properties_error():
expected_error_message = (
'The following property was found in the response, but is documented as being "writeOnly": "one"'
"\n\nReference:"
"\n\nPOST /endpoint > response > one"
'\n\nResponse body:\n {\n "one": 1\n}'
'\nSchema section:\n {\n "one": {\n "type": "int",\n "writeOnly": true\n }\n}'
'\n\nHint: Remove the key from your API response, or remove the "WriteOnly" restriction'
)
tester = SchemaTester()
with pytest.raises(DocumentationError, match=expected_error_message):
tester.test_openapi_object(
{"properties": {"one": {"type": "int", "writeOnly": True}}},
{"one": 1},
OpenAPITestConfig(reference="POST /endpoint > response"),
)
Loading

0 comments on commit eae1eee

Please sign in to comment.