diff --git a/.github/workflows/python-test.yml b/.github/workflows/python-test.yml index 2f7743da..f6cea286 100644 --- a/.github/workflows/python-test.yml +++ b/.github/workflows/python-test.yml @@ -23,7 +23,7 @@ jobs: uses: actions/setup-python@v2 with: python-version: ${{ matrix.python-version }} - + - name: Get full Python version id: full-python-version run: echo ::set-output name=version::$(python -c "import sys; print('-'.join(str(v) for v in sys.version_info))") diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 35275c38..9a47e619 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -22,7 +22,7 @@ repos: entry: flynt language: python additional_dependencies: ['flynt==0.64'] - + - id: black name: black entry: black diff --git a/tests/integration/data/v3.0/nullable_ref.yaml b/tests/integration/data/v3.0/nullable_ref.yaml new file mode 100644 index 00000000..2d2aabc2 --- /dev/null +++ b/tests/integration/data/v3.0/nullable_ref.yaml @@ -0,0 +1,58 @@ +openapi: "3.0.0" +info: + version: "0.1" + title: OpenAPI specification with nullable refs +paths: + /people/{personID}: + get: + summary: Show a person + parameters: + - name: personID + in: path + required: true + description: The ID of the person to retrieve + schema: + type: string + format: uuid + responses: + default: + description: Expected response to a valid request + content: + application/json: + schema: + $ref: '#/components/schemas/Person' +components: + schemas: + Person: + x-model: Person + type: object + required: + - id + - name + properties: + id: + description: The ID of the person. + type: string + format: uuid + name: + description: The full name of the person. + type: string + user: + description: The associated user account, if any. + nullable: true + allOf: + - $ref: '#/components/schemas/User' + User: + x-model: User + type: object + required: + - id + - username + properties: + id: + description: The ID of the user. + type: string + format: uuid + username: + description: The username of the user. + type: string diff --git a/tests/integration/validation/test_nullable_ref.py b/tests/integration/validation/test_nullable_ref.py new file mode 100644 index 00000000..8051edc8 --- /dev/null +++ b/tests/integration/validation/test_nullable_ref.py @@ -0,0 +1,62 @@ +import json +import uuid +from dataclasses import is_dataclass + +import pytest + +from openapi_core.testing import MockRequest +from openapi_core.testing import MockResponse +from openapi_core.validation.response import openapi_v30_response_validator + + +@pytest.fixture(scope="class") +def spec(factory): + return factory.spec_from_file("data/v3.0/nullable_ref.yaml") + + +class TestNullableRefs: + @pytest.mark.xfail(message="The nullable attribute should be respected") + def test_with_null_value(self, spec): + person = { + "id": str(uuid.uuid4()), + "name": "Joe Bloggs", + "user": None, + } + request = MockRequest("", "get", f"/people/{person['id']}") + response = MockResponse(json.dumps(person)) + + result = openapi_v30_response_validator.validate( + spec, request, response + ) + + assert not result.errors + assert is_dataclass(result.data) + assert result.data.__class__.__name__ == "Person" + assert result.data.id == uuid.UUID(person["id"]) + assert result.data.name == person["name"] + assert result.data.user is None + + def test_with_non_null_value(self, spec): + person = { + "id": str(uuid.uuid4()), + "name": "Joe Bloggs", + "user": { + "id": str(uuid.uuid4()), + "username": "joebloggs", + }, + } + request = MockRequest("", "get", f"/people/{person['id']}") + response = MockResponse(json.dumps(person)) + + result = openapi_v30_response_validator.validate( + spec, request, response + ) + + assert not result.errors + assert is_dataclass(result.data) + assert result.data.__class__.__name__ == "Person" + assert result.data.id == uuid.UUID(person["id"]) + assert result.data.name == person["name"] + assert result.data.user is not None + assert result.data.user.id == uuid.UUID(person["user"]["id"]) + assert result.data.user.username == person["user"]["username"] diff --git a/tox.ini b/tox.ini new file mode 100644 index 00000000..77480043 --- /dev/null +++ b/tox.ini @@ -0,0 +1,10 @@ +[tox] +minversion = 3.18.0 +requires = tox-poetry + +[testenv] +commands = pytest {posargs:tests/} + +[testenv:lint] +allowlist_externals = poetry +commands = poetry run pre-commit run -a