blob: c6d7ce247616acf8a610c8503359feb04ee4d72a [file] [log] [blame]
// Copyright 2015 The Bazel Authors. All rights reserved.
//
// 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.google.devtools.build.lib.packages;
import static com.google.common.truth.Truth.assertThat;
import static com.google.devtools.build.lib.packages.Attribute.ConfigurationTransition.HOST;
import static com.google.devtools.build.lib.packages.Attribute.ConfigurationTransition.SPLIT;
import static com.google.devtools.build.lib.packages.Attribute.attr;
import static com.google.devtools.build.lib.packages.BuildType.LABEL;
import static com.google.devtools.build.lib.packages.BuildType.LABEL_LIST;
import static com.google.devtools.build.lib.syntax.Type.INTEGER;
import static com.google.devtools.build.lib.syntax.Type.STRING;
import static com.google.devtools.build.lib.syntax.Type.STRING_LIST;
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.google.common.base.Predicates;
import com.google.common.collect.ImmutableList;
import com.google.devtools.build.lib.analysis.config.BuildOptions;
import com.google.devtools.build.lib.analysis.util.TestAspects;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.packages.Attribute.SplitTransition;
import com.google.devtools.build.lib.packages.Attribute.SplitTransitionProvider;
import com.google.devtools.build.lib.syntax.Type;
import com.google.devtools.build.lib.util.FileType;
import com.google.devtools.build.lib.util.FileTypeSet;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* Tests of Attribute code.
*/
@RunWith(JUnit4.class)
public class AttributeTest {
private void assertDefaultValue(Object expected, Attribute attr) {
assertEquals(expected, attr.getDefaultValue(null));
}
private void assertType(Type<?> expectedType, Attribute attr) {
assertEquals(expectedType, attr.getType());
}
@Test
public void testBasics() throws Exception {
Attribute attr = attr("foo", Type.INTEGER).mandatory().value(3).build();
assertEquals("foo", attr.getName());
assertEquals(3, attr.getDefaultValue(null));
assertEquals(Type.INTEGER, attr.getType());
assertTrue(attr.isMandatory());
assertTrue(attr.isDocumented());
attr = attr("$foo", Type.INTEGER).build();
assertFalse(attr.isDocumented());
}
@Test
public void testNonEmptyReqiresListType() throws Exception {
try {
attr("foo", Type.INTEGER).nonEmpty().value(3).build();
fail();
} catch (NullPointerException e) {
assertThat(e).hasMessage("attribute 'foo' must be a list");
}
}
@Test
public void testNonEmpty() throws Exception {
Attribute attr = attr("foo", BuildType.LABEL_LIST).nonEmpty().legacyAllowAnyFileType().build();
assertEquals("foo", attr.getName());
assertEquals(BuildType.LABEL_LIST, attr.getType());
assertTrue(attr.isNonEmpty());
}
@Test
public void testSingleArtifactReqiresLabelType() throws Exception {
try {
attr("foo", Type.INTEGER).singleArtifact().value(3).build();
fail();
} catch (IllegalStateException e) {
assertThat(e).hasMessage("attribute 'foo' must be a label-valued type");
}
}
@Test
public void testDoublePropertySet() {
Attribute.Builder<String> builder = attr("x", STRING).mandatory().cfg(HOST).undocumented("")
.value("y");
try {
builder.mandatory();
fail();
} catch (IllegalStateException expected) {
// expected
}
try {
builder.cfg(HOST);
fail();
} catch (IllegalStateException expected) {
// expected
}
try {
builder.undocumented("");
fail();
} catch (IllegalStateException expected) {
// expected
}
try {
builder.value("z");
fail();
} catch (IllegalStateException expected) {
// expected
}
builder = attr("$x", STRING);
try {
builder.undocumented("");
fail();
} catch (IllegalStateException expected) {
// expected
}
}
/**
* Tests the "convenience factories" (string, label, etc) for default
* values.
*/
@Test
public void testConvenienceFactoriesDefaultValues() throws Exception {
assertDefaultValue(0,
attr("x", INTEGER).build());
assertDefaultValue(42,
attr("x", INTEGER).value(42).build());
assertDefaultValue("",
attr("x", STRING).build());
assertDefaultValue("foo",
attr("x", STRING).value("foo").build());
Label label = Label.parseAbsolute("//foo:bar");
assertDefaultValue(null,
attr("x", LABEL).legacyAllowAnyFileType().build());
assertDefaultValue(label,
attr("x", LABEL).legacyAllowAnyFileType().value(label).build());
List<String> slist = Arrays.asList("foo", "bar");
assertDefaultValue(Collections.emptyList(),
attr("x", STRING_LIST).build());
assertDefaultValue(slist,
attr("x", STRING_LIST).value(slist).build());
List<Label> llist = Arrays.asList(Label.parseAbsolute("//foo:bar"),
Label.parseAbsolute("//foo:wiz"));
assertDefaultValue(Collections.emptyList(),
attr("x", LABEL_LIST).legacyAllowAnyFileType().build());
assertDefaultValue(llist,
attr("x", LABEL_LIST).legacyAllowAnyFileType().value(llist).build());
}
/**
* Tests the "convenience factories" (string, label, etc) for types.
*/
@Test
public void testConvenienceFactoriesTypes() throws Exception {
assertType(INTEGER,
attr("x", INTEGER).build());
assertType(INTEGER,
attr("x", INTEGER).value(42).build());
assertType(STRING,
attr("x", STRING).build());
assertType(STRING,
attr("x", STRING).value("foo").build());
Label label = Label.parseAbsolute("//foo:bar");
assertType(LABEL,
attr("x", LABEL).legacyAllowAnyFileType().build());
assertType(LABEL,
attr("x", LABEL).legacyAllowAnyFileType().value(label).build());
List<String> slist = Arrays.asList("foo", "bar");
assertType(STRING_LIST,
attr("x", STRING_LIST).build());
assertType(STRING_LIST,
attr("x", STRING_LIST).value(slist).build());
List<Label> llist = Arrays.asList(Label.parseAbsolute("//foo:bar"),
Label.parseAbsolute("//foo:wiz"));
assertType(LABEL_LIST,
attr("x", LABEL_LIST).legacyAllowAnyFileType().build());
assertType(LABEL_LIST,
attr("x", LABEL_LIST).legacyAllowAnyFileType().value(llist).build());
}
@Test
public void testCloneBuilder() {
FileTypeSet txtFiles = FileTypeSet.of(FileType.of("txt"));
RuleClass.Builder.RuleClassNamePredicate ruleClasses =
new RuleClass.Builder.RuleClassNamePredicate("mock_rule");
Attribute parentAttr =
attr("x", LABEL_LIST)
.allowedFileTypes(txtFiles)
.mandatory()
.aspect(TestAspects.SIMPLE_ASPECT)
.build();
{
Attribute childAttr1 = parentAttr.cloneBuilder().build();
assertEquals("x", childAttr1.getName());
assertEquals(txtFiles, childAttr1.getAllowedFileTypesPredicate());
assertEquals(Predicates.alwaysTrue(), childAttr1.getAllowedRuleClassesPredicate());
assertTrue(childAttr1.isMandatory());
assertFalse(childAttr1.isNonEmpty());
assertThat(childAttr1.getAspects(null /* rule */)).hasSize(1);
}
{
Attribute childAttr2 =
parentAttr
.cloneBuilder()
.nonEmpty()
.allowedRuleClasses(ruleClasses)
.aspect(TestAspects.ERROR_ASPECT)
.build();
assertEquals("x", childAttr2.getName());
assertEquals(txtFiles, childAttr2.getAllowedFileTypesPredicate());
assertEquals(ruleClasses, childAttr2.getAllowedRuleClassesPredicate());
assertTrue(childAttr2.isMandatory());
assertTrue(childAttr2.isNonEmpty());
assertThat(childAttr2.getAspects(null /* rule */)).hasSize(2);
}
//Check if the parent attribute is unchanged
assertFalse(parentAttr.isNonEmpty());
assertEquals(Predicates.alwaysTrue(), parentAttr.getAllowedRuleClassesPredicate());
}
/**
* Tests that configurability settings are properly received.
*/
@Test
public void testConfigurability() {
assertTrue(attr("foo_configurable", BuildType.LABEL_LIST).legacyAllowAnyFileType().build()
.isConfigurable());
assertFalse(attr("foo_nonconfigurable", BuildType.LABEL_LIST).legacyAllowAnyFileType()
.nonconfigurable("test").build().isConfigurable());
}
@Test
public void testSplitTransition() throws Exception {
TestSplitTransition splitTransition = new TestSplitTransition();
Attribute attr = attr("foo", LABEL).cfg(splitTransition).allowedFileTypes().build();
assertThat(attr.getConfigurationTransition()).isEqualTo(SPLIT);
assertTrue(attr.hasSplitConfigurationTransition());
assertThat(attr.getSplitTransition(null)).isEqualTo(splitTransition);
}
@Test
public void testSplitTransitionProvider() throws Exception {
TestSplitTransitionProvider splitTransitionProvider = new TestSplitTransitionProvider();
Attribute attr =
attr("foo", LABEL).cfg(splitTransitionProvider).allowedFileTypes().build();
assertThat(attr.getConfigurationTransition()).isEqualTo(SPLIT);
assertTrue(attr.hasSplitConfigurationTransition());
assertTrue(attr.getSplitTransition(null) instanceof TestSplitTransition);
}
@Test
public void testHostTransition() throws Exception {
Attribute attr = attr("foo", LABEL).cfg(HOST).allowedFileTypes().build();
assertThat(attr.getConfigurationTransition()).isEqualTo(HOST);
assertFalse(attr.hasSplitConfigurationTransition());
}
private static class TestSplitTransition implements SplitTransition<BuildOptions> {
@Override
public boolean defaultsToSelf() {
return true;
}
@Override
public List<BuildOptions> split(BuildOptions buildOptions) {
return ImmutableList.of(buildOptions.clone(), buildOptions.clone());
}
}
private static class TestSplitTransitionProvider implements SplitTransitionProvider {
@Override
public SplitTransition<?> apply(Rule fromRule) {
return new TestSplitTransition();
}
}
}