summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/activity/src/com/android/intentresolver/ChooserActivityTest.java15
-rw-r--r--tests/shared/src/com/android/intentresolver/contentpreview/FakeThumbnailLoader.kt36
-rw-r--r--tests/shared/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/PayloadToggleInteractorKosmos.kt2
-rw-r--r--tests/unit/src/com/android/intentresolver/contentpreview/CachingImagePreviewImageLoaderTest.kt278
-rw-r--r--tests/unit/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/CursorPreviewsInteractorTest.kt119
-rw-r--r--tests/unit/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/FetchPreviewsInteractorTest.kt69
-rw-r--r--tests/unit/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/SelectablePreviewInteractorTest.kt2
-rw-r--r--tests/unit/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/SelectablePreviewsInteractorTest.kt14
-rw-r--r--tests/unit/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/SelectionInteractorTest.kt70
-rw-r--r--tests/unit/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/SetCursorPreviewsInteractorTest.kt12
-rw-r--r--tests/unit/src/com/android/intentresolver/contentpreview/payloadtoggle/ui/viewmodel/ShareouselViewModelTest.kt69
11 files changed, 506 insertions, 180 deletions
diff --git a/tests/activity/src/com/android/intentresolver/ChooserActivityTest.java b/tests/activity/src/com/android/intentresolver/ChooserActivityTest.java
index 24b7fb12..a8b8b2e9 100644
--- a/tests/activity/src/com/android/intentresolver/ChooserActivityTest.java
+++ b/tests/activity/src/com/android/intentresolver/ChooserActivityTest.java
@@ -118,8 +118,12 @@ import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.rule.ActivityTestRule;
import com.android.intentresolver.chooser.DisplayResolveInfo;
+import com.android.intentresolver.contentpreview.FakeThumbnailLoader;
import com.android.intentresolver.contentpreview.ImageLoader;
import com.android.intentresolver.contentpreview.ImageLoaderModule;
+import com.android.intentresolver.contentpreview.PreviewCacheSize;
+import com.android.intentresolver.contentpreview.PreviewMaxConcurrency;
+import com.android.intentresolver.contentpreview.ThumbnailLoader;
import com.android.intentresolver.data.repository.FakeUserRepository;
import com.android.intentresolver.data.repository.UserRepository;
import com.android.intentresolver.data.repository.UserRepositoryModule;
@@ -272,6 +276,17 @@ public class ChooserActivityTest {
@BindValue
final ImageLoader mImageLoader = mFakeImageLoader;
+ @BindValue
+ @PreviewCacheSize
+ int mPreviewCacheSize = 16;
+
+ @BindValue
+ @PreviewMaxConcurrency
+ int mPreviewMaxConcurrency = 4;
+
+ @BindValue
+ ThumbnailLoader mThumbnailLoader = new FakeThumbnailLoader();
+
@Before
public void setUp() {
// TODO: use the other form of `adoptShellPermissionIdentity()` where we explicitly list the
diff --git a/tests/shared/src/com/android/intentresolver/contentpreview/FakeThumbnailLoader.kt b/tests/shared/src/com/android/intentresolver/contentpreview/FakeThumbnailLoader.kt
new file mode 100644
index 00000000..d3fdf17d
--- /dev/null
+++ b/tests/shared/src/com/android/intentresolver/contentpreview/FakeThumbnailLoader.kt
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.intentresolver.contentpreview
+
+import android.graphics.Bitmap
+import android.net.Uri
+
+/** Fake implementation of [ThumbnailLoader] for use in testing. */
+class FakeThumbnailLoader : ThumbnailLoader {
+
+ val fakeInvoke = mutableMapOf<Uri, suspend () -> Bitmap?>()
+ val invokeCalls = mutableListOf<Uri>()
+ var unfinishedInvokeCount = 0
+
+ override suspend fun invoke(uri: Uri): Bitmap? {
+ invokeCalls.add(uri)
+ unfinishedInvokeCount++
+ val result = fakeInvoke[uri]?.invoke()
+ unfinishedInvokeCount--
+ return result
+ }
+}
diff --git a/tests/shared/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/PayloadToggleInteractorKosmos.kt b/tests/shared/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/PayloadToggleInteractorKosmos.kt
index 659c178c..8f7c59de 100644
--- a/tests/shared/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/PayloadToggleInteractorKosmos.kt
+++ b/tests/shared/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/PayloadToggleInteractorKosmos.kt
@@ -20,6 +20,7 @@ import com.android.intentresolver.backgroundDispatcher
import com.android.intentresolver.contentResolver
import com.android.intentresolver.contentpreview.HeadlineGenerator
import com.android.intentresolver.contentpreview.ImageLoader
+import com.android.intentresolver.contentpreview.mimetypeClassifier
import com.android.intentresolver.contentpreview.payloadtoggle.data.repository.activityResultRepository
import com.android.intentresolver.contentpreview.payloadtoggle.data.repository.cursorPreviewsRepository
import com.android.intentresolver.contentpreview.payloadtoggle.data.repository.pendingSelectionCallbackRepository
@@ -97,6 +98,7 @@ val Kosmos.selectionInteractor
selectionsRepo = previewSelectionsRepository,
targetIntentModifier = targetIntentModifier,
updateTargetIntentInteractor = updateTargetIntentInteractor,
+ mimeTypeClassifier = mimetypeClassifier,
)
val Kosmos.setCursorPreviewsInteractor
diff --git a/tests/unit/src/com/android/intentresolver/contentpreview/CachingImagePreviewImageLoaderTest.kt b/tests/unit/src/com/android/intentresolver/contentpreview/CachingImagePreviewImageLoaderTest.kt
new file mode 100644
index 00000000..331f9f64
--- /dev/null
+++ b/tests/unit/src/com/android/intentresolver/contentpreview/CachingImagePreviewImageLoaderTest.kt
@@ -0,0 +1,278 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.intentresolver.contentpreview
+
+import android.graphics.Bitmap
+import android.net.Uri
+import com.google.common.truth.Truth.assertThat
+import kotlin.math.ceil
+import kotlin.math.roundToInt
+import kotlin.time.Duration.Companion.milliseconds
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.advanceTimeBy
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+
+@OptIn(ExperimentalCoroutinesApi::class)
+class CachingImagePreviewImageLoaderTest {
+
+ private val testDispatcher = StandardTestDispatcher()
+ private val testScope = TestScope(testDispatcher)
+ private val testJobTime = 100.milliseconds
+ private val testCacheSize = 4
+ private val testMaxConcurrency = 2
+ private val testTimeToFillCache =
+ testJobTime * ceil((testCacheSize).toFloat() / testMaxConcurrency.toFloat()).roundToInt()
+ private val testUris =
+ List(5) { Uri.fromParts("TestScheme$it", "TestSsp$it", "TestFragment$it") }
+ private val testTimeToLoadAllUris =
+ testJobTime * ceil((testUris.size).toFloat() / testMaxConcurrency.toFloat()).roundToInt()
+ private val testBitmap = Bitmap.createBitmap(10, 10, Bitmap.Config.ALPHA_8)
+ private val fakeThumbnailLoader =
+ FakeThumbnailLoader().apply {
+ testUris.forEach {
+ fakeInvoke[it] = {
+ delay(testJobTime)
+ testBitmap
+ }
+ }
+ }
+
+ private val imageLoader =
+ CachingImagePreviewImageLoader(
+ scope = testScope.backgroundScope,
+ bgDispatcher = testDispatcher,
+ thumbnailLoader = fakeThumbnailLoader,
+ cacheSize = testCacheSize,
+ maxConcurrency = testMaxConcurrency,
+ )
+
+ @Test
+ fun loadImage_notCached_callsThumbnailLoader() =
+ testScope.runTest {
+ // Arrange
+ var result: Bitmap? = null
+
+ // Act
+ imageLoader.loadImage(testScope, testUris[0]) { result = it }
+ advanceTimeBy(testJobTime)
+ runCurrent()
+
+ // Assert
+ assertThat(fakeThumbnailLoader.invokeCalls).containsExactly(testUris[0])
+ assertThat(result).isSameInstanceAs(testBitmap)
+ }
+
+ @Test
+ fun loadImage_cached_usesCachedValue() =
+ testScope.runTest {
+ // Arrange
+ imageLoader.loadImage(testScope, testUris[0]) {}
+ advanceTimeBy(testJobTime)
+ runCurrent()
+ fakeThumbnailLoader.invokeCalls.clear()
+ var result: Bitmap? = null
+
+ // Act
+ imageLoader.loadImage(testScope, testUris[0]) { result = it }
+ advanceTimeBy(testJobTime)
+ runCurrent()
+
+ // Assert
+ assertThat(fakeThumbnailLoader.invokeCalls).isEmpty()
+ assertThat(result).isSameInstanceAs(testBitmap)
+ }
+
+ @Test
+ fun loadImage_error_returnsNull() =
+ testScope.runTest {
+ // Arrange
+ fakeThumbnailLoader.fakeInvoke[testUris[0]] = {
+ delay(testJobTime)
+ throw RuntimeException("Test exception")
+ }
+ var result: Bitmap? = testBitmap
+
+ // Act
+ imageLoader.loadImage(testScope, testUris[0]) { result = it }
+ advanceTimeBy(testJobTime)
+ runCurrent()
+
+ // Assert
+ assertThat(fakeThumbnailLoader.invokeCalls).containsExactly(testUris[0])
+ assertThat(result).isNull()
+ }
+
+ @Test
+ fun loadImage_uncached_limitsConcurrency() =
+ testScope.runTest {
+ // Arrange
+ val results = mutableListOf<Bitmap?>()
+ assertThat(testUris.size).isGreaterThan(testMaxConcurrency)
+
+ // Act
+ testUris.take(testMaxConcurrency + 1).forEach { uri ->
+ imageLoader.loadImage(testScope, uri) { results.add(it) }
+ }
+
+ // Assert
+ assertThat(results).isEmpty()
+ advanceTimeBy(testJobTime)
+ runCurrent()
+ assertThat(results).hasSize(testMaxConcurrency)
+ advanceTimeBy(testJobTime)
+ runCurrent()
+ assertThat(results).hasSize(testMaxConcurrency + 1)
+ assertThat(results)
+ .containsExactlyElementsIn(List(testMaxConcurrency + 1) { testBitmap })
+ }
+
+ @Test
+ fun loadImage_cacheEvicted_cancelsLoadAndReturnsNull() =
+ testScope.runTest {
+ // Arrange
+ val results = MutableList<Bitmap?>(testUris.size) { null }
+ assertThat(testUris.size).isGreaterThan(testCacheSize)
+
+ // Act
+ imageLoader.loadImage(testScope, testUris[0]) { results[0] = it }
+ runCurrent()
+ testUris.indices.drop(1).take(testCacheSize).forEach { i ->
+ imageLoader.loadImage(testScope, testUris[i]) { results[i] = it }
+ }
+ advanceTimeBy(testTimeToFillCache)
+ runCurrent()
+
+ // Assert
+ assertThat(fakeThumbnailLoader.invokeCalls).containsExactlyElementsIn(testUris)
+ assertThat(results)
+ .containsExactlyElementsIn(
+ List(testUris.size) { index -> if (index == 0) null else testBitmap }
+ )
+ .inOrder()
+ assertThat(fakeThumbnailLoader.unfinishedInvokeCount).isEqualTo(1)
+ }
+
+ @Test
+ fun prePopulate_fillsCache() =
+ testScope.runTest {
+ // Arrange
+ val fullCacheUris = testUris.take(testCacheSize)
+ assertThat(fullCacheUris).hasSize(testCacheSize)
+
+ // Act
+ imageLoader.prePopulate(fullCacheUris)
+ advanceTimeBy(testTimeToFillCache)
+ runCurrent()
+
+ // Assert
+ assertThat(fakeThumbnailLoader.invokeCalls).containsExactlyElementsIn(fullCacheUris)
+
+ // Act
+ fakeThumbnailLoader.invokeCalls.clear()
+ imageLoader.prePopulate(fullCacheUris)
+ advanceTimeBy(testTimeToFillCache)
+ runCurrent()
+
+ // Assert
+ assertThat(fakeThumbnailLoader.invokeCalls).isEmpty()
+ }
+
+ @Test
+ fun prePopulate_greaterThanCacheSize_fillsCacheThenDropsRemaining() =
+ testScope.runTest {
+ // Arrange
+ assertThat(testUris.size).isGreaterThan(testCacheSize)
+
+ // Act
+ imageLoader.prePopulate(testUris)
+ advanceTimeBy(testTimeToLoadAllUris)
+ runCurrent()
+
+ // Assert
+ assertThat(fakeThumbnailLoader.invokeCalls)
+ .containsExactlyElementsIn(testUris.take(testCacheSize))
+
+ // Act
+ fakeThumbnailLoader.invokeCalls.clear()
+ imageLoader.prePopulate(testUris)
+ advanceTimeBy(testTimeToLoadAllUris)
+ runCurrent()
+
+ // Assert
+ assertThat(fakeThumbnailLoader.invokeCalls).isEmpty()
+ }
+
+ @Test
+ fun prePopulate_fewerThatCacheSize_loadsTheGiven() =
+ testScope.runTest {
+ // Arrange
+ val unfilledCacheUris = testUris.take(testMaxConcurrency)
+ assertThat(unfilledCacheUris.size).isLessThan(testCacheSize)
+
+ // Act
+ imageLoader.prePopulate(unfilledCacheUris)
+ advanceTimeBy(testJobTime)
+ runCurrent()
+
+ // Assert
+ assertThat(fakeThumbnailLoader.invokeCalls).containsExactlyElementsIn(unfilledCacheUris)
+
+ // Act
+ fakeThumbnailLoader.invokeCalls.clear()
+ imageLoader.prePopulate(unfilledCacheUris)
+ advanceTimeBy(testJobTime)
+ runCurrent()
+
+ // Assert
+ assertThat(fakeThumbnailLoader.invokeCalls).isEmpty()
+ }
+
+ @Test
+ fun invoke_uncached_alwaysCallsTheThumbnailLoader() =
+ testScope.runTest {
+ // Arrange
+
+ // Act
+ imageLoader.invoke(testUris[0], caching = false)
+ imageLoader.invoke(testUris[0], caching = false)
+ advanceTimeBy(testJobTime)
+ runCurrent()
+
+ // Assert
+ assertThat(fakeThumbnailLoader.invokeCalls).containsExactly(testUris[0], testUris[0])
+ }
+
+ @Test
+ fun invoke_cached_usesTheCacheWhenPossible() =
+ testScope.runTest {
+ // Arrange
+
+ // Act
+ imageLoader.invoke(testUris[0], caching = true)
+ imageLoader.invoke(testUris[0], caching = true)
+ advanceTimeBy(testJobTime)
+ runCurrent()
+
+ // Assert
+ assertThat(fakeThumbnailLoader.invokeCalls).containsExactly(testUris[0])
+ }
+}
diff --git a/tests/unit/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/CursorPreviewsInteractorTest.kt b/tests/unit/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/CursorPreviewsInteractorTest.kt
index ff699373..0036e803 100644
--- a/tests/unit/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/CursorPreviewsInteractorTest.kt
+++ b/tests/unit/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/CursorPreviewsInteractorTest.kt
@@ -111,8 +111,12 @@ class CursorPreviewsInteractorTest {
@Test
fun initialCursorLoad() =
runTestWithDeps(
+ cursor = (0 until 10),
+ cursorStartPosition = 2,
cursorSizes = mapOf(0 to (200 x 100)),
- metadatSizes = mapOf(0 to (300 x 100), 3 to (400 x 100))
+ metadatSizes = mapOf(0 to (300 x 100), 3 to (400 x 100)),
+ pageSize = 2,
+ maxLoadedPages = 3,
) { deps ->
backgroundScope.launch {
cursorPreviewsInteractor.launch(deps.cursor, deps.initialPreviews)
@@ -120,31 +124,29 @@ class CursorPreviewsInteractorTest {
runCurrent()
assertThat(cursorPreviewsRepository.previewsModel.value).isNotNull()
- assertThat(cursorPreviewsRepository.previewsModel.value!!.startIdx).isEqualTo(0)
- assertThat(cursorPreviewsRepository.previewsModel.value!!.loadMoreLeft).isNull()
- assertThat(cursorPreviewsRepository.previewsModel.value!!.loadMoreRight).isNull()
- assertThat(cursorPreviewsRepository.previewsModel.value!!.previewModels)
- .containsExactly(
- PreviewModel(
- uri = Uri.fromParts("scheme0", "ssp0", "fragment0"),
- mimeType = "image/bitmap",
- aspectRatio = 2f,
- ),
- PreviewModel(
- uri = Uri.fromParts("scheme1", "ssp1", "fragment1"),
- mimeType = "image/bitmap"
- ),
- PreviewModel(
- uri = Uri.fromParts("scheme2", "ssp2", "fragment2"),
- mimeType = "image/bitmap"
- ),
- PreviewModel(
- uri = Uri.fromParts("scheme3", "ssp3", "fragment3"),
- mimeType = "image/bitmap",
- aspectRatio = 4f,
- ),
- )
- .inOrder()
+ with(cursorPreviewsRepository.previewsModel.value!!) {
+ assertThat(previewModels)
+ .containsExactlyElementsIn(
+ List(6) {
+ PreviewModel(
+ uri = Uri.fromParts("scheme$it", "ssp$it", "fragment$it"),
+ mimeType = "image/bitmap",
+ aspectRatio =
+ when (it) {
+ 0 -> 2f
+ 3 -> 4f
+ else -> 1f
+ }
+ )
+ }
+ )
+ .inOrder()
+ assertThat(startIdx).isEqualTo(0)
+ assertThat(loadMoreLeft).isNull()
+ assertThat(loadMoreRight).isNotNull()
+ assertThat(leftTriggerIndex).isEqualTo(2)
+ assertThat(rightTriggerIndex).isEqualTo(4)
+ }
}
@Test
@@ -181,39 +183,6 @@ class CursorPreviewsInteractorTest {
}
@Test
- fun loadMoreLeft_keepRight() =
- runTestWithDeps(
- initialSelection = listOf(24),
- cursor = (0 until 48),
- pageSize = 16,
- maxLoadedPages = 2,
- ) { deps ->
- backgroundScope.launch {
- cursorPreviewsInteractor.launch(deps.cursor, deps.initialPreviews)
- }
- runCurrent()
-
- assertThat(cursorPreviewsRepository.previewsModel.value).isNotNull()
- assertThat(cursorPreviewsRepository.previewsModel.value!!.previewModels).hasSize(16)
- assertThat(cursorPreviewsRepository.previewsModel.value!!.previewModels.first().uri)
- .isEqualTo(Uri.fromParts("scheme16", "ssp16", "fragment16"))
- assertThat(cursorPreviewsRepository.previewsModel.value!!.previewModels.last().uri)
- .isEqualTo(Uri.fromParts("scheme31", "ssp31", "fragment31"))
- assertThat(cursorPreviewsRepository.previewsModel.value!!.loadMoreLeft).isNotNull()
-
- cursorPreviewsRepository.previewsModel.value!!.loadMoreLeft!!.invoke()
- runCurrent()
-
- assertThat(cursorPreviewsRepository.previewsModel.value).isNotNull()
- assertThat(cursorPreviewsRepository.previewsModel.value!!.previewModels).hasSize(32)
- assertThat(cursorPreviewsRepository.previewsModel.value!!.previewModels.first().uri)
- .isEqualTo(Uri.fromParts("scheme0", "ssp0", "fragment0"))
- assertThat(cursorPreviewsRepository.previewsModel.value!!.previewModels.last().uri)
- .isEqualTo(Uri.fromParts("scheme31", "ssp31", "fragment31"))
- assertThat(cursorPreviewsRepository.previewsModel.value!!.loadMoreLeft).isNull()
- }
-
- @Test
fun loadMoreRight_evictLeft() =
runTestWithDeps(
initialSelection = listOf(24),
@@ -246,38 +215,6 @@ class CursorPreviewsInteractorTest {
}
@Test
- fun loadMoreRight_keepLeft() =
- runTestWithDeps(
- initialSelection = listOf(24),
- cursor = (0 until 48),
- pageSize = 16,
- maxLoadedPages = 2,
- ) { deps ->
- backgroundScope.launch {
- cursorPreviewsInteractor.launch(deps.cursor, deps.initialPreviews)
- }
- runCurrent()
-
- assertThat(cursorPreviewsRepository.previewsModel.value).isNotNull()
- assertThat(cursorPreviewsRepository.previewsModel.value!!.previewModels).hasSize(16)
- assertThat(cursorPreviewsRepository.previewsModel.value!!.previewModels.first().uri)
- .isEqualTo(Uri.fromParts("scheme16", "ssp16", "fragment16"))
- assertThat(cursorPreviewsRepository.previewsModel.value!!.previewModels.last().uri)
- .isEqualTo(Uri.fromParts("scheme31", "ssp31", "fragment31"))
- assertThat(cursorPreviewsRepository.previewsModel.value!!.loadMoreRight).isNotNull()
-
- cursorPreviewsRepository.previewsModel.value!!.loadMoreRight!!.invoke()
- runCurrent()
-
- assertThat(cursorPreviewsRepository.previewsModel.value).isNotNull()
- assertThat(cursorPreviewsRepository.previewsModel.value!!.previewModels).hasSize(32)
- assertThat(cursorPreviewsRepository.previewsModel.value!!.previewModels.first().uri)
- .isEqualTo(Uri.fromParts("scheme16", "ssp16", "fragment16"))
- assertThat(cursorPreviewsRepository.previewsModel.value!!.previewModels.last().uri)
- .isEqualTo(Uri.fromParts("scheme47", "ssp47", "fragment47"))
- }
-
- @Test
fun noMoreRight_appendUnclaimedFromInitialSelection() =
runTestWithDeps(
initialSelection = listOf(24, 50),
diff --git a/tests/unit/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/FetchPreviewsInteractorTest.kt b/tests/unit/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/FetchPreviewsInteractorTest.kt
index 735bcb1d..d04c984f 100644
--- a/tests/unit/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/FetchPreviewsInteractorTest.kt
+++ b/tests/unit/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/FetchPreviewsInteractorTest.kt
@@ -53,7 +53,7 @@ class FetchPreviewsInteractorTest {
cursor: Iterable<Int> = (0 until 4),
cursorStartPosition: Int = cursor.count() / 2,
pageSize: Int = 16,
- maxLoadedPages: Int = 3,
+ maxLoadedPages: Int = 8,
previewSizes: Map<Int, Size> = emptyMap(),
block: KosmosTestScope.() -> Unit,
) {
@@ -113,7 +113,7 @@ class FetchPreviewsInteractorTest {
.isEqualTo(
PreviewsModel(
previewModels =
- setOf(
+ listOf(
PreviewModel(
uri = Uri.fromParts("scheme1", "ssp1", "fragment1"),
mimeType = "image/bitmap",
@@ -127,6 +127,8 @@ class FetchPreviewsInteractorTest {
startIdx = 1,
loadMoreLeft = null,
loadMoreRight = null,
+ leftTriggerIndex = 0,
+ rightTriggerIndex = 1,
)
)
}
@@ -202,38 +204,6 @@ class FetchPreviewsInteractorTest {
}
@Test
- fun loadMoreLeft_keepRight() =
- runTest(
- initialSelection = listOf(24),
- cursor = (0 until 48),
- pageSize = 16,
- maxLoadedPages = 2,
- ) {
- backgroundScope.launch { fetchPreviewsInteractor.activate() }
- fakeCursorResolver.complete()
- runCurrent()
-
- assertThat(cursorPreviewsRepository.previewsModel.value).isNotNull()
- assertThat(cursorPreviewsRepository.previewsModel.value!!.previewModels).hasSize(16)
- assertThat(cursorPreviewsRepository.previewsModel.value!!.previewModels.first().uri)
- .isEqualTo(Uri.fromParts("scheme16", "ssp16", "fragment16"))
- assertThat(cursorPreviewsRepository.previewsModel.value!!.previewModels.last().uri)
- .isEqualTo(Uri.fromParts("scheme31", "ssp31", "fragment31"))
- assertThat(cursorPreviewsRepository.previewsModel.value!!.loadMoreLeft).isNotNull()
-
- cursorPreviewsRepository.previewsModel.value!!.loadMoreLeft!!.invoke()
- runCurrent()
-
- assertThat(cursorPreviewsRepository.previewsModel.value).isNotNull()
- assertThat(cursorPreviewsRepository.previewsModel.value!!.previewModels).hasSize(32)
- assertThat(cursorPreviewsRepository.previewsModel.value!!.previewModels.first().uri)
- .isEqualTo(Uri.fromParts("scheme0", "ssp0", "fragment0"))
- assertThat(cursorPreviewsRepository.previewsModel.value!!.previewModels.last().uri)
- .isEqualTo(Uri.fromParts("scheme31", "ssp31", "fragment31"))
- assertThat(cursorPreviewsRepository.previewsModel.value!!.loadMoreLeft).isNull()
- }
-
- @Test
fun loadMoreRight_evictLeft() =
runTest(
initialSelection = listOf(24),
@@ -265,37 +235,6 @@ class FetchPreviewsInteractorTest {
}
@Test
- fun loadMoreRight_keepLeft() =
- runTest(
- initialSelection = listOf(24),
- cursor = (0 until 48),
- pageSize = 16,
- maxLoadedPages = 2,
- ) {
- backgroundScope.launch { fetchPreviewsInteractor.activate() }
- fakeCursorResolver.complete()
- runCurrent()
-
- assertThat(cursorPreviewsRepository.previewsModel.value).isNotNull()
- assertThat(cursorPreviewsRepository.previewsModel.value!!.previewModels).hasSize(16)
- assertThat(cursorPreviewsRepository.previewsModel.value!!.previewModels.first().uri)
- .isEqualTo(Uri.fromParts("scheme16", "ssp16", "fragment16"))
- assertThat(cursorPreviewsRepository.previewsModel.value!!.previewModels.last().uri)
- .isEqualTo(Uri.fromParts("scheme31", "ssp31", "fragment31"))
- assertThat(cursorPreviewsRepository.previewsModel.value!!.loadMoreRight).isNotNull()
-
- cursorPreviewsRepository.previewsModel.value!!.loadMoreRight!!.invoke()
- runCurrent()
-
- assertThat(cursorPreviewsRepository.previewsModel.value).isNotNull()
- assertThat(cursorPreviewsRepository.previewsModel.value!!.previewModels).hasSize(32)
- assertThat(cursorPreviewsRepository.previewsModel.value!!.previewModels.first().uri)
- .isEqualTo(Uri.fromParts("scheme16", "ssp16", "fragment16"))
- assertThat(cursorPreviewsRepository.previewsModel.value!!.previewModels.last().uri)
- .isEqualTo(Uri.fromParts("scheme47", "ssp47", "fragment47"))
- }
-
- @Test
fun noMoreRight_appendUnclaimedFromInitialSelection() =
runTest(
initialSelection = listOf(24, 50),
diff --git a/tests/unit/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/SelectablePreviewInteractorTest.kt b/tests/unit/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/SelectablePreviewInteractorTest.kt
index a3c65570..0275a9c3 100644
--- a/tests/unit/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/SelectablePreviewInteractorTest.kt
+++ b/tests/unit/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/SelectablePreviewInteractorTest.kt
@@ -64,7 +64,7 @@ class SelectablePreviewInteractorTest {
assertThat(underTest.isSelected.first()).isFalse()
previewSelectionsRepository.selections.value =
- setOf(
+ listOf(
PreviewModel(
uri = Uri.fromParts("scheme", "ssp", "fragment"),
mimeType = "image/bitmap"
diff --git a/tests/unit/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/SelectablePreviewsInteractorTest.kt b/tests/unit/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/SelectablePreviewsInteractorTest.kt
index be5ddfe5..14b9c49c 100644
--- a/tests/unit/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/SelectablePreviewsInteractorTest.kt
+++ b/tests/unit/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/SelectablePreviewsInteractorTest.kt
@@ -39,7 +39,7 @@ class SelectablePreviewsInteractorTest {
cursorPreviewsRepository.previewsModel.value =
PreviewsModel(
previewModels =
- setOf(
+ listOf(
PreviewModel(
uri = Uri.fromParts("scheme", "ssp", "fragment"),
mimeType = "image/bitmap",
@@ -52,9 +52,11 @@ class SelectablePreviewsInteractorTest {
startIdx = 0,
loadMoreLeft = null,
loadMoreRight = null,
+ leftTriggerIndex = 0,
+ rightTriggerIndex = 1,
)
previewSelectionsRepository.selections.value =
- setOf(
+ listOf(
PreviewModel(uri = Uri.fromParts("scheme", "ssp", "fragment"), mimeType = null),
)
targetIntentModifier = TargetIntentModifier { error("unexpected invocation") }
@@ -94,7 +96,7 @@ class SelectablePreviewsInteractorTest {
@Test
fun keySet_reflectsRepositoryUpdate() = runKosmosTest {
previewSelectionsRepository.selections.value =
- setOf(
+ listOf(
PreviewModel(uri = Uri.fromParts("scheme", "ssp", "fragment"), mimeType = null),
)
targetIntentModifier = TargetIntentModifier { error("unexpected invocation") }
@@ -114,7 +116,7 @@ class SelectablePreviewsInteractorTest {
cursorPreviewsRepository.previewsModel.value =
PreviewsModel(
previewModels =
- setOf(
+ listOf(
PreviewModel(
uri = Uri.fromParts("scheme", "ssp", "fragment"),
mimeType = "image/bitmap",
@@ -127,8 +129,10 @@ class SelectablePreviewsInteractorTest {
startIdx = 5,
loadMoreLeft = null,
loadMoreRight = { loadRequested = true },
+ leftTriggerIndex = 0,
+ rightTriggerIndex = 1,
)
- previewSelectionsRepository.selections.value = emptySet()
+ previewSelectionsRepository.selections.value = emptyList()
runCurrent()
assertThat(previews.value).isNotNull()
diff --git a/tests/unit/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/SelectionInteractorTest.kt b/tests/unit/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/SelectionInteractorTest.kt
new file mode 100644
index 00000000..a50efebf
--- /dev/null
+++ b/tests/unit/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/SelectionInteractorTest.kt
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.intentresolver.contentpreview.payloadtoggle.domain.interactor
+
+import android.content.Intent
+import android.net.Uri
+import com.android.intentresolver.contentpreview.mimetypeClassifier
+import com.android.intentresolver.contentpreview.payloadtoggle.data.repository.previewSelectionsRepository
+import com.android.intentresolver.contentpreview.payloadtoggle.shared.model.PreviewModel
+import com.android.intentresolver.util.runKosmosTest
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+
+class SelectionInteractorTest {
+ @Test
+ fun singleSelection_removalPrevented() = runKosmosTest {
+ val initialPreview =
+ PreviewModel(uri = Uri.fromParts("scheme", "ssp", "fragment"), mimeType = null)
+ previewSelectionsRepository.selections.value = listOf(initialPreview)
+
+ val underTest =
+ SelectionInteractor(
+ previewSelectionsRepository,
+ { Intent() },
+ updateTargetIntentInteractor,
+ mimetypeClassifier,
+ )
+
+ assertThat(underTest.selections.value).containsExactly(initialPreview)
+
+ // Shouldn't do anything!
+ underTest.unselect(initialPreview)
+
+ assertThat(underTest.selections.value).containsExactly(initialPreview)
+ }
+
+ @Test
+ fun multipleSelections_removalAllowed() = runKosmosTest {
+ val first = PreviewModel(uri = Uri.fromParts("scheme", "ssp", "fragment"), mimeType = null)
+ val second =
+ PreviewModel(uri = Uri.fromParts("scheme2", "ssp2", "fragment2"), mimeType = null)
+ previewSelectionsRepository.selections.value = listOf(first, second)
+
+ val underTest =
+ SelectionInteractor(
+ previewSelectionsRepository,
+ { Intent() },
+ updateTargetIntentInteractor,
+ mimetypeClassifier
+ )
+
+ underTest.unselect(first)
+
+ assertThat(underTest.selections.value).containsExactly(second)
+ }
+}
diff --git a/tests/unit/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/SetCursorPreviewsInteractorTest.kt b/tests/unit/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/SetCursorPreviewsInteractorTest.kt
index 5aac7b55..a165b41e 100644
--- a/tests/unit/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/SetCursorPreviewsInteractorTest.kt
+++ b/tests/unit/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/SetCursorPreviewsInteractorTest.kt
@@ -34,8 +34,8 @@ class SetCursorPreviewsInteractorTest {
fun setPreviews_noAdditionalData() = runKosmosTest {
val loadState =
setCursorPreviewsInteractor.setPreviews(
- previewsByKey =
- setOf(
+ previews =
+ listOf(
PreviewModel(
uri = Uri.fromParts("scheme", "ssp", "fragment"),
mimeType = null,
@@ -44,6 +44,8 @@ class SetCursorPreviewsInteractorTest {
startIndex = 100,
hasMoreLeft = false,
hasMoreRight = false,
+ leftTriggerIndex = 0,
+ rightTriggerIndex = 0,
)
assertThat(loadState.first()).isNull()
@@ -69,8 +71,8 @@ class SetCursorPreviewsInteractorTest {
val loadState =
setCursorPreviewsInteractor
.setPreviews(
- previewsByKey =
- setOf(
+ previews =
+ listOf(
PreviewModel(
uri = Uri.fromParts("scheme", "ssp", "fragment"),
mimeType = null,
@@ -79,6 +81,8 @@ class SetCursorPreviewsInteractorTest {
startIndex = 100,
hasMoreLeft = true,
hasMoreRight = true,
+ leftTriggerIndex = 0,
+ rightTriggerIndex = 0,
)
.stateIn(backgroundScope)
diff --git a/tests/unit/src/com/android/intentresolver/contentpreview/payloadtoggle/ui/viewmodel/ShareouselViewModelTest.kt b/tests/unit/src/com/android/intentresolver/contentpreview/payloadtoggle/ui/viewmodel/ShareouselViewModelTest.kt
index bd3d88f8..ec4a9c3e 100644
--- a/tests/unit/src/com/android/intentresolver/contentpreview/payloadtoggle/ui/viewmodel/ShareouselViewModelTest.kt
+++ b/tests/unit/src/com/android/intentresolver/contentpreview/payloadtoggle/ui/viewmodel/ShareouselViewModelTest.kt
@@ -25,6 +25,7 @@ import android.graphics.drawable.Icon
import android.net.Uri
import com.android.intentresolver.FakeImageLoader
import com.android.intentresolver.contentpreview.HeadlineGenerator
+import com.android.intentresolver.contentpreview.mimetypeClassifier
import com.android.intentresolver.contentpreview.payloadtoggle.data.model.CustomActionModel
import com.android.intentresolver.contentpreview.payloadtoggle.data.repository.activityResultRepository
import com.android.intentresolver.contentpreview.payloadtoggle.data.repository.cursorPreviewsRepository
@@ -39,6 +40,7 @@ import com.android.intentresolver.contentpreview.payloadtoggle.domain.interactor
import com.android.intentresolver.contentpreview.payloadtoggle.domain.interactor.payloadToggleImageLoader
import com.android.intentresolver.contentpreview.payloadtoggle.domain.interactor.selectablePreviewsInteractor
import com.android.intentresolver.contentpreview.payloadtoggle.domain.interactor.selectionInteractor
+import com.android.intentresolver.contentpreview.payloadtoggle.shared.ContentType
import com.android.intentresolver.contentpreview.payloadtoggle.shared.model.PreviewModel
import com.android.intentresolver.contentpreview.payloadtoggle.shared.model.PreviewsModel
import com.android.intentresolver.data.model.ChooserRequest
@@ -68,23 +70,24 @@ class ShareouselViewModelTest {
actionsInteractor = customActionsInteractor,
headlineGenerator = headlineGenerator,
chooserRequestInteractor = chooserRequestInteractor,
+ mimeTypeClassifier = mimetypeClassifier,
selectionInteractor = selectionInteractor,
scope = viewModelScope,
)
}
@Test
- fun headline() = runTest {
- assertThat(shareouselViewModel.headline.first()).isEqualTo("IMAGES: 1")
+ fun headline_images() = runTest {
+ assertThat(shareouselViewModel.headline.first()).isEqualTo("FILES: 1")
previewSelectionsRepository.selections.value =
- setOf(
+ listOf(
PreviewModel(
uri = Uri.fromParts("scheme", "ssp", "fragment"),
- mimeType = null,
+ mimeType = "image/png",
),
PreviewModel(
uri = Uri.fromParts("scheme1", "ssp1", "fragment1"),
- mimeType = null,
+ mimeType = "image/jpeg",
)
)
runCurrent()
@@ -92,6 +95,40 @@ class ShareouselViewModelTest {
}
@Test
+ fun headline_videos() = runTest {
+ previewSelectionsRepository.selections.value =
+ listOf(
+ PreviewModel(
+ uri = Uri.fromParts("scheme", "ssp", "fragment"),
+ mimeType = "video/mpeg",
+ ),
+ PreviewModel(
+ uri = Uri.fromParts("scheme1", "ssp1", "fragment1"),
+ mimeType = "video/mpeg",
+ )
+ )
+ runCurrent()
+ assertThat(shareouselViewModel.headline.first()).isEqualTo("VIDEOS: 2")
+ }
+
+ @Test
+ fun headline_mixed() = runTest {
+ previewSelectionsRepository.selections.value =
+ listOf(
+ PreviewModel(
+ uri = Uri.fromParts("scheme", "ssp", "fragment"),
+ mimeType = "image/jpeg",
+ ),
+ PreviewModel(
+ uri = Uri.fromParts("scheme1", "ssp1", "fragment1"),
+ mimeType = "video/mpeg",
+ )
+ )
+ runCurrent()
+ assertThat(shareouselViewModel.headline.first()).isEqualTo("FILES: 2")
+ }
+
+ @Test
fun metadataText() = runTest {
val request =
ChooserRequest(
@@ -112,19 +149,21 @@ class ShareouselViewModelTest {
cursorPreviewsRepository.previewsModel.value =
PreviewsModel(
previewModels =
- setOf(
+ listOf(
PreviewModel(
uri = Uri.fromParts("scheme", "ssp", "fragment"),
- mimeType = null,
+ mimeType = "image/png",
),
PreviewModel(
uri = Uri.fromParts("scheme1", "ssp1", "fragment1"),
- mimeType = null,
+ mimeType = "video/mpeg",
)
),
startIdx = 1,
loadMoreLeft = null,
loadMoreRight = null,
+ leftTriggerIndex = 0,
+ rightTriggerIndex = 1,
)
runCurrent()
@@ -140,15 +179,17 @@ class ShareouselViewModelTest {
.inOrder()
val previewVm =
- shareouselViewModel.preview(
+ shareouselViewModel.preview.invoke(
PreviewModel(
uri = Uri.fromParts("scheme1", "ssp1", "fragment1"),
- mimeType = null
- )
+ mimeType = "video/mpeg"
+ ),
+ /* index = */ 1,
)
assertWithMessage("preview bitmap is null").that(previewVm.bitmap.first()).isNotNull()
assertThat(previewVm.isSelected.first()).isFalse()
+ assertThat(previewVm.contentType).isEqualTo(ContentType.Video)
previewVm.setSelected(true)
@@ -208,7 +249,7 @@ class ShareouselViewModelTest {
this.pendingIntentSender = pendingIntentSender
this.targetIntentModifier = targetIntentModifier
previewSelectionsRepository.selections.value =
- setOf(PreviewModel(uri = Uri.fromParts("scheme", "ssp", "fragment"), mimeType = null))
+ listOf(PreviewModel(uri = Uri.fromParts("scheme", "ssp", "fragment"), mimeType = null))
payloadToggleImageLoader =
FakeImageLoader(
initialBitmaps =
@@ -234,9 +275,9 @@ class ShareouselViewModelTest {
override fun getFilesWithTextHeadline(text: CharSequence, count: Int): String =
error("not supported")
- override fun getVideosHeadline(count: Int): String = error("not supported")
+ override fun getVideosHeadline(count: Int): String = "VIDEOS: $count"
- override fun getFilesHeadline(count: Int): String = error("not supported")
+ override fun getFilesHeadline(count: Int): String = "FILES: $count"
}
// instantiate the view model, and then runCurrent() so that it is fully hydrated before
// starting the test