blob: cbfdbfb18f3337c9ad7dbcfc2973167bec62f1e8 [file] [log] [blame]
Han-Wen Nienhuys3428dc92015-10-21 15:03:34 +00001// Copyright 2015 The Bazel Authors. All rights reserved.
2//
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.devtools.build.lib.packages.Attribute.attr;
18import static com.google.devtools.build.lib.syntax.Type.BOOLEAN;
19import static com.google.devtools.build.lib.syntax.Type.INTEGER;
20import static com.google.devtools.build.lib.syntax.Type.STRING;
21import static com.google.devtools.build.lib.syntax.Type.STRING_LIST;
Florian Weikert432d1982015-12-01 14:38:06 +000022import static org.junit.Assert.fail;
Han-Wen Nienhuys3428dc92015-10-21 15:03:34 +000023
Googler72f3a102017-12-01 16:28:28 -080024import com.google.common.base.Predicate;
cpeyserd78b3742017-08-04 19:48:53 +020025import com.google.common.collect.ImmutableList;
cparsonse2d200f2018-03-06 16:15:11 -080026import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
cpeyserd78b3742017-08-04 19:48:53 +020027import com.google.devtools.build.lib.cmdline.Label;
Googler72f3a102017-12-01 16:28:28 -080028import com.google.devtools.build.lib.packages.RuleClass.Builder.RuleClassNamePredicate;
Han-Wen Nienhuys3428dc92015-10-21 15:03:34 +000029import com.google.devtools.build.lib.packages.RuleClass.Builder.RuleClassType;
Florian Weikertcca703a2015-12-07 09:56:38 +000030import com.google.devtools.build.lib.packages.util.PackageLoadingTestCase;
Florian Weikert432d1982015-12-01 14:38:06 +000031import org.junit.Test;
32import org.junit.runner.RunWith;
33import org.junit.runners.JUnit4;
Han-Wen Nienhuys3428dc92015-10-21 15:03:34 +000034
35/**
36 * Tests for the {@link RuleClass.Builder}.
37 */
Florian Weikert432d1982015-12-01 14:38:06 +000038@RunWith(JUnit4.class)
Florian Weikertcca703a2015-12-07 09:56:38 +000039public class RuleClassBuilderTest extends PackageLoadingTestCase {
cparsonse2d200f2018-03-06 16:15:11 -080040 private static final RuleClass.ConfiguredTargetFactory<Object, Object, Exception>
Han-Wen Nienhuys3428dc92015-10-21 15:03:34 +000041 DUMMY_CONFIGURED_TARGET_FACTORY =
cparsonse2d200f2018-03-06 16:15:11 -080042 new RuleClass.ConfiguredTargetFactory<Object, Object, Exception>() {
Han-Wen Nienhuys3428dc92015-10-21 15:03:34 +000043 @Override
cparsonse2d200f2018-03-06 16:15:11 -080044 public Object create(Object ruleContext)
45 throws InterruptedException, RuleErrorException, ActionConflictException {
Han-Wen Nienhuys3428dc92015-10-21 15:03:34 +000046 throw new IllegalStateException();
47 }
48 };
49
Florian Weikert432d1982015-12-01 14:38:06 +000050 @Test
Han-Wen Nienhuys3428dc92015-10-21 15:03:34 +000051 public void testRuleClassBuilderBasics() throws Exception {
52 RuleClass ruleClassA =
53 new RuleClass.Builder("ruleA", RuleClassType.NORMAL, false)
54 .factory(DUMMY_CONFIGURED_TARGET_FACTORY)
55 .add(attr("srcs", BuildType.LABEL_LIST).legacyAllowAnyFileType())
56 .add(attr("tags", STRING_LIST))
57 .add(attr("X", com.google.devtools.build.lib.syntax.Type.INTEGER).mandatory())
58 .build();
59
lberkiaea56b32017-05-30 12:35:33 +020060 assertThat(ruleClassA.getName()).isEqualTo("ruleA");
61 assertThat(ruleClassA.getAttributeCount()).isEqualTo(3);
62 assertThat(ruleClassA.hasBinaryOutput()).isTrue();
Han-Wen Nienhuys3428dc92015-10-21 15:03:34 +000063
lberkiaea56b32017-05-30 12:35:33 +020064 assertThat((int) ruleClassA.getAttributeIndex("srcs")).isEqualTo(0);
65 assertThat(ruleClassA.getAttributeByName("srcs")).isEqualTo(ruleClassA.getAttribute(0));
Han-Wen Nienhuys3428dc92015-10-21 15:03:34 +000066
lberkiaea56b32017-05-30 12:35:33 +020067 assertThat((int) ruleClassA.getAttributeIndex("tags")).isEqualTo(1);
68 assertThat(ruleClassA.getAttributeByName("tags")).isEqualTo(ruleClassA.getAttribute(1));
Han-Wen Nienhuys3428dc92015-10-21 15:03:34 +000069
lberkiaea56b32017-05-30 12:35:33 +020070 assertThat((int) ruleClassA.getAttributeIndex("X")).isEqualTo(2);
71 assertThat(ruleClassA.getAttributeByName("X")).isEqualTo(ruleClassA.getAttribute(2));
Han-Wen Nienhuys3428dc92015-10-21 15:03:34 +000072 }
73
Florian Weikert432d1982015-12-01 14:38:06 +000074 @Test
Han-Wen Nienhuys3428dc92015-10-21 15:03:34 +000075 public void testRuleClassBuilderTestIsBinary() throws Exception {
76 RuleClass ruleClassA =
77 new RuleClass.Builder("rule_test", RuleClassType.TEST, false)
78 .factory(DUMMY_CONFIGURED_TARGET_FACTORY)
79 .add(attr("tags", STRING_LIST))
80 .add(attr("size", STRING).value("medium"))
81 .add(attr("timeout", STRING))
82 .add(attr("flaky", BOOLEAN).value(false))
83 .add(attr("shard_count", INTEGER).value(-1))
84 .add(attr("local", BOOLEAN))
85 .build();
lberkiaea56b32017-05-30 12:35:33 +020086 assertThat(ruleClassA.hasBinaryOutput()).isTrue();
Han-Wen Nienhuys3428dc92015-10-21 15:03:34 +000087 }
88
Florian Weikert432d1982015-12-01 14:38:06 +000089 @Test
Han-Wen Nienhuys3428dc92015-10-21 15:03:34 +000090 public void testRuleClassBuilderGenruleIsNotBinary() throws Exception {
91 RuleClass ruleClassA =
92 new RuleClass.Builder("ruleA", RuleClassType.NORMAL, false)
93 .factory(DUMMY_CONFIGURED_TARGET_FACTORY)
94 .setOutputToGenfiles()
95 .add(attr("tags", STRING_LIST))
96 .build();
lberkiaea56b32017-05-30 12:35:33 +020097 assertThat(ruleClassA.hasBinaryOutput()).isFalse();
Han-Wen Nienhuys3428dc92015-10-21 15:03:34 +000098 }
99
Florian Weikert432d1982015-12-01 14:38:06 +0000100 @Test
Han-Wen Nienhuys3428dc92015-10-21 15:03:34 +0000101 public void testRuleClassTestNameValidity() throws Exception {
102 try {
103 new RuleClass.Builder("ruleA", RuleClassType.TEST, false).build();
104 fail();
105 } catch (IllegalArgumentException e) {
106 // Expected exception.
107 }
108 }
109
Florian Weikert432d1982015-12-01 14:38:06 +0000110 @Test
Han-Wen Nienhuys3428dc92015-10-21 15:03:34 +0000111 public void testRuleClassNormalNameValidity() throws Exception {
112 try {
113 new RuleClass.Builder("ruleA_test", RuleClassType.NORMAL, false).build();
114 fail();
115 } catch (IllegalArgumentException e) {
116 // Expected exception.
117 }
118 }
119
Florian Weikert432d1982015-12-01 14:38:06 +0000120 @Test
Han-Wen Nienhuys3428dc92015-10-21 15:03:34 +0000121 public void testDuplicateAttribute() throws Exception {
122 RuleClass.Builder builder =
123 new RuleClass.Builder("ruleA", RuleClassType.NORMAL, false).add(attr("a", STRING));
124 try {
125 builder.add(attr("a", STRING));
126 fail();
127 } catch (IllegalStateException e) {
128 // Expected exception.
129 }
130 }
131
Florian Weikert432d1982015-12-01 14:38:06 +0000132 @Test
Han-Wen Nienhuys3428dc92015-10-21 15:03:34 +0000133 public void testPropertiesOfAbstractRuleClass() throws Exception {
134 try {
135 new RuleClass.Builder("$ruleA", RuleClassType.ABSTRACT, false).setOutputToGenfiles();
136 fail();
137 } catch (IllegalStateException e) {
138 // Expected exception.
139 }
140
141 try {
142 new RuleClass.Builder("$ruleB", RuleClassType.ABSTRACT, false)
143 .setImplicitOutputsFunction(null);
144 fail();
145 } catch (IllegalStateException e) {
146 // Expected exception.
147 }
148 }
149
Florian Weikert432d1982015-12-01 14:38:06 +0000150 @Test
Han-Wen Nienhuys3428dc92015-10-21 15:03:34 +0000151 public void testDuplicateInheritedAttribute() throws Exception {
152 RuleClass a =
153 new RuleClass.Builder("ruleA", RuleClassType.NORMAL, false)
154 .factory(DUMMY_CONFIGURED_TARGET_FACTORY)
155 .add(attr("a", STRING).value("A"))
156 .add(attr("tags", STRING_LIST))
157 .build();
158 RuleClass b =
159 new RuleClass.Builder("ruleB", RuleClassType.NORMAL, false)
160 .factory(DUMMY_CONFIGURED_TARGET_FACTORY)
161 .add(attr("a", STRING).value("B"))
162 .add(attr("tags", STRING_LIST))
163 .build();
164 try {
165 // In case of multiple attribute inheritance the attributes must equal
166 new RuleClass.Builder("ruleC", RuleClassType.NORMAL, false, a, b).build();
167 fail();
168 } catch (IllegalArgumentException e) {
169 assertThat(e).hasMessage("Attribute a is inherited multiple times in ruleC ruleclass");
170 }
171 }
172
Florian Weikert432d1982015-12-01 14:38:06 +0000173 @Test
Han-Wen Nienhuys3428dc92015-10-21 15:03:34 +0000174 public void testRemoveAttribute() throws Exception {
175 RuleClass a =
176 new RuleClass.Builder("rule", RuleClassType.NORMAL, false)
177 .factory(DUMMY_CONFIGURED_TARGET_FACTORY)
178 .add(attr("a", STRING))
179 .add(attr("b", STRING))
180 .add(attr("tags", STRING_LIST))
181 .build();
182 RuleClass.Builder builder =
183 new RuleClass.Builder("c", RuleClassType.NORMAL, false, a)
184 .factory(DUMMY_CONFIGURED_TARGET_FACTORY);
185 RuleClass c = builder.removeAttribute("a").add(attr("a", INTEGER)).removeAttribute("b").build();
lberkiaea56b32017-05-30 12:35:33 +0200186 assertThat(c.hasAttr("a", STRING)).isFalse();
187 assertThat(c.hasAttr("a", INTEGER)).isTrue();
188 assertThat(c.hasAttr("b", STRING)).isFalse();
Han-Wen Nienhuys3428dc92015-10-21 15:03:34 +0000189
190 try {
191 builder.removeAttribute("c");
192 fail();
193 } catch (IllegalStateException e) {
194 // Expected exception.
195 }
196 }
cpeyserd78b3742017-08-04 19:48:53 +0200197
198 @Test
199 public void testRequiredToolchainsAreInherited() throws Exception {
200 Label mockToolchainType = Label.parseAbsoluteUnchecked("//mock_toolchain_type");
201 RuleClass parent =
202 new RuleClass.Builder("$parent", RuleClassType.ABSTRACT, false)
203 .add(attr("tags", STRING_LIST))
204 .addRequiredToolchains(ImmutableList.of(mockToolchainType))
205 .build();
206 RuleClass child =
207 new RuleClass.Builder("child", RuleClassType.NORMAL, false, parent)
208 .factory(DUMMY_CONFIGURED_TARGET_FACTORY)
209 .add(attr("attr", STRING))
210 .build();
211 assertThat(child.getRequiredToolchains()).contains(mockToolchainType);
212 }
Googler72f3a102017-12-01 16:28:28 -0800213
214 @Test
215 public void testBasicRuleNamePredicates() throws Exception {
216 Predicate<String> abcdef = nothingBut("abc", "def").asPredicateOfRuleClassName();
217 assertThat(abcdef.test("abc")).isTrue();
218 assertThat(abcdef.test("def")).isTrue();
219 assertThat(abcdef.test("ghi")).isFalse();
220 }
221
222 @Test
223 public void testTwoRuleNamePredicateFactoriesEquivalent() throws Exception {
224 RuleClassNamePredicate a = nothingBut("abc", "def");
225 RuleClassNamePredicate b = RuleClassNamePredicate.only(ImmutableList.of("abc", "def"));
226 assertThat(a.asPredicateOfRuleClassName()).isEqualTo(b.asPredicateOfRuleClassName());
227 assertThat(a.asPredicateOfRuleClass()).isEqualTo(b.asPredicateOfRuleClass());
228 }
229
230 @Test
231 public void testEverythingButRuleNamePredicates() throws Exception {
232 Predicate<String> abcdef = allBut("abc", "def").asPredicateOfRuleClassName();
233 assertThat(abcdef.test("abc")).isFalse();
234 assertThat(abcdef.test("def")).isFalse();
235 assertThat(abcdef.test("ghi")).isTrue();
236 }
237
238 @Test
239 public void testRuleClassNamePredicateIntersection() {
240 // two positives intersect iff they contain any of the same items
241 assertThat(nothingBut("abc", "def").consideredOverlapping(nothingBut("abc"))).isTrue();
242 assertThat(nothingBut("abc", "def").consideredOverlapping(nothingBut("ghi"))).isFalse();
243
244 // negatives are never considered to overlap...
245 assertThat(allBut("abc", "def").consideredOverlapping(allBut("abc", "def"))).isFalse();
246 assertThat(allBut("abc", "def").consideredOverlapping(allBut("ghi", "jkl"))).isFalse();
247
248 assertThat(allBut("abc", "def").consideredOverlapping(nothingBut("abc", "def"))).isFalse();
249 assertThat(nothingBut("abc", "def").consideredOverlapping(allBut("abc", "def"))).isFalse();
250
251 assertThat(allBut("abc", "def").consideredOverlapping(nothingBut("abc"))).isFalse();
252 assertThat(allBut("abc").consideredOverlapping(nothingBut("abc", "def"))).isFalse();
253 }
254
255 private RuleClassNamePredicate nothingBut(String... excludedRuleClasses) {
256 return RuleClassNamePredicate.only(excludedRuleClasses);
257 }
258
259 private RuleClassNamePredicate allBut(String... excludedRuleClasses) {
260 return RuleClassNamePredicate.allExcept(excludedRuleClasses);
261 }
Han-Wen Nienhuys3428dc92015-10-21 15:03:34 +0000262}