/*
* Copyright 2012-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.rules;
import static com.facebook.buck.rules.TestCellBuilder.createCellRoots;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
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.parser.NoSuchBuildTargetException;
import com.facebook.buck.rules.coercer.DefaultTypeCoercerFactory;
import com.facebook.buck.testutil.FakeProjectFilesystem;
import com.facebook.buck.util.MoreCollectors;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.hash.Hashing;
import org.junit.Test;
public class TargetNodeVisibilityTest {
private static final ProjectFilesystem filesystem = new FakeProjectFilesystem();
private static final BuildTarget orcaTarget =
BuildTarget.builder(filesystem.getRootPath(), "//src/com/facebook/orca", "orca").build();
private static final BuildTarget publicTarget =
BuildTarget.builder(filesystem.getRootPath(), "//src/com/facebook/for", "everyone").build();
private static final BuildTarget nonPublicTarget1 =
BuildTarget.builder(filesystem.getRootPath(), "//src/com/facebook/something1", "nonPublic")
.build();
private static final BuildTarget nonPublicTarget2 =
BuildTarget.builder(filesystem.getRootPath(), "//src/com/facebook/something2", "nonPublic")
.build();
private static final ImmutableList<String> DEFAULT = ImmutableList.of();
private static final ImmutableList<String> PUBLIC = ImmutableList.of("PUBLIC");
private static final ImmutableList<String> ORCA =
ImmutableList.of(orcaTarget.getFullyQualifiedName());
private static final ImmutableList<String> SOME_OTHER = ImmutableList.of("//some/other:target");
@Test
public void testVisibilityPublic() throws NoSuchBuildTargetException {
TargetNode<?, ?> publicTargetNode = createTargetNode(publicTarget, PUBLIC);
TargetNode<?, ?> orcaRule = createTargetNode(orcaTarget, DEFAULT);
assertTrue(publicTargetNode.isVisibleTo(orcaRule));
assertFalse(orcaRule.isVisibleTo(publicTargetNode));
}
@Test
public void testVisibilityNonPublic() throws NoSuchBuildTargetException {
TargetNode<?, ?> nonPublicTargetNode1 = createTargetNode(nonPublicTarget1, ORCA);
TargetNode<?, ?> nonPublicTargetNode2 = createTargetNode(nonPublicTarget2, ORCA);
TargetNode<?, ?> orcaRule = createTargetNode(orcaTarget, DEFAULT);
TargetNode<?, ?> publicTargetNode = createTargetNode(publicTarget, PUBLIC);
assertTrue(
shouldBeVisibleMessage(nonPublicTargetNode1, orcaTarget),
nonPublicTargetNode1.isVisibleTo(orcaRule));
assertTrue(
shouldBeVisibleMessage(nonPublicTargetNode2, orcaTarget),
nonPublicTargetNode2.isVisibleTo(orcaRule));
assertFalse(orcaRule.isVisibleTo(nonPublicTargetNode1));
assertFalse(orcaRule.isVisibleTo(nonPublicTargetNode2));
assertTrue(publicTargetNode.isVisibleTo(nonPublicTargetNode1));
assertFalse(nonPublicTargetNode1.isVisibleTo(publicTargetNode));
}
@Test
public void testVisibilityNonPublicFailure() throws NoSuchBuildTargetException {
TargetNode<?, ?> nonPublicTargetNode1 = createTargetNode(nonPublicTarget1, ORCA);
TargetNode<?, ?> publicTargetNode = createTargetNode(publicTarget, PUBLIC);
try {
nonPublicTargetNode1.isVisibleToOrThrow(publicTargetNode);
fail("checkVisibility() should throw an exception");
} catch (RuntimeException e) {
assertEquals(
String.format(
"%s depends on %s, which is not visible",
publicTarget, nonPublicTargetNode1.getBuildTarget()),
e.getMessage());
}
}
@Test
public void testVisibilityMix() throws NoSuchBuildTargetException {
TargetNode<?, ?> nonPublicTargetNode1 = createTargetNode(nonPublicTarget1, ORCA);
TargetNode<?, ?> nonPublicTargetNode2 = createTargetNode(nonPublicTarget2, ORCA);
TargetNode<?, ?> publicTargetNode = createTargetNode(publicTarget, PUBLIC);
TargetNode<?, ?> orcaRule = createTargetNode(orcaTarget, DEFAULT);
assertTrue(
shouldBeVisibleMessage(nonPublicTargetNode1, orcaTarget),
nonPublicTargetNode1.isVisibleTo(orcaRule));
assertTrue(
shouldBeVisibleMessage(nonPublicTargetNode2, orcaTarget),
nonPublicTargetNode2.isVisibleTo(orcaRule));
assertTrue(publicTargetNode.isVisibleTo(orcaRule));
assertFalse(orcaRule.isVisibleTo(nonPublicTargetNode1));
assertFalse(orcaRule.isVisibleTo(nonPublicTargetNode2));
assertFalse(orcaRule.isVisibleTo(publicTargetNode));
}
@Test
public void testVisibilityMixFailure() throws NoSuchBuildTargetException {
TargetNode<?, ?> nonPublicTargetNode1 = createTargetNode(nonPublicTarget1, ORCA);
TargetNode<?, ?> nonPublicTargetNode2 = createTargetNode(nonPublicTarget2, SOME_OTHER);
TargetNode<?, ?> publicTargetNode = createTargetNode(publicTarget, PUBLIC);
TargetNode<?, ?> orcaRule = createTargetNode(orcaTarget, DEFAULT);
publicTargetNode.isVisibleToOrThrow(orcaRule);
nonPublicTargetNode1.isVisibleToOrThrow(orcaRule);
try {
nonPublicTargetNode2.isVisibleToOrThrow(orcaRule);
fail("checkVisibility() should throw an exception");
} catch (RuntimeException e) {
assertEquals(
String.format(
"%s depends on %s, which is not visible",
orcaTarget, nonPublicTargetNode2.getBuildTarget()),
e.getMessage());
}
}
@Test
public void testVisibilityForDirectory() throws NoSuchBuildTargetException {
BuildTarget libTarget = BuildTarget.builder(filesystem.getRootPath(), "//lib", "lib").build();
TargetNode<?, ?> targetInSpecifiedDirectory =
createTargetNode(
BuildTarget.builder(filesystem.getRootPath(), "//src/com/facebook", "test").build(),
DEFAULT);
TargetNode<?, ?> targetUnderSpecifiedDirectory =
createTargetNode(
BuildTarget.builder(filesystem.getRootPath(), "//src/com/facebook/buck", "test")
.build(),
DEFAULT);
TargetNode<?, ?> targetInOtherDirectory =
createTargetNode(
BuildTarget.builder(filesystem.getRootPath(), "//src/com/instagram", "test").build(),
DEFAULT);
TargetNode<?, ?> targetInParentDirectory =
createTargetNode(
BuildTarget.builder(filesystem.getRootPath(), "//", "test").build(), DEFAULT);
// Build rule that visible to targets in or under directory src/com/facebook
TargetNode<?, ?> directoryTargetNode =
createTargetNode(libTarget, ImmutableList.of("//src/com/facebook/..."));
assertTrue(directoryTargetNode.isVisibleTo(targetInSpecifiedDirectory));
assertTrue(directoryTargetNode.isVisibleTo(targetUnderSpecifiedDirectory));
assertFalse(directoryTargetNode.isVisibleTo(targetInOtherDirectory));
assertFalse(directoryTargetNode.isVisibleTo(targetInParentDirectory));
// Build rule that's visible to all targets, equals to PUBLIC.
TargetNode<?, ?> pubicTargetNode = createTargetNode(libTarget, ImmutableList.of("//..."));
assertTrue(pubicTargetNode.isVisibleTo(targetInSpecifiedDirectory));
assertTrue(pubicTargetNode.isVisibleTo(targetUnderSpecifiedDirectory));
assertTrue(pubicTargetNode.isVisibleTo(targetInOtherDirectory));
assertTrue(pubicTargetNode.isVisibleTo(targetInParentDirectory));
}
@Test
public void testOnlyWithinViewIsVisible() throws NoSuchBuildTargetException {
TargetNode<?, ?> publicTargetNode = createTargetNode(publicTarget, PUBLIC, ORCA);
TargetNode<?, ?> publicOrcaRule = createTargetNode(orcaTarget, PUBLIC, SOME_OTHER);
assertTrue(publicOrcaRule.isVisibleTo(publicTargetNode));
assertFalse(publicTargetNode.isVisibleTo(publicOrcaRule));
}
private String shouldBeVisibleMessage(TargetNode<?, ?> rule, BuildTarget target) {
return String.format(
"%1$s should be visible to %2$s because the visibility list of %1$s contains %2$s",
rule.getBuildTarget(), target);
}
public static class FakeRuleDescription implements Description<FakeRuleDescription.FakeArg> {
@Override
public Class<FakeArg> getConstructorArgType() {
return FakeArg.class;
}
@Override
public BuildRule createBuildRule(
TargetGraph targetGraph,
BuildRuleParams params,
BuildRuleResolver resolver,
CellPathResolver cellRoots,
FakeArg args) {
return new FakeBuildRule(params, new SourcePathResolver(new SourcePathRuleFinder(resolver)));
}
public static class FakeArg extends AbstractDescriptionArg {}
}
private static TargetNode<?, ?> createTargetNode(
BuildTarget buildTarget, ImmutableList<String> visibilities)
throws NoSuchBuildTargetException {
return createTargetNode(buildTarget, visibilities, DEFAULT);
}
private static TargetNode<?, ?> createTargetNode(
BuildTarget buildTarget, ImmutableList<String> visibilities, ImmutableList<String> withinView)
throws NoSuchBuildTargetException {
VisibilityPatternParser parser = new VisibilityPatternParser();
CellPathResolver cellNames = new FakeCellPathResolver(filesystem);
Description<FakeRuleDescription.FakeArg> description = new FakeRuleDescription();
FakeRuleDescription.FakeArg arg = new FakeRuleDescription.FakeArg();
return new TargetNodeFactory(new DefaultTypeCoercerFactory())
.create(
Hashing.sha1().hashString(buildTarget.getFullyQualifiedName(), UTF_8),
description,
arg,
filesystem,
buildTarget,
ImmutableSet.of(),
visibilities
.stream()
.map(s -> parser.parse(cellNames, s))
.collect(MoreCollectors.toImmutableSet()),
withinView
.stream()
.map(s -> parser.parse(cellNames, s))
.collect(MoreCollectors.toImmutableSet()),
createCellRoots(filesystem));
}
}