Skip to content

Commit 6fe11a1

Browse files
committed
protobuf: Fix proto2 compilation
Signed-off-by: Johannes Zottele <[email protected]>
1 parent ab7abb1 commit 6fe11a1

File tree

7 files changed

+70
-14
lines changed

7 files changed

+70
-14
lines changed

protobuf/protobuf-core/src/commonMain/kotlin/kotlinx/rpc/protobuf/internal/ProtobufException.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
package kotlinx.rpc.protobuf.internal
66

7+
import kotlinx.rpc.internal.utils.InternalRpcApi
8+
79
public sealed class ProtobufException : RuntimeException {
810
protected constructor(message: String, cause: Throwable? = null) : super(message, cause)
911
}
@@ -13,6 +15,7 @@ public class ProtobufDecodingException : ProtobufException {
1315
public constructor(message: String, cause: Throwable? = null) : super(message, cause)
1416

1517
public companion object Companion {
18+
@InternalRpcApi
1619
public fun missingRequiredField(messageName: String, fieldName: String): ProtobufDecodingException =
1720
ProtobufDecodingException("Message '$messageName' is missing a required field: $fieldName")
1821

protobuf/protobuf-core/src/commonTest/kotlin/kotlinx/rpc/protobuf/test/ProtosTest.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -453,4 +453,10 @@ class ProtosTest {
453453
(decoded.oneOfWithGroup as WithGroups.OneOfWithGroup.Testgroup).value.value
454454
)
455455
}
456+
457+
@Test
458+
fun test() {
459+
println("Float printed: ${Float.NEGATIVE_INFINITY}")
460+
}
461+
456462
}
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
syntax = "proto3";
1+
//syntax = "proto3";
22

33
package kotlinx.rpc.protobuf.test;
44

@@ -7,4 +7,5 @@ import "presence_check.proto";
77
message TestMap {
88
map<string, int64> primitives = 1;
99
map<int32, kotlinx.rpc.protobuf.test.PresenceCheck> messages = 2;
10+
map<int32, int32> map_int32_int32 = 3;
1011
}

protoc-gen/common/src/main/kotlin/kotlinx/rpc/protoc/gen/core/model/model.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,11 +91,14 @@ data class FieldDeclaration(
9191

9292
val isPartOfOneof: Boolean = dec.realContainingOneof != null
9393

94+
val isPartOfMapEntry = dec.containingType.options.mapEntry
95+
9496
// aligns with edition settings and backward compatibility with proto2 and proto3
9597
val nullable: Boolean = (dec.hasPresence() && !dec.isRequired && !dec.hasDefaultValue()
9698
&& !dec.isRepeated // repeated fields cannot be nullable (just empty)
9799
&& !isPartOfOneof // upper conditions would match oneof inner fields
98100
&& type !is FieldType.Message // messages must not be null (to conform protobuf standards)
101+
&& !isPartOfMapEntry // map entry fields cannot be null
99102
)
100103
|| type is FieldType.OneOf // all OneOf fields are nullable
101104
val number: Int = dec.number

protoc-gen/protobuf/src/main/kotlin/kotlinx/rpc/protoc/gen/ModelToProtobufKotlinCommonGenerator.kt

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -911,25 +911,53 @@ class ModelToProtobufKotlinCommonGenerator(
911911
return type.defaultValue ?: error("No default value for field $name")
912912
}
913913

914-
return when (val value = dec.defaultValue) {
915-
is String -> {
914+
val value = dec.defaultValue
915+
return when {
916+
value is String -> {
916917
"\"$value\""
917918
}
918919

919-
is ByteString -> {
920+
value is ByteString -> {
920921
"BytesDefaults.$name"
921922
}
922923

923-
is Descriptors.EnumValueDescriptor -> {
924+
value is Descriptors.EnumValueDescriptor -> {
924925
value.fqName().safeFullName()
925926
}
926927

928+
value is Int && (type == FieldType.IntegralType.UINT32 || type == FieldType.IntegralType.FIXED32) -> {
929+
Integer.toUnsignedString(value) + "u"
930+
}
931+
932+
value is Long && (type == FieldType.IntegralType.UINT64 || type == FieldType.IntegralType.FIXED64) -> {
933+
java.lang.Long.toUnsignedString(value) + "uL"
934+
}
935+
936+
value is Float -> {
937+
when (value.toString()) {
938+
"Infinity" -> "Float.POSITIVE_INFINITY"
939+
"-Infinity" -> "Float.NEGATIVE_INFINITY"
940+
"NaN" -> "Float.NaN"
941+
else -> value.toString() + "f"
942+
}
943+
}
944+
945+
value is Double -> {
946+
when (value.toString()) {
947+
"Infinity" -> "Double.POSITIVE_INFINITY"
948+
"-Infinity" -> "Double.NEGATIVE_INFINITY"
949+
"NaN" -> "Double.NaN"
950+
else -> value.toString()
951+
}
952+
}
953+
927954
else -> {
928955
"${value}${type.scalarDefaultSuffix()}"
929956
}
930957
}
931958
}
932959

960+
933961
private fun FieldType.decodeEncodeFuncName(): String? = when (this) {
934962
FieldType.IntegralType.STRING -> "String"
935963
FieldType.IntegralType.BYTES -> "Bytes"

tests/protobuf-conformance/build.gradle.kts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ tasks.withType<BufGenerateTask>().configureEach {
5151
protoSourceSets {
5252
main {
5353
proto {
54-
exclude("**/test_messages_proto2.proto")
54+
// exclude("**/test_messages_proto2.proto")
5555
exclude("**/test_messages_proto2_editions.proto")
5656
exclude("**/test_messages_edition2023.proto")
5757
}
@@ -91,7 +91,8 @@ val generateConformanceTests = tasks.register<JavaExec>("generateConformanceTest
9191
}
9292

9393
val conformanceTest = properties.getOrDefault("conformance.test", "").toString()
94-
val conformanceTestDebug = properties.getOrDefault("conformance.test.debug", "false").toString().toBooleanStrictOrNull() ?: false
94+
val conformanceTestDebug =
95+
properties.getOrDefault("conformance.test.debug", "false").toString().toBooleanStrictOrNull() ?: false
9596

9697
val generateConformanceFileDescriptorSet = tasks
9798
.withType<GenerateConformanceFileDescriptorSet>()

tests/protobuf-conformance/src/test/kotlin/kotlinx/rpc/protoc/gen/test/ConformanceTest.kt

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import kotlinx.rpc.protoc.gen.test.runner.createConformanceTestFiles
99
import kotlinx.rpc.protoc.gen.test.runner.execConformanceTestRunner
1010
import kotlinx.rpc.protoc.gen.test.runner.getJavaClient
1111
import org.junit.jupiter.api.DynamicTest
12+
import org.junit.jupiter.api.Test
1213
import org.junit.jupiter.api.TestFactory
1314
import org.junit.jupiter.api.TestInstance
1415
import org.junit.jupiter.api.fail
@@ -60,25 +61,38 @@ class ConformanceTest {
6061
val mockDir = Path(CONFORMANCE_OUTPUT_DIR).resolve("mock")
6162
val (baselineFile, _) = createConformanceTestFiles(mockDir, createBlank = false)
6263

64+
// Include only Editions_Proto3 or Proto3 tests and exclude any JSON-related tests
65+
fun includeTest(name: String): Boolean {
66+
val trimmed = name.substringBefore('#').trim()
67+
if (trimmed.isEmpty()) return false
68+
val isProto3Edition = trimmed.contains(".Editions_Proto3.") || trimmed.contains(".Proto3.")
69+
|| trimmed.contains(".Proto2.")
70+
val isJsonRelated = trimmed.contains(".Json") // matches JsonInput, JsonOutput, etc.
71+
return isProto3Edition && !isJsonRelated
72+
}
73+
6374
val baseline = baselineFile
6475
.readLines()
6576
.map { it.substringBefore('#').trim() }
6677
.filter { it.isNotEmpty() }
78+
.filter { includeTest(it) }
6779
.toSet()
6880

69-
val fails = failingTestsFile.readLines().associate {
70-
it.substringBefore('#').trim() to it.substringAfter('#').trim()
71-
}
81+
val fails = failingTestsFile.readLines()
82+
.map { it to (it.substringAfter('#', missingDelimiterValue = "").trim()) }
83+
.map { (line, msg) -> line.substringBefore('#').trim() to msg }
84+
.filter { (name, _) -> includeTest(name) }
85+
.toMap()
7286

7387
val passed = baseline - fails.keys
7488

7589
println(
7690
"""
7791
78-
=== Conformance Test Results ===
79-
Total baseline tests: ${baseline.size}
80-
[+] Passed tests: ${passed.size}
81-
[-] Failed tests: ${fails.size}
92+
=== Conformance Test Results (filtered) ===
93+
Total baseline tests (filtered): ${baseline.size}
94+
[+] Passed tests: ${passed.size}
95+
[-] Failed tests: ${fails.size}
8296
""".trimIndent()
8397
)
8498

0 commit comments

Comments
 (0)