From 0573465b5b73e0fcd465287016e66afe7a69f467 Mon Sep 17 00:00:00 2001 From: Hans Puac Date: Fri, 18 Dec 2020 09:54:18 +0100 Subject: [PATCH] Port UnderscoresToCamelCase logic from protobuf java compiler In some edge cases the generated names did not match the java names. This fixes issue https://github.com/marcoferrer/kroto-plus/issues/115 --- .../krotoplus/utils/StringCaseExts.kt | 39 +++++++++++++++---- .../src/test/kotlin/StringCaseExtsTests.kt | 25 ++++++++++++ 2 files changed, 57 insertions(+), 7 deletions(-) create mode 100644 protoc-gen-kroto-plus/src/test/kotlin/StringCaseExtsTests.kt diff --git a/protoc-gen-kroto-plus/src/main/kotlin/com/github/marcoferrer/krotoplus/utils/StringCaseExts.kt b/protoc-gen-kroto-plus/src/main/kotlin/com/github/marcoferrer/krotoplus/utils/StringCaseExts.kt index 9f1dbda..9462b01 100644 --- a/protoc-gen-kroto-plus/src/main/kotlin/com/github/marcoferrer/krotoplus/utils/StringCaseExts.kt +++ b/protoc-gen-kroto-plus/src/main/kotlin/com/github/marcoferrer/krotoplus/utils/StringCaseExts.kt @@ -18,19 +18,44 @@ package com.github.marcoferrer.krotoplus.utils import com.google.common.base.CaseFormat +/** + * This is the Kotlin implementation of the C++ UnderscoresToCamelCase function that is used by the protobuf java + * compiler in the java_helpers.cc file. + * See https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/compiler/java/java_helpers.cc#L168-L203 + * The exact same logic was ported to ensure the generated names match the generated Java names. + */ val upperCamelCase = { it: String -> - // We cant use CaseFormat.UPPER_CAMEL since - // protoc is lenient with malformed field names - if (it.contains("_")) - it.split("_").joinToString(separator = "") { it.capitalize() } else - it.capitalize() - + StringBuilder().apply { + var capNextLetter = true + it.forEach { c -> + when (c) { + in 'a'..'z' -> { + if (capNextLetter) { + append(c.toUpperCase()) + } else { + append(c) + } + capNextLetter = false + } + in 'A'..'Z' -> { + append(c) + capNextLetter = false + } + in '0'..'9' -> { + append(c) + capNextLetter = true + } + else -> { + capNextLetter = true + } + } + } + }.toString() }.memoize() fun String.toUpperCamelCase(): String = upperCamelCase(this) private val upperSnakeCase = { it: String -> - val valueCamel = it.toUpperCamelCase() CaseFormat.UPPER_CAMEL .converterTo(CaseFormat.UPPER_UNDERSCORE) diff --git a/protoc-gen-kroto-plus/src/test/kotlin/StringCaseExtsTests.kt b/protoc-gen-kroto-plus/src/test/kotlin/StringCaseExtsTests.kt new file mode 100644 index 0000000..ad0a0bd --- /dev/null +++ b/protoc-gen-kroto-plus/src/test/kotlin/StringCaseExtsTests.kt @@ -0,0 +1,25 @@ +package com.github.marcoferrer.krotoplus.utils + +import kotlin.test.Test +import kotlin.test.assertEquals + +class StringCaseExtsTests { + @Test + fun `toUpperCamelCase capitalizes first character`() { + assertEquals("SomethingAwesome", "somethingAwesome".toUpperCamelCase()) + assertEquals("Test", "test".toUpperCamelCase()) + } + + @Test + fun `toUpperCamelCase uppercases character after underscore`() { + assertEquals("ThisIsAnAwesomeText", "this_is_an_awesome_text".toUpperCamelCase()) + assertEquals("SomeExample", "some_example".toUpperCamelCase()) + } + + @Test + fun `toUpperCamelCase uppercases character after number`() { + assertEquals("SomeMethod4Me", "some_method4me".toUpperCamelCase()) + assertEquals("SomeB2BCase", "some_b2b_case".toUpperCamelCase()) + assertEquals("Fun4Devs", "fun4devs".toUpperCamelCase()) + } +} \ No newline at end of file