blob: a7fe80942f7055e19f4c825ddf47c2fe2f14911f [file] [log] [blame]
Michael Staibb51251e2015-09-29 23:31:51 +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;
17import static com.google.common.truth.Truth.assertWithMessage;
18import static com.google.devtools.build.lib.packages.Attribute.attr;
Lukacs Berkiffa73ad2015-09-18 11:40:12 +000019import static com.google.devtools.build.lib.packages.BuildType.LABEL;
20import static com.google.devtools.build.lib.packages.BuildType.LABEL_LIST;
21import static com.google.devtools.build.lib.packages.BuildType.OUTPUT_LIST;
Ulf Adams83763ee2015-05-04 15:36:12 +000022import static com.google.devtools.build.lib.packages.ImplicitOutputsFunction.substitutePlaceholderIntoTemplate;
gregce74d84d42020-04-17 10:02:03 -070023import static com.google.devtools.build.lib.packages.RuleClass.Builder.STARLARK_BUILD_SETTING_DEFAULT_ATTR_NAME;
Lukacs Berki0e1a9942015-06-18 08:53:18 +000024import static com.google.devtools.build.lib.packages.RuleClass.NO_EXTERNAL_BINDINGS;
John Cater39401a92020-07-09 10:12:55 -070025import static com.google.devtools.build.lib.packages.RuleClass.NO_TOOLCHAINS_TO_REGISTER;
Googlerc5fcc862019-09-06 16:17:47 -070026import static com.google.devtools.build.lib.packages.Type.BOOLEAN;
27import static com.google.devtools.build.lib.packages.Type.INTEGER;
28import static com.google.devtools.build.lib.packages.Type.STRING;
29import static com.google.devtools.build.lib.packages.Type.STRING_LIST;
michajlo660d17f2020-03-27 09:01:57 -070030import static org.junit.Assert.assertThrows;
Florian Weikert432d1982015-12-01 14:38:06 +000031import static org.junit.Assert.fail;
Ulf Adams83763ee2015-05-04 15:36:12 +000032
Ulf Adams83763ee2015-05-04 15:36:12 +000033import com.google.common.base.Predicate;
34import com.google.common.base.Predicates;
michajlo0a89cef2020-04-06 12:04:12 -070035import com.google.common.base.Strings;
Ulf Adams83763ee2015-05-04 15:36:12 +000036import com.google.common.collect.ImmutableList;
37import com.google.common.collect.ImmutableMap;
38import com.google.common.collect.ImmutableSet;
39import com.google.common.collect.Iterables;
40import com.google.common.collect.Lists;
cparsonse2d200f2018-03-06 16:15:11 -080041import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
jcatera666f002020-04-14 14:55:20 -070042import com.google.devtools.build.lib.analysis.config.Fragment;
John Caterb3b3e8b2019-04-03 09:18:42 -070043import com.google.devtools.build.lib.analysis.config.transitions.TransitionFactory;
Lukacs Berki6e91eb92015-09-21 09:12:37 +000044import com.google.devtools.build.lib.cmdline.Label;
Lukacs Berkia6434362015-09-15 13:56:14 +000045import com.google.devtools.build.lib.cmdline.LabelSyntaxException;
Kristina Chodorow73fa2032015-08-28 17:57:46 +000046import com.google.devtools.build.lib.cmdline.PackageIdentifier;
Ulf Adams83763ee2015-05-04 15:36:12 +000047import com.google.devtools.build.lib.events.Event;
48import com.google.devtools.build.lib.events.EventCollector;
49import com.google.devtools.build.lib.events.EventKind;
gregce18694cd2020-05-12 15:40:05 -070050import com.google.devtools.build.lib.packages.Attribute.StarlarkComputedDefaultTemplate.CannotPrecomputeDefaultsException;
Ulf Adams83763ee2015-05-04 15:36:12 +000051import com.google.devtools.build.lib.packages.Attribute.ValidityPredicate;
Michael Staibb51251e2015-09-29 23:31:51 +000052import com.google.devtools.build.lib.packages.ConfigurationFragmentPolicy.MissingFragmentPolicy;
Ulf Adams83763ee2015-05-04 15:36:12 +000053import com.google.devtools.build.lib.packages.RuleClass.Builder.RuleClassType;
gregce4aa059a2019-02-26 13:20:47 -080054import com.google.devtools.build.lib.packages.RuleClass.Builder.ThirdPartyLicenseExistencePolicy;
Janak Ramakrishnan3be65b82016-05-18 15:53:10 +000055import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory;
Mark Schalleree624452016-01-13 18:41:24 +000056import com.google.devtools.build.lib.packages.RuleFactory.BuildLangTypedAttributeValuesMap;
Florian Weikertcca703a2015-12-07 09:56:38 +000057import com.google.devtools.build.lib.packages.util.PackageLoadingTestCase;
adonovanf5262c52020-04-02 09:25:14 -070058import com.google.devtools.build.lib.syntax.Location;
adonovanf3a344e82019-12-11 11:10:11 -080059import com.google.devtools.build.lib.syntax.StarlarkFunction;
Klaus Aehlig2bb1bf92019-10-31 10:28:44 -070060import com.google.devtools.build.lib.syntax.StarlarkSemantics;
Googlera3421e22019-09-26 06:48:32 -070061import com.google.devtools.build.lib.syntax.StarlarkThread;
Ulf Adams83763ee2015-05-04 15:36:12 +000062import com.google.devtools.build.lib.vfs.Path;
janakr518bb872018-10-03 15:59:28 -070063import com.google.devtools.build.lib.vfs.RootedPath;
Ulf Adams83763ee2015-05-04 15:36:12 +000064import java.util.ArrayList;
65import java.util.Arrays;
66import java.util.Collections;
67import java.util.HashMap;
68import java.util.HashSet;
69import java.util.Iterator;
70import java.util.LinkedHashMap;
71import java.util.List;
72import java.util.Map;
73import java.util.Set;
Janak Ramakrishnan3be65b82016-05-18 15:53:10 +000074import javax.annotation.Nullable;
Florian Weikertea6c82d2016-09-05 12:15:31 +000075import org.junit.Before;
76import org.junit.Test;
77import org.junit.runner.RunWith;
78import org.junit.runners.JUnit4;
Janak Ramakrishnan3be65b82016-05-18 15:53:10 +000079
Ulf Adams83763ee2015-05-04 15:36:12 +000080/**
81 * Tests for {@link RuleClass}.
82 */
Florian Weikert432d1982015-12-01 14:38:06 +000083@RunWith(JUnit4.class)
Florian Weikertcca703a2015-12-07 09:56:38 +000084public class RuleClassTest extends PackageLoadingTestCase {
cparsonse2d200f2018-03-06 16:15:11 -080085 private static final RuleClass.ConfiguredTargetFactory<Object, Object, Exception>
86 DUMMY_CONFIGURED_TARGET_FACTORY =
87 new RuleClass.ConfiguredTargetFactory<Object, Object, Exception>() {
88 @Override
89 public Object create(Object ruleContext)
90 throws InterruptedException, RuleErrorException, ActionConflictException {
91 throw new IllegalStateException();
92 }
93 };
Ulf Adams83763ee2015-05-04 15:36:12 +000094
adonovanebb86fc2020-03-20 14:57:54 -070095 private static final ImmutableList<StarlarkThread.CallStackEntry> DUMMY_STACK =
96 ImmutableList.of(
97 new StarlarkThread.CallStackEntry(
98 "<toplevel>", Location.fromFileLineColumn("BUILD", 10, 1)),
99 new StarlarkThread.CallStackEntry("bar", Location.fromFileLineColumn("bar.bzl", 42, 1)),
100 new StarlarkThread.CallStackEntry("rule", Location.BUILTIN));
101
jcatera666f002020-04-14 14:55:20 -0700102 private static final class DummyFragment extends Fragment {}
Ulf Adams83763ee2015-05-04 15:36:12 +0000103
adonovan40a737c2020-03-11 14:32:19 -0700104 private static final ImmutableList<StarlarkThread.CallStackEntry> NO_STACK = ImmutableList.of();
Ulf Adams83763ee2015-05-04 15:36:12 +0000105
106 private static final Predicate<String> PREFERRED_DEPENDENCY_PREDICATE = Predicates.alwaysFalse();
107
Lukacs Berkia6434362015-09-15 13:56:14 +0000108 private static RuleClass createRuleClassA() throws LabelSyntaxException {
Janak Ramakrishnan3be65b82016-05-18 15:53:10 +0000109 return newRuleClass(
110 "ruleA",
111 false,
112 false,
113 false,
114 false,
115 false,
116 false,
cparsons55781c92018-10-17 12:03:08 -0700117 false,
Janak Ramakrishnan3be65b82016-05-18 15:53:10 +0000118 ImplicitOutputsFunction.NONE,
Cal Peyser19dda252017-01-11 23:37:05 +0000119 null,
Janak Ramakrishnan3be65b82016-05-18 15:53:10 +0000120 DUMMY_CONFIGURED_TARGET_FACTORY,
121 PredicatesWithMessage.<Rule>alwaysTrue(),
122 PREFERRED_DEPENDENCY_PREDICATE,
Dmitry Lomovb91d3922017-01-09 20:12:57 +0000123 AdvertisedProviderSet.EMPTY,
Janak Ramakrishnan3be65b82016-05-18 15:53:10 +0000124 null,
Janak Ramakrishnan3be65b82016-05-18 15:53:10 +0000125 ImmutableSet.<Class<?>>of(),
126 MissingFragmentPolicy.FAIL_ANALYSIS,
127 true,
Ulf Adams83763ee2015-05-04 15:36:12 +0000128 attr("my-string-attr", STRING).mandatory().build(),
Janak Ramakrishnan3be65b82016-05-18 15:53:10 +0000129 attr("my-label-attr", LABEL)
130 .mandatory()
131 .legacyAllowAnyFileType()
dannark90e2b4b2018-06-27 13:35:04 -0700132 .value(Label.parseAbsolute("//default:label", ImmutableMap.of()))
Janak Ramakrishnan3be65b82016-05-18 15:53:10 +0000133 .build(),
Ulf Adams83763ee2015-05-04 15:36:12 +0000134 attr("my-labellist-attr", LABEL_LIST).mandatory().legacyAllowAnyFileType().build(),
135 attr("my-integer-attr", INTEGER).value(42).build(),
136 attr("my-string-attr2", STRING).mandatory().value((String) null).build(),
137 attr("my-stringlist-attr", STRING_LIST).build(),
138 attr("my-sorted-stringlist-attr", STRING_LIST).orderIndependent().build());
139 }
140
141 private static RuleClass createRuleClassB(RuleClass ruleClassA) {
142 // emulates attribute inheritance
143 List<Attribute> attributes = new ArrayList<>(ruleClassA.getAttributes());
144 attributes.add(attr("another-string-attr", STRING).mandatory().build());
Janak Ramakrishnan3be65b82016-05-18 15:53:10 +0000145 return newRuleClass(
146 "ruleB",
147 false,
148 false,
149 false,
150 false,
151 false,
152 false,
cparsons55781c92018-10-17 12:03:08 -0700153 false,
Janak Ramakrishnan3be65b82016-05-18 15:53:10 +0000154 ImplicitOutputsFunction.NONE,
Cal Peyser19dda252017-01-11 23:37:05 +0000155 null,
Janak Ramakrishnan3be65b82016-05-18 15:53:10 +0000156 DUMMY_CONFIGURED_TARGET_FACTORY,
157 PredicatesWithMessage.<Rule>alwaysTrue(),
158 PREFERRED_DEPENDENCY_PREDICATE,
Dmitry Lomovb91d3922017-01-09 20:12:57 +0000159 AdvertisedProviderSet.EMPTY,
Janak Ramakrishnan3be65b82016-05-18 15:53:10 +0000160 null,
Janak Ramakrishnan3be65b82016-05-18 15:53:10 +0000161 ImmutableSet.<Class<?>>of(),
162 MissingFragmentPolicy.FAIL_ANALYSIS,
163 true,
Lukacs Berki549bfce2016-04-22 15:29:12 +0000164 attributes.toArray(new Attribute[0]));
Ulf Adams83763ee2015-05-04 15:36:12 +0000165 }
166
Florian Weikert432d1982015-12-01 14:38:06 +0000167 @Test
Ulf Adams83763ee2015-05-04 15:36:12 +0000168 public void testRuleClassBasics() throws Exception {
169 RuleClass ruleClassA = createRuleClassA();
170
lberkiaea56b32017-05-30 12:35:33 +0200171 assertThat(ruleClassA.getName()).isEqualTo("ruleA");
172 assertThat(ruleClassA.getAttributeCount()).isEqualTo(7);
Ulf Adams83763ee2015-05-04 15:36:12 +0000173
lberkiaea56b32017-05-30 12:35:33 +0200174 assertThat((int) ruleClassA.getAttributeIndex("my-string-attr")).isEqualTo(0);
175 assertThat((int) ruleClassA.getAttributeIndex("my-label-attr")).isEqualTo(1);
176 assertThat((int) ruleClassA.getAttributeIndex("my-labellist-attr")).isEqualTo(2);
177 assertThat((int) ruleClassA.getAttributeIndex("my-integer-attr")).isEqualTo(3);
178 assertThat((int) ruleClassA.getAttributeIndex("my-string-attr2")).isEqualTo(4);
179 assertThat((int) ruleClassA.getAttributeIndex("my-stringlist-attr")).isEqualTo(5);
180 assertThat((int) ruleClassA.getAttributeIndex("my-sorted-stringlist-attr")).isEqualTo(6);
Ulf Adams83763ee2015-05-04 15:36:12 +0000181
lberkiaea56b32017-05-30 12:35:33 +0200182 assertThat(ruleClassA.getAttributeByName("my-string-attr"))
183 .isEqualTo(ruleClassA.getAttribute(0));
184 assertThat(ruleClassA.getAttributeByName("my-label-attr"))
185 .isEqualTo(ruleClassA.getAttribute(1));
186 assertThat(ruleClassA.getAttributeByName("my-labellist-attr"))
187 .isEqualTo(ruleClassA.getAttribute(2));
188 assertThat(ruleClassA.getAttributeByName("my-integer-attr"))
189 .isEqualTo(ruleClassA.getAttribute(3));
190 assertThat(ruleClassA.getAttributeByName("my-string-attr2"))
191 .isEqualTo(ruleClassA.getAttribute(4));
192 assertThat(ruleClassA.getAttributeByName("my-stringlist-attr"))
193 .isEqualTo(ruleClassA.getAttribute(5));
194 assertThat(ruleClassA.getAttributeByName("my-sorted-stringlist-attr"))
195 .isEqualTo(ruleClassA.getAttribute(6));
Ulf Adams83763ee2015-05-04 15:36:12 +0000196
lberkie355e772017-05-31 14:34:53 +0200197 // default based on type
198 assertThat(ruleClassA.getAttribute(0).getDefaultValue(null)).isEqualTo("");
lberkiaea56b32017-05-30 12:35:33 +0200199 assertThat(ruleClassA.getAttribute(1).getDefaultValue(null))
dannark90e2b4b2018-06-27 13:35:04 -0700200 .isEqualTo(Label.parseAbsolute("//default:label", ImmutableMap.of()));
lberkiaea56b32017-05-30 12:35:33 +0200201 assertThat(ruleClassA.getAttribute(2).getDefaultValue(null)).isEqualTo(Collections.emptyList());
202 assertThat(ruleClassA.getAttribute(3).getDefaultValue(null)).isEqualTo(42);
lberkie355e772017-05-31 14:34:53 +0200203 // default explicitly specified
204 assertThat(ruleClassA.getAttribute(4).getDefaultValue(null)).isNull();
lberkiaea56b32017-05-30 12:35:33 +0200205 assertThat(ruleClassA.getAttribute(5).getDefaultValue(null)).isEqualTo(Collections.emptyList());
206 assertThat(ruleClassA.getAttribute(6).getDefaultValue(null)).isEqualTo(Collections.emptyList());
Ulf Adams83763ee2015-05-04 15:36:12 +0000207 }
208
Florian Weikert432d1982015-12-01 14:38:06 +0000209 @Test
Ulf Adams83763ee2015-05-04 15:36:12 +0000210 public void testRuleClassInheritance() throws Exception {
211 RuleClass ruleClassA = createRuleClassA();
212 RuleClass ruleClassB = createRuleClassB(ruleClassA);
213
lberkiaea56b32017-05-30 12:35:33 +0200214 assertThat(ruleClassB.getName()).isEqualTo("ruleB");
215 assertThat(ruleClassB.getAttributeCount()).isEqualTo(8);
Ulf Adams83763ee2015-05-04 15:36:12 +0000216
lberkiaea56b32017-05-30 12:35:33 +0200217 assertThat((int) ruleClassB.getAttributeIndex("my-string-attr")).isEqualTo(0);
218 assertThat((int) ruleClassB.getAttributeIndex("my-label-attr")).isEqualTo(1);
219 assertThat((int) ruleClassB.getAttributeIndex("my-labellist-attr")).isEqualTo(2);
220 assertThat((int) ruleClassB.getAttributeIndex("my-integer-attr")).isEqualTo(3);
221 assertThat((int) ruleClassB.getAttributeIndex("my-string-attr2")).isEqualTo(4);
222 assertThat((int) ruleClassB.getAttributeIndex("my-stringlist-attr")).isEqualTo(5);
223 assertThat((int) ruleClassB.getAttributeIndex("my-sorted-stringlist-attr")).isEqualTo(6);
224 assertThat((int) ruleClassB.getAttributeIndex("another-string-attr")).isEqualTo(7);
Ulf Adams83763ee2015-05-04 15:36:12 +0000225
lberkiaea56b32017-05-30 12:35:33 +0200226 assertThat(ruleClassB.getAttributeByName("my-string-attr"))
227 .isEqualTo(ruleClassB.getAttribute(0));
228 assertThat(ruleClassB.getAttributeByName("my-label-attr"))
229 .isEqualTo(ruleClassB.getAttribute(1));
230 assertThat(ruleClassB.getAttributeByName("my-labellist-attr"))
231 .isEqualTo(ruleClassB.getAttribute(2));
232 assertThat(ruleClassB.getAttributeByName("my-integer-attr"))
233 .isEqualTo(ruleClassB.getAttribute(3));
234 assertThat(ruleClassB.getAttributeByName("my-string-attr2"))
235 .isEqualTo(ruleClassB.getAttribute(4));
236 assertThat(ruleClassB.getAttributeByName("my-stringlist-attr"))
237 .isEqualTo(ruleClassB.getAttribute(5));
238 assertThat(ruleClassB.getAttributeByName("my-sorted-stringlist-attr"))
239 .isEqualTo(ruleClassB.getAttribute(6));
240 assertThat(ruleClassB.getAttributeByName("another-string-attr"))
241 .isEqualTo(ruleClassB.getAttribute(7));
Ulf Adams83763ee2015-05-04 15:36:12 +0000242 }
243
244 private static final String TEST_PACKAGE_NAME = "testpackage";
245
246 private static final String TEST_RULE_NAME = "my-rule-A";
247
248 private static final int TEST_RULE_DEFINED_AT_LINE = 42;
249
Brian Silvermand7d6d622016-03-17 09:53:39 +0000250 private static final String TEST_RULE_LABEL = "@//" + TEST_PACKAGE_NAME + ":" + TEST_RULE_NAME;
Ulf Adams83763ee2015-05-04 15:36:12 +0000251
252 private Path testBuildfilePath;
253 private Location testRuleLocation;
254
Florian Weikert432d1982015-12-01 14:38:06 +0000255 @Before
256 public final void setRuleLocation() throws Exception {
janakr518bb872018-10-03 15:59:28 -0700257 testBuildfilePath = root.getRelative("testpackage/BUILD");
adonovan22096af2020-01-08 07:09:52 -0800258 testRuleLocation =
259 Location.fromFileLineColumn(testBuildfilePath.toString(), TEST_RULE_DEFINED_AT_LINE, 0);
Ulf Adams83763ee2015-05-04 15:36:12 +0000260 }
261
262 private Package.Builder createDummyPackageBuilder() {
janakr518bb872018-10-03 15:59:28 -0700263 return packageFactory
Klaus Aehlig2bb1bf92019-10-31 10:28:44 -0700264 .newPackageBuilder(
265 PackageIdentifier.createInMainRepo(TEST_PACKAGE_NAME),
266 "TESTING",
adonovanb85d0b72020-05-08 11:59:19 -0700267 StarlarkSemantics.DEFAULT)
janakr518bb872018-10-03 15:59:28 -0700268 .setFilename(RootedPath.toRootedPath(root, testBuildfilePath));
Ulf Adams83763ee2015-05-04 15:36:12 +0000269 }
270
Florian Weikert432d1982015-12-01 14:38:06 +0000271 @Test
Ulf Adams83763ee2015-05-04 15:36:12 +0000272 public void testDuplicatedDeps() throws Exception {
Janak Ramakrishnan3be65b82016-05-18 15:53:10 +0000273 RuleClass depsRuleClass =
274 newRuleClass(
275 "ruleDeps",
276 false,
277 false,
278 false,
279 false,
280 false,
281 false,
cparsons55781c92018-10-17 12:03:08 -0700282 false,
Janak Ramakrishnan3be65b82016-05-18 15:53:10 +0000283 ImplicitOutputsFunction.NONE,
Cal Peyser19dda252017-01-11 23:37:05 +0000284 null,
Janak Ramakrishnan3be65b82016-05-18 15:53:10 +0000285 DUMMY_CONFIGURED_TARGET_FACTORY,
286 PredicatesWithMessage.<Rule>alwaysTrue(),
287 PREFERRED_DEPENDENCY_PREDICATE,
Dmitry Lomovb91d3922017-01-09 20:12:57 +0000288 AdvertisedProviderSet.EMPTY,
Janak Ramakrishnan3be65b82016-05-18 15:53:10 +0000289 null,
Janak Ramakrishnan3be65b82016-05-18 15:53:10 +0000290 ImmutableSet.<Class<?>>of(),
291 MissingFragmentPolicy.FAIL_ANALYSIS,
292 true,
293 attr("list1", LABEL_LIST).mandatory().legacyAllowAnyFileType().build(),
294 attr("list2", LABEL_LIST).mandatory().legacyAllowAnyFileType().build(),
295 attr("list3", LABEL_LIST).mandatory().legacyAllowAnyFileType().build());
Ulf Adams83763ee2015-05-04 15:36:12 +0000296
297 // LinkedHashMap -> predictable iteration order for testing
298 Map<String, Object> attributeValues = new LinkedHashMap<>();
299 attributeValues.put("list1", Lists.newArrayList("//testpackage:dup1", ":dup1", ":nodup"));
300 attributeValues.put("list2", Lists.newArrayList(":nodup1", ":nodup2"));
301 attributeValues.put("list3", Lists.newArrayList(":dup1", ":dup1", ":dup2", ":dup2"));
302
303 reporter.removeHandler(failFastHandler);
adonovan40a737c2020-03-11 14:32:19 -0700304 createRule(depsRuleClass, "depsRule", attributeValues, testRuleLocation, NO_STACK);
Ulf Adams83763ee2015-05-04 15:36:12 +0000305
cpovirka4d3da62019-05-02 14:27:33 -0700306 assertThat(eventCollector.count()).isSameInstanceAs(3);
Ulf Adams83763ee2015-05-04 15:36:12 +0000307 assertDupError("//testpackage:dup1", "list1", "depsRule");
308 assertDupError("//testpackage:dup1", "list3", "depsRule");
309 assertDupError("//testpackage:dup2", "list3", "depsRule");
310 }
311
312 private void assertDupError(String label, String attrName, String ruleName) {
313 assertContainsEvent(String.format("Label '%s' is duplicated in the '%s' attribute of rule '%s'",
314 label, attrName, ruleName));
315 }
316
Florian Weikert432d1982015-12-01 14:38:06 +0000317 @Test
Ulf Adams83763ee2015-05-04 15:36:12 +0000318 public void testCreateRuleWithLegacyPublicVisibility() throws Exception {
Janak Ramakrishnan3be65b82016-05-18 15:53:10 +0000319 RuleClass ruleClass =
320 newRuleClass(
321 "ruleVis",
322 false,
323 false,
324 false,
325 false,
326 false,
327 false,
cparsons55781c92018-10-17 12:03:08 -0700328 false,
Janak Ramakrishnan3be65b82016-05-18 15:53:10 +0000329 ImplicitOutputsFunction.NONE,
Cal Peyser19dda252017-01-11 23:37:05 +0000330 null,
Janak Ramakrishnan3be65b82016-05-18 15:53:10 +0000331 DUMMY_CONFIGURED_TARGET_FACTORY,
332 PredicatesWithMessage.<Rule>alwaysTrue(),
333 PREFERRED_DEPENDENCY_PREDICATE,
Dmitry Lomovb91d3922017-01-09 20:12:57 +0000334 AdvertisedProviderSet.EMPTY,
Janak Ramakrishnan3be65b82016-05-18 15:53:10 +0000335 null,
Janak Ramakrishnan3be65b82016-05-18 15:53:10 +0000336 ImmutableSet.<Class<?>>of(),
337 MissingFragmentPolicy.FAIL_ANALYSIS,
338 true,
339 attr("visibility", LABEL_LIST).legacyAllowAnyFileType().build());
Ulf Adams83763ee2015-05-04 15:36:12 +0000340 Map<String, Object> attributeValues = new HashMap<>();
341 attributeValues.put("visibility", Arrays.asList("//visibility:legacy_public"));
342
343 reporter.removeHandler(failFastHandler);
344 EventCollector collector = new EventCollector(EventKind.ERRORS);
345 reporter.addHandler(collector);
346
adonovan40a737c2020-03-11 14:32:19 -0700347 createRule(ruleClass, TEST_RULE_NAME, attributeValues, testRuleLocation, NO_STACK);
Ulf Adams83763ee2015-05-04 15:36:12 +0000348
349 assertContainsEvent("//visibility:legacy_public only allowed in package declaration");
350 }
351
Florian Weikert432d1982015-12-01 14:38:06 +0000352 @Test
Ulf Adams83763ee2015-05-04 15:36:12 +0000353 public void testCreateRule() throws Exception {
354 RuleClass ruleClassA = createRuleClassA();
355
356 // LinkedHashMap -> predictable iteration order for testing
357 Map<String, Object> attributeValues = new LinkedHashMap<>();
358 attributeValues.put("my-labellist-attr", "foobar"); // wrong type
359 attributeValues.put("bogus-attr", "foobar"); // no such attr
360 attributeValues.put("my-stringlist-attr", Arrays.asList("foo", "bar"));
361
362 reporter.removeHandler(failFastHandler);
363 EventCollector collector = new EventCollector(EventKind.ERRORS);
364 reporter.addHandler(collector);
365
adonovan40a737c2020-03-11 14:32:19 -0700366 Rule rule = createRule(ruleClassA, TEST_RULE_NAME, attributeValues, testRuleLocation, NO_STACK);
Ulf Adams83763ee2015-05-04 15:36:12 +0000367
368 // TODO(blaze-team): (2009) refactor to use assertContainsEvent
369 Iterator<String> expectedMessages = Arrays.asList(
370 "expected value of type 'list(label)' for attribute 'my-labellist-attr' "
Francois-Rene Rideaud61f5312015-06-13 03:34:47 +0000371 + "in 'ruleA' rule, but got \"foobar\" (string)",
Ulf Adams83763ee2015-05-04 15:36:12 +0000372 "no such attribute 'bogus-attr' in 'ruleA' rule",
373 "missing value for mandatory "
374 + "attribute 'my-string-attr' in 'ruleA' rule",
375 "missing value for mandatory attribute 'my-label-attr' in 'ruleA' rule",
376 "missing value for mandatory "
377 + "attribute 'my-labellist-attr' in 'ruleA' rule",
378 "missing value for mandatory "
379 + "attribute 'my-string-attr2' in 'ruleA' rule"
380 ).iterator();
381
382 for (Event event : collector) {
adonovan22096af2020-01-08 07:09:52 -0800383 assertThat(event.getLocation().line()).isEqualTo(TEST_RULE_DEFINED_AT_LINE);
384 assertThat(event.getLocation().file()).isEqualTo(testBuildfilePath.toString());
lberkiaea56b32017-05-30 12:35:33 +0200385 assertThat(event.getMessage())
386 .isEqualTo(TEST_RULE_LABEL.toString().substring(1) + ": " + expectedMessages.next());
Ulf Adams83763ee2015-05-04 15:36:12 +0000387 }
388
389 // Test basic rule properties:
lberkiaea56b32017-05-30 12:35:33 +0200390 assertThat(rule.getRuleClass()).isEqualTo("ruleA");
391 assertThat(rule.getName()).isEqualTo(TEST_RULE_NAME);
392 assertThat(rule.getLabel().toString()).isEqualTo(TEST_RULE_LABEL.substring(1));
Ulf Adams83763ee2015-05-04 15:36:12 +0000393
394 // Test attribute access:
395 AttributeMap attributes = RawAttributeMapper.of(rule);
lberkiaea56b32017-05-30 12:35:33 +0200396 assertThat(attributes.get("my-label-attr", BuildType.LABEL).toString())
397 .isEqualTo("//default:label");
398 assertThat(attributes.get("my-integer-attr", Type.INTEGER).intValue()).isEqualTo(42);
lberkie355e772017-05-31 14:34:53 +0200399 // missing attribute -> default chosen based on type
400 assertThat(attributes.get("my-string-attr", Type.STRING)).isEmpty();
Lukacs Berkiffa73ad2015-09-18 11:40:12 +0000401 assertThat(attributes.get("my-labellist-attr", BuildType.LABEL_LIST)).isEmpty();
lberkiaea56b32017-05-30 12:35:33 +0200402 assertThat(attributes.get("my-stringlist-attr", Type.STRING_LIST))
403 .isEqualTo(Arrays.asList("foo", "bar"));
jcaterb9226772019-04-29 12:04:52 -0700404 IllegalArgumentException e =
405 assertThrows(
406 IllegalArgumentException.class, () -> attributes.get("my-labellist-attr", Type.STRING));
407 assertThat(e)
408 .hasMessageThat()
409 .isEqualTo(
410 "Attribute my-labellist-attr is of type list(label) "
411 + "and not of type string in ruleA rule //testpackage:my-rule-A");
Ulf Adams83763ee2015-05-04 15:36:12 +0000412 }
413
Florian Weikert432d1982015-12-01 14:38:06 +0000414 @Test
Ulf Adams83763ee2015-05-04 15:36:12 +0000415 public void testImplicitOutputs() throws Exception {
Janak Ramakrishnan3be65b82016-05-18 15:53:10 +0000416 RuleClass ruleClassC =
417 newRuleClass(
418 "ruleC",
419 false,
420 false,
421 false,
422 false,
423 false,
424 false,
cparsons55781c92018-10-17 12:03:08 -0700425 false,
Janak Ramakrishnan3be65b82016-05-18 15:53:10 +0000426 ImplicitOutputsFunction.fromTemplates(
427 "foo-%{name}.bar", "lib%{name}-wazoo-%{name}.mumble", "stuff-%{outs}-bar"),
Cal Peyser19dda252017-01-11 23:37:05 +0000428 null,
Janak Ramakrishnan3be65b82016-05-18 15:53:10 +0000429 DUMMY_CONFIGURED_TARGET_FACTORY,
430 PredicatesWithMessage.<Rule>alwaysTrue(),
431 PREFERRED_DEPENDENCY_PREDICATE,
Dmitry Lomovb91d3922017-01-09 20:12:57 +0000432 AdvertisedProviderSet.EMPTY,
Janak Ramakrishnan3be65b82016-05-18 15:53:10 +0000433 null,
Janak Ramakrishnan3be65b82016-05-18 15:53:10 +0000434 ImmutableSet.<Class<?>>of(),
435 MissingFragmentPolicy.FAIL_ANALYSIS,
436 true,
Benjamin Peterson11b87602017-04-12 19:53:07 +0000437 attr("name", STRING).build(),
Janak Ramakrishnan3be65b82016-05-18 15:53:10 +0000438 attr("outs", OUTPUT_LIST).build());
Ulf Adams83763ee2015-05-04 15:36:12 +0000439
440 Map<String, Object> attributeValues = new HashMap<>();
441 attributeValues.put("outs", Collections.singletonList("explicit_out"));
Benjamin Peterson11b87602017-04-12 19:53:07 +0000442 attributeValues.put("name", "myrule");
Ulf Adams83763ee2015-05-04 15:36:12 +0000443
adonovan40a737c2020-03-11 14:32:19 -0700444 Rule rule = createRule(ruleClassC, "myrule", attributeValues, testRuleLocation, NO_STACK);
Ulf Adams83763ee2015-05-04 15:36:12 +0000445
446 Set<String> set = new HashSet<>();
447 for (OutputFile outputFile : rule.getOutputFiles()) {
448 set.add(outputFile.getName());
cpovirka4d3da62019-05-02 14:27:33 -0700449 assertThat(outputFile.getGeneratingRule()).isSameInstanceAs(rule);
Ulf Adams83763ee2015-05-04 15:36:12 +0000450 }
451 assertThat(set).containsExactly("foo-myrule.bar", "libmyrule-wazoo-myrule.mumble",
452 "stuff-explicit_out-bar", "explicit_out");
453 }
454
Florian Weikert432d1982015-12-01 14:38:06 +0000455 @Test
Ulf Adams83763ee2015-05-04 15:36:12 +0000456 public void testImplicitOutsWithBasenameDirname() throws Exception {
Janak Ramakrishnan3be65b82016-05-18 15:53:10 +0000457 RuleClass ruleClass =
458 newRuleClass(
459 "ruleClass",
460 false,
461 false,
462 false,
463 false,
464 false,
465 false,
cparsons55781c92018-10-17 12:03:08 -0700466 false,
Janak Ramakrishnan3be65b82016-05-18 15:53:10 +0000467 ImplicitOutputsFunction.fromTemplates("%{dirname}lib%{basename}.bar"),
Cal Peyser19dda252017-01-11 23:37:05 +0000468 null,
Janak Ramakrishnan3be65b82016-05-18 15:53:10 +0000469 DUMMY_CONFIGURED_TARGET_FACTORY,
470 PredicatesWithMessage.<Rule>alwaysTrue(),
471 PREFERRED_DEPENDENCY_PREDICATE,
Dmitry Lomovb91d3922017-01-09 20:12:57 +0000472 AdvertisedProviderSet.EMPTY,
Janak Ramakrishnan3be65b82016-05-18 15:53:10 +0000473 null,
Janak Ramakrishnan3be65b82016-05-18 15:53:10 +0000474 ImmutableSet.<Class<?>>of(),
475 MissingFragmentPolicy.FAIL_ANALYSIS,
476 true);
Ulf Adams83763ee2015-05-04 15:36:12 +0000477
adonovan40a737c2020-03-11 14:32:19 -0700478 Rule rule = createRule(ruleClass, "myRule", ImmutableMap.of(), testRuleLocation, NO_STACK);
lberkiaea56b32017-05-30 12:35:33 +0200479 assertThat(Iterables.getOnlyElement(rule.getOutputFiles()).getName())
480 .isEqualTo("libmyRule.bar");
Ulf Adams83763ee2015-05-04 15:36:12 +0000481
adonovan40a737c2020-03-11 14:32:19 -0700482 Rule ruleWithSlash =
483 createRule(ruleClass, "myRule/with/slash", ImmutableMap.of(), testRuleLocation, NO_STACK);
lberkiaea56b32017-05-30 12:35:33 +0200484 assertThat(Iterables.getOnlyElement(ruleWithSlash.getOutputFiles()).getName())
485 .isEqualTo("myRule/with/libslash.bar");
Ulf Adams83763ee2015-05-04 15:36:12 +0000486 }
487
488 /**
489 * Helper routine that instantiates a rule class with the given computed default and supporting
490 * attributes for the default to reference.
491 */
492 private static RuleClass getRuleClassWithComputedDefault(Attribute computedDefault) {
Janak Ramakrishnan3be65b82016-05-18 15:53:10 +0000493 return newRuleClass(
494 "ruleClass",
495 false,
496 false,
497 false,
498 false,
499 false,
500 false,
cparsons55781c92018-10-17 12:03:08 -0700501 false,
Janak Ramakrishnan3be65b82016-05-18 15:53:10 +0000502 ImplicitOutputsFunction.fromTemplates("empty"),
Cal Peyser19dda252017-01-11 23:37:05 +0000503 null,
Janak Ramakrishnan3be65b82016-05-18 15:53:10 +0000504 DUMMY_CONFIGURED_TARGET_FACTORY,
505 PredicatesWithMessage.<Rule>alwaysTrue(),
506 PREFERRED_DEPENDENCY_PREDICATE,
Dmitry Lomovb91d3922017-01-09 20:12:57 +0000507 AdvertisedProviderSet.EMPTY,
Janak Ramakrishnan3be65b82016-05-18 15:53:10 +0000508 null,
Janak Ramakrishnan3be65b82016-05-18 15:53:10 +0000509 ImmutableSet.<Class<?>>of(),
510 MissingFragmentPolicy.FAIL_ANALYSIS,
511 true,
Ulf Adams83763ee2015-05-04 15:36:12 +0000512 attr("condition", BOOLEAN).value(false).build(),
513 attr("declared1", BOOLEAN).value(false).build(),
514 attr("declared2", BOOLEAN).value(false).build(),
515 attr("nonconfigurable", BOOLEAN).nonconfigurable("test").value(false).build(),
516 computedDefault);
517 }
518
519 /**
520 * Helper routine that checks that a computed default is valid and bound to the expected value.
521 */
522 private void checkValidComputedDefault(Object expectedValue, Attribute computedDefault,
523 ImmutableMap<String, Object> attrValueMap) throws Exception {
juliexxia84d1a662018-12-26 14:07:04 -0800524 assertThat(computedDefault.getDefaultValueUnchecked())
525 .isInstanceOf(Attribute.ComputedDefault.class);
adonovan40a737c2020-03-11 14:32:19 -0700526 Rule rule =
527 createRule(
528 getRuleClassWithComputedDefault(computedDefault),
529 "myRule",
530 attrValueMap,
531 testRuleLocation,
532 NO_STACK);
Ulf Adams83763ee2015-05-04 15:36:12 +0000533 AttributeMap attributes = RawAttributeMapper.of(rule);
lberkiaea56b32017-05-30 12:35:33 +0200534 assertThat(attributes.get(computedDefault.getName(), computedDefault.getType()))
535 .isEqualTo(expectedValue);
Ulf Adams83763ee2015-05-04 15:36:12 +0000536 }
537
538 /**
539 * Helper routine that checks that a computed default is invalid due to declared dependency
540 * issues and fails with the expected message.
541 */
542 private void checkInvalidComputedDefault(Attribute computedDefault, String expectedMessage)
543 throws Exception {
jcaterb9226772019-04-29 12:04:52 -0700544 IllegalArgumentException e =
545 assertThrows(
546 IllegalArgumentException.class,
547 () ->
548 createRule(
549 getRuleClassWithComputedDefault(computedDefault),
550 "myRule",
551 ImmutableMap.<String, Object>of(),
adonovan40a737c2020-03-11 14:32:19 -0700552 testRuleLocation,
553 NO_STACK));
jcaterb9226772019-04-29 12:04:52 -0700554 assertThat(e).hasMessageThat().isEqualTo(expectedMessage);
Ulf Adams83763ee2015-05-04 15:36:12 +0000555 }
556
557 /**
558 * Tests computed default values are computed as expected.
559 */
Florian Weikert432d1982015-12-01 14:38:06 +0000560 @Test
Ulf Adams83763ee2015-05-04 15:36:12 +0000561 public void testComputedDefault() throws Exception {
562 Attribute computedDefault =
563 attr("$result", BOOLEAN).value(new Attribute.ComputedDefault("condition") {
564 @Override
565 public Object getDefault(AttributeMap rule) {
566 return rule.get("condition", Type.BOOLEAN);
567 }
568 }).build();
569
570 checkValidComputedDefault(Boolean.FALSE, computedDefault,
571 ImmutableMap.<String, Object>of("condition", Boolean.FALSE));
572 checkValidComputedDefault(Boolean.TRUE, computedDefault,
573 ImmutableMap.<String, Object>of("condition", Boolean.TRUE));
574 }
575
576 /**
577 * Tests that computed defaults can only read attribute values for configurable attributes that
578 * have been explicitly declared.
579 */
Florian Weikert432d1982015-12-01 14:38:06 +0000580 @Test
Ulf Adams83763ee2015-05-04 15:36:12 +0000581 public void testComputedDefaultDeclarations() throws Exception {
582 checkValidComputedDefault(
583 Boolean.FALSE,
584 attr("$good_default_no_declares", BOOLEAN).value(
585 new Attribute.ComputedDefault() {
586 @Override public Object getDefault(AttributeMap rule) {
587 // OK: not a value check:
588 return rule.isAttributeValueExplicitlySpecified("undeclared");
589 }
590 }).build(),
591 ImmutableMap.<String, Object>of());
592
593 checkValidComputedDefault(
594 Boolean.FALSE,
595 attr("$good_default_one_declare", BOOLEAN).value(
596 new Attribute.ComputedDefault("declared1") {
597 @Override public Object getDefault(AttributeMap rule) {
598 return rule.get("declared1", Type.BOOLEAN);
599 }
600 }).build(),
601 ImmutableMap.<String, Object>of());
602
603 checkValidComputedDefault(
604 Boolean.FALSE,
605 attr("$good_default_two_declares", BOOLEAN).value(
606 new Attribute.ComputedDefault("declared1", "declared2") {
607 @Override public Object getDefault(AttributeMap rule) {
608 return rule.get("declared1", Type.BOOLEAN) && rule.get("declared2", Type.BOOLEAN);
609 }
610 }).build(),
611 ImmutableMap.<String, Object>of());
612
613 checkInvalidComputedDefault(
614 attr("$bad_default_no_declares", BOOLEAN).value(
615 new Attribute.ComputedDefault() {
616 @Override public Object getDefault(AttributeMap rule) {
617 return rule.get("declared1", Type.BOOLEAN);
618 }
619 }).build(),
620 "attribute \"declared1\" isn't available in this computed default context");
621
622 checkInvalidComputedDefault(
623 attr("$bad_default_one_declare", BOOLEAN).value(
624 new Attribute.ComputedDefault("declared1") {
625 @Override public Object getDefault(AttributeMap rule) {
626 return rule.get("declared1", Type.BOOLEAN) || rule.get("declared2", Type.BOOLEAN);
627 }
628 }).build(),
629 "attribute \"declared2\" isn't available in this computed default context");
630
631 checkInvalidComputedDefault(
632 attr("$bad_default_two_declares", BOOLEAN).value(
633 new Attribute.ComputedDefault("declared1", "declared2") {
634 @Override public Object getDefault(AttributeMap rule) {
635 return rule.get("condition", Type.BOOLEAN);
636 }
637 }).build(),
638 "attribute \"condition\" isn't available in this computed default context");
639 }
640
641 /**
642 * Tests that computed defaults *can* read attribute values for non-configurable attributes
643 * without needing to explicitly declare them.
644 */
Florian Weikert432d1982015-12-01 14:38:06 +0000645 @Test
Ulf Adams83763ee2015-05-04 15:36:12 +0000646 public void testComputedDefaultWithNonConfigurableAttributes() throws Exception {
647 checkValidComputedDefault(
648 Boolean.FALSE,
649 attr("$good_default_reading_undeclared_nonconfigurable_attribute", BOOLEAN).value(
650 new Attribute.ComputedDefault() {
651 @Override public Object getDefault(AttributeMap rule) {
652 return rule.get("nonconfigurable", Type.BOOLEAN);
653 }
654 }).build(),
655 ImmutableMap.<String, Object>of());
656 }
657
Florian Weikert432d1982015-12-01 14:38:06 +0000658 @Test
Ulf Adams83763ee2015-05-04 15:36:12 +0000659 public void testOutputsAreOrdered() throws Exception {
Janak Ramakrishnan3be65b82016-05-18 15:53:10 +0000660 RuleClass ruleClassC =
661 newRuleClass(
662 "ruleC",
663 false,
664 false,
665 false,
666 false,
667 false,
668 false,
cparsons55781c92018-10-17 12:03:08 -0700669 false,
Janak Ramakrishnan3be65b82016-05-18 15:53:10 +0000670 ImplicitOutputsFunction.fromTemplates("first-%{name}", "second-%{name}", "out-%{outs}"),
Cal Peyser19dda252017-01-11 23:37:05 +0000671 null,
Janak Ramakrishnan3be65b82016-05-18 15:53:10 +0000672 DUMMY_CONFIGURED_TARGET_FACTORY,
673 PredicatesWithMessage.<Rule>alwaysTrue(),
674 PREFERRED_DEPENDENCY_PREDICATE,
Dmitry Lomovb91d3922017-01-09 20:12:57 +0000675 AdvertisedProviderSet.EMPTY,
Janak Ramakrishnan3be65b82016-05-18 15:53:10 +0000676 null,
Janak Ramakrishnan3be65b82016-05-18 15:53:10 +0000677 ImmutableSet.<Class<?>>of(),
678 MissingFragmentPolicy.FAIL_ANALYSIS,
679 true,
Benjamin Peterson11b87602017-04-12 19:53:07 +0000680 attr("name", STRING).build(),
Janak Ramakrishnan3be65b82016-05-18 15:53:10 +0000681 attr("outs", OUTPUT_LIST).build());
Ulf Adams83763ee2015-05-04 15:36:12 +0000682
683 Map<String, Object> attributeValues = new HashMap<>();
684 attributeValues.put("outs", ImmutableList.of("third", "fourth"));
Benjamin Peterson11b87602017-04-12 19:53:07 +0000685 attributeValues.put("name", "myrule");
Ulf Adams83763ee2015-05-04 15:36:12 +0000686
adonovan40a737c2020-03-11 14:32:19 -0700687 Rule rule = createRule(ruleClassC, "myrule", attributeValues, testRuleLocation, NO_STACK);
Ulf Adams83763ee2015-05-04 15:36:12 +0000688
689 List<String> actual = new ArrayList<>();
690 for (OutputFile outputFile : rule.getOutputFiles()) {
691 actual.add(outputFile.getName());
cpovirka4d3da62019-05-02 14:27:33 -0700692 assertThat(outputFile.getGeneratingRule()).isSameInstanceAs(rule);
Ulf Adams83763ee2015-05-04 15:36:12 +0000693 }
694 assertWithMessage("unexpected output set").that(actual).containsExactly("first-myrule",
695 "second-myrule", "out-third", "out-fourth", "third", "fourth");
696 assertWithMessage("invalid output ordering").that(actual).containsExactly("first-myrule",
697 "second-myrule", "out-third", "out-fourth", "third", "fourth").inOrder();
698 }
699
Florian Weikert432d1982015-12-01 14:38:06 +0000700 @Test
Ulf Adams83763ee2015-05-04 15:36:12 +0000701 public void testSubstitutePlaceholderIntoTemplate() throws Exception {
Janak Ramakrishnan3be65b82016-05-18 15:53:10 +0000702 RuleClass ruleClass =
703 newRuleClass(
704 "ruleA",
705 false,
706 false,
707 false,
708 false,
709 false,
710 false,
cparsons55781c92018-10-17 12:03:08 -0700711 false,
Janak Ramakrishnan3be65b82016-05-18 15:53:10 +0000712 ImplicitOutputsFunction.NONE,
Cal Peyser19dda252017-01-11 23:37:05 +0000713 null,
Janak Ramakrishnan3be65b82016-05-18 15:53:10 +0000714 DUMMY_CONFIGURED_TARGET_FACTORY,
715 PredicatesWithMessage.<Rule>alwaysTrue(),
716 PREFERRED_DEPENDENCY_PREDICATE,
Dmitry Lomovb91d3922017-01-09 20:12:57 +0000717 AdvertisedProviderSet.EMPTY,
Janak Ramakrishnan3be65b82016-05-18 15:53:10 +0000718 null,
Janak Ramakrishnan3be65b82016-05-18 15:53:10 +0000719 ImmutableSet.<Class<?>>of(),
720 MissingFragmentPolicy.FAIL_ANALYSIS,
721 true,
722 attr("a", STRING_LIST).mandatory().build(),
723 attr("b", STRING_LIST).mandatory().build(),
724 attr("c", STRING_LIST).mandatory().build(),
725 attr("baz", STRING_LIST).mandatory().build(),
726 attr("empty", STRING_LIST).build());
Ulf Adams83763ee2015-05-04 15:36:12 +0000727
728 Map<String, Object> attributeValues = new LinkedHashMap<>();
729 attributeValues.put("a", ImmutableList.of("a", "A"));
730 attributeValues.put("b", ImmutableList.of("b", "B"));
731 attributeValues.put("c", ImmutableList.of("c", "C"));
732 attributeValues.put("baz", ImmutableList.of("baz", "BAZ"));
733 attributeValues.put("empty", ImmutableList.<String>of());
734
adonovan40a737c2020-03-11 14:32:19 -0700735 AttributeMap rule =
736 RawAttributeMapper.of(
737 createRule(ruleClass, "testrule", attributeValues, testRuleLocation, NO_STACK));
Ulf Adams83763ee2015-05-04 15:36:12 +0000738
739 assertThat(substitutePlaceholderIntoTemplate("foo", rule)).containsExactly("foo");
740 assertThat(substitutePlaceholderIntoTemplate("foo-%{baz}-bar", rule)).containsExactly(
741 "foo-baz-bar", "foo-BAZ-bar").inOrder();
742 assertThat(substitutePlaceholderIntoTemplate("%{a}-%{b}-%{c}", rule)).containsExactly("a-b-c",
743 "a-b-C", "a-B-c", "a-B-C", "A-b-c", "A-b-C", "A-B-c", "A-B-C").inOrder();
744 assertThat(substitutePlaceholderIntoTemplate("%{a", rule)).containsExactly("%{a");
745 assertThat(substitutePlaceholderIntoTemplate("%{a}}", rule)).containsExactly("a}", "A}")
746 .inOrder();
747 assertThat(substitutePlaceholderIntoTemplate("x%{a}y%{empty}", rule)).isEmpty();
748 }
749
Florian Weikert432d1982015-12-01 14:38:06 +0000750 @Test
Ulf Adams83763ee2015-05-04 15:36:12 +0000751 public void testOrderIndependentAttribute() throws Exception {
752 RuleClass ruleClassA = createRuleClassA();
753
754 List<String> list = Arrays.asList("foo", "bar", "baz");
755 Map<String, Object> attributeValues = new LinkedHashMap<>();
756 // mandatory values
757 attributeValues.put("my-string-attr", "");
758 attributeValues.put("my-label-attr", "//project");
759 attributeValues.put("my-string-attr2", "");
760 attributeValues.put("my-labellist-attr", Collections.emptyList());
761 // to compare the effect of .orderIndependent()
762 attributeValues.put("my-stringlist-attr", list);
763 attributeValues.put("my-sorted-stringlist-attr", list);
764
adonovan40a737c2020-03-11 14:32:19 -0700765 Rule rule = createRule(ruleClassA, "testrule", attributeValues, testRuleLocation, NO_STACK);
Ulf Adams83763ee2015-05-04 15:36:12 +0000766 AttributeMap attributes = RawAttributeMapper.of(rule);
767
lberkiaea56b32017-05-30 12:35:33 +0200768 assertThat(attributes.get("my-stringlist-attr", Type.STRING_LIST)).isEqualTo(list);
769 assertThat(attributes.get("my-sorted-stringlist-attr", Type.STRING_LIST))
770 .isEqualTo(Arrays.asList("bar", "baz", "foo"));
Ulf Adams83763ee2015-05-04 15:36:12 +0000771 }
772
Florian Weikertea6c82d2016-09-05 12:15:31 +0000773 private Rule createRule(
adonovan40a737c2020-03-11 14:32:19 -0700774 RuleClass ruleClass,
775 String name,
776 Map<String, Object> attributeValues,
777 Location location,
778 List<StarlarkThread.CallStackEntry> callstack)
Florian Weikertea6c82d2016-09-05 12:15:31 +0000779 throws LabelSyntaxException, InterruptedException, CannotPrecomputeDefaultsException {
Ulf Adams83763ee2015-05-04 15:36:12 +0000780 Package.Builder pkgBuilder = createDummyPackageBuilder();
781 Label ruleLabel;
782 try {
783 ruleLabel = pkgBuilder.createLabel(name);
Lukacs Berkia6434362015-09-15 13:56:14 +0000784 } catch (LabelSyntaxException e) {
Googler98eab102018-10-11 12:28:22 -0700785 throw new IllegalArgumentException("Rule has illegal label", e);
Ulf Adams83763ee2015-05-04 15:36:12 +0000786 }
Mark Schalleree624452016-01-13 18:41:24 +0000787 return ruleClass.createRule(
788 pkgBuilder,
789 ruleLabel,
790 new BuildLangTypedAttributeValuesMap(attributeValues),
791 reporter,
Mark Schalleree624452016-01-13 18:41:24 +0000792 location,
adonovan40a737c2020-03-11 14:32:19 -0700793 callstack,
Greg Estren37cd5c42019-01-30 12:25:50 -0800794 /*checkThirdPartyRulesHaveLicenses=*/ true);
Ulf Adams83763ee2015-05-04 15:36:12 +0000795 }
796
Florian Weikert432d1982015-12-01 14:38:06 +0000797 @Test
Ulf Adams83763ee2015-05-04 15:36:12 +0000798 public void testOverrideWithWrongType() {
jcaterb9226772019-04-29 12:04:52 -0700799 RuleClass parentRuleClass = createParentRuleClass();
Ulf Adams83763ee2015-05-04 15:36:12 +0000800
jcaterb9226772019-04-29 12:04:52 -0700801 RuleClass.Builder childRuleClassBuilder =
802 new RuleClass.Builder("child_rule", RuleClassType.NORMAL, false, parentRuleClass);
803 IllegalStateException e =
804 assertThrows(
805 IllegalStateException.class,
806 () -> childRuleClassBuilder.override(attr("attr", INTEGER)));
807 assertThat(e)
808 .hasMessageThat()
809 .isEqualTo(
810 "The type of the new attribute 'int' is different from "
811 + "the original one 'string'.");
Ulf Adams83763ee2015-05-04 15:36:12 +0000812 }
813
Florian Weikert432d1982015-12-01 14:38:06 +0000814 @Test
Ulf Adams83763ee2015-05-04 15:36:12 +0000815 public void testOverrideWithRightType() {
816 RuleClass parentRuleClass = createParentRuleClass();
817
818 RuleClass.Builder childRuleClassBuilder = new RuleClass.Builder(
819 "child_rule", RuleClassType.NORMAL, false, parentRuleClass);
820 childRuleClassBuilder.override(attr("attr", STRING));
821 }
822
Florian Weikert432d1982015-12-01 14:38:06 +0000823 @Test
Ulf Adams83763ee2015-05-04 15:36:12 +0000824 public void testCopyAndOverrideAttribute() throws Exception {
825 RuleClass parentRuleClass = createParentRuleClass();
826 RuleClass childRuleClass = createChildRuleClass(parentRuleClass);
827
828 Map<String, Object> parentValues = new LinkedHashMap<>();
829 Map<String, Object> childValues = new LinkedHashMap<>();
830 childValues.put("attr", "somevalue");
adonovan40a737c2020-03-11 14:32:19 -0700831 createRule(parentRuleClass, "parent_rule", parentValues, testRuleLocation, NO_STACK);
832 createRule(childRuleClass, "child_rule", childValues, testRuleLocation, NO_STACK);
Ulf Adams83763ee2015-05-04 15:36:12 +0000833 }
834
Florian Weikert432d1982015-12-01 14:38:06 +0000835 @Test
Ulf Adams83763ee2015-05-04 15:36:12 +0000836 public void testCopyAndOverrideAttributeMandatoryMissing() throws Exception {
837 RuleClass parentRuleClass = createParentRuleClass();
838 RuleClass childRuleClass = createChildRuleClass(parentRuleClass);
839
840 Map<String, Object> childValues = new LinkedHashMap<>();
841 reporter.removeHandler(failFastHandler);
adonovan40a737c2020-03-11 14:32:19 -0700842 createRule(childRuleClass, "child_rule", childValues, testRuleLocation, NO_STACK);
Ulf Adams83763ee2015-05-04 15:36:12 +0000843
cpovirka4d3da62019-05-02 14:27:33 -0700844 assertThat(eventCollector.count()).isSameInstanceAs(1);
Ulf Adams83763ee2015-05-04 15:36:12 +0000845 assertContainsEvent("//testpackage:child_rule: missing value for mandatory "
846 + "attribute 'attr' in 'child_rule' rule");
847 }
848
Florian Weikert432d1982015-12-01 14:38:06 +0000849 @Test
Ulf Adams83763ee2015-05-04 15:36:12 +0000850 public void testRequiredFragmentInheritance() throws Exception {
851 RuleClass parentRuleClass = createParentRuleClass();
852 RuleClass childRuleClass = createChildRuleClass(parentRuleClass);
Michael Staibb51251e2015-09-29 23:31:51 +0000853 assertThat(parentRuleClass.getConfigurationFragmentPolicy().getRequiredConfigurationFragments())
Ulf Adams83763ee2015-05-04 15:36:12 +0000854 .containsExactly(DummyFragment.class);
Michael Staibb51251e2015-09-29 23:31:51 +0000855 assertThat(childRuleClass.getConfigurationFragmentPolicy().getRequiredConfigurationFragments())
Ulf Adams83763ee2015-05-04 15:36:12 +0000856 .containsExactly(DummyFragment.class);
857 }
858
Janak Ramakrishnan3be65b82016-05-18 15:53:10 +0000859 private static RuleClass newRuleClass(
860 String name,
gregce0503fee2020-06-11 09:22:27 -0700861 boolean starlarkExecutable,
Janak Ramakrishnan3be65b82016-05-18 15:53:10 +0000862 boolean documented,
863 boolean publicByDefault,
864 boolean binaryOutput,
865 boolean workspaceOnly,
866 boolean outputsDefaultExecutable,
cparsons55781c92018-10-17 12:03:08 -0700867 boolean isAnalysisTest,
Janak Ramakrishnan3be65b82016-05-18 15:53:10 +0000868 ImplicitOutputsFunction implicitOutputsFunction,
John Caterb3b3e8b2019-04-03 09:18:42 -0700869 TransitionFactory<Rule> transitionFactory,
cparsonse2d200f2018-03-06 16:15:11 -0800870 ConfiguredTargetFactory<?, ?, ?> configuredTargetFactory,
Janak Ramakrishnan3be65b82016-05-18 15:53:10 +0000871 PredicateWithMessage<Rule> validityPredicate,
872 Predicate<String> preferredDependencyPredicate,
Dmitry Lomovb91d3922017-01-09 20:12:57 +0000873 AdvertisedProviderSet advertisedProviders,
adonovanf3a344e82019-12-11 11:10:11 -0800874 @Nullable StarlarkFunction configuredTargetFunction,
Janak Ramakrishnan3be65b82016-05-18 15:53:10 +0000875 Set<Class<?>> allowedConfigurationFragments,
876 MissingFragmentPolicy missingFragmentPolicy,
877 boolean supportsConstraintChecking,
878 Attribute... attributes) {
Janak Ramakrishnan3be65b82016-05-18 15:53:10 +0000879 return new RuleClass(
880 name,
adonovanebb86fc2020-03-20 14:57:54 -0700881 DUMMY_STACK,
882 /*key=*/ name,
janakr6ff110e2018-03-21 21:44:27 -0700883 RuleClassType.NORMAL,
gregce0503fee2020-06-11 09:22:27 -0700884 /*isStarlark=*/ starlarkExecutable,
885 /*starlarkTestable=*/ false,
Janak Ramakrishnan3be65b82016-05-18 15:53:10 +0000886 documented,
887 publicByDefault,
888 binaryOutput,
889 workspaceOnly,
890 outputsDefaultExecutable,
cparsons55781c92018-10-17 12:03:08 -0700891 isAnalysisTest,
cparsons9d40c6b2019-02-25 12:24:40 -0800892 /* hasAnalysisTestTransition=*/ false,
Googlerc2200fd2018-09-14 17:35:59 -0700893 /* hasFunctionTransitionWhitelist=*/ false,
gregce1d8d6dd2019-04-10 09:27:34 -0700894 /* ignoreLicenses=*/ false,
Janak Ramakrishnan3be65b82016-05-18 15:53:10 +0000895 implicitOutputsFunction,
Michael Staib2a675202017-03-20 18:06:48 +0000896 transitionFactory,
Janak Ramakrishnan3be65b82016-05-18 15:53:10 +0000897 configuredTargetFactory,
898 validityPredicate,
899 preferredDependencyPredicate,
900 advertisedProviders,
Janak Ramakrishnan3be65b82016-05-18 15:53:10 +0000901 configuredTargetFunction,
John Cater39401a92020-07-09 10:12:55 -0700902 NO_EXTERNAL_BINDINGS,
903 NO_TOOLCHAINS_TO_REGISTER,
mstaibe5538ad2017-04-04 18:32:23 +0000904 /*optionReferenceFunction=*/ RuleClass.NO_OPTION_REFERENCE,
ajurkowski9f2cab52020-05-12 12:00:24 -0700905 /*ruleDefinitionEnvironmentLabel=*/ null,
906 /*ruleDefinitionEnvironmentDigest=*/ null,
Janak Ramakrishnan3be65b82016-05-18 15:53:10 +0000907 new ConfigurationFragmentPolicy.Builder()
908 .requiresConfigurationFragments(allowedConfigurationFragments)
909 .setMissingFragmentPolicy(missingFragmentPolicy)
910 .build(),
911 supportsConstraintChecking,
gregce4aa059a2019-02-26 13:20:47 -0800912 ThirdPartyLicenseExistencePolicy.USER_CONTROLLABLE,
John Cateree45c662018-06-05 11:09:01 -0700913 /*requiredToolchains=*/ ImmutableSet.of(),
jcater01bb1f92019-06-17 12:09:11 -0700914 /*useToolchainResolution=*/ true,
John Cater099cf2f2020-06-11 12:58:36 -0700915 /*useToolchainTransition=*/ true,
John Cateree45c662018-06-05 11:09:01 -0700916 /* executionPlatformConstraints= */ ImmutableSet.of(),
juliexxia693048d2020-04-01 06:41:42 -0700917 /* execGroups= */ ImmutableMap.of(),
John Cateree45c662018-06-05 11:09:01 -0700918 OutputFile.Kind.FILE,
juliexxia1f332e02018-10-31 14:20:55 -0700919 ImmutableList.copyOf(attributes),
920 /* buildSetting= */ null);
Ulf Adams83763ee2015-05-04 15:36:12 +0000921 }
922
Janak Ramakrishnan3be65b82016-05-18 15:53:10 +0000923 private static RuleClass createParentRuleClass() {
924 return newRuleClass(
925 "parent_rule",
926 false,
927 false,
928 false,
929 false,
930 false,
931 false,
cparsons55781c92018-10-17 12:03:08 -0700932 false,
Janak Ramakrishnan3be65b82016-05-18 15:53:10 +0000933 ImplicitOutputsFunction.NONE,
Cal Peyser19dda252017-01-11 23:37:05 +0000934 null,
Janak Ramakrishnan3be65b82016-05-18 15:53:10 +0000935 DUMMY_CONFIGURED_TARGET_FACTORY,
936 PredicatesWithMessage.<Rule>alwaysTrue(),
937 PREFERRED_DEPENDENCY_PREDICATE,
Dmitry Lomovb91d3922017-01-09 20:12:57 +0000938 AdvertisedProviderSet.EMPTY,
Janak Ramakrishnan3be65b82016-05-18 15:53:10 +0000939 null,
Janak Ramakrishnan3be65b82016-05-18 15:53:10 +0000940 ImmutableSet.<Class<?>>of(DummyFragment.class),
941 MissingFragmentPolicy.FAIL_ANALYSIS,
942 true,
943 attr("attr", STRING).build());
944 }
945
946 private static RuleClass createChildRuleClass(RuleClass parentRuleClass) {
Ulf Adams83763ee2015-05-04 15:36:12 +0000947 RuleClass.Builder childRuleClassBuilder = new RuleClass.Builder(
948 "child_rule", RuleClassType.NORMAL, false, parentRuleClass);
949 return childRuleClassBuilder.override(
950 childRuleClassBuilder
951 .factory(DUMMY_CONFIGURED_TARGET_FACTORY)
952 .copy("attr").mandatory())
953 .add(attr("tags", STRING_LIST))
954 .build();
955 }
956
Florian Weikert432d1982015-12-01 14:38:06 +0000957 @Test
Ulf Adams83763ee2015-05-04 15:36:12 +0000958 public void testValidityChecker() throws Exception {
959 RuleClass depClass = new RuleClass.Builder("dep", RuleClassType.NORMAL, false)
960 .factory(DUMMY_CONFIGURED_TARGET_FACTORY)
961 .add(attr("tags", STRING_LIST))
962 .build();
adonovan40a737c2020-03-11 14:32:19 -0700963 final Rule dep1 = createRule(depClass, "dep1", ImmutableMap.of(), testRuleLocation, NO_STACK);
964 final Rule dep2 = createRule(depClass, "dep2", ImmutableMap.of(), testRuleLocation, NO_STACK);
Ulf Adams83763ee2015-05-04 15:36:12 +0000965
lberkiaea56b32017-05-30 12:35:33 +0200966 ValidityPredicate checker =
967 new ValidityPredicate() {
968 @Override
969 public String checkValid(Rule from, Rule to) {
970 assertThat(from.getName()).isEqualTo("top");
971 if (to.getName().equals("dep1")) {
972 return "pear";
973 } else if (to.getName().equals("dep2")) {
974 return null;
975 } else {
976 fail("invalid dependency");
977 return null;
978 }
979 }
980 };
Ulf Adams83763ee2015-05-04 15:36:12 +0000981
982 RuleClass topClass = new RuleClass.Builder("top", RuleClassType.NORMAL, false)
983 .factory(DUMMY_CONFIGURED_TARGET_FACTORY)
984 .add(attr("tags", STRING_LIST))
985 .add(attr("deps", LABEL_LIST).legacyAllowAnyFileType()
986 .validityPredicate(checker))
987 .build();
988
adonovan40a737c2020-03-11 14:32:19 -0700989 Rule topRule = createRule(topClass, "top", ImmutableMap.of(), testRuleLocation, NO_STACK);
Ulf Adams83763ee2015-05-04 15:36:12 +0000990
lberkiaea56b32017-05-30 12:35:33 +0200991 assertThat(topClass.getAttributeByName("deps").getValidityPredicate().checkValid(topRule, dep1))
992 .isEqualTo("pear");
993 assertThat(topClass.getAttributeByName("deps").getValidityPredicate().checkValid(topRule, dep2))
994 .isNull();
Ulf Adams83763ee2015-05-04 15:36:12 +0000995 }
996
997 /**
998 * Tests structure for making certain rules "preferential choices" for certain files
999 * under --compile_one_dependency.
1000 */
Florian Weikert432d1982015-12-01 14:38:06 +00001001 @Test
Ulf Adams83763ee2015-05-04 15:36:12 +00001002 public void testPreferredDependencyChecker() throws Exception {
1003 final String cppFile = "file.cc";
1004 final String textFile = "file.txt";
1005
1006 // Default: not preferred for anything.
1007 RuleClass defaultClass = new RuleClass.Builder("defaultClass", RuleClassType.NORMAL, false)
1008 .factory(DUMMY_CONFIGURED_TARGET_FACTORY)
1009 .add(attr("tags", STRING_LIST))
1010 .build();
adonovan40a737c2020-03-11 14:32:19 -07001011 final Rule defaultRule =
1012 createRule(defaultClass, "defaultRule", ImmutableMap.of(), testRuleLocation, NO_STACK);
lberkiaea56b32017-05-30 12:35:33 +02001013 assertThat(defaultRule.getRuleClassObject().isPreferredDependency(cppFile)).isFalse();
1014 assertThat(defaultRule.getRuleClassObject().isPreferredDependency(textFile)).isFalse();
Ulf Adams83763ee2015-05-04 15:36:12 +00001015
1016 // Make a rule that's preferred for C++ sources.
1017 RuleClass cppClass = new RuleClass.Builder("cppClass", RuleClassType.NORMAL, false)
1018 .factory(DUMMY_CONFIGURED_TARGET_FACTORY)
1019 .add(attr("tags", STRING_LIST))
1020 .setPreferredDependencyPredicate(new Predicate<String>() {
1021 @Override
1022 public boolean apply(String filename) {
1023 return filename.endsWith(".cc");
1024 }
1025 })
1026 .build();
adonovan40a737c2020-03-11 14:32:19 -07001027 final Rule cppRule =
1028 createRule(cppClass, "cppRule", ImmutableMap.of(), testRuleLocation, NO_STACK);
lberkiaea56b32017-05-30 12:35:33 +02001029 assertThat(cppRule.getRuleClassObject().isPreferredDependency(cppFile)).isTrue();
1030 assertThat(cppRule.getRuleClassObject().isPreferredDependency(textFile)).isFalse();
Ulf Adams83763ee2015-05-04 15:36:12 +00001031 }
1032
Florian Weikert432d1982015-12-01 14:38:06 +00001033 @Test
Ulf Adams83763ee2015-05-04 15:36:12 +00001034 public void testBadRuleClassNames() {
1035 expectError(RuleClassType.NORMAL, "8abc");
Laurent Le Brun6ce51e12015-07-07 11:54:41 +00001036 expectError(RuleClassType.NORMAL, "!abc");
Ulf Adams83763ee2015-05-04 15:36:12 +00001037 expectError(RuleClassType.NORMAL, "a b");
1038 }
1039
1040 private void expectError(RuleClassType type, String name) {
jcaterb9226772019-04-29 12:04:52 -07001041 assertThrows(IllegalArgumentException.class, () -> type.checkName(name));
Ulf Adams83763ee2015-05-04 15:36:12 +00001042 }
John Catereca28402017-05-17 21:44:12 +02001043
1044 @Test
1045 public void testRequiredToolchains() throws Exception {
1046 RuleClass.Builder ruleClassBuilder =
1047 new RuleClass.Builder("ruleClass", RuleClassType.NORMAL, false)
1048 .factory(DUMMY_CONFIGURED_TARGET_FACTORY)
1049 .add(attr("tags", STRING_LIST));
1050
John Cater9a8d16e2017-07-05 16:12:07 -04001051 ruleClassBuilder.addRequiredToolchains(
dannark90e2b4b2018-06-27 13:35:04 -07001052 Label.parseAbsolute("//toolchain:tc1", ImmutableMap.of()),
1053 Label.parseAbsolute("//toolchain:tc2", ImmutableMap.of()));
John Catereca28402017-05-17 21:44:12 +02001054
1055 RuleClass ruleClass = ruleClassBuilder.build();
1056
John Cater9a8d16e2017-07-05 16:12:07 -04001057 assertThat(ruleClass.getRequiredToolchains())
1058 .containsExactly(
dannark90e2b4b2018-06-27 13:35:04 -07001059 Label.parseAbsolute("//toolchain:tc1", ImmutableMap.of()),
1060 Label.parseAbsolute("//toolchain:tc2", ImmutableMap.of()));
John Catereca28402017-05-17 21:44:12 +02001061 }
John Cateree45c662018-06-05 11:09:01 -07001062
1063 @Test
John Cater04be3f82019-11-07 12:20:25 -08001064 public void testExecutionPlatformConstraints() throws Exception {
John Cateree45c662018-06-05 11:09:01 -07001065 RuleClass.Builder ruleClassBuilder =
1066 new RuleClass.Builder("ruleClass", RuleClassType.NORMAL, false)
1067 .factory(DUMMY_CONFIGURED_TARGET_FACTORY)
John Cater04be3f82019-11-07 12:20:25 -08001068 .add(attr("tags", STRING_LIST));
John Cateree45c662018-06-05 11:09:01 -07001069
1070 ruleClassBuilder.addExecutionPlatformConstraints(
dannark90e2b4b2018-06-27 13:35:04 -07001071 Label.parseAbsolute("//constraints:cv1", ImmutableMap.of()),
1072 Label.parseAbsolute("//constraints:cv2", ImmutableMap.of()));
John Cateree45c662018-06-05 11:09:01 -07001073
1074 RuleClass ruleClass = ruleClassBuilder.build();
1075
1076 assertThat(ruleClass.getExecutionPlatformConstraints())
1077 .containsExactly(
dannark90e2b4b2018-06-27 13:35:04 -07001078 Label.parseAbsolute("//constraints:cv1", ImmutableMap.of()),
1079 Label.parseAbsolute("//constraints:cv2", ImmutableMap.of()));
John Cateree45c662018-06-05 11:09:01 -07001080 }
1081
1082 @Test
1083 public void testExecutionPlatformConstraints_inheritConstraintsFromParent() throws Exception {
1084 RuleClass parentRuleClass =
1085 new RuleClass.Builder("$parentRuleClass", RuleClassType.ABSTRACT, false)
1086 .add(attr("tags", STRING_LIST))
John Cateree45c662018-06-05 11:09:01 -07001087 .addExecutionPlatformConstraints(
dannark90e2b4b2018-06-27 13:35:04 -07001088 Label.parseAbsolute("//constraints:cv1", ImmutableMap.of()),
1089 Label.parseAbsolute("//constraints:cv2", ImmutableMap.of()))
John Cateree45c662018-06-05 11:09:01 -07001090 .build();
1091
1092 RuleClass childRuleClass =
1093 new RuleClass.Builder("childRuleClass", RuleClassType.NORMAL, false, parentRuleClass)
1094 .factory(DUMMY_CONFIGURED_TARGET_FACTORY)
1095 .build();
1096
1097 assertThat(childRuleClass.getExecutionPlatformConstraints())
1098 .containsExactly(
dannark90e2b4b2018-06-27 13:35:04 -07001099 Label.parseAbsolute("//constraints:cv1", ImmutableMap.of()),
1100 Label.parseAbsolute("//constraints:cv2", ImmutableMap.of()));
John Cateree45c662018-06-05 11:09:01 -07001101 }
1102
1103 @Test
1104 public void testExecutionPlatformConstraints_inheritAndAddConstraints() throws Exception {
1105 RuleClass parentRuleClass =
1106 new RuleClass.Builder("$parentRuleClass", RuleClassType.ABSTRACT, false)
1107 .add(attr("tags", STRING_LIST))
1108 .build();
1109
1110 RuleClass.Builder childRuleClassBuilder =
1111 new RuleClass.Builder("childRuleClass", RuleClassType.NORMAL, false, parentRuleClass)
1112 .factory(DUMMY_CONFIGURED_TARGET_FACTORY)
John Cateree45c662018-06-05 11:09:01 -07001113 .addExecutionPlatformConstraints(
dannark90e2b4b2018-06-27 13:35:04 -07001114 Label.parseAbsolute("//constraints:cv1", ImmutableMap.of()),
1115 Label.parseAbsolute("//constraints:cv2", ImmutableMap.of()));
John Cateree45c662018-06-05 11:09:01 -07001116
1117 RuleClass childRuleClass = childRuleClassBuilder.build();
1118
1119 assertThat(childRuleClass.getExecutionPlatformConstraints())
1120 .containsExactly(
dannark90e2b4b2018-06-27 13:35:04 -07001121 Label.parseAbsolute("//constraints:cv1", ImmutableMap.of()),
1122 Label.parseAbsolute("//constraints:cv2", ImmutableMap.of()));
John Cateree45c662018-06-05 11:09:01 -07001123 }
juliexxia1f332e02018-10-31 14:20:55 -07001124
1125 @Test
juliexxia693048d2020-04-01 06:41:42 -07001126 public void testExecGroups() throws Exception {
1127 RuleClass.Builder ruleClassBuilder =
1128 new RuleClass.Builder("ruleClass", RuleClassType.NORMAL, false)
1129 .factory(DUMMY_CONFIGURED_TARGET_FACTORY)
1130 .add(attr("tags", STRING_LIST));
1131
1132 Label toolchain = Label.parseAbsoluteUnchecked("//toolchain");
1133 Label constraint = Label.parseAbsoluteUnchecked("//constraint");
1134
1135 ruleClassBuilder.addExecGroups(
1136 ImmutableMap.of(
juliexxiafae89042020-06-12 12:05:21 -07001137 "cherry", ExecGroup.create(ImmutableSet.of(toolchain), ImmutableSet.of(constraint))));
juliexxia693048d2020-04-01 06:41:42 -07001138
1139 RuleClass ruleClass = ruleClassBuilder.build();
1140
1141 assertThat(ruleClass.getExecGroups()).hasSize(1);
juliexxiafae89042020-06-12 12:05:21 -07001142 assertThat(ruleClass.getExecGroups().get("cherry").requiredToolchains())
juliexxia693048d2020-04-01 06:41:42 -07001143 .containsExactly(toolchain);
juliexxiafae89042020-06-12 12:05:21 -07001144 assertThat(ruleClass.getExecGroups().get("cherry").execCompatibleWith())
juliexxia693048d2020-04-01 06:41:42 -07001145 .containsExactly(constraint);
1146 }
1147
1148 @Test
juliexxia1f332e02018-10-31 14:20:55 -07001149 public void testBuildSetting_createsDefaultAttribute() {
1150 RuleClass labelFlag =
1151 new RuleClass.Builder("label_flag", RuleClassType.NORMAL, false)
1152 .factory(DUMMY_CONFIGURED_TARGET_FACTORY)
1153 .add(attr("tags", STRING_LIST))
1154 .setBuildSetting(new BuildSetting(true, LABEL))
1155 .build();
1156 RuleClass stringSetting =
1157 new RuleClass.Builder("string_setting", RuleClassType.NORMAL, false)
1158 .factory(DUMMY_CONFIGURED_TARGET_FACTORY)
1159 .add(attr("tags", STRING_LIST))
1160 .setBuildSetting(new BuildSetting(false, STRING))
1161 .build();
1162
gregce74d84d42020-04-17 10:02:03 -07001163 assertThat(labelFlag.hasAttr(STARLARK_BUILD_SETTING_DEFAULT_ATTR_NAME, LABEL)).isTrue();
1164 assertThat(stringSetting.hasAttr(STARLARK_BUILD_SETTING_DEFAULT_ATTR_NAME, STRING)).isTrue();
juliexxia1f332e02018-10-31 14:20:55 -07001165 }
1166
1167 @Test
1168 public void testBuildSetting_doesNotCreateDefaultAttributeIfNotBuildSetting() {
1169 RuleClass stringSetting =
1170 new RuleClass.Builder("non_build_setting", RuleClassType.NORMAL, false)
1171 .factory(DUMMY_CONFIGURED_TARGET_FACTORY)
1172 .add(attr("tags", STRING_LIST))
1173 .build();
1174
gregce74d84d42020-04-17 10:02:03 -07001175 assertThat(stringSetting.hasAttr(STARLARK_BUILD_SETTING_DEFAULT_ATTR_NAME, LABEL)).isFalse();
juliexxia1f332e02018-10-31 14:20:55 -07001176 }
michajlob839a512020-03-11 10:04:23 -07001177
1178 @Test
1179 public void testBuildTooManyAttributesRejected() {
1180 RuleClass.Builder builder =
gregce0503fee2020-06-11 09:22:27 -07001181 new RuleClass.Builder("myclass", RuleClassType.NORMAL, /*starlark=*/ false)
michajlob839a512020-03-11 10:04:23 -07001182 .factory(DUMMY_CONFIGURED_TARGET_FACTORY)
1183 .add(attr("tags", STRING_LIST));
michajlo7475b772020-03-12 15:10:11 -07001184 for (int i = 0; i < 200; i++) {
michajlob839a512020-03-11 10:04:23 -07001185 builder.add(attr("attr" + i, STRING));
1186 }
1187
1188 IllegalArgumentException expected =
1189 assertThrows(IllegalArgumentException.class, builder::build);
1190
1191 assertThat(expected)
1192 .hasMessageThat()
michajlo7475b772020-03-12 15:10:11 -07001193 .isEqualTo("Rule class myclass declared too many attributes (201 > 200)");
michajlob839a512020-03-11 10:04:23 -07001194 }
michajlo0a89cef2020-04-06 12:04:12 -07001195
1196 @Test
1197 public void testBuildTooLongAttributeNameRejected() {
1198 IllegalArgumentException expected =
1199 assertThrows(
1200 IllegalArgumentException.class,
1201 () ->
gregce0503fee2020-06-11 09:22:27 -07001202 new RuleClass.Builder("myclass", RuleClassType.NORMAL, /*starlark=*/ false)
michajlo0a89cef2020-04-06 12:04:12 -07001203 .factory(DUMMY_CONFIGURED_TARGET_FACTORY)
1204 .add(attr("tags", STRING_LIST))
1205 .add(attr(Strings.repeat("x", 150), STRING))
1206 .build());
1207
1208 assertThat(expected)
1209 .hasMessageThat()
1210 .matches("Attribute myclass\\.x{150}'s name is too long \\(150 > 128\\)");
1211 }
Ulf Adams83763ee2015-05-04 15:36:12 +00001212}