From 0a654788723d5586afdae55c90d46ad49af85199 Mon Sep 17 00:00:00 2001 From: Andreas Hug Date: Sun, 24 Jul 2016 10:32:45 +0200 Subject: [PATCH] Refactor allownull integration tests Reduce test complexity by splitting up in multiple tests, suggested in https://github.com/Yelp/bravado-core/pull/64#discussion_r71975165 --- tests/unmarshal/unmarshal_nullable_test.py | 175 ++++++++++++++------- 1 file changed, 115 insertions(+), 60 deletions(-) diff --git a/tests/unmarshal/unmarshal_nullable_test.py b/tests/unmarshal/unmarshal_nullable_test.py index ef054c78..7220b5e9 100644 --- a/tests/unmarshal/unmarshal_nullable_test.py +++ b/tests/unmarshal/unmarshal_nullable_test.py @@ -5,60 +5,66 @@ from jsonschema.exceptions import ValidationError -@pytest.mark.parametrize('value', ['x', None]) -@pytest.mark.parametrize('nullable', [True, False]) -def test_unmarshal_with_primitive(empty_swagger_spec, value, nullable): - """If the value is a primitive, validation should pass if - `x-nullable` is `True` and the value is `None`. `required` is not - possible in this scenario. - - +---------------------+--------------+ - | x-nullable == False | 'x' -> pass | - | | None -> fail | - +---------------------+--------------+ - | x-nullable == True | 'x' -> pass | - | | None -> pass | - +---------------------+--------------+ - """ +"""If the value is a primitive, validation should pass if +`x-nullable` is `True` and the value is `None`. `required` is not +possible in this scenario. + ++---------------------+------------------+ +| x-nullable == False | 'x' -> pass (1) | +| | None -> fail (2) | ++---------------------+------------------+ +| x-nullable == True | 'x' -> pass (3) | +| | None -> pass (4) | ++---------------------+------------------+ +""" + + +@pytest.mark.parametrize(['nullable', 'value'], + [(False, 'x'), (True, 'x'), (True, None)]) +def test_unmarshal_with_primitive_pass(empty_swagger_spec, value, nullable): + """Test scenarios in which validation should pass: (1), (3), (4)""" content_spec = { 'type': 'string', 'x-nullable': nullable, } + validate_schema_object(empty_swagger_spec, content_spec, value) + result = unmarshal_schema_object(empty_swagger_spec, content_spec, value) + assert result == value - try: + +def test_unmarshal_with_primitive_fail(empty_swagger_spec): + """Test scenarios in which validation should fail: (2)""" + content_spec = { + 'type': 'string', + 'x-nullable': False, + } + value = None + with pytest.raises(ValidationError) as excinfo: validate_schema_object(empty_swagger_spec, content_spec, value) - result = unmarshal_schema_object( - empty_swagger_spec, content_spec, value) - except ValidationError as e: - result = e + unmarshal_schema_object(empty_swagger_spec, content_spec, value) + assert excinfo.value.message == "None is not of type 'string'" - if nullable is False and not value: - assert result.message == "None is not of type 'string'" - else: - assert result == value +"""If the value is an object, validation should pass if +`x-nullable` is `True` and the value is `None`. `required` doesn't +have an influence. -@pytest.mark.parametrize('value', [{'x': 'y'}, {'x': None}, {}]) -@pytest.mark.parametrize('nullable', [True, False]) -@pytest.mark.parametrize('required', [True, False]) -def test_unmarshal_with_object(empty_swagger_spec, value, nullable, required): - """If the value is an object, validation should pass if - `x-nullable` is `True` and the value is `None`. `required` doesn't - have an influence. - - +---------------------+---------------------+---------------------+ - | | required == False | required == True | - +---------------------+---------------------+---------------------+ - | x-nullable == False | {} -> pass | {} -> fail | - | | {'x': 'y'} -> pass | {'x': 'y'} -> pass | - | | {'x': None} -> fail | {'x': None} -> fail | - +---------------------+---------------------+---------------------+ - | x-nullable == True | {} -> pass | {} -> fail | - | | {'x': 'y'} -> pass | {'x': 'y'} -> pass | - | | {'x': None} -> pass | {'x': None} -> pass | - +---------------------+---------------------+---------------------+ - """ - content_spec = { ++---------------------+-------------------------+--------------------------+ +| | required == False | required == True | ++---------------------+-------------------------+--------------------------+ +| x-nullable == False | {} -> pass (1) | {} -> fail (4) | +| | {'x': 'y'} -> pass (2) | {'x': 'y'} -> pass (5) | +| | {'x': None} -> fail (3) | {'x': None} -> fail (6) | ++---------------------+-------------------------+--------------------------+ +| x-nullable == True | {} -> pass (7) | {} -> fail (10) | +| | {'x': 'y'} -> pass (8) | {'x': 'y'} -> pass (11) | +| | {'x': None} -> pass (9) | {'x': None} -> pass (12) | ++---------------------+-------------------------+--------------------------+ +""" + + +def content_spec_factory(required, nullable): + return { 'type': 'object', 'required': ['x'] if required else [], 'properties': { @@ -69,19 +75,68 @@ def test_unmarshal_with_object(empty_swagger_spec, value, nullable, required): } } - try: + +@pytest.mark.parametrize('nullable', [True, False]) +@pytest.mark.parametrize('required', [True, False]) +def test_unmarshal_with_object_default(empty_swagger_spec, nullable, required): + """With a value set, validation should always pass: (2), (5), (8), (11)""" + content_spec = content_spec_factory(required, nullable) + value = {'x': 'y'} + + validate_schema_object(empty_swagger_spec, content_spec, value) + result = unmarshal_schema_object(empty_swagger_spec, content_spec, value) + assert result == value + + +@pytest.mark.parametrize('nullable', [True, False]) +def test_unmarshal_with_object_req_no_value(empty_swagger_spec, nullable): + """When the value is required but not set at all, validation + should fail: (4), (10) + """ + content_spec = content_spec_factory(True, nullable) + value = {} + + with pytest.raises(ValidationError) as excinfo: + validate_schema_object(empty_swagger_spec, content_spec, value) + unmarshal_schema_object(empty_swagger_spec, content_spec, value) + assert excinfo.value.message == "'x' is a required property" + + +@pytest.mark.parametrize('nullable', [True, False]) +def test_unmarshal_with_object_no_req_no_value(empty_swagger_spec, nullable): + """When the value is not required and not set at all, validation + should pass: (1), (7) + """ + content_spec = content_spec_factory(False, nullable=nullable) + value = {} + + validate_schema_object(empty_swagger_spec, content_spec, value) + result = unmarshal_schema_object(empty_swagger_spec, content_spec, value) + assert result == {'x': None} # Missing parameters are re-introduced + + +@pytest.mark.parametrize('required', [True, False]) +def test_unmarshal_with_object_no_null_value_none(empty_swagger_spec, required): + """When nullable is `False` and the value is set to `None`, validation + should fail: (3), (6) + """ + content_spec = content_spec_factory(required, False) + value = {'x': None} + + with pytest.raises(ValidationError) as excinfo: validate_schema_object(empty_swagger_spec, content_spec, value) - result = unmarshal_schema_object( - empty_swagger_spec, content_spec, value) - except ValidationError as e: - result = e - - if value == {} and required is True: - assert result.message == "'x' is a required property" - elif value == {} and required is False: - # Unmarshal re-introduces missing properties with None which is ok. - assert result == {'x': None} - elif nullable is False and value['x'] is None: - assert result.message == "None is not of type 'string'" - else: - result == value + unmarshal_schema_object(empty_swagger_spec, content_spec, value) + assert excinfo.value.message == "None is not of type 'string'" + + +@pytest.mark.parametrize('required', [True, False]) +def test_unmarshal_with_object_null_value_none(empty_swagger_spec, required): + """When nullable is `True` and the value is set to `None`, validation + should pass: (9), (12) + """ + content_spec = content_spec_factory(required, True) + value = {'x': None} + + validate_schema_object(empty_swagger_spec, content_spec, value) + result = unmarshal_schema_object(empty_swagger_spec, content_spec, value) + assert result == {'x': None}