/*
* Copyright 2016-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.jvm.java;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import com.facebook.buck.io.ProjectFilesystem;
import com.facebook.buck.jvm.java.testutil.AbiCompilationModeTest;
import com.facebook.buck.model.BuildTarget;
import com.facebook.buck.model.BuildTargetFactory;
import com.facebook.buck.rules.BuildRule;
import com.facebook.buck.rules.BuildRuleResolver;
import com.facebook.buck.rules.DefaultTargetNodeToBuildRuleTransformer;
import com.facebook.buck.rules.FakeSourcePath;
import com.facebook.buck.rules.SourcePathResolver;
import com.facebook.buck.rules.SourcePathRuleFinder;
import com.facebook.buck.rules.TargetGraph;
import com.facebook.buck.rules.TargetNode;
import com.facebook.buck.shell.GenruleBuilder;
import com.facebook.buck.testutil.FakeProjectFilesystem;
import com.facebook.buck.testutil.TargetGraphFactory;
import com.facebook.buck.util.MoreCollectors;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.hash.HashCode;
import java.nio.file.Path;
import java.util.Optional;
import javax.annotation.Nullable;
import org.hamcrest.Matchers;
import org.junit.Before;
import org.junit.Test;
public class JavaLibraryClasspathProviderTest extends AbiCompilationModeTest {
private TargetNode<?, ?> aNode;
private TargetNode<?, ?> bNode;
private TargetNode<?, ?> cNode;
private TargetNode<?, ?> dNode;
private TargetNode<?, ?> eNode;
private TargetNode<?, ?> zNode;
private BuildRule a;
private BuildRule b;
private BuildRule c;
private BuildRule d;
private BuildRule e;
private BuildRule z;
private SourcePathResolver resolver;
private ProjectFilesystem filesystem;
@Before
public void setUp() throws Exception {
filesystem = new FakeProjectFilesystem();
// Create our target graph. All nodes are JavaLibrary except b
// (exports c) az (no exports)
// / \
//(non java) b c (exports e)
// | |
// d e
dNode = makeRule("//foo:d", ImmutableSet.of("foo", "d.java"), ImmutableSet.of(), filesystem);
bNode =
GenruleBuilder.newGenruleBuilder(BuildTargetFactory.newInstance("//foo:b"))
.setSrcs(ImmutableList.of(new FakeSourcePath(filesystem, "foo/b.java")))
.setCmd("echo $(classpath //foo:d")
.setOut("b.out")
.build();
eNode = makeRule("//foo:e", ImmutableSet.of("foo", "e.java"), ImmutableSet.of(), filesystem);
// exported
cNode =
makeRule(
"//foo:c",
ImmutableSet.of("foo", "c.java"),
ImmutableSet.of(eNode),
ImmutableSet.of(eNode), // exported
filesystem);
aNode =
makeRule(
"//foo:a",
ImmutableSet.of("foo", "a.java"),
ImmutableSet.of(bNode, cNode),
ImmutableSet.of(cNode),
filesystem);
zNode =
makeRule(
"//foo:z", ImmutableSet.of("foo", "a.java"), ImmutableSet.of(bNode, cNode), filesystem);
TargetGraph targetGraph =
TargetGraphFactory.newInstance(aNode, bNode, cNode, dNode, eNode, zNode);
BuildRuleResolver ruleResolver =
new BuildRuleResolver(targetGraph, new DefaultTargetNodeToBuildRuleTransformer());
resolver = new SourcePathResolver(new SourcePathRuleFinder(ruleResolver));
a = ruleResolver.requireRule(aNode.getBuildTarget());
b = ruleResolver.requireRule(bNode.getBuildTarget());
c = ruleResolver.requireRule(cNode.getBuildTarget());
d = ruleResolver.requireRule(dNode.getBuildTarget());
e = ruleResolver.requireRule(eNode.getBuildTarget());
z = ruleResolver.requireRule(zNode.getBuildTarget());
}
@Test
public void getOutputClasspathEntries() throws Exception {
JavaLibrary aLib = (JavaLibrary) a;
assertEquals(
ImmutableSet.of(
getFullOutput(a),
getFullOutput(c), // a exports c
getFullOutput(e) // c exports e
),
JavaLibraryClasspathProvider.getOutputClasspathJars(
aLib, Optional.of(aLib.getSourcePathToOutput()))
.stream()
.map(resolver::getAbsolutePath)
.collect(MoreCollectors.toImmutableSet()));
}
@Test
public void getClasspathFromLibraries() throws Exception {
assertEquals(
ImmutableSet.of(getFullOutput(a), getFullOutput(c), getFullOutput(e)),
// b is non-java so b and d do not appear
JavaLibraryClasspathProvider.getClasspathsFromLibraries(
JavaLibraryClasspathProvider.getClasspathDeps(ImmutableSet.of(a)))
.stream()
.map(resolver::getAbsolutePath)
.collect(MoreCollectors.toImmutableSet()));
assertEquals(
ImmutableSet.of(
getFullOutput(c),
getFullOutput(e), // c exports e
getFullOutput(d)),
JavaLibraryClasspathProvider.getClasspathsFromLibraries(
JavaLibraryClasspathProvider.getClasspathDeps(ImmutableSet.of(c, d)))
.stream()
.map(resolver::getAbsolutePath)
.collect(MoreCollectors.toImmutableSet()));
}
@Test
public void getClasspathDeps() {
assertEquals(
ImmutableSet.of(a, c, e),
JavaLibraryClasspathProvider.getClasspathDeps(ImmutableSet.of(a)));
assertEquals(
ImmutableSet.of(d, c, e),
JavaLibraryClasspathProvider.getClasspathDeps(ImmutableSet.of(d, c)));
}
@Test
public void getTransitiveClasspaths() throws Exception {
JavaLibrary aLib = (JavaLibrary) a;
assertEquals(
ImmutableSet.builder()
.add(getFullOutput(a))
.add(getFullOutput(c)) // a exports c
.add(getFullOutput(e)) // c exports e
// b is non-java so b and d do not appear
.build(),
aLib.getTransitiveClasspaths()
.stream()
.map(resolver::getAbsolutePath)
.collect(MoreCollectors.toImmutableSet()));
}
@Test
public void getTransitiveClasspathDeps() throws Exception {
TargetNode<?, ?> noOutputNode =
makeRule("//no:output", ImmutableSet.of(), ImmutableSet.of(zNode), filesystem);
TargetGraph targetGraph =
TargetGraphFactory.newInstance(aNode, bNode, cNode, dNode, eNode, zNode, noOutputNode);
BuildRuleResolver ruleResolver =
new BuildRuleResolver(targetGraph, new DefaultTargetNodeToBuildRuleTransformer());
JavaLibrary noOutput = (JavaLibrary) ruleResolver.requireRule(noOutputNode.getBuildTarget());
assertEquals(
"root does not appear if output jar not present.",
ImmutableSet.of(c, e, z),
JavaLibraryClasspathProvider.getTransitiveClasspathDeps(noOutput));
assertEquals(
"root does appear if output jar present.",
ImmutableSet.of(z, c, e),
JavaLibraryClasspathProvider.getTransitiveClasspathDeps((JavaLibrary) z));
BuildRule mavenCoord =
new JavaLibraryBuilder(
BuildTargetFactory.newInstance("//has:output"),
filesystem,
HashCode.fromString("aaaa"))
.setMavenCoords("com.example:buck:1.0")
.addDep(z.getBuildTarget())
.build(ruleResolver);
assertEquals(
"Does appear if no output jar but maven coordinate present.",
ImmutableSet.of(z, c, e, mavenCoord),
JavaLibraryClasspathProvider.getTransitiveClasspathDeps((JavaLibrary) mavenCoord));
}
@Test
public void getJavaLibraryDeps() throws Exception {
assertThat(
JavaLibraryClasspathProvider.getJavaLibraryDeps(ImmutableList.of(a, b, c, d, e)),
Matchers.containsInAnyOrder(a, c, d, e));
}
private Path getFullOutput(BuildRule lib) {
return resolver.getAbsolutePath(lib.getSourcePathToOutput());
}
private TargetNode<?, ?> makeRule(
String target,
Iterable<String> srcs,
Iterable<TargetNode<?, ?>> deps,
ProjectFilesystem filesystem)
throws Exception {
return makeRule(target, srcs, deps, null, filesystem);
}
private TargetNode<?, ?> makeRule(
String target,
Iterable<String> srcs,
Iterable<TargetNode<?, ?>> deps,
@Nullable Iterable<TargetNode<?, ?>> exportedDeps,
final ProjectFilesystem filesystem)
throws Exception {
JavaLibraryBuilder builder;
BuildTarget parsedTarget = BuildTargetFactory.newInstance(target);
JavaBuckConfig testConfig = getJavaBuckConfigWithCompilationMode();
builder = JavaLibraryBuilder.createBuilder(parsedTarget, testConfig);
for (String src : srcs) {
builder.addSrc(filesystem.getBuckPaths().getGenDir().resolve(src));
}
for (TargetNode<?, ?> dep : deps) {
builder.addDep(dep.getBuildTarget());
}
if (exportedDeps != null) {
for (TargetNode<?, ?> dep : exportedDeps) {
builder.addExportedDep(dep.getBuildTarget());
}
}
return builder.build();
}
}