|
26 | 26 | import io.swagger.v3.parser.util.SchemaTypeUtil; |
27 | 27 | import org.openapitools.codegen.*; |
28 | 28 | import org.openapitools.codegen.config.CodegenConfigurator; |
| 29 | +import org.openapitools.codegen.model.ModelMap; |
| 30 | +import org.openapitools.codegen.model.ModelsMap; |
29 | 31 | import org.openapitools.codegen.languages.PythonClientCodegen; |
30 | 32 | import org.openapitools.codegen.languages.features.CXFServerFeatures; |
31 | 33 | import org.testng.Assert; |
|
38 | 40 | import java.nio.file.Paths; |
39 | 41 | import java.util.ArrayList; |
40 | 42 | import java.util.Arrays; |
| 43 | +import java.util.Collections; |
| 44 | +import java.util.HashMap; |
41 | 45 | import java.util.List; |
42 | 46 | import java.util.Map; |
43 | 47 | import java.util.function.Function; |
|
47 | 51 | import static org.junit.jupiter.api.Assertions.assertNull; |
48 | 52 | import static org.openapitools.codegen.TestUtils.assertFileContains; |
49 | 53 | import static org.openapitools.codegen.TestUtils.assertFileExists; |
| 54 | +import static org.openapitools.codegen.TestUtils.assertFileNotContains; |
50 | 55 |
|
51 | 56 | public class PythonClientCodegenTest { |
52 | 57 |
|
@@ -685,4 +690,120 @@ public void testNonPoetry1LicenseFormat() throws IOException { |
685 | 690 | // Verify it does NOT use the legacy string format |
686 | 691 | TestUtils.assertFileNotContains(pyprojectPath, "license = \"BSD-3-Clause\""); |
687 | 692 | } |
| 693 | + |
| 694 | + @Test(description = "test enumUnknownDefaultCase option") |
| 695 | + public void testEnumUnknownDefaultCaseOption() { |
| 696 | + final PythonClientCodegen codegen = new PythonClientCodegen(); |
| 697 | + |
| 698 | + // Test default value is false |
| 699 | + codegen.processOpts(); |
| 700 | + Assert.assertEquals(codegen.getEnumUnknownDefaultCase(), Boolean.FALSE); |
| 701 | + |
| 702 | + // Test setting via additionalProperties |
| 703 | + codegen.additionalProperties().put(CodegenConstants.ENUM_UNKNOWN_DEFAULT_CASE, "true"); |
| 704 | + codegen.processOpts(); |
| 705 | + Assert.assertEquals(codegen.getEnumUnknownDefaultCase(), Boolean.TRUE); |
| 706 | + } |
| 707 | + |
| 708 | + @Test(description = "test enum model generation with enumUnknownDefaultCase") |
| 709 | + public void testEnumModelWithUnknownDefaultCase() { |
| 710 | + final OpenAPI openAPI = TestUtils.parseFlattenSpec("src/test/resources/3_0/enum_unknown_default_case.yaml"); |
| 711 | + final PythonClientCodegen codegen = new PythonClientCodegen(); |
| 712 | + |
| 713 | + // Enable enumUnknownDefaultCase |
| 714 | + codegen.additionalProperties().put(CodegenConstants.ENUM_UNKNOWN_DEFAULT_CASE, "true"); |
| 715 | + codegen.setOpenAPI(openAPI); |
| 716 | + codegen.processOpts(); |
| 717 | + |
| 718 | + // Verify that enumUnknownDefaultCase is set |
| 719 | + Assert.assertEquals(codegen.getEnumUnknownDefaultCase(), Boolean.TRUE); |
| 720 | + |
| 721 | + // Process all models to trigger enum processing |
| 722 | + Map<String, Schema> schemas = openAPI.getComponents().getSchemas(); |
| 723 | + Map<String, ModelsMap> allModels = new HashMap<>(); |
| 724 | + for (String modelName : schemas.keySet()) { |
| 725 | + Schema schema = schemas.get(modelName); |
| 726 | + CodegenModel cm = codegen.fromModel(modelName, schema); |
| 727 | + ModelsMap modelsMap = new ModelsMap(); |
| 728 | + modelsMap.setModels(Collections.singletonList(new ModelMap(Collections.singletonMap("model", cm)))); |
| 729 | + allModels.put(modelName, modelsMap); |
| 730 | + } |
| 731 | + |
| 732 | + // Post-process to add enumVars |
| 733 | + allModels = codegen.postProcessAllModels(allModels); |
| 734 | + |
| 735 | + // Get the ColorEnum model |
| 736 | + CodegenModel colorEnum = null; |
| 737 | + for (Map.Entry<String, ModelsMap> entry : allModels.entrySet()) { |
| 738 | + if ("ColorEnum".equals(entry.getKey())) { |
| 739 | + colorEnum = entry.getValue().getModels().get(0).getModel(); |
| 740 | + break; |
| 741 | + } |
| 742 | + } |
| 743 | + |
| 744 | + Assert.assertNotNull(colorEnum); |
| 745 | + Assert.assertNotNull(colorEnum.allowableValues); |
| 746 | + |
| 747 | + List<Map<String, Object>> enumVars = (List<Map<String, Object>>) colorEnum.allowableValues.get("enumVars"); |
| 748 | + Assert.assertNotNull(enumVars); |
| 749 | + |
| 750 | + // Check that we have the expected enum values including UNKNOWN_DEFAULT_OPEN_API |
| 751 | + Assert.assertTrue(enumVars.stream().anyMatch(var -> "'RED'".equals(var.get("value")))); |
| 752 | + Assert.assertTrue(enumVars.stream().anyMatch(var -> "'GREEN'".equals(var.get("value")))); |
| 753 | + Assert.assertTrue(enumVars.stream().anyMatch(var -> "'BLUE'".equals(var.get("value")))); |
| 754 | + Assert.assertTrue(enumVars.stream().anyMatch(var -> "'YELLOW'".equals(var.get("value")))); |
| 755 | + Assert.assertTrue(enumVars.stream().anyMatch(var -> "'unknown_default_open_api'".equals(var.get("value")))); |
| 756 | + } |
| 757 | + |
| 758 | + @Test(description = "test enum generation with enumUnknownDefaultCase enabled") |
| 759 | + public void testEnumGenerationWithUnknownDefaultCase() throws IOException { |
| 760 | + File output = Files.createTempDirectory("test").toFile().getCanonicalFile(); |
| 761 | + output.deleteOnExit(); |
| 762 | + String outputPath = output.getAbsolutePath().replace('\\', '/'); |
| 763 | + |
| 764 | + final CodegenConfigurator configurator = new CodegenConfigurator() |
| 765 | + .setGeneratorName("python") |
| 766 | + .setInputSpec("src/test/resources/3_0/enum_unknown_default_case.yaml") |
| 767 | + .setOutputDir(outputPath) |
| 768 | + .addAdditionalProperty(CodegenConstants.ENUM_UNKNOWN_DEFAULT_CASE, "true"); |
| 769 | + |
| 770 | + DefaultGenerator generator = new DefaultGenerator(); |
| 771 | + List<File> files = generator.opts(configurator.toClientOptInput()).generate(); |
| 772 | + files.forEach(File::deleteOnExit); |
| 773 | + |
| 774 | + Path enumFile = Paths.get(outputPath, "openapi_client", "models", "color_enum.py"); |
| 775 | + |
| 776 | + // Check that UNKNOWN_DEFAULT_OPEN_API is added (with single quotes as Python generates) |
| 777 | + TestUtils.assertFileContains(enumFile, "UNKNOWN_DEFAULT_OPEN_API = 'unknown_default_open_api'"); |
| 778 | + |
| 779 | + // Check that _missing_ method is added |
| 780 | + TestUtils.assertFileContains(enumFile, "@classmethod"); |
| 781 | + TestUtils.assertFileContains(enumFile, "def _missing_(cls, value):"); |
| 782 | + TestUtils.assertFileContains(enumFile, "return cls.UNKNOWN_DEFAULT_OPEN_API"); |
| 783 | + } |
| 784 | + |
| 785 | + @Test(description = "test enum generation with enumUnknownDefaultCase disabled") |
| 786 | + public void testEnumGenerationWithoutUnknownDefaultCase() throws IOException { |
| 787 | + File output = Files.createTempDirectory("test").toFile().getCanonicalFile(); |
| 788 | + output.deleteOnExit(); |
| 789 | + String outputPath = output.getAbsolutePath().replace('\\', '/'); |
| 790 | + |
| 791 | + final CodegenConfigurator configurator = new CodegenConfigurator() |
| 792 | + .setGeneratorName("python") |
| 793 | + .setInputSpec("src/test/resources/3_0/enum_unknown_default_case.yaml") |
| 794 | + .setOutputDir(outputPath) |
| 795 | + .addAdditionalProperty(CodegenConstants.ENUM_UNKNOWN_DEFAULT_CASE, "false"); |
| 796 | + |
| 797 | + DefaultGenerator generator = new DefaultGenerator(); |
| 798 | + List<File> files = generator.opts(configurator.toClientOptInput()).generate(); |
| 799 | + files.forEach(File::deleteOnExit); |
| 800 | + |
| 801 | + Path enumFile = Paths.get(outputPath, "openapi_client", "models", "color_enum.py"); |
| 802 | + |
| 803 | + // Check that UNKNOWN_DEFAULT_OPEN_API is NOT added |
| 804 | + TestUtils.assertFileNotContains(enumFile, "UNKNOWN_DEFAULT_OPEN_API"); |
| 805 | + |
| 806 | + // Check that _missing_ method is NOT added |
| 807 | + TestUtils.assertFileNotContains(enumFile, "def _missing_(cls, value):"); |
| 808 | + } |
688 | 809 | } |
0 commit comments