blob: e32e35b4a9017f8b429a6a9078691fd717f5cfe1 [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.thrift;
import static org.junit.Assert.assertEquals;
import com.facebook.buck.cli.FakeBuckConfig;
import com.facebook.buck.cxx.CxxBuckConfig;
import com.facebook.buck.cxx.CxxPlatform;
import com.facebook.buck.cxx.DefaultCxxPlatforms;
import com.facebook.buck.model.BuildTarget;
import com.facebook.buck.model.BuildTargetFactory;
import com.facebook.buck.model.FlavorDomain;
import com.facebook.buck.model.ImmutableFlavor;
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.FakeBuildRule;
import com.facebook.buck.rules.FakeBuildRuleParamsBuilder;
import com.facebook.buck.rules.SourcePath;
import com.facebook.buck.rules.SourcePathResolver;
import com.facebook.buck.rules.TestSourcePath;
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 org.junit.Test;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Map;
public class ThriftCxxEnhancerTest {
private static final BuildTarget TARGET = BuildTargetFactory.newInstance("//:test#cpp");
private static final FakeBuckConfig BUCK_CONFIG = new FakeBuckConfig();
private static final ThriftBuckConfig THRIFT_BUCK_CONFIG = new ThriftBuckConfig(BUCK_CONFIG);
private static final CxxBuckConfig CXX_BUCK_CONFIG = new CxxBuckConfig(BUCK_CONFIG);
private static final CxxPlatform CXX_PLATFORM = DefaultCxxPlatforms.build(
BUCK_CONFIG);
private static final FlavorDomain<CxxPlatform> CXX_PLATFORMS =
new FlavorDomain<>(
"C/C++ Platform",
ImmutableMap.of(CXX_PLATFORM.getFlavor(), CXX_PLATFORM));
private static final ThriftCxxEnhancer ENHANCER_CPP = new ThriftCxxEnhancer(
THRIFT_BUCK_CONFIG,
CXX_BUCK_CONFIG,
CXX_PLATFORMS,
/* cpp2 */ false);
private static final ThriftCxxEnhancer ENHANCER_CPP2 = new ThriftCxxEnhancer(
THRIFT_BUCK_CONFIG,
CXX_BUCK_CONFIG,
CXX_PLATFORMS,
/* cpp2 */ true);
private static FakeBuildRule createFakeBuildRule(
String target,
SourcePathResolver resolver,
BuildRule... deps) {
return new FakeBuildRule(
new FakeBuildRuleParamsBuilder(BuildTargetFactory.newInstance(target))
.setDeps(ImmutableSortedSet.copyOf(deps))
.build(),
resolver);
}
private static ThriftCompiler createFakeThriftCompiler(
String target,
SourcePathResolver resolver) {
return new ThriftCompiler(
BuildRuleParamsFactory.createTrivialBuildRuleParams(
BuildTargetFactory.newInstance(target)),
resolver,
new TestSourcePath("compiler"),
ImmutableList.<String>of(),
Paths.get("output"),
new TestSourcePath("source"),
"language",
ImmutableSet.<String>of(),
ImmutableList.<Path>of(),
ImmutableMap.<Path, SourcePath>of());
}
@Test
public void getLanguage() {
assertEquals(
"cpp",
ENHANCER_CPP.getLanguage());
assertEquals(
"cpp2",
ENHANCER_CPP2.getLanguage());
}
@Test
public void getFlavor() {
assertEquals(
ImmutableFlavor.of("cpp"),
ENHANCER_CPP.getFlavor());
assertEquals(
ImmutableFlavor.of("cpp2"),
ENHANCER_CPP2.getFlavor());
}
private ImmutableSet<String> getExpectedOptions(BuildTarget target, ImmutableSet<String> opts) {
return ImmutableSet.<String>builder()
.addAll(opts)
.add(String.format("include_prefix=%s", target.getBasePath()))
.build();
}
@Test
public void getOptions() {
ThriftConstructorArg arg = new ThriftConstructorArg();
ImmutableSet<String> options;
// Test empty options.
options = ImmutableSet.of();
arg.cppOptions = Optional.of(options);
assertEquals(
getExpectedOptions(TARGET, options),
ENHANCER_CPP.getOptions(TARGET, arg));
arg.cpp2Options = Optional.of(options);
assertEquals(
getExpectedOptions(TARGET, options),
ENHANCER_CPP2.getOptions(TARGET, arg));
// Test set options.
options = ImmutableSet.of("test", "option");
arg.cppOptions = Optional.of(options);
assertEquals(
getExpectedOptions(TARGET, options),
ENHANCER_CPP.getOptions(TARGET, arg));
arg.cpp2Options = Optional.of(options);
assertEquals(
getExpectedOptions(TARGET, options),
ENHANCER_CPP.getOptions(TARGET, arg));
// Test absent options.
arg.cppOptions = Optional.absent();
assertEquals(
getExpectedOptions(TARGET, ImmutableSet.<String>of()),
ENHANCER_CPP.getOptions(TARGET, arg));
arg.cpp2Options = Optional.absent();
assertEquals(
getExpectedOptions(TARGET, ImmutableSet.<String>of()),
ENHANCER_CPP2.getOptions(TARGET, arg));
}
private void expectImplicitDeps(
ThriftCxxEnhancer enhancer,
ImmutableSet<String> options,
ImmutableSet<BuildTarget> expected) {
ThriftConstructorArg arg = new ThriftConstructorArg();
arg.cppOptions = Optional.of(options);
arg.cpp2Options = Optional.of(options);
assertEquals(
expected,
enhancer.getImplicitDepsForTargetFromConstructorArg(TARGET, arg));
}
@Test
public void getImplicitDeps() {
// Setup an enhancer which sets all appropriate values in the config.
ImmutableMap<String, BuildTarget> config = ImmutableMap.of(
"cpp_library", BuildTargetFactory.newInstance("//:cpp_library"),
"cpp2_library", BuildTargetFactory.newInstance("//:cpp2_library"),
"cpp_reflection_library", BuildTargetFactory.newInstance("//:cpp_reflection_library"),
"cpp_frozen_library", BuildTargetFactory.newInstance("//:cpp_froze_library"),
"cpp_json_library", BuildTargetFactory.newInstance("//:cpp_json_library"));
ImmutableMap.Builder<String, String> strConfig = ImmutableMap.builder();
for (ImmutableMap.Entry<String, BuildTarget> ent : config.entrySet()) {
strConfig.put(ent.getKey(), ent.getValue().toString());
}
FakeBuckConfig buckConfig = new FakeBuckConfig(
ImmutableMap.<String, Map<String, String>>of("thrift", strConfig.build()));
ThriftBuckConfig thriftBuckConfig = new ThriftBuckConfig(buckConfig);
ThriftCxxEnhancer cppEnhancerWithSettings = new ThriftCxxEnhancer(
thriftBuckConfig,
CXX_BUCK_CONFIG,
CXX_PLATFORMS,
/* cpp2 */ false);
ThriftCxxEnhancer cpp2EnhancerWithSettings = new ThriftCxxEnhancer(
thriftBuckConfig,
CXX_BUCK_CONFIG,
CXX_PLATFORMS,
/* cpp2 */ true);
// With no options we just need to find the C/C++ thrift library.
expectImplicitDeps(
cppEnhancerWithSettings,
ImmutableSet.<String>of(),
ImmutableSet.of(
config.get("cpp_library"),
config.get("cpp_reflection_library")));
expectImplicitDeps(
cpp2EnhancerWithSettings,
ImmutableSet.<String>of(),
ImmutableSet.of(
config.get("cpp2_library"),
config.get("cpp_reflection_library")));
// Now check for correct reaction to the "bootstrap" option.
expectImplicitDeps(
cppEnhancerWithSettings,
ImmutableSet.of("bootstrap"),
ImmutableSet.<BuildTarget>of());
expectImplicitDeps(
cpp2EnhancerWithSettings,
ImmutableSet.of("bootstrap"),
ImmutableSet.<BuildTarget>of());
// Check the "frozen2" option
expectImplicitDeps(
cppEnhancerWithSettings,
ImmutableSet.of("frozen2"),
ImmutableSet.of(
config.get("cpp_library"),
config.get("cpp_reflection_library"),
config.get("cpp_frozen_library")));
expectImplicitDeps(
cpp2EnhancerWithSettings,
ImmutableSet.of("frozen2"),
ImmutableSet.of(
config.get("cpp2_library"),
config.get("cpp_reflection_library"),
config.get("cpp_frozen_library")));
// Check the "json" option
expectImplicitDeps(
cppEnhancerWithSettings,
ImmutableSet.of("json"),
ImmutableSet.of(
config.get("cpp_library"),
config.get("cpp_reflection_library"),
config.get("cpp_json_library")));
expectImplicitDeps(
cpp2EnhancerWithSettings,
ImmutableSet.of("json"),
ImmutableSet.of(
config.get("cpp2_library"),
config.get("cpp_reflection_library"),
config.get("cpp_json_library")));
// Check the "compatibility" option
expectImplicitDeps(
cppEnhancerWithSettings,
ImmutableSet.of("compatibility"),
ImmutableSet.of(
config.get("cpp_library"),
config.get("cpp_reflection_library")));
expectImplicitDeps(
cpp2EnhancerWithSettings,
ImmutableSet.of("compatibility"),
ImmutableSet.of(
TARGET,
config.get("cpp_library"),
config.get("cpp_reflection_library"),
config.get("cpp2_library")));
}
@Test
public void getGeneratedThriftSources() {
// Test with no options.
assertEquals(
ImmutableList.of(
"test_constants.h",
"test_constants.cpp",
"test_types.h",
"test_types.cpp",
"test_reflection.h",
"test_reflection.cpp",
"Test.h",
"Test.cpp"),
ENHANCER_CPP.getGeneratedThriftSources(
ImmutableSet.<String>of(),
"test.thrift",
ImmutableList.of("Test")));
assertEquals(
ImmutableList.of(
"test_constants.h",
"test_constants.cpp",
"test_types.h",
"test_types.cpp",
"test_types.tcc",
"Test.h",
"Test.cpp",
"Test.tcc"),
ENHANCER_CPP2.getGeneratedThriftSources(
ImmutableSet.<String>of(),
"test.thrift",
ImmutableList.of("Test")));
// Test with "frozen" option.
assertEquals(
ImmutableList.of(
"test_constants.h",
"test_constants.cpp",
"test_types.h",
"test_types.cpp",
"test_layouts.h",
"test_layouts.cpp",
"test_reflection.h",
"test_reflection.cpp",
"Test.h",
"Test.cpp"),
ENHANCER_CPP.getGeneratedThriftSources(
ImmutableSet.of("frozen"),
"test.thrift",
ImmutableList.of("Test")));
assertEquals(
ImmutableList.of(
"test_constants.h",
"test_constants.cpp",
"test_types.h",
"test_types.cpp",
"test_types.tcc",
"test_layouts.h",
"test_layouts.cpp",
"Test.h",
"Test.cpp",
"Test.tcc"),
ENHANCER_CPP2.getGeneratedThriftSources(
ImmutableSet.of("frozen"),
"test.thrift",
ImmutableList.of("Test")));
// Test with "bootstrap" option.
assertEquals(
ImmutableList.of(
"test_constants.h",
"test_constants.cpp",
"test_types.h",
"test_types.cpp",
"Test.h",
"Test.cpp"),
ENHANCER_CPP.getGeneratedThriftSources(
ImmutableSet.of("bootstrap"),
"test.thrift",
ImmutableList.of("Test")));
assertEquals(
ImmutableList.of(
"test_constants.h",
"test_constants.cpp",
"test_types.h",
"test_types.cpp",
"test_types.tcc",
"Test.h",
"Test.cpp",
"Test.tcc"),
ENHANCER_CPP2.getGeneratedThriftSources(
ImmutableSet.of("bootstrap"),
"test.thrift",
ImmutableList.of("Test")));
// Test with "templates" option.
assertEquals(
ImmutableList.of(
"test_constants.h",
"test_constants.cpp",
"test_types.h",
"test_types.cpp",
"test_types.tcc",
"test_reflection.h",
"test_reflection.cpp",
"Test.h",
"Test.cpp",
"Test.tcc"),
ENHANCER_CPP.getGeneratedThriftSources(
ImmutableSet.of("templates"),
"test.thrift",
ImmutableList.of("Test")));
assertEquals(
ImmutableList.of(
"test_constants.h",
"test_constants.cpp",
"test_types.h",
"test_types.cpp",
"test_types.tcc",
"Test.h",
"Test.cpp",
"Test.tcc"),
ENHANCER_CPP2.getGeneratedThriftSources(
ImmutableSet.of("templates"),
"test.thrift",
ImmutableList.of("Test")));
// Test with "perfhash" option.
assertEquals(
ImmutableList.of(
"test_constants.h",
"test_constants.cpp",
"test_types.h",
"test_types.cpp",
"test_reflection.h",
"test_reflection.cpp",
"Test.h",
"Test.cpp",
"Test_gperf.tcc"),
ENHANCER_CPP.getGeneratedThriftSources(
ImmutableSet.of("perfhash"),
"test.thrift",
ImmutableList.of("Test")));
assertEquals(
ImmutableList.of(
"test_constants.h",
"test_constants.cpp",
"test_types.h",
"test_types.cpp",
"test_types.tcc",
"Test.h",
"Test.cpp",
"Test.tcc"),
ENHANCER_CPP2.getGeneratedThriftSources(
ImmutableSet.of("perfhash"),
"test.thrift",
ImmutableList.of("Test")));
}
@Test
public void createBuildRule() {
BuildRuleResolver resolver = new BuildRuleResolver();
SourcePathResolver pathResolver = new SourcePathResolver(resolver);
BuildRuleParams flavoredParams =
BuildRuleParamsFactory.createTrivialBuildRuleParams(TARGET);
// Add a dummy dependency to the constructor arg to make sure it gets through.
BuildRule argDep = createFakeBuildRule("//:arg_dep", pathResolver);
resolver.addToIndex(argDep);
ThriftConstructorArg arg = new ThriftConstructorArg();
arg.cpp2Options = Optional.absent();
arg.cpp2Deps = Optional.of(
ImmutableSortedSet.of(argDep.getBuildTarget()));
ThriftCompiler thrift1 = createFakeThriftCompiler("//:thrift_source1", pathResolver);
resolver.addToIndex(thrift1);
ThriftCompiler thrift2 = createFakeThriftCompiler("//:thrift_source2", pathResolver);
resolver.addToIndex(thrift2);
// Setup up some thrift inputs to pass to the createBuildRule method.
ImmutableMap<String, ThriftSource> sources = ImmutableMap.of(
"test1.thrift", new ThriftSource(
thrift1,
ImmutableList.<String>of(),
Paths.get("output1")),
"test2.thrift", new ThriftSource(
thrift2,
ImmutableList.<String>of(),
Paths.get("output2")));
// Create a dummy implicit dep to pass in.
BuildRule dep = createFakeBuildRule("//:dep", pathResolver);
resolver.addToIndex(dep);
ImmutableSortedSet<BuildRule> deps = ImmutableSortedSet.of(dep);
// Run the enhancer to create the language specific build rule.
ENHANCER_CPP2.createBuildRule(
flavoredParams,
resolver,
arg,
sources,
deps);
}
}