blob: 3163f636a24ec66396076b4f3affffd2f96a8ed8 [file] [log] [blame]
/*
* Copyright 2016 The Bazel Authors. All rights reserved.
*
* 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.google.idea.blaze.android.rendering;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import com.android.tools.idea.rendering.RenderErrorContributor;
import com.android.tools.idea.rendering.RenderErrorModelFactory;
import com.android.tools.idea.rendering.RenderResult;
import com.android.tools.idea.rendering.errors.ui.RenderErrorModel;
import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
import com.google.idea.blaze.android.sync.model.AndroidResourceModule;
import com.google.idea.blaze.android.sync.model.AndroidResourceModuleRegistry;
import com.google.idea.blaze.base.BlazeTestCase;
import com.google.idea.blaze.base.ideinfo.AndroidIdeInfo;
import com.google.idea.blaze.base.ideinfo.ArtifactLocation;
import com.google.idea.blaze.base.ideinfo.JavaIdeInfo;
import com.google.idea.blaze.base.ideinfo.TargetIdeInfo;
import com.google.idea.blaze.base.ideinfo.TargetKey;
import com.google.idea.blaze.base.ideinfo.TargetMap;
import com.google.idea.blaze.base.ideinfo.TargetMapBuilder;
import com.google.idea.blaze.base.lang.buildfile.references.BuildReferenceManager;
import com.google.idea.blaze.base.model.BlazeProjectData;
import com.google.idea.blaze.base.model.MockBlazeProjectDataBuilder;
import com.google.idea.blaze.base.model.primitives.Label;
import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
import com.google.idea.blaze.base.settings.BlazeImportSettings;
import com.google.idea.blaze.base.settings.BlazeImportSettingsManager;
import com.google.idea.blaze.base.sync.data.BlazeProjectDataManager;
import com.google.idea.blaze.base.sync.workspace.ArtifactLocationDecoder;
import com.google.idea.blaze.base.targetmaps.SourceToTargetMap;
import com.google.idea.blaze.base.targetmaps.TransitiveDependencyMap;
import com.intellij.mock.MockModule;
import com.intellij.mock.MockPsiFile;
import com.intellij.mock.MockPsiManager;
import com.intellij.mock.MockVirtualFile;
import com.intellij.openapi.extensions.ExtensionPoint;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.openapi.fileTypes.FileTypeManager;
import com.intellij.openapi.fileTypes.MockFileTypeManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleUtilCore;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ProjectFileIndex;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.JavaPsiFacade;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.psi.impl.JavaPsiFacadeImpl;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.ProjectScopeBuilder;
import com.intellij.psi.search.ProjectScopeBuilderImpl;
import java.io.File;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/** Unit tests for {@link BlazeRenderErrorContributor}. */
@RunWith(JUnit4.class)
public class BlazeRenderErrorContributorTest extends BlazeTestCase {
private static final String BLAZE_BIN = "blaze-out/crosstool/bin";
private static final String GENERATED_RESOURCES_ERROR = "Generated resources";
private static final String NON_STANDARD_MANIFEST_NAME_ERROR = "Non-standard manifest name";
private static final String MISSING_CLASS_DEPENDENCIES_ERROR = "Missing class dependencies";
private static final WorkspaceRoot workspaceRoot = new WorkspaceRoot(new File("/"));
private Module module;
private MockBlazeProjectDataManager projectDataManager;
private BlazeRenderErrorContributor.BlazeProvider provider;
@Override
protected void initTest(Container applicationServices, Container projectServices) {
super.initTest(applicationServices, projectServices);
applicationServices.register(FileTypeManager.class, new MockFileTypeManager());
projectServices.register(ProjectFileIndex.class, mock(ProjectFileIndex.class));
projectServices.register(BuildReferenceManager.class, new MockBuildReferenceManager(project));
projectServices.register(TransitiveDependencyMap.class, new TransitiveDependencyMap(project));
projectServices.register(ProjectScopeBuilder.class, new ProjectScopeBuilderImpl(project));
projectServices.register(
AndroidResourceModuleRegistry.class, new AndroidResourceModuleRegistry());
BlazeImportSettingsManager importSettingsManager = new BlazeImportSettingsManager();
BlazeImportSettings settings = new BlazeImportSettings("", "", "", "", BuildSystem.Blaze);
importSettingsManager.setImportSettings(settings);
projectServices.register(BlazeImportSettingsManager.class, importSettingsManager);
createPsiClassesAndSourceToTargetMap(projectServices);
projectDataManager = new MockBlazeProjectDataManager();
projectServices.register(BlazeProjectDataManager.class, projectDataManager);
ExtensionPoint<RenderErrorContributor.Provider> extensionPoint =
registerExtensionPoint(
ExtensionPointName.create("com.android.rendering.renderErrorContributor"),
RenderErrorContributor.Provider.class);
extensionPoint.registerExtension(new RenderErrorContributor.Provider());
extensionPoint.registerExtension(new BlazeRenderErrorContributor.BlazeProvider());
module = new MockModule(project, () -> {});
// For the isApplicable tests.
provider = new BlazeRenderErrorContributor.BlazeProvider();
}
@Test
public void testProviderIsApplicable() {
assertThat(provider.isApplicable(project)).isTrue();
}
@Test
public void testProviderNotApplicableIfNotBlaze() {
BlazeImportSettingsManager.getInstance(project).loadState(null);
assertThat(provider.isApplicable(project)).isFalse();
}
@Test
public void testNoIssuesIfNoErrors() {
PsiFile file = new MockPsiFile(new MockPsiManager(project));
file.putUserData(ModuleUtilCore.KEY_MODULE, module);
RenderResult result = RenderResult.createBlank(file);
RenderErrorModel errorModel = RenderErrorModelFactory.createErrorModel(result, null);
assertThat(errorModel.getIssues()).isEmpty();
}
@Test
public void testNoBlazeIssuesIfNoRelatedErrors() {
RenderErrorModel errorModel = createRenderErrorModelWithBrokenClasses();
errorModel
.getIssues()
.forEach(
issue ->
assertThat(issue.getSummary())
.isNoneOf(
GENERATED_RESOURCES_ERROR,
NON_STANDARD_MANIFEST_NAME_ERROR,
MISSING_CLASS_DEPENDENCIES_ERROR));
}
@Test
public void testReportGeneratedResources() {
createTargetMapWithGeneratedResources();
RenderErrorModel errorModel = createRenderErrorModelWithBrokenClasses();
RenderErrorModel.Issue generatedResourcesIssue =
Iterables.getOnlyElement(
errorModel
.getIssues()
.stream()
.filter(issue -> issue.getSummary().equals(GENERATED_RESOURCES_ERROR))
.collect(Collectors.toList()));
assertThat(generatedResourcesIssue.getHtmlContent())
.isEqualTo(
"Generated resources will not be discovered by the IDE:"
+ "<DL>"
+ "<DD>-&NBSP;"
+ "com/google/example/dependency/generated/res "
+ "from <A HREF=\"file:///src/com/google/example/dependency/BUILD\">"
+ "//com/google/example:generated</A>"
+ "<DD>-&NBSP;"
+ "com/google/example/main/generated/res "
+ "from <A HREF=\"file:///src/com/google/example/main/BUILD\">"
+ "//com/google/example:main</A>"
+ "<DD>-&NBSP;"
+ "com/google/example/transitive/generated/one/res "
+ "from <A HREF=\"file:///src/com/google/example/transitive/BUILD\">"
+ "//com/google/example/transitive:generated</A>"
+ "<DD>-&NBSP;"
+ "com/google/example/transitive/generated/two/res "
+ "from <A HREF=\"file:///src/com/google/example/transitive/BUILD\">"
+ "//com/google/example/transitive:generated</A>"
+ "</DL>"
+ "Please avoid using generated resources, then "
+ "<A HREF=\"action:sync\">sync the project</A> and "
+ "<A HREF=\"refreshRender\">refresh the layout</A>.");
}
@Test
public void testReportNonStandardAndroidManifestName() {
createTargetMapWithNonStandardAndroidManifestName();
RenderErrorModel errorModel = createRenderErrorModelWithBrokenClasses();
RenderErrorModel.Issue nonStandardManifestNameIssue =
Iterables.getOnlyElement(
errorModel
.getIssues()
.stream()
.filter(issue -> issue.getSummary().equals(NON_STANDARD_MANIFEST_NAME_ERROR))
.collect(Collectors.toList()));
assertThat(nonStandardManifestNameIssue.getHtmlContent())
.isEqualTo(
"<A HREF=\"file:///src/com/google/example/main/BUILD\">"
+ "//com/google/example:main</A> "
+ "uses a non-standard name for the Android manifest: "
+ "<A HREF=\"file:///src/com/google/example/main/WeirdManifest.xml\">"
+ "WeirdManifest.xml</A>"
+ "<BR/>"
+ "Please rename it to AndroidManifest.xml, then "
+ "<A HREF=\"action:sync\">sync the project</A> and "
+ "<A HREF=\"refreshRender\">refresh the layout</A>.");
}
@Test
public void testNoReportNonStandardAndroidManifestNameInDependency() {
createTargetMapWithNonStandardAndroidManifestNameInDependency();
RenderErrorModel errorModel = createRenderErrorModelWithBrokenClasses();
errorModel
.getIssues()
.forEach(
issue -> assertThat(issue.getSummary()).isNotEqualTo(NON_STANDARD_MANIFEST_NAME_ERROR));
}
@Test
public void testReportMissingClassDependencies() {
createTargetMapWithMissingClassDependency();
RenderErrorModel errorModel =
createRenderErrorModelWithMissingClasses(
"com.google.example.independent.LibraryView",
"com.google.example.independent.LibraryView2",
"com.google.example.independent.Library2View",
"com.google.example.dependent.LibraryView",
"com.google.example.ResourceView");
RenderErrorModel.Issue missingClassDependenciesIssue =
Iterables.getOnlyElement(
errorModel
.getIssues()
.stream()
.filter(issue -> issue.getSummary().equals(MISSING_CLASS_DEPENDENCIES_ERROR))
.collect(Collectors.toList()));
assertThat(missingClassDependenciesIssue.getHtmlContent())
.isEqualTo(
"<A HREF=\"file:///src/com/google/example/BUILD\">"
+ "//com/google/example:resources</A> "
+ "contains resource files that reference these classes:"
+ "<DL>"
+ "<DD>-&NBSP;"
+ "<A HREF=\"openClass:com.google.example.independent.Library2View\">"
+ "com.google.example.independent.Library2View</A> "
+ "from <A HREF=\"file:///src/com/google/example/BUILD\">"
+ "//com/google/example/independent:library2</A> "
+ "<DD>-&NBSP;"
+ "<A HREF=\"openClass:com.google.example.independent.LibraryView\">"
+ "com.google.example.independent.LibraryView</A> "
+ "from <A HREF=\"file:///src/com/google/example/BUILD\">"
+ "//com/google/example/independent:library</A> "
+ "<DD>-&NBSP;"
+ "<A HREF=\"openClass:com.google.example.independent.LibraryView2\">"
+ "com.google.example.independent.LibraryView2</A> "
+ "from <A HREF=\"file:///src/com/google/example/BUILD\">"
+ "//com/google/example/independent:library</A> "
+ "</DL>"
+ "Please fix your dependencies so that "
+ "<A HREF=\"file:///src/com/google/example/BUILD\">"
+ "//com/google/example:resources</A> "
+ "correctly depends on these classes, then "
+ "<A HREF=\"action:sync\">sync the project</A> and "
+ "<A HREF=\"refreshRender\">refresh the layout</A>."
+ "<BR/>"
+ "<BR/>"
+ "<B>NOTE: blaze can still build with the incorrect dependencies "
+ "due to the way it handles resources, "
+ "but the layout editor needs them to be correct.</B>");
}
@Test
public void testNoReportMissingClassDependenciesIfClassInSameTarget() {
createTargetMapWithMissingClassDependency();
RenderErrorModel errorModel =
createRenderErrorModelWithMissingClasses("com.google.example.ResourceView");
errorModel
.getIssues()
.forEach(
issue -> assertThat(issue.getSummary()).isNotEqualTo(MISSING_CLASS_DEPENDENCIES_ERROR));
}
@Test
public void testNoReportMissingClassDependenciesIfClassInDependency() {
createTargetMapWithMissingClassDependency();
RenderErrorModel errorModel =
createRenderErrorModelWithMissingClasses("com.google.example.dependent.LibraryView");
errorModel
.getIssues()
.forEach(
issue -> assertThat(issue.getSummary()).isNotEqualTo(MISSING_CLASS_DEPENDENCIES_ERROR));
}
private RenderErrorModel createRenderErrorModelWithBrokenClasses() {
PsiFile file = new MockPsiFile(new MockPsiManager(project));
file.putUserData(ModuleUtilCore.KEY_MODULE, module);
RenderResult result = RenderResult.createBlank(file);
result
.getLogger()
.addBrokenClass("com.google.example.CustomView", new Exception("resource not found"));
return RenderErrorModelFactory.createErrorModel(result, null);
}
private RenderErrorModel createRenderErrorModelWithMissingClasses(String... classNames) {
PsiFile file = new MockPsiFile(new MockPsiManager(project));
file.putUserData(ModuleUtilCore.KEY_MODULE, module);
RenderResult result = RenderResult.createBlank(file);
for (String className : classNames) {
result.getLogger().addMissingClass(className);
}
return RenderErrorModelFactory.createErrorModel(result, null);
}
private static ArtifactLocation artifact(String relativePath, boolean isSource) {
return ArtifactLocation.builder()
.setIsSource(isSource)
.setRootExecutionPathFragment(isSource ? "" : BLAZE_BIN)
.setRelativePath(relativePath)
.build();
}
private void createTargetMapWithGeneratedResources() {
Label mainResourcesTarget = Label.create("//com/google/example:main");
Label dependencyGeneratedResourceTarget = Label.create("//com/google/example:generated");
Label dependencySourceResourceTarget = Label.create("//com/google/example:source");
Label transitiveGeneratedResourcesTarget =
Label.create("//com/google/example/transitive:generated");
Label transitiveSourceResourceTarget = Label.create("//com/google/example/transitive:source");
Label unrelatedGeneratedResourceTarget = Label.create("//com/google/unrelated:generated");
Label unrelatedSourceResourceTarget = Label.create("//com/google/unrelated:source");
ArtifactLocation mainGeneratedResource =
artifact("com/google/example/main/generated/res", false);
ArtifactLocation mainSourceResource = artifact("com/google/example/main/source/res", true);
ArtifactLocation dependencyGeneratedResource =
artifact("com/google/example/dependency/generated/res", false);
ArtifactLocation dependencySourceResource =
artifact("com/google/example/dependency/source/res", true);
ArtifactLocation transitiveGeneratedResourceOne =
artifact("com/google/example/transitive/generated/one/res", false);
ArtifactLocation transitiveGeneratedResourceTwo =
artifact("com/google/example/transitive/generated/two/res", false);
ArtifactLocation transitiveSourceResource =
artifact("com/google/example/transitive/source/res", true);
ArtifactLocation unrelatedGeneratedResource =
artifact("com/google/unrelated/generated/res", false);
ArtifactLocation unrelatedSourceResource = artifact("com/google/unrelated/source/res", true);
ArtifactLocation mainBuildFile = artifact("com/google/example/main/BUILD", true);
ArtifactLocation dependencyBuildFile = artifact("com/google/example/dependency/BUILD", true);
ArtifactLocation transitiveBuildFile = artifact("com/google/example/transitive/BUILD", true);
ArtifactLocation unrelatedBuildFile = artifact("com/google/unrelated/BUILD", true);
AndroidResourceModuleRegistry registry = AndroidResourceModuleRegistry.getInstance(project);
registry.put(
module,
AndroidResourceModule.builder(TargetKey.forPlainTarget(mainResourcesTarget))
// .addResource(mainGeneratedResource) // Dropped.
.addResource(mainSourceResource)
.addTransitiveResourceDependency(dependencyGeneratedResourceTarget)
.addTransitiveResource(dependencyGeneratedResource)
.addTransitiveResourceDependency(dependencySourceResourceTarget)
.addTransitiveResource(dependencySourceResource)
.addTransitiveResourceDependency(transitiveGeneratedResourcesTarget)
.addTransitiveResource(transitiveGeneratedResourceOne)
.addTransitiveResource(transitiveGeneratedResourceTwo)
.addTransitiveResourceDependency(transitiveSourceResourceTarget)
.addTransitiveResource(transitiveSourceResource)
.build());
// Not using these, but they should be in the registry.
registry.put(
mock(Module.class),
AndroidResourceModule.builder(TargetKey.forPlainTarget(dependencyGeneratedResourceTarget))
// .addResource(dependencyGeneratedResource) // Dropped.
.addTransitiveResourceDependency(transitiveSourceResourceTarget)
.addTransitiveResource(transitiveSourceResource)
.build());
registry.put(
mock(Module.class),
AndroidResourceModule.builder(TargetKey.forPlainTarget(dependencySourceResourceTarget))
.addResource(dependencySourceResource)
.addTransitiveResourceDependency(transitiveGeneratedResourcesTarget)
.addTransitiveResource(transitiveGeneratedResourceOne)
.addTransitiveResource(transitiveGeneratedResourceTwo)
.build());
registry.put(
mock(Module.class),
AndroidResourceModule.builder(TargetKey.forPlainTarget(transitiveGeneratedResourcesTarget))
// .addResource(transitiveGeneratedResourceOne) // Dropped.
// .addResource(transitiveGeneratedResourceTwo) // Dropped.
.build());
registry.put(
mock(Module.class),
AndroidResourceModule.builder(TargetKey.forPlainTarget(transitiveSourceResourceTarget))
.addResource(transitiveSourceResource)
.build());
registry.put(
mock(Module.class),
AndroidResourceModule.builder(TargetKey.forPlainTarget(unrelatedGeneratedResourceTarget))
// .addResource(unrelatedGeneratedResource) // Dropped.
.build());
registry.put(
mock(Module.class),
AndroidResourceModule.builder(TargetKey.forPlainTarget(unrelatedSourceResourceTarget))
.addResource(unrelatedSourceResource)
.build());
TargetMap targetMap =
TargetMapBuilder.builder()
.addTarget(
TargetIdeInfo.builder()
.setLabel(mainResourcesTarget)
.setBuildFile(mainBuildFile)
.setAndroidInfo(
AndroidIdeInfo.builder()
.setGenerateResourceClass(true)
.addResource(mainGeneratedResource)
.addResource(mainSourceResource))
.addDependency(dependencyGeneratedResourceTarget)
.addDependency(dependencySourceResourceTarget))
.addTarget(
TargetIdeInfo.builder()
.setLabel(dependencyGeneratedResourceTarget)
.setBuildFile(dependencyBuildFile)
.setAndroidInfo(
AndroidIdeInfo.builder()
.setGenerateResourceClass(true)
.addResource(dependencyGeneratedResource))
.addDependency(transitiveSourceResourceTarget))
.addTarget(
TargetIdeInfo.builder()
.setLabel(dependencySourceResourceTarget)
.setBuildFile(dependencyBuildFile)
.setAndroidInfo(
AndroidIdeInfo.builder()
.setGenerateResourceClass(true)
.addResource(dependencySourceResource))
.addDependency(transitiveGeneratedResourcesTarget))
.addTarget(
TargetIdeInfo.builder()
.setLabel(transitiveGeneratedResourcesTarget)
.setBuildFile(transitiveBuildFile)
.setAndroidInfo(
AndroidIdeInfo.builder()
.setGenerateResourceClass(true)
.addResource(transitiveGeneratedResourceOne)
.addResource(transitiveGeneratedResourceTwo)))
.addTarget(
TargetIdeInfo.builder()
.setLabel(transitiveSourceResourceTarget)
.setBuildFile(transitiveBuildFile)
.setAndroidInfo(
AndroidIdeInfo.builder()
.setGenerateResourceClass(true)
.addResource(transitiveSourceResource)))
.addTarget(
TargetIdeInfo.builder()
.setLabel(unrelatedGeneratedResourceTarget)
.setBuildFile(unrelatedBuildFile)
.setAndroidInfo(
AndroidIdeInfo.builder()
.setGenerateResourceClass(true)
.addResource(unrelatedGeneratedResource)))
.addTarget(
TargetIdeInfo.builder()
.setLabel(unrelatedSourceResourceTarget)
.setBuildFile(unrelatedBuildFile)
.setAndroidInfo(
AndroidIdeInfo.builder()
.setGenerateResourceClass(true)
.addResource(unrelatedSourceResource)))
.build();
projectDataManager.setTargetMap(targetMap);
}
private void createTargetMapWithNonStandardAndroidManifestName() {
Label mainResourceTarget = Label.create("//com/google/example:main");
ArtifactLocation mainManifest = artifact("com/google/example/main/WeirdManifest.xml", true);
ArtifactLocation mainResource = artifact("com/google/example/main/res", true);
ArtifactLocation mainBuildFile = artifact("com/google/example/main/BUILD", true);
AndroidResourceModuleRegistry registry = AndroidResourceModuleRegistry.getInstance(project);
registry.put(
module,
AndroidResourceModule.builder(TargetKey.forPlainTarget(mainResourceTarget))
.addResource(mainResource)
.build());
TargetMap targetMap =
TargetMapBuilder.builder()
.addTarget(
TargetIdeInfo.builder()
.setLabel(mainResourceTarget)
.setBuildFile(mainBuildFile)
.setAndroidInfo(
AndroidIdeInfo.builder()
.setGenerateResourceClass(true)
.setManifestFile(mainManifest)
.addResource(mainResource)))
.build();
projectDataManager.setTargetMap(targetMap);
}
private void createTargetMapWithNonStandardAndroidManifestNameInDependency() {
Label mainResourceTarget = Label.create("//com/google/example:main");
Label dependencyResourceTarget = Label.create("//com/google/example:dependency");
ArtifactLocation mainManifest = artifact("com/google/example/main/AndroidManifest.xml", true);
ArtifactLocation mainResource = artifact("com/google/example/main/res", true);
ArtifactLocation mainBuildFile = artifact("com/google/example/main/BUILD", true);
ArtifactLocation dependencyManifest =
artifact("com/google/example/dependency/MyManifest.xml", true);
ArtifactLocation dependencyResource = artifact("com/google/example/dependency/res", true);
ArtifactLocation dependencyBuildFile = artifact("com/google/example/dependency/BUILD", true);
AndroidResourceModuleRegistry registry = AndroidResourceModuleRegistry.getInstance(project);
registry.put(
module,
AndroidResourceModule.builder(TargetKey.forPlainTarget(mainResourceTarget))
.addResource(mainResource)
.addTransitiveResourceDependency(dependencyResourceTarget)
.addTransitiveResource(dependencyResource)
.build());
registry.put(
mock(Module.class),
AndroidResourceModule.builder(TargetKey.forPlainTarget(dependencyResourceTarget))
.addResource(dependencyResource)
.build());
TargetMap targetMap =
TargetMapBuilder.builder()
.addTarget(
TargetIdeInfo.builder()
.setLabel(mainResourceTarget)
.setBuildFile(mainBuildFile)
.setAndroidInfo(
AndroidIdeInfo.builder()
.setGenerateResourceClass(true)
.setManifestFile(mainManifest)
.addResource(mainResource)))
.addTarget(
TargetIdeInfo.builder()
.setLabel(dependencyResourceTarget)
.setBuildFile(dependencyBuildFile)
.setAndroidInfo(
AndroidIdeInfo.builder()
.setGenerateResourceClass(true)
.setManifestFile(dependencyManifest)
.addResource(dependencyResource)))
.build();
projectDataManager.setTargetMap(targetMap);
}
private void createTargetMapWithMissingClassDependency() {
Label parentTarget = Label.create("//com/google/example:app");
Label independentLibraryTarget = Label.create("//com/google/example/independent:library");
Label independentLibrary2Target = Label.create("//com/google/example/independent:library2");
Label dependentLibraryTarget = Label.create("//com/google/example/dependent:library");
Label resourcesTarget = Label.create("//com/google/example:resources");
ArtifactLocation manifest = artifact("com/google/example/AndroidManifest.xml", true);
ArtifactLocation resources = artifact("com/google/example/res", true);
ArtifactLocation buildFile = artifact("com/google/example/BUILD", true);
AndroidResourceModuleRegistry registry = AndroidResourceModuleRegistry.getInstance(project);
registry.put(
module,
AndroidResourceModule.builder(TargetKey.forPlainTarget(resourcesTarget))
.addResource(resources)
.build());
TargetMap targetMap =
TargetMapBuilder.builder()
.addTarget(
TargetIdeInfo.builder()
.setLabel(parentTarget)
.setBuildFile(buildFile)
.addDependency(independentLibraryTarget)
.addDependency(resourcesTarget))
.addTarget(
TargetIdeInfo.builder()
.setLabel(independentLibraryTarget)
.setBuildFile(buildFile)
.setJavaInfo(JavaIdeInfo.builder())
.addDependency(independentLibrary2Target))
.addTarget(
TargetIdeInfo.builder()
.setLabel(independentLibrary2Target)
.setBuildFile(buildFile)
.setJavaInfo(JavaIdeInfo.builder()))
.addTarget(
TargetIdeInfo.builder()
.setLabel(resourcesTarget)
.setBuildFile(buildFile)
.setAndroidInfo(
AndroidIdeInfo.builder()
.setGenerateResourceClass(true)
.setManifestFile(manifest)
.addResource(resources))
.addDependency(dependentLibraryTarget))
.addTarget(
TargetIdeInfo.builder()
.setLabel(dependentLibraryTarget)
.setBuildFile(buildFile)
.setJavaInfo(JavaIdeInfo.builder()))
.build();
projectDataManager.setTargetMap(targetMap);
}
private void createPsiClassesAndSourceToTargetMap(Container projectServices) {
PsiManager psiManager = new MockPsiManager(project);
VirtualFile independentLibraryView =
new MockVirtualFile("src/com/google/example/independent/LibraryView.java");
VirtualFile independentLibraryView2 =
new MockVirtualFile("src/com/google/example/independent/LibraryView2.java");
VirtualFile independentLibrary2View =
new MockVirtualFile("src/com/google/example/independent/Library2View.java");
VirtualFile dependentLibraryView =
new MockVirtualFile("src/com/google/example/dependent/LibraryView.java");
VirtualFile resourceView = new MockVirtualFile("src/com/google/example/ResourceView.java");
ImmutableMap<String, PsiClass> classes =
ImmutableMap.of(
"com.google.example.independent.LibraryView",
mockPsiClass(independentLibraryView),
"com.google.example.independent.LibraryView2",
mockPsiClass(independentLibraryView2),
"com.google.example.independent.Library2View",
mockPsiClass(independentLibrary2View),
"com.google.example.dependent.LibraryView",
mockPsiClass(dependentLibraryView),
"com.google.example.ResourceView",
mockPsiClass(resourceView));
ImmutableMap<File, TargetKey> sourceToTarget =
ImmutableMap.of(
VfsUtilCore.virtualToIoFile(independentLibraryView),
TargetKey.forPlainTarget(Label.create("//com/google/example/independent:library")),
VfsUtilCore.virtualToIoFile(independentLibraryView2),
TargetKey.forPlainTarget(Label.create("//com/google/example/independent:library")),
VfsUtilCore.virtualToIoFile(independentLibrary2View),
TargetKey.forPlainTarget(Label.create("//com/google/example/independent:library2")),
VfsUtilCore.virtualToIoFile(dependentLibraryView),
TargetKey.forPlainTarget(Label.create("//com/google/example/dependent:library")),
VfsUtilCore.virtualToIoFile(resourceView),
TargetKey.forPlainTarget(Label.create("//com/google/example:resources")));
projectServices.register(
JavaPsiFacade.class, new MockJavaPsiFacade(project, psiManager, classes));
projectServices.register(SourceToTargetMap.class, new MockSourceToTargetMap(sourceToTarget));
}
private static PsiClass mockPsiClass(VirtualFile virtualFile) {
PsiFile psiFile = mock(PsiFile.class);
when(psiFile.getVirtualFile()).thenReturn(virtualFile);
PsiClass psiClass = mock(PsiClass.class);
when(psiClass.getContainingFile()).thenReturn(psiFile);
return psiClass;
}
private static class MockBlazeProjectDataManager implements BlazeProjectDataManager {
private BlazeProjectData blazeProjectData;
public void setTargetMap(TargetMap targetMap) {
ArtifactLocationDecoder decoder =
(location) -> new File("/src", location.getExecutionRootRelativePath());
this.blazeProjectData =
MockBlazeProjectDataBuilder.builder(workspaceRoot)
.setTargetMap(targetMap)
.setArtifactLocationDecoder(decoder)
.build();
}
@Nullable
@Override
public BlazeProjectData getBlazeProjectData() {
return blazeProjectData;
}
}
private static class MockBuildReferenceManager extends BuildReferenceManager {
public MockBuildReferenceManager(Project project) {
super(project);
}
@Nullable
@Override
public PsiElement resolveLabel(Label label) {
return null;
}
}
private static class MockJavaPsiFacade extends JavaPsiFacadeImpl {
private ImmutableMap<String, PsiClass> classes;
public MockJavaPsiFacade(
Project project, PsiManager psiManager, ImmutableMap<String, PsiClass> classes) {
super(project, psiManager, null, null);
this.classes = classes;
}
@Override
public PsiClass findClass(String qualifiedName, GlobalSearchScope scope) {
return classes.get(qualifiedName);
}
}
private static class MockSourceToTargetMap implements SourceToTargetMap {
private ImmutableMap<File, TargetKey> sourceToTarget;
public MockSourceToTargetMap(ImmutableMap<File, TargetKey> sourceToTarget) {
this.sourceToTarget = sourceToTarget;
}
@Override
public ImmutableCollection<Label> getTargetsToBuildForSourceFile(File file) {
return ImmutableList.of();
}
@Override
public ImmutableCollection<TargetKey> getRulesForSourceFile(File file) {
return ImmutableList.of(sourceToTarget.get(file));
}
}
}