blob: 674ae39d28395776d27b101e08fc2a7e0cf35e41 [file] [log] [blame]
/*
* Copyright (C) 2018 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.
*/
@file:JvmName("ResourcesTestsUtil")
package com.android.tools.idea.res
import com.android.SdkConstants
import com.android.ide.common.rendering.api.ResourceNamespace
import com.android.ide.common.util.toPathString
import com.android.projectmodel.SelectiveResourceFolder
import com.android.tools.idea.projectsystem.FilenameConstants
import com.android.tools.idea.resources.aar.AarSourceResourceRepository
import com.android.tools.idea.util.toVirtualFile
import com.intellij.openapi.module.Module
import com.intellij.openapi.roots.LibraryOrderEntry
import com.intellij.openapi.roots.ModuleRootModificationUtil
import com.intellij.openapi.util.io.FileUtil
import com.intellij.openapi.vfs.VfsUtil
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiFile
import com.intellij.testFramework.PsiTestUtil
import org.jetbrains.android.AndroidTestBase
import org.jetbrains.android.facet.AndroidFacet
import java.io.File
import java.nio.file.Paths
import java.util.jar.JarEntry
import java.util.jar.JarOutputStream
const val AAR_LIBRARY_NAME = "com.test:test-library:1.0.0"
const val AAR_PACKAGE_NAME = "com.test.testlibrary"
fun createTestAppResourceRepository(facet: AndroidFacet): LocalResourceRepository {
val moduleResources = createTestModuleRepository(facet, emptyList())
val projectResources = ProjectResourceRepository.createForTest(facet, listOf(moduleResources))
val appResources = AppResourceRepository.createForTest(facet, listOf<LocalResourceRepository>(projectResources), emptyList())
val aar = getTestAarRepository()
appResources.updateRoots(listOf(projectResources), listOf(aar))
return appResources
}
@JvmOverloads
fun getTestAarRepository(libraryDirName: String = "my_aar_lib"): AarSourceResourceRepository {
return AarSourceResourceRepository.create(
Paths.get(AndroidTestBase.getTestDataPath(), "rendering", FilenameConstants.EXPLODED_AAR, libraryDirName, "res").toFile(),
AAR_LIBRARY_NAME
)
}
fun getTestAarRepositoryWithResourceFolders(libraryDirName: String, vararg resources: String): AarSourceResourceRepository {
val root = Paths.get(AndroidTestBase.getTestDataPath(), "rendering", FilenameConstants.EXPLODED_AAR, libraryDirName, "res").toPathString()
return AarSourceResourceRepository.create(
SelectiveResourceFolder(root, resources.map { resource -> root.resolve(resource) }),
AAR_LIBRARY_NAME
)
}
@JvmOverloads
fun createTestModuleRepository(
facet: AndroidFacet,
resourceDirectories: Collection<VirtualFile>,
namespace: ResourceNamespace = ResourceNamespace.RES_AUTO,
dynamicRepo: DynamicResourceValueRepository? = null
): LocalResourceRepository {
return ModuleResourceRepository.createForTest(facet, resourceDirectories, namespace, dynamicRepo)
}
/**
* Adds a library dependency to the given module and runs the given function to add resources to it.
*
* [ResourceRepositoryManager] will find the newly added library and create a separate repository for it when
* [ResourceRepositoryManager.getExistingAppResources] is called.
*
* @param module module to add the dependency to.
* @param libraryName name of the newly created [LibraryOrderEntry].
* @param packageName package name to be put in the library manifest.
* @param createResources code that will be invoked on the library resources folder, to add desired resources. VFS will be refreshed after
* the function is done.
*/
fun addAarDependency(
module: Module,
libraryName: String,
packageName: String,
createResources: (File) -> Unit
) {
val aarDir = FileUtil.createTempDirectory(libraryName, "_exploded")
// Create a manifest file in the right place, so that files inside aarDir are considered resource files.
// See AndroidResourceUtil#isResourceDirectory which is called from ResourcesDomFileDescription#isResourcesFile.
aarDir.resolve(SdkConstants.FN_ANDROID_MANIFEST_XML).writeText(
// language=xml
"""
<manifest package="$packageName">
</manifest>
""".trimIndent()
)
val resDir = aarDir.resolve(SdkConstants.FD_RES)
resDir.mkdir()
resDir.resolve(SdkConstants.FD_RES_VALUES).mkdir()
val classesJar = aarDir.resolve(SdkConstants.FN_CLASSES_JAR)
JarOutputStream(classesJar.outputStream()).use {
it.putNextEntry(JarEntry("META-INF/empty"))
}
// See ResourceFolderManager.isAarDependency for what this library must look like to be considered an AAR.
val library = PsiTestUtil.addProjectLibrary(
module,
"$libraryName.aar",
listOf(
resDir.toVirtualFile(refresh = true),
classesJar.toVirtualFile(refresh = true)
),
emptyList()
)
ModuleRootModificationUtil.addDependency(module, library)
createResources(resDir)
VfsUtil.markDirtyAndRefresh(false, true, true, aarDir.toVirtualFile(refresh = true))
}
/**
* Adds an AARv2 library dependency to the given module. The library uses the checked-in example res.apk file which uses
* `com.example.mylibrary` package name and contains a single resource, `@string/my_aar_string`.
*/
fun addBinaryAarDependency(module: Module) {
// See org.jetbrains.android.facet.ResourceFolderManager#isAarDependency
PsiTestUtil.addLibrary(
module,
"mylibrary.aar",
"${AndroidTestBase.getTestDataPath()}/dom/layout/myaar-v2",
"classes.jar",
"res.apk"
)
}
/**
* Exposes protected method [LocalResourceRepository.isScanPending] for usage in tests.
*/
fun checkIfScanPending(repository: LocalResourceRepository, psiFile: PsiFile) = repository.isScanPending(psiFile)