commonMain.com.apollographql.apollo3.api.test.TestResolver.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of apollo-api-jvm Show documentation
Show all versions of apollo-api-jvm Show documentation
Apollo GraphQL API classes
package com.apollographql.apollo3.api.test
import com.apollographql.apollo3.annotations.ApolloExperimental
import com.apollographql.apollo3.api.CompiledListType
import com.apollographql.apollo3.api.CompiledNamedType
import com.apollographql.apollo3.api.CompiledNotNullType
import com.apollographql.apollo3.api.CompiledType
import com.apollographql.apollo3.api.CustomScalarType
import com.apollographql.apollo3.api.EnumType
import kotlin.native.concurrent.ThreadLocal
/**
* Implement [TestResolver] to generate fake data during tests.
*/
@ApolloExperimental
interface TestResolver {
/**
* Resolve the given field
*
* @param responseName the name of the field as seen in the json
* @param compiledType the GraphQL type of the field
* @param enumValues if [compiledType] is an enum, the list of possible values
* @param ctors if [compiledType] is a composite type or any non-null or list combination of a composite type,
* ctors contain a list of constructors for the possible shapes
*
* @return T the Kotlin value for the field. Can be Int, Double, String, List or Map or null
*/
fun resolve(responseName: String, compiledType: CompiledType, enumValues: List, ctors: Array Map>?): T
}
@ApolloExperimental
open class DefaultTestResolver : TestResolver {
private val MAX_STACK_SIZE = 256
private val stack = Array(MAX_STACK_SIZE) { 0 }
private var stackSize = 0
private var intCounter = 0
private var floatCounter = 0.5
private var compositeCounter = 0
private var enumCounter = 0
private var booleanCounter = false
open fun resolveListSize(path: List): Int {
return 3
}
open fun resolveInt(path: List): Int {
return intCounter++
}
open fun resolveString(path: List): String {
return path.subList(path.indexOfLast { it is String }, path.size).joinToString("")
}
open fun resolveFloat(path: List): Double {
return floatCounter++
}
open fun resolveBoolean(path: List): Boolean {
return booleanCounter.also {
booleanCounter = !booleanCounter
}
}
open fun resolveEnum(path: List, enumValues: List): String {
return enumValues[(enumCounter++) % enumValues.size]
}
open fun resolveComposite(path: List, ctors: Array Map>): Map {
return ctors[(compositeCounter++) % ctors.size]()
}
open fun resolveCustomScalar(path: List): String {
error("Cannot resolve custom scalar at $path")
}
private fun push(v: Any) {
check(stackSize < MAX_STACK_SIZE) {
"Nesting too deep at ${stack.joinToString(".")}"
}
stack[stackSize++] = v
}
private fun pop() {
stackSize--
stack[stackSize] = 0 // Allow garbage collection
}
private fun resolveInternal(responseName: String,
compiledType: CompiledType,
enumValues: List,
ctors: Array Map>?): T {
val path = stack.take(stackSize).toList()
@Suppress("UNCHECKED_CAST")
return when (compiledType) {
is CompiledNotNullType -> resolve(responseName, compiledType.ofType, enumValues, ctors)
is CompiledListType -> {
0.until(resolveListSize(path)).map { i ->
push(i)
resolveInternal(responseName, compiledType.ofType, enumValues, ctors).also {
pop()
}
}
}
is CustomScalarType -> {
when (compiledType.name) {
"Int" -> resolveInt(path)
"Float" -> resolveFloat(path)
"Boolean" -> resolveBoolean(path)
"String" -> resolveString(path)
"ID" -> resolveString(path)
else -> {
resolveCustomScalar(path)
}
}
}
is EnumType -> {
resolveEnum(path, enumValues)
}
is CompiledNamedType -> {
resolveComposite(path, ctors ?: error("no ctors for $responseName"))
}
} as T
}
override fun resolve(
responseName: String,
compiledType: CompiledType,
enumValues: List,
ctors: Array Map>?,
): T {
push(responseName)
return resolveInternal(responseName, compiledType, enumValues, ctors).also {
pop()
}
}
}
@ThreadLocal
@ApolloExperimental
internal var currentTestResolver: TestResolver? = null
@ApolloExperimental
fun withTestResolver(testResolver: TestResolver, block: () -> T): T {
currentTestResolver = testResolver
return block().also {
currentTestResolver = null
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy