mirror of
https://github.com/usetrmnl/trmnl-android.git
synced 2026-04-29 13:35:26 -07:00
test: Add comprehensive test coverage for device ID and battery reporting
- Add tests for getDeviceIdFromApi() method (mocked response) - Add tests for reportBatteryStatus() success and failure scenarios - Add tests for null deviceId and userApiToken validation - Add tests for fake data mode behavior - Add tests for saveDeviceId/getDeviceId in TrmnlDeviceConfigDataStore - Add tests for deviceId persistence in dual-storage (JSON + legacy) - Add tests for deviceId removal when set to null Test coverage includes: - 6 new tests in TrmnlDisplayRepositoryTest - 5 new tests in TrmnlDeviceConfigDataStoreTest - All edge cases and error conditions validated
This commit is contained in:
@@ -626,4 +626,100 @@ class TrmnlDeviceConfigDataStoreTest {
|
||||
val preferences = deviceConfigDataStore.deviceModelPreferencesFlow.first()
|
||||
assertThat(preferences).isEmpty()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `saveDeviceId and getDeviceId work correctly`() =
|
||||
runTest {
|
||||
// Arrange
|
||||
val expectedDeviceId = 12345
|
||||
|
||||
// Act
|
||||
deviceConfigDataStore.saveDeviceId(expectedDeviceId)
|
||||
val retrievedDeviceId = deviceConfigDataStore.getDeviceId()
|
||||
|
||||
// Assert
|
||||
assertThat(retrievedDeviceId).isEqualTo(expectedDeviceId)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getDeviceId returns null when not saved`() =
|
||||
runTest {
|
||||
// Act
|
||||
val deviceId = deviceConfigDataStore.getDeviceId()
|
||||
|
||||
// Assert
|
||||
assertThat(deviceId).isNull()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `saveDeviceConfig persists deviceId to both JSON and legacy storage`() =
|
||||
runTest {
|
||||
// Arrange
|
||||
val configWithDeviceId =
|
||||
TrmnlDeviceConfig(
|
||||
type = TrmnlDeviceType.BYOD,
|
||||
apiAccessToken = "test-token",
|
||||
apiBaseUrl = "https://usetrmnl.com",
|
||||
userApiToken = "user_test_token",
|
||||
deviceId = 999,
|
||||
)
|
||||
|
||||
// Act
|
||||
deviceConfigDataStore.saveDeviceConfig(configWithDeviceId)
|
||||
|
||||
// Assert - Verify device ID is persisted via getDeviceId (legacy storage)
|
||||
val deviceId = deviceConfigDataStore.getDeviceId()
|
||||
assertThat(deviceId).isEqualTo(999)
|
||||
|
||||
// Assert - Verify device ID is persisted via deviceConfigFlow (JSON storage)
|
||||
val loadedConfig = deviceConfigDataStore.deviceConfigFlow.first()
|
||||
assertThat(loadedConfig).isNotNull()
|
||||
assertThat(loadedConfig?.deviceId).isEqualTo(999)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `deviceConfigFlow loads deviceId from legacy storage when JSON not present`() =
|
||||
runTest {
|
||||
// Arrange - Save individual fields (legacy approach) without JSON
|
||||
deviceConfigDataStore.saveDeviceType(TrmnlDeviceType.BYOD)
|
||||
deviceConfigDataStore.saveAccessToken("test-token")
|
||||
deviceConfigDataStore.saveServerUrl("https://usetrmnl.com")
|
||||
deviceConfigDataStore.saveDeviceId(777)
|
||||
|
||||
// Act
|
||||
val loadedConfig = deviceConfigDataStore.deviceConfigFlow.first()
|
||||
|
||||
// Assert
|
||||
assertThat(loadedConfig).isNotNull()
|
||||
assertThat(loadedConfig?.deviceId).isEqualTo(777)
|
||||
assertThat(loadedConfig?.type).isEqualTo(TrmnlDeviceType.BYOD)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `saveDeviceConfig removes deviceId from storage when null`() =
|
||||
runTest {
|
||||
// Arrange - First save config with deviceId
|
||||
val configWithDeviceId =
|
||||
TrmnlDeviceConfig(
|
||||
type = TrmnlDeviceType.BYOD,
|
||||
apiAccessToken = "test-token",
|
||||
apiBaseUrl = "https://usetrmnl.com",
|
||||
deviceId = 123,
|
||||
)
|
||||
deviceConfigDataStore.saveDeviceConfig(configWithDeviceId)
|
||||
|
||||
// Verify it was saved
|
||||
assertThat(deviceConfigDataStore.getDeviceId()).isEqualTo(123)
|
||||
|
||||
// Act - Now save config without deviceId
|
||||
val configWithoutDeviceId = configWithDeviceId.copy(deviceId = null)
|
||||
deviceConfigDataStore.saveDeviceConfig(configWithoutDeviceId)
|
||||
|
||||
// Assert - DeviceId should be removed
|
||||
val deviceId = deviceConfigDataStore.getDeviceId()
|
||||
assertThat(deviceId).isNull()
|
||||
|
||||
val loadedConfig = deviceConfigDataStore.deviceConfigFlow.first()
|
||||
assertThat(loadedConfig?.deviceId).isNull()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -571,4 +571,150 @@ class TrmnlDisplayRepositoryTest {
|
||||
assertThat(result.httpResponseMetadata?.statusCode).isEqualTo(500)
|
||||
assertThat(result.httpResponseMetadata?.contentLength).isEqualTo(123L)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getDeviceIdFromApi should return mocked device ID`() =
|
||||
runTest {
|
||||
// Act
|
||||
val result = repository.getDeviceIdFromApi(byodDeviceConfig)
|
||||
|
||||
// Assert
|
||||
assertThat(result.isSuccess).isTrue()
|
||||
assertThat(result.getOrNull()).isEqualTo(1)
|
||||
|
||||
// Verify API was NOT called since we're using mocked response
|
||||
coVerify(exactly = 0) { apiService.getDeviceMe(any(), any()) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `reportBatteryStatus should succeed with valid BYOD config`() =
|
||||
runTest {
|
||||
// Arrange
|
||||
val byodConfigWithDeviceId =
|
||||
byodDeviceConfig.copy(
|
||||
deviceId = 123,
|
||||
userApiToken = "user_test_token",
|
||||
)
|
||||
|
||||
val expectedApiUrl = "https://server.example.com/api/devices/123"
|
||||
|
||||
coEvery {
|
||||
userApiService.updateDevice(
|
||||
fullApiUrl = expectedApiUrl,
|
||||
accessToken = "Bearer user_test_token",
|
||||
updateRequest = any(),
|
||||
)
|
||||
} returns ApiResult.success(mockk(relaxed = true))
|
||||
|
||||
// Act
|
||||
val result = repository.reportBatteryStatus(byodConfigWithDeviceId, 85)
|
||||
|
||||
// Assert
|
||||
assertThat(result.isSuccess).isTrue()
|
||||
|
||||
coVerify {
|
||||
userApiService.updateDevice(
|
||||
fullApiUrl = expectedApiUrl,
|
||||
accessToken = "Bearer user_test_token",
|
||||
updateRequest = match { it.percentCharged == 85.0 },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `reportBatteryStatus should fail when deviceId is null`() =
|
||||
runTest {
|
||||
// Arrange
|
||||
val configWithoutDeviceId =
|
||||
byodDeviceConfig.copy(
|
||||
deviceId = null,
|
||||
userApiToken = "user_test_token",
|
||||
)
|
||||
|
||||
// Act
|
||||
val result = repository.reportBatteryStatus(configWithoutDeviceId, 85)
|
||||
|
||||
// Assert
|
||||
assertThat(result.isFailure).isTrue()
|
||||
assertThat(result.exceptionOrNull()).isInstanceOf(IllegalStateException::class.java)
|
||||
assertThat(result.exceptionOrNull()?.message).contains("Device ID is required")
|
||||
|
||||
// Verify API was NOT called
|
||||
coVerify(exactly = 0) { userApiService.updateDevice(any(), any(), any()) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `reportBatteryStatus should fail when userApiToken is null`() =
|
||||
runTest {
|
||||
// Arrange
|
||||
val configWithoutUserToken =
|
||||
byodDeviceConfig.copy(
|
||||
deviceId = 123,
|
||||
userApiToken = null,
|
||||
)
|
||||
|
||||
// Act
|
||||
val result = repository.reportBatteryStatus(configWithoutUserToken, 85)
|
||||
|
||||
// Assert
|
||||
assertThat(result.isFailure).isTrue()
|
||||
assertThat(result.exceptionOrNull()).isInstanceOf(IllegalStateException::class.java)
|
||||
assertThat(result.exceptionOrNull()?.message).contains("User API token is required")
|
||||
|
||||
// Verify API was NOT called
|
||||
coVerify(exactly = 0) { userApiService.updateDevice(any(), any(), any()) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `reportBatteryStatus should handle API failure`() =
|
||||
runTest {
|
||||
// Arrange
|
||||
val byodConfigWithDeviceId =
|
||||
byodDeviceConfig.copy(
|
||||
deviceId = 123,
|
||||
userApiToken = "user_test_token",
|
||||
)
|
||||
|
||||
val expectedApiUrl = "https://server.example.com/api/devices/123"
|
||||
val apiException = java.io.IOException("Network error")
|
||||
val httpFailure: ApiResult.Failure<Unit> =
|
||||
ApiResult.networkFailure(apiException)
|
||||
|
||||
coEvery {
|
||||
userApiService.updateDevice(
|
||||
fullApiUrl = expectedApiUrl,
|
||||
accessToken = "Bearer user_test_token",
|
||||
updateRequest = any(),
|
||||
)
|
||||
} returns httpFailure
|
||||
|
||||
// Act
|
||||
val result = repository.reportBatteryStatus(byodConfigWithDeviceId, 85)
|
||||
|
||||
// Assert
|
||||
assertThat(result.isFailure).isTrue()
|
||||
assertThat(result.exceptionOrNull()).isEqualTo(apiException)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `reportBatteryStatus should skip API call in fake data mode`() =
|
||||
runTest {
|
||||
// Arrange
|
||||
every { repositoryConfigProvider.shouldUseFakeData } returns true
|
||||
|
||||
val byodConfigWithDeviceId =
|
||||
byodDeviceConfig.copy(
|
||||
deviceId = 123,
|
||||
userApiToken = "user_test_token",
|
||||
)
|
||||
|
||||
// Act
|
||||
val result = repository.reportBatteryStatus(byodConfigWithDeviceId, 85)
|
||||
|
||||
// Assert
|
||||
assertThat(result.isSuccess).isTrue()
|
||||
|
||||
// Verify API was NOT called
|
||||
coVerify(exactly = 0) { userApiService.updateDevice(any(), any(), any()) }
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user