Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/main/resources/handlebars/python/model.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -129,10 +129,10 @@ class {{classname}}({{#parent}}{{parent}}{{/parent}}{{^parent}}object{{/parent}}
)
{{/isListContainer}}
{{#isMapContainer}}
if not set({{{name}}}.keys()).issubset(set(allowed_values)):
if not set({{{name}}}.values()).issubset(set(allowed_values)):
raise ValueError(
"Invalid keys in `{{{name}}}` [{0}], must be a subset of [{1}]" # noqa: E501
.format(", ".join(map(str, set({{{name}}}.keys()) - set(allowed_values))), # noqa: E501
"Invalid values in `{{{name}}}` [{0}], must be a subset of [{1}]" # noqa: E501
.format(", ".join(map(str, set({{{name}}}.values()) - set(allowed_values))), # noqa: E501
", ".join(map(str, allowed_values)))
)
{{/isMapContainer}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,10 +99,10 @@ class {{classname}}(Model):
)
{{/isListContainer}}
{{#isMapContainer}}
if not set({{{name}}}.keys()).issubset(set(allowed_values)):
if not set({{{name}}}.values()).issubset(set(allowed_values)):
raise ValueError(
"Invalid keys in `{{{name}}}` [{0}], must be a subset of [{1}]" # noqa: E501
.format(", ".join(map(str, set({{{name}}}.keys()) - set(allowed_values))), # noqa: E501
"Invalid values in `{{{name}}}` [{0}], must be a subset of [{1}]" # noqa: E501
.format(", ".join(map(str, set({{{name}}}.values()) - set(allowed_values))), # noqa: E501
", ".join(map(str, allowed_values)))
)
{{/isMapContainer}}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package io.swagger.codegen.v3.generators.python;

import io.swagger.codegen.v3.generators.GeneratorRunner;
import io.swagger.codegen.v3.service.GenerationRequest;
import org.testng.Assert;
import org.testng.annotations.Test;

import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;

/**
* Regression test for the Python generator `Map<String, Enum>` setter validation.
*
* <p>The {@code model.mustache} template used to emit
* {@code set(x.keys()).issubset(allowed_values)} for properties declared as
* {@code type: object} with {@code additionalProperties.enum}. Per OpenAPI 3.0
* semantics, {@code additionalProperties} describes map values, so the enum
* constraint applies to the values, not the keys. The fix validates
* {@code set(x.values()).issubset(allowed_values)} and updates the error message
* from "Invalid keys in" to "Invalid values in".
*/
public class PythonMapEnumValidationTest {

@Test
public void mapOfEnumSetterValidatesValuesNotKeys() throws Exception {
final List<File> files = GeneratorRunner.runGenerator(
"python",
"3_0_0/map_of_inner_enum.yaml",
GenerationRequest.CodegenVersion.V3,
false,
true,
true,
null,
options -> {});

Assert.assertFalse(files.isEmpty());

final File modelFile = files.stream()
.filter(f -> f.getName().equals("employee_with_map_of_enum.py"))
.findFirst()
.orElseThrow(() -> new RuntimeException("employee_with_map_of_enum.py was not generated"));

final String content = new String(Files.readAllBytes(Paths.get(modelFile.toURI())));

Assert.assertTrue(
content.contains("set(project_role.values()).issubset(set(allowed_values))"),
"Setter should validate map values (not keys) against the enum.\nGenerated:\n" + content);
Assert.assertTrue(
content.contains("Invalid values in `project_role`"),
"Setter error message should reference 'Invalid values in'.\nGenerated:\n" + content);
Assert.assertFalse(
content.contains("set(project_role.keys()).issubset(set(allowed_values))"),
"Setter must not validate map keys against the enum.\nGenerated:\n" + content);
Assert.assertFalse(
content.contains("Invalid keys in `project_role`"),
"Setter error message must not reference 'Invalid keys in'.\nGenerated:\n" + content);
}
}