From 3a91c00a8c2d9b5da866ba20731712349ff87d17 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 11 Jun 2025 10:29:10 +0200 Subject: [PATCH] Add unit tests on AndroidBatteryOptimization --- .../battery/AndroidBatteryOptimizationTest.kt | 113 ++++++++++++++++++ services/toolbox/test/build.gradle.kts | 1 + .../test/intent/FakeExternalIntentLauncher.kt | 3 +- 3 files changed, 116 insertions(+), 1 deletion(-) create mode 100644 libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/battery/AndroidBatteryOptimizationTest.kt diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/battery/AndroidBatteryOptimizationTest.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/battery/AndroidBatteryOptimizationTest.kt new file mode 100644 index 0000000000..e3a28550ca --- /dev/null +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/battery/AndroidBatteryOptimizationTest.kt @@ -0,0 +1,113 @@ +/* + * Copyright 2025 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.libraries.push.impl.battery + +import android.content.ActivityNotFoundException +import android.content.Intent +import android.provider.Settings +import androidx.test.platform.app.InstrumentationRegistry +import com.google.common.truth.Truth.assertThat +import io.element.android.services.toolbox.api.intent.ExternalIntentLauncher +import io.element.android.services.toolbox.test.intent.FakeExternalIntentLauncher +import io.element.android.tests.testutils.lambda.lambdaRecorder +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner + +@RunWith(RobolectricTestRunner::class) +class AndroidBatteryOptimizationTest { + @Test + fun `isIgnoringBatteryOptimizations should return false`() { + val sut = createAndroidBatteryOptimization() + assertThat(sut.isIgnoringBatteryOptimizations()).isFalse() + } + + @Test + fun `requestDisablingBatteryOptimization is called once with expected intent`() { + val launchLambda = lambdaRecorder { intent -> + assertThat(intent.action).isEqualTo(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS) + assertThat(intent.data.toString()).isEqualTo("package:${InstrumentationRegistry.getInstrumentation().context.packageName}") + } + val externalIntentLauncher = FakeExternalIntentLauncher(launchLambda) + val sut = createAndroidBatteryOptimization( + externalIntentLauncher = externalIntentLauncher, + ) + val result = sut.requestDisablingBatteryOptimization() + launchLambda.assertions().isCalledOnce() + assertThat(result).isTrue() + } + + @Test + fun `in case of 1 error, requestDisablingBatteryOptimization returns true`() { + var callNumber = 0 + val launchLambda = lambdaRecorder { intent -> + callNumber++ + when (callNumber) { + 1 -> { + assertThat(intent.action).isEqualTo(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS) + assertThat(intent.data.toString()).isEqualTo("package:${InstrumentationRegistry.getInstrumentation().context.packageName}") + throw ActivityNotFoundException("Test exception") + } + 2 -> { + assertThat(intent.action).isEqualTo(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS) + assertThat(intent.data).isNull() + // No error + } + else -> { + throw AssertionError("Unexpected call number: $callNumber") + } + } + } + val externalIntentLauncher = FakeExternalIntentLauncher(launchLambda) + val sut = createAndroidBatteryOptimization( + externalIntentLauncher = externalIntentLauncher, + ) + val result = sut.requestDisablingBatteryOptimization() + launchLambda.assertions().isCalledExactly(2) + assertThat(result).isTrue() + } + + @Test + fun `in case of 2 errors, requestDisablingBatteryOptimization returns false`() { + var callNumber = 0 + val launchLambda = lambdaRecorder { intent -> + callNumber++ + when (callNumber) { + 1 -> { + assertThat(intent.action).isEqualTo(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS) + assertThat(intent.data.toString()).isEqualTo("package:${InstrumentationRegistry.getInstrumentation().context.packageName}") + throw ActivityNotFoundException("Test exception") + } + 2 -> { + assertThat(intent.action).isEqualTo(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS) + assertThat(intent.data).isNull() + throw ActivityNotFoundException("Test exception") + } + else -> { + throw AssertionError("Unexpected call number: $callNumber") + } + } + } + val externalIntentLauncher = FakeExternalIntentLauncher(launchLambda) + val sut = createAndroidBatteryOptimization( + externalIntentLauncher = externalIntentLauncher, + ) + val result = sut.requestDisablingBatteryOptimization() + launchLambda.assertions().isCalledExactly(2) + assertThat(result).isFalse() + } + + private fun createAndroidBatteryOptimization( + externalIntentLauncher: ExternalIntentLauncher = FakeExternalIntentLauncher(), + ): AndroidBatteryOptimization { + return AndroidBatteryOptimization( + context = InstrumentationRegistry.getInstrumentation().context, + externalIntentLauncher = externalIntentLauncher, + ) + } +} diff --git a/services/toolbox/test/build.gradle.kts b/services/toolbox/test/build.gradle.kts index 9f3f9bfee3..8d2f2b8a2d 100644 --- a/services/toolbox/test/build.gradle.kts +++ b/services/toolbox/test/build.gradle.kts @@ -14,4 +14,5 @@ android { dependencies { api(projects.services.toolbox.api) + implementation(projects.tests.testutils) } diff --git a/services/toolbox/test/src/main/kotlin/io/element/android/services/toolbox/test/intent/FakeExternalIntentLauncher.kt b/services/toolbox/test/src/main/kotlin/io/element/android/services/toolbox/test/intent/FakeExternalIntentLauncher.kt index 721a6ebe1b..a8e9589b6d 100644 --- a/services/toolbox/test/src/main/kotlin/io/element/android/services/toolbox/test/intent/FakeExternalIntentLauncher.kt +++ b/services/toolbox/test/src/main/kotlin/io/element/android/services/toolbox/test/intent/FakeExternalIntentLauncher.kt @@ -9,9 +9,10 @@ package io.element.android.services.toolbox.test.intent import android.content.Intent import io.element.android.services.toolbox.api.intent.ExternalIntentLauncher +import io.element.android.tests.testutils.lambda.lambdaError class FakeExternalIntentLauncher( - var launchLambda: (Intent) -> Unit = {}, + var launchLambda: (Intent) -> Unit = { lambdaError() }, ) : ExternalIntentLauncher { override fun launch(intent: Intent) { launchLambda(intent)