Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[csharp] Introducing the enumPropertyNaming option to the C# Generator #16981

Merged
merged 2 commits into from
Nov 7, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@

import static org.openapitools.codegen.utils.CamelizeOption.LOWERCASE_FIRST_LETTER;
import static org.openapitools.codegen.utils.StringUtils.camelize;
import static org.openapitools.codegen.utils.StringUtils.underscore;

public abstract class AbstractCSharpCodegen extends DefaultCodegen implements CodegenConfig {

Expand Down Expand Up @@ -84,6 +85,7 @@ public abstract class AbstractCSharpCodegen extends DefaultCodegen implements Co

protected String sourceFolder = "src";
protected String invalidNamePrefix = "var";
protected CodegenConstants.ENUM_PROPERTY_NAMING_TYPE enumPropertyNaming = CodegenConstants.ENUM_PROPERTY_NAMING_TYPE.PascalCase;

// TODO: Add option for test folder output location. Nice to allow e.g. ./test instead of ./src.
// This would require updating relative paths (e.g. path to main project file in test project file)
Expand Down Expand Up @@ -391,6 +393,10 @@ public void processOpts() {
setEnumValueSuffix(additionalProperties.get(CodegenConstants.ENUM_VALUE_SUFFIX).toString());
}

if (additionalProperties.containsKey(CodegenConstants.ENUM_PROPERTY_NAMING)) {
setEnumPropertyNaming((String) additionalProperties.get(CodegenConstants.ENUM_PROPERTY_NAMING));
}

// This either updates additionalProperties with the above fixes, or sets the default if the option was not specified.
additionalProperties.put(CodegenConstants.INTERFACE_PREFIX, interfacePrefix);

Expand Down Expand Up @@ -1598,6 +1604,22 @@ public void setSupportNullable(final boolean supportNullable) {
this.supportNullable = supportNullable;
}

public CodegenConstants.ENUM_PROPERTY_NAMING_TYPE getEnumPropertyNaming() {
return this.enumPropertyNaming;
}

public void setEnumPropertyNaming(final String enumPropertyNamingType) {
try {
this.enumPropertyNaming = CodegenConstants.ENUM_PROPERTY_NAMING_TYPE.valueOf(enumPropertyNamingType);
} catch (IllegalArgumentException ex) {
StringBuilder sb = new StringBuilder(enumPropertyNamingType + " is an invalid enum property naming option. Please choose from:");
for (CodegenConstants.ENUM_PROPERTY_NAMING_TYPE t : CodegenConstants.ENUM_PROPERTY_NAMING_TYPE.values()) {
sb.append("\n ").append(t.name());
}
throw new RuntimeException(sb.toString());
}
}

@Override
public String toEnumValue(String value, String datatype) {
// C# only supports enums as literals for int, int?, long, long?, byte, and byte?. All else must be treated as strings.
Expand All @@ -1622,20 +1644,20 @@ public String toEnumValue(String value, String datatype) {
@Override
public String toEnumVarName(String name, String datatype) {
if (name.length() == 0) {
return "Empty";
return adjustNamingStyle("Empty");
}

// for symbol, e.g. $, #
if (getSymbolName(name) != null) {
return camelize(getSymbolName(name));
return adjustNamingStyle(getSymbolName(name));
}

String enumName = sanitizeName(name);

enumName = enumName.replaceFirst("^_", "");
enumName = enumName.replaceFirst("_$", "");

enumName = camelize(enumName) + this.enumValueSuffix;
enumName = adjustNamingStyle(enumName) + this.enumValueSuffix;

if (enumName.matches("\\d.*")) { // starts with number
return "_" + enumName;
Expand All @@ -1644,6 +1666,27 @@ public String toEnumVarName(String name, String datatype) {
}
}

private String adjustNamingStyle(String name)
wing328 marked this conversation as resolved.
Show resolved Hide resolved
{
switch (getEnumPropertyNaming()) {
case original:
return name;
case camelCase:
// NOTE: Removes hyphens and underscores
return camelize(name, LOWERCASE_FIRST_LETTER);
case PascalCase:
// NOTE: Removes hyphens and underscores
return camelize(name);
case snake_case:
// NOTE: Removes hyphens
return underscore(name);
case UPPERCASE:
return underscore(name).toUpperCase(Locale.ROOT);
default:
return name;
}
}

@Override
public String toEnumName(CodegenProperty property) {
return sanitizeName(camelize(property.name)) + this.enumNameSuffix;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,15 @@
import org.openapitools.codegen.languages.CSharpClientCodegen;
import org.testng.Assert;
import org.testng.annotations.Test;
import org.testng.annotations.DataProvider;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

import org.openapitools.codegen.CodegenConstants.ENUM_PROPERTY_NAMING_TYPE;
import static org.openapitools.codegen.CodegenConstants.ENUM_PROPERTY_NAMING_TYPE.*;

public class CSharpModelEnumTest {
// TODO there's no parent/child method in ComposeSchema so we will need to revise the code
// before we can re-enable the test case below
Expand Down Expand Up @@ -148,4 +152,54 @@ public void useEmptyEnumSuffixes() {
Assert.assertEquals(codegen.toEnumVarName("Aaaa", ""), "Aaaa");
}

@Test(description = "support enum naming style options", dataProvider = "enumVarName")
public void testToEnumVarName(String name, String expected, ENUM_PROPERTY_NAMING_TYPE naming) throws Exception {
final AspNetServerCodegen codegen = new AspNetServerCodegen();
codegen.setEnumPropertyNaming(naming.name());
codegen.setEnumValueSuffix("");

Assert.assertEquals(codegen.toEnumVarName(name, "string"), expected);
}

@DataProvider(name = "enumVarName")
public Object[][] provideTestData()
{
return new Object[][] {
{ "FooBar", "fooBar", camelCase },
{ "fooBar", "fooBar", camelCase },
{ "foo-bar", "fooBar", camelCase },
{ "foo_bar", "fooBar", camelCase },
{ "foo bar", "fooBar", camelCase },
{ "FOO-BAR", "fOOBAR", camelCase }, // camelize doesn't support uppercase
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we will try to fix that in another PR.

{ "FOO_BAR", "fOOBAR", camelCase }, // ditto
{ "FooBar", "FooBar", PascalCase },
{ "fooBar", "FooBar", PascalCase },
{ "foo-bar", "FooBar", PascalCase },
{ "foo_bar", "FooBar", PascalCase },
{ "foo bar", "FooBar", PascalCase },
{ "FOO-BAR", "FOOBAR", PascalCase }, // ditto
{ "FOO_BAR", "FOOBAR", PascalCase }, // ditto
{ "FooBar", "foo_bar", snake_case },
{ "fooBar", "foo_bar", snake_case },
{ "foo-bar", "foo_bar", snake_case },
{ "foo_bar", "foo_bar", snake_case },
{ "foo bar", "foo_bar", snake_case },
{ "FOO-BAR", "foo_bar", snake_case },
{ "FOO_BAR", "foo_bar", snake_case },
{ "FooBar", "FOO_BAR", UPPERCASE },
{ "fooBar", "FOO_BAR", UPPERCASE },
{ "foo-bar", "FOO_BAR", UPPERCASE },
{ "foo_bar", "FOO_BAR", UPPERCASE },
{ "foo bar", "FOO_BAR", UPPERCASE },
{ "FOO-BAR", "FOO_BAR", UPPERCASE },
{ "FOO_BAR", "FOO_BAR", UPPERCASE },
{ "FooBar", "FooBar", original },
{ "fooBar", "fooBar", original },
{ "foo-bar", "foo_bar", original },
{ "foo_bar", "foo_bar", original },
{ "foo bar", "foo_bar", original },
{ "FOO-BAR", "FOO_BAR", original },
{ "FOO_BAR", "FOO_BAR", original },
};
}
}
Loading