blob: 75b4d8e51f296d07a6694d48dddcaf3380d92508 [file] [log] [blame]
Han-Wen Nienhuys3428dc92015-10-21 15:03:34 +00001// Copyright 2015 The Bazel Authors. All rights reserved.
Ulf Adams83763ee2015-05-04 15:36:12 +00002//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14package com.google.devtools.build.lib.packages;
15
16import static com.google.common.truth.Truth.assertThat;
Ulf Adams83763ee2015-05-04 15:36:12 +000017import static com.google.devtools.build.lib.packages.Attribute.attr;
Lukacs Berkiffa73ad2015-09-18 11:40:12 +000018import static com.google.devtools.build.lib.packages.BuildType.LABEL;
19import static com.google.devtools.build.lib.packages.BuildType.LABEL_LIST;
Googlerc5fcc862019-09-06 16:17:47 -070020import static com.google.devtools.build.lib.packages.Type.INTEGER;
21import static com.google.devtools.build.lib.packages.Type.STRING;
22import static com.google.devtools.build.lib.packages.Type.STRING_LIST;
michajlo660d17f2020-03-27 09:01:57 -070023import static org.junit.Assert.assertThrows;
Ulf Adams83763ee2015-05-04 15:36:12 +000024
25import com.google.common.base.Predicates;
dannark90e2b4b2018-06-27 13:35:04 -070026import com.google.common.collect.ImmutableMap;
Chris Parsons2e62c0d2016-04-19 22:13:59 +000027import com.google.devtools.build.lib.analysis.config.BuildOptions;
gregcea048f0f2020-06-11 15:10:01 -070028import com.google.devtools.build.lib.analysis.config.BuildOptionsView;
gregce676a9572017-12-21 11:33:32 -080029import com.google.devtools.build.lib.analysis.config.HostTransition;
jcater98a09b62019-04-02 13:06:19 -070030import com.google.devtools.build.lib.analysis.config.TransitionFactories;
John Cater5adcd3e2019-03-28 10:14:32 -070031import com.google.devtools.build.lib.analysis.config.transitions.ConfigurationTransition;
gregce6bc35ed2017-12-22 11:51:39 -080032import com.google.devtools.build.lib.analysis.config.transitions.SplitTransition;
John Cater0a9e1ed2019-03-27 11:02:01 -070033import com.google.devtools.build.lib.analysis.config.transitions.TransitionFactory;
Carmi Grushko215fa842016-03-31 18:14:39 +000034import com.google.devtools.build.lib.analysis.util.TestAspects;
Lukacs Berki6e91eb92015-09-21 09:12:37 +000035import com.google.devtools.build.lib.cmdline.Label;
gregcef0a40ac2020-03-31 14:11:30 -070036import com.google.devtools.build.lib.events.EventHandler;
Googler72f3a102017-12-01 16:28:28 -080037import com.google.devtools.build.lib.packages.RuleClass.Builder.RuleClassNamePredicate;
John Cater0a9e1ed2019-03-27 11:02:01 -070038import com.google.devtools.build.lib.testutil.FakeAttributeMapper;
Ulf Adams83763ee2015-05-04 15:36:12 +000039import com.google.devtools.build.lib.util.FileType;
40import com.google.devtools.build.lib.util.FileTypeSet;
lberkiaea56b32017-05-30 12:35:33 +020041import java.util.Arrays;
42import java.util.Collections;
43import java.util.List;
Googler19226b72020-02-06 12:58:43 -080044import java.util.Map;
adonovan3ed7ed52020-09-30 12:03:28 -070045import net.starlark.java.eval.StarlarkInt;
Ulf Adams83763ee2015-05-04 15:36:12 +000046import org.junit.Test;
47import org.junit.runner.RunWith;
48import org.junit.runners.JUnit4;
49
lberkiaea56b32017-05-30 12:35:33 +020050/** Tests of Attribute code. */
Ulf Adams83763ee2015-05-04 15:36:12 +000051@RunWith(JUnit4.class)
52public class AttributeTest {
53
54 private void assertDefaultValue(Object expected, Attribute attr) {
lberkiaea56b32017-05-30 12:35:33 +020055 assertThat(attr.getDefaultValue(null)).isEqualTo(expected);
Ulf Adams83763ee2015-05-04 15:36:12 +000056 }
57
58 private void assertType(Type<?> expectedType, Attribute attr) {
lberkiaea56b32017-05-30 12:35:33 +020059 assertThat(attr.getType()).isEqualTo(expectedType);
Ulf Adams83763ee2015-05-04 15:36:12 +000060 }
61
62 @Test
63 public void testBasics() throws Exception {
adonovan3ed7ed52020-09-30 12:03:28 -070064 Attribute attr = attr("foo", Type.INTEGER).mandatory().value(StarlarkInt.of(3)).build();
lberkiaea56b32017-05-30 12:35:33 +020065 assertThat(attr.getName()).isEqualTo("foo");
adonovan3ed7ed52020-09-30 12:03:28 -070066 assertThat(attr.getDefaultValue(null)).isEqualTo(StarlarkInt.of(3));
lberkiaea56b32017-05-30 12:35:33 +020067 assertThat(attr.getType()).isEqualTo(Type.INTEGER);
68 assertThat(attr.isMandatory()).isTrue();
69 assertThat(attr.isDocumented()).isTrue();
Ulf Adams83763ee2015-05-04 15:36:12 +000070 attr = attr("$foo", Type.INTEGER).build();
lberkiaea56b32017-05-30 12:35:33 +020071 assertThat(attr.isDocumented()).isFalse();
Ulf Adams83763ee2015-05-04 15:36:12 +000072 }
73
74 @Test
75 public void testNonEmptyReqiresListType() throws Exception {
jcaterb9226772019-04-29 12:04:52 -070076 NullPointerException e =
77 assertThrows(
78 NullPointerException.class,
adonovan3ed7ed52020-09-30 12:03:28 -070079 () -> attr("foo", Type.INTEGER).nonEmpty().value(StarlarkInt.of(3)).build());
jcaterb9226772019-04-29 12:04:52 -070080 assertThat(e).hasMessageThat().isEqualTo("attribute 'foo' must be a list");
Ulf Adams83763ee2015-05-04 15:36:12 +000081 }
82
83 @Test
84 public void testNonEmpty() throws Exception {
Lukacs Berkiffa73ad2015-09-18 11:40:12 +000085 Attribute attr = attr("foo", BuildType.LABEL_LIST).nonEmpty().legacyAllowAnyFileType().build();
lberkiaea56b32017-05-30 12:35:33 +020086 assertThat(attr.getName()).isEqualTo("foo");
87 assertThat(attr.getType()).isEqualTo(BuildType.LABEL_LIST);
88 assertThat(attr.isNonEmpty()).isTrue();
Ulf Adams83763ee2015-05-04 15:36:12 +000089 }
90
91 @Test
92 public void testSingleArtifactReqiresLabelType() throws Exception {
jcaterb9226772019-04-29 12:04:52 -070093 IllegalStateException e =
94 assertThrows(
95 IllegalStateException.class,
adonovan3ed7ed52020-09-30 12:03:28 -070096 () -> attr("foo", Type.INTEGER).singleArtifact().value(StarlarkInt.of(3)).build());
jcaterb9226772019-04-29 12:04:52 -070097 assertThat(e).hasMessageThat().isEqualTo("attribute 'foo' must be a label-valued type");
Ulf Adams83763ee2015-05-04 15:36:12 +000098 }
99
100 @Test
101 public void testDoublePropertySet() {
jcaterffb65c82019-03-29 07:52:16 -0700102 Attribute.Builder<String> builder =
103 attr("x", STRING)
104 .mandatory()
105 .cfg(HostTransition.createFactory())
106 .undocumented("")
107 .value("y");
jcaterb9226772019-04-29 12:04:52 -0700108 assertThrows(IllegalStateException.class, () -> builder.mandatory());
109 assertThrows(IllegalStateException.class, () -> builder.cfg(HostTransition.createFactory()));
110 assertThrows(IllegalStateException.class, () -> builder.undocumented(""));
111 assertThrows(IllegalStateException.class, () -> builder.value("z"));
Ulf Adams83763ee2015-05-04 15:36:12 +0000112
jcaterb9226772019-04-29 12:04:52 -0700113 Attribute.Builder<String> builder2 = attr("$x", STRING);
114 assertThrows(IllegalStateException.class, () -> builder2.undocumented(""));
Ulf Adams83763ee2015-05-04 15:36:12 +0000115 }
116
117 /**
118 * Tests the "convenience factories" (string, label, etc) for default
119 * values.
120 */
121 @Test
122 public void testConvenienceFactoriesDefaultValues() throws Exception {
adonovan3ed7ed52020-09-30 12:03:28 -0700123 assertDefaultValue(StarlarkInt.of(0), attr("x", INTEGER).build());
124 assertDefaultValue(StarlarkInt.of(42), attr("x", INTEGER).value(StarlarkInt.of(42)).build());
Ulf Adams83763ee2015-05-04 15:36:12 +0000125
126 assertDefaultValue("",
127 attr("x", STRING).build());
128 assertDefaultValue("foo",
129 attr("x", STRING).value("foo").build());
130
dannark90e2b4b2018-06-27 13:35:04 -0700131 Label label = Label.parseAbsolute("//foo:bar", ImmutableMap.of());
Ulf Adams83763ee2015-05-04 15:36:12 +0000132 assertDefaultValue(null,
133 attr("x", LABEL).legacyAllowAnyFileType().build());
134 assertDefaultValue(label,
135 attr("x", LABEL).legacyAllowAnyFileType().value(label).build());
136
137 List<String> slist = Arrays.asList("foo", "bar");
138 assertDefaultValue(Collections.emptyList(),
139 attr("x", STRING_LIST).build());
140 assertDefaultValue(slist,
141 attr("x", STRING_LIST).value(slist).build());
142
dannark90e2b4b2018-06-27 13:35:04 -0700143 List<Label> llist =
144 Arrays.asList(
145 Label.parseAbsolute("//foo:bar", ImmutableMap.of()),
146 Label.parseAbsolute("//foo:wiz", ImmutableMap.of()));
Ulf Adams83763ee2015-05-04 15:36:12 +0000147 assertDefaultValue(Collections.emptyList(),
148 attr("x", LABEL_LIST).legacyAllowAnyFileType().build());
149 assertDefaultValue(llist,
150 attr("x", LABEL_LIST).legacyAllowAnyFileType().value(llist).build());
151 }
152
153 /**
154 * Tests the "convenience factories" (string, label, etc) for types.
155 */
156 @Test
157 public void testConvenienceFactoriesTypes() throws Exception {
158 assertType(INTEGER,
159 attr("x", INTEGER).build());
adonovan3ed7ed52020-09-30 12:03:28 -0700160 assertType(INTEGER, attr("x", INTEGER).value(StarlarkInt.of(42)).build());
Ulf Adams83763ee2015-05-04 15:36:12 +0000161
162 assertType(STRING,
163 attr("x", STRING).build());
164 assertType(STRING,
165 attr("x", STRING).value("foo").build());
166
dannark90e2b4b2018-06-27 13:35:04 -0700167 Label label = Label.parseAbsolute("//foo:bar", ImmutableMap.of());
Ulf Adams83763ee2015-05-04 15:36:12 +0000168 assertType(LABEL,
169 attr("x", LABEL).legacyAllowAnyFileType().build());
170 assertType(LABEL,
171 attr("x", LABEL).legacyAllowAnyFileType().value(label).build());
172
173 List<String> slist = Arrays.asList("foo", "bar");
174 assertType(STRING_LIST,
175 attr("x", STRING_LIST).build());
176 assertType(STRING_LIST,
177 attr("x", STRING_LIST).value(slist).build());
178
dannark90e2b4b2018-06-27 13:35:04 -0700179 List<Label> llist =
180 Arrays.asList(
181 Label.parseAbsolute("//foo:bar", ImmutableMap.of()),
182 Label.parseAbsolute("//foo:wiz", ImmutableMap.of()));
Ulf Adams83763ee2015-05-04 15:36:12 +0000183 assertType(LABEL_LIST,
184 attr("x", LABEL_LIST).legacyAllowAnyFileType().build());
185 assertType(LABEL_LIST,
186 attr("x", LABEL_LIST).legacyAllowAnyFileType().value(llist).build());
187 }
188
189 @Test
190 public void testCloneBuilder() {
191 FileTypeSet txtFiles = FileTypeSet.of(FileType.of("txt"));
Googler72f3a102017-12-01 16:28:28 -0800192 RuleClassNamePredicate ruleClasses = RuleClassNamePredicate.only("mock_rule");
Han-Wen Nienhuys3428dc92015-10-21 15:03:34 +0000193
Carmi Grushko215fa842016-03-31 18:14:39 +0000194 Attribute parentAttr =
195 attr("x", LABEL_LIST)
196 .allowedFileTypes(txtFiles)
197 .mandatory()
Luis Fernando Pino Duquee82713d2016-04-26 16:22:38 +0000198 .aspect(TestAspects.SIMPLE_ASPECT)
Carmi Grushko215fa842016-03-31 18:14:39 +0000199 .build();
Han-Wen Nienhuys3428dc92015-10-21 15:03:34 +0000200
Carmi Grushko215fa842016-03-31 18:14:39 +0000201 {
202 Attribute childAttr1 = parentAttr.cloneBuilder().build();
lberkiaea56b32017-05-30 12:35:33 +0200203 assertThat(childAttr1.getName()).isEqualTo("x");
204 assertThat(childAttr1.getAllowedFileTypesPredicate()).isEqualTo(txtFiles);
205 assertThat(childAttr1.getAllowedRuleClassesPredicate()).isEqualTo(Predicates.alwaysTrue());
206 assertThat(childAttr1.isMandatory()).isTrue();
207 assertThat(childAttr1.isNonEmpty()).isFalse();
cushon8c6b7ab2018-04-27 01:25:50 -0700208 assertThat(childAttr1.getAspects(/* rule= */ null)).hasSize(1);
Carmi Grushko215fa842016-03-31 18:14:39 +0000209 }
Ulf Adams83763ee2015-05-04 15:36:12 +0000210
Carmi Grushko215fa842016-03-31 18:14:39 +0000211 {
212 Attribute childAttr2 =
213 parentAttr
214 .cloneBuilder()
215 .nonEmpty()
216 .allowedRuleClasses(ruleClasses)
Luis Fernando Pino Duquee82713d2016-04-26 16:22:38 +0000217 .aspect(TestAspects.ERROR_ASPECT)
Carmi Grushko215fa842016-03-31 18:14:39 +0000218 .build();
lberkiaea56b32017-05-30 12:35:33 +0200219 assertThat(childAttr2.getName()).isEqualTo("x");
220 assertThat(childAttr2.getAllowedFileTypesPredicate()).isEqualTo(txtFiles);
Googler72f3a102017-12-01 16:28:28 -0800221 assertThat(childAttr2.getAllowedRuleClassesPredicate())
222 .isEqualTo(ruleClasses.asPredicateOfRuleClass());
lberkiaea56b32017-05-30 12:35:33 +0200223 assertThat(childAttr2.isMandatory()).isTrue();
224 assertThat(childAttr2.isNonEmpty()).isTrue();
cushon8c6b7ab2018-04-27 01:25:50 -0700225 assertThat(childAttr2.getAspects(/* rule= */ null)).hasSize(2);
Carmi Grushko215fa842016-03-31 18:14:39 +0000226 }
Ulf Adams83763ee2015-05-04 15:36:12 +0000227
lberkiaea56b32017-05-30 12:35:33 +0200228 // Check if the parent attribute is unchanged
229 assertThat(parentAttr.isNonEmpty()).isFalse();
230 assertThat(parentAttr.getAllowedRuleClassesPredicate()).isEqualTo(Predicates.alwaysTrue());
Ulf Adams83763ee2015-05-04 15:36:12 +0000231 }
232
233 /**
234 * Tests that configurability settings are properly received.
235 */
236 @Test
237 public void testConfigurability() {
lberkiaea56b32017-05-30 12:35:33 +0200238 assertThat(
239 attr("foo_configurable", BuildType.LABEL_LIST)
240 .legacyAllowAnyFileType()
241 .build()
242 .isConfigurable())
243 .isTrue();
244 assertThat(
245 attr("foo_nonconfigurable", BuildType.LABEL_LIST)
246 .legacyAllowAnyFileType()
247 .nonconfigurable("test")
248 .build()
249 .isConfigurable())
250 .isFalse();
Ulf Adams83763ee2015-05-04 15:36:12 +0000251 }
Chris Parsons2e62c0d2016-04-19 22:13:59 +0000252
253 @Test
254 public void testSplitTransition() throws Exception {
255 TestSplitTransition splitTransition = new TestSplitTransition();
jcater98a09b62019-04-02 13:06:19 -0700256 Attribute attr =
257 attr("foo", LABEL).cfg(TransitionFactories.of(splitTransition)).allowedFileTypes().build();
jcatere8f5a982019-04-02 11:12:19 -0700258 assertThat(attr.getTransitionFactory().isSplit()).isTrue();
John Cater5adcd3e2019-03-28 10:14:32 -0700259 ConfigurationTransition transition =
John Cater2c0dece2019-04-02 09:18:18 -0700260 attr.getTransitionFactory()
jcater23589462019-05-20 08:51:24 -0700261 .create(
262 AttributeTransitionData.builder().attributes(FakeAttributeMapper.empty()).build());
John Cater5adcd3e2019-03-28 10:14:32 -0700263 assertThat(transition).isEqualTo(splitTransition);
Chris Parsons2e62c0d2016-04-19 22:13:59 +0000264 }
265
266 @Test
267 public void testSplitTransitionProvider() throws Exception {
268 TestSplitTransitionProvider splitTransitionProvider = new TestSplitTransitionProvider();
269 Attribute attr =
270 attr("foo", LABEL).cfg(splitTransitionProvider).allowedFileTypes().build();
jcatere8f5a982019-04-02 11:12:19 -0700271 assertThat(attr.getTransitionFactory().isSplit()).isTrue();
John Cater5adcd3e2019-03-28 10:14:32 -0700272 ConfigurationTransition transition =
John Cater2c0dece2019-04-02 09:18:18 -0700273 attr.getTransitionFactory()
jcater23589462019-05-20 08:51:24 -0700274 .create(
275 AttributeTransitionData.builder().attributes(FakeAttributeMapper.empty()).build());
John Cater5adcd3e2019-03-28 10:14:32 -0700276 assertThat(transition).isInstanceOf(TestSplitTransition.class);
Chris Parsons2e62c0d2016-04-19 22:13:59 +0000277 }
278
279 @Test
280 public void testHostTransition() throws Exception {
jcaterffb65c82019-03-29 07:52:16 -0700281 Attribute attr =
282 attr("foo", LABEL).cfg(HostTransition.createFactory()).allowedFileTypes().build();
jcaterb44167f2019-04-02 12:06:26 -0700283 assertThat(attr.getTransitionFactory().isHost()).isTrue();
jcatere8f5a982019-04-02 11:12:19 -0700284 assertThat(attr.getTransitionFactory().isSplit()).isFalse();
Chris Parsons2e62c0d2016-04-19 22:13:59 +0000285 }
286
gregce6bc35ed2017-12-22 11:51:39 -0800287 private static class TestSplitTransition implements SplitTransition {
Chris Parsons2e62c0d2016-04-19 22:13:59 +0000288 @Override
gregcea048f0f2020-06-11 15:10:01 -0700289 public Map<String, BuildOptions> split(
290 BuildOptionsView buildOptions, EventHandler eventHandler) {
291 return ImmutableMap.of(
292 "test0", buildOptions.clone().underlying(), "test1", buildOptions.clone().underlying());
Chris Parsons2e62c0d2016-04-19 22:13:59 +0000293 }
294 }
295
John Cater0a9e1ed2019-03-27 11:02:01 -0700296 private static class TestSplitTransitionProvider
John Cater2c0dece2019-04-02 09:18:18 -0700297 implements TransitionFactory<AttributeTransitionData> {
Chris Parsons2e62c0d2016-04-19 22:13:59 +0000298 @Override
John Cater2c0dece2019-04-02 09:18:18 -0700299 public SplitTransition create(AttributeTransitionData data) {
Chris Parsons2e62c0d2016-04-19 22:13:59 +0000300 return new TestSplitTransition();
301 }
cparsons21e25182019-01-15 16:00:26 -0800302
303 @Override
John Cater0a9e1ed2019-03-27 11:02:01 -0700304 public boolean isSplit() {
305 return true;
306 }
Chris Parsons2e62c0d2016-04-19 22:13:59 +0000307 }
gregceda4c9592017-07-27 22:09:34 +0200308
309 @Test
310 public void allowedRuleClassesAndAllowedRuleClassesWithWarningsCannotOverlap() throws Exception {
jcaterb9226772019-04-29 12:04:52 -0700311 IllegalStateException e =
312 assertThrows(
313 IllegalStateException.class,
314 () ->
315 attr("x", LABEL_LIST)
316 .allowedRuleClasses("foo", "bar", "baz")
317 .allowedRuleClassesWithWarning("bar")
318 .allowedFileTypes()
319 .build());
320 assertThat(e).hasMessageThat().contains("may not contain the same rule classes");
gregceda4c9592017-07-27 22:09:34 +0200321 }
Ulf Adams83763ee2015-05-04 15:36:12 +0000322}