Skip to content

Commit

Permalink
Bugfix StackOverflow Crash in Swift5 Code Generation (OpenAPITools#2966)
Browse files Browse the repository at this point in the history
  • Loading branch information
Donkov76 committed Aug 26, 2020
1 parent 98582d5 commit 3fe75f1
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1002,15 +1002,15 @@ public Map<String, Object> postProcessOperationsWithModels(Map<String, Object> o
List<CodegenOperation> operations = (List<CodegenOperation>) objectMap.get("operation");
for (CodegenOperation operation : operations) {
for (CodegenParameter cp : operation.allParams) {
cp.vendorExtensions.put("x-swift-example", constructExampleCode(cp, modelMaps));
cp.vendorExtensions.put("x-swift-example", constructExampleCode(cp, modelMaps, new ExampleCodeGenerationContext()));
}
}
return objs;
}

public String constructExampleCode(CodegenParameter codegenParameter, HashMap<String, CodegenModel> modelMaps) {
public String constructExampleCode(CodegenParameter codegenParameter, HashMap<String, CodegenModel> modelMaps, ExampleCodeGenerationContext context) {
if (codegenParameter.isListContainer) { // array
return "[" + constructExampleCode(codegenParameter.items, modelMaps) + "]";
return "[" + constructExampleCode(codegenParameter.items, modelMaps, context) + "]";
} else if (codegenParameter.isMapContainer) { // TODO: map, file type
return "\"TODO\"";
} else if (languageSpecificPrimitives.contains(codegenParameter.dataType)) { // primitive type
Expand Down Expand Up @@ -1040,17 +1040,17 @@ public String constructExampleCode(CodegenParameter codegenParameter, HashMap<St
} else { // model
// look up the model
if (modelMaps.containsKey(codegenParameter.dataType)) {
return constructExampleCode(modelMaps.get(codegenParameter.dataType), modelMaps);
return constructExampleCode(modelMaps.get(codegenParameter.dataType), modelMaps, context);
} else {
//LOGGER.error("Error in constructing examples. Failed to look up the model " + codegenParameter.dataType);
return "TODO";
}
}
}

public String constructExampleCode(CodegenProperty codegenProperty, HashMap<String, CodegenModel> modelMaps) {
private String constructExampleCode(CodegenProperty codegenProperty, HashMap<String, CodegenModel> modelMaps, ExampleCodeGenerationContext context) {
if (codegenProperty.isListContainer) { // array
return "[" + constructExampleCode(codegenProperty.items, modelMaps) + "]";
return "[" + constructExampleCode(codegenProperty.items, modelMaps, context) + "]";
} else if (codegenProperty.isMapContainer) { // TODO: map, file type
return "\"TODO\"";
} else if (languageSpecificPrimitives.contains(codegenProperty.dataType)) { // primitive type
Expand Down Expand Up @@ -1080,23 +1080,59 @@ public String constructExampleCode(CodegenProperty codegenProperty, HashMap<Stri
} else {
// look up the model
if (modelMaps.containsKey(codegenProperty.dataType)) {
return constructExampleCode(modelMaps.get(codegenProperty.dataType), modelMaps);
return constructExampleCode(modelMaps.get(codegenProperty.dataType), modelMaps, context);
} else {
//LOGGER.error("Error in constructing examples. Failed to look up the model " + codegenProperty.dataType);
return "\"TODO\"";
}
}
}

public String constructExampleCode(CodegenModel codegenModel, HashMap<String, CodegenModel> modelMaps) {
String example;
example = codegenModel.name + "(";
List<String> propertyExamples = new ArrayList<>();
for (CodegenProperty codegenProperty : codegenModel.vars) {
propertyExamples.add(codegenProperty.name + ": " + constructExampleCode(codegenProperty, modelMaps));
private String constructExampleCode(CodegenModel codegenModel, HashMap<String, CodegenModel> modelMaps, ExampleCodeGenerationContext context) {
if (context.isTypeVisted(codegenModel.dataType)) {
String exampleCode = context.getExampleCode(codegenModel.dataType);
if (exampleCode != null) {
// Reuse already generated exampleCode
return exampleCode;
} else {
// Visited but no Example Code. Circuit Breaker --> No StackOverflow
return "{...}";
}
} else {
context.visitType(codegenModel.dataType);
String example = codegenModel.name + "(";
List<String> propertyExamples = new ArrayList<>();
for (CodegenProperty codegenProperty : codegenModel.vars) {
String propertyExample = constructExampleCode(codegenProperty, modelMaps, context);
propertyExamples.add(codegenProperty.name + ": " + propertyExample);
}
example += StringUtils.join(propertyExamples, ", ");
example += ")";

context.setExampleCode(codegenModel.dataType, example);
return example;
}
example += StringUtils.join(propertyExamples, ", ");
example += ")";
return example;
}

private static class ExampleCodeGenerationContext {

private Map<String, String> modelExampleCode = new HashMap<>();

public boolean isTypeVisted(String type) {
return modelExampleCode.containsKey(type);
}

public void visitType(String type) {
modelExampleCode.put(type, null);
}

public void setExampleCode(String type, String code) {
modelExampleCode.put(type, code);
}

public String getExampleCode(String type) {
return modelExampleCode.get(type);
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,21 @@
import org.openapitools.codegen.CodegenOperation;
import org.openapitools.codegen.DefaultCodegen;
import org.openapitools.codegen.TestUtils;
import org.openapitools.codegen.*;
import org.openapitools.codegen.config.CodegenConfigurator;
import org.openapitools.codegen.languages.Swift5ClientCodegen;
import org.testng.Assert;
import org.testng.annotations.Test;

import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.Arrays;
import java.util.List;


public class Swift5ClientCodegenTest {

Expand Down Expand Up @@ -118,6 +129,38 @@ public void dateTest() {
Assert.assertEquals(op.bodyParam.dataType, "Date");
}

@Test(description = "Bug onvista", enabled = true)
public void crashSwift5ExampleCodeGenerationStackOverflowTest() throws IOException {
//final OpenAPI openAPI = TestUtils.parseFlattenSpec("src/test/resources/bugs/Swift5CodeGenerationStackOverflow#2966.yaml");
Path target = Files.createTempDirectory("test");
File output = target.toFile();
try {
final CodegenConfigurator configurator = new CodegenConfigurator()
.setGeneratorName("swift5")
.setValidateSpec(false)
.setInputSpec("src/test/resources/bugs/Swift5CodeGenerationStackOverflow#2966.yaml")
.setEnablePostProcessFile(true)
.setOutputDir(target.toAbsolutePath().toString());

final ClientOptInput clientOptInput = configurator.toClientOptInput();
DefaultGenerator generator = new DefaultGenerator(false);

generator.setGeneratorPropertyDefault(CodegenConstants.MODELS, "true");
generator.setGeneratorPropertyDefault(CodegenConstants.MODEL_TESTS, "true");
generator.setGeneratorPropertyDefault(CodegenConstants.MODEL_DOCS, "true");
generator.setGeneratorPropertyDefault(CodegenConstants.APIS, "true");
generator.setGeneratorPropertyDefault(CodegenConstants.SUPPORTING_FILES, "true");
generator.setGeneratorPropertyDefault(CodegenConstants.API_DOCS, "true");
generator.setGeneratorPropertyDefault(CodegenConstants.ENABLE_POST_PROCESS_FILE, "true");

List<File> files = generator.opts(clientOptInput).generate();
Assert.assertTrue(files.size() > 0, "No files generated");
} finally {
output.delete();
}
}


@Test(enabled = true)
public void testDefaultPodAuthors() throws Exception {
// Given
Expand Down

0 comments on commit 3fe75f1

Please sign in to comment.