/* * SPDX-License-Identifier: GPL-3.0-or-later */ package com.runicgateway.app.ui import com.runicgateway.app.core.result.ApiResult import com.runicgateway.app.ui.components.isRetryable import org.junit.Assert.assertEquals import org.junit.Assert.assertFalse import org.junit.Assert.assertTrue import org.junit.Test import java.io.IOException /** Unit tests for folding an [ApiResult] into a screen [UiState] (PLAN.md §7). */ class UiStateTest { @Test fun okBecomesSuccess() { assertEquals(UiState.Success("hi"), ApiResult.Ok("hi").toUiState()) } @Test fun networkErrorMapsToNetworkKind() { val state = ApiResult.NetworkError(IOException()).toUiState() assertEquals(ErrorKind.NETWORK, (state as UiState.Error).kind) } @Test fun knownStatusesMapToKinds() { assertEquals(ErrorKind.NOT_FOUND, kindOf(404)) assertEquals(ErrorKind.RATE_LIMITED, kindOf(429)) assertEquals(ErrorKind.SHARD_OFFLINE, kindOf(503)) assertEquals(ErrorKind.SERVER, kindOf(500)) } @Test fun httpStatusIsPreserved() { val state = ApiResult.HttpError(503).toUiState() as UiState.Error assertEquals(503, state.httpStatus) assertTrue(ApiResult.HttpError(503).let { it.status == 503 }) } // ── Shard reads: 404/403 mean "this shard doesn't publish it" (M11) ── @Test fun shardReadsTreat404And403AsFeatureUnavailable() { // requireFeature answers 404 for a disabled feature (deliberately not // disclosing that it exists) and 403 for a viewer below its audience rung. assertEquals(ErrorKind.FEATURE_UNAVAILABLE, shardKindOf(404)) assertEquals(ErrorKind.FEATURE_UNAVAILABLE, shardKindOf(403)) } @Test fun shardReadsLeaveEveryOtherStatusAlone() { assertEquals(ErrorKind.SHARD_OFFLINE, shardKindOf(503)) assertEquals(ErrorKind.RATE_LIMITED, shardKindOf(429)) assertEquals(ErrorKind.SERVER, shardKindOf(500)) assertEquals( ErrorKind.NETWORK, (ApiResult.NetworkError(IOException()).toShardUiState() as UiState.Error).kind, ) assertEquals(UiState.Success("hi"), ApiResult.Ok("hi").toShardUiState()) } @Test fun nonShardReadsKeep404AsNotFound() { // The remap is scoped to shard routes on purpose: off them, a 404 is still a // deleted post or an unknown wiki slug. assertEquals(ErrorKind.NOT_FOUND, kindOf(404)) } @Test fun anUnavailableFeatureIsNotRetryable() { // An admin controls this, so a retry button would read as a transient failure // the user could wait out. assertFalse(isRetryable(ErrorKind.FEATURE_UNAVAILABLE)) for (kind in ErrorKind.entries.filter { it != ErrorKind.FEATURE_UNAVAILABLE }) { assertTrue("$kind should offer a retry", isRetryable(kind)) } } private fun kindOf(status: Int): ErrorKind = (ApiResult.HttpError(status).toUiState() as UiState.Error).kind private fun shardKindOf(status: Int): ErrorKind = (ApiResult.HttpError(status).toShardUiState() as UiState.Error).kind }