/* * Copyright (C) 2025 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.lemenzo.files.rules import android.net.Uri import android.os.Bundle import android.provider.DocumentsContract import androidx.test.platform.app.InstrumentationRegistry import com.lemenzo.files.DocumentsProviderHelper import com.lemenzo.files.StubProvider import com.lemenzo.files.base.RootInfo import com.lemenzo.files.base.UserId import org.junit.rules.ExternalResource /** * Rule that creates test files in a test. * When `skipCreation` is false, this essentially falls back to providing a `docsHelper`. */ class TestFilesRule(private val skipCreation: Boolean = false) : ExternalResource() { // Only needed so that the file creation function could throw. interface CreateFilesFunction { @Throws(Exception::class) fun apply(helper: DocumentsProviderHelper) } lateinit var docsHelper: DocumentsProviderHelper // A map of the URIs that are created, used to keep track of names of items that are created // as children of other items. private val createdUris = mutableMapOf() // The creation operations are deferred as the rules are instantiated prior to the environment // being ready. private val deferredOperations = mutableListOf<() -> Unit>() override fun before() { docsHelper = DocumentsProviderHelper( UserId.DEFAULT_USER, StubProvider.DEFAULT_AUTHORITY, InstrumentationRegistry.getInstrumentation().context, StubProvider.DEFAULT_AUTHORITY, ) docsHelper.clear(null, null) docsHelper.configure(null, Bundle.EMPTY) if (skipCreation) { require( deferredOperations.isEmpty() ) { "Have deferred operations yet requested to skip creation." } return } if (deferredOperations.isEmpty()) { createDefault() } else { deferredOperations.forEach { it() } } } /** * Run file/folder create operations encapsulated in a provided function. Technically this lets * running any DocumentsProviderHelper functions, but should only be used to create files. */ fun createTestFiles(createTestFiles: CreateFilesFunction): TestFilesRule { deferredOperations.add { createTestFiles.apply(docsHelper) } return this } /** Returns `Uri` of the file with `filename` within the `root`. */ fun getUriInRoot(root: String, fileName: String): Uri? { return docsHelper.findDocument(getRoot(root).documentId, fileName).derivedUri } /** Returns`RootInfo` for the for the specified `root`. */ fun getRoot(root: String): RootInfo { return docsHelper.getRoot(root) } /** Creates a default set of files for testing. */ private fun createDefault() { val root0 = docsHelper.getRoot(StubProvider.ROOT_0_ID) val root1 = docsHelper.getRoot(StubProvider.ROOT_1_ID) docsHelper.createFolder(root0, DIR_NAME_1) docsHelper.createDocument(root0, "text/plain", FILE_NAME_1) docsHelper.createDocument(root0, "image/png", FILE_NAME_2) docsHelper.createDocumentWithFlags( root0.documentId, "text/plain", FILE_NAME_NO_RENAME, DocumentsContract.Document.FLAG_SUPPORTS_WRITE, ) docsHelper.createDocument(root1, "text/plain", FILE_NAME_3) docsHelper.createDocument(root1, "text/plain", FILE_NAME_4) } override fun after() { docsHelper.cleanUp() } companion object { @JvmField val DIR_NAME_1: String = "Dir1" @JvmField val CHILD_DIR_1: String = "ChildDir1" @JvmField val FILE_NAME_1: String = "file1.log" @JvmField val FILE_NAME_2: String = "file12.png" @JvmField val FILE_NAME_3: String = "anotherFile0.log" @JvmField val FILE_NAME_4: String = "poodles.text" @JvmField val FILE_NAME_NO_RENAME: String = "NO_RENAMEfile.txt" } }