Skip to content

Commit a675cb3

Browse files
authored
Add protobuf conformance tests (#2404)
Add conformance tests using test_messages_proto3 construct google provides
1 parent 79ecba6 commit a675cb3

File tree

9 files changed

+1122
-0
lines changed

9 files changed

+1122
-0
lines changed
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/*
2+
* Copyright 2017-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
5+
package kotlinx.serialization.protobuf.conformance
6+
7+
import com.google.protobuf_test_messages.proto3.*
8+
import kotlinx.serialization.*
9+
import kotlinx.serialization.protobuf.*
10+
import kotlin.test.*
11+
12+
@Serializable
13+
data class KTestMessagesProto3Enum(
14+
@ProtoNumber(21) val optionalNestedEnum: KNestedEnum = KNestedEnum.FOO,
15+
@ProtoNumber(22) val optionalForeignEnum: KForeignEnum = KForeignEnum.FOREIGN_FOO,
16+
@ProtoNumber(23) val optionalAliasedEnum: KAliasedEnum = KAliasedEnum.ALIAS_FOO,
17+
) {
18+
enum class KNestedEnum {
19+
@ProtoNumber(0)
20+
FOO,
21+
22+
@ProtoNumber(1)
23+
BAR,
24+
25+
@ProtoNumber(2)
26+
BAZ,
27+
28+
@ProtoNumber(-1)
29+
NEG;
30+
31+
fun toProto() = TestMessagesProto3.TestAllTypesProto3.NestedEnum.valueOf(this.name)
32+
}
33+
34+
35+
enum class KAliasedEnum {
36+
@ProtoNumber(0)
37+
ALIAS_FOO,
38+
39+
@ProtoNumber(1)
40+
ALIAS_BAR,
41+
42+
@ProtoNumber(2)
43+
ALIAS_BAZ,
44+
45+
@ProtoNumber(2)
46+
MOO,
47+
48+
@ProtoNumber(2)
49+
moo,
50+
51+
@ProtoNumber(2)
52+
bAz;
53+
54+
fun toProto() = TestMessagesProto3.TestAllTypesProto3.AliasedEnum.valueOf(this.name)
55+
}
56+
}
57+
58+
enum class KForeignEnum {
59+
@ProtoNumber(0)
60+
FOREIGN_FOO,
61+
62+
@ProtoNumber(1)
63+
FOREIGN_BAR,
64+
65+
@ProtoNumber(2)
66+
FOREIGN_BAZ;
67+
68+
fun toProto() = TestMessagesProto3.ForeignEnum.valueOf(this.name)
69+
}
70+
71+
class Proto3EnumTest {
72+
@Test
73+
fun default() {
74+
val message = KTestMessagesProto3Enum(
75+
optionalNestedEnum = KTestMessagesProto3Enum.KNestedEnum.NEG,
76+
optionalForeignEnum = KForeignEnum.FOREIGN_BAR,
77+
optionalAliasedEnum = KTestMessagesProto3Enum.KAliasedEnum.ALIAS_BAR
78+
)
79+
80+
val bytes = ProtoBuf.encodeToByteArray(message)
81+
val restored = TestMessagesProto3.TestAllTypesProto3.parseFrom(bytes)
82+
83+
assertEquals(message.optionalNestedEnum.toProto(), restored.optionalNestedEnum)
84+
assertEquals(message.optionalForeignEnum.toProto(), restored.optionalForeignEnum)
85+
assertEquals(message.optionalAliasedEnum.toProto(), restored.optionalAliasedEnum)
86+
87+
val restoredMessage = ProtoBuf.decodeFromByteArray<KTestMessagesProto3Enum>(restored.toByteArray())
88+
assertEquals(message, restoredMessage)
89+
}
90+
}
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
/*
2+
* Copyright 2017-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
5+
package kotlinx.serialization.protobuf.conformance
6+
7+
import com.google.protobuf_test_messages.proto3.*
8+
import io.kotlintest.properties.*
9+
import kotlinx.serialization.*
10+
import kotlinx.serialization.protobuf.*
11+
import kotlin.test.*
12+
13+
@Serializable
14+
data class KTestMessagesProto3Map(
15+
@ProtoNumber(56) val mapInt32Int32: Map<Int, Int> = emptyMap(),
16+
@ProtoNumber(57) val mapInt64Int64: Map<Long, Long> = emptyMap(),
17+
@ProtoNumber(58) val mapUint32Uint32: Map<UInt, UInt> = emptyMap(),
18+
@ProtoNumber(59) val mapUint64Uint64: Map<ULong, ULong> = emptyMap(),
19+
@ProtoNumber(60) val mapSint32Sint32: Map<Int, Int> = emptyMap(),
20+
@ProtoNumber(61) val mapSint64Sint64: Map<Long, Long> = emptyMap(),
21+
@ProtoNumber(62) val mapFixed32Fixed32: Map<Int, Int> = emptyMap(),
22+
@ProtoNumber(63) val mapFixed64Fixed64: Map<Long, Long> = emptyMap(),
23+
@ProtoNumber(64) val mapSfixed32Sfixed32: Map<Int, Int> = emptyMap(),
24+
@ProtoNumber(65) val mapSfixed64Sfixed64: Map<Long, Long> = emptyMap(),
25+
@ProtoNumber(66) val mapInt32Float: Map<Int, Float> = emptyMap(),
26+
@ProtoNumber(67) val mapInt32Double: Map<Int, Double> = emptyMap(),
27+
@ProtoNumber(68) val mapBoolBool: Map<Boolean, Boolean> = emptyMap(),
28+
@ProtoNumber(69) val mapStringString: Map<String, String> = emptyMap(),
29+
@ProtoNumber(70) val mapStringBytes: Map<String, ByteArray> = emptyMap(),
30+
@ProtoNumber(71) val mapStringNestedMessage: Map<String, KTestMessagesProto3Message.KNestedMessage> = emptyMap(),
31+
@ProtoNumber(72) val mapStringForeignMessage: Map<String, KForeignMessage> = emptyMap(),
32+
@ProtoNumber(73) val mapStringNestedEnum: Map<String, KTestMessagesProto3Enum.KNestedEnum> = emptyMap(),
33+
@ProtoNumber(74) val mapStringForeignEnum: Map<String, KForeignEnum> = emptyMap(),
34+
)
35+
36+
class Proto3MapTest {
37+
@Test
38+
fun default() {
39+
val message = KTestMessagesProto3Map(
40+
mapInt32Int32 = Gen.map(Gen.int(), Gen.int()).generate(),
41+
mapInt64Int64 = Gen.map(Gen.long(), Gen.long()).generate(),
42+
mapUint32Uint32 = Gen.map(Gen.int().map { it.toUInt() }, Gen.int().map { it.toUInt() }).generate(),
43+
mapUint64Uint64 = Gen.map(Gen.int().map { it.toULong() }, Gen.int().map { it.toULong() }).generate(),
44+
mapInt32Float = Gen.map(Gen.int(), Gen.float()).generate(),
45+
mapInt32Double = Gen.map(Gen.int(), Gen.double()).generate(),
46+
mapBoolBool = Gen.map(Gen.bool(), Gen.bool()).generate(),
47+
mapStringString = Gen.map(Gen.string(), Gen.string()).generate(),
48+
mapStringBytes = Gen.map(Gen.string(), Gen.string().map { it.toByteArray() }).generate(),
49+
mapStringNestedMessage = mapOf(
50+
"asd_1" to KTestMessagesProto3Message.KNestedMessage(
51+
1,
52+
null
53+
),
54+
"asi_#" to KTestMessagesProto3Message.KNestedMessage(
55+
2,
56+
KTestMessagesProto3Message(
57+
KTestMessagesProto3Message.KNestedMessage(3, null),
58+
)
59+
)
60+
),
61+
mapStringForeignMessage = mapOf(
62+
"" to KForeignMessage(1),
63+
"-2" to KForeignMessage(-12),
64+
),
65+
mapStringNestedEnum = Gen.map(
66+
Gen.string(), Gen.oneOf(
67+
KTestMessagesProto3Enum.KNestedEnum.entries,
68+
)
69+
).generate(),
70+
mapStringForeignEnum = Gen.map(
71+
Gen.string(), Gen.oneOf(
72+
KForeignEnum.entries,
73+
)
74+
).generate(),
75+
)
76+
77+
val bytes = ProtoBuf.encodeToByteArray(message)
78+
val restored = TestMessagesProto3.TestAllTypesProto3.parseFrom(bytes)
79+
80+
81+
assertEquals(message.mapInt32Int32, restored.mapInt32Int32Map)
82+
assertEquals(message.mapInt64Int64, restored.mapInt64Int64Map)
83+
assertEquals(
84+
message.mapUint32Uint32,
85+
restored.mapUint32Uint32Map.map { it.key.toUInt() to it.value.toUInt() }.toMap()
86+
)
87+
assertEquals(
88+
message.mapUint64Uint64,
89+
restored.mapUint64Uint64Map.map { it.key.toULong() to it.value.toULong() }.toMap()
90+
)
91+
assertEquals(message.mapInt32Float, restored.mapInt32FloatMap)
92+
assertEquals(message.mapInt32Double, restored.mapInt32DoubleMap)
93+
assertEquals(message.mapBoolBool, restored.mapBoolBoolMap)
94+
assertEquals(message.mapStringString, restored.mapStringStringMap)
95+
assertContentEquals(
96+
message.mapStringBytes.mapValues { it.value.toString(Charsets.UTF_32) }.entries.toList(),
97+
restored.mapStringBytesMap.mapValues { it.value.toByteArray().toString(Charsets.UTF_32) }.entries.toList()
98+
)
99+
assertEquals(
100+
message.mapStringNestedMessage.mapValues { it.value.toProto() },
101+
restored.mapStringNestedMessageMap
102+
)
103+
assertEquals(
104+
message.mapStringForeignMessage.mapValues { it.value.toProto() },
105+
restored.mapStringForeignMessageMap
106+
)
107+
assertEquals(
108+
message.mapStringNestedEnum.mapValues { it.value.name },
109+
restored.mapStringNestedEnumMap.mapValues { it.value.name },
110+
)
111+
assertEquals(
112+
message.mapStringForeignEnum.mapValues { it.value.name },
113+
restored.mapStringForeignEnumMap.mapValues { it.value.name }
114+
)
115+
116+
val restoredMessage = ProtoBuf.decodeFromByteArray<KTestMessagesProto3Map>(restored.toByteArray())
117+
assertEquals(message.copy(mapStringBytes = mapOf()), restoredMessage.copy(mapStringBytes = mapOf()))
118+
}
119+
120+
@Test
121+
@Ignore
122+
// Issue: https://github.com/Kotlin/kotlinx.serialization/issues/2417
123+
fun signedAndFixed() {
124+
val message = KTestMessagesProto3Map(
125+
mapSint32Sint32 = Gen.map(Gen.int(), Gen.int()).generate(),
126+
mapSint64Sint64 = Gen.map(Gen.long(), Gen.long()).generate(),
127+
mapFixed32Fixed32 = Gen.map(Gen.int(), Gen.int()).generate(),
128+
mapFixed64Fixed64 = Gen.map(Gen.long(), Gen.long()).generate(),
129+
mapSfixed32Sfixed32 = Gen.map(Gen.int(), Gen.int()).generate(),
130+
mapSfixed64Sfixed64 = Gen.map(Gen.long(), Gen.long()).generate(),
131+
)
132+
133+
val bytes = ProtoBuf.encodeToByteArray(message)
134+
val restored = TestMessagesProto3.TestAllTypesProto3.parseFrom(bytes)
135+
136+
137+
assertContentEquals(message.mapSint32Sint32.entries.toList(), restored.mapSint32Sint32Map.entries.toList())
138+
assertContentEquals(message.mapSint64Sint64.entries.toList(), restored.mapSint64Sint64Map.entries.toList())
139+
assertContentEquals(message.mapFixed32Fixed32.entries.toList(), restored.mapFixed32Fixed32Map.entries.toList())
140+
assertContentEquals(message.mapFixed64Fixed64.entries.toList(), restored.mapFixed64Fixed64Map.entries.toList())
141+
assertContentEquals(
142+
message.mapSfixed32Sfixed32.entries.toList(),
143+
restored.mapSfixed32Sfixed32Map.entries.toList()
144+
)
145+
assertContentEquals(
146+
message.mapSfixed64Sfixed64.entries.toList(),
147+
restored.mapSfixed64Sfixed64Map.entries.toList()
148+
)
149+
150+
151+
val restoredMessage = ProtoBuf.decodeFromByteArray<KTestMessagesProto3Map>(restored.toByteArray())
152+
assertEquals(message, restoredMessage)
153+
}
154+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*
2+
* Copyright 2017-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
5+
package kotlinx.serialization.protobuf.conformance
6+
7+
import com.google.protobuf_test_messages.proto3.*
8+
import kotlinx.serialization.*
9+
import kotlinx.serialization.protobuf.*
10+
import kotlin.test.*
11+
12+
@Serializable
13+
data class KTestMessagesProto3Message(
14+
@ProtoNumber(18) val optionalNestedMessage: KNestedMessage? = null,
15+
@ProtoNumber(19) val optionalForeignMessage: KForeignMessage? = null,
16+
) {
17+
@Serializable
18+
data class KNestedMessage(
19+
@ProtoNumber(1) val a: Int = 0,
20+
@ProtoNumber(2) val corecursive: KTestMessagesProto3Message? = null,
21+
) {
22+
fun toProto(): TestMessagesProto3.TestAllTypesProto3.NestedMessage =
23+
TestMessagesProto3.TestAllTypesProto3.NestedMessage.parseFrom(
24+
ProtoBuf.encodeToByteArray(this)
25+
)
26+
}
27+
}
28+
29+
@Serializable
30+
data class KForeignMessage(
31+
@ProtoNumber(1) val c: Int = 0,
32+
) {
33+
fun toProto(): TestMessagesProto3.ForeignMessage =
34+
TestMessagesProto3.ForeignMessage.parseFrom(
35+
ProtoBuf.encodeToByteArray(this)
36+
)
37+
}
38+
39+
class Proto3MessageTest {
40+
@Test
41+
fun default() {
42+
val message = KTestMessagesProto3Message(
43+
optionalNestedMessage = KTestMessagesProto3Message.KNestedMessage(
44+
a = 150,
45+
corecursive = KTestMessagesProto3Message(
46+
optionalNestedMessage = KTestMessagesProto3Message.KNestedMessage(
47+
a = 42,
48+
)
49+
)
50+
),
51+
optionalForeignMessage = KForeignMessage(
52+
c = 150,
53+
)
54+
)
55+
56+
val bytes = ProtoBuf.encodeToByteArray(message)
57+
val restored = TestMessagesProto3.TestAllTypesProto3.parseFrom(bytes)
58+
assertEquals(message.optionalNestedMessage?.a, restored.optionalNestedMessage.a)
59+
assertEquals(
60+
message.optionalNestedMessage?.corecursive?.optionalNestedMessage?.a,
61+
restored.optionalNestedMessage.corecursive.optionalNestedMessage.a
62+
)
63+
assertEquals(message.optionalForeignMessage?.c, restored.optionalForeignMessage.c)
64+
}
65+
}

0 commit comments

Comments
 (0)