Merge branch 'add_go_generator' into oas3_support2

This commit is contained in:
wing328 2018-03-28 15:42:58 +08:00
commit f54b78f4bb
7 changed files with 1190 additions and 0 deletions

View File

@ -0,0 +1,477 @@
package org.openapitools.codegen.languages;
import org.openapitools.codegen.*;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.Operation;
import io.swagger.v3.oas.models.media.*;
import io.swagger.v3.core.util.Yaml;
import java.util.*;
import org.apache.commons.lang3.StringUtils;
import com.fasterxml.jackson.core.JsonProcessingException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public abstract class AbstractGoCodegen extends DefaultCodegen implements CodegenConfig {
protected static Logger LOGGER = LoggerFactory.getLogger(AbstractGoCodegen.class);
protected boolean withXml = false;
protected String packageName = "swagger";
public AbstractGoCodegen() {
super();
defaultIncludes = new HashSet<String>(
Arrays.asList(
"map",
"array")
);
languageSpecificPrimitives = new HashSet<String>(
Arrays.asList(
"string",
"bool",
"uint",
"uint32",
"uint64",
"int",
"int32",
"int64",
"float32",
"float64",
"complex64",
"complex128",
"rune",
"byte")
);
instantiationTypes.clear();
/*instantiationTypes.put("array", "GoArray");
instantiationTypes.put("map", "GoMap");*/
typeMapping.clear();
typeMapping.put("integer", "int32");
typeMapping.put("long", "int64");
typeMapping.put("number", "float32");
typeMapping.put("float", "float32");
typeMapping.put("double", "float64");
typeMapping.put("boolean", "bool");
typeMapping.put("string", "string");
typeMapping.put("UUID", "string");
typeMapping.put("date", "string");
typeMapping.put("DateTime", "time.Time");
typeMapping.put("password", "string");
typeMapping.put("File", "*os.File");
typeMapping.put("file", "*os.File");
// map binary to string as a workaround
// the correct solution is to use []byte
typeMapping.put("binary", "string");
typeMapping.put("ByteArray", "string");
typeMapping.put("object", "interface{}");
typeMapping.put("UUID", "string");
importMapping = new HashMap<String, String>();
importMapping.put("time.Time", "time");
importMapping.put("*os.File", "os");
cliOptions.clear();
cliOptions.add(new CliOption(CodegenConstants.PACKAGE_NAME, "Go package name (convention: lowercase).")
.defaultValue("swagger"));
cliOptions.add(new CliOption(CodegenConstants.HIDE_GENERATION_TIMESTAMP, "hides the timestamp when files were generated")
.defaultValue(Boolean.TRUE.toString()));
}
/**
* Escapes a reserved word as defined in the `reservedWords` array. Handle escaping
* those terms here. This logic is only called if a variable matches the reserved words
*
* @return the escaped term
*/
@Override
public String escapeReservedWord(String name)
{
// Can't start with an underscore, as our fields need to start with an
// UppercaseLetter so that Go treats them as public/visible.
// Options?
// - MyName
// - AName
// - TheName
// - XName
// - X_Name
// ... or maybe a suffix?
// - Name_ ... think this will work.
if(this.reservedWordsMappings().containsKey(name)) {
return this.reservedWordsMappings().get(name);
}
return camelize(name) + '_';
}
@Override
public String toVarName(String name) {
// replace - with _ e.g. created-at => created_at
name = sanitizeName(name.replaceAll("-", "_"));
// if it's all uppper case, do nothing
if (name.matches("^[A-Z_]*$"))
return name;
// camelize (lower first character) the variable name
// pet_id => PetId
name = camelize(name);
// for reserved word or word starting with number, append _
if (isReservedWord(name))
name = escapeReservedWord(name);
// for reserved word or word starting with number, append _
if (name.matches("^\\d.*"))
name = "Var" + name;
return name;
}
@Override
public String toParamName(String name) {
// params should be lowerCamelCase. E.g. "person Person", instead of
// "Person Person".
//
// REVISIT: Actually, for idiomatic go, the param name should
// really should just be a letter, e.g. "p Person"), but we'll get
// around to that some other time... Maybe.
return camelize(toVarName(name), true);
}
@Override
public String toModelName(String name) {
// camelize the model name
// phone_number => PhoneNumber
return camelize(toModel(name));
}
@Override
public String toModelFilename(String name) {
return toModel("model_" + name);
}
public String toModel(String name) {
if (!StringUtils.isEmpty(modelNamePrefix)) {
name = modelNamePrefix + "_" + name;
}
if (!StringUtils.isEmpty(modelNameSuffix)) {
name = name + "_" + modelNameSuffix;
}
name = sanitizeName(name);
// model name cannot use reserved keyword, e.g. return
if (isReservedWord(name)) {
LOGGER.warn(name + " (reserved word) cannot be used as model name. Renamed to " + ("model_" + name));
name = "model_" + name; // e.g. return => ModelReturn (after camelize)
}
// model name starts with number
if (name.matches("^\\d.*")) {
LOGGER.warn(name + " (model name starts with number) cannot be used as model name. Renamed to " + ("model_" + name));
name = "model_" + name; // e.g. 200Response => Model200Response (after camelize)
}
return underscore(name);
}
@Override
public String toApiFilename(String name) {
// replace - with _ e.g. created-at => created_at
name = name.replaceAll("-", "_"); // FIXME: a parameter should not be assigned. Also declare the methods parameters as 'final'.
// e.g. PetApi.go => pet_api.go
return "api_" + underscore(name);
}
/**
* Overrides postProcessParameter to add a vendor extension "x-exportParamName".
* This is useful when paramName starts with a lowercase letter, but we need that
* param to be exportable (starts with an Uppercase letter).
*
* @param parameter CodegenParameter object to be processed.
*/
@Override
public void postProcessParameter(CodegenParameter parameter){
// Give the base class a chance to process
super.postProcessParameter(parameter);
char firstChar = parameter.paramName.charAt(0);
if (Character.isUpperCase(firstChar)) {
// First char is already uppercase, just use paramName.
parameter.vendorExtensions.put("x-exportParamName", parameter.paramName);
}
// It's a lowercase first char, let's convert it to uppercase
StringBuilder sb = new StringBuilder(parameter.paramName);
sb.setCharAt(0, Character.toUpperCase(firstChar));
parameter.vendorExtensions.put("x-exportParamName", sb.toString());
}
@Override
public String getTypeDeclaration(Schema p) {
if(p instanceof ArraySchema) {
ArraySchema ap = (ArraySchema) p;
Schema inner = ap.getItems();
return "[]" + getTypeDeclaration(inner);
}
else if (p instanceof MapSchema) {
MapSchema mp = (MapSchema) p;
Schema inner = (Schema) mp.getAdditionalProperties();
return getSchemaType(p) + "[string]" + getTypeDeclaration(inner);
}
//return super.getTypeDeclaration(p);
// Not using the supertype invocation, because we want to UpperCamelize
// the type.
String openAPIType = getSchemaType(p);
if (typeMapping.containsKey(openAPIType)) {
return typeMapping.get(openAPIType);
}
if(typeMapping.containsValue(openAPIType)) {
return openAPIType;
}
if(languageSpecificPrimitives.contains(openAPIType)) {
return openAPIType;
}
return toModelName(openAPIType);
}
@Override
public String getSchemaType(Schema p) {
String openAPIType = super.getSchemaType(p);
String type = null;
if(typeMapping.containsKey(openAPIType)) {
type = typeMapping.get(openAPIType);
if(languageSpecificPrimitives.contains(type))
return (type);
}
else
type = openAPIType;
return type;
}
@Override
public String toOperationId(String operationId) {
String sanitizedOperationId = sanitizeName(operationId);
// method name cannot use reserved keyword, e.g. return
if (isReservedWord(sanitizedOperationId)) {
LOGGER.warn(operationId + " (reserved word) cannot be used as method name. Renamed to " + camelize("call_" + operationId));
sanitizedOperationId = "call_" + sanitizedOperationId;
}
return camelize(sanitizedOperationId);
}
@Override
public Map<String, Object> postProcessOperations(Map<String, Object> objs) {
@SuppressWarnings("unchecked")
Map<String, Object> objectMap = (Map<String, Object>) objs.get("operations");
@SuppressWarnings("unchecked")
List<CodegenOperation> operations = (List<CodegenOperation>) objectMap.get("operation");
for (CodegenOperation operation : operations) {
// http method verb conversion (e.g. PUT => Put)
operation.httpMethod = camelize(operation.httpMethod.toLowerCase());
}
// remove model imports to avoid error
List<Map<String, String>> imports = (List<Map<String, String>>) objs.get("imports");
if (imports == null)
return objs;
Iterator<Map<String, String>> iterator = imports.iterator();
while (iterator.hasNext()) {
String _import = iterator.next().get("import");
if (_import.startsWith(apiPackage()))
iterator.remove();
}
// if their is a return type, import encoding/json and if needed encoding/xml
for (CodegenOperation operation : operations) {
if(operation.returnBaseType != null ) {
imports.add(createMapping("import", "encoding/json"));
if (withXml)
imports.add(createMapping("import", "encoding/xml"));
break; //just need to import once
}
}
// this will only import "fmt" if there are items in pathParams
for (CodegenOperation operation : operations) {
if(operation.pathParams != null && operation.pathParams.size() > 0) {
imports.add(createMapping("import", "fmt"));
break; //just need to import once
}
}
// recursively add import for mapping one type to multiple imports
List<Map<String, String>> recursiveImports = (List<Map<String, String>>) objs.get("imports");
if (recursiveImports == null)
return objs;
ListIterator<Map<String, String>> listIterator = imports.listIterator();
while (listIterator.hasNext()) {
String _import = listIterator.next().get("import");
// if the import package happens to be found in the importMapping (key)
// add the corresponding import package to the list
if (importMapping.containsKey(_import)) {
listIterator.add(createMapping("import", importMapping.get(_import)));
}
}
return objs;
}
@Override
public Map<String, Object> postProcessModels(Map<String, Object> objs) {
// remove model imports to avoid error
List<Map<String, String>> imports = (List<Map<String, String>>) objs.get("imports");
final String prefix = modelPackage();
Iterator<Map<String, String>> iterator = imports.iterator();
while (iterator.hasNext()) {
String _import = iterator.next().get("import");
if (_import.startsWith(prefix))
iterator.remove();
}
// recursively add import for mapping one type to multiple imports
List<Map<String, String>> recursiveImports = (List<Map<String, String>>) objs.get("imports");
if (recursiveImports == null)
return objs;
ListIterator<Map<String, String>> listIterator = imports.listIterator();
while (listIterator.hasNext()) {
String _import = listIterator.next().get("import");
// if the import package happens to be found in the importMapping (key)
// add the corresponding import package to the list
if (importMapping.containsKey(_import)) {
listIterator.add(createMapping("import", importMapping.get(_import)));
}
}
return postProcessModelsEnum(objs);
}
@Override
public Map<String, Object> postProcessSupportingFileData(Map<String, Object> objs) {
OpenAPI openAPI = (OpenAPI) objs.get("openapi");
if (openAPI != null) {
try {
objs.put("swagger-yaml", Yaml.mapper().writeValueAsString(openAPI));
} catch (JsonProcessingException e) {
LOGGER.error(e.getMessage(), e);
}
}
return super.postProcessSupportingFileData(objs);
}
@Override
protected boolean needToImport(String type) {
return !defaultIncludes.contains(type)
&& !languageSpecificPrimitives.contains(type);
}
public void setPackageName(String packageName) {
this.packageName = packageName;
}
@Override
public String escapeQuotationMark(String input) {
// remove " to avoid code injection
return input.replace("\"", "");
}
@Override
public String escapeUnsafeCharacters(String input) {
return input.replace("*/", "*_/").replace("/*", "/_*");
}
public Map<String, String> createMapping(String key, String value){
Map<String, String> customImport = new HashMap<String, String>();
customImport.put(key, value);
return customImport;
}
@Override
public String toEnumValue(String value, String datatype) {
if ("int".equals(datatype) || "double".equals(datatype) || "float".equals(datatype)) {
return value;
} else {
return escapeText(value);
}
}
@Override
public String toEnumDefaultValue(String value, String datatype) {
return datatype + "_" + value;
}
@Override
public String toEnumVarName(String name, String datatype) {
if (name.length() == 0) {
return "EMPTY";
}
// number
if ("int".equals(datatype) || "double".equals(datatype) || "float".equals(datatype)) {
String varName = name;
varName = varName.replaceAll("-", "MINUS_");
varName = varName.replaceAll("\\+", "PLUS_");
varName = varName.replaceAll("\\.", "_DOT_");
return varName;
}
// for symbol, e.g. $, #
if (getSymbolName(name) != null) {
return getSymbolName(name).toUpperCase();
}
// string
String enumName = sanitizeName(underscore(name).toUpperCase());
enumName = enumName.replaceFirst("^_", "");
enumName = enumName.replaceFirst("_$", "");
if (isReservedWord(enumName) || enumName.matches("\\d.*")) { // reserved word or starts with number
return escapeReservedWord(enumName);
} else {
return enumName;
}
}
@Override
public String toEnumName(CodegenProperty property) {
String enumName = underscore(toModelName(property.name)).toUpperCase();
// remove [] for array or map of enum
enumName = enumName.replace("[]", "");
if (enumName.matches("\\d.*")) { // starts with number
return "_" + enumName;
} else {
return enumName;
}
}
public void setWithXml(boolean withXml) {
this.withXml = withXml;
}
}

View File

@ -0,0 +1,179 @@
package org.openapitools.codegen.languages;
import org.openapitools.codegen.*;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.Operation;
import io.swagger.v3.oas.models.media.*;
import java.io.File;
import java.util.*;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class GoClientCodegen extends AbstractGoCodegen {
protected String packageVersion = "1.0.0";
protected String apiDocPath = "docs/";
protected String modelDocPath = "docs/";
public static final String WITH_XML = "withXml";
public GoClientCodegen() {
super();
outputFolder = "generated-code/go";
modelTemplateFiles.put("model.mustache", ".go");
apiTemplateFiles.put("api.mustache", ".go");
modelDocTemplateFiles.put("model_doc.mustache", ".md");
apiDocTemplateFiles.put("api_doc.mustache", ".md");
embeddedTemplateDir = templateDir = "go";
setReservedWordsLowerCase(
Arrays.asList(
// data type
"string", "bool", "uint", "uint8", "uint16", "uint32", "uint64",
"int", "int8", "int16", "int32", "int64", "float32", "float64",
"complex64", "complex128", "rune", "byte", "uintptr",
"break", "default", "func", "interface", "select",
"case", "defer", "go", "map", "struct",
"chan", "else", "goto", "package", "switch",
"const", "fallthrough", "if", "range", "type",
"continue", "for", "import", "return", "var", "error", "ApiResponse", "nil")
// Added "error" as it's used so frequently that it may as well be a keyword
);
cliOptions.add(new CliOption(CodegenConstants.PACKAGE_VERSION, "Go package version.")
.defaultValue("1.0.0"));
cliOptions.add(CliOption.newBoolean(WITH_XML, "whether to include support for application/xml content type and include XML annotations in the model (works with libraries that provide support for JSON and XML)"));
}
@Override
public void processOpts() {
super.processOpts();
// default HIDE_GENERATION_TIMESTAMP to true
if (!additionalProperties.containsKey(CodegenConstants.HIDE_GENERATION_TIMESTAMP)) {
additionalProperties.put(CodegenConstants.HIDE_GENERATION_TIMESTAMP, Boolean.TRUE.toString());
} else {
additionalProperties.put(CodegenConstants.HIDE_GENERATION_TIMESTAMP,
Boolean.valueOf(additionalProperties().get(CodegenConstants.HIDE_GENERATION_TIMESTAMP).toString()));
}
if (additionalProperties.containsKey(CodegenConstants.PACKAGE_NAME)) {
setPackageName((String) additionalProperties.get(CodegenConstants.PACKAGE_NAME));
}
else {
setPackageName("swagger");
}
if (additionalProperties.containsKey(CodegenConstants.PACKAGE_VERSION)) {
setPackageVersion((String) additionalProperties.get(CodegenConstants.PACKAGE_VERSION));
}
else {
setPackageVersion("1.0.0");
}
additionalProperties.put(CodegenConstants.PACKAGE_NAME, packageName);
additionalProperties.put(CodegenConstants.PACKAGE_VERSION, packageVersion);
additionalProperties.put("apiDocPath", apiDocPath);
additionalProperties.put("modelDocPath", modelDocPath);
modelPackage = packageName;
apiPackage = packageName;
supportingFiles.add(new SupportingFile("swagger.mustache", "api", "swagger.yaml"));
supportingFiles.add(new SupportingFile("README.mustache", "", "README.md"));
supportingFiles.add(new SupportingFile("git_push.sh.mustache", "", "git_push.sh"));
supportingFiles.add(new SupportingFile("gitignore.mustache", "", ".gitignore"));
supportingFiles.add(new SupportingFile("configuration.mustache", "", "configuration.go"));
supportingFiles.add(new SupportingFile("client.mustache", "", "client.go"));
supportingFiles.add(new SupportingFile("response.mustache", "", "response.go"));
supportingFiles.add(new SupportingFile(".travis.yml", "", ".travis.yml"));
if(additionalProperties.containsKey(WITH_XML)) {
setWithXml(Boolean.parseBoolean(additionalProperties.get(WITH_XML).toString()));
if ( withXml ) {
additionalProperties.put(WITH_XML, "true");
}
}
}
/**
* Configures the type of generator.
*
* @return the CodegenType for this generator
* @see org.openapitools.codegen.CodegenType
*/
@Override
public CodegenType getTag() {
return CodegenType.CLIENT;
}
/**
* Configures a friendly name for the generator. This will be used by the generator
* to select the library with the -l flag.
*
* @return the friendly name for the generator
*/
@Override
public String getName() {
return "go";
}
/**
* Returns human-friendly help for the generator. Provide the consumer with help
* tips, parameters here
*
* @return A string value for the help message
*/
@Override
public String getHelp() {
return "Generates a Go client library (beta).";
}
/**
* Location to write api files. You can use the apiPackage() as defined when the class is
* instantiated
*/
@Override
public String apiFileFolder() {
return outputFolder + File.separator;
}
@Override
public String modelFileFolder() {
return outputFolder + File.separator;
}
@Override
public String apiDocFileFolder() {
return (outputFolder + "/" + apiDocPath).replace('/', File.separatorChar);
}
@Override
public String modelDocFileFolder() {
return (outputFolder + "/" + modelDocPath).replace('/', File.separatorChar);
}
@Override
public String toModelDocFilename(String name) {
return toModelName(name);
}
@Override
public String toApiDocFilename(String name) {
return toApiName(name);
}
public void setPackageVersion(String packageVersion) {
this.packageVersion = packageVersion;
}
}

View File

@ -0,0 +1,161 @@
package org.openapitools.codegen.languages;
import org.openapitools.codegen.*;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.Operation;
import io.swagger.v3.oas.models.media.*;
import java.io.File;
import java.util.*;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class GoServerCodegen extends AbstractGoCodegen {
protected String apiVersion = "1.0.0";
protected int serverPort = 8080;
protected String projectName = "swagger-server";
protected String apiPath = "go";
public GoServerCodegen() {
super();
// set the output folder here
outputFolder = "generated-code/go";
/*
* Models. You can write model files using the modelTemplateFiles map.
* if you want to create one template for file, you can do so here.
* for multiple files for model, just put another entry in the `modelTemplateFiles` with
* a different extension
*/
modelTemplateFiles.put(
"model.mustache",
".go");
/*
* Api classes. You can write classes for each Api file with the apiTemplateFiles map.
* as with models, add multiple entries with different extensions for multiple files per
* class
*/
apiTemplateFiles.put(
"controller-api.mustache", // the template to use
".go"); // the extension for each file to write
/*
* Template Location. This is the location which templates will be read from. The generator
* will use the resource stream to attempt to read the templates.
*/
embeddedTemplateDir = templateDir = "go-server";
/*
* Reserved words. Override this with reserved words specific to your language
*/
setReservedWordsLowerCase(
Arrays.asList(
// data type
"string", "bool", "uint", "uint8", "uint16", "uint32", "uint64",
"int", "int8", "int16", "int32", "int64", "float32", "float64",
"complex64", "complex128", "rune", "byte", "uintptr",
"break", "default", "func", "interface", "select",
"case", "defer", "go", "map", "struct",
"chan", "else", "goto", "package", "switch",
"const", "fallthrough", "if", "range", "type",
"continue", "for", "import", "return", "var", "error", "nil")
// Added "error" as it's used so frequently that it may as well be a keyword
);
}
@Override
public void processOpts() {
super.processOpts();
if (additionalProperties.containsKey(CodegenConstants.PACKAGE_NAME)) {
setPackageName((String) additionalProperties.get(CodegenConstants.PACKAGE_NAME));
}
else {
setPackageName("swagger");
}
/*
* Additional Properties. These values can be passed to the templates and
* are available in models, apis, and supporting files
*/
additionalProperties.put("apiVersion", apiVersion);
additionalProperties.put("serverPort", serverPort);
additionalProperties.put("apiPath", apiPath);
additionalProperties.put(CodegenConstants.PACKAGE_NAME, packageName);
modelPackage = packageName;
apiPackage = packageName;
/*
* Supporting Files. You can write single files for the generator with the
* entire object tree available. If the input file has a suffix of `.mustache
* it will be processed by the template engine. Otherwise, it will be copied
*/
supportingFiles.add(new SupportingFile("swagger.mustache", "api", "swagger.yaml"));
supportingFiles.add(new SupportingFile("main.mustache", "", "main.go"));
supportingFiles.add(new SupportingFile("routers.mustache", apiPath, "routers.go"));
supportingFiles.add(new SupportingFile("logger.mustache", apiPath, "logger.go"));
writeOptional(outputFolder, new SupportingFile("README.mustache", apiPath, "README.md"));
}
@Override
public String apiPackage() {
return apiPath;
}
/**
* Configures the type of generator.
*
* @return the CodegenType for this generator
* @see org.openapitools.codegen.CodegenType
*/
@Override
public CodegenType getTag() {
return CodegenType.SERVER;
}
/**
* Configures a friendly name for the generator. This will be used by the generator
* to select the library with the -l flag.
*
* @return the friendly name for the generator
*/
@Override
public String getName() {
return "go-server";
}
/**
* Returns human-friendly help for the generator. Provide the consumer with help
* tips, parameters here
*
* @return A string value for the help message
*/
@Override
public String getHelp() {
return "Generates a Go server library using the swagger-tools project. By default, " +
"it will also generate service classes--which you can disable with the `-Dnoservice` environment variable.";
}
/**
* Location to write api files. You can use the apiPackage() as defined when the class is
* instantiated
*/
@Override
public String apiFileFolder() {
return outputFolder + File.separator + apiPackage().replace('.', File.separatorChar);
}
@Override
public String modelFileFolder() {
return outputFolder + File.separator + apiPackage().replace('.', File.separatorChar);
}
}

View File

@ -0,0 +1,39 @@
package org.openapitools.codegen.go;
import org.openapitools.codegen.AbstractOptionsTest;
import org.openapitools.codegen.CodegenConfig;
import org.openapitools.codegen.languages.GoClientCodegen;
import org.openapitools.codegen.options.GoClientOptionsProvider;
import mockit.Expectations;
import mockit.Tested;
public class GoClientOptionsTest extends AbstractOptionsTest {
@Tested
private GoClientCodegen clientCodegen;
public GoClientOptionsTest() {
super(new GoClientOptionsProvider());
}
@Override
protected CodegenConfig getCodegenConfig() {
return clientCodegen;
}
@SuppressWarnings("unused")
@Override
protected void setExpectations() {
new Expectations(clientCodegen) {{
clientCodegen.setPackageVersion(GoClientOptionsProvider.PACKAGE_VERSION_VALUE);
times = 1;
clientCodegen.setPackageName(GoClientOptionsProvider.PACKAGE_NAME_VALUE);
times = 1;
clientCodegen.setWithXml(GoClientOptionsProvider.WITH_XML_VALUE);
times = 1;
clientCodegen.setPrependFormOrBodyParameters(Boolean.valueOf(GoClientOptionsProvider.PREPEND_FORM_OR_BODY_PARAMETERS_VALUE));
times = 1;
}};
}
}

View File

@ -0,0 +1,262 @@
package org.openapitools.codegen.go;
import org.openapitools.codegen.languages.GoClientCodegen;
import org.openapitools.codegen.*;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.Operation;
import io.swagger.v3.oas.models.media.*;
import io.swagger.v3.parser.util.SchemaTypeUtil;
import com.google.common.collect.Sets;
import org.testng.Assert;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
@SuppressWarnings("static-method")
public class GoModelTest {
@Test(description = "convert a simple Go model")
public void simpleModelTest() {
final Schema model = new Schema()
.description("a sample model")
.addProperties("id", new IntegerSchema().format(SchemaTypeUtil.INTEGER64_FORMAT))
.addProperties("name", new StringSchema())
.addProperties("createdAt", new DateTimeSchema())
.addRequiredItem("id")
.addRequiredItem("name");
final DefaultCodegen codegen = new GoClientCodegen();
final CodegenModel cm = codegen.fromModel("sample", model);
Assert.assertEquals(cm.name, "sample");
Assert.assertEquals(cm.classname, "Sample");
Assert.assertEquals(cm.description, "a sample model");
Assert.assertEquals(cm.vars.size(), 3);
Assert.assertEquals(cm.imports.size(), 1);
final CodegenProperty property1 = cm.vars.get(0);
Assert.assertEquals(property1.baseName, "id");
Assert.assertEquals(property1.datatype, "int64");
Assert.assertEquals(property1.name, "Id");
Assert.assertEquals(property1.defaultValue, "null");
Assert.assertEquals(property1.baseType, "int64");
Assert.assertTrue(property1.hasMore);
Assert.assertTrue(property1.required);
Assert.assertTrue(property1.isPrimitiveType);
Assert.assertTrue(property1.isNotContainer);
final CodegenProperty property2 = cm.vars.get(1);
Assert.assertEquals(property2.baseName, "name");
Assert.assertEquals(property2.datatype, "string");
Assert.assertEquals(property2.name, "Name");
Assert.assertEquals(property2.defaultValue, "null");
Assert.assertEquals(property2.baseType, "string");
Assert.assertTrue(property2.hasMore);
Assert.assertTrue(property2.required);
Assert.assertTrue(property2.isPrimitiveType);
Assert.assertTrue(property2.isNotContainer);
final CodegenProperty property3 = cm.vars.get(2);
Assert.assertEquals(property3.baseName, "createdAt");
Assert.assertEquals(property3.complexType, "time.Time");
Assert.assertEquals(property3.datatype, "time.Time");
Assert.assertEquals(property3.name, "CreatedAt");
Assert.assertEquals(property3.defaultValue, "null");
Assert.assertEquals(property3.baseType, "time.Time");
Assert.assertFalse(property3.hasMore);
Assert.assertFalse(property3.required);
Assert.assertTrue(property3.isNotContainer);
}
@Test(description = "convert a model with list property")
public void listPropertyTest() {
final Schema model = new Schema()
.description("a sample model")
.addProperties("id", new IntegerSchema().format(SchemaTypeUtil.INTEGER64_FORMAT))
.addProperties("urls", new ArraySchema()
.items(new StringSchema()))
.addRequiredItem("id");
final DefaultCodegen codegen = new GoClientCodegen();
final CodegenModel cm = codegen.fromModel("sample", model);
Assert.assertEquals(cm.name, "sample");
Assert.assertEquals(cm.classname, "Sample");
Assert.assertEquals(cm.description, "a sample model");
Assert.assertEquals(cm.vars.size(), 2);
final CodegenProperty property1 = cm.vars.get(0);
Assert.assertEquals(property1.baseName, "id");
Assert.assertEquals(property1.datatype, "int64");
Assert.assertEquals(property1.name, "Id");
Assert.assertEquals(property1.defaultValue, "null");
Assert.assertEquals(property1.baseType, "int64");
Assert.assertTrue(property1.hasMore);
Assert.assertTrue(property1.required);
Assert.assertTrue(property1.isPrimitiveType);
Assert.assertTrue(property1.isNotContainer);
final CodegenProperty property2 = cm.vars.get(1);
Assert.assertEquals(property2.baseName, "urls");
Assert.assertEquals(property2.datatype, "[]string");
Assert.assertEquals(property2.name, "Urls");
Assert.assertEquals(property2.baseType, "array");
Assert.assertFalse(property2.hasMore);
Assert.assertEquals(property2.containerType, "array");
Assert.assertFalse(property2.required);
Assert.assertTrue(property2.isPrimitiveType);
Assert.assertTrue(property2.isContainer);
}
@Test(description = "convert a model with a map property")
public void mapPropertyTest() {
final Schema model = new Schema()
.description("a sample model")
.addProperties("translations", new MapSchema()
.additionalProperties(new StringSchema()))
.addRequiredItem("id");
final DefaultCodegen codegen = new GoClientCodegen();
final CodegenModel cm = codegen.fromModel("sample", model);
Assert.assertEquals(cm.name, "sample");
Assert.assertEquals(cm.classname, "Sample");
Assert.assertEquals(cm.description, "a sample model");
Assert.assertEquals(cm.vars.size(), 1);
final CodegenProperty property1 = cm.vars.get(0);
Assert.assertEquals(property1.baseName, "translations");
Assert.assertEquals(property1.datatype, "map[string]string");
Assert.assertEquals(property1.name, "Translations");
Assert.assertEquals(property1.baseType, "map");
Assert.assertEquals(property1.containerType, "map");
Assert.assertFalse(property1.required);
Assert.assertTrue(property1.isContainer);
Assert.assertTrue(property1.isPrimitiveType);
}
@Test(description = "convert a model with complex property")
public void complexPropertyTest() {
final Schema model = new Schema()
.description("a sample model")
.addProperties("children", new Schema().$ref("#/definitions/Children"));
final DefaultCodegen codegen = new GoClientCodegen();
final CodegenModel cm = codegen.fromModel("sample", model);
Assert.assertEquals(cm.name, "sample");
Assert.assertEquals(cm.classname, "Sample");
Assert.assertEquals(cm.description, "a sample model");
Assert.assertEquals(cm.vars.size(), 1);
final CodegenProperty property1 = cm.vars.get(0);
Assert.assertEquals(property1.baseName, "children");
Assert.assertEquals(property1.datatype, "Children");
Assert.assertEquals(property1.name, "Children");
Assert.assertEquals(property1.baseType, "Children");
Assert.assertFalse(property1.required);
Assert.assertTrue(property1.isNotContainer);
}
@Test(description = "convert a model with complex list property")
public void complexListProperty() {
final Schema model = new Schema()
.description("a sample model")
.addProperties("children", new ArraySchema()
.items(new Schema().$ref("#/definitions/Children")));
final DefaultCodegen codegen = new GoClientCodegen();
final CodegenModel cm = codegen.fromModel("sample", model);
Assert.assertEquals(cm.name, "sample");
Assert.assertEquals(cm.classname, "Sample");
Assert.assertEquals(cm.description, "a sample model");
Assert.assertEquals(cm.vars.size(), 1);
final CodegenProperty property1 = cm.vars.get(0);
Assert.assertEquals(property1.baseName, "children");
Assert.assertEquals(property1.datatype, "[]Children");
Assert.assertEquals(property1.name, "Children");
Assert.assertEquals(property1.baseType, "array");
Assert.assertEquals(property1.containerType, "array");
Assert.assertFalse(property1.required);
Assert.assertTrue(property1.isContainer);
}
@Test(description = "convert a model with complex map property")
public void complexMapProperty() {
final Schema model = new Schema()
.description("a sample model")
.addProperties("children", new MapSchema()
.additionalProperties(new Schema().$ref("#/definitions/Children")));
final DefaultCodegen codegen = new GoClientCodegen();
final CodegenModel cm = codegen.fromModel("sample", model);
Assert.assertEquals(cm.name, "sample");
Assert.assertEquals(cm.classname, "Sample");
Assert.assertEquals(cm.description, "a sample model");
Assert.assertEquals(cm.vars.size(), 1);
Assert.assertEquals(Sets.intersection(cm.imports, Sets.newHashSet("Children")).size(), 1);
final CodegenProperty property1 = cm.vars.get(0);
Assert.assertEquals(property1.baseName, "children");
Assert.assertEquals(property1.complexType, "Children");
Assert.assertEquals(property1.datatype, "map[string]Children");
Assert.assertEquals(property1.name, "Children");
Assert.assertEquals(property1.baseType, "map");
Assert.assertEquals(property1.containerType, "map");
Assert.assertFalse(property1.required);
Assert.assertTrue(property1.isContainer);
Assert.assertFalse(property1.isNotContainer);
}
@Test(description = "convert an array model")
public void arrayModelTest() {
final Schema model = new ArraySchema()
.items(new Schema().$ref("#/definitions/Children"))
.description("an array model");
final DefaultCodegen codegen = new GoClientCodegen();
final CodegenModel cm = codegen.fromModel("sample", model);
Assert.assertEquals(cm.name, "sample");
Assert.assertEquals(cm.classname, "Sample");
Assert.assertEquals(cm.description, "an array model");
Assert.assertEquals(cm.vars.size(), 0);
Assert.assertEquals(cm.imports.size(), 1);
}
@Test(description = "convert an map model")
public void mapModelTest() {
final Schema model = new Schema()
.additionalProperties(new Schema().$ref("#/definitions/Children"))
.description("a map model");
final DefaultCodegen codegen = new GoClientCodegen();
final CodegenModel cm = codegen.fromModel("sample", model);
Assert.assertEquals(cm.name, "sample");
Assert.assertEquals(cm.classname, "Sample");
Assert.assertEquals(cm.description, "a map model");
Assert.assertEquals(cm.vars.size(), 0);
Assert.assertEquals(cm.imports.size(), 1);
Assert.assertEquals(Sets.intersection(cm.imports, Sets.newHashSet("Children")).size(), 1);
}
@DataProvider(name = "modelNames")
public static Object[][] primeNumbers() {
return new Object[][] {
{"sample", "Sample"},
{"sample_name", "SampleName"},
{"sample__name", "SampleName"},
{"/sample", "Sample"},
{"\\sample", "Sample"},
{"sample.name", "SampleName"},
{"_sample", "Sample"},
};
}
@Test(dataProvider = "modelNames", description = "avoid inner class")
public void modelNameTest(String name, String expectedName) {
final Schema model = new Schema();
final DefaultCodegen codegen = new GoClientCodegen();
final CodegenModel cm = codegen.fromModel(name, model);
Assert.assertEquals(cm.name, name);
Assert.assertEquals(cm.classname, expectedName);
}
}

View File

@ -0,0 +1,38 @@
package org.openapitools.codegen.options;
import org.openapitools.codegen.CodegenConstants;
import org.openapitools.codegen.languages.GoClientCodegen;
import com.google.common.collect.ImmutableMap;
import java.util.Map;
public class GoClientOptionsProvider implements OptionsProvider {
public static final String PACKAGE_VERSION_VALUE = "1.0.0";
public static final String PACKAGE_NAME_VALUE = "Go";
public static final boolean WITH_XML_VALUE = true;
public static final Boolean PREPEND_FORM_OR_BODY_PARAMETERS_VALUE = true;
@Override
public String getLanguage() {
return "go";
}
@Override
public Map<String, String> createOptions() {
ImmutableMap.Builder<String, String> builder = new ImmutableMap.Builder<String, String>();
return builder
.put(CodegenConstants.PACKAGE_VERSION, PACKAGE_VERSION_VALUE)
.put(CodegenConstants.PACKAGE_NAME, PACKAGE_NAME_VALUE)
.put(CodegenConstants.HIDE_GENERATION_TIMESTAMP, "true")
.put(CodegenConstants.WITH_XML, "true")
.put(CodegenConstants.PREPEND_FORM_OR_BODY_PARAMETERS, "true")
.build();
}
@Override
public boolean isServer() {
return false;
}
}

View File

@ -0,0 +1,34 @@
package org.openapitools.codegen.options;
import org.openapitools.codegen.CodegenConstants;
import com.google.common.collect.ImmutableMap;
import java.util.Map;
public class GoServerOptionsProvider implements OptionsProvider {
public static final String SORT_PARAMS_VALUE = "false";
public static final String ENSURE_UNIQUE_PARAMS_VALUE = "true";
public static final String ALLOW_UNICODE_IDENTIFIERS_VALUE = "false";
public static final String PREPEND_FORM_OR_BODY_PARAMETERS_VALUE = "true";
@Override
public String getLanguage() {
return "go-server";
}
@Override
public Map<String, String> createOptions() {
ImmutableMap.Builder<String, String> builder = new ImmutableMap.Builder<String, String>();
return builder.put(CodegenConstants.SORT_PARAMS_BY_REQUIRED_FLAG, SORT_PARAMS_VALUE)
.put(CodegenConstants.ENSURE_UNIQUE_PARAMS, ENSURE_UNIQUE_PARAMS_VALUE)
.put(CodegenConstants.ALLOW_UNICODE_IDENTIFIERS, ALLOW_UNICODE_IDENTIFIERS_VALUE)
.put(CodegenConstants.PREPEND_FORM_OR_BODY_PARAMETERS, "true")
.build();
}
@Override
public boolean isServer() {
return true;
}
}