diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ca4454d0..36b5a38a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -37,6 +37,11 @@ material3WindowSizeClass = "1.3.2" richtext = "1.0.0-alpha02" glimmer = "1.0.0-alpha08" projected = "1.0.0-alpha05" +coreKtxVersion = "1.6.1" +truth = "1.4.4" +robolectric = "4.16.1" +mockitoKotlin = "4.1.0" +runner = "1.6.1" [libraries] @@ -89,6 +94,12 @@ androidx-lifecycle-viewmodel-android = { group = "androidx.lifecycle", name = "l androidx-exifinterface = { group = "androidx.exifinterface", name = "exifinterface", version.ref = "exifinterface" } androidx-xr-glimmer = { group = "androidx.xr.glimmer", name = "glimmer", version.ref = "glimmer" } androidx-xr-projected = { group = "androidx.xr.projected", name = "projected", version.ref = "projected" } +androidx-projected-testing = { group = "androidx.xr.projected", name = "projected-testing", version.ref = "projected" } +core-ktx = { group = "androidx.test", name = "core-ktx", version.ref = "coreKtxVersion" } +truth = { group = "com.google.truth", name = "truth", version.ref = "truth" } +robolectric = { group = "org.robolectric", name = "robolectric", version.ref = "robolectric" } +mockito-kotlin = { group = "org.mockito.kotlin", name = "mockito-kotlin", version.ref = "mockitoKotlin" } +androidx-runner = { group = "androidx.test", name = "runner", version.ref = "runner" } [plugins] android-application = { id = "com.android.application", version.ref = "agp" } diff --git a/samples/gemini-live-todo/build.gradle.kts b/samples/gemini-live-todo/build.gradle.kts index 05ccb02d..484e9f86 100644 --- a/samples/gemini-live-todo/build.gradle.kts +++ b/samples/gemini-live-todo/build.gradle.kts @@ -48,6 +48,11 @@ android { kotlinOptions { jvmTarget = "17" } + testOptions { + unitTests { + isIncludeAndroidResources = true + } + } } dependencies { @@ -69,7 +74,16 @@ dependencies { implementation(libs.hilt.navigation.compose) implementation(libs.androidx.activity.compose) implementation(libs.kotlinx.serialization.json) + + testImplementation(libs.junit) + testImplementation(libs.androidx.junit) + testImplementation(libs.androidx.projected.testing) + testImplementation(libs.truth) + testImplementation(libs.robolectric) + testImplementation(libs.core.ktx) + testImplementation(libs.mockito.kotlin) + androidTestImplementation(libs.androidx.junit) androidTestImplementation(libs.androidx.espresso.core) } diff --git a/samples/gemini-live-todo/src/test/java/com/android/ai/samples/geminilivetodo/ProjectedContextTests.kt b/samples/gemini-live-todo/src/test/java/com/android/ai/samples/geminilivetodo/ProjectedContextTests.kt new file mode 100644 index 00000000..aaa22841 --- /dev/null +++ b/samples/gemini-live-todo/src/test/java/com/android/ai/samples/geminilivetodo/ProjectedContextTests.kt @@ -0,0 +1,70 @@ +package com.android.ai.samples.geminilivetodo + +import android.content.Context +import android.os.Build +import androidx.test.core.app.ApplicationProvider +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.xr.projected.ProjectedContext +import androidx.xr.projected.ProjectedDeviceController +import androidx.xr.projected.ProjectedDeviceController.Capability.Companion.CAPABILITY_VISUAL_UI +import androidx.xr.projected.experimental.ExperimentalProjectedApi +import androidx.xr.projected.testing.ProjectedTestRule +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.runBlocking +import org.junit.Assert.assertThrows +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.annotation.Config +import kotlin.intArrayOf + +@OptIn(ExperimentalProjectedApi::class) +@Config(sdk = [Build.VERSION_CODES.BAKLAVA]) +@RunWith(AndroidJUnit4::class) +class ProjectedContextTests { + @get:Rule + val projectedTestRule = ProjectedTestRule() + + private val context: Context + get() = ApplicationProvider.getApplicationContext() + + @Test + fun app_initializesProjectedContext_whenDeviceIsConnected() { + val projectedContext = ProjectedContext.createProjectedDeviceContext(context) + assertThat(projectedContext).isNotNull() + } + + @Test + fun app_throwsException_whenDeviceDisconnected() { + projectedTestRule.isDeviceConnected = false + + assertThrows(IllegalStateException::class.java) { + ProjectedContext.createProjectedDeviceContext(context) + } + } + + + @Test + fun capabilities_includesVisualUiByDefault_returnsCapabilityVisualUi() { + projectedTestRule.launchTestProjectedDeviceActivity { activity -> + val projectedDeviceController = runBlocking { + ProjectedDeviceController.create(activity) + } + + assertThat(projectedDeviceController.capabilities).contains(CAPABILITY_VISUAL_UI) + } + } + + @Test + fun capabilities_emptyCapabilities_doesNotReturnCapabilityVisualUi() { + projectedTestRule.launchTestProjectedDeviceActivity { activity -> + projectedTestRule.capabilities = setOf() + + val projectedDeviceController = runBlocking { + ProjectedDeviceController.create(activity) + } + + assertThat(projectedDeviceController.capabilities).doesNotContain(CAPABILITY_VISUAL_UI) + } + } +}