blob: 2fe73f460e30a4a8c4f14faa31f6b9db5743558c [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;
gregce676a9572017-12-21 11:33:32 -080028import com.google.devtools.build.lib.analysis.config.HostTransition;
jcater98a09b62019-04-02 13:06:19 -070029import com.google.devtools.build.lib.analysis.config.TransitionFactories;
John Cater5adcd3e2019-03-28 10:14:32 -070030import com.google.devtools.build.lib.analysis.config.transitions.ConfigurationTransition;
gregce6bc35ed2017-12-22 11:51:39 -080031import com.google.devtools.build.lib.analysis.config.transitions.SplitTransition;
John Cater0a9e1ed2019-03-27 11:02:01 -070032import com.google.devtools.build.lib.analysis.config.transitions.TransitionFactory;
Carmi Grushko215fa842016-03-31 18:14:39 +000033import com.google.devtools.build.lib.analysis.util.TestAspects;
Lukacs Berki6e91eb92015-09-21 09:12:37 +000034import com.google.devtools.build.lib.cmdline.Label;
gregcef0a40ac2020-03-31 14:11:30 -070035import com.google.devtools.build.lib.events.EventHandler;
Googler72f3a102017-12-01 16:28:28 -080036import com.google.devtools.build.lib.packages.RuleClass.Builder.RuleClassNamePredicate;
John Cater0a9e1ed2019-03-27 11:02:01 -070037import com.google.devtools.build.lib.testutil.FakeAttributeMapper;
Ulf Adams83763ee2015-05-04 15:36:12 +000038import com.google.devtools.build.lib.util.FileType;
39import com.google.devtools.build.lib.util.FileTypeSet;
lberkiaea56b32017-05-30 12:35:33 +020040import java.util.Arrays;
41import java.util.Collections;
42import java.util.List;
Googler19226b72020-02-06 12:58:43 -080043import java.util.Map;
Ulf Adams83763ee2015-05-04 15:36:12 +000044import org.junit.Test;
45import org.junit.runner.RunWith;
46import org.junit.runners.JUnit4;
47
lberkiaea56b32017-05-30 12:35:33 +020048/** Tests of Attribute code. */
Ulf Adams83763ee2015-05-04 15:36:12 +000049@RunWith(JUnit4.class)
50public class AttributeTest {
51
52 private void assertDefaultValue(Object expected, Attribute attr) {
lberkiaea56b32017-05-30 12:35:33 +020053 assertThat(attr.getDefaultValue(null)).isEqualTo(expected);
Ulf Adams83763ee2015-05-04 15:36:12 +000054 }
55
56 private void assertType(Type<?> expectedType, Attribute attr) {
lberkiaea56b32017-05-30 12:35:33 +020057 assertThat(attr.getType()).isEqualTo(expectedType);
Ulf Adams83763ee2015-05-04 15:36:12 +000058 }
59
60 @Test
61 public void testBasics() throws Exception {
62 Attribute attr = attr("foo", Type.INTEGER).mandatory().value(3).build();
lberkiaea56b32017-05-30 12:35:33 +020063 assertThat(attr.getName()).isEqualTo("foo");
64 assertThat(attr.getDefaultValue(null)).isEqualTo(3);
65 assertThat(attr.getType()).isEqualTo(Type.INTEGER);
66 assertThat(attr.isMandatory()).isTrue();
67 assertThat(attr.isDocumented()).isTrue();
Ulf Adams83763ee2015-05-04 15:36:12 +000068 attr = attr("$foo", Type.INTEGER).build();
lberkiaea56b32017-05-30 12:35:33 +020069 assertThat(attr.isDocumented()).isFalse();
Ulf Adams83763ee2015-05-04 15:36:12 +000070 }
71
72 @Test
73 public void testNonEmptyReqiresListType() throws Exception {
jcaterb9226772019-04-29 12:04:52 -070074 NullPointerException e =
75 assertThrows(
76 NullPointerException.class,
77 () -> attr("foo", Type.INTEGER).nonEmpty().value(3).build());
78 assertThat(e).hasMessageThat().isEqualTo("attribute 'foo' must be a list");
Ulf Adams83763ee2015-05-04 15:36:12 +000079 }
80
81 @Test
82 public void testNonEmpty() throws Exception {
Lukacs Berkiffa73ad2015-09-18 11:40:12 +000083 Attribute attr = attr("foo", BuildType.LABEL_LIST).nonEmpty().legacyAllowAnyFileType().build();
lberkiaea56b32017-05-30 12:35:33 +020084 assertThat(attr.getName()).isEqualTo("foo");
85 assertThat(attr.getType()).isEqualTo(BuildType.LABEL_LIST);
86 assertThat(attr.isNonEmpty()).isTrue();
Ulf Adams83763ee2015-05-04 15:36:12 +000087 }
88
89 @Test
90 public void testSingleArtifactReqiresLabelType() throws Exception {
jcaterb9226772019-04-29 12:04:52 -070091 IllegalStateException e =
92 assertThrows(
93 IllegalStateException.class,
94 () -> attr("foo", Type.INTEGER).singleArtifact().value(3).build());
95 assertThat(e).hasMessageThat().isEqualTo("attribute 'foo' must be a label-valued type");
Ulf Adams83763ee2015-05-04 15:36:12 +000096 }
97
98 @Test
99 public void testDoublePropertySet() {
jcaterffb65c82019-03-29 07:52:16 -0700100 Attribute.Builder<String> builder =
101 attr("x", STRING)
102 .mandatory()
103 .cfg(HostTransition.createFactory())
104 .undocumented("")
105 .value("y");
jcaterb9226772019-04-29 12:04:52 -0700106 assertThrows(IllegalStateException.class, () -> builder.mandatory());
107 assertThrows(IllegalStateException.class, () -> builder.cfg(HostTransition.createFactory()));
108 assertThrows(IllegalStateException.class, () -> builder.undocumented(""));
109 assertThrows(IllegalStateException.class, () -> builder.value("z"));
Ulf Adams83763ee2015-05-04 15:36:12 +0000110
jcaterb9226772019-04-29 12:04:52 -0700111 Attribute.Builder<String> builder2 = attr("$x", STRING);
112 assertThrows(IllegalStateException.class, () -> builder2.undocumented(""));
Ulf Adams83763ee2015-05-04 15:36:12 +0000113 }
114
115 /**
116 * Tests the "convenience factories" (string, label, etc) for default
117 * values.
118 */
119 @Test
120 public void testConvenienceFactoriesDefaultValues() throws Exception {
121 assertDefaultValue(0,
122 attr("x", INTEGER).build());
123 assertDefaultValue(42,
124 attr("x", INTEGER).value(42).build());
125
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());
160 assertType(INTEGER,
161 attr("x", INTEGER).value(42).build());
162
163 assertType(STRING,
164 attr("x", STRING).build());
165 assertType(STRING,
166 attr("x", STRING).value("foo").build());
167
dannark90e2b4b2018-06-27 13:35:04 -0700168 Label label = Label.parseAbsolute("//foo:bar", ImmutableMap.of());
Ulf Adams83763ee2015-05-04 15:36:12 +0000169 assertType(LABEL,
170 attr("x", LABEL).legacyAllowAnyFileType().build());
171 assertType(LABEL,
172 attr("x", LABEL).legacyAllowAnyFileType().value(label).build());
173
174 List<String> slist = Arrays.asList("foo", "bar");
175 assertType(STRING_LIST,
176 attr("x", STRING_LIST).build());
177 assertType(STRING_LIST,
178 attr("x", STRING_LIST).value(slist).build());
179
dannark90e2b4b2018-06-27 13:35:04 -0700180 List<Label> llist =
181 Arrays.asList(
182 Label.parseAbsolute("//foo:bar", ImmutableMap.of()),
183 Label.parseAbsolute("//foo:wiz", ImmutableMap.of()));
Ulf Adams83763ee2015-05-04 15:36:12 +0000184 assertType(LABEL_LIST,
185 attr("x", LABEL_LIST).legacyAllowAnyFileType().build());
186 assertType(LABEL_LIST,
187 attr("x", LABEL_LIST).legacyAllowAnyFileType().value(llist).build());
188 }
189
190 @Test
191 public void testCloneBuilder() {
192 FileTypeSet txtFiles = FileTypeSet.of(FileType.of("txt"));
Googler72f3a102017-12-01 16:28:28 -0800193 RuleClassNamePredicate ruleClasses = RuleClassNamePredicate.only("mock_rule");
Han-Wen Nienhuys3428dc92015-10-21 15:03:34 +0000194
Carmi Grushko215fa842016-03-31 18:14:39 +0000195 Attribute parentAttr =
196 attr("x", LABEL_LIST)
197 .allowedFileTypes(txtFiles)
198 .mandatory()
Luis Fernando Pino Duquee82713d2016-04-26 16:22:38 +0000199 .aspect(TestAspects.SIMPLE_ASPECT)
Carmi Grushko215fa842016-03-31 18:14:39 +0000200 .build();
Han-Wen Nienhuys3428dc92015-10-21 15:03:34 +0000201
Carmi Grushko215fa842016-03-31 18:14:39 +0000202 {
203 Attribute childAttr1 = parentAttr.cloneBuilder().build();
lberkiaea56b32017-05-30 12:35:33 +0200204 assertThat(childAttr1.getName()).isEqualTo("x");
205 assertThat(childAttr1.getAllowedFileTypesPredicate()).isEqualTo(txtFiles);
206 assertThat(childAttr1.getAllowedRuleClassesPredicate()).isEqualTo(Predicates.alwaysTrue());
207 assertThat(childAttr1.isMandatory()).isTrue();
208 assertThat(childAttr1.isNonEmpty()).isFalse();
cushon8c6b7ab2018-04-27 01:25:50 -0700209 assertThat(childAttr1.getAspects(/* rule= */ null)).hasSize(1);
Carmi Grushko215fa842016-03-31 18:14:39 +0000210 }
Ulf Adams83763ee2015-05-04 15:36:12 +0000211
Carmi Grushko215fa842016-03-31 18:14:39 +0000212 {
213 Attribute childAttr2 =
214 parentAttr
215 .cloneBuilder()
216 .nonEmpty()
217 .allowedRuleClasses(ruleClasses)
Luis Fernando Pino Duquee82713d2016-04-26 16:22:38 +0000218 .aspect(TestAspects.ERROR_ASPECT)
Carmi Grushko215fa842016-03-31 18:14:39 +0000219 .build();
lberkiaea56b32017-05-30 12:35:33 +0200220 assertThat(childAttr2.getName()).isEqualTo("x");
221 assertThat(childAttr2.getAllowedFileTypesPredicate()).isEqualTo(txtFiles);
Googler72f3a102017-12-01 16:28:28 -0800222 assertThat(childAttr2.getAllowedRuleClassesPredicate())
223 .isEqualTo(ruleClasses.asPredicateOfRuleClass());
lberkiaea56b32017-05-30 12:35:33 +0200224 assertThat(childAttr2.isMandatory()).isTrue();
225 assertThat(childAttr2.isNonEmpty()).isTrue();
cushon8c6b7ab2018-04-27 01:25:50 -0700226 assertThat(childAttr2.getAspects(/* rule= */ null)).hasSize(2);
Carmi Grushko215fa842016-03-31 18:14:39 +0000227 }
Ulf Adams83763ee2015-05-04 15:36:12 +0000228
lberkiaea56b32017-05-30 12:35:33 +0200229 // Check if the parent attribute is unchanged
230 assertThat(parentAttr.isNonEmpty()).isFalse();
231 assertThat(parentAttr.getAllowedRuleClassesPredicate()).isEqualTo(Predicates.alwaysTrue());
Ulf Adams83763ee2015-05-04 15:36:12 +0000232 }
233
234 /**
235 * Tests that configurability settings are properly received.
236 */
237 @Test
238 public void testConfigurability() {
lberkiaea56b32017-05-30 12:35:33 +0200239 assertThat(
240 attr("foo_configurable", BuildType.LABEL_LIST)
241 .legacyAllowAnyFileType()
242 .build()
243 .isConfigurable())
244 .isTrue();
245 assertThat(
246 attr("foo_nonconfigurable", BuildType.LABEL_LIST)
247 .legacyAllowAnyFileType()
248 .nonconfigurable("test")
249 .build()
250 .isConfigurable())
251 .isFalse();
Ulf Adams83763ee2015-05-04 15:36:12 +0000252 }
Chris Parsons2e62c0d2016-04-19 22:13:59 +0000253
254 @Test
255 public void testSplitTransition() throws Exception {
256 TestSplitTransition splitTransition = new TestSplitTransition();
jcater98a09b62019-04-02 13:06:19 -0700257 Attribute attr =
258 attr("foo", LABEL).cfg(TransitionFactories.of(splitTransition)).allowedFileTypes().build();
jcatere8f5a982019-04-02 11:12:19 -0700259 assertThat(attr.getTransitionFactory().isSplit()).isTrue();
John Cater5adcd3e2019-03-28 10:14:32 -0700260 ConfigurationTransition transition =
John Cater2c0dece2019-04-02 09:18:18 -0700261 attr.getTransitionFactory()
jcater23589462019-05-20 08:51:24 -0700262 .create(
263 AttributeTransitionData.builder().attributes(FakeAttributeMapper.empty()).build());
John Cater5adcd3e2019-03-28 10:14:32 -0700264 assertThat(transition).isEqualTo(splitTransition);
Chris Parsons2e62c0d2016-04-19 22:13:59 +0000265 }
266
267 @Test
268 public void testSplitTransitionProvider() throws Exception {
269 TestSplitTransitionProvider splitTransitionProvider = new TestSplitTransitionProvider();
270 Attribute attr =
271 attr("foo", LABEL).cfg(splitTransitionProvider).allowedFileTypes().build();
jcatere8f5a982019-04-02 11:12:19 -0700272 assertThat(attr.getTransitionFactory().isSplit()).isTrue();
John Cater5adcd3e2019-03-28 10:14:32 -0700273 ConfigurationTransition transition =
John Cater2c0dece2019-04-02 09:18:18 -0700274 attr.getTransitionFactory()
jcater23589462019-05-20 08:51:24 -0700275 .create(
276 AttributeTransitionData.builder().attributes(FakeAttributeMapper.empty()).build());
John Cater5adcd3e2019-03-28 10:14:32 -0700277 assertThat(transition).isInstanceOf(TestSplitTransition.class);
Chris Parsons2e62c0d2016-04-19 22:13:59 +0000278 }
279
280 @Test
281 public void testHostTransition() throws Exception {
jcaterffb65c82019-03-29 07:52:16 -0700282 Attribute attr =
283 attr("foo", LABEL).cfg(HostTransition.createFactory()).allowedFileTypes().build();
jcaterb44167f2019-04-02 12:06:26 -0700284 assertThat(attr.getTransitionFactory().isHost()).isTrue();
jcatere8f5a982019-04-02 11:12:19 -0700285 assertThat(attr.getTransitionFactory().isSplit()).isFalse();
Chris Parsons2e62c0d2016-04-19 22:13:59 +0000286 }
287
gregce6bc35ed2017-12-22 11:51:39 -0800288 private static class TestSplitTransition implements SplitTransition {
Chris Parsons2e62c0d2016-04-19 22:13:59 +0000289 @Override
gregcef0a40ac2020-03-31 14:11:30 -0700290 public Map<String, BuildOptions> split(BuildOptions buildOptions, EventHandler eventHandler) {
Googler19226b72020-02-06 12:58:43 -0800291 return ImmutableMap.of("test0", buildOptions.clone(), "test1", buildOptions.clone());
Chris Parsons2e62c0d2016-04-19 22:13:59 +0000292 }
293 }
294
John Cater0a9e1ed2019-03-27 11:02:01 -0700295 private static class TestSplitTransitionProvider
John Cater2c0dece2019-04-02 09:18:18 -0700296 implements TransitionFactory<AttributeTransitionData> {
Chris Parsons2e62c0d2016-04-19 22:13:59 +0000297 @Override
John Cater2c0dece2019-04-02 09:18:18 -0700298 public SplitTransition create(AttributeTransitionData data) {
Chris Parsons2e62c0d2016-04-19 22:13:59 +0000299 return new TestSplitTransition();
300 }
cparsons21e25182019-01-15 16:00:26 -0800301
302 @Override
John Cater0a9e1ed2019-03-27 11:02:01 -0700303 public boolean isSplit() {
304 return true;
305 }
Chris Parsons2e62c0d2016-04-19 22:13:59 +0000306 }
gregceda4c9592017-07-27 22:09:34 +0200307
308 @Test
309 public void allowedRuleClassesAndAllowedRuleClassesWithWarningsCannotOverlap() throws Exception {
jcaterb9226772019-04-29 12:04:52 -0700310 IllegalStateException e =
311 assertThrows(
312 IllegalStateException.class,
313 () ->
314 attr("x", LABEL_LIST)
315 .allowedRuleClasses("foo", "bar", "baz")
316 .allowedRuleClassesWithWarning("bar")
317 .allowedFileTypes()
318 .build());
319 assertThat(e).hasMessageThat().contains("may not contain the same rule classes");
gregceda4c9592017-07-27 22:09:34 +0200320 }
Ulf Adams83763ee2015-05-04 15:36:12 +0000321}