/* * 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.cxx; import static com.facebook.buck.util.environment.Platform.WINDOWS; import static org.hamcrest.CoreMatchers.not; import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; import static org.junit.Assume.assumeThat; import com.facebook.buck.cli.FakeBuckConfig; import com.facebook.buck.io.ProjectFilesystem; import com.facebook.buck.model.BuildTarget; import com.facebook.buck.model.UnflavoredBuildTarget; import com.facebook.buck.rules.BuildRuleParams; import com.facebook.buck.rules.BuildRuleResolver; import com.facebook.buck.rules.CommandTool; import com.facebook.buck.rules.DefaultTargetNodeToBuildRuleTransformer; import com.facebook.buck.rules.FakeBuildRuleParamsBuilder; import com.facebook.buck.rules.FakeSourcePath; import com.facebook.buck.rules.PathSourcePath; import com.facebook.buck.rules.RuleKeyObjectSink; import com.facebook.buck.rules.SourcePath; import com.facebook.buck.rules.SourcePathResolver; import com.facebook.buck.rules.SourcePathRuleFinder; import com.facebook.buck.rules.TargetGraph; import com.facebook.buck.rules.Tool; import com.facebook.buck.rules.args.RuleKeyAppendableFunction; import com.facebook.buck.rules.coercer.FrameworkPath; import com.facebook.buck.step.ExecutionContext; import com.facebook.buck.step.StepExecutionResult; import com.facebook.buck.step.TestExecutionContext; import com.facebook.buck.testutil.FakeProjectFilesystem; import com.facebook.buck.util.environment.Platform; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableSet; import java.io.IOException; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Optional; import org.junit.Test; public class CxxCollectAndLogInferDependenciesStepTest { private static ProjectFilesystem createFakeFilesystem(String fakeRoot) { final Path fakeRootPath = Paths.get(fakeRoot); Preconditions.checkArgument(fakeRootPath.isAbsolute(), "fakeRoot must be an absolute path"); return new FakeProjectFilesystem(fakeRootPath); } private CxxInferCapture createCaptureRule( BuildRuleParams buildRuleParams, SourcePathResolver sourcePathResolver, ProjectFilesystem filesystem, InferBuckConfig inferBuckConfig) throws Exception { RuleKeyAppendableFunction<FrameworkPath, Path> defaultFrameworkPathSearchPathFunction = new RuleKeyAppendableFunction<FrameworkPath, Path>() { @Override public void appendToRuleKey(RuleKeyObjectSink sink) { // Do nothing. } @Override public Path apply(FrameworkPath input) { return Paths.get("test", "framework", "path", input.toString()); } }; SourcePath preprocessor = new PathSourcePath(filesystem, Paths.get("preprocessor")); Tool preprocessorTool = new CommandTool.Builder().addInput(preprocessor).build(); PreprocessorDelegate preprocessorDelegate = new PreprocessorDelegate( sourcePathResolver, CxxPlatformUtils.DEFAULT_COMPILER_DEBUG_PATH_SANITIZER, CxxPlatformUtils.DEFAULT_PLATFORM.getHeaderVerification(), Paths.get("whatever"), new GccPreprocessor(preprocessorTool), PreprocessorFlags.builder().build(), defaultFrameworkPathSearchPathFunction, Optional.empty(), /* leadingIncludePaths */ Optional.empty()); return new CxxInferCapture( buildRuleParams, CxxToolFlags.of(), CxxToolFlags.of(), new FakeSourcePath("src.c"), AbstractCxxSource.Type.C, Paths.get("src.o"), preprocessorDelegate, inferBuckConfig, CxxPlatformUtils.DEFAULT_COMPILER_DEBUG_PATH_SANITIZER); } @Test public void testStepWritesNoCellTokenInFileWhenCellIsAbsent() throws IOException, InterruptedException { assumeThat(Platform.detect(), is(not(WINDOWS))); ProjectFilesystem filesystem = createFakeFilesystem("/Users/user/src"); BuildTarget testBuildTarget = BuildTarget.builder() .setUnflavoredBuildTarget( UnflavoredBuildTarget.of( filesystem.getRootPath(), Optional.empty(), "//target", "short")) .addFlavors(CxxInferEnhancer.InferFlavors.INFER.get()) .build(); BuildRuleParams testBuildRuleParams = new FakeBuildRuleParamsBuilder(testBuildTarget).setProjectFilesystem(filesystem).build(); InferBuckConfig inferBuckConfig = new InferBuckConfig(FakeBuckConfig.builder().build()); CxxInferCaptureAndAggregatingRules<CxxInferAnalyze> captureAndAggregatingRules = new CxxInferCaptureAndAggregatingRules<>( ImmutableSet.of(), ImmutableSet.<CxxInferAnalyze>of()); CxxInferAnalyze analyzeRule = new CxxInferAnalyze(testBuildRuleParams, inferBuckConfig, captureAndAggregatingRules); Path outputFile = Paths.get("infer-deps.txt"); CxxCollectAndLogInferDependenciesStep step = CxxCollectAndLogInferDependenciesStep.fromAnalyzeRule(analyzeRule, filesystem, outputFile); ExecutionContext executionContext = TestExecutionContext.newInstance(); int exitCode = step.execute(executionContext).getExitCode(); assertThat(exitCode, is(StepExecutionResult.SUCCESS.getExitCode())); String expectedOutput = InferLogLine.fromBuildTarget(testBuildTarget, analyzeRule.getAbsolutePathToResultsDir()) .toString(); assertEquals(expectedOutput + "\n", filesystem.readFileIfItExists(outputFile).get()); } @Test public void testStepWritesSingleCellTokenInFile() throws IOException, InterruptedException { assumeThat(Platform.detect(), is(not(WINDOWS))); ProjectFilesystem filesystem = createFakeFilesystem("/Users/user/src"); String cellName = "cellname"; BuildTarget testBuildTarget = BuildTarget.builder() .setUnflavoredBuildTarget( UnflavoredBuildTarget.of( filesystem.getRootPath(), Optional.of(cellName), "//target", "short")) .addFlavors(CxxInferEnhancer.InferFlavors.INFER.get()) .build(); BuildRuleParams testBuildRuleParams = new FakeBuildRuleParamsBuilder(testBuildTarget).setProjectFilesystem(filesystem).build(); InferBuckConfig inferBuckConfig = new InferBuckConfig(FakeBuckConfig.builder().build()); CxxInferCaptureAndAggregatingRules<CxxInferAnalyze> captureAndAggregatingRules = new CxxInferCaptureAndAggregatingRules<>( ImmutableSet.of(), ImmutableSet.<CxxInferAnalyze>of()); CxxInferAnalyze analyzeRule = new CxxInferAnalyze(testBuildRuleParams, inferBuckConfig, captureAndAggregatingRules); Path outputFile = Paths.get("infer-deps.txt"); CxxCollectAndLogInferDependenciesStep step = CxxCollectAndLogInferDependenciesStep.fromAnalyzeRule(analyzeRule, filesystem, outputFile); ExecutionContext executionContext = TestExecutionContext.newInstance(); int exitCode = step.execute(executionContext).getExitCode(); assertThat(exitCode, is(StepExecutionResult.SUCCESS.getExitCode())); String expectedOutput = InferLogLine.fromBuildTarget(testBuildTarget, analyzeRule.getAbsolutePathToResultsDir()) .toString(); assertEquals(expectedOutput + "\n", filesystem.readFileIfItExists(outputFile).get()); } @Test public void testStepWritesTwoCellTokensInFile() throws Exception { assumeThat(Platform.detect(), is(not(WINDOWS))); // filesystem, buildTarget and buildRuleParams for first cell (analysis) ProjectFilesystem filesystem1 = createFakeFilesystem("/Users/user/cell_one"); BuildTarget buildTarget1 = BuildTarget.builder() .setUnflavoredBuildTarget( UnflavoredBuildTarget.of( filesystem1.getRootPath(), Optional.of("cell1"), "//target/in_cell_one", "short1")) .addFlavors(CxxInferEnhancer.InferFlavors.INFER.get()) .build(); BuildRuleParams buildRuleParams1 = new FakeBuildRuleParamsBuilder(buildTarget1).setProjectFilesystem(filesystem1).build(); // filesystem, buildTarget and buildRuleParams for second cell (capture) ProjectFilesystem filesystem2 = createFakeFilesystem("/Users/user/cell_two"); BuildTarget buildTarget2 = BuildTarget.builder() .setUnflavoredBuildTarget( UnflavoredBuildTarget.of( filesystem2.getRootPath(), Optional.of("cell2"), "//target/in_cell_two", "short2")) .addFlavors(CxxInferEnhancer.InferFlavors.INFER_CAPTURE.get()) .build(); BuildRuleParams buildRuleParams2 = new FakeBuildRuleParamsBuilder(buildTarget2).setProjectFilesystem(filesystem2).build(); BuildRuleResolver testBuildRuleResolver = new BuildRuleResolver(TargetGraph.EMPTY, new DefaultTargetNodeToBuildRuleTransformer()); SourcePathResolver testSourcePathResolver = new SourcePathResolver(new SourcePathRuleFinder(testBuildRuleResolver)); InferBuckConfig inferBuckConfig = new InferBuckConfig(FakeBuckConfig.builder().build()); CxxInferCapture captureRule = createCaptureRule(buildRuleParams2, testSourcePathResolver, filesystem2, inferBuckConfig); CxxInferCaptureAndAggregatingRules<CxxInferAnalyze> captureAndAggregatingRules = new CxxInferCaptureAndAggregatingRules<>( ImmutableSet.of(captureRule), ImmutableSet.<CxxInferAnalyze>of()); CxxInferAnalyze analyzeRule = new CxxInferAnalyze(buildRuleParams1, inferBuckConfig, captureAndAggregatingRules); Path outputFile = Paths.get("infer-deps.txt"); CxxCollectAndLogInferDependenciesStep step = CxxCollectAndLogInferDependenciesStep.fromAnalyzeRule(analyzeRule, filesystem1, outputFile); ExecutionContext executionContext = TestExecutionContext.newInstance(); int exitCode = step.execute(executionContext).getExitCode(); assertThat(exitCode, is(StepExecutionResult.SUCCESS.getExitCode())); String expectedOutput = InferLogLine.fromBuildTarget(buildTarget1, analyzeRule.getAbsolutePathToResultsDir()) .toString() + "\n" + InferLogLine.fromBuildTarget(buildTarget2, captureRule.getAbsolutePathToOutput()) .toString(); assertEquals(expectedOutput + "\n", filesystem1.readFileIfItExists(outputFile).get()); } @Test public void testStepWritesOneCellTokenInFileWhenOneCellIsAbsent() throws Exception { assumeThat(Platform.detect(), is(not(WINDOWS))); // filesystem, buildTarget and buildRuleParams for first, unnamed cell (analysis) ProjectFilesystem filesystem1 = createFakeFilesystem("/Users/user/default_cell"); BuildTarget buildTarget1 = BuildTarget.builder() .setUnflavoredBuildTarget( UnflavoredBuildTarget.of( filesystem1.getRootPath(), Optional.empty(), "//target/in_default_cell", "short")) .addFlavors(CxxInferEnhancer.InferFlavors.INFER.get()) .build(); BuildRuleParams buildRuleParams1 = new FakeBuildRuleParamsBuilder(buildTarget1).setProjectFilesystem(filesystem1).build(); // filesystem, buildTarget and buildRuleParams for second cell (capture) ProjectFilesystem filesystem2 = createFakeFilesystem("/Users/user/cell_two"); BuildTarget buildTarget2 = BuildTarget.builder() .setUnflavoredBuildTarget( UnflavoredBuildTarget.of( filesystem2.getRootPath(), Optional.of("cell2"), "//target/in_cell_two", "short2")) .addFlavors(CxxInferEnhancer.InferFlavors.INFER_CAPTURE.get()) .build(); BuildRuleParams buildRuleParams2 = new FakeBuildRuleParamsBuilder(buildTarget2).setProjectFilesystem(filesystem2).build(); BuildRuleResolver testBuildRuleResolver = new BuildRuleResolver(TargetGraph.EMPTY, new DefaultTargetNodeToBuildRuleTransformer()); SourcePathResolver testSourcePathResolver = new SourcePathResolver(new SourcePathRuleFinder(testBuildRuleResolver)); InferBuckConfig inferBuckConfig = new InferBuckConfig(FakeBuckConfig.builder().build()); CxxInferCapture captureRule = createCaptureRule(buildRuleParams2, testSourcePathResolver, filesystem2, inferBuckConfig); CxxInferCaptureAndAggregatingRules<CxxInferAnalyze> captureAndAggregatingRules = new CxxInferCaptureAndAggregatingRules<>( ImmutableSet.of(captureRule), ImmutableSet.<CxxInferAnalyze>of()); CxxInferAnalyze analyzeRule = new CxxInferAnalyze(buildRuleParams1, inferBuckConfig, captureAndAggregatingRules); Path outputFile = Paths.get("infer-deps.txt"); CxxCollectAndLogInferDependenciesStep step = CxxCollectAndLogInferDependenciesStep.fromAnalyzeRule(analyzeRule, filesystem1, outputFile); ExecutionContext executionContext = TestExecutionContext.newInstance(); int exitCode = step.execute(executionContext).getExitCode(); assertThat(exitCode, is(StepExecutionResult.SUCCESS.getExitCode())); String expectedOutput = InferLogLine.fromBuildTarget(buildTarget1, analyzeRule.getAbsolutePathToResultsDir()) .toString() + "\n" + InferLogLine.fromBuildTarget(buildTarget2, captureRule.getAbsolutePathToOutput()) .toString(); assertEquals(expectedOutput + "\n", filesystem1.readFileIfItExists(outputFile).get()); } }