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 KTestMessagesProto3Repeated(
15     @ProtoNumber(31) @ProtoPacked val repeatedInt32: List<Int> = emptyList(),
16     @ProtoNumber(32) @ProtoPacked val repeatedInt64: List<Long> = emptyList(),
17     @ProtoNumber(33) @ProtoPacked val repeatedUint32: List<UInt> = emptyList(),
18     @ProtoNumber(34) @ProtoPacked val repeatedUint64: List<ULong> = emptyList(),
19     @ProtoNumber(35) @ProtoPacked val repeatedSint32: List<Int> = emptyList(),
20     @ProtoNumber(36) @ProtoPacked val repeatedSint64: List<Long> = emptyList(),
21     @ProtoNumber(37) @ProtoPacked val repeatedFixed32: List<Int> = emptyList(),
22     @ProtoNumber(38) @ProtoPacked val repeatedFixed64: List<Long> = emptyList(),
23     @ProtoNumber(39) @ProtoPacked val repeatedSfixed32: List<Int> = emptyList(),
24     @ProtoNumber(40) @ProtoPacked val repeatedSfixed64: List<Long> = emptyList(),
25     @ProtoNumber(41) @ProtoPacked val repeatedFloat: List<Float> = emptyList(),
26     @ProtoNumber(42) @ProtoPacked val repeatedDouble: List<Double> = emptyList(),
27     @ProtoNumber(43) @ProtoPacked val repeatedBool: List<Boolean> = emptyList(),
28     @ProtoNumber(44) val repeatedString: List<String> = emptyList(),
29     @ProtoNumber(45) val repeatedBytes: List<ByteArray> = emptyList(),
30     @ProtoNumber(48) val repeatedNestedMessages: List<KTestMessagesProto3Message.KNestedMessage> = emptyList(),
31     @ProtoNumber(49) val repeatedForeignMessages: List<KForeignMessage> = emptyList(),
32 )
33 
34 class Proto3RepeatedTest {
35     @Test
defaultnull36     fun default() {
37         val message = KTestMessagesProto3Repeated(
38             repeatedInt32 = Gen.list(Gen.int()).generate(),
39             repeatedInt64 = Gen.list(Gen.long()).generate(),
40             repeatedFloat = Gen.list(Gen.float()).generate(),
41             repeatedDouble = Gen.list(Gen.double()).generate(),
42             repeatedBool = Gen.list(Gen.bool()).generate(),
43             repeatedString = Gen.list(Gen.string()).generate(),
44             repeatedBytes = Gen.list(Gen.string().map { it.toByteArray() }).generate(),
45             repeatedNestedMessages = listOf(
46                 KTestMessagesProto3Message.KNestedMessage(
47                     1,
48                     null
49                 ),
50                 KTestMessagesProto3Message.KNestedMessage(
51                     2,
52                     KTestMessagesProto3Message(
53                         KTestMessagesProto3Message.KNestedMessage(3, null),
54                     )
55                 )
56             ),
57             repeatedForeignMessages = listOf(
58                 KForeignMessage(1),
59                 KForeignMessage(-12),
60             )
61         )
62 
63         val bytes = ProtoBuf.encodeToByteArray(message)
64         val restored = TestMessagesProto3.TestAllTypesProto3.parseFrom(bytes)
65 
66         assertEquals(message.repeatedInt32, restored.repeatedInt32List)
67         assertEquals(message.repeatedInt64, restored.repeatedInt64List)
68         assertEquals(message.repeatedFloat, restored.repeatedFloatList)
69         assertEquals(message.repeatedDouble, restored.repeatedDoubleList)
70         assertEquals(message.repeatedBool, restored.repeatedBoolList)
71         assertEquals(message.repeatedString, restored.repeatedStringList)
72         assertEquals(message.repeatedNestedMessages.map { it.toProto() }, restored.repeatedNestedMessageList)
73         assertEquals(message.repeatedForeignMessages.map { it.toProto() }, restored.repeatedForeignMessageList)
74         assertEquals(message.repeatedBytes.map { it.toList() }, restored.repeatedBytesList.map { it.toList() })
75 
76         val restoredMessage = ProtoBuf.decodeFromByteArray<KTestMessagesProto3Repeated>(restored.toByteArray())
77         // [equals] method is not implemented for [ByteArray] so we need to compare it separately.
78         assertEquals(message, restoredMessage.copy(repeatedBytes = message.repeatedBytes))
79         assertContentEquals(
80             message.repeatedBytes.flatMap { it.toList() },
81             restoredMessage.repeatedBytes.flatMap { it.toList() },
82         )
83     }
84 
85     @Test
86     @Ignore
87     // Issue: https://github.com/Kotlin/kotlinx.serialization/issues/2419
signedAndFixednull88     fun signedAndFixed() {
89         val message = KTestMessagesProto3Repeated(
90             repeatedSint32 = Gen.list(Gen.int()).generate(),
91             repeatedSint64 = Gen.list(Gen.long()).generate(),
92             repeatedFixed32 = Gen.list(Gen.int()).generate(),
93             repeatedFixed64 = Gen.list(Gen.long()).generate(),
94             repeatedSfixed32 = Gen.list(Gen.int()).generate(),
95             repeatedSfixed64 = Gen.list(Gen.long()).generate(),
96         )
97 
98         val bytes = ProtoBuf.encodeToByteArray(message)
99         val restored = TestMessagesProto3.TestAllTypesProto3.parseFrom(bytes)
100 
101         assertEquals(message.repeatedUint32, restored.repeatedUint32List.map { it.toUInt() })
102         assertEquals(message.repeatedUint64, restored.repeatedUint64List.map { it.toULong() })
103         assertEquals(message.repeatedSint32, restored.repeatedSint32List)
104         assertEquals(message.repeatedSint64, restored.repeatedSint64List)
105         assertEquals(message.repeatedFixed32, restored.repeatedFixed32List)
106         assertEquals(message.repeatedFixed64, restored.repeatedFixed64List)
107         assertEquals(message.repeatedSfixed32, restored.repeatedSfixed32List)
108         assertEquals(message.repeatedSfixed64, restored.repeatedSfixed64List)
109 
110         val restoredMessage = ProtoBuf.decodeFromByteArray<KTestMessagesProto3Repeated>(restored.toByteArray())
111         assertEquals(message, restoredMessage)
112     }
113 
114 
115     @Test
116     @Ignore
117     // Issue: https://github.com/Kotlin/kotlinx.serialization/issues/2418
unsignednull118     fun unsigned() {
119         val message = KTestMessagesProto3Repeated(
120             repeatedUint32 = Gen.list(Gen.int().map { it.toUInt() }).generate(),
121             repeatedUint64 = Gen.list(Gen.long().map { it.toULong() }).generate(),
122         )
123 
124         val bytes = ProtoBuf.encodeToByteArray(message)
125         val restored = TestMessagesProto3.TestAllTypesProto3.parseFrom(bytes)
126 
127         assertEquals(message.repeatedUint32, restored.repeatedUint32List.map { it.toUInt() })
128         assertEquals(message.repeatedUint64, restored.repeatedUint64List.map { it.toULong() })
129 
130         val restoredMessage = ProtoBuf.decodeFromByteArray<KTestMessagesProto3Repeated>(restored.toByteArray())
131         assertEquals(message, restoredMessage)
132     }
133 }
134