From 6d6832e7a657189206ec2960d928acb892b09628 Mon Sep 17 00:00:00 2001 From: Bartek Kryza Date: Mon, 12 Sep 2016 05:00:49 +0200 Subject: [PATCH] Fix for #3712 - invalid enum array validation in Python client mustache model (#3713) * Fixed invalid enum array validation in Python client mustache model * Updated the Petstore Python client tests * Removed superfluous array enum test * Added test cases for Python client array and map enums * Improved map enum error message --- .../src/main/resources/python/model.mustache | 20 +++ .../python/petstore_api/models/enum_arrays.py | 7 +- .../python/petstore_api/models/map_test.py | 7 +- .../petstore/python/tests/test_enum_arrays.py | 164 ++++++++++++++++++ .../petstore/python/tests/test_map_test.py | 106 +++++++++++ 5 files changed, 298 insertions(+), 6 deletions(-) create mode 100644 samples/client/petstore/python/tests/test_enum_arrays.py create mode 100644 samples/client/petstore/python/tests/test_map_test.py diff --git a/modules/swagger-codegen/src/main/resources/python/model.mustache b/modules/swagger-codegen/src/main/resources/python/model.mustache index 1569b3d37c97..aa4a9f2e90ca 100644 --- a/modules/swagger-codegen/src/main/resources/python/model.mustache +++ b/modules/swagger-codegen/src/main/resources/python/model.mustache @@ -61,11 +61,31 @@ class {{classname}}(object): """ {{#isEnum}} allowed_values = [{{#allowableValues}}{{#values}}"{{{this}}}"{{^-last}}, {{/-last}}{{/values}}{{/allowableValues}}] +{{#isContainer}} +{{#isListContainer}} + if not set({{{name}}}).issubset(set(allowed_values)): + raise ValueError( + "Invalid values for `{{{name}}}` [{0}], must be a subset of [{1}]" + .format(", ".join(map(str, set({{{name}}})-set(allowed_values))), + ", ".join(map(str, allowed_values))) + ) +{{/isListContainer}} +{{#isMapContainer}} + if not set({{{name}}}.keys()).issubset(set(allowed_values)): + raise ValueError( + "Invalid keys in `{{{name}}}` [{0}], must be a subset of [{1}]" + .format(", ".join(map(str, set({{{name}}}.keys())-set(allowed_values))), + ", ".join(map(str, allowed_values))) + ) +{{/isMapContainer}} +{{/isContainer}} +{{^isContainer}} if {{{name}}} not in allowed_values: raise ValueError( "Invalid value for `{{{name}}}` ({0}), must be one of {1}" .format({{{name}}}, allowed_values) ) +{{/isContainer}} {{/isEnum}} {{^isEnum}} {{#hasValidation}} diff --git a/samples/client/petstore/python/petstore_api/models/enum_arrays.py b/samples/client/petstore/python/petstore_api/models/enum_arrays.py index 855f26cbef69..a7b01873f872 100644 --- a/samples/client/petstore/python/petstore_api/models/enum_arrays.py +++ b/samples/client/petstore/python/petstore_api/models/enum_arrays.py @@ -105,10 +105,11 @@ class EnumArrays(object): :type: list[str] """ allowed_values = ["fish", "crab"] - if array_enum not in allowed_values: + if not set(array_enum).issubset(set(allowed_values)): raise ValueError( - "Invalid value for `array_enum` ({0}), must be one of {1}" - .format(array_enum, allowed_values) + "Invalid values for `array_enum` [{0}], must be a subset of [{1}]" + .format(", ".join(map(str, set(array_enum)-set(allowed_values))), + ", ".join(map(str, allowed_values))) ) self._array_enum = array_enum diff --git a/samples/client/petstore/python/petstore_api/models/map_test.py b/samples/client/petstore/python/petstore_api/models/map_test.py index 58ad0d7ac3ef..8201a5b46826 100644 --- a/samples/client/petstore/python/petstore_api/models/map_test.py +++ b/samples/client/petstore/python/petstore_api/models/map_test.py @@ -99,10 +99,11 @@ class MapTest(object): :type: dict(str, str) """ allowed_values = ["UPPER", "lower"] - if map_of_enum_string not in allowed_values: + if not set(map_of_enum_string.keys()).issubset(set(allowed_values)): raise ValueError( - "Invalid value for `map_of_enum_string` ({0}), must be one of {1}" - .format(map_of_enum_string, allowed_values) + "Invalid keys in `map_of_enum_string` [{0}], must be a subset of [{1}]" + .format(", ".join(map(str, set(map_of_enum_string.keys())-set(allowed_values))), + ", ".join(map(str, allowed_values))) ) self._map_of_enum_string = map_of_enum_string diff --git a/samples/client/petstore/python/tests/test_enum_arrays.py b/samples/client/petstore/python/tests/test_enum_arrays.py new file mode 100644 index 000000000000..aa373339a60a --- /dev/null +++ b/samples/client/petstore/python/tests/test_enum_arrays.py @@ -0,0 +1,164 @@ +# coding: utf-8 + +""" +Run the tests. +$ pip install nose (optional) +$ cd petstore_api-python +$ nosetests -v +""" + +import os +import time +import unittest + +import petstore_api + + +class EnumArraysTests(unittest.TestCase): + + def test_enumarrays_init(self): + # + # Check various combinations of valid values. + # + fish_or_crab = petstore_api.EnumArrays(just_symbol=">=") + self.assertEqual(fish_or_crab.just_symbol, ">=") + self.assertEqual(fish_or_crab.array_enum, None) + + fish_or_crab = petstore_api.EnumArrays(just_symbol="$", array_enum=["fish"]) + self.assertEqual(fish_or_crab.just_symbol, "$") + self.assertEqual(fish_or_crab.array_enum, ["fish"]) + + fish_or_crab = petstore_api.EnumArrays(just_symbol=">=", array_enum=["fish"]) + self.assertEqual(fish_or_crab.just_symbol, ">=") + self.assertEqual(fish_or_crab.array_enum, ["fish"]) + + fish_or_crab = petstore_api.EnumArrays("$", ["crab"]) + self.assertEqual(fish_or_crab.just_symbol, "$") + self.assertEqual(fish_or_crab.array_enum, ["crab"]) + + + # + # Check if setting invalid values fails + # + try: + fish_or_crab = petstore_api.EnumArrays(just_symbol="<=") + except ValueError: + self.assertEqual(fish_or_crab.just_symbol, None) + self.assertEqual(fish_or_crab.array_enum, None) + + try: + fish_or_crab = petstore_api.EnumArrays(just_symbol="$", array_enum=["dog"]) + except ValueError: + self.assertEqual(fish_or_crab.just_symbol, None) + self.assertEqual(fish_or_crab.array_enum, None) + + + try: + fish_or_crab = petstore_api.EnumArrays(just_symbol=["$"], array_enum=["dog"]) + except ValueError: + self.assertEqual(fish_or_crab.just_symbol, None) + self.assertEqual(fish_or_crab.array_enum, None) + + + def test_enumarrays_setter(self): + + # + # Check various combinations of valid values + # + fish_or_crab = petstore_api.EnumArrays() + + fish_or_crab.just_symbol = ">=" + self.assertEqual(fish_or_crab.just_symbol, ">=") + + fish_or_crab.just_symbol = "$" + self.assertEqual(fish_or_crab.just_symbol, "$") + + fish_or_crab.array_enum = [] + self.assertEqual(fish_or_crab.array_enum, []) + + fish_or_crab.array_enum = ["fish"] + self.assertEqual(fish_or_crab.array_enum, ["fish"]) + + fish_or_crab.array_enum = ["fish", "fish", "fish"] + self.assertEqual(fish_or_crab.array_enum, ["fish", "fish", "fish"]) + + fish_or_crab.array_enum = ["crab"] + self.assertEqual(fish_or_crab.array_enum, ["crab"]) + + fish_or_crab.array_enum = ["crab", "fish"] + self.assertEqual(fish_or_crab.array_enum, ["crab", "fish"]) + + fish_or_crab.array_enum = ["crab", "fish", "crab", "fish"] + self.assertEqual(fish_or_crab.array_enum, ["crab", "fish", "crab", "fish"]) + + # + # Check if setting invalid values fails + # + fish_or_crab = petstore_api.EnumArrays() + try: + fish_or_crab.just_symbol = "!=" + except ValueError: + self.assertEqual(fish_or_crab.just_symbol, None) + + try: + fish_or_crab.just_symbol = ["fish"] + except ValueError: + self.assertEqual(fish_or_crab.just_symbol, None) + + try: + fish_or_crab.array_enum = ["cat"] + except ValueError: + self.assertEqual(fish_or_crab.array_enum, None) + + try: + fish_or_crab.array_enum = ["fish", "crab", "dog"] + except ValueError: + self.assertEqual(fish_or_crab.array_enum, None) + + try: + fish_or_crab.array_enum = "fish" + except ValueError: + self.assertEqual(fish_or_crab.array_enum, None) + + + def test_todict(self): + # + # Check if dictionary serialization works + # + dollar_fish_crab_dict = { + 'just_symbol': "$", + 'array_enum': ["fish", "crab"] + } + + dollar_fish_crab = petstore_api.EnumArrays("$", ["fish", "crab"]) + + self.assertEqual(dollar_fish_crab_dict, dollar_fish_crab.to_dict()) + + # + # Sanity check for different arrays + # + dollar_crab_fish_dict = { + 'just_symbol': "$", + 'array_enum': ["crab", "fish"] + } + + dollar_fish_crab = petstore_api.EnumArrays("$", ["fish", "crab"]) + + self.assertNotEqual(dollar_crab_fish_dict, dollar_fish_crab.to_dict()) + + + def test_equals(self): + # + # Check if object comparison works + # + fish1 = petstore_api.EnumArrays("$", ["fish"]) + fish2 = petstore_api.EnumArrays("$", ["fish"]) + self.assertEqual(fish1, fish2) + + fish = petstore_api.EnumArrays("$", ["fish"]) + crab = petstore_api.EnumArrays("$", ["crab"]) + self.assertNotEqual(fish, crab) + + dollar = petstore_api.EnumArrays("$") + greater = petstore_api.EnumArrays(">=") + self.assertNotEqual(dollar, greater) \ No newline at end of file diff --git a/samples/client/petstore/python/tests/test_map_test.py b/samples/client/petstore/python/tests/test_map_test.py new file mode 100644 index 000000000000..3ed54f93d24c --- /dev/null +++ b/samples/client/petstore/python/tests/test_map_test.py @@ -0,0 +1,106 @@ +# coding: utf-8 + +""" +Run the tests. +$ pip install nose (optional) +$ cd petstore_api-python +$ nosetests -v +""" + +import os +import time +import unittest + +import petstore_api + + +class MapTestTests(unittest.TestCase): + + + def test_maptest_init(self): + # + # Test MapTest construction with valid values + # + up_or_low_dict = { + 'UPPER': "UP", + 'lower': "low" + } + map_enum_test = petstore_api.MapTest(map_of_enum_string=up_or_low_dict) + + self.assertEqual(map_enum_test.map_of_enum_string, up_or_low_dict) + + map_of_map_of_strings = { + 'val1': 1, + 'valText': "Text", + 'valueDict': up_or_low_dict + } + map_enum_test = petstore_api.MapTest(map_map_of_string=map_of_map_of_strings) + + self.assertEqual(map_enum_test.map_map_of_string, map_of_map_of_strings) + + # + # Make sure that the init fails for invalid enum values + # + black_or_white_dict = { + 'black': "UP", + 'white': "low" + } + try: + map_enum_test = petstore_api.MapTest(map_of_enum_string=black_or_white_dict) + except ValueError: + self.assertEqual(map_enum_test, None) + + + def test_maptest_setter(self): + # + # Check with some valid values + # + map_enum_test = petstore_api.MapTest() + up_or_low_dict = { + 'UPPER': "UP", + 'lower': "low" + } + map_enum_test.map_of_enum_string = up_or_low_dict + self.assertEqual(map_enum_test.map_of_enum_string, up_or_low_dict) + + + # + # Check if the setter fails for invalid enum values + # + map_enum_test = petstore_api.MapTest() + black_or_white_dict = { + 'black': "UP", + 'white': "low" + } + try: + map_enum_test.map_of_enum_string = black_or_white_dict + except ValueError: + self.assertEqual(map_enum_test.map_of_enum_string, None) + + + def test_todict(self): + # + # Check dictionary serialization + # + map_enum_test = petstore_api.MapTest() + up_or_low_dict = { + 'UPPER': "UP", + 'lower': "low" + } + map_of_map_of_strings = { + 'val1': 1, + 'valText': "Text", + 'valueDict': up_or_low_dict + } + map_enum_test.map_of_enum_string = up_or_low_dict + map_enum_test.map_map_of_string = map_of_map_of_strings + + self.assertEqual(map_enum_test.map_of_enum_string, up_or_low_dict) + self.assertEqual(map_enum_test.map_map_of_string, map_of_map_of_strings) + + expected_dict = { + 'map_of_enum_string': up_or_low_dict, + 'map_map_of_string': map_of_map_of_strings + } + + self.assertEqual(map_enum_test.to_dict(), expected_dict)