blob: 8492d931686e75f5a8734fe0d52d8be83044ce1a [file] [log] [blame]
/*
* Copyright 2014-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.cxx;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import com.facebook.buck.android.AndroidPackageable;
import com.facebook.buck.android.AndroidPackageableCollector;
import com.facebook.buck.cli.FakeBuckConfig;
import com.facebook.buck.io.ProjectFilesystem;
import com.facebook.buck.model.BuildTarget;
import com.facebook.buck.model.BuildTargetFactory;
import com.facebook.buck.model.FlavorDomain;
import com.facebook.buck.python.ImmutablePythonPackageComponents;
import com.facebook.buck.python.PythonPackageComponents;
import com.facebook.buck.rules.BuildRule;
import com.facebook.buck.rules.BuildRuleParams;
import com.facebook.buck.rules.BuildRuleParamsFactory;
import com.facebook.buck.rules.BuildRuleResolver;
import com.facebook.buck.rules.BuildTargetSourcePath;
import com.facebook.buck.rules.FakeBuildRule;
import com.facebook.buck.rules.FakeBuildRuleParamsBuilder;
import com.facebook.buck.rules.PathSourcePath;
import com.facebook.buck.rules.SourcePath;
import com.facebook.buck.rules.SourcePathResolver;
import com.facebook.buck.shell.GenruleBuilder;
import com.facebook.buck.testutil.FakeProjectFilesystem;
import com.facebook.buck.testutil.TargetGraphFactory;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.Iterables;
import org.junit.Test;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Map;
public class CxxPythonExtensionDescriptionTest {
private static final BuildTarget PYTHON_DEP_TARGET =
BuildTargetFactory.newInstance("//:python_dep");
private static FakeBuildRule createFakeBuildRule(
String target,
SourcePathResolver resolver,
BuildRule... deps) {
return new FakeBuildRule(
new FakeBuildRuleParamsBuilder(BuildTargetFactory.newInstance(target))
.setDeps(ImmutableSortedSet.copyOf(deps))
.build(), resolver);
}
public CxxPythonExtensionBuilder getBuilder(BuildTarget target) {
FakeBuckConfig buckConfig = new FakeBuckConfig(
ImmutableMap.<String, Map<String, String>>of(
"cxx", ImmutableMap.of(
"python_dep", PYTHON_DEP_TARGET.toString())));
CxxBuckConfig cxxBuckConfig = new CxxBuckConfig(buckConfig);
FlavorDomain<CxxPlatform> cxxPlatforms = CxxPythonExtensionBuilder.createDefaultPlatforms();
return new CxxPythonExtensionBuilder(target, cxxBuckConfig, cxxPlatforms);
}
@Test
public void createBuildRuleBaseModule() {
BuildTarget target = BuildTargetFactory.newInstance("//:target");
ProjectFilesystem filesystem = new FakeProjectFilesystem();
CxxPlatform cxxPlatform = CxxPythonExtensionBuilder.createDefaultPlatform();
// Verify we use the default base module when none is set.
CxxPythonExtensionBuilder normalBuilder = getBuilder(target);
CxxPythonExtensionDescription desc =
(CxxPythonExtensionDescription) normalBuilder.build().getDescription();
CxxPythonExtension normal = (CxxPythonExtension) normalBuilder
.build(
new BuildRuleResolver(),
filesystem,
TargetGraphFactory.newInstance(
normalBuilder.build(),
GenruleBuilder.newGenruleBuilder(PYTHON_DEP_TARGET).build()));
PythonPackageComponents normalComps = normal.getPythonPackageComponents(cxxPlatform);
assertEquals(
ImmutableSet.of(
target.getBasePath().resolve(desc.getExtensionName(target))),
normalComps.getModules().keySet());
// Verify that explicitly setting works.
String name = "blah";
CxxPythonExtensionBuilder baseModuleBuilder = getBuilder(target)
.setBaseModule(name);
desc = (CxxPythonExtensionDescription) baseModuleBuilder.build().getDescription();
CxxPythonExtension baseModule = (CxxPythonExtension) baseModuleBuilder
.build(
new BuildRuleResolver(),
filesystem,
TargetGraphFactory.newInstance(
baseModuleBuilder.build(),
GenruleBuilder.newGenruleBuilder(PYTHON_DEP_TARGET).build()));
PythonPackageComponents baseModuleComps = baseModule.getPythonPackageComponents(cxxPlatform);
assertEquals(
ImmutableSet.of(
Paths.get(name).resolve(desc.getExtensionName(target))),
baseModuleComps.getModules().keySet());
}
@Test
public void createBuildRuleNativeLinkableDep() {
BuildTarget target = BuildTargetFactory.newInstance("//:target");
BuildRuleResolver resolver = new BuildRuleResolver();
SourcePathResolver pathResolver = new SourcePathResolver(resolver);
CxxPlatform cxxPlatform = CxxPythonExtensionBuilder.createDefaultPlatform();
// Setup a C/C++ library that we'll depend on form the C/C++ binary description.
final BuildRule sharedLibraryDep = createFakeBuildRule("//:shared", pathResolver);
final Path sharedLibraryOutput = Paths.get("output/path/lib.so");
final String sharedLibrarySoname = "soname";
BuildTarget depTarget = BuildTargetFactory.newInstance("//:dep");
BuildRuleParams depParams = BuildRuleParamsFactory.createTrivialBuildRuleParams(depTarget);
AbstractCxxLibrary dep = new AbstractCxxLibrary(depParams, pathResolver) {
@Override
public CxxPreprocessorInput getCxxPreprocessorInput(CxxPlatform cxxPlatform) {
return CxxPreprocessorInput.EMPTY;
}
@Override
public NativeLinkableInput getNativeLinkableInput(
CxxPlatform cxxPlatform,
Linker.LinkableDepType type) {
return type == Linker.LinkableDepType.STATIC ?
ImmutableNativeLinkableInput.of(
ImmutableList.<SourcePath>of(),
ImmutableList.<String>of()) :
ImmutableNativeLinkableInput.of(
ImmutableList.<SourcePath>of(
new BuildTargetSourcePath(
getProjectFilesystem(),
sharedLibraryDep.getBuildTarget(),
sharedLibraryOutput)),
ImmutableList.of(sharedLibraryOutput.toString()));
}
@Override
public PythonPackageComponents getPythonPackageComponents(CxxPlatform cxxPlatform) {
return ImmutablePythonPackageComponents.of(
ImmutableMap.<Path, SourcePath>of(),
ImmutableMap.<Path, SourcePath>of(),
ImmutableMap.<Path, SourcePath>of(
Paths.get(sharedLibrarySoname),
new PathSourcePath(getProjectFilesystem(), sharedLibraryOutput)));
}
@Override
public Iterable<AndroidPackageable> getRequiredPackageables() {
return ImmutableList.of();
}
@Override
public void addToCollector(AndroidPackageableCollector collector) {}
@Override
public ImmutableMap<String, SourcePath> getSharedLibraries(CxxPlatform cxxPlatform) {
return ImmutableMap.of();
}
};
resolver.addAllToIndex(ImmutableList.of(sharedLibraryDep, dep));
// Create args with the above dep set and create the python extension.
CxxPythonExtensionBuilder extensionBuilder = (CxxPythonExtensionBuilder) getBuilder(target)
.setDeps(ImmutableSortedSet.of(depTarget));
CxxPythonExtensionDescription desc =
(CxxPythonExtensionDescription) extensionBuilder.build().getDescription();
CxxPythonExtension extension = (CxxPythonExtension) extensionBuilder.build(
resolver,
new FakeProjectFilesystem(),
TargetGraphFactory.newInstance(
extensionBuilder.build(),
GenruleBuilder.newGenruleBuilder(PYTHON_DEP_TARGET).build(),
GenruleBuilder.newGenruleBuilder(depTarget).build()));
// Verify that the shared library dep propagated to the link rule.
extension.getPythonPackageComponents(cxxPlatform);
BuildRule rule = resolver.getRule(desc.getExtensionTarget(target, cxxPlatform.getFlavor()));
assertEquals(
ImmutableSortedSet.of(sharedLibraryDep),
rule.getDeps());
}
@Test
public void createBuildRulePythonPackageable() {
ProjectFilesystem projectFilesystem = new FakeProjectFilesystem();
BuildTarget target = BuildTargetFactory.newInstance("//:target");
BuildRuleResolver resolver = new BuildRuleResolver();
CxxPlatform cxxPlatform = CxxPythonExtensionBuilder.createDefaultPlatform();
CxxPythonExtensionBuilder extensionBuilder = getBuilder(target);
CxxPythonExtensionDescription desc =
(CxxPythonExtensionDescription) extensionBuilder.build().getDescription();
CxxPythonExtension extension = (CxxPythonExtension) extensionBuilder.build(
resolver,
projectFilesystem,
TargetGraphFactory.newInstance(
extensionBuilder.build(),
GenruleBuilder.newGenruleBuilder(PYTHON_DEP_TARGET).build()));
// Verify that we get the expected view from the python packageable interface.
PythonPackageComponents actualComponent = extension.getPythonPackageComponents(cxxPlatform);
BuildRule rule = resolver.getRule(desc.getExtensionTarget(target, cxxPlatform.getFlavor()));
PythonPackageComponents expectedComponents = ImmutablePythonPackageComponents.of(
ImmutableMap.<Path, SourcePath>of(
target.getBasePath().resolve(desc.getExtensionName(target)),
new BuildTargetSourcePath(projectFilesystem, rule.getBuildTarget())),
ImmutableMap.<Path, SourcePath>of(),
ImmutableMap.<Path, SourcePath>of());
assertEquals(
expectedComponents,
actualComponent);
}
@Test
public void findDepsFromParamsAddsPythonDep() {
BuildTarget target = BuildTargetFactory.newInstance("//:target");
CxxPythonExtensionDescription desc =
(CxxPythonExtensionDescription) getBuilder(target).build().getDescription();
CxxPythonExtensionDescription.Arg constructorArg = desc.createUnpopulatedConstructorArg();
constructorArg.lexSrcs = Optional.of(ImmutableList.<SourcePath>of());
Iterable<BuildTarget> res = desc.findDepsForTargetFromConstructorArgs(
BuildTargetFactory.newInstance("//foo:bar"),
constructorArg);
assertTrue(Iterables.contains(res, PYTHON_DEP_TARGET));
}
}