https://kotlinlang.org logo
#ktor
Title
# ktor
j

jean

10/14/2021, 7:05 AM
I have the following json :
Copy code
private val jsonResponse = """
        {
          "offset": 0,
          "limit": 20,
          "available": 104,
          "items": [
            {
              "type": "news type",
              "title": "news title",
              "image": "news image",
              "link": "news link",
              "date": "1621807201000"
            }
          ]
        }
    """.trimIndent()
When I parse it manually with
Json.decodeFromString<NewsList>(jsonResponse)
I get my
NewsList
object without any issues, but when I run my unit test with a
MockEngine
returning the json as a string for any request, I end up with the following error :
Copy code
kotlinx.serialization.json.internal.JsonDecodingException: Expected start of the array '[', but had 'EOF' instead
JSON input: .....ink": "news link",
      "date": "1621807201000"
    }
  ]
}
What am I doing wrong here?
a

Aleksei Tirman [JB]

10/14/2021, 12:56 PM
Could you please share a code snippet for your test?
j

jean

10/14/2021, 1:26 PM
Sure, this one works :
Copy code
private val jsonResponse = """
    {
      "offset": 0,
      "limit": 20,
      "available": 104,
      "items": [
        {
          "type": "news type",
          "title": "news title",
          "image": "news image",
          "link": "news link",
          "date": "1621807201000"
        }
      ]
    }
""".trimIndent()

@Test
fun `get news from api should succeed`() = runTest {
    val response = Json.decodeFromString<NewsList>(jsonResponse)
    assertEquals(0, response.offset.value)
    assertEquals(20, response.limit.value)
    assertEquals(104, response.available.value)
}
But not this :
Copy code
@Test
fun `get news from api should succeed`() = runTest {
    val engine = MockEngine { request ->
        respond(
            content = ByteReadChannel(jsonResponse),
            status = HttpStatusCode.OK,
            headers = headersOf(HttpHeaders.ContentType, "application/json")
        )
    }

    val result = ApiClient(engine).client.get<HttpResponse>("/") {
        parameter("offset", 0)
        parameter("limit", 20)
    }
    val body = result.receive<String>()
    val news = Json.decodeFromString<NewsList>(body)
    assertEquals(
        NewsList(
            offset = Offset(0),
            limit = Limit(20),
            available = Available(104),
            items = Json.decodeFromString(jsonResponse)
        ), news
    )
}
a

Aleksei Tirman [JB]

10/14/2021, 1:34 PM
Please post the definition for
NewsList
class.
j

jean

10/14/2021, 1:53 PM
Copy code
typealias NewsList = ListWrapper<News>

@Serializable
data class ListWrapper<T>(
    val offset: Offset,
    val limit: Limit,
    val available: Available,
    val items: List<T>
)
a

Aleksei Tirman [JB]

10/14/2021, 2:08 PM
I've got an error
Unexpected JSON token at offset 12: Expected start of the object '{', but had ' ' instead
because
Offset
is a class but integer value (
0
) is present in JSON.
j

jean

10/14/2021, 2:10 PM
Offset, Limit and Available are defined as such :
Copy code
@JvmInline
@Serializable
value class Offset(val value: Int)
But the issue is that it works in one case and not the other, so I would assume it’s not due to the json source?
This is all part of a KMM project where the test is located inside
commonTest
If I put a breakpoint at the line
val news = Json.decodeFromString<NewsList>(body)
and run it manually in the debugger inspector, I can see the object is correctly created. The test fail the moment I resume it
d

David Soller

10/14/2021, 3:01 PM
@jean are you sure it's not failing on the second decode e.g.:
Copy code
NewsList(
            offset = Offset(0),
            limit = Limit(20),
            available = Available(104),
            items = Json.decodeFromString(jsonResponse)
        ), news
As it looks like in that
MockEngine
test
jsonResponse
might be treated as both a
NewsList
and
List<News>
e.g. the
items =
section. Which would match with the original error you posted
Copy code
kotlinx.serialization.json.internal.JsonDecodingException: Expected start of the array '[', but had 'EOF' instead
JSON input: .....ink": "news link",
e.g.
items
wants a
[...]
but you my be giving it a
{...}
Either way best of luck!
j

jean

10/15/2021, 6:01 AM
now I feel stupid 🤦‍♂️ yes that was the issue, thanks @David Soller!
d

David Soller

10/15/2021, 12:29 PM
🙂 Glad to help @jean
4 Views