Coverage Summary for Class: NetworkEitherDeferredCallKt (com.javiersc.network.either.internal.deferred)
Class |
Method, %
|
Branch, %
|
Line, %
|
Instruction, %
|
NetworkEitherDeferredCallKt |
60%
(3/5)
|
100%
(2/2)
|
47.4%
(9/19)
|
56%
(42/75)
|
NetworkEitherDeferredCallKt$deferredAdapt$1 |
100%
(1/1)
|
50%
(1/2)
|
100%
(1/1)
|
57.1%
(4/7)
|
NetworkEitherDeferredCallKt$deferredAdapt$2 |
100%
(3/3)
|
62.5%
(10/16)
|
70.6%
(12/17)
|
63%
(51/81)
|
Total |
77.8%
(7/9)
|
65%
(13/20)
|
59.5%
(22/37)
|
59.5%
(97/163)
|
package com.javiersc.network.either.internal.deferred
import com.javiersc.network.either.NetworkEither
import com.javiersc.network.either.NetworkEither.Companion.localFailure
import com.javiersc.network.either.NetworkEither.Companion.remoteFailure
import com.javiersc.network.either.NetworkEither.Companion.success
import com.javiersc.network.either.NetworkEither.Companion.unknownFailure
import com.javiersc.network.either.internal.hasBody
import com.javiersc.network.either.internal.utils.emptyHeader
import com.javiersc.network.either.internal.utils.printlnError
import com.javiersc.network.either.internal.utils.printlnWarning
import io.ktor.http.HttpStatusCode.Companion.NoContent
import io.ktor.util.toMap
import java.io.EOFException
import java.io.InterruptedIOException
import java.net.ConnectException
import java.net.UnknownHostException
import kotlinx.coroutines.CompletableDeferred
import kotlinx.serialization.SerializationException
import okhttp3.ResponseBody
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Converter
import retrofit2.HttpException
import retrofit2.Response
internal fun <F : Any, S : Any> deferredAdapt(
call: Call<S>,
errorConverter: Converter<ResponseBody, F>,
isNetworkAvailable: () -> Boolean,
): CompletableDeferred<NetworkEither<F, S>> {
val deferred = CompletableDeferred<NetworkEither<F, S>>()
deferred.invokeOnCompletion { if (deferred.isCancelled) call.cancel() }
call.enqueue(
object : Callback<S> {
override fun onResponse(call: Call<S>, response: Response<S>) {
response.responseDeferredHandler(errorConverter, deferred)
}
override fun onFailure(call: Call<S>, throwable: Throwable) {
when (throwable) {
is UnknownHostException,
is ConnectException,
is InterruptedIOException -> {
onCommonConnectionException(deferred, isNetworkAvailable())
}
is EOFException -> {
onEOFException(deferred)
}
is IllegalStateException -> {
onIllegalStateException(deferred, throwable)
}
is HttpException -> {
onHttpException(deferred, errorConverter, throwable)
}
is SerializationException -> {
if (throwable.hasBody) onIllegalStateException(deferred, throwable)
else onEOFException(deferred)
}
else -> {
deferred.complete(unknownFailure(throwable))
}
}
}
}
)
return deferred
}
private fun <F, S> onEOFException(deferred: CompletableDeferred<NetworkEither<F, S>>) {
printlnWarning(
"""
| # # # # # # # # # # # # # # WARNING # # # # # # # # # # # # # # # # # # #
| # Every 2XX response should have a body except 204/205, as the response #
| # was empty, the response is transformed to Success with code 204 and #
| # the headers are lost. The type should be Unit. #
| # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
"""
.trimMargin()
)
@Suppress("UNCHECKED_CAST")
try {
val success = success(Unit as S, NoContent.value, emptyHeader.toMap())
deferred.complete(success)
} catch (e: ClassCastException) {
printlnError(
"""
| # # # # # # # # # # # # # # ERROR # # # # # # # # # # # # # # # # # #
| # NetworkResponse should use Unit as Success type when body is null #
| # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
"""
.trimMargin()
)
deferred.complete(unknownFailure(e))
}
}
private fun <F, S> onIllegalStateException(
deferred: CompletableDeferred<NetworkEither<F, S>>,
throwable: Throwable
) {
printlnError(
"""
| # # # # # # # # # # # # # # ERROR # # # # # # # # # # # # # # #
| # Response body can't be serialized with the object provided #
| # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
"""
.trimMargin()
)
deferred.complete(unknownFailure(throwable))
}
private fun <F, S> onCommonConnectionException(
deferred: CompletableDeferred<NetworkEither<F, S>>,
isNetworkAvailable: Boolean
) {
deferred.complete(if (isNetworkAvailable) remoteFailure() else localFailure())
}
private fun <F : Any, S : Any> onHttpException(
deferred: CompletableDeferred<NetworkEither<F, S>>,
errorConverter: Converter<ResponseBody, F>,
exception: HttpException,
) = exception.httpExceptionDeferredHandler(errorConverter, deferred)