Loading tests/unit/com/android/documentsui/loaders/BaseLoaderTest.kt +14 −2 Original line number Diff line number Diff line Loading @@ -52,7 +52,19 @@ data class LoaderTestParams( val otherArgs: Bundle, // The number of files that are expected, for the above parameters, to be found by a loader. val expectedCount: Int, ) ) { override fun toString(): String { var base = "query '$query'" if (lastModifiedDelta != null) { val durationInMs = lastModifiedDelta.toSeconds() base = "$base, modified in the last ${durationInMs}s" } if (!otherArgs.isEmpty) { base = "$base, and $otherArgs" } return "$base, expecting $expectedCount matches" } } /** * Common base class for search and folder loaders. Loading @@ -63,7 +75,7 @@ open class BaseLoaderTest { lateinit var mTestConfigStore: TestConfigStore @Before open fun setUp() { fun setUp() { mEnv = TestEnv.create() mTestConfigStore = TestConfigStore() mEnv.state.configStore = mTestConfigStore Loading tests/unit/com/android/documentsui/loaders/FolderLoaderTest.kt +1 −2 Original line number Diff line number Diff line Loading @@ -62,8 +62,7 @@ class FolderLoaderTest(private val testParams: LoaderTestParams) : BaseLoaderTes lateinit var queryOptions: QueryOptions @Before override fun setUp() { super.setUp() fun setUpTest() { queryOptions = QueryOptions( TOTAL_FILE_COUNT, Loading tests/unit/com/android/documentsui/loaders/SearchLoaderTest.kt +145 −88 Original line number Diff line number Diff line Loading @@ -21,20 +21,24 @@ import android.provider.DocumentsContract import androidx.test.filters.SmallTest import com.android.documentsui.ContentLock import com.android.documentsui.LockingContentObserver import com.android.documentsui.Model import com.android.documentsui.base.DocumentInfo import com.android.documentsui.base.FolderInfo import com.android.documentsui.flags.Flags.FLAG_USE_SEARCH_V2_READ_ONLY import com.android.documentsui.rules.CheckAndForceMaterial3Flag import com.android.documentsui.sorting.SortModel import com.android.documentsui.testing.TestFeatures import com.android.documentsui.testing.TestFileTypeLookup import com.android.documentsui.testing.TestProvidersAccess import com.google.common.truth.Expect import java.time.Duration import java.util.Locale import java.util.concurrent.ExecutorService import java.util.concurrent.Executors import junit.framework.Assert.assertEquals import org.junit.Assert.assertThrows import org.junit.Before import org.junit.Ignore import org.junit.Rule import org.junit.Test import org.junit.experimental.runners.Enclosed import org.junit.runner.RunWith import org.junit.runners.Parameterized import org.junit.runners.Parameterized.Parameters Loading @@ -47,9 +51,13 @@ fun createQueryArgs(vararg mimeTypes: String): Bundle { return args } @RunWith(Parameterized::class) @RunWith(Enclosed::class) @SmallTest class SearchLoaderTest(private val testParams: LoaderTestParams) : BaseLoaderTest() { class SearchLoaderTest { // Collection of tests that are parametrized by query, duration, and MIME type. @RunWith(Parameterized::class) class ParametrizedTests(private val testParams: LoaderTestParams) : BaseLoaderTest() { lateinit var mExecutor: ExecutorService val mContentLock = ContentLock() val mContentObserver = LockingContentObserver(mContentLock) {} Loading @@ -72,9 +80,11 @@ class SearchLoaderTest(private val testParams: LoaderTestParams) : BaseLoaderTes @get:Rule val checkFlags = CheckAndForceMaterial3Flag() @get:Rule val expect: Expect = Expect.create() @Before override fun setUp() { super.setUp() fun setUpTest() { mExecutor = Executors.newSingleThreadExecutor() } Loading @@ -94,8 +104,7 @@ class SearchLoaderTest(private val testParams: LoaderTestParams) : BaseLoaderTes testParams.otherArgs, ) val folderInfo = listOf( val folderInfo = listOf( FolderInfo( TestProvidersAccess.DOWNLOADS.rootId, TestProvidersAccess.DOWNLOADS.authority Loading @@ -114,52 +123,100 @@ class SearchLoaderTest(private val testParams: LoaderTestParams) : BaseLoaderTes mExecutor, ) val directoryResult = loader.loadInBackground() assertEquals(testParams.expectedCount, getFileCount(directoryResult)) expect.that(getFileCount(directoryResult)).isEqualTo(testParams.expectedCount) } } // Collection of plain tests that do not use parameters. class PlainTests : BaseLoaderTest() { @get:Rule val checkFlags = CheckAndForceMaterial3Flag() @get:Rule val expect: Expect = Expect.create() lateinit var mExecutor: ExecutorService val mContentLock = ContentLock() val mContentObserver = LockingContentObserver(mContentLock) {} @Before fun setUpTest() { mExecutor = Executors.newSingleThreadExecutor() } fun generateDocuments( count: Int, suffixOffset: Int, extensions: Array<String> ): Array<DocumentInfo> { return Array(count) { i -> val suffix = String.format(Locale.US, "%05d", 2 * i + suffixOffset) val ext = extensions[i % extensions.size] mEnv.model.createFile("document-$suffix.$ext") } } /** * Checks that the merging, filtering and sorting of results works correctly. We set up * two providers: home and pickles storage. They get files with names that have a zipper * like pattern, when sorted. Here we are checking if merging two cursors, with filtering * produces the expected result. */ @Test @RequiresFlagsEnabled(FLAG_USE_SEARCH_V2_READ_ONLY) @Ignore("b/397095797") fun testBlankQueryAndRecency() { val userIds = listOf(TestProvidersAccess.DOWNLOADS.userId) val folderInfo = listOf( FolderInfo( TestProvidersAccess.DOWNLOADS.rootId, TestProvidersAccess.DOWNLOADS.authority ) fun testValidateMergeFilterSort() { val fileCount = 200 val maxCount = fileCount / 2 mEnv.mockProviders.apply { // Pickles documents have IDs 0, 2, 4, .., 398. Half of the documents are images, // the other half are documents (PDFs). get(TestProvidersAccess.PICKLES.authority)!!.setNextChildDocumentsReturns( *generateDocuments(fileCount, 0, arrayOf("png", "pdf")) ) val noLastModifiedQueryOptions = QueryOptions(10, null, null, true, arrayOf("*/*"), Bundle()) // Blank query and no last modified duration is invalid. assertThrows(IllegalArgumentException::class.java) { SearchLoader( mActivity, userIds, TestFileTypeLookup(), mContentObserver, folderInfo, "", noLastModifiedQueryOptions, mEnv.state.sortModel, mExecutor, // Home documents have IDs 1, 3, 5, ... 399. Half of the documents are images, // the other half are videos. get(TestProvidersAccess.HOME.authority)!!.setNextChildDocumentsReturns( *generateDocuments(fileCount, 1, arrayOf("png", "avi")) ) } // Null query and no last modified duration is invalid. assertThrows(IllegalArgumentException::class.java) { SearchLoader( // Setup the sort model so that results are sorted by their name. val sortModel = SortModel.createModel() sortModel.setDefaultDimension(SortModel.SORT_DIMENSION_ID_TITLE) val folderInfo = listOf( FolderInfo( TestProvidersAccess.PICKLES.rootId, TestProvidersAccess.PICKLES.authority ), FolderInfo( TestProvidersAccess.HOME.rootId, TestProvidersAccess.HOME.authority ), ) val loader = SearchLoader( mActivity, userIds, listOf(TestProvidersAccess.PICKLES.userId, TestProvidersAccess.HOME.userId), TestFileTypeLookup(), mContentObserver, folderInfo, null, noLastModifiedQueryOptions, mEnv.state.sortModel, "document-", QueryOptions(maxCount, null, null, false, arrayOf("image/png"), Bundle()), sortModel, mExecutor, ) val result = loader.loadInBackground() expect.that(result?.cursor?.getCount()).isEqualTo(maxCount) // We expect a perfect mix of documents from PICKLES and HOME. Pickles has odd indices // Home has even indices. However, the filtering cursor should take out all non-images // leaving us with 0, 4, 8, ..., from PICKLES and 1, 5, 9, ... from HOME. val model = Model(TestFeatures()) model.update(result) val names = model.modelIds.map { model.getDocument(it)!!.displayName } expect.that(names).isEqualTo((0..maxCount - 1).map { val index = String.format(Locale.US, "%05d", 4 * (it / 2) + (it % 2)) "document-$index.png" }) } } } Loading
tests/unit/com/android/documentsui/loaders/BaseLoaderTest.kt +14 −2 Original line number Diff line number Diff line Loading @@ -52,7 +52,19 @@ data class LoaderTestParams( val otherArgs: Bundle, // The number of files that are expected, for the above parameters, to be found by a loader. val expectedCount: Int, ) ) { override fun toString(): String { var base = "query '$query'" if (lastModifiedDelta != null) { val durationInMs = lastModifiedDelta.toSeconds() base = "$base, modified in the last ${durationInMs}s" } if (!otherArgs.isEmpty) { base = "$base, and $otherArgs" } return "$base, expecting $expectedCount matches" } } /** * Common base class for search and folder loaders. Loading @@ -63,7 +75,7 @@ open class BaseLoaderTest { lateinit var mTestConfigStore: TestConfigStore @Before open fun setUp() { fun setUp() { mEnv = TestEnv.create() mTestConfigStore = TestConfigStore() mEnv.state.configStore = mTestConfigStore Loading
tests/unit/com/android/documentsui/loaders/FolderLoaderTest.kt +1 −2 Original line number Diff line number Diff line Loading @@ -62,8 +62,7 @@ class FolderLoaderTest(private val testParams: LoaderTestParams) : BaseLoaderTes lateinit var queryOptions: QueryOptions @Before override fun setUp() { super.setUp() fun setUpTest() { queryOptions = QueryOptions( TOTAL_FILE_COUNT, Loading
tests/unit/com/android/documentsui/loaders/SearchLoaderTest.kt +145 −88 Original line number Diff line number Diff line Loading @@ -21,20 +21,24 @@ import android.provider.DocumentsContract import androidx.test.filters.SmallTest import com.android.documentsui.ContentLock import com.android.documentsui.LockingContentObserver import com.android.documentsui.Model import com.android.documentsui.base.DocumentInfo import com.android.documentsui.base.FolderInfo import com.android.documentsui.flags.Flags.FLAG_USE_SEARCH_V2_READ_ONLY import com.android.documentsui.rules.CheckAndForceMaterial3Flag import com.android.documentsui.sorting.SortModel import com.android.documentsui.testing.TestFeatures import com.android.documentsui.testing.TestFileTypeLookup import com.android.documentsui.testing.TestProvidersAccess import com.google.common.truth.Expect import java.time.Duration import java.util.Locale import java.util.concurrent.ExecutorService import java.util.concurrent.Executors import junit.framework.Assert.assertEquals import org.junit.Assert.assertThrows import org.junit.Before import org.junit.Ignore import org.junit.Rule import org.junit.Test import org.junit.experimental.runners.Enclosed import org.junit.runner.RunWith import org.junit.runners.Parameterized import org.junit.runners.Parameterized.Parameters Loading @@ -47,9 +51,13 @@ fun createQueryArgs(vararg mimeTypes: String): Bundle { return args } @RunWith(Parameterized::class) @RunWith(Enclosed::class) @SmallTest class SearchLoaderTest(private val testParams: LoaderTestParams) : BaseLoaderTest() { class SearchLoaderTest { // Collection of tests that are parametrized by query, duration, and MIME type. @RunWith(Parameterized::class) class ParametrizedTests(private val testParams: LoaderTestParams) : BaseLoaderTest() { lateinit var mExecutor: ExecutorService val mContentLock = ContentLock() val mContentObserver = LockingContentObserver(mContentLock) {} Loading @@ -72,9 +80,11 @@ class SearchLoaderTest(private val testParams: LoaderTestParams) : BaseLoaderTes @get:Rule val checkFlags = CheckAndForceMaterial3Flag() @get:Rule val expect: Expect = Expect.create() @Before override fun setUp() { super.setUp() fun setUpTest() { mExecutor = Executors.newSingleThreadExecutor() } Loading @@ -94,8 +104,7 @@ class SearchLoaderTest(private val testParams: LoaderTestParams) : BaseLoaderTes testParams.otherArgs, ) val folderInfo = listOf( val folderInfo = listOf( FolderInfo( TestProvidersAccess.DOWNLOADS.rootId, TestProvidersAccess.DOWNLOADS.authority Loading @@ -114,52 +123,100 @@ class SearchLoaderTest(private val testParams: LoaderTestParams) : BaseLoaderTes mExecutor, ) val directoryResult = loader.loadInBackground() assertEquals(testParams.expectedCount, getFileCount(directoryResult)) expect.that(getFileCount(directoryResult)).isEqualTo(testParams.expectedCount) } } // Collection of plain tests that do not use parameters. class PlainTests : BaseLoaderTest() { @get:Rule val checkFlags = CheckAndForceMaterial3Flag() @get:Rule val expect: Expect = Expect.create() lateinit var mExecutor: ExecutorService val mContentLock = ContentLock() val mContentObserver = LockingContentObserver(mContentLock) {} @Before fun setUpTest() { mExecutor = Executors.newSingleThreadExecutor() } fun generateDocuments( count: Int, suffixOffset: Int, extensions: Array<String> ): Array<DocumentInfo> { return Array(count) { i -> val suffix = String.format(Locale.US, "%05d", 2 * i + suffixOffset) val ext = extensions[i % extensions.size] mEnv.model.createFile("document-$suffix.$ext") } } /** * Checks that the merging, filtering and sorting of results works correctly. We set up * two providers: home and pickles storage. They get files with names that have a zipper * like pattern, when sorted. Here we are checking if merging two cursors, with filtering * produces the expected result. */ @Test @RequiresFlagsEnabled(FLAG_USE_SEARCH_V2_READ_ONLY) @Ignore("b/397095797") fun testBlankQueryAndRecency() { val userIds = listOf(TestProvidersAccess.DOWNLOADS.userId) val folderInfo = listOf( FolderInfo( TestProvidersAccess.DOWNLOADS.rootId, TestProvidersAccess.DOWNLOADS.authority ) fun testValidateMergeFilterSort() { val fileCount = 200 val maxCount = fileCount / 2 mEnv.mockProviders.apply { // Pickles documents have IDs 0, 2, 4, .., 398. Half of the documents are images, // the other half are documents (PDFs). get(TestProvidersAccess.PICKLES.authority)!!.setNextChildDocumentsReturns( *generateDocuments(fileCount, 0, arrayOf("png", "pdf")) ) val noLastModifiedQueryOptions = QueryOptions(10, null, null, true, arrayOf("*/*"), Bundle()) // Blank query and no last modified duration is invalid. assertThrows(IllegalArgumentException::class.java) { SearchLoader( mActivity, userIds, TestFileTypeLookup(), mContentObserver, folderInfo, "", noLastModifiedQueryOptions, mEnv.state.sortModel, mExecutor, // Home documents have IDs 1, 3, 5, ... 399. Half of the documents are images, // the other half are videos. get(TestProvidersAccess.HOME.authority)!!.setNextChildDocumentsReturns( *generateDocuments(fileCount, 1, arrayOf("png", "avi")) ) } // Null query and no last modified duration is invalid. assertThrows(IllegalArgumentException::class.java) { SearchLoader( // Setup the sort model so that results are sorted by their name. val sortModel = SortModel.createModel() sortModel.setDefaultDimension(SortModel.SORT_DIMENSION_ID_TITLE) val folderInfo = listOf( FolderInfo( TestProvidersAccess.PICKLES.rootId, TestProvidersAccess.PICKLES.authority ), FolderInfo( TestProvidersAccess.HOME.rootId, TestProvidersAccess.HOME.authority ), ) val loader = SearchLoader( mActivity, userIds, listOf(TestProvidersAccess.PICKLES.userId, TestProvidersAccess.HOME.userId), TestFileTypeLookup(), mContentObserver, folderInfo, null, noLastModifiedQueryOptions, mEnv.state.sortModel, "document-", QueryOptions(maxCount, null, null, false, arrayOf("image/png"), Bundle()), sortModel, mExecutor, ) val result = loader.loadInBackground() expect.that(result?.cursor?.getCount()).isEqualTo(maxCount) // We expect a perfect mix of documents from PICKLES and HOME. Pickles has odd indices // Home has even indices. However, the filtering cursor should take out all non-images // leaving us with 0, 4, 8, ..., from PICKLES and 1, 5, 9, ... from HOME. val model = Model(TestFeatures()) model.update(result) val names = model.modelIds.map { model.getDocument(it)!!.displayName } expect.that(names).isEqualTo((0..maxCount - 1).map { val index = String.format(Locale.US, "%05d", 4 * (it / 2) + (it % 2)) "document-$index.png" }) } } }