13
13
* See the License for the specific language governing permissions and
14
14
* limitations under the License.
15
15
*/
16
-
17
- @file:OptIn(ExperimentalSerializationApi ::class )
18
-
19
16
package com.google.firebase.dataconnect
20
17
21
18
import com.google.firebase.dataconnect.testutil.shouldBe
22
19
import com.google.firebase.dataconnect.testutil.shouldBeDefaultInstance
23
20
import com.google.firebase.dataconnect.testutil.shouldContainWithNonAbuttingText
24
21
import com.google.firebase.dataconnect.util.ProtoUtil.buildStructProto
25
22
import com.google.firebase.dataconnect.util.ProtoUtil.encodeToStruct
23
+ import com.google.firebase.dataconnect.util.ProtoUtil.toListValueProto
26
24
import com.google.protobuf.Struct
27
25
import io.kotest.assertions.throwables.shouldThrow
28
- import kotlinx.serialization.ExperimentalSerializationApi
26
+ import io.kotest.property.Arb
27
+ import io.kotest.property.arbitrary.arbitrary
28
+ import io.kotest.property.arbitrary.boolean
29
+ import io.kotest.property.arbitrary.double
30
+ import io.kotest.property.arbitrary.int
31
+ import io.kotest.property.arbitrary.list
32
+ import io.kotest.property.arbitrary.next
33
+ import io.kotest.property.arbitrary.orNull
34
+ import io.kotest.property.arbitrary.string
35
+ import io.kotest.property.checkAll
36
+ import kotlinx.coroutines.test.runTest
29
37
import kotlinx.serialization.Serializable
30
38
import org.junit.Test
31
39
32
40
class ProtoStructEncoderUnitTest {
33
41
34
42
@Test
35
43
fun `encodeToStruct() should throw if a NUMBER_VALUE is produced` () {
36
- val exception = shouldThrow<IllegalArgumentException > { encodeToStruct(42 ) }
44
+ val intValue: Int = Arb .int().next()
45
+ val exception = shouldThrow<IllegalArgumentException > { encodeToStruct(intValue) }
37
46
exception.message shouldContainWithNonAbuttingText " NUMBER_VALUE"
38
47
}
39
48
40
49
@Test
41
50
fun `encodeToStruct() should throw if a BOOL_VALUE is produced` () {
42
- val exception = shouldThrow<IllegalArgumentException > { encodeToStruct(true ) }
51
+ val booleanValue: Boolean = Arb .boolean().next()
52
+ val exception = shouldThrow<IllegalArgumentException > { encodeToStruct(booleanValue) }
43
53
exception.message shouldContainWithNonAbuttingText " BOOL_VALUE"
44
54
}
45
55
46
56
@Test
47
57
fun `encodeToStruct() should throw if a STRING_VALUE is produced` () {
48
- val exception =
49
- shouldThrow<IllegalArgumentException > { encodeToStruct(" arbitrary string value " ) }
58
+ val stringValue : String = Arb .string().next()
59
+ val exception = shouldThrow<IllegalArgumentException > { encodeToStruct(stringValue ) }
50
60
exception.message shouldContainWithNonAbuttingText " STRING_VALUE"
51
61
}
52
62
53
63
@Test
54
64
fun `encodeToStruct() should throw if a LIST_VALUE is produced` () {
55
- val exception =
56
- shouldThrow<IllegalArgumentException > { encodeToStruct(listOf ( " element1 " , " element2 " ) ) }
65
+ val listValue : List < String > = Arb .list( Arb .string( 5 .. 10 ), 1 .. 10 ).next()
66
+ val exception = shouldThrow<IllegalArgumentException > { encodeToStruct(listValue ) }
57
67
exception.message shouldContainWithNonAbuttingText " LIST_VALUE"
58
68
}
59
69
@@ -70,109 +80,79 @@ class ProtoStructEncoderUnitTest {
70
80
}
71
81
72
82
@Test
73
- fun `encodeToStruct() should encode an class with all primitive types` () {
83
+ fun `encodeToStruct() should encode an class with all primitive types` () = runTest {
74
84
@Serializable
75
85
data class TestData (
76
86
val iv : Int ,
77
87
val dv : Double ,
78
- val bvt : Boolean ,
79
- val bvf : Boolean ,
88
+ val bv : Boolean ,
80
89
val sv : String ,
81
- val nsvn : String? ,
82
- val nsvnn : String?
90
+ val svn : String? ,
83
91
)
84
- val encodedStruct =
85
- encodeToStruct(
86
- TestData (
87
- iv = 42 ,
88
- dv = 1234.5 ,
89
- bvt = true ,
90
- bvf = false ,
91
- sv = " blah blah" ,
92
- nsvn = null ,
93
- nsvnn = " I'm not null"
94
- )
95
- )
96
-
97
- encodedStruct.shouldBe(
98
- buildStructProto {
99
- put(" iv" , 42.0 )
100
- put(" dv" , 1234.5 )
101
- put(" bvt" , true )
102
- put(" bvf" , false )
103
- put(" sv" , " blah blah" )
104
- putNull(" nsvn" )
105
- put(" nsvnn" , " I'm not null" )
92
+ val arb: Arb <Pair <TestData , Struct >> = arbitrary {
93
+ val iv = Arb .int().bind()
94
+ val dv = Arb .double().bind()
95
+ val bv = Arb .boolean().bind()
96
+ val sv = Arb .string().bind()
97
+ val svn = Arb .string().orNull(0.33 ).bind()
98
+
99
+ val testData = TestData (iv = iv, dv = dv, bv = bv, sv = sv, svn = svn)
100
+
101
+ val struct = buildStructProto {
102
+ put(" iv" , iv)
103
+ put(" dv" , dv)
104
+ put(" bv" , bv)
105
+ put(" sv" , sv)
106
+ if (svn == = null ) {
107
+ putNull(" svn" )
108
+ } else {
109
+ put(" svn" , svn)
110
+ }
106
111
}
107
- )
112
+
113
+ Pair (testData, struct)
114
+ }
115
+
116
+ checkAll(arb) { (testData, expectedStruct) ->
117
+ val encodedStruct = encodeToStruct(testData)
118
+ encodedStruct shouldBe expectedStruct
119
+ }
108
120
}
109
121
110
122
@Test
111
- fun `encodeToStruct() should encode lists with all primitive types` () {
123
+ fun `encodeToStruct() should encode lists with all primitive types` () = runTest {
112
124
@Serializable
113
125
data class TestData (
114
126
val iv : List <Int >,
115
127
val dv : List <Double >,
116
128
val bv : List <Boolean >,
117
129
val sv : List <String >,
118
- val nsv : List <String ?>
130
+ val svn : List <String ?>
119
131
)
120
- val encodedStruct =
121
- encodeToStruct(
122
- TestData (
123
- iv = listOf (42 , 43 ),
124
- dv = listOf (1234.5 , 5678.9 ),
125
- bv = listOf (true , false , false , true ),
126
- sv = listOf (" abcde" , " fghij" ),
127
- nsv = listOf (" klmno" , null , " pqrst" , null )
128
- )
129
- )
130
-
131
- encodedStruct.shouldBe(
132
- buildStructProto {
133
- putList(" iv" ) {
134
- add(42.0 )
135
- add(43.0 )
136
- }
137
- putList(" dv" ) {
138
- add(1234.5 )
139
- add(5678.9 )
140
- }
141
- putList(" bv" ) {
142
- add(true )
143
- add(false )
144
- add(false )
145
- add(true )
146
- }
147
- putList(" sv" ) {
148
- add(" abcde" )
149
- add(" fghij" )
150
- }
151
- putList(" nsv" ) {
152
- add(" klmno" )
153
- addNull()
154
- add(" pqrst" )
155
- addNull()
156
- }
132
+ val arb: Arb <Pair <TestData , Struct >> = arbitrary {
133
+ val iv = Arb .list(Arb .int()).bind()
134
+ val dv = Arb .list(Arb .double()).bind()
135
+ val bv = Arb .list(Arb .boolean()).bind()
136
+ val sv = Arb .list(Arb .string()).bind()
137
+ val svn = Arb .list(Arb .string().orNull(0.33 )).bind()
138
+
139
+ val testData = TestData (iv = iv, dv = dv, bv = bv, sv = sv, svn = svn)
140
+
141
+ val struct = buildStructProto {
142
+ put(" iv" , iv.map { it.toDouble() }.toListValueProto())
143
+ put(" dv" , dv.toListValueProto())
144
+ put(" bv" , bv.toListValueProto())
145
+ put(" sv" , sv.toListValueProto())
146
+ put(" svn" , svn.toListValueProto())
157
147
}
158
- )
159
- }
160
148
161
- @Test
162
- fun `encodeToStruct() should support nested composite types` () {
163
- @Serializable data class TestData3 (val s : String )
164
- @Serializable data class TestData2 (val data3 : TestData3 , val data3N : TestData3 ? )
165
- @Serializable data class TestData1 (val data2 : TestData2 )
166
- val encodedStruct = encodeToStruct(TestData1 (TestData2 (TestData3 (" zzzz" ), null )))
167
-
168
- encodedStruct.shouldBe(
169
- buildStructProto {
170
- putStruct(" data2" ) {
171
- putNull(" data3N" )
172
- putStruct(" data3" ) { put(" s" , " zzzz" ) }
173
- }
174
- }
175
- )
149
+ Pair (testData, struct)
150
+ }
151
+
152
+ checkAll(arb) { (testData, expectedStruct) ->
153
+ val encodedStruct = encodeToStruct(testData)
154
+ encodedStruct shouldBe expectedStruct
155
+ }
176
156
}
177
157
178
158
@Test
@@ -194,29 +174,45 @@ class ProtoStructEncoderUnitTest {
194
174
}
195
175
196
176
@Test
197
- fun `encodeToStruct() should support OptionalVariable Value when T is not nullable` () {
198
- @Serializable data class TestData (val s : OptionalVariable <String >)
199
-
200
- val encodedStruct = encodeToStruct(TestData (OptionalVariable .Value (" Hello" )))
201
-
202
- encodedStruct shouldBe buildStructProto { put(" s" , " Hello" ) }
203
- }
204
-
205
- @Test
206
- fun `encodeToStruct() should support OptionalVariable Value when T is nullable but not null` () {
207
- @Serializable data class TestData (val s : OptionalVariable <String ?>)
208
-
209
- val encodedStruct = encodeToStruct(TestData (OptionalVariable .Value (" World" )))
210
-
211
- encodedStruct shouldBe buildStructProto { put(" s" , " World" ) }
177
+ fun `encodeToStruct() should support OptionalVariable Value when T is not nullable` () = runTest {
178
+ @Serializable
179
+ data class TestData (val s : OptionalVariable <String >, val i : OptionalVariable <Int >)
180
+ val arb = arbitrary {
181
+ val s = OptionalVariable .Value (Arb .string().bind())
182
+ val i = OptionalVariable .Value (Arb .int().bind())
183
+ TestData (s, i)
184
+ }
185
+
186
+ checkAll(arb) { testData ->
187
+ val encodedStruct = encodeToStruct(testData)
188
+ val expected = buildStructProto {
189
+ put(" s" , testData.s.valueOrThrow())
190
+ put(" i" , testData.i.valueOrThrow())
191
+ }
192
+ encodedStruct shouldBe expected
193
+ }
212
194
}
213
195
214
196
@Test
215
- fun `encodeToStruct() should support OptionalVariable Value when T is nullable and null` () {
216
- @Serializable data class TestData (val s : OptionalVariable <String ?>)
217
-
218
- val encodedStruct = encodeToStruct(TestData (OptionalVariable .Value (null )))
219
-
220
- encodedStruct shouldBe buildStructProto { putNull(" s" ) }
197
+ fun `encodeToStruct() should support OptionalVariable Value when T is nullable` () = runTest {
198
+ @Serializable
199
+ data class TestData (
200
+ val s : OptionalVariable <String ?>,
201
+ val i : OptionalVariable <Int ?>,
202
+ )
203
+ val arb = arbitrary {
204
+ val s = OptionalVariable .Value (Arb .string().orNull(0.33 ).bind())
205
+ val i = OptionalVariable .Value (Arb .int().orNull(0.33 ).bind())
206
+ TestData (s, i)
207
+ }
208
+
209
+ checkAll(arb) { testData ->
210
+ val encodedStruct = encodeToStruct(testData)
211
+ val expected = buildStructProto {
212
+ put(" s" , testData.s.valueOrThrow())
213
+ put(" i" , testData.i.valueOrThrow())
214
+ }
215
+ encodedStruct shouldBe expected
216
+ }
221
217
}
222
218
}
0 commit comments