1 /*
2  * Copyright 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package androidx.navigation.serialization
18 
19 import android.os.Bundle
20 import android.os.Parcel
21 import android.os.Parcelable
22 import androidx.navigation.CollectionNavType
23 import androidx.navigation.NamedNavArgument
24 import androidx.navigation.NavArgument
25 import androidx.navigation.NavType
26 import androidx.navigation.navArgument
27 import com.google.common.truth.Truth.assertThat
28 import kotlin.reflect.typeOf
29 import kotlin.test.assertFailsWith
30 import kotlin.test.fail
31 import kotlinx.serialization.SerialName
32 import kotlinx.serialization.Serializable
33 import kotlinx.serialization.SerializationException
34 import kotlinx.serialization.serializer
35 import org.junit.Test
36 import org.junit.runner.RunWith
37 import org.junit.runners.JUnit4
38 
39 @RunWith(JUnit4::class)
40 class NavArgumentGeneratorTest {
41     @Test
convertToIntnull42     fun convertToInt() {
43         @Serializable class TestClass(val arg: Int)
44 
45         val converted = serializer<TestClass>().generateNavArguments()
46         val expected =
47             navArgument("arg") {
48                 type = NavType.IntType
49                 nullable = false
50             }
51         assertThat(converted).containsExactlyInOrder(expected)
52         assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
53     }
54 
55     @Test
convertToIntNullablenull56     fun convertToIntNullable() {
57         @Serializable class TestClass(val arg: Int?)
58 
59         val converted = serializer<TestClass>().generateNavArguments()
60         val expected =
61             navArgument("arg") {
62                 type = InternalNavType.IntNullableType
63                 nullable = true
64             }
65         assertThat(converted).containsExactlyInOrder(expected)
66         assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
67     }
68 
69     @Test
convertToStringnull70     fun convertToString() {
71         @Serializable class TestClass(val arg: String)
72 
73         val converted = serializer<TestClass>().generateNavArguments()
74         val expected =
75             navArgument("arg") {
76                 type = InternalNavType.StringNonNullableType
77                 nullable = false
78             }
79         assertThat(converted).containsExactlyInOrder(expected)
80         assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
81     }
82 
83     @Test
convertToStringNullablenull84     fun convertToStringNullable() {
85         @Serializable class TestClass(val arg: String?)
86 
87         val converted = serializer<TestClass>().generateNavArguments()
88         val expected =
89             navArgument("arg") {
90                 type = NavType.StringType
91                 nullable = true
92             }
93         assertThat(converted).containsExactlyInOrder(expected)
94         assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
95     }
96 
97     @Test
convertToBooleannull98     fun convertToBoolean() {
99         @Serializable class TestClass(val arg: Boolean)
100 
101         val converted = serializer<TestClass>().generateNavArguments()
102         val expected =
103             navArgument("arg") {
104                 type = NavType.BoolType
105                 nullable = false
106             }
107         assertThat(converted).containsExactlyInOrder(expected)
108         assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
109     }
110 
111     @Test
convertToBooleanNullablenull112     fun convertToBooleanNullable() {
113         @Serializable class TestClass(val arg: Boolean?)
114 
115         val converted = serializer<TestClass>().generateNavArguments()
116         val expected =
117             navArgument("arg") {
118                 type = InternalNavType.BoolNullableType
119                 nullable = true
120             }
121         assertThat(converted).containsExactlyInOrder(expected)
122         assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
123     }
124 
125     @Test
convertToDoublenull126     fun convertToDouble() {
127         @Serializable class TestClass(val arg: Double)
128 
129         val converted = serializer<TestClass>().generateNavArguments()
130         val expected =
131             navArgument("arg") {
132                 type = InternalNavType.DoubleType
133                 nullable = false
134             }
135         assertThat(converted).containsExactlyInOrder(expected)
136         assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
137     }
138 
139     @Test
convertToDoubleNullablenull140     fun convertToDoubleNullable() {
141         @Serializable class TestClass(val arg: Double?)
142 
143         val converted = serializer<TestClass>().generateNavArguments()
144         val expected =
145             navArgument("arg") {
146                 type = InternalNavType.DoubleNullableType
147                 nullable = true
148             }
149         assertThat(converted).containsExactlyInOrder(expected)
150         assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
151     }
152 
153     @Test
convertToFloatnull154     fun convertToFloat() {
155         @Serializable class TestClass(val arg: Float)
156 
157         val converted = serializer<TestClass>().generateNavArguments()
158         val expected =
159             navArgument("arg") {
160                 type = NavType.FloatType
161                 nullable = false
162             }
163         assertThat(converted).containsExactlyInOrder(expected)
164         assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
165     }
166 
167     @Test
convertToFloatNullablenull168     fun convertToFloatNullable() {
169         @Serializable class TestClass(val arg: Float?)
170 
171         val converted = serializer<TestClass>().generateNavArguments()
172         val expected =
173             navArgument("arg") {
174                 type = InternalNavType.FloatNullableType
175                 nullable = true
176             }
177         assertThat(converted).containsExactlyInOrder(expected)
178         assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
179     }
180 
181     @Test
convertToLongnull182     fun convertToLong() {
183         @Serializable class TestClass(val arg: Long)
184 
185         val converted = serializer<TestClass>().generateNavArguments()
186         val expected =
187             navArgument("arg") {
188                 type = NavType.LongType
189                 nullable = false
190             }
191         assertThat(converted).containsExactlyInOrder(expected)
192         assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
193     }
194 
195     @Test
convertToLongNullablenull196     fun convertToLongNullable() {
197         @Serializable class TestClass(val arg: Long?)
198 
199         val converted = serializer<TestClass>().generateNavArguments()
200         val expected =
201             navArgument("arg") {
202                 type = InternalNavType.LongNullableType
203                 nullable = true
204             }
205         assertThat(converted).containsExactlyInOrder(expected)
206         assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
207     }
208 
209     @Test
convertToIntArraynull210     fun convertToIntArray() {
211         @Serializable class TestClass(val arg: IntArray)
212 
213         val converted = serializer<TestClass>().generateNavArguments()
214         val expected =
215             navArgument("arg") {
216                 type = NavType.IntArrayType
217                 nullable = false
218             }
219         assertThat(converted).containsExactlyInOrder(expected)
220         assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
221     }
222 
223     @Test
convertToIntArrayNullablenull224     fun convertToIntArrayNullable() {
225         @Serializable class TestClass(val arg: IntArray?)
226 
227         val converted = serializer<TestClass>().generateNavArguments()
228         val expected =
229             navArgument("arg") {
230                 type = NavType.IntArrayType
231                 nullable = true
232             }
233         assertThat(converted).containsExactlyInOrder(expected)
234         assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
235     }
236 
237     @Test
convertToIntListnull238     fun convertToIntList() {
239         @Serializable class TestClass(val arg: List<Int>)
240 
241         val converted = serializer<TestClass>().generateNavArguments()
242         val expected =
243             navArgument("arg") {
244                 type = NavType.IntListType
245                 nullable = false
246             }
247         assertThat(converted).containsExactlyInOrder(expected)
248         assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
249     }
250 
251     @Test
convertArrayListToIntListnull252     fun convertArrayListToIntList() {
253         @Serializable class TestClass(val arg: ArrayList<Int>)
254 
255         val converted = serializer<TestClass>().generateNavArguments()
256         val expected =
257             navArgument("arg") {
258                 type = NavType.IntListType
259                 nullable = false
260             }
261         assertThat(converted).containsExactlyInOrder(expected)
262         assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
263     }
264 
265     @Test
convertToIntListNullablenull266     fun convertToIntListNullable() {
267         @Serializable class TestClass(val arg: List<Int>?)
268 
269         val converted = serializer<TestClass>().generateNavArguments()
270         val expected =
271             navArgument("arg") {
272                 type = NavType.IntListType
273                 nullable = true
274             }
275         assertThat(converted).containsExactlyInOrder(expected)
276         assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
277     }
278 
279     @Test
convertToLongArraynull280     fun convertToLongArray() {
281         @Serializable class TestClass(val arg: LongArray)
282 
283         val converted = serializer<TestClass>().generateNavArguments()
284         val expected =
285             navArgument("arg") {
286                 type = NavType.LongArrayType
287                 nullable = false
288             }
289         assertThat(converted).containsExactlyInOrder(expected)
290         assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
291     }
292 
293     @Test
convertToLongArrayNullablenull294     fun convertToLongArrayNullable() {
295         @Serializable class TestClass(val arg: LongArray?)
296 
297         val converted = serializer<TestClass>().generateNavArguments()
298         val expected =
299             navArgument("arg") {
300                 type = NavType.LongArrayType
301                 nullable = true
302             }
303         assertThat(converted).containsExactlyInOrder(expected)
304         assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
305     }
306 
307     @Test
convertToLongListnull308     fun convertToLongList() {
309         @Serializable class TestClass(val arg: List<Long>)
310 
311         val converted = serializer<TestClass>().generateNavArguments()
312         val expected =
313             navArgument("arg") {
314                 type = NavType.LongListType
315                 nullable = false
316             }
317         assertThat(converted).containsExactlyInOrder(expected)
318         assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
319     }
320 
321     @Test
convertArrayListToLongListnull322     fun convertArrayListToLongList() {
323         @Serializable class TestClass(val arg: ArrayList<Long>)
324 
325         val converted = serializer<TestClass>().generateNavArguments()
326         val expected =
327             navArgument("arg") {
328                 type = NavType.LongListType
329                 nullable = false
330             }
331         assertThat(converted).containsExactlyInOrder(expected)
332         assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
333     }
334 
335     @Test
convertToLongListNullablenull336     fun convertToLongListNullable() {
337         @Serializable class TestClass(val arg: List<Long>?)
338 
339         val converted = serializer<TestClass>().generateNavArguments()
340         val expected =
341             navArgument("arg") {
342                 type = NavType.LongListType
343                 nullable = true
344             }
345         assertThat(converted).containsExactlyInOrder(expected)
346         assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
347     }
348 
349     @Test
convertToFloatArraynull350     fun convertToFloatArray() {
351         @Serializable class TestClass(val arg: FloatArray)
352 
353         val converted = serializer<TestClass>().generateNavArguments()
354         val expected =
355             navArgument("arg") {
356                 type = NavType.FloatArrayType
357                 nullable = false
358             }
359         assertThat(converted).containsExactlyInOrder(expected)
360         assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
361     }
362 
363     @Test
convertToFloatArrayNullablenull364     fun convertToFloatArrayNullable() {
365         @Serializable class TestClass(val arg: FloatArray?)
366 
367         val converted = serializer<TestClass>().generateNavArguments()
368         val expected =
369             navArgument("arg") {
370                 type = NavType.FloatArrayType
371                 nullable = true
372             }
373         assertThat(converted).containsExactlyInOrder(expected)
374         assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
375     }
376 
377     @Test
convertToFloatListnull378     fun convertToFloatList() {
379         @Serializable class TestClass(val arg: List<Float>)
380 
381         val converted = serializer<TestClass>().generateNavArguments()
382         val expected =
383             navArgument("arg") {
384                 type = NavType.FloatListType
385                 nullable = false
386             }
387         assertThat(converted).containsExactlyInOrder(expected)
388         assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
389     }
390 
391     @Test
convertArrayListToFloatListnull392     fun convertArrayListToFloatList() {
393         @Serializable class TestClass(val arg: ArrayList<Float>)
394 
395         val converted = serializer<TestClass>().generateNavArguments()
396         val expected =
397             navArgument("arg") {
398                 type = NavType.FloatListType
399                 nullable = false
400             }
401         assertThat(converted).containsExactlyInOrder(expected)
402         assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
403     }
404 
405     @Test
convertToFloatListNullablenull406     fun convertToFloatListNullable() {
407         @Serializable class TestClass(val arg: List<Float>?)
408 
409         val converted = serializer<TestClass>().generateNavArguments()
410         val expected =
411             navArgument("arg") {
412                 type = NavType.FloatListType
413                 nullable = true
414             }
415         assertThat(converted).containsExactlyInOrder(expected)
416         assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
417     }
418 
419     @Test
convertToBoolArraynull420     fun convertToBoolArray() {
421         @Serializable class TestClass(val arg: BooleanArray)
422 
423         val converted = serializer<TestClass>().generateNavArguments()
424         val expected =
425             navArgument("arg") {
426                 type = NavType.BoolArrayType
427                 nullable = false
428             }
429         assertThat(converted).containsExactlyInOrder(expected)
430         assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
431     }
432 
433     @Test
convertToBoolArrayNullablenull434     fun convertToBoolArrayNullable() {
435         @Serializable class TestClass(val arg: BooleanArray?)
436 
437         val converted = serializer<TestClass>().generateNavArguments()
438         val expected =
439             navArgument("arg") {
440                 type = NavType.BoolArrayType
441                 nullable = true
442             }
443         assertThat(converted).containsExactlyInOrder(expected)
444         assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
445     }
446 
447     @Test
convertToBooleanListnull448     fun convertToBooleanList() {
449         @Serializable class TestClass(val arg: List<Boolean>)
450 
451         val converted = serializer<TestClass>().generateNavArguments()
452         val expected =
453             navArgument("arg") {
454                 type = NavType.BoolListType
455                 nullable = false
456             }
457         assertThat(converted).containsExactlyInOrder(expected)
458         assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
459     }
460 
461     @Test
convertArrayListToBooleanListnull462     fun convertArrayListToBooleanList() {
463         @Serializable class TestClass(val arg: ArrayList<Boolean>)
464 
465         val converted = serializer<TestClass>().generateNavArguments()
466         val expected =
467             navArgument("arg") {
468                 type = NavType.BoolListType
469                 nullable = false
470             }
471         assertThat(converted).containsExactlyInOrder(expected)
472         assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
473     }
474 
475     @Test
convertToBooleanListNullablenull476     fun convertToBooleanListNullable() {
477         @Serializable class TestClass(val arg: List<Boolean>?)
478 
479         val converted = serializer<TestClass>().generateNavArguments()
480         val expected =
481             navArgument("arg") {
482                 type = NavType.BoolListType
483                 nullable = true
484             }
485         assertThat(converted).containsExactlyInOrder(expected)
486         assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
487     }
488 
489     @Test
convertToDoubleArraynull490     fun convertToDoubleArray() {
491         @Serializable class TestClass(val arg: DoubleArray)
492 
493         val converted = serializer<TestClass>().generateNavArguments()
494         val expected =
495             navArgument("arg") {
496                 type = InternalNavType.DoubleArrayType
497                 nullable = false
498             }
499         assertThat(converted).containsExactlyInOrder(expected)
500         assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
501     }
502 
503     @Test
convertToDoubleArrayNullablenull504     fun convertToDoubleArrayNullable() {
505         @Serializable class TestClass(val arg: DoubleArray?)
506 
507         val converted = serializer<TestClass>().generateNavArguments()
508         val expected =
509             navArgument("arg") {
510                 type = InternalNavType.DoubleArrayType
511                 nullable = true
512             }
513         assertThat(converted).containsExactlyInOrder(expected)
514         assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
515     }
516 
517     @Test
convertToDoubleListnull518     fun convertToDoubleList() {
519         @Serializable class TestClass(val arg: List<Double>)
520 
521         val converted = serializer<TestClass>().generateNavArguments()
522         val expected =
523             navArgument("arg") {
524                 type = InternalNavType.DoubleListType
525                 nullable = false
526             }
527         assertThat(converted).containsExactlyInOrder(expected)
528         assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
529     }
530 
531     @Test
convertToDoubleListNullablenull532     fun convertToDoubleListNullable() {
533         @Serializable class TestClass(val arg: List<Double>?)
534 
535         val converted = serializer<TestClass>().generateNavArguments()
536         val expected =
537             navArgument("arg") {
538                 type = InternalNavType.DoubleListType
539                 nullable = true
540             }
541         assertThat(converted).containsExactlyInOrder(expected)
542         assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
543     }
544 
545     @Test
convertToStringArraynull546     fun convertToStringArray() {
547         @Serializable class TestClass(val arg: Array<String>)
548 
549         val converted = serializer<TestClass>().generateNavArguments()
550         val expected =
551             navArgument("arg") {
552                 type = NavType.StringArrayType
553                 nullable = false
554             }
555         assertThat(converted).containsExactlyInOrder(expected)
556         assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
557     }
558 
559     @Test
convertToStringArrayNullablenull560     fun convertToStringArrayNullable() {
561         @Serializable class TestClass(val arg: Array<String>?)
562 
563         val converted = serializer<TestClass>().generateNavArguments()
564         val expected =
565             navArgument("arg") {
566                 type = NavType.StringArrayType
567                 nullable = true
568             }
569         assertThat(converted).containsExactlyInOrder(expected)
570         assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
571     }
572 
573     @Test
convertToStringNullableArrayNullablenull574     fun convertToStringNullableArrayNullable() {
575         @Serializable class TestClass(val arg: Array<String?>?)
576 
577         val converted = serializer<TestClass>().generateNavArguments()
578         val expected =
579             navArgument("arg") {
580                 type = InternalNavType.StringNullableArrayType
581                 nullable = true
582             }
583         assertThat(converted).containsExactlyInOrder(expected)
584         assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
585     }
586 
587     @Test
convertToStringListnull588     fun convertToStringList() {
589         @Serializable class TestClass(val arg: List<String>)
590 
591         val converted = serializer<TestClass>().generateNavArguments()
592         val expected =
593             navArgument("arg") {
594                 type = NavType.StringListType
595                 nullable = false
596             }
597         assertThat(converted).containsExactlyInOrder(expected)
598         assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
599     }
600 
601     @Test
convertToStringListNullablenull602     fun convertToStringListNullable() {
603         @Serializable class TestClass(val arg: List<String>?)
604 
605         val converted = serializer<TestClass>().generateNavArguments()
606         val expected =
607             navArgument("arg") {
608                 type = NavType.StringListType
609                 nullable = true
610             }
611         assertThat(converted).containsExactlyInOrder(expected)
612         assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
613     }
614 
615     @Test
convertToStringNullableListnull616     fun convertToStringNullableList() {
617         @Serializable class TestClass(val arg: List<String?>)
618         val converted = serializer<TestClass>().generateNavArguments()
619         val expected =
620             navArgument("arg") {
621                 type = InternalNavType.StringNullableListType
622                 nullable = false
623             }
624         assertThat(converted).containsExactlyInOrder(expected)
625         assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
626     }
627 
628     @Test
convertToStringNullableListNullablenull629     fun convertToStringNullableListNullable() {
630         @Serializable class TestClass(val arg: List<String?>?)
631         val converted = serializer<TestClass>().generateNavArguments()
632         val expected =
633             navArgument("arg") {
634                 type = InternalNavType.StringNullableListType
635                 nullable = true
636             }
637         assertThat(converted).containsExactlyInOrder(expected)
638         assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
639     }
640 
641     @Test
convertArrayListToStringListnull642     fun convertArrayListToStringList() {
643         @Serializable class TestClass(val arg: ArrayList<String>)
644 
645         val converted = serializer<TestClass>().generateNavArguments()
646         val expected =
647             navArgument("arg") {
648                 type = NavType.StringListType
649                 nullable = false
650             }
651         assertThat(converted).containsExactlyInOrder(expected)
652         assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
653     }
654 
655     @Test
convertToEnumListnull656     fun convertToEnumList() {
657         @Serializable class TestClass(val arg: List<TestEnum>)
658 
659         val converted = serializer<TestClass>().generateNavArguments()
660         val expected =
661             navArgument("arg") {
662                 type = InternalAndroidNavType.EnumListType(TestEnum::class.java)
663                 nullable = false
664             }
665         assertThat(converted).containsExactlyInOrder(expected)
666         assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
667     }
668 
669     @Test
convertToEnumListNullablenull670     fun convertToEnumListNullable() {
671         @Serializable class TestClass(val arg: List<TestEnum>?)
672 
673         val converted = serializer<TestClass>().generateNavArguments()
674         val expected =
675             navArgument("arg") {
676                 type = InternalAndroidNavType.EnumListType(TestEnum::class.java)
677                 nullable = true
678             }
679         assertThat(converted).containsExactlyInOrder(expected)
680         assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
681     }
682 
683     @Test
convertToParcelablenull684     fun convertToParcelable() {
685         @Serializable
686         class TestParcelable : Parcelable {
687             override fun describeContents() = 0
688 
689             override fun writeToParcel(dest: Parcel, flags: Int) {}
690         }
691 
692         @Serializable class TestClass(val arg: TestParcelable)
693 
694         val navType =
695             object : NavType<TestParcelable>(false) {
696                 override fun put(bundle: Bundle, key: String, value: TestParcelable) {}
697 
698                 override fun get(bundle: Bundle, key: String) = null
699 
700                 override fun parseValue(value: String) = TestParcelable()
701             }
702 
703         val converted =
704             serializer<TestClass>().generateNavArguments(mapOf(typeOf<TestParcelable>() to navType))
705         val expected =
706             navArgument("arg") {
707                 type = navType
708                 nullable = false
709             }
710         assertThat(converted).containsExactlyInOrder(expected)
711         assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
712     }
713 
714     @Test
convertToParcelableNullablenull715     fun convertToParcelableNullable() {
716         @Serializable
717         class TestParcelable : Parcelable {
718             override fun describeContents() = 0
719 
720             override fun writeToParcel(dest: Parcel, flags: Int) {}
721         }
722 
723         @Serializable class TestClass(val arg: TestParcelable?)
724 
725         val navType =
726             object : NavType<TestParcelable?>(true) {
727                 override fun put(bundle: Bundle, key: String, value: TestParcelable?) {}
728 
729                 override fun get(bundle: Bundle, key: String) = null
730 
731                 override fun parseValue(value: String) = TestParcelable()
732             }
733 
734         val converted =
735             serializer<TestClass>()
736                 .generateNavArguments(mapOf(typeOf<TestParcelable?>() to navType))
737         val expected =
738             navArgument("arg") {
739                 type = navType
740                 nullable = true
741             }
742         assertThat(converted).containsExactlyInOrder(expected)
743         assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
744     }
745 
746     @Test
convertToParcelableArraynull747     fun convertToParcelableArray() {
748         @Serializable
749         class TestParcelable : Parcelable {
750             override fun describeContents() = 0
751 
752             override fun writeToParcel(dest: Parcel, flags: Int) {}
753         }
754 
755         @Serializable class TestClass(val arg: Array<TestParcelable>)
756 
757         val navType =
758             object : NavType<Array<TestParcelable>>(false) {
759                 override fun put(bundle: Bundle, key: String, value: Array<TestParcelable>) {}
760 
761                 override fun get(bundle: Bundle, key: String) = null
762 
763                 override fun parseValue(value: String) = emptyArray<TestParcelable>()
764             }
765         val converted =
766             serializer<TestClass>()
767                 .generateNavArguments(mapOf(typeOf<Array<TestParcelable>>() to navType))
768         val expected =
769             navArgument("arg") {
770                 type = navType
771                 nullable = false
772             }
773         assertThat(converted).containsExactlyInOrder(expected)
774         assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
775     }
776 
777     @Test
convertToParcelableArrayNullablenull778     fun convertToParcelableArrayNullable() {
779         @Serializable
780         class TestParcelable : Parcelable {
781             override fun describeContents() = 0
782 
783             override fun writeToParcel(dest: Parcel, flags: Int) {}
784         }
785 
786         @Serializable class TestClass(val arg: Array<TestParcelable>?)
787 
788         val navType =
789             object : NavType<Array<TestParcelable>>(true) {
790                 override fun put(bundle: Bundle, key: String, value: Array<TestParcelable>) {}
791 
792                 override fun get(bundle: Bundle, key: String) = null
793 
794                 override fun parseValue(value: String) = emptyArray<TestParcelable>()
795             }
796         val converted =
797             serializer<TestClass>()
798                 .generateNavArguments(mapOf(typeOf<Array<TestParcelable>?>() to navType))
799         val expected =
800             navArgument("arg") {
801                 type = navType
802                 nullable = true
803             }
804         assertThat(converted).containsExactlyInOrder(expected)
805         assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
806     }
807 
808     @Test
convertToSerializablenull809     fun convertToSerializable() {
810         @Serializable class TestSerializable : java.io.Serializable
811 
812         @Serializable class TestClass(val arg: TestSerializable)
813 
814         val navType =
815             object : NavType<TestSerializable>(false) {
816                 override fun put(bundle: Bundle, key: String, value: TestSerializable) {}
817 
818                 override fun get(bundle: Bundle, key: String) = null
819 
820                 override fun parseValue(value: String) = TestSerializable()
821             }
822         val converted =
823             serializer<TestClass>()
824                 .generateNavArguments(mapOf(typeOf<TestSerializable>() to navType))
825         val expected =
826             navArgument("arg") {
827                 type = navType
828                 nullable = false
829             }
830         assertThat(converted).containsExactlyInOrder(expected)
831         assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
832     }
833 
834     @Test
convertToSerializableNullablenull835     fun convertToSerializableNullable() {
836         @Serializable class TestSerializable : java.io.Serializable
837 
838         @Serializable class TestClass(val arg: TestSerializable?)
839 
840         val navType =
841             object : NavType<TestSerializable>(true) {
842                 override fun put(bundle: Bundle, key: String, value: TestSerializable) {}
843 
844                 override fun get(bundle: Bundle, key: String) = null
845 
846                 override fun parseValue(value: String) = TestSerializable()
847             }
848         val converted =
849             serializer<TestClass>()
850                 .generateNavArguments(mapOf(typeOf<TestSerializable?>() to navType))
851         val expected =
852             navArgument("arg") {
853                 type = navType
854                 nullable = true
855             }
856         assertThat(converted).containsExactlyInOrder(expected)
857         assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
858     }
859 
860     @Test
convertToSerializableArraynull861     fun convertToSerializableArray() {
862         @Serializable class TestSerializable : java.io.Serializable
863 
864         @Serializable class TestClass(val arg: Array<TestSerializable>)
865 
866         val navType =
867             object : NavType<Array<TestSerializable>>(false) {
868                 override fun put(bundle: Bundle, key: String, value: Array<TestSerializable>) {}
869 
870                 override fun get(bundle: Bundle, key: String) = null
871 
872                 override fun parseValue(value: String) = emptyArray<TestSerializable>()
873             }
874         val converted =
875             serializer<TestClass>()
876                 .generateNavArguments(mapOf(typeOf<Array<TestSerializable>>() to navType))
877         val expected =
878             navArgument("arg") {
879                 type = navType
880                 nullable = false
881             }
882         assertThat(converted).containsExactlyInOrder(expected)
883         assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
884     }
885 
886     @Test
convertToSerializableArrayNullablenull887     fun convertToSerializableArrayNullable() {
888         @Serializable class TestSerializable : java.io.Serializable
889 
890         @Serializable class TestClass(val arg: Array<TestSerializable>?)
891 
892         val navType =
893             object : NavType<Array<TestSerializable>>(true) {
894                 override fun put(bundle: Bundle, key: String, value: Array<TestSerializable>) {}
895 
896                 override fun get(bundle: Bundle, key: String) = null
897 
898                 override fun parseValue(value: String) = emptyArray<TestSerializable>()
899             }
900         val converted =
901             serializer<TestClass>()
902                 .generateNavArguments(mapOf(typeOf<Array<TestSerializable>?>() to navType))
903         val expected =
904             navArgument("arg") {
905                 type = navType
906                 nullable = true
907             }
908         assertThat(converted).containsExactlyInOrder(expected)
909         assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
910     }
911 
912     @Test
convertToEnumnull913     fun convertToEnum() {
914         @Serializable class TestClass(val arg: TestEnum)
915 
916         val expected =
917             navArgument("arg") {
918                 type = NavType.EnumType(TestEnum::class.java)
919                 nullable = false
920             }
921         val converted = serializer<TestClass>().generateNavArguments()
922         assertThat(converted).containsExactlyInOrder(expected)
923         assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
924     }
925 
926     @Test
convertToTopLevelEnumnull927     fun convertToTopLevelEnum() {
928         @Serializable class TestClass(val arg: TestTopLevelEnum)
929 
930         val expected =
931             navArgument("arg") {
932                 type = NavType.EnumType(TestTopLevelEnum::class.java)
933                 nullable = false
934             }
935         val converted = serializer<TestClass>().generateNavArguments()
936         assertThat(converted).containsExactlyInOrder(expected)
937         assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
938     }
939 
940     @Test
convertToEnumNullablenull941     fun convertToEnumNullable() {
942         @Serializable class TestClass(val arg: TestEnum?)
943 
944         @Suppress("UNCHECKED_CAST")
945         val expected =
946             navArgument("arg") {
947                 type =
948                     InternalAndroidNavType.EnumNullableType(TestEnum::class.java as Class<Enum<*>?>)
949                 nullable = true
950             }
951         val converted = serializer<TestClass>().generateNavArguments()
952         assertThat(converted).containsExactlyInOrder(expected)
953         assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
954     }
955 
956     @Test
convertToNestedEnumnull957     fun convertToNestedEnum() {
958         @Serializable class TestClass(val arg: EnumWrapper.NestedEnum)
959 
960         val expected =
961             navArgument("arg") {
962                 type = NavType.EnumType(EnumWrapper.NestedEnum::class.java)
963                 nullable = false
964             }
965         val converted = serializer<TestClass>().generateNavArguments()
966         assertThat(converted).containsExactlyInOrder(expected)
967         assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
968     }
969 
970     @Test
convertToEnumOverriddenSerialNameIllegalnull971     fun convertToEnumOverriddenSerialNameIllegal() {
972         @Serializable class TestClass(val arg: TestEnumCustomSerialName)
973 
974         val exception =
975             assertFailsWith<IllegalArgumentException> {
976                 serializer<TestClass>().generateNavArguments()
977             }
978         assertThat(exception.message)
979             .isEqualTo(
980                 "Cannot find class with name \"MyCustomSerialName\". Ensure that the " +
981                     "serialName for this argument is the default fully qualified name." +
982                     "\nIf the build is minified, try annotating the Enum class " +
983                     "with \"androidx.annotation.Keep\" to ensure the Enum is not removed."
984             )
985     }
986 
987     @Test
convertToEnumArraynull988     fun convertToEnumArray() {
989         @Serializable class TestClass(val arg: Array<TestEnum>)
990         val navType =
991             object : CollectionNavType<Array<TestEnum>>(false) {
992                 override fun put(bundle: Bundle, key: String, value: Array<TestEnum>) {}
993 
994                 override fun serializeAsValues(value: Array<TestEnum>) = emptyList<String>()
995 
996                 override fun emptyCollection(): Array<TestEnum> = emptyArray()
997 
998                 override fun get(bundle: Bundle, key: String) = null
999 
1000                 override fun parseValue(value: String) = emptyArray<TestEnum>()
1001             }
1002         val converted =
1003             serializer<TestClass>()
1004                 .generateNavArguments(mapOf(typeOf<Array<TestEnum>>() to navType))
1005         val expected =
1006             navArgument("arg") {
1007                 type = navType
1008                 nullable = false
1009             }
1010         assertThat(converted).containsExactlyInOrder(expected)
1011         assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
1012     }
1013 
1014     @Test
convertValueClassnull1015     fun convertValueClass() {
1016         // test value class as destination route
1017         val converted = serializer<TestValueClass>().generateNavArguments()
1018         val expected =
1019             navArgument("arg") {
1020                 type = NavType.IntType
1021                 nullable = false
1022                 unknownDefaultValuePresent = false
1023             }
1024         assertThat(converted).containsExactlyInOrder(expected)
1025 
1026         // test value class as route arg
1027         @Serializable class TestClass(val arg: TestValueClass)
1028         val navType =
1029             object : NavType<TestValueClass>(false) {
1030                 override fun put(bundle: Bundle, key: String, value: TestValueClass) {}
1031 
1032                 override fun get(bundle: Bundle, key: String): TestValueClass? = null
1033 
1034                 override fun parseValue(value: String): TestValueClass = TestValueClass(0)
1035             }
1036         val converted2 =
1037             serializer<TestClass>().generateNavArguments(mapOf(typeOf<TestValueClass>() to navType))
1038         val expected2 =
1039             navArgument("arg") {
1040                 type = navType
1041                 nullable = false
1042                 unknownDefaultValuePresent = false
1043             }
1044         assertThat(converted2).containsExactlyInOrder(expected2)
1045     }
1046 
1047     @Test
convertWithDefaultValuenull1048     fun convertWithDefaultValue() {
1049         @Serializable class TestClass(val arg: String = "test")
1050         val converted = serializer<TestClass>().generateNavArguments()
1051         val expected =
1052             navArgument("arg") {
1053                 type = InternalNavType.StringNonNullableType
1054                 nullable = false
1055                 unknownDefaultValuePresent = true
1056             }
1057         assertThat(converted).containsExactlyInOrder(expected)
1058         assertThat(converted[0].argument.isDefaultValueUnknown).isTrue()
1059     }
1060 
1061     @Test
convertNullableWithDefaultValuenull1062     fun convertNullableWithDefaultValue() {
1063         @Serializable class TestClass(val arg: String? = "test")
1064         val converted = serializer<TestClass>().generateNavArguments()
1065         val expected =
1066             navArgument("arg") {
1067                 type = NavType.StringType
1068                 nullable = true
1069                 unknownDefaultValuePresent = true
1070                 // since String? is nullable, we cannot know for sure the default value is not null
1071             }
1072         assertThat(converted).containsExactlyInOrder(expected)
1073         assertThat(converted[0].argument.isDefaultValueUnknown).isTrue()
1074     }
1075 
1076     @Test
convertNullableWithNullDefaultValuenull1077     fun convertNullableWithNullDefaultValue() {
1078         @Serializable class TestClass(val arg: String? = null)
1079         val converted = serializer<TestClass>().generateNavArguments()
1080         val expected =
1081             navArgument("arg") {
1082                 type = NavType.StringType
1083                 nullable = true
1084                 unknownDefaultValuePresent = true
1085             }
1086         assertThat(converted).containsExactlyInOrder(expected)
1087         assertThat(converted[0].argument.isDefaultValueUnknown).isTrue()
1088     }
1089 
1090     @Test
convertIllegalCustomTypenull1091     fun convertIllegalCustomType() {
1092         @Serializable class TestClass(val arg: Set<String>)
1093 
1094         val exception =
1095             assertFailsWith<IllegalArgumentException> {
1096                 serializer<TestClass>().generateNavArguments()
1097             }
1098 
1099         assertThat(exception.message)
1100             .isEqualTo(
1101                 "Route androidx.navigation.serialization.NavArgumentGeneratorTest" +
1102                     ".convertIllegalCustomType.TestClass could not find any NavType for " +
1103                     "argument arg of type kotlin.collections.LinkedHashSet - typeMap " +
1104                     "received was {}"
1105             )
1106     }
1107 
1108     @Test
convertCustomTypenull1109     fun convertCustomType() {
1110         @Serializable class TestClass(val arg: ArrayList<String>)
1111 
1112         val CustomNavType =
1113             object : NavType<ArrayList<String>>(false) {
1114                 override fun put(bundle: Bundle, key: String, value: ArrayList<String>) {}
1115 
1116                 override fun get(bundle: Bundle, key: String): ArrayList<String> = arrayListOf()
1117 
1118                 override fun parseValue(value: String): ArrayList<String> = arrayListOf()
1119             }
1120 
1121         val converted =
1122             serializer<TestClass>()
1123                 .generateNavArguments(mapOf(typeOf<ArrayList<String>>() to CustomNavType))
1124         val expected =
1125             navArgument("arg") {
1126                 type = CustomNavType
1127                 nullable = false
1128             }
1129         assertThat(converted).containsExactlyInOrder(expected)
1130         assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
1131     }
1132 
1133     @Test
convertCustomTypeNullablenull1134     fun convertCustomTypeNullable() {
1135         @Serializable class TestClass(val arg: ArrayList<String>?)
1136 
1137         val CustomNavType =
1138             object : NavType<ArrayList<String>?>(true) {
1139                 override fun put(bundle: Bundle, key: String, value: ArrayList<String>?) {}
1140 
1141                 override fun get(bundle: Bundle, key: String): ArrayList<String> = arrayListOf()
1142 
1143                 override fun parseValue(value: String): ArrayList<String> = arrayListOf()
1144             }
1145 
1146         val converted =
1147             serializer<TestClass>()
1148                 .generateNavArguments(mapOf(typeOf<ArrayList<String>?>() to CustomNavType))
1149         val expected =
1150             navArgument("arg") {
1151                 type = CustomNavType
1152                 nullable = true
1153             }
1154         assertThat(converted).containsExactlyInOrder(expected)
1155         assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
1156     }
1157 
1158     @Test
convertCustomTypeNullableIllegalnull1159     fun convertCustomTypeNullableIllegal() {
1160         val CustomNavType =
1161             object : NavType<ArrayList<String>>(false) {
1162                 override val name = "customNavType"
1163 
1164                 override fun put(bundle: Bundle, key: String, value: ArrayList<String>) {}
1165 
1166                 override fun get(bundle: Bundle, key: String): ArrayList<String> = arrayListOf()
1167 
1168                 override fun parseValue(value: String): ArrayList<String> = arrayListOf()
1169             }
1170 
1171         // CustomNavType does not allow nullable but we declare the arg as nullable here
1172         @Serializable class TestClass(val arg: ArrayList<String>?)
1173 
1174         val exception =
1175             assertFailsWith<IllegalArgumentException> {
1176                 serializer<TestClass>()
1177                     .generateNavArguments(mapOf(typeOf<ArrayList<String>?>() to CustomNavType))
1178             }
1179         assertThat(exception.message).isEqualTo("customNavType does not allow nullable values")
1180     }
1181 
1182     @Test
convertMultiplenull1183     fun convertMultiple() {
1184         @Serializable class TestClass(val arg: Int, val arg2: String?)
1185 
1186         val converted = serializer<TestClass>().generateNavArguments()
1187         val expectedInt =
1188             navArgument("arg") {
1189                 type = NavType.IntType
1190                 nullable = false
1191             }
1192         val expectedString =
1193             navArgument("arg2") {
1194                 type = NavType.StringType
1195                 nullable = true
1196             }
1197         assertThat(converted).containsExactlyInOrder(expectedInt, expectedString)
1198         assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
1199         assertThat(converted[1].argument.isDefaultValueUnknown).isFalse()
1200     }
1201 
1202     @Test
convertMultipleWithDefaultValuesnull1203     fun convertMultipleWithDefaultValues() {
1204         @Serializable class TestClass(val arg: Int = 0, val arg2: String? = "test")
1205 
1206         val converted = serializer<TestClass>().generateNavArguments()
1207         val expectedInt =
1208             navArgument("arg") {
1209                 type = NavType.IntType
1210                 nullable = false
1211                 unknownDefaultValuePresent = true
1212             }
1213         val expectedString =
1214             navArgument("arg2") {
1215                 type = NavType.StringType
1216                 nullable = true
1217                 unknownDefaultValuePresent = true
1218             }
1219         assertThat(converted).containsExactlyInOrder(expectedInt, expectedString)
1220         assertThat(converted[0].argument.isDefaultValueUnknown).isTrue()
1221         assertThat(converted[1].argument.isDefaultValueUnknown).isTrue()
1222     }
1223 
1224     @Test
convertMultipleCustomTypesnull1225     fun convertMultipleCustomTypes() {
1226         @Serializable class TestClass(val arg: ArrayList<String>?, val arg2: ArrayList<Int>)
1227 
1228         val CustomStringList =
1229             object : NavType<ArrayList<String>?>(true) {
1230                 override fun put(bundle: Bundle, key: String, value: ArrayList<String>?) {}
1231 
1232                 override fun get(bundle: Bundle, key: String): ArrayList<String> = arrayListOf()
1233 
1234                 override fun parseValue(value: String): ArrayList<String> = arrayListOf()
1235             }
1236 
1237         val CustomIntList =
1238             object : NavType<ArrayList<Int>>(true) {
1239                 override fun put(bundle: Bundle, key: String, value: ArrayList<Int>) {}
1240 
1241                 override fun get(bundle: Bundle, key: String): ArrayList<Int> = arrayListOf()
1242 
1243                 override fun parseValue(value: String): ArrayList<Int> = arrayListOf()
1244             }
1245 
1246         val converted =
1247             serializer<TestClass>()
1248                 .generateNavArguments(
1249                     mapOf(
1250                         typeOf<ArrayList<String>?>() to CustomStringList,
1251                         typeOf<ArrayList<Int>>() to CustomIntList
1252                     )
1253                 )
1254         val expectedStringList =
1255             navArgument("arg") {
1256                 type = CustomStringList
1257                 nullable = true
1258             }
1259         val expectedIntList =
1260             navArgument("arg2") {
1261                 type = CustomIntList
1262                 nullable = false
1263             }
1264         assertThat(converted).containsExactlyInOrder(expectedStringList, expectedIntList)
1265         assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
1266         assertThat(converted[1].argument.isDefaultValueUnknown).isFalse()
1267     }
1268 
1269     @Test
convertMultipleCustomTypesWithDefaultValuenull1270     fun convertMultipleCustomTypesWithDefaultValue() {
1271         @Serializable
1272         class TestClass(
1273             val arg: ArrayList<String>? = arrayListOf(),
1274             val arg2: ArrayList<Int> = arrayListOf()
1275         )
1276 
1277         val CustomStringList =
1278             object : NavType<ArrayList<String>?>(true) {
1279                 override fun put(bundle: Bundle, key: String, value: ArrayList<String>?) {}
1280 
1281                 override fun get(bundle: Bundle, key: String): ArrayList<String> = arrayListOf()
1282 
1283                 override fun parseValue(value: String): ArrayList<String> = arrayListOf()
1284             }
1285 
1286         val CustomIntList =
1287             object : NavType<ArrayList<Int>>(true) {
1288                 override fun put(bundle: Bundle, key: String, value: ArrayList<Int>) {}
1289 
1290                 override fun get(bundle: Bundle, key: String): ArrayList<Int> = arrayListOf()
1291 
1292                 override fun parseValue(value: String): ArrayList<Int> = arrayListOf()
1293             }
1294 
1295         val converted =
1296             serializer<TestClass>()
1297                 .generateNavArguments(
1298                     mapOf(
1299                         typeOf<ArrayList<String>?>() to CustomStringList,
1300                         typeOf<ArrayList<Int>>() to CustomIntList
1301                     )
1302                 )
1303         val expectedStringList =
1304             navArgument("arg") {
1305                 type = CustomStringList
1306                 nullable = true
1307                 unknownDefaultValuePresent = true
1308             }
1309         val expectedIntList =
1310             navArgument("arg2") {
1311                 type = CustomIntList
1312                 nullable = false
1313                 unknownDefaultValuePresent = true
1314             }
1315         assertThat(converted).containsExactlyInOrder(expectedStringList, expectedIntList)
1316         assertThat(converted[0].argument.isDefaultValueUnknown).isTrue()
1317         assertThat(converted[1].argument.isDefaultValueUnknown).isTrue()
1318     }
1319 
1320     @Test
convertNestedCustomTypesnull1321     fun convertNestedCustomTypes() {
1322         @Serializable class TestClass(val arg: ArrayList<List<String>>)
1323 
1324         val CustomStringList =
1325             object : NavType<ArrayList<List<String>>>(false) {
1326                 override fun put(bundle: Bundle, key: String, value: ArrayList<List<String>>) {}
1327 
1328                 override fun get(bundle: Bundle, key: String): ArrayList<List<String>> =
1329                     arrayListOf()
1330 
1331                 override fun parseValue(value: String): ArrayList<List<String>> = arrayListOf()
1332             }
1333 
1334         val converted =
1335             serializer<TestClass>()
1336                 .generateNavArguments(mapOf(typeOf<ArrayList<List<String>>>() to CustomStringList))
1337         val expectedStringList =
1338             navArgument("arg") {
1339                 type = CustomStringList
1340                 nullable = false
1341             }
1342         assertThat(converted).containsExactlyInOrder(expectedStringList)
1343         assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
1344     }
1345 
1346     @Test
convertNativeAndCustomTypesnull1347     fun convertNativeAndCustomTypes() {
1348         @Serializable class TestClass(val arg: String, val arg2: ArrayList<Int>)
1349 
1350         val CustomIntList =
1351             object : NavType<ArrayList<Int>>(true) {
1352                 override fun put(bundle: Bundle, key: String, value: ArrayList<Int>) {}
1353 
1354                 override fun get(bundle: Bundle, key: String): ArrayList<Int> = arrayListOf()
1355 
1356                 override fun parseValue(value: String): ArrayList<Int> = arrayListOf()
1357             }
1358 
1359         val converted =
1360             serializer<TestClass>()
1361                 .generateNavArguments(mapOf(typeOf<ArrayList<Int>>() to CustomIntList))
1362         val expectedString =
1363             navArgument("arg") {
1364                 type = InternalNavType.StringNonNullableType
1365                 nullable = false
1366             }
1367         val expectedIntList =
1368             navArgument("arg2") {
1369                 type = CustomIntList
1370                 nullable = false
1371             }
1372 
1373         assertThat(converted).containsExactlyInOrder(expectedString, expectedIntList)
1374         assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
1375         assertThat(converted[1].argument.isDefaultValueUnknown).isFalse()
1376     }
1377 
1378     @Test
convertPrioritizesProvidedNavTypenull1379     fun convertPrioritizesProvidedNavType() {
1380         val CustomIntNavType =
1381             object : NavType<Int>(true) {
1382                 override fun put(bundle: Bundle, key: String, value: Int) {}
1383 
1384                 override fun get(bundle: Bundle, key: String): Int = 0
1385 
1386                 override fun parseValue(value: String): Int = 0
1387             }
1388 
1389         @Serializable class TestClass(val arg: Int)
1390 
1391         val converted =
1392             serializer<TestClass>().generateNavArguments(mapOf(typeOf<Int>() to CustomIntNavType))
1393         val expected =
1394             navArgument("arg") {
1395                 type = CustomIntNavType
1396                 nullable = false
1397             }
1398         assertThat(converted).containsExactlyInOrder(expected)
1399         assertThat(converted[0]).isNotEqualTo(NavType.IntType)
1400         assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
1401     }
1402 
1403     @Test
convertOnlyIfArgHasBackingFieldnull1404     fun convertOnlyIfArgHasBackingField() {
1405         @Serializable
1406         class TestClass {
1407             val noBackingField: Int
1408                 get() = 0
1409         }
1410 
1411         val converted = serializer<TestClass>().generateNavArguments()
1412         assertThat(converted).isEmpty()
1413     }
1414 
1415     @Test
convertArgFromClassBodynull1416     fun convertArgFromClassBody() {
1417         @Serializable
1418         class TestClass {
1419             val arg: Int = 0
1420         }
1421 
1422         val converted = serializer<TestClass>().generateNavArguments()
1423         val expected =
1424             navArgument("arg") {
1425                 type = NavType.IntType
1426                 nullable = false
1427                 unknownDefaultValuePresent = true
1428             }
1429         assertThat(converted).containsExactlyInOrder(expected)
1430         assertThat(converted[0].argument.isDefaultValueUnknown).isTrue()
1431     }
1432 
1433     @Test
nonSerializableClassInvalidnull1434     fun nonSerializableClassInvalid() {
1435         @SerialName(PATH_SERIAL_NAME) class TestClass
1436 
1437         assertFailsWith<SerializationException> {
1438             // the class must be serializable
1439             serializer<TestClass>().generateNavArguments()
1440         }
1441     }
1442 
1443     @Test
abstractClassInvalidnull1444     fun abstractClassInvalid() {
1445         @Serializable abstract class TestClass(val arg: Int)
1446 
1447         val serializer = serializer<TestClass>()
1448         val exception =
1449             assertFailsWith<IllegalArgumentException> { serializer.generateNavArguments() }
1450         assertThat(exception.message)
1451             .isEqualTo(
1452                 "Cannot generate NavArguments for polymorphic serializer " +
1453                     "kotlinx.serialization.PolymorphicSerializer(baseClass: " +
1454                     "class androidx.navigation.serialization." +
1455                     "NavArgumentGeneratorTest\$abstractClassInvalid\$TestClass (Kotlin reflection " +
1456                     "is not available)). Arguments can only be generated from concrete classes " +
1457                     "or objects."
1458             )
1459     }
1460 
1461     @Test
childClassOfAbstract_duplicateArgsnull1462     fun childClassOfAbstract_duplicateArgs() {
1463         @Serializable abstract class TestAbstractClass(val arg: Int)
1464 
1465         @Serializable class TestClass(val arg2: Int) : TestAbstractClass(0)
1466 
1467         val serializer = serializer<TestClass>()
1468         val converted = serializer.generateNavArguments()
1469         // args will be duplicated
1470         val expectedInt =
1471             navArgument("arg") {
1472                 type = NavType.IntType
1473                 nullable = false
1474             }
1475         val expectedInt2 =
1476             navArgument("arg2") {
1477                 type = NavType.IntType
1478                 nullable = false
1479             }
1480         assertThat(converted).containsExactlyInOrder(expectedInt, expectedInt2)
1481     }
1482 
1483     @Test
childClassOfSealed_withArgsnull1484     fun childClassOfSealed_withArgs() {
1485         val serializer = serializer<SealedClass.TestClass>()
1486         val converted = serializer.generateNavArguments()
1487         // child class overrides parent variable so only child variables are generated as args
1488         val expected =
1489             navArgument("arg2") {
1490                 type = NavType.IntType
1491                 nullable = false
1492             }
1493         assertThat(converted).containsExactlyInOrder(expected)
1494     }
1495 
1496     @Serializable @JvmInline value class TestValueClass(val arg: Int)
1497 
1498     // writing our own assert so we don't need to override NamedNavArgument's equals
1499     // and hashcode which will need to be public api.
assertThatnull1500     private fun assertThat(actual: List<NamedNavArgument>) = actual
1501 
1502     private fun List<NamedNavArgument>.containsExactlyInOrder(
1503         vararg expectedArgs: NamedNavArgument
1504     ) {
1505         if (expectedArgs.size != this.size) {
1506             fail("expected list has size ${expectedArgs.size} and actual list has size $size}")
1507         }
1508         for (i in indices) {
1509             val actual = this[i]
1510             val expected = expectedArgs[i]
1511             if (expected.name != actual.name) {
1512                 fail("expected name ${expected.name}, was actually ${actual.name}")
1513             }
1514 
1515             if (!expected.argument.isEqual(actual.argument)) {
1516                 fail(
1517                     """expected ${expected.name} to be:
1518                 |   ${expected.argument}
1519                 |   but was:
1520                 |   ${actual.argument}
1521                 """
1522                         .trimMargin()
1523                 )
1524             }
1525         }
1526     }
1527 
NavArgumentnull1528     private fun NavArgument.isEqual(other: NavArgument): Boolean {
1529         if (this === other) return true
1530         if (javaClass != other.javaClass) return false
1531         if (isNullable != other.isNullable) return false
1532         if (isDefaultValuePresent != other.isDefaultValuePresent) return false
1533         if (isDefaultValueUnknown != other.isDefaultValueUnknown) return false
1534         if (type != other.type) return false
1535         // In context of serialization, we can only tell if defaultValue is present but don't know
1536         // actual value, so we cannot compare it to the generated defaultValue. But if
1537         // there is no defaultValue, we expect them both to be null.
1538         return if (!isDefaultValuePresent) {
1539             defaultValue == null && other.defaultValue == null
1540         } else true
1541     }
1542 
1543     enum class TestEnum {
1544         TEST
1545     }
1546 
1547     @SerialName("MyCustomSerialName")
1548     enum class TestEnumCustomSerialName {
1549         TEST
1550     }
1551 
1552     @Serializable
1553     private class EnumWrapper {
1554         enum class NestedEnum {
1555             ONE,
1556             TWO
1557         }
1558     }
1559 }
1560 
1561 enum class TestTopLevelEnum {
1562     TEST
1563 }
1564