Skip to content

Commit 9e978b5

Browse files
authored
Fix withErrors (#254)
* Fix withErrors * Simplify test
1 parent e126738 commit 9e978b5

File tree

3 files changed

+177
-25
lines changed
  • normalized-cache/src
  • test-utils/src/commonMain/kotlin/com/apollographql/cache/normalized/testing

3 files changed

+177
-25
lines changed

normalized-cache/src/commonMain/kotlin/com/apollographql/cache/normalized/api/DataWithErrors.kt

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,26 +34,25 @@ fun <D : Executable.Data> D.withErrors(
3434
/**
3535
* Returns this data with the given [errors] inlined.
3636
*/
37-
private fun Map<String, ApolloJsonElement>.withErrors(errors: List<Error>?): DataWithErrors {
37+
internal fun Map<String, ApolloJsonElement>.withErrors(errors: List<Error>?): DataWithErrors {
3838
if (errors == null || errors.isEmpty()) return this
3939
var dataWithErrors = this
4040
for (error in errors) {
41-
val path = error.path
42-
if (path == null) continue
43-
dataWithErrors = dataWithErrors.withValueAt(path, error)
41+
val path = error.path ?: continue
42+
dataWithErrors = dataWithErrors.withErrorAt(path, error)
4443
}
4544
return dataWithErrors
4645
}
4746

4847
@Suppress("UNCHECKED_CAST")
49-
private fun Map<String, ApolloJsonElement>.withValueAt(path: List<Any>, value: Any?): DataWithErrors {
48+
private fun Map<String, ApolloJsonElement>.withErrorAt(path: List<Any>, error: Error): DataWithErrors {
5049
var node: Any? = this.toMutableMap()
5150
val root = node
5251
for ((i, key) in path.withIndex()) {
5352
if (key is String) {
5453
node as MutableMap<String, Any?>
5554
if (i == path.lastIndex) {
56-
node[key] = value
55+
node[key] = error
5756
} else {
5857
when (val v = node[key]) {
5958
is Map<*, *> -> {
@@ -64,15 +63,18 @@ private fun Map<String, ApolloJsonElement>.withValueAt(path: List<Any>, value: A
6463
node[key] = v.toMutableList()
6564
}
6665

67-
else -> break
66+
else -> {
67+
node[key] = error
68+
break
69+
}
6870
}
6971
}
7072
node = node[key]!!
7173
} else {
7274
key as Int
7375
node as MutableList<Any?>
7476
if (i == path.lastIndex) {
75-
node[key] = value
77+
node[key] = error
7678
} else {
7779
when (val v = node[key]) {
7880
is Map<*, *> -> {
@@ -83,7 +85,10 @@ private fun Map<String, ApolloJsonElement>.withValueAt(path: List<Any>, value: A
8385
node[key] = v.toMutableList()
8486
}
8587

86-
else -> break
88+
else -> {
89+
node[key] = error
90+
break
91+
}
8792
}
8893
}
8994
node = node[key]!!
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
@file:Suppress("UNCHECKED_CAST")
2+
3+
package com.apollographql.cache.normalized.api
4+
5+
import com.apollographql.apollo.api.Error
6+
import com.apollographql.apollo.api.internal.readErrors
7+
import com.apollographql.apollo.api.json.ApolloJsonElement
8+
import com.apollographql.apollo.api.json.BufferedSourceJsonReader
9+
import com.apollographql.apollo.api.json.readAny
10+
import com.apollographql.cache.normalized.testing.assertErrorsEquals
11+
import okio.Buffer
12+
import kotlin.test.Test
13+
14+
class WithErrorsTest {
15+
@Test
16+
fun pathAtPresentPosition() {
17+
val dataJson =
18+
// language=JSON
19+
"""
20+
{
21+
"hero": {
22+
"name": "R2-D2",
23+
"heroFriends": [
24+
{
25+
"id": "1000",
26+
"name": "Luke Skywalker"
27+
},
28+
{
29+
"id": "1002",
30+
"name": null
31+
},
32+
{
33+
"id": "1003",
34+
"name": "Leia Organa"
35+
}
36+
]
37+
}
38+
}
39+
""".trimIndent()
40+
val data = BufferedSourceJsonReader(Buffer().writeUtf8(dataJson)).readAny() as Map<String, ApolloJsonElement>
41+
42+
val errorsJson =
43+
// language=JSON
44+
"""
45+
[
46+
{
47+
"message": "Name for character with ID 1002 could not be fetched.",
48+
"locations": [{"line": 6,"column": 7}],
49+
"path": ["hero", "heroFriends", 1, "name"]
50+
}
51+
]
52+
""".trimIndent()
53+
val errors = BufferedSourceJsonReader(Buffer().writeUtf8(errorsJson)).readErrors()
54+
55+
val dataWithErrors = data.withErrors(errors)
56+
assertErrorsEquals(
57+
expected = Error.Builder("Name for character with ID 1002 could not be fetched.")
58+
.locations(listOf(Error.Location(6, 7)))
59+
.path(listOf("hero", "heroFriends", 1, "name"))
60+
.build(),
61+
actual = dataWithErrors["hero"].asMap()["heroFriends"].asList()[1].asMap()["name"] as Error,
62+
)
63+
}
64+
65+
@Test
66+
fun pathAtAbsentPositionInList() {
67+
val dataJson =
68+
// language=JSON
69+
"""
70+
{
71+
"hero": {
72+
"name": "R2-D2",
73+
"heroFriends": [
74+
{
75+
"id": "1000",
76+
"name": "Luke Skywalker"
77+
},
78+
null,
79+
{
80+
"id": "1003",
81+
"name": "Leia Organa"
82+
}
83+
]
84+
}
85+
}
86+
""".trimIndent()
87+
val data = BufferedSourceJsonReader(Buffer().writeUtf8(dataJson)).readAny() as Map<String, ApolloJsonElement>
88+
89+
val errorsJson =
90+
// language=JSON
91+
"""
92+
[
93+
{
94+
"message": "Name for character with ID 1002 could not be fetched.",
95+
"locations": [{"line": 6,"column": 7}],
96+
"path": ["hero", "heroFriends", 1, "name"]
97+
}
98+
]
99+
""".trimIndent()
100+
val errors = BufferedSourceJsonReader(Buffer().writeUtf8(errorsJson)).readErrors()
101+
102+
val dataWithErrors = data.withErrors(errors)
103+
assertErrorsEquals(
104+
expected = Error.Builder("Name for character with ID 1002 could not be fetched.")
105+
.locations(listOf(Error.Location(6, 7)))
106+
.path(listOf("hero", "heroFriends", 1, "name"))
107+
.build(),
108+
actual = dataWithErrors["hero"].asMap()["heroFriends"].asList()[1] as Error,
109+
)
110+
}
111+
112+
@Test
113+
fun pathAtAbsentPositionInObject() {
114+
val dataJson =
115+
// language=JSON
116+
"""
117+
{
118+
"foo": null
119+
}
120+
""".trimIndent()
121+
val data = BufferedSourceJsonReader(Buffer().writeUtf8(dataJson)).readAny() as Map<String, ApolloJsonElement>
122+
123+
val errorsJson =
124+
// language=JSON
125+
"""
126+
[
127+
{
128+
"message": "Baz is null",
129+
"path": ["foo", "bar", 1, "baz"]
130+
}
131+
]
132+
""".trimIndent()
133+
val errors = BufferedSourceJsonReader(Buffer().writeUtf8(errorsJson)).readErrors()
134+
135+
val dataWithErrors = data.withErrors(errors)
136+
assertErrorsEquals(
137+
expected = Error.Builder("Baz is null")
138+
.path(listOf("foo", "bar", 1, "baz"))
139+
.build(),
140+
actual = dataWithErrors["foo"] as Error,
141+
)
142+
}
143+
}
144+
145+
private fun Any?.asMap(): Map<String, Any?> = this as Map<String, Any?>
146+
private fun Any?.asList(): List<Any?> = this as List<Any?>

test-utils/src/commonMain/kotlin/com/apollographql/cache/normalized/testing/Errors.kt

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package com.apollographql.cache.normalized.testing
22

33
import com.apollographql.apollo.api.Error
4-
import com.apollographql.apollo.api.Error.Location
54
import kotlin.test.assertContentEquals
65
import kotlin.test.assertNotNull
76
import kotlin.test.assertNull
@@ -11,24 +10,26 @@ import kotlin.test.assertNull
1110
*/
1211
private data class ComparableError(
1312
val message: String,
14-
val locations: List<Location>?,
13+
val locations: List<ComparableLocation>?,
1514
val path: List<Any>?,
1615
)
1716

18-
fun assertErrorsEquals(expected: Iterable<Error>?, actual: Iterable<Error>?) =
19-
assertContentEquals(expected?.map {
20-
ComparableError(
21-
message = it.message,
22-
locations = it.locations,
23-
path = it.path,
24-
)
25-
}, actual?.map {
26-
ComparableError(
27-
message = it.message,
28-
locations = it.locations,
29-
path = it.path,
30-
)
31-
})
17+
private data class ComparableLocation(
18+
val line: Int,
19+
val column: Int,
20+
)
21+
22+
private fun Error.toComparableError(): ComparableError = ComparableError(
23+
message = message,
24+
locations = locations?.map { location -> ComparableLocation(location.line, location.column) },
25+
path = path,
26+
)
27+
28+
fun assertErrorsEquals(expected: Iterable<Error>?, actual: Iterable<Error>?) {
29+
val expectedList = expected?.map(Error::toComparableError)
30+
val actualList = actual?.map(Error::toComparableError)
31+
assertContentEquals(expectedList, actualList)
32+
}
3233

3334
fun assertErrorsEquals(expected: Error?, actual: Error?) {
3435
if (expected == null) {

0 commit comments

Comments
 (0)