diff --git a/src/main/java/com/google/api/generator/gapic/utils/JavaStyle.java b/src/main/java/com/google/api/generator/gapic/utils/JavaStyle.java index c5210d7c72..35d460cc2b 100644 --- a/src/main/java/com/google/api/generator/gapic/utils/JavaStyle.java +++ b/src/main/java/com/google/api/generator/gapic/utils/JavaStyle.java @@ -15,25 +15,50 @@ package com.google.api.generator.gapic.utils; import com.google.common.base.CaseFormat; +import com.google.common.base.Strings; +import java.util.stream.IntStream; public class JavaStyle { private static final String UNDERSCORE = "_"; public static String toLowerCamelCase(String s) { + if (Strings.isNullOrEmpty(s)) { + return s; + } + if (s.indexOf(UNDERSCORE) >= 0) { s = CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, s); } - return String.format("%s%s", s.substring(0, 1).toLowerCase(), s.substring(1)); + return capitalizeLettersAfterDigits( + String.format("%s%s", s.substring(0, 1).toLowerCase(), s.substring(1))); } public static String toUpperCamelCase(String s) { + if (Strings.isNullOrEmpty(s)) { + return s; + } + if (s.indexOf(UNDERSCORE) >= 0) { s = CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, s); } - return String.format("%s%s", s.substring(0, 1).toUpperCase(), s.substring(1)); + return capitalizeLettersAfterDigits( + String.format("%s%s", s.substring(0, 1).toUpperCase(), s.substring(1))); } public static String toUpperSnakeCase(String s) { return CaseFormat.UPPER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, toUpperCamelCase(s)); } + + private static String capitalizeLettersAfterDigits(String s) { + return IntStream.range(0, s.length()) + .collect( + StringBuilder::new, + (sb, i) -> + sb.append( + i > 0 && Character.isDigit(s.charAt(i - 1)) + ? Character.toUpperCase(s.charAt(i)) + : s.charAt(i)), + StringBuilder::append) + .toString(); + } } diff --git a/src/test/java/com/google/api/generator/gapic/BUILD.bazel b/src/test/java/com/google/api/generator/gapic/BUILD.bazel index 7a9cbd0da5..4710f67755 100644 --- a/src/test/java/com/google/api/generator/gapic/BUILD.bazel +++ b/src/test/java/com/google/api/generator/gapic/BUILD.bazel @@ -7,5 +7,6 @@ filegroup( "//src/test/java/com/google/api/generator/gapic/dummy:dummy_files", "//src/test/java/com/google/api/generator/gapic/model:model_files", "//src/test/java/com/google/api/generator/gapic/protoparser:protoparser_files", + "//src/test/java/com/google/api/generator/gapic/utils:utils_files", ], ) diff --git a/src/test/java/com/google/api/generator/gapic/utils/BUILD.bazel b/src/test/java/com/google/api/generator/gapic/utils/BUILD.bazel new file mode 100644 index 0000000000..157800f105 --- /dev/null +++ b/src/test/java/com/google/api/generator/gapic/utils/BUILD.bazel @@ -0,0 +1,21 @@ +package(default_visibility = ["//visibility:public"]) + +TESTS = [ + "JavaStyleTest", +] + +filegroup( + name = "utils_files", + srcs = ["{0}.java".format(f) for f in TESTS], +) + +[java_test( + name = test_name, + srcs = ["{0}.java".format(test_name)], + test_class = "com.google.api.generator.gapic.utils.{0}".format(test_name), + deps = [ + "//src/main/java/com/google/api/generator/gapic/utils", + "@com_google_truth_truth//jar", + "@junit_junit//jar", + ], +) for test_name in TESTS] diff --git a/src/test/java/com/google/api/generator/gapic/utils/JavaStyleTest.java b/src/test/java/com/google/api/generator/gapic/utils/JavaStyleTest.java new file mode 100644 index 0000000000..10b65c9b9c --- /dev/null +++ b/src/test/java/com/google/api/generator/gapic/utils/JavaStyleTest.java @@ -0,0 +1,114 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.api.generator.gapic.utils; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.Assert.assertEquals; + +import org.junit.Test; + +public class JavaStyleTest { + @Test + public void emptyOrNull() { + String value = ""; + assertEquals("", JavaStyle.toLowerCamelCase(value)); + assertEquals("", JavaStyle.toUpperCamelCase(value)); + + value = null; + assertThat(JavaStyle.toLowerCamelCase(value)).isNull(); + assertThat(JavaStyle.toUpperCamelCase(value)).isNull(); + } + + @Test + public void singleWord() { + String value = "dog"; + assertEquals("dog", JavaStyle.toLowerCamelCase(value)); + assertEquals("Dog", JavaStyle.toUpperCamelCase(value)); + } + + @Test + public void fromLowerSnake() { + String value = "factory_decorator_delegate_impl"; + assertEquals("factoryDecoratorDelegateImpl", JavaStyle.toLowerCamelCase(value)); + assertEquals("FactoryDecoratorDelegateImpl", JavaStyle.toUpperCamelCase(value)); + } + + @Test + public void fromUpperSnake() { + String value = "FACTORY_DECORATOR_DELEGATE_IMPL"; + assertEquals("factoryDecoratorDelegateImpl", JavaStyle.toLowerCamelCase(value)); + assertEquals("FactoryDecoratorDelegateImpl", JavaStyle.toUpperCamelCase(value)); + } + + @Test + public void fromLowerCamelCase() { + String value = "factoryDecoratorDelegateImpl"; + assertEquals("factoryDecoratorDelegateImpl", JavaStyle.toLowerCamelCase(value)); + assertEquals("FactoryDecoratorDelegateImpl", JavaStyle.toUpperCamelCase(value)); + } + + @Test + public void fromUpperCamelCase() { + String value = "FactoryDecoratorDelegateImpl"; + assertEquals("factoryDecoratorDelegateImpl", JavaStyle.toLowerCamelCase(value)); + assertEquals("FactoryDecoratorDelegateImpl", JavaStyle.toUpperCamelCase(value)); + } + + @Test + public void wordAndNumber() { + String value = "dog2"; + assertEquals("dog2", JavaStyle.toLowerCamelCase(value)); + assertEquals("Dog2", JavaStyle.toUpperCamelCase(value)); + value = "dog_2"; + assertEquals("dog2", JavaStyle.toLowerCamelCase(value)); + assertEquals("Dog2", JavaStyle.toUpperCamelCase(value)); + } + + @Test + public void upperWordAndNumber() { + String value = "Dog_v2"; + assertEquals("dogV2", JavaStyle.toLowerCamelCase(value)); + assertEquals("DogV2", JavaStyle.toUpperCamelCase(value)); + } + + @Test + public void upperWordAndCharsAfterDigit() { + String value = "dogV2cc"; + assertEquals("dogV2Cc", JavaStyle.toLowerCamelCase(value)); + assertEquals("DogV2Cc", JavaStyle.toUpperCamelCase(value)); + + value = "dogv2_cc"; + assertEquals("dogv2Cc", JavaStyle.toLowerCamelCase(value)); + assertEquals("Dogv2Cc", JavaStyle.toUpperCamelCase(value)); + + value = "dog_v2_cc"; + assertEquals("dogV2Cc", JavaStyle.toLowerCamelCase(value)); + assertEquals("DogV2Cc", JavaStyle.toUpperCamelCase(value)); + + value = "foo1bar2car3"; + assertEquals("foo1Bar2Car3", JavaStyle.toLowerCamelCase(value)); + assertEquals("Foo1Bar2Car3", JavaStyle.toUpperCamelCase(value)); + } + + @Test + public void acronyms() { + String value = "iam_http_xml_dog"; + assertEquals("iamHttpXmlDog", JavaStyle.toLowerCamelCase(value)); + assertEquals("IamHttpXmlDog", JavaStyle.toUpperCamelCase(value)); + value = "IAM_HTTP_XML_DOG"; + assertEquals("iamHttpXmlDog", JavaStyle.toLowerCamelCase(value)); + assertEquals("IamHttpXmlDog", JavaStyle.toUpperCamelCase(value)); + } +}