| // 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(); | |
| } | |
| } | |
| } |