blob: a712648df4f4496598f495ba5af8a30bfcb45fbd [file] [log] [blame]
/*
* Copyright 2017 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.sync;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import com.google.common.collect.ImmutableList;
import com.google.idea.blaze.android.AndroidIntegrationTestSetupRule;
import com.google.idea.blaze.android.sdk.BlazeSdkProvider;
import com.google.idea.blaze.android.sdk.MockBlazeSdkProvider;
import com.google.idea.blaze.base.ideinfo.AndroidIdeInfo;
import com.google.idea.blaze.base.ideinfo.CIdeInfo;
import com.google.idea.blaze.base.ideinfo.CToolchainIdeInfo;
import com.google.idea.blaze.base.ideinfo.TargetIdeInfo;
import com.google.idea.blaze.base.ideinfo.TargetMap;
import com.google.idea.blaze.base.ideinfo.TargetMapBuilder;
import com.google.idea.blaze.base.model.BlazeProjectData;
import com.google.idea.blaze.base.model.primitives.ExecutionRootPath;
import com.google.idea.blaze.base.model.primitives.Kind;
import com.google.idea.blaze.base.model.primitives.LanguageClass;
import com.google.idea.blaze.base.model.primitives.WorkspacePath;
import com.google.idea.blaze.base.model.primitives.WorkspaceType;
import com.google.idea.blaze.base.sync.BlazeSyncIntegrationTestCase;
import com.google.idea.blaze.base.sync.BlazeSyncParams;
import com.google.idea.blaze.base.sync.BlazeSyncParams.SyncMode;
import com.google.idea.blaze.base.sync.data.BlazeDataStorage;
import com.google.idea.blaze.base.sync.data.BlazeProjectDataManager;
import com.google.idea.blaze.base.sync.projectstructure.ModuleFinder;
import com.google.idea.blaze.cpp.BlazeCWorkspace;
import com.google.idea.blaze.java.sync.BlazeJavaSyncAugmenter;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.projectRoots.SdkTypeId;
import com.intellij.openapi.roots.ContentEntry;
import com.intellij.openapi.vfs.VirtualFile;
import com.jetbrains.cidr.lang.OCLanguageKind;
import com.jetbrains.cidr.lang.workspace.OCResolveConfiguration;
import com.jetbrains.cidr.lang.workspace.OCWorkspace;
import com.jetbrains.cidr.lang.workspace.OCWorkspaceManager;
import com.jetbrains.cidr.lang.workspace.compiler.OCCompilerSettings;
import java.util.Arrays;
import java.util.List;
import org.jetbrains.android.facet.AndroidFacet;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/** Android-specific sync integration tests. */
@RunWith(JUnit4.class)
public class AndroidSyncTest extends BlazeSyncIntegrationTestCase {
@Rule
public final AndroidIntegrationTestSetupRule androidSetupRule =
new AndroidIntegrationTestSetupRule();
@Before
public void setup() {
mockSdk("android-25", "Android 25 SDK");
registerProjectService(OCWorkspaceManager.class, new MockOCWorkspaceManager());
}
private void mockSdk(String targetHash, String sdkName) {
SdkTypeId sdkType = mock(SdkTypeId.class);
when(sdkType.getName()).thenReturn("Android SDK");
Sdk sdk = mock(Sdk.class);
when(sdk.getName()).thenReturn(sdkName);
when(sdk.getSdkType()).thenReturn(sdkType);
MockBlazeSdkProvider sdkProvider = (MockBlazeSdkProvider) BlazeSdkProvider.getInstance();
sdkProvider.addSdk(targetHash, sdk);
}
@Test
public void testAndroidSyncAugmenterPresent() {
assertThat(
Arrays.stream(BlazeJavaSyncAugmenter.EP_NAME.getExtensions())
.anyMatch(e -> e instanceof BlazeAndroidJavaSyncAugmenter))
.isTrue();
}
@Test
public void testSimpleSync() throws Exception {
setProjectView(
"directories:",
" java/com/google",
"targets:",
" //java/com/google:lib",
"android_sdk_platform: android-25");
workspace.createFile(
new WorkspacePath("java/com/google/Source.java"),
"package com.google;",
"public class Source {}");
workspace.createFile(
new WorkspacePath("java/com/google/Other.java"),
"package com.google;",
"public class Other {}");
VirtualFile javaRoot = workspace.createDirectory(new WorkspacePath("java/com/google"));
TargetMap targetMap =
TargetMapBuilder.builder()
.addTarget(
TargetIdeInfo.builder()
.setBuildFile(sourceRoot("java/com/google/BUILD"))
.setLabel("//java/com/google:lib")
.setKind("android_library")
.setAndroidInfo(
AndroidIdeInfo.builder()
.setManifestFile(sourceRoot("java/com/google/AndroidManifest.xml"))
.addResource(sourceRoot("java/com/google/res/values/strings.xml"))
.setResourceJavaPackage("com.google")
.setGenerateResourceClass(true))
.addSource(sourceRoot("java/com/google/Source.java"))
.addSource(sourceRoot("java/com/google/Other.java")))
.build();
setTargetMap(targetMap);
runBlazeSync(
new BlazeSyncParams.Builder("Sync", SyncMode.INCREMENTAL)
.addProjectViewTargets(true)
.build());
errorCollector.assertNoIssues();
BlazeProjectData blazeProjectData =
BlazeProjectDataManager.getInstance(getProject()).getBlazeProjectData();
assertThat(blazeProjectData).isNotNull();
assertThat(blazeProjectData.targetMap).isEqualTo(targetMap);
assertThat(blazeProjectData.workspaceLanguageSettings.getWorkspaceType())
.isEqualTo(WorkspaceType.ANDROID);
ImmutableList<ContentEntry> contentEntries = getWorkspaceContentEntries();
assertThat(contentEntries).hasSize(1);
assertThat(findContentEntry(javaRoot)).isNotNull();
assertThat(findContentEntry(javaRoot).getSourceFolders()).hasLength(1);
// Check that the workspace is set to android
Module workspaceModule =
ModuleFinder.getInstance(getProject())
.findModuleByName(BlazeDataStorage.WORKSPACE_MODULE_NAME);
assertThat(workspaceModule).isNotNull();
assertThat(AndroidFacet.getInstance(workspaceModule)).isNotNull();
// Check that a resource module was created
Module resourceModule =
ModuleFinder.getInstance(getProject()).findModuleByName("java.com.google.lib");
assertThat(resourceModule).isNotNull();
assertThat(AndroidFacet.getInstance(resourceModule)).isNotNull();
}
@Test
public void testMultipleToolchainsNoIssue() {
// Test what happens if there are multiple toolchains in the target map
// (e.g., from --fat_apk_cpu)
setProjectView(
"directories:",
" java/com/google",
"targets:",
" //java/com/google:app",
"additional_languages:",
" c",
"android_sdk_platform: android-25");
workspace.createDirectory(new WorkspacePath("java/com/google"));
workspace.createFile(
new WorkspacePath("java/com/google/Source.java"),
"package com.google;",
"public class Source {}");
workspace.createFile(
new WorkspacePath("java/com/google/Other.java"),
"package com.google;",
"public class Other {}");
workspace.createFile(new WorkspacePath("java/com/google/jni/native.cc"), "void foo() {}");
workspace.createFile(new WorkspacePath("java/com/google/jni/native2.cc"), "void bar() {}");
TargetMap targetMap =
TargetMapBuilder.builder()
.addTarget(
TargetIdeInfo.builder()
.setBuildFile(sourceRoot("android_ndk_linux/toolchains/BUILD"))
.setLabel("//android_ndk_linux/toolchains:armv7a")
.setKind(Kind.CC_TOOLCHAIN)
.setCToolchainInfo(
CToolchainIdeInfo.builder()
.setTargetName("arm-linux-androideabi")
.setCppExecutable(
new ExecutionRootPath("bin/arm-linux-androideabi-gcc"))
.setPreprocessorExecutable(
new ExecutionRootPath("bin/arm-linux-androideabi-cpp"))
.addBaseCompilerOptions(
ImmutableList.of(
"-DOS_ANDROID",
"-mbionic",
"-ffunction-sections",
"-march=armv7-a",
"-mfpu=vfpv3-d16"))
.addCppCompilerOptions(ImmutableList.of("-std=gnu++11"))
.addBuiltInIncludeDirectories(
ImmutableList.of(
new ExecutionRootPath(
"lib/gcc/arm-linux-androideabi/4.8/include")))
.addLinkOptions(
ImmutableList.of(
"--sysroot=android_ndk_linux/platforms/android-18/arch-arm"))
.addUnfilteredCompilerOptions(
ImmutableList.of(
"--sysroot=android_ndk_linux/platforms/android-18/arch-arm"))
.addUnfilteredToolchainSystemIncludes(
ImmutableList.of(
new ExecutionRootPath(
"android_ndk_linux/sources/llvm-libc++/libcxx/include")))))
.addTarget(
TargetIdeInfo.builder()
.setBuildFile(sourceRoot("android_ndk_linux/toolchains/BUILD"))
.setLabel("//android_ndk_linux/toolchains:aarch64")
.setKind(Kind.CC_TOOLCHAIN)
.setCToolchainInfo(
CToolchainIdeInfo.builder()
.setTargetName("aarch64-linux-android")
.setCppExecutable(
new ExecutionRootPath("prebuilt/bin/aarch64-linux-android-gcc"))
.setPreprocessorExecutable(
new ExecutionRootPath("prebuilt/bin/aarch64-linux-android-cpp"))
.addBaseCompilerOptions(
ImmutableList.of("-DOS_ANDROID", "-mbionic", "-ffunction-sections"))
.addCppCompilerOptions(ImmutableList.of("-std=gnu++11"))
.addBuiltInIncludeDirectories(
ImmutableList.of(
new ExecutionRootPath(
"lib/gcc/aarch64-linux-android/4.9/include")))
.addLinkOptions(
ImmutableList.of(
"--sysroot=android_ndk_linux/platforms/android-21/arch-arm64"))
.addUnfilteredCompilerOptions(
ImmutableList.of(
"--sysroot=android_ndk_linux/platforms/android-21/arch-arm64"))
.addUnfilteredToolchainSystemIncludes(
ImmutableList.of(
new ExecutionRootPath(
"android_ndk_linux/sources/llvm-libc++/libcxx/include")))))
.addTarget(
TargetIdeInfo.builder()
.setBuildFile(sourceRoot("java/com/google/BUILD"))
.setLabel("//java/com/google:lib")
.setKind("android_library")
.setAndroidInfo(
AndroidIdeInfo.builder()
.setManifestFile(sourceRoot("java/com/google/AndroidManifest.xml"))
.addResource(sourceRoot("java/com/google/res/values/strings.xml"))
.setResourceJavaPackage("com.google")
.setGenerateResourceClass(true))
.addSource(sourceRoot("java/com/google/Other.java")))
// Technically, blaze returns multiple instances of native libs (one for each CPU from
// fat APK). However, we just pick the first instance we run into for the target map.
.addTarget(
TargetIdeInfo.builder()
.setBuildFile(sourceRoot("java/com/google/BUILD"))
.setLabel("//java/com/google:native_lib")
.setKind("cc_library")
.setCInfo(
CIdeInfo.builder()
.addTransitiveQuoteIncludeDirectories(
ImmutableList.of(
new ExecutionRootPath("."),
new ExecutionRootPath("blaze-out/android-aarch64-etc/genfiles"),
new ExecutionRootPath(
"blaze-out/android-aarch64-etc/genfiles/third_party/java")))
.addTransitiveSystemIncludeDirectories(
ImmutableList.of(
new ExecutionRootPath("third_party/stl/gcc3"),
new ExecutionRootPath("third_party/java/jdk/include"))))
.addSource(sourceRoot("java/com/google/jni/native.cc"))
.addDependency("//android_ndk_linux/toolchains:aarch64"))
.addTarget(
TargetIdeInfo.builder()
.setBuildFile(sourceRoot("java/com/google/BUILD"))
.setLabel("//java/com/google:native_lib2")
.setKind("cc_library")
.setCInfo(
CIdeInfo.builder()
.addTransitiveQuoteIncludeDirectories(
ImmutableList.of(
new ExecutionRootPath("."),
new ExecutionRootPath("blaze-out/android-aarch64-etc/genfiles"),
new ExecutionRootPath(
"blaze-out/android-aarch64-etc/genfiles/third_party/java")))
.addTransitiveSystemIncludeDirectories(
ImmutableList.of(
new ExecutionRootPath("third_party/stl/gcc3"),
new ExecutionRootPath("third_party/java/jdk/include"))))
.addSource(sourceRoot("java/com/google/jni/native2.cc"))
.addDependency("//java/com/google:native_lib")
.addDependency("//android_ndk_linux/toolchains:armv7a"))
// Other targets like android_binary and android_test might also depend on
// a cc_toolchain.
.addTarget(
TargetIdeInfo.builder()
.setBuildFile(sourceRoot("java/com/google/BUILD"))
.setLabel("//java/com/google:app")
.setKind("android_binary")
.setAndroidInfo(
AndroidIdeInfo.builder()
.setManifestFile(sourceRoot("java/com/google/AndroidManifest.xml"))
.setResourceJavaPackage("com.google")
.setGenerateResourceClass(true))
.addSource(sourceRoot("java/com/google/Source.java"))
.addDependency("//tools/jdk:toolchain")
.addDependency("//android_ndk_linux/toolchains:armv7a")
.addDependency("//java/com/google:lib")
.addDependency("//java/com/google:native_lib")
.addDependency("//java/com/google:native_lib2"))
.build();
setTargetMap(targetMap);
runBlazeSync(
new BlazeSyncParams.Builder("Sync", SyncMode.INCREMENTAL)
.addProjectViewTargets(true)
.build());
errorCollector.assertNoIssues();
BlazeProjectData blazeProjectData =
BlazeProjectDataManager.getInstance(getProject()).getBlazeProjectData();
assertThat(blazeProjectData).isNotNull();
assertThat(blazeProjectData.targetMap).isEqualTo(targetMap);
assertThat(blazeProjectData.workspaceLanguageSettings.getWorkspaceType())
.isEqualTo(WorkspaceType.ANDROID);
assertThat(blazeProjectData.workspaceLanguageSettings.isLanguageActive(LanguageClass.C))
.isTrue();
// Check that the workspace is set to android
Module workspaceModule =
ModuleFinder.getInstance(getProject())
.findModuleByName(BlazeDataStorage.WORKSPACE_MODULE_NAME);
assertThat(workspaceModule).isNotNull();
assertThat(AndroidFacet.getInstance(workspaceModule)).isNotNull();
// Check resolve configurations for the native code match the toolchain that was in
// the library's deps (not switched for some reason).
VirtualFile nativeCc =
fileSystem.findFile(
workspaceRoot
.fileForPath(new WorkspacePath("java/com/google/jni/native.cc"))
.getPath());
VirtualFile nativeCc2 =
fileSystem.findFile(
workspaceRoot
.fileForPath(new WorkspacePath("java/com/google/jni/native2.cc"))
.getPath());
List<? extends OCResolveConfiguration> resolveConfigurations =
OCWorkspaceManager.getWorkspace(getProject()).getConfigurationsForFile(nativeCc);
assertThat(resolveConfigurations).hasSize(1);
OCCompilerSettings compilerSettings = resolveConfigurations.get(0).getCompilerSettings();
List<String> compilerSwitches =
compilerSettings.getCompilerSwitches(OCLanguageKind.CPP, nativeCc).getCommandLineArgs();
assertThat(compilerSwitches)
.contains("--sysroot=android_ndk_linux/platforms/android-21/arch-arm64");
resolveConfigurations =
OCWorkspaceManager.getWorkspace(getProject()).getConfigurationsForFile(nativeCc2);
assertThat(resolveConfigurations).hasSize(1);
compilerSettings = resolveConfigurations.get(0).getCompilerSettings();
compilerSwitches =
compilerSettings.getCompilerSwitches(OCLanguageKind.CPP, nativeCc).getCommandLineArgs();
assertThat(compilerSwitches)
.contains("--sysroot=android_ndk_linux/platforms/android-18/arch-arm");
}
private class MockOCWorkspaceManager extends OCWorkspaceManager {
@Override
public OCWorkspace getWorkspace() {
return BlazeCWorkspace.getInstance(getProject());
}
}
}