/* * Copyright 2013-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.android; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import com.facebook.buck.io.ProjectFilesystem; 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.DefaultBuildTargetSourcePath; import com.facebook.buck.rules.DefaultTargetNodeToBuildRuleTransformer; import com.facebook.buck.rules.FakeSourcePath; import com.facebook.buck.rules.PathSourcePath; 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.TargetNode; import com.facebook.buck.shell.GenruleBuilder; import com.facebook.buck.testutil.FakeProjectFilesystem; import com.facebook.buck.testutil.TargetGraphFactory; import com.facebook.buck.testutil.integration.TemporaryPaths; import com.facebook.buck.util.MoreCollectors; import com.google.common.collect.ImmutableList; import java.io.File; import java.nio.file.Path; import java.nio.file.Paths; import org.hamcrest.Matchers; import org.junit.Rule; import org.junit.Test; public class RobolectricTestRuleTest { private class ResourceRule implements HasAndroidResourceDeps { private final SourcePath resourceDirectory; private final SourcePath assetsDirectory; ResourceRule(SourcePath resourceDirectory) { this(resourceDirectory, null); } ResourceRule(SourcePath resourceDirectory, SourcePath assetsDirectory) { this.resourceDirectory = resourceDirectory; this.assetsDirectory = assetsDirectory; } @Override public SourcePath getPathToTextSymbolsFile() { return null; } @Override public SourcePath getPathToRDotJavaPackageFile() { return null; } @Override public String getRDotJavaPackage() { return null; } @Override public SourcePath getRes() { return resourceDirectory; } @Override public SourcePath getAssets() { return assetsDirectory; } @Override public BuildTarget getBuildTarget() { return null; } } @Rule public TemporaryPaths temporaryFolder = new TemporaryPaths(); @Test public void testRobolectricContainsAllResourceDependenciesInResVmArg() throws Exception { ProjectFilesystem filesystem = new FakeProjectFilesystem(temporaryFolder.getRoot()); ImmutableList.Builder<HasAndroidResourceDeps> resDepsBuilder = ImmutableList.builder(); for (int i = 0; i < 10; i++) { String path = "java/src/com/facebook/base/" + i + "/res"; filesystem.mkdirs(Paths.get(path).resolve("values")); resDepsBuilder.add(new ResourceRule(new FakeSourcePath(path))); } ImmutableList<HasAndroidResourceDeps> resDeps = resDepsBuilder.build(); BuildTarget robolectricBuildTarget = BuildTargetFactory.newInstance( "//java/src/com/facebook/base/robolectricTest:robolectricTest"); TargetNode<?, ?> robolectricTestNode = RobolectricTestBuilder.createBuilder(robolectricBuildTarget, filesystem).build(); TargetGraph targetGraph = TargetGraphFactory.newInstance(robolectricTestNode); BuildRuleResolver resolver = new BuildRuleResolver(targetGraph, new DefaultTargetNodeToBuildRuleTransformer()); SourcePathResolver pathResolver = new SourcePathResolver(new SourcePathRuleFinder(resolver)); RobolectricTest robolectricTest = (RobolectricTest) resolver.requireRule(robolectricBuildTarget); String result = robolectricTest.getRobolectricResourceDirectories(pathResolver, resDeps); for (HasAndroidResourceDeps dep : resDeps) { // Every value should be a PathSourcePath assertTrue( result + " does not contain " + dep.getRes(), result.contains(((PathSourcePath) dep.getRes()).getRelativePath().toString())); } } @Test public void testRobolectricResourceDependenciesVmArgHasCorrectFormat() throws Exception { ProjectFilesystem filesystem = new FakeProjectFilesystem(temporaryFolder.getRoot()); filesystem.mkdirs(Paths.get("res1/values")); filesystem.mkdirs(Paths.get("res2/values")); filesystem.mkdirs(Paths.get("res3/values")); filesystem.mkdirs(Paths.get("res4_to_ignore")); Path resDep1 = Paths.get("res1"); Path resDep2 = Paths.get("res2"); Path resDep3 = Paths.get("res3"); Path resDep4 = Paths.get("res4_to_ignore"); StringBuilder expectedVmArgBuilder = new StringBuilder(); expectedVmArgBuilder .append("-D") .append(RobolectricTest.LIST_OF_RESOURCE_DIRECTORIES_PROPERTY_NAME) .append("=") .append(resDep1) .append(File.pathSeparator) .append(resDep2) .append(File.pathSeparator) .append(resDep3); BuildTarget robolectricBuildTarget = BuildTargetFactory.newInstance( "//java/src/com/facebook/base/robolectricTest:robolectricTest"); TargetNode<?, ?> robolectricTestNode = RobolectricTestBuilder.createBuilder(robolectricBuildTarget, filesystem).build(); TargetGraph targetGraph = TargetGraphFactory.newInstance(robolectricTestNode); BuildRuleResolver resolver = new BuildRuleResolver(targetGraph, new DefaultTargetNodeToBuildRuleTransformer()); SourcePathResolver pathResolver = new SourcePathResolver(new SourcePathRuleFinder(resolver)); RobolectricTest robolectricTest = (RobolectricTest) resolver.requireRule(robolectricBuildTarget); String result = robolectricTest.getRobolectricResourceDirectories( pathResolver, ImmutableList.of( new ResourceRule(new PathSourcePath(filesystem, resDep1)), new ResourceRule(new PathSourcePath(filesystem, resDep2)), new ResourceRule(null), new ResourceRule(new PathSourcePath(filesystem, resDep3)), new ResourceRule(new PathSourcePath(filesystem, resDep4)))); assertEquals(expectedVmArgBuilder.toString(), result); } @Test public void testRobolectricThrowsIfResourceDirNotThere() throws Exception { ProjectFilesystem filesystem = new FakeProjectFilesystem(temporaryFolder.getRoot()); BuildTarget robolectricBuildTarget = BuildTargetFactory.newInstance( "//java/src/com/facebook/base/robolectricTest:robolectricTest"); TargetNode<?, ?> robolectricTestNode = RobolectricTestBuilder.createBuilder(robolectricBuildTarget, filesystem).build(); TargetGraph targetGraph = TargetGraphFactory.newInstance(robolectricTestNode); BuildRuleResolver resolver = new BuildRuleResolver(targetGraph, new DefaultTargetNodeToBuildRuleTransformer()); SourcePathResolver pathResolver = new SourcePathResolver(new SourcePathRuleFinder(resolver)); RobolectricTest robolectricTest = (RobolectricTest) resolver.requireRule(robolectricBuildTarget); try { robolectricTest.getRobolectricResourceDirectories( pathResolver, ImmutableList.of( new ResourceRule(new PathSourcePath(filesystem, Paths.get("not_there_res"))))); fail("Expected FileNotFoundException"); } catch (RuntimeException e) { assertThat(e.getMessage(), Matchers.containsString("not_there_res")); } } @Test public void testRobolectricAssetsDependenciesVmArgHasCorrectFormat() throws Exception { ProjectFilesystem filesystem = new FakeProjectFilesystem(temporaryFolder.getRoot()); filesystem.mkdirs(Paths.get("assets1/svg")); filesystem.mkdirs(Paths.get("assets2/xml")); filesystem.mkdirs(Paths.get("assets3_to_ignore")); Path assetsDep1 = Paths.get("assets1"); Path assetsDep2 = Paths.get("assets2"); Path assetsDep3 = Paths.get("assets3_to_ignore"); StringBuilder expectedVmArgBuilder = new StringBuilder(); expectedVmArgBuilder .append("-D") .append(RobolectricTest.LIST_OF_ASSETS_DIRECTORIES_PROPERTY_NAME) .append("=") .append(assetsDep1) .append(File.pathSeparator) .append(assetsDep2); BuildTarget robolectricBuildTarget = BuildTargetFactory.newInstance( "//java/src/com/facebook/base/robolectricTest:robolectricTest"); TargetNode<?, ?> robolectricTestNode = RobolectricTestBuilder.createBuilder(robolectricBuildTarget, filesystem).build(); TargetGraph targetGraph = TargetGraphFactory.newInstance(robolectricTestNode); BuildRuleResolver resolver = new BuildRuleResolver(targetGraph, new DefaultTargetNodeToBuildRuleTransformer()); SourcePathResolver pathResolver = new SourcePathResolver(new SourcePathRuleFinder(resolver)); RobolectricTest robolectricTest = (RobolectricTest) resolver.requireRule(robolectricBuildTarget); String result = robolectricTest.getRobolectricAssetsDirectories( pathResolver, ImmutableList.of( new ResourceRule(null, new PathSourcePath(filesystem, assetsDep1)), new ResourceRule(null, null), new ResourceRule(null, new PathSourcePath(filesystem, assetsDep2)), new ResourceRule(null, new PathSourcePath(filesystem, assetsDep3)))); assertEquals(expectedVmArgBuilder.toString(), result); } @Test public void testRobolectricThrowsIfAssetsDirNotThere() throws Exception { ProjectFilesystem filesystem = new FakeProjectFilesystem(temporaryFolder.getRoot()); BuildTarget robolectricBuildTarget = BuildTargetFactory.newInstance( "//java/src/com/facebook/base/robolectricTest:robolectricTest"); TargetNode<?, ?> robolectricTestNode = RobolectricTestBuilder.createBuilder(robolectricBuildTarget, filesystem).build(); TargetGraph targetGraph = TargetGraphFactory.newInstance(robolectricTestNode); BuildRuleResolver resolver = new BuildRuleResolver(targetGraph, new DefaultTargetNodeToBuildRuleTransformer()); SourcePathResolver pathResolver = new SourcePathResolver(new SourcePathRuleFinder(resolver)); RobolectricTest robolectricTest = (RobolectricTest) resolver.requireRule(robolectricBuildTarget); try { robolectricTest.getRobolectricResourceDirectories( pathResolver, ImmutableList.of( new ResourceRule(new PathSourcePath(filesystem, Paths.get("not_there_assets"))))); fail("Expected FileNotFoundException"); } catch (RuntimeException e) { assertThat(e.getMessage(), Matchers.containsString("not_there_assets")); } } @Test public void runtimeDepsIncludeTransitiveResources() throws Exception { ProjectFilesystem filesystem = new FakeProjectFilesystem(temporaryFolder.getRoot()); BuildTarget resGenRuleTarget = BuildTargetFactory.newInstance("//:res-gen"); TargetNode<?, ?> resGenRuleNode = GenruleBuilder.newGenruleBuilder(resGenRuleTarget).setOut("res-out").build(); BuildTarget assetsGenRuleTarget = BuildTargetFactory.newInstance("//:assets-gen"); TargetNode<?, ?> assetsGenRuleNode = GenruleBuilder.newGenruleBuilder(assetsGenRuleTarget).setOut("assets-out").build(); BuildTarget res2RuleTarget = BuildTargetFactory.newInstance("//:res2"); TargetNode<?, ?> res2Node = AndroidResourceBuilder.createBuilder(res2RuleTarget) .setRes(new DefaultBuildTargetSourcePath(resGenRuleTarget)) .setAssets(new DefaultBuildTargetSourcePath(assetsGenRuleTarget)) .setRDotJavaPackage("foo.bar") .build(); BuildTarget robolectricBuildTarget = BuildTargetFactory.newInstance( "//java/src/com/facebook/base/robolectricTest:robolectricTest"); TargetNode<?, ?> robolectricTestNode = RobolectricTestBuilder.createBuilder(robolectricBuildTarget, filesystem) .addDep(res2RuleTarget) .build(); TargetGraph targetGraph = TargetGraphFactory.newInstance( resGenRuleNode, assetsGenRuleNode, res2Node, robolectricTestNode); BuildRuleResolver resolver = new BuildRuleResolver(targetGraph, new DefaultTargetNodeToBuildRuleTransformer()); RobolectricTest robolectricTest = (RobolectricTest) resolver.requireRule(robolectricBuildTarget); BuildRule resGenRule = resolver.requireRule(resGenRuleTarget); BuildRule assetsGenRule = resolver.requireRule(assetsGenRuleTarget); assertThat( robolectricTest.getRuntimeDeps().collect(MoreCollectors.toImmutableSet()), Matchers.hasItems(resGenRule.getBuildTarget(), assetsGenRule.getBuildTarget())); } }