/* * Copyright 2013-present Facebook, Inc. * * 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.facebook.buck.android; import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.in; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.oneOf; import static org.junit.Assert.assertThat; import com.facebook.buck.jvm.java.JavaLibraryBuilder; import com.facebook.buck.jvm.java.KeystoreBuilder; import com.facebook.buck.model.BuildTarget; import com.facebook.buck.model.BuildTargetFactory; import com.facebook.buck.model.InternalFlavor; import com.facebook.buck.rules.FakeSourcePath; import com.facebook.buck.rules.TargetGraph; import com.facebook.buck.rules.TargetNode; import com.facebook.buck.testutil.TargetGraphFactory; import com.facebook.buck.util.MoreCollectors; import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSortedSet; import com.google.common.collect.Iterables; import java.nio.file.Paths; import java.util.HashSet; import java.util.Optional; import java.util.Set; import org.junit.Test; public class APKModuleTest { private void verifyDependencies( APKModuleGraph graph, APKModule module, ImmutableSet<String> names) { ImmutableSet<APKModule> deps = graph.getGraph().getOutgoingNodesFor(module); assertThat(deps.size(), is(names.size())); for (APKModule dep : deps) { assertThat(dep.getName(), in(names)); } } /* + - - - - - -+ ' root: ' ' ' ' +--------+ ' +-------------- ' | Binary | ' --------+ | ' +--------+ ' | | ' | ' | | ' | ' | v ' | ' v + - - - - - - + ' | ' +- - - - - + ' android: ' ' | ' ' java: ' ' ' ' | ' ' ' ' +---------+ ' ' | ' ' +------+ ' ' | Android | ' ' | ' ' | Java | ' ' +---------+ ' ' | ' ' +------+ ' ' ' ' | ' ' ' + - - - - - - + ' | ' +- - - - - + | ' | ' | | ' | ' | | ' v ' | | ' +--------+ ' | +-------------> ' | Common | ' <-------+ ' +--------+ ' ' ' + - - - - - -+ */ @Test public void testAPKModuleGraphSimple() throws Exception { ImmutableSet.Builder<TargetNode<?, ?>> nodeBuilder = ImmutableSet.builder(); BuildTarget commonLibraryTarget = BuildTargetFactory.newInstance( "//src/com/facebook/test-common-library:test-common-library"); nodeBuilder.add( AndroidLibraryBuilder.createBuilder(commonLibraryTarget) .addSrc(Paths.get("src/com/facebook/TestCommonLibrary.java")) .build()); BuildTarget javaLibraryTarget = BuildTargetFactory.newInstance("//src/com/facebook/test-java-library:test-java-library") .withFlavors(InternalFlavor.of("flavor")); nodeBuilder.add( JavaLibraryBuilder.createBuilder(javaLibraryTarget) .addSrc(Paths.get("src/com/facebook/TestJavaLibrary.java")) .addDep(commonLibraryTarget) .build()); BuildTarget androidLibraryTarget = BuildTargetFactory.newInstance( "//src/com/facebook/test-android-library:test-android-library"); nodeBuilder.add( AndroidLibraryBuilder.createBuilder(androidLibraryTarget) .addSrc(Paths.get("src/com/facebook/TestAndroidLibrary.java")) .addDep(commonLibraryTarget) .build()); BuildTarget keystoreTarget = BuildTargetFactory.newInstance("//:keystore"); nodeBuilder.add( KeystoreBuilder.createBuilder(keystoreTarget) .setStore(new FakeSourcePath("debug.keystore")) .setProperties(new FakeSourcePath("keystore.properties")) .build()); BuildTarget androidBinaryTarget = BuildTargetFactory.newInstance( "//src/com/facebook/test-android-binary:test-android-binary"); nodeBuilder.add( AndroidBinaryBuilder.createBuilder(androidBinaryTarget) .setManifest(new FakeSourcePath("AndroidManifest.xml")) .setKeystore(keystoreTarget) .setOriginalDeps( ImmutableSortedSet.of(androidLibraryTarget, javaLibraryTarget, commonLibraryTarget)) .build()); TargetGraph graph = TargetGraphFactory.newInstance(nodeBuilder.build()); Set<BuildTarget> seedTargets = new HashSet<>(); seedTargets.add(androidLibraryTarget); seedTargets.add(javaLibraryTarget); APKModuleGraph dag = new APKModuleGraph(graph, androidBinaryTarget, Optional.of(seedTargets)); ImmutableSet<APKModule> topLevelNodes = dag.getGraph().getNodesWithNoIncomingEdges(); assertThat(topLevelNodes.size(), is(2)); for (APKModule apkModule : topLevelNodes) { assertThat( apkModule.getName(), oneOf( "src.com.facebook.test.android.library", "src.com.facebook.test.java.library.test.java.library.flavor")); ImmutableSet<APKModule> dependencies = dag.getGraph().getOutgoingNodesFor(apkModule); assertThat(apkModule.isRootModule(), is(false)); assertThat(dependencies.size(), is(1)); assertThat( Iterables.getFirst(dependencies, null).getName(), is(APKModuleGraph.ROOT_APKMODULE_NAME)); assertThat(Iterables.getFirst(dependencies, null).isRootModule(), is(true)); } assertThat( dag.getAPKModules() .stream() .map(APKModule::getName) .collect(MoreCollectors.toImmutableSet()), containsInAnyOrder( "dex", "src.com.facebook.test.android.library", "src.com.facebook.test.java.library.test.java.library.flavor")); } /* +- - - - - - - - - - - - + ' root: ' ' ' ' +--------------------+ ' +------------------- ' | Binary | ' -------------+ | ' +--------------------+ ' | | ' | ' | | ' | ' | v ' | ' v + - - - - - - + ' | ' +- - - - - + ' android: ' ' | ' ' java: ' ' ' ' v ' ' ' ' +---------+ ' ' +--------------------+ ' ' +------+ ' ' | Android | ' =======> ' | Common | ' <======= ' | Java | ' ' +---------+ ' ' +--------------------+ ' ' +------+ ' ' ' ' ' ' ' + - - - - - - + +- - - - - - - - - - - - + +- - - - - + H H H H H H H +- - - - - - - - - - - - + H H ' shared_android_java: ' H H ' ' H H ' +--------------------+ ' H #==================> ' | Shared | ' <============# ' +--------------------+ ' ' ' +- - - - - - - - - - - - + -- target dependecy == package and target dependecy */ @Test public void testAPKModuleGraphSharedDependency() throws Exception { ImmutableSet.Builder<TargetNode<?, ?>> nodeBuilder = ImmutableSet.builder(); BuildTarget commonLibraryTarget = BuildTargetFactory.newInstance("//:test-common-library"); nodeBuilder.add( AndroidLibraryBuilder.createBuilder(commonLibraryTarget) .addSrc(Paths.get("src/com/facebook/TestCommonLibrary.java")) .build()); BuildTarget sharedLibraryTarget = BuildTargetFactory.newInstance("//:test-shared-library"); nodeBuilder.add( AndroidLibraryBuilder.createBuilder(sharedLibraryTarget) .addSrc(Paths.get("src/com/facebook/TestSharedLibrary.java")) .addDep(commonLibraryTarget) .build()); BuildTarget javaLibraryTarget = BuildTargetFactory.newInstance("//:test-java-library"); nodeBuilder.add( JavaLibraryBuilder.createBuilder(javaLibraryTarget) .addSrc(Paths.get("src/com/facebook/TestJavaLibrary.java")) .addDep(commonLibraryTarget) .addDep(sharedLibraryTarget) .build()); BuildTarget androidLibraryTarget = BuildTargetFactory.newInstance("//:test-android-library"); nodeBuilder.add( AndroidLibraryBuilder.createBuilder(androidLibraryTarget) .addSrc(Paths.get("src/com/facebook/TestAndroidLibrary.java")) .addDep(commonLibraryTarget) .addDep(sharedLibraryTarget) .build()); BuildTarget keystoreTarget = BuildTargetFactory.newInstance("//:keystore"); nodeBuilder.add( KeystoreBuilder.createBuilder(keystoreTarget) .setStore(new FakeSourcePath("debug.keystore")) .setProperties(new FakeSourcePath("keystore.properties")) .build()); BuildTarget androidBinaryTarget = BuildTargetFactory.newInstance("//:test-android-binary"); nodeBuilder.add( AndroidBinaryBuilder.createBuilder(androidBinaryTarget) .setManifest(new FakeSourcePath("AndroidManifest.xml")) .setKeystore(keystoreTarget) .setOriginalDeps( ImmutableSortedSet.of(androidLibraryTarget, javaLibraryTarget, commonLibraryTarget)) .build()); TargetGraph graph = TargetGraphFactory.newInstance(nodeBuilder.build()); Set<BuildTarget> seedTargets = new HashSet<>(); seedTargets.add(androidLibraryTarget); seedTargets.add(javaLibraryTarget); APKModuleGraph dag = new APKModuleGraph(graph, androidBinaryTarget, Optional.of(seedTargets)); ImmutableSet<APKModule> topLevelNodes = dag.getGraph().getNodesWithNoIncomingEdges(); assertThat(topLevelNodes.size(), is(2)); for (APKModule apkModule : topLevelNodes) { assertThat(apkModule.getName(), oneOf("test.android.library", "test.java.library")); ImmutableSet<APKModule> dependencies = dag.getGraph().getOutgoingNodesFor(apkModule); assertThat(dependencies.size(), is(2)); assertThat( Iterables.getFirst(dependencies, null).getName(), oneOf(APKModuleGraph.ROOT_APKMODULE_NAME, "test.shared.library")); } } /* +----------------------------+ | | | | +--------------+---------------+ | | | v v +--------+ +---------+ +------+ +--------+ +--------+ | Binary | --> | Android | --> | Java | --> | Shared | --> | | +--------+ +---------+ +------+ +--------+ | | | | | | | +--------------+---------------+-----------------------> | Common | | | | | | | | | +---------------+-----------------------> | | | +--------+ | ^ +---------------------------+ */ @Test public void testAPKModuleGraphComplexDependencyTree() throws Exception { ImmutableSet.Builder<TargetNode<?, ?>> nodeBuilder = ImmutableSet.builder(); BuildTarget commonLibraryTarget = BuildTargetFactory.newInstance("//:test-common-library"); nodeBuilder.add( AndroidLibraryBuilder.createBuilder(commonLibraryTarget) .addSrc(Paths.get("src/com/facebook/TestCommonLibrary.java")) .build()); BuildTarget sharedLibraryTarget = BuildTargetFactory.newInstance("//:test-shared-library"); nodeBuilder.add( AndroidLibraryBuilder.createBuilder(sharedLibraryTarget) .addSrc(Paths.get("src/com/facebook/TestSharedLibrary.java")) .addDep(commonLibraryTarget) .build()); BuildTarget javaDepLibraryTarget = BuildTargetFactory.newInstance("//:test-java-dep-library"); nodeBuilder.add( AndroidLibraryBuilder.createBuilder(javaDepLibraryTarget) .addSrc(Paths.get("src/com/facebook/TestJavaDepLibrary.java")) .build()); BuildTarget javaLibraryTarget = BuildTargetFactory.newInstance("//:test-java-library"); nodeBuilder.add( JavaLibraryBuilder.createBuilder(javaLibraryTarget) .addSrc(Paths.get("src/com/facebook/TestJavaLibrary.java")) .addDep(commonLibraryTarget) .addDep(javaDepLibraryTarget) .addDep(sharedLibraryTarget) .build()); BuildTarget androidLibraryTarget = BuildTargetFactory.newInstance("//:test-android-library"); nodeBuilder.add( AndroidLibraryBuilder.createBuilder(androidLibraryTarget) .addSrc(Paths.get("src/com/facebook/TestAndroidLibrary.java")) .addDep(javaLibraryTarget) .addDep(commonLibraryTarget) .addDep(sharedLibraryTarget) .build()); BuildTarget keystoreTarget = BuildTargetFactory.newInstance("//:keystore"); nodeBuilder.add( KeystoreBuilder.createBuilder(keystoreTarget) .setStore(new FakeSourcePath("debug.keystore")) .setProperties(new FakeSourcePath("keystore.properties")) .build()); BuildTarget androidBinaryTarget = BuildTargetFactory.newInstance("//:test-android-binary"); nodeBuilder.add( AndroidBinaryBuilder.createBuilder(androidBinaryTarget) .setManifest(new FakeSourcePath("AndroidManifest.xml")) .setKeystore(keystoreTarget) .setOriginalDeps( ImmutableSortedSet.of(androidLibraryTarget, javaLibraryTarget, commonLibraryTarget)) .build()); TargetGraph graph = TargetGraphFactory.newInstance(nodeBuilder.build()); Set<BuildTarget> seedTargets = new HashSet<>(); seedTargets.add(androidLibraryTarget); seedTargets.add(javaLibraryTarget); APKModuleGraph dag = new APKModuleGraph(graph, androidBinaryTarget, Optional.of(seedTargets)); ImmutableSet<APKModule> topLevelNodes = dag.getGraph().getNodesWithNoIncomingEdges(); assertThat(topLevelNodes.size(), is(2)); for (APKModule apkModule : topLevelNodes) { assertThat(apkModule.getName(), oneOf("test.android.library", "test.java.library")); ImmutableSet<APKModule> dependencies = dag.getGraph().getOutgoingNodesFor(apkModule); for (APKModule depModule : dependencies) { assertThat( depModule.getName(), oneOf("test.java.library", "test.shared.library", APKModuleGraph.ROOT_APKMODULE_NAME)); switch (depModule.getName()) { case APKModuleGraph.ROOT_APKMODULE_NAME: assertThat(dag.getGraph().getOutgoingNodesFor(depModule).size(), is(0)); break; case "test.java.library": verifyDependencies( dag, depModule, ImmutableSet.of("test.shared.library", APKModuleGraph.ROOT_APKMODULE_NAME)); break; case "test.shared.library": verifyDependencies(dag, depModule, ImmutableSet.of(APKModuleGraph.ROOT_APKMODULE_NAME)); break; } } } } }