1 /* <lambda>null2 * 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.json 6 7 import kotlinx.serialization.* 8 import kotlinx.serialization.test.* 9 import kotlin.test.* 10 11 class TrailingCommaTest : JsonTestBase() { 12 val tj = Json { allowTrailingComma = true } 13 14 @Serializable 15 data class Optional(val data: String = "") 16 17 @Serializable 18 data class MultipleFields(val a: String, val b: String, val c: String) 19 20 private val multipleFields = MultipleFields("1", "2", "3") 21 22 @Serializable 23 data class WithMap(val m: Map<String, String>) 24 25 private val withMap = WithMap(mapOf("a" to "1", "b" to "2", "c" to "3")) 26 27 @Serializable 28 data class WithList(val l: List<Int>) 29 30 private val withList = WithList(listOf(1, 2, 3)) 31 32 @Test 33 fun basic() = parametrizedTest { mode -> 34 val sd = """{"data":"str",}""" 35 assertEquals(Optional("str"), tj.decodeFromString<Optional>(sd, mode)) 36 } 37 38 @Test 39 fun trailingCommaNotAllowedByDefaultForObjects() = parametrizedTest { mode -> 40 val sd = """{"data":"str",}""" 41 checkSerializationException({ 42 default.decodeFromString<Optional>(sd, mode) 43 }, { message -> 44 assertContains( 45 message, 46 """Unexpected JSON token at offset 13: Trailing comma before the end of JSON object""" 47 ) 48 }) 49 } 50 51 @Test 52 fun trailingCommaNotAllowedByDefaultForLists() = parametrizedTest { mode -> 53 val sd = """{"l":[1,]}""" 54 checkSerializationException({ 55 default.decodeFromString<WithList>(sd, mode) 56 }, { message -> 57 assertContains( 58 message, 59 """Unexpected JSON token at offset 7: Trailing comma before the end of JSON array""" 60 ) 61 }) 62 } 63 64 @Test 65 fun trailingCommaNotAllowedByDefaultForMaps() = parametrizedTest { mode -> 66 val sd = """{"m":{"a": "b",}}""" 67 checkSerializationException({ 68 default.decodeFromString<WithMap>(sd, mode) 69 }, { message -> 70 assertContains( 71 message, 72 """Unexpected JSON token at offset 14: Trailing comma before the end of JSON object""" 73 ) 74 }) 75 } 76 77 @Test 78 fun emptyObjectNotAllowed() = parametrizedTest { mode -> 79 assertFailsWithMessage<SerializationException>("Unexpected leading comma") { 80 tj.decodeFromString<Optional>("""{,}""", mode) 81 } 82 } 83 84 @Test 85 fun emptyListNotAllowed() = parametrizedTest { mode -> 86 assertFailsWithMessage<SerializationException>("Unexpected leading comma") { 87 tj.decodeFromString<WithList>("""{"l":[,]}""", mode) 88 } 89 } 90 91 @Test 92 fun emptyMapNotAllowed() = parametrizedTest { mode -> 93 assertFailsWithMessage<SerializationException>("Unexpected leading comma") { 94 tj.decodeFromString<WithMap>("""{"m":{,}}""", mode) 95 } 96 } 97 98 @Test 99 fun testMultipleFields() = parametrizedTest { mode -> 100 val input = """{"a":"1","b":"2","c":"3", }""" 101 assertEquals(multipleFields, tj.decodeFromString(input, mode)) 102 } 103 104 @Test 105 fun testWithMap() = parametrizedTest { mode -> 106 val input = """{"m":{"a":"1","b":"2","c":"3", }}""" 107 108 assertEquals(withMap, tj.decodeFromString(input, mode)) 109 } 110 111 @Test 112 fun testWithList() = parametrizedTest { mode -> 113 val input = """{"l":[1, 2, 3, ]}""" 114 assertEquals(withList, tj.decodeFromString(input, mode)) 115 } 116 117 @Serializable 118 data class Mixed(val mf: MultipleFields, val wm: WithMap, val wl: WithList) 119 120 @Test 121 fun testMixed() = parametrizedTest { mode -> 122 //language=JSON5 123 val input = """{"mf":{"a":"1","b":"2","c":"3",}, 124 "wm":{"m":{"a":"1","b":"2","c":"3",},}, 125 "wl":{"l":[1, 2, 3,],},}""" 126 assertEquals(Mixed(multipleFields, withMap, withList), tj.decodeFromString(input, mode)) 127 } 128 } 129