@Test public void ruleKeyChangesIfInputContentsFromPathSourcePathInRuleKeyAppendableChanges() { BuildRuleResolver resolver = new BuildRuleResolver(TargetGraph.EMPTY, new DefaultTargetNodeToBuildRuleTransformer()); SourcePathResolver pathResolver = new SourcePathResolver(resolver); final FakeProjectFilesystem filesystem = new FakeProjectFilesystem(); final Path output = Paths.get("output"); BuildRuleParams params = new FakeBuildRuleParamsBuilder("//:rule").setProjectFilesystem(filesystem).build(); BuildRule rule = new NoopBuildRule(params, pathResolver) { @AddToRuleKey RuleKeyAppendableWithInput input = new RuleKeyAppendableWithInput(new PathSourcePath(filesystem, output)); }; // Build a rule key with a particular hash set for the output for the above rule. FakeFileHashCache hashCache = new FakeFileHashCache(ImmutableMap.of(filesystem.resolve(output), HashCode.fromInt(0))); RuleKey inputKey1 = new InputBasedRuleKeyBuilderFactory(0, hashCache, pathResolver).build(rule); // Now, build a rule key with a different hash for the output for the above rule. hashCache = new FakeFileHashCache(ImmutableMap.of(filesystem.resolve(output), HashCode.fromInt(1))); RuleKey inputKey2 = new InputBasedRuleKeyBuilderFactory(0, hashCache, pathResolver).build(rule); assertThat(inputKey1, Matchers.not(Matchers.equalTo(inputKey2))); }
@Test public void modifyingTheContentsOfTheFileChangesTheRuleKey() throws IOException { Path root = Files.createTempDirectory("root"); FakeProjectFilesystem filesystem = new FakeProjectFilesystem(root.toFile()); Path temp = Paths.get("example_file"); FileHashCache hashCache = new DefaultFileHashCache(filesystem); SourcePathResolver resolver = new SourcePathResolver(new BuildRuleResolver()); RuleKeyBuilderFactory ruleKeyFactory = new DefaultRuleKeyBuilderFactory(hashCache, resolver); filesystem.writeContentsToPath("I like cheese", temp); ExportFileBuilder builder = ExportFileBuilder.newExportFileBuilder(BuildTargetFactory.newInstance("//some:file")) .setSrc(new PathSourcePath(filesystem, temp)); ExportFile rule = (ExportFile) builder.build(new BuildRuleResolver(), filesystem); RuleKey original = ruleKeyFactory.newInstance(rule).build(); filesystem.writeContentsToPath("I really like cheese", temp); // Create a new rule. The FileHashCache held by the existing rule will retain a reference to the // previous content of the file, so we need to create an identical rule. rule = (ExportFile) builder.build(new BuildRuleResolver(), filesystem); hashCache = new DefaultFileHashCache(filesystem); resolver = new SourcePathResolver(new BuildRuleResolver()); ruleKeyFactory = new DefaultRuleKeyBuilderFactory(hashCache, resolver); RuleKey refreshed = ruleKeyFactory.newInstance(rule).build(); assertNotEquals(original, refreshed); }
@Test public void ruleKeyChangesIfInputContentsFromPathSourceChanges() throws Exception { BuildRuleResolver resolver = new BuildRuleResolver(TargetGraph.EMPTY, new DefaultTargetNodeToBuildRuleTransformer()); SourcePathResolver pathResolver = new SourcePathResolver(resolver); FakeProjectFilesystem filesystem = new FakeProjectFilesystem(); Path output = Paths.get("output"); BuildRule rule = ExportFileBuilder.newExportFileBuilder(BuildTargetFactory.newInstance("//:rule")) .setOut("out") .setSrc(new PathSourcePath(filesystem, output)) .build(resolver, filesystem); // Build a rule key with a particular hash set for the output for the above rule. FakeFileHashCache hashCache = new FakeFileHashCache(ImmutableMap.of(filesystem.resolve(output), HashCode.fromInt(0))); RuleKey inputKey1 = new InputBasedRuleKeyBuilderFactory(0, hashCache, pathResolver).build(rule); // Now, build a rule key with a different hash for the output for the above rule. hashCache = new FakeFileHashCache(ImmutableMap.of(filesystem.resolve(output), HashCode.fromInt(1))); RuleKey inputKey2 = new InputBasedRuleKeyBuilderFactory(0, hashCache, pathResolver).build(rule); assertThat(inputKey1, Matchers.not(Matchers.equalTo(inputKey2))); }
@Test public void recursiveVsNonRecursive() throws IOException, InterruptedException { FakeProjectFilesystem filesystem = new FakeProjectFilesystem(); Path buildFile = Paths.get("a", "BUCK"); filesystem.mkdirs(buildFile.getParent()); filesystem.touch(buildFile); Path nestedBuildFile = Paths.get("a", "b", "BUCK"); filesystem.mkdirs(nestedBuildFile.getParent()); filesystem.touch(nestedBuildFile); // Test a non-recursive spec. BuildFileSpec nonRecursiveSpec = BuildFileSpec.fromPath(buildFile.getParent()); ImmutableSet<Path> expectedBuildFiles = ImmutableSet.of(filesystem.resolve(buildFile)); Cell cell = new TestCellBuilder().setFilesystem(filesystem).build(); ImmutableSet<Path> actualBuildFiles = nonRecursiveSpec.findBuildFiles(cell); assertEquals(expectedBuildFiles, actualBuildFiles); // Test a recursive spec. BuildFileSpec recursiveSpec = BuildFileSpec.fromRecursivePath(buildFile.getParent()); expectedBuildFiles = ImmutableSet.of(filesystem.resolve(buildFile), filesystem.resolve(nestedBuildFile)); actualBuildFiles = recursiveSpec.findBuildFiles(cell); assertEquals(expectedBuildFiles, actualBuildFiles); }
@Test public void invalidSourcePathShouldGiveSpecificErrorMsg() throws NoSuchFieldException { Type type = TestFields.class.getField("setOfSourcePaths").getGenericType(); TypeCoercer<?> coercer = typeCoercerFactory.typeCoercerForType(type); Path baratheon = Paths.get("Baratheon.java"); Path lannister = Paths.get("Lannister.java"); Path stark = Paths.get("Stark.java"); Path targaryen = Paths.get("Targaryen.java"); ImmutableList<Path> input = ImmutableList.of(baratheon, lannister, stark, targaryen); for (Path p : input) { if (!p.equals(baratheon)) { filesystem.touch(p); } } try { coercer.coerce(buildRuleResolver, filesystem, Paths.get(""), input); } catch (CoerceFailedException e) { String result = e.getMessage(); String expected = "cannot coerce 'Baratheon.java'"; for (Path p : input) { if (!p.equals(baratheon)) { assertFalse(result.contains(p.toString())); } } assertTrue(result.contains(expected)); } }
@Test public void ruleKeyChangesIfInputContentsFromBuildTargetSourcePathInRuleKeyAppendableChanges() throws Exception { BuildRuleResolver resolver = new BuildRuleResolver(TargetGraph.EMPTY, new DefaultTargetNodeToBuildRuleTransformer()); SourcePathResolver pathResolver = new SourcePathResolver(resolver); final FakeProjectFilesystem filesystem = new FakeProjectFilesystem(); final BuildRule dep = GenruleBuilder.newGenruleBuilder(BuildTargetFactory.newInstance("//:dep")) .setOut("out") .build(resolver, filesystem); BuildRuleParams params = new FakeBuildRuleParamsBuilder("//:rule") .setDeclaredDeps(ImmutableSortedSet.of(dep)) .setProjectFilesystem(filesystem) .build(); BuildRule rule = new NoopBuildRule(params, pathResolver) { @AddToRuleKey RuleKeyAppendableWithInput input = new RuleKeyAppendableWithInput(new BuildTargetSourcePath(dep.getBuildTarget())); }; // Build a rule key with a particular hash set for the output for the above rule. FakeFileHashCache hashCache = new FakeFileHashCache( ImmutableMap.of( filesystem.resolve(Preconditions.checkNotNull(dep.getPathToOutput())), HashCode.fromInt(0))); RuleKey inputKey1 = new InputBasedRuleKeyBuilderFactory(0, hashCache, pathResolver).build(rule); // Now, build a rule key with a different hash for the output for the above rule. hashCache = new FakeFileHashCache( ImmutableMap.of( filesystem.resolve(Preconditions.checkNotNull(dep.getPathToOutput())), HashCode.fromInt(1))); RuleKey inputKey2 = new InputBasedRuleKeyBuilderFactory(0, hashCache, pathResolver).build(rule); assertThat(inputKey1, Matchers.not(Matchers.equalTo(inputKey2))); }
@Test public void xctoolCommandWithAppAndLogicTests() throws Exception { FakeProjectFilesystem projectFilesystem = new FakeProjectFilesystem(); XctoolRunTestsStep step = new XctoolRunTestsStep( projectFilesystem, Paths.get("/path/to/xctool"), Optional.<Long>absent(), "iphonesimulator", Optional.of("name=iPhone 5s,OS=8.2"), ImmutableSet.of(Paths.get("/path/to/FooLogicTest.xctest")), ImmutableMap.of(Paths.get("/path/to/FooAppTest.xctest"), Paths.get("/path/to/Foo.app")), Paths.get("/path/to/output.json"), Optional.<XctoolRunTestsStep.StdoutReadingCallback>absent()); ProcessExecutorParams xctoolParams = ProcessExecutorParams.builder() .setCommand( ImmutableList.of( "/path/to/xctool", "-reporter", "json-stream", "-sdk", "iphonesimulator", "-destination", "name=iPhone 5s,OS=8.2", "run-tests", "-logicTest", "/path/to/FooLogicTest.xctest", "-appTest", "/path/to/FooAppTest.xctest:/path/to/Foo.app")) .setDirectory(projectFilesystem.getRootPath().toAbsolutePath().toFile()) .setRedirectOutput(ProcessBuilder.Redirect.PIPE) .build(); FakeProcess fakeXctoolSuccess = new FakeProcess(0, "", ""); FakeProcessExecutor processExecutor = new FakeProcessExecutor(ImmutableMap.of(xctoolParams, fakeXctoolSuccess)); ExecutionContext executionContext = TestExecutionContext.newBuilder() .setProcessExecutor(processExecutor) .setEnvironment(ImmutableMap.<String, String>of()) .build(); assertThat(step.execute(executionContext), equalTo(0)); }
@Test public void coercePath() throws CoerceFailedException, IOException { String path = "hello.a"; projectFilesystem.touch(Paths.get(path)); SourcePath sourcePath = sourcePathTypeCoercer.coerce(cellRoots, projectFilesystem, pathRelativeToProjectRoot, path); assertEquals(new PathSourcePath(projectFilesystem, Paths.get(path)), sourcePath); }
/** Ensure that build rules with the same inputs but different deps have unique RuleKeys. */ @Test public void testRuleKeyDependsOnDeps() throws Exception { FakeProjectFilesystem filesystem = new FakeProjectFilesystem(); FileHashCache hashCache = new DefaultFileHashCache(filesystem); BuildRuleResolver ruleResolver1 = new BuildRuleResolver(TargetGraph.EMPTY, new BuildTargetNodeToBuildRuleTransformer()); BuildRuleResolver ruleResolver2 = new BuildRuleResolver(TargetGraph.EMPTY, new BuildTargetNodeToBuildRuleTransformer()); RuleKeyBuilderFactory ruleKeyBuilderFactory1 = new DefaultRuleKeyBuilderFactory(hashCache, new SourcePathResolver(ruleResolver1)); RuleKeyBuilderFactory ruleKeyBuilderFactory2 = new DefaultRuleKeyBuilderFactory(hashCache, new SourcePathResolver(ruleResolver2)); // Create a dependent build rule, //src/com/facebook/buck/cli:common. JavaLibraryBuilder builder = JavaLibraryBuilder.createBuilder( BuildTargetFactory.newInstance("//src/com/facebook/buck/cli:common")); BuildRule commonJavaLibrary = builder.build(ruleResolver1); builder.build(ruleResolver2); // Create a java_library() rule with no deps. Path mainSrc = Paths.get("src/com/facebook/buck/cli/Main.java"); filesystem.mkdirs(mainSrc.getParent()); filesystem.writeContentsToPath("hello", mainSrc); JavaLibraryBuilder javaLibraryBuilder = JavaLibraryBuilder.createBuilder( BuildTargetFactory.newInstance("//src/com/facebook/buck/cli:cli")) .addSrc(mainSrc); BuildRule libraryNoCommon = javaLibraryBuilder.build(ruleResolver1, filesystem); // Create the same java_library() rule, but with a dep on //src/com/facebook/buck/cli:common. javaLibraryBuilder.addDep(commonJavaLibrary.getBuildTarget()); BuildRule libraryWithCommon = javaLibraryBuilder.build(ruleResolver2, filesystem); // Assert that the RuleKeys are distinct. RuleKey r1 = ruleKeyBuilderFactory1.build(libraryNoCommon); RuleKey r2 = ruleKeyBuilderFactory2.build(libraryWithCommon); assertThat( "Rule keys should be distinct because the deps of the rules are different.", r1, not(equalTo(r2))); }
@Test public void coercingAbsolutePathThrows() throws CoerceFailedException, IOException { Path path = MorePathsForTests.rootRelativePath("hello.a"); projectFilesystem.touch(path); exception.expect(CoerceFailedException.class); exception.expectMessage("SourcePath cannot contain an absolute path"); sourcePathTypeCoercer.coerce( cellRoots, projectFilesystem, pathRelativeToProjectRoot, path.toString()); }
@Test public void shouldRewriteLineMarkers() { BuildRuleResolver ruleResolver = new BuildRuleResolver(TargetGraph.EMPTY, new DefaultTargetNodeToBuildRuleTransformer()); SourcePathResolver pathResolver = new SourcePathResolver(ruleResolver); Path original = Paths.get("buck-out/foo#bar/world.h"); Path finalPath = Paths.get("SANITIZED/world.h"); HeaderPathNormalizer.Builder normalizerBuilder = new HeaderPathNormalizer.Builder(pathResolver, Functions.<Path>identity()); normalizerBuilder.addHeader(new FakeSourcePath("hello/////world.h"), original); HeaderPathNormalizer normalizer = normalizerBuilder.build(); DebugPathSanitizer sanitizer = new DebugPathSanitizer( 9, File.separatorChar, Paths.get("PWD"), ImmutableBiMap.of(Paths.get("hello"), Paths.get("SANITIZED"))); FakeProjectFilesystem fakeProjectFilesystem = new FakeProjectFilesystem(); CxxPreprocessorOutputTransformerFactory transformer = new CxxPreprocessorOutputTransformerFactory( fakeProjectFilesystem.getRootPath(), normalizer, sanitizer); // Fixup line marker lines properly. assertThat( String.format("# 12 \"%s\"", Escaper.escapePathForCIncludeString(finalPath)), equalTo(transformer.transformLine(String.format("# 12 \"%s\"", original)))); assertThat( String.format("# 12 \"%s\" 2 1", Escaper.escapePathForCIncludeString(finalPath)), equalTo(transformer.transformLine(String.format("# 12 \"%s\" 2 1", original)))); // test.h isn't in the replacement map, so shouldn't be replaced. assertThat("# 4 \"test.h\"", equalTo(transformer.transformLine("# 4 \"test.h\""))); // Don't modify non-line-marker lines. assertThat("int main() {", equalTo(transformer.transformLine("int main() {"))); }
@Test public void usesFirstCache() throws IOException { ProjectFilesystem filesystem = FakeProjectFilesystem.createJavaOnlyFilesystem(); Path path = Paths.get("world.txt"); filesystem.touch(path); Path fullPath = filesystem.resolve(path); DefaultFileHashCache innerCache = new DefaultFileHashCache(filesystem); StackedFileHashCache cache = new StackedFileHashCache(ImmutableList.of(innerCache)); cache.get(fullPath); assertTrue(innerCache.willGet(path)); }
@Test public void coerceRelativeBuildTarget() throws CoerceFailedException, IOException { SourcePath sourcePath = sourcePathTypeCoercer.coerce( cellRoots, projectFilesystem, pathRelativeToProjectRoot, ":hello"); assertEquals( new BuildTargetSourcePath( BuildTarget.of( UnflavoredBuildTarget.of( projectFilesystem.getRootPath(), Optional.<String>absent(), "//", "hello"), ImmutableSortedSet.<Flavor>of())), sourcePath); }
@Test public void shouldSetSrcAndOutToNameParameterIfNeitherAreSet() throws IOException { ProjectFilesystem projectFilesystem = FakeProjectFilesystem.createJavaOnlyFilesystem(); ExportFile exportFile = (ExportFile) ExportFileBuilder.newExportFileBuilder(target) .build(new BuildRuleResolver(), projectFilesystem); List<Step> steps = exportFile.getBuildSteps(context, new FakeBuildableContext()); MoreAsserts.assertSteps( "The output directory should be created and then the file should be copied there.", ImmutableList.of( "mkdir -p /opt/src/buck/buck-out/gen", "cp " + projectFilesystem.resolve("example.html") + " buck-out/gen/example.html"), steps, TestExecutionContext.newInstance()); assertEquals(Paths.get("buck-out/gen/example.html"), exportFile.getPathToOutput()); }
@Test public void createBuildRuleWithFlavoredTargetCallsEnhancerCorrectly() throws IOException { BuildRuleResolver resolver = new BuildRuleResolver(); SourcePathResolver pathResolver = new SourcePathResolver(resolver); FakeProjectFilesystem filesystem = new FakeProjectFilesystem(); // Setup the default values returned by the language specific enhancer. String language = "fake"; Flavor flavor = ImmutableFlavor.of("fake"); final BuildRule implicitDep = createFakeBuildRule("//implicit:dep", pathResolver); resolver.addToIndex(implicitDep); filesystem.mkdirs(implicitDep.getBuildTarget().getBasePath()); filesystem.touch(implicitDep.getBuildTarget().getBasePath().resolve("BUCK")); ImmutableSet<BuildTarget> implicitDeps = ImmutableSet.of(implicitDep.getBuildTarget()); ImmutableSet<String> options = ImmutableSet.of(); // Create the build targets and params. BuildTarget unflavoredTarget = BuildTargetFactory.newInstance("//:thrift"); BuildRuleParams unflavoredParams = new FakeBuildRuleParamsBuilder(unflavoredTarget).setProjectFilesystem(filesystem).build(); BuildTarget flavoredTarget = BuildTargets.createFlavoredBuildTarget(unflavoredTarget.checkUnflavored(), flavor); BuildRuleParams flavoredParams = new FakeBuildRuleParamsBuilder(flavoredTarget).setProjectFilesystem(filesystem).build(); // Setup a thrift source file generated by a genrule. final String thriftSourceName1 = "foo.thrift"; BuildTarget genruleTarget = BuildTargetFactory.newInstance("//:genrule"); final Genrule genrule = (Genrule) GenruleBuilder.newGenruleBuilder(genruleTarget) .setOut(thriftSourceName1) .build(resolver); SourcePath thriftSource1 = new BuildTargetSourcePath(genrule.getBuildTarget()); final ImmutableList<String> thriftServices1 = ImmutableList.of(); // Setup a normal thrift source file. final String thriftSourceName2 = "bar.thrift"; SourcePath thriftSource2 = new TestSourcePath(thriftSourceName2); final ImmutableList<String> thriftServices2 = ImmutableList.of(); // Create a build rule that represents the thrift rule. final FakeBuildRule thriftRule = createFakeBuildRule("//thrift:target", pathResolver); resolver.addToIndex(thriftRule); filesystem.mkdirs(thriftRule.getBuildTarget().getBasePath()); filesystem.touch(thriftRule.getBuildTarget().getBasePath().resolve("BUCK")); // Setup a simple description with an empty config. FakeBuckConfig buckConfig = new FakeBuckConfig( ImmutableMap.of( "thrift", ImmutableMap.of("compiler", thriftRule.getBuildTarget().toString()))); ThriftBuckConfig thriftBuckConfig = new ThriftBuckConfig(buckConfig); ThriftLibraryDescription desc = new ThriftLibraryDescription( thriftBuckConfig, ImmutableList.<ThriftLanguageSpecificEnhancer>of()); // Setup the include rules. final BuildRule thriftIncludeSymlinkTree = createFakeBuildRule( desc.createThriftIncludeSymlinkTreeTarget(unflavoredTarget), pathResolver); // Setup our language enhancer FakeThriftLanguageSpecificEnhancer enhancer = new FakeThriftLanguageSpecificEnhancer(language, flavor, implicitDeps, options) { @Override public void checkCreateBuildRuleInputs( ImmutableMap<String, ThriftSource> sources, ImmutableSortedSet<BuildRule> deps) { // Verify both thrift sources are present in the list. assertEquals(2, sources.size()); ThriftSource src1 = sources.get(thriftSourceName1); assertNotNull(src1); ThriftSource src2 = sources.get(thriftSourceName2); assertNotNull(src2); // Verify the services are listed correctly for both sources. assertEquals(thriftServices1, src1.getServices()); assertEquals(thriftServices2, src2.getServices()); // Verify dependencies are setup correctly. assertEquals( ImmutableSortedSet.of(genrule, thriftRule, thriftIncludeSymlinkTree), src1.getCompileRule().getDeps()); assertEquals( ImmutableSortedSet.of(genrule, thriftRule, thriftIncludeSymlinkTree), src2.getCompileRule().getDeps()); // Verify the language specific implicit rules are added correctly. assertEquals( ImmutableSortedSet.<BuildRule>naturalOrder().add(implicitDep).build(), deps); } }; // Recreate the description with the enhancer we setup above. desc = new ThriftLibraryDescription( thriftBuckConfig, ImmutableList.<ThriftLanguageSpecificEnhancer>of(enhancer)); // Setup the internal structure indicating that the thrift target was set in the // buck config. // desc.setCompilerTarget(thriftRule.getBuildTarget()); // Setup the implicit deps for the flavored build target. // desc.setImplicitDeps(flavoredTarget, ImmutableList.of(implicitDep.getBuildTarget())); // Build up the constructor arg. ThriftConstructorArg arg = desc.createUnpopulatedConstructorArg(); arg.name = "thrift"; arg.srcs = ImmutableMap.of( thriftSource1, thriftServices1, thriftSource2, thriftServices2); arg.deps = Optional.absent(); arg.flags = Optional.absent(); // Setup the unflavored target, which should just produce a ThriftInclude, SymlinkTree, and // ThriftLibrary rule. BuildRule rule = desc.createBuildRule(TargetGraph.EMPTY, unflavoredParams, resolver, arg); resolver.addToIndex(rule); // Now attempt to create the flavored thrift library. desc.createBuildRule(TargetGraph.EMPTY, flavoredParams, resolver, arg); }
@Test public void createThriftCompilerBuildRulesHasCorrectDeps() throws IOException { BuildRuleResolver resolver = new BuildRuleResolver(); SourcePathResolver pathResolver = new SourcePathResolver(resolver); FakeProjectFilesystem filesystem = new FakeProjectFilesystem(); String language = "fake"; Flavor flavor = ImmutableFlavor.of("fake"); ImmutableSet<String> options = ImmutableSet.of(); // Setup the default values returned by the language specific enhancer. BuildTarget unflavoredTarget = BuildTargetFactory.newInstance("//:thrift"); BuildRuleParams unflavoredParams = new FakeBuildRuleParamsBuilder(BuildTarget.builder(unflavoredTarget).build()) .setProjectFilesystem(filesystem) .build(); // Setup a thrift source file generated by a genrule. BuildTarget flavoredTarget = BuildTargets.createFlavoredBuildTarget(unflavoredTarget.checkUnflavored(), flavor); BuildRuleParams flavoredParams = new FakeBuildRuleParamsBuilder(flavoredTarget).setProjectFilesystem(filesystem).build(); // Create a path for the thrift compiler. Path thriftPath = Paths.get("thrift_path"); filesystem.touch(thriftPath); // Setup an thrift buck config, with the path to the thrift compiler set. FakeBuckConfig buckConfig = new FakeBuckConfig( ImmutableMap.of("thrift", ImmutableMap.of("compiler", thriftPath.toString())), filesystem); ThriftBuckConfig thriftBuckConfig = new ThriftBuckConfig(buckConfig); ThriftLibraryDescription desc = new ThriftLibraryDescription( thriftBuckConfig, ImmutableList.<ThriftLanguageSpecificEnhancer>of()); // Setup a simple thrift source. String sourceName = "test.thrift"; SourcePath sourcePath = new TestSourcePath(sourceName); // Generate these rules using no deps. ImmutableMap<String, ThriftCompiler> rules = desc.createThriftCompilerBuildRules( flavoredParams, resolver, ThriftLibraryDescription.CompilerType.THRIFT, ImmutableList.<String>of(), language, options, ImmutableMap.of(sourceName, sourcePath), ImmutableSortedSet.<ThriftLibrary>of()); // Now verify that the generated rule had no associated deps. assertSame(rules.size(), 1); ThriftCompiler rule = rules.get(sourceName); assertNotNull(rule); assertEquals(ImmutableSortedSet.<BuildRule>of(), rule.getDeps()); // Lets do this again, but pass in a ThriftLibrary deps, wrapping some includes we need. Path includeRoot = desc.getIncludeRoot(unflavoredTarget); HeaderSymlinkTree thriftIncludeSymlinkTree = createFakeSymlinkTree( desc.createThriftIncludeSymlinkTreeTarget(unflavoredTarget), pathResolver, includeRoot); ThriftLibrary lib = new ThriftLibrary( unflavoredParams, pathResolver, ImmutableSortedSet.<ThriftLibrary>of(), thriftIncludeSymlinkTree, ImmutableMap.<Path, SourcePath>of()); // Generate these rules using no deps. rules = desc.createThriftCompilerBuildRules( flavoredParams, resolver, ThriftLibraryDescription.CompilerType.THRIFT, ImmutableList.<String>of(), language, options, ImmutableMap.of(sourceName, sourcePath), ImmutableSortedSet.of(lib)); // Now verify that the generated rule has all the deps from the passed in thrift library. assertSame(rules.size(), 1); rule = rules.get(sourceName); assertNotNull(rule); assertEquals(ImmutableSortedSet.<BuildRule>of(thriftIncludeSymlinkTree), rule.getDeps()); // Setup a simple genrule that creates the thrift source and verify its dep is propagated. Genrule genrule = (Genrule) GenruleBuilder.newGenruleBuilder(BuildTargetFactory.newInstance("//:genrule")) .setOut(sourceName) .build(resolver); SourcePath ruleSourcePath = new BuildTargetSourcePath(genrule.getBuildTarget()); // Generate these rules using no deps and the genrule generated source. rules = desc.createThriftCompilerBuildRules( flavoredParams, resolver, ThriftLibraryDescription.CompilerType.THRIFT, ImmutableList.<String>of(), language, options, ImmutableMap.of(sourceName, ruleSourcePath), ImmutableSortedSet.<ThriftLibrary>of()); // Now verify that the generated rule had no associated deps. assertSame(rules.size(), 1); rule = rules.get(sourceName); assertNotNull(rule); assertEquals(ImmutableSortedSet.<BuildRule>of(genrule), rule.getDeps()); // Create a build rule that represents the thrift rule. FakeBuildRule thriftRule = createFakeBuildRule("//thrift:target", pathResolver); resolver.addToIndex(thriftRule); filesystem.mkdirs(thriftRule.getBuildTarget().getBasePath()); filesystem.touch(thriftRule.getBuildTarget().getBasePath().resolve("BUCK")); // Setup an empty thrift buck config, and set compiler target. buckConfig = new FakeBuckConfig( ImmutableMap.of( "thrift", ImmutableMap.of("compiler", thriftRule.getBuildTarget().toString())), filesystem); thriftBuckConfig = new ThriftBuckConfig(buckConfig); desc = new ThriftLibraryDescription( thriftBuckConfig, ImmutableList.<ThriftLanguageSpecificEnhancer>of()); // Generate these rules using no deps with a compiler target. rules = desc.createThriftCompilerBuildRules( flavoredParams, resolver, ThriftLibraryDescription.CompilerType.THRIFT, ImmutableList.<String>of(), language, options, ImmutableMap.of(sourceName, sourcePath), ImmutableSortedSet.<ThriftLibrary>of()); // Now verify that the generated rule only has deps from the compiler target. assertSame(rules.size(), 1); rule = rules.get(sourceName); assertNotNull(rule); assertEquals(ImmutableSortedSet.<BuildRule>of(thriftRule), rule.getDeps()); }
@Test public void createLexYaccBuildRules() throws IOException { BuildRuleResolver resolver = new BuildRuleResolver(); // Setup our C++ buck config with the paths to the lex/yacc binaries. FakeProjectFilesystem filesystem = new FakeProjectFilesystem(); Path lexPath = Paths.get("lex"); filesystem.touch(lexPath); Path yaccPath = Paths.get("yacc"); filesystem.touch(yaccPath); BuckConfig buckConfig = FakeBuckConfig.builder() .setSections( ImmutableMap.of( "cxx", ImmutableMap.of( "lex", lexPath.toString(), "yacc", yaccPath.toString()))) .setFilesystem(filesystem) .build(); CxxPlatform cxxBuckConfig = DefaultCxxPlatforms.build(new CxxBuckConfig(buckConfig)); // Setup the target name and build params. UnflavoredBuildTarget target = BuildTargetFactory.newInstance("//:test").getUnflavoredBuildTarget(); BuildRuleParams params = new FakeBuildRuleParamsBuilder(BuildTarget.of(target)).build(); // Setup a genrule that generates our lex source. String lexSourceName = "test.ll"; BuildTarget genruleTarget = BuildTargetFactory.newInstance("//:genrule_lex"); Genrule genrule = (Genrule) GenruleBuilder.newGenruleBuilder(genruleTarget).setOut(lexSourceName).build(resolver); SourcePath lexSource = new BuildTargetSourcePath(genrule.getBuildTarget()); // Use a regular path for our yacc source. String yaccSourceName = "test.yy"; SourcePath yaccSource = new TestSourcePath(yaccSourceName); // Build the rules. CxxHeaderSourceSpec actual = CxxDescriptionEnhancer.createLexYaccBuildRules( params, resolver, cxxBuckConfig, ImmutableList.<String>of(), ImmutableMap.of(lexSourceName, lexSource), ImmutableList.<String>of(), ImmutableMap.of(yaccSourceName, yaccSource)); // Grab the generated lex rule and verify it has the genrule as a dep. Lex lex = (Lex) resolver.getRule(CxxDescriptionEnhancer.createLexBuildTarget(target, lexSourceName)); assertNotNull(lex); assertEquals(ImmutableSortedSet.<BuildRule>of(genrule), lex.getDeps()); // Grab the generated yacc rule and verify it has no deps. Yacc yacc = (Yacc) resolver.getRule(CxxDescriptionEnhancer.createYaccBuildTarget(target, yaccSourceName)); assertNotNull(yacc); assertEquals(ImmutableSortedSet.<BuildRule>of(), yacc.getDeps()); // Check the header/source spec is correct. Path lexOutputSource = CxxDescriptionEnhancer.getLexSourceOutputPath(target, lexSourceName); Path lexOutputHeader = CxxDescriptionEnhancer.getLexHeaderOutputPath(target, lexSourceName); Path yaccOutputPrefix = CxxDescriptionEnhancer.getYaccOutputPrefix( target, Files.getNameWithoutExtension(yaccSourceName)); Path yaccOutputSource = Yacc.getSourceOutputPath(yaccOutputPrefix); Path yaccOutputHeader = Yacc.getHeaderOutputPath(yaccOutputPrefix); CxxHeaderSourceSpec expected = CxxHeaderSourceSpec.of( ImmutableMap.<Path, SourcePath>of( target.getBasePath().resolve(lexSourceName + ".h"), new BuildTargetSourcePath(lex.getBuildTarget(), lexOutputHeader), target.getBasePath().resolve(yaccSourceName + ".h"), new BuildTargetSourcePath(yacc.getBuildTarget(), yaccOutputHeader)), ImmutableMap.of( lexSourceName + ".cc", CxxSource.of( CxxSource.Type.CXX, new BuildTargetSourcePath(lex.getBuildTarget(), lexOutputSource), ImmutableList.<String>of()), yaccSourceName + ".cc", CxxSource.of( CxxSource.Type.CXX, new BuildTargetSourcePath(yacc.getBuildTarget(), yaccOutputSource), ImmutableList.<String>of()))); assertEquals(expected, actual); }
@Test public void testGetBuildStepsWhenThereAreClassesToDex() throws IOException, InterruptedException { SourcePathResolver pathResolver = new SourcePathResolver(new BuildRuleResolver()); FakeJavaLibrary javaLibraryRule = new FakeJavaLibrary(BuildTargetFactory.newInstance("//foo:bar"), pathResolver) { @Override public ImmutableSortedMap<String, HashCode> getClassNamesToHashes() { return ImmutableSortedMap.of("com/example/Foo", HashCode.fromString("cafebabe")); } @Override public Sha1HashCode getAbiKey() { return Sha1HashCode.of("f7f34ed13b881c6c6f663533cde4a436ea84435e"); } }; javaLibraryRule.setOutputFile("buck-out/gen/foo/bar.jar"); BuildContext context = createMock(BuildContext.class); FakeBuildableContext buildableContext = new FakeBuildableContext(); replayAll(); ProjectFilesystem filesystem = FakeProjectFilesystem.createJavaOnlyFilesystem("/home/user"); createFiles(filesystem, "buck-out/gen/foo/bar#dex.dex.jar", "buck-out/gen/foo/bar.jar"); BuildTarget buildTarget = BuildTargetFactory.newInstance("//foo:bar#dex"); BuildRuleParams params = new FakeBuildRuleParamsBuilder(buildTarget).setProjectFilesystem(filesystem).build(); DexProducedFromJavaLibrary preDex = new DexProducedFromJavaLibrary(params, pathResolver, javaLibraryRule); List<Step> steps = preDex.getBuildSteps(context, buildableContext); verifyAll(); resetAll(); AndroidPlatformTarget androidPlatformTarget = createMock(AndroidPlatformTarget.class); expect(androidPlatformTarget.getDxExecutable()).andReturn(Paths.get("/usr/bin/dx")); replayAll(); ExecutionContext executionContext = TestExecutionContext.newBuilder() .setAndroidPlatformTargetSupplier(Suppliers.ofInstance(androidPlatformTarget)) .build(); String expectedDxCommand = String.format( "%s --dex --no-optimize --force-jumbo --output %s %s", Paths.get("/usr/bin/dx"), Paths.get("/home/user/buck-out/gen/foo/bar#dex.dex.jar"), Paths.get("/home/user/buck-out/gen/foo/bar.jar")); MoreAsserts.assertSteps( "Generate bar.dex.jar.", ImmutableList.of( String.format("rm -f %s", Paths.get("/home/user/buck-out/gen/foo/bar#dex.dex.jar")), String.format("mkdir -p %s", Paths.get("/home/user/buck-out/gen/foo")), "estimate_linear_alloc", "(cd /home/user && " + expectedDxCommand + ")", "zip-scrub buck-out/gen/foo/bar#dex.dex.jar", "record_dx_success"), steps, executionContext); verifyAll(); resetAll(); replayAll(); ((EstimateLinearAllocStep) steps.get(2)).setLinearAllocEstimateForTesting(250); Step recordArtifactAndMetadataStep = steps.get(5); int exitCode = recordArtifactAndMetadataStep.execute(executionContext); assertEquals(0, exitCode); assertEquals( "The generated .dex.jar file should be in the set of recorded artifacts.", ImmutableSet.of(Paths.get("buck-out/gen/foo/bar#dex.dex.jar")), buildableContext.getRecordedArtifacts()); buildableContext.assertContainsMetadataMapping( DexProducedFromJavaLibrary.LINEAR_ALLOC_KEY_ON_DISK_METADATA, "250"); verifyAll(); }