|
1 | | - |
2 | | -from typing import Any |
3 | 1 | import pytest |
4 | 2 | from end_to_end_tests.end_to_end_test_helpers import ( |
5 | | - assert_bad_schema_warning, |
6 | 3 | assert_model_decode_encode, |
7 | | - inline_spec_should_cause_warnings, |
8 | | - inline_spec_should_fail, |
9 | 4 | with_generated_code_import, |
10 | 5 | with_generated_client_fixture, |
11 | 6 | with_generated_code_imports, |
@@ -133,52 +128,89 @@ def test_invalid_int(self, MyModel): |
133 | 128 | MyModel.from_dict({"mustBeThirty": 29}) |
134 | 129 |
|
135 | 130 |
|
136 | | -class TestEnumAndConstInvalidSchemas: |
137 | | - @pytest.fixture(scope="class") |
138 | | - def warnings(self): |
139 | | - return inline_spec_should_cause_warnings( |
| 131 | +# The following tests of literal enums use basically the same specs as the tests above, but |
| 132 | +# the "literal_enums" option is enabled in the test configuration. |
| 133 | + |
| 134 | +@with_generated_client_fixture( |
140 | 135 | """ |
141 | 136 | components: |
142 | 137 | schemas: |
143 | | - WithBadDefaultValue: |
144 | | - enum: ["A"] |
145 | | - default: "B" |
146 | | - WithBadDefaultType: |
147 | | - enum: ["A"] |
148 | | - default: 123 |
149 | | - WithMixedTypes: |
150 | | - enum: ["A", 1] |
151 | | - WithUnsupportedType: |
152 | | - enum: [1.4, 1.5] |
153 | | - DefaultNotMatchingConst: |
154 | | - const: "aaa" |
155 | | - default: "bbb" |
156 | | -""" |
157 | | - ) |
158 | | - |
159 | | - def test_enum_bad_default_value(self, warnings): |
160 | | - assert_bad_schema_warning(warnings, "WithBadDefaultValue", "Value B is not valid") |
161 | | - |
162 | | - def test_enum_bad_default_type(self, warnings): |
163 | | - assert_bad_schema_warning(warnings, "WithBadDefaultType", "Cannot convert 123 to enum") |
164 | | - |
165 | | - def test_enum_mixed_types(self, warnings): |
166 | | - assert_bad_schema_warning(warnings, "WithMixedTypes", "Enum values must all be the same type") |
| 138 | + MyEnum: |
| 139 | + type: string |
| 140 | + enum: ["a", "A"] |
| 141 | + MyIntEnum: |
| 142 | + type: integer |
| 143 | + enum: [2, 3] |
| 144 | + MyEnumIncludingNull: |
| 145 | + type: ["string", "null"] |
| 146 | + enum: ["a", "b", null] |
| 147 | + MyNullOnlyEnum: |
| 148 | + enum: [null] |
| 149 | + MyModel: |
| 150 | + properties: |
| 151 | + enumProp: {"$ref": "#/components/schemas/MyEnum"} |
| 152 | + intEnumProp: {"$ref": "#/components/schemas/MyIntEnum"} |
| 153 | + nullableEnumProp: |
| 154 | + oneOf: |
| 155 | + - {"$ref": "#/components/schemas/MyEnum"} |
| 156 | + - type: "null" |
| 157 | + enumIncludingNullProp: {"$ref": "#/components/schemas/MyEnumIncludingNull"} |
| 158 | + nullOnlyEnumProp: {"$ref": "#/components/schemas/MyNullOnlyEnum"} |
| 159 | + inlineEnumProp: |
| 160 | + type: string |
| 161 | + enum: ["a", "b"] |
| 162 | +""", |
| 163 | + config=""" |
| 164 | +literal_enums: true |
| 165 | +""", |
| 166 | +) |
| 167 | +@with_generated_code_import(".models.MyModel") |
| 168 | +class TestLiteralEnums: |
| 169 | + def test_enum_prop(self, MyModel): |
| 170 | + assert_model_decode_encode(MyModel, {"enumProp": "a"}, MyModel(enum_prop="a")) |
| 171 | + assert_model_decode_encode(MyModel, {"enumProp": "A"}, MyModel(enum_prop="A")) |
| 172 | + assert_model_decode_encode(MyModel, {"intEnumProp": 2}, MyModel(int_enum_prop=2)) |
| 173 | + assert_model_decode_encode(MyModel, {"inlineEnumProp": "a"}, MyModel(inline_enum_prop="a")) |
| 174 | + |
| 175 | + def test_enum_prop_type(self, MyModel): |
| 176 | + assert MyModel.from_dict({"enumProp": "a"}).enum_prop.__class__ is str |
| 177 | + assert MyModel.from_dict({"intEnumProp": 2}).int_enum_prop.__class__ is int |
| 178 | + |
| 179 | + def test_nullable_enum_prop(self, MyModel): |
| 180 | + assert_model_decode_encode(MyModel, {"nullableEnumProp": "B"}, MyModel(nullable_enum_prop="B")) |
| 181 | + assert_model_decode_encode(MyModel, {"nullableEnumProp": None}, MyModel(nullable_enum_prop=None)) |
| 182 | + assert_model_decode_encode(MyModel, {"enumIncludingNullProp": "a"}, MyModel(enum_including_null_prop="a")) |
| 183 | + assert_model_decode_encode(MyModel, {"enumIncludingNullProp": None}, MyModel(enum_including_null_prop=None)) |
| 184 | + assert_model_decode_encode(MyModel, {"nullOnlyEnumProp": None}, MyModel(null_only_enum_prop=None)) |
167 | 185 |
|
168 | | - def test_enum_unsupported_type(self, warnings): |
169 | | - assert_bad_schema_warning(warnings, "WithUnsupportedType", "Unsupported enum type") |
| 186 | + def test_invalid_values(self, MyModel): |
| 187 | + with pytest.raises(TypeError): |
| 188 | + MyModel.from_dict({"enumProp": "c"}) |
| 189 | + with pytest.raises(TypeError): |
| 190 | + MyModel.from_dict({"enumProp": 2}) |
| 191 | + with pytest.raises(TypeError): |
| 192 | + MyModel.from_dict({"intEnumProp": 0}) |
| 193 | + with pytest.raises(TypeError): |
| 194 | + MyModel.from_dict({"intEnumProp": "a"}) |
170 | 195 |
|
171 | | - def test_const_default_not_matching(self, warnings): |
172 | | - assert_bad_schema_warning(warnings, "DefaultNotMatchingConst", "Invalid value for const") |
173 | 196 |
|
174 | | - def test_enum_duplicate_values(self): |
175 | | - # This one currently causes a full generator failure rather than a warning |
176 | | - result = inline_spec_should_fail( |
| 197 | +@with_generated_client_fixture( |
177 | 198 | """ |
178 | 199 | components: |
179 | 200 | schemas: |
180 | | - WithDuplicateValues: |
181 | | - enum: ["x", "x"] |
182 | | -""" |
183 | | - ) |
184 | | - assert "Duplicate key X in enum" in str(result.exception) |
| 201 | + MyEnum: |
| 202 | + type: string |
| 203 | + enum: ["a", "A"] |
| 204 | + MyModel: |
| 205 | + properties: |
| 206 | + enumProp: |
| 207 | + allOf: |
| 208 | + - $ref: "#/components/schemas/MyEnum" |
| 209 | + default: A |
| 210 | +""", |
| 211 | + config="literal_enums: true", |
| 212 | +) |
| 213 | +@with_generated_code_import(".models.MyModel") |
| 214 | +class TestLiteralEnumDefaults: |
| 215 | + def test_default_value(self, MyModel): |
| 216 | + assert MyModel().enum_prop == "A" |
0 commit comments