Han-Wen Nienhuys | 3428dc9 | 2015-10-21 15:03:34 +0000 | [diff] [blame] | 1 | // 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. |
| 14 | package com.google.devtools.build.lib.packages; |
| 15 | |
| 16 | import static com.google.common.truth.Truth.assertThat; |
| 17 | import static com.google.devtools.build.lib.packages.Attribute.attr; |
| 18 | import static com.google.devtools.build.lib.syntax.Type.BOOLEAN; |
| 19 | import static com.google.devtools.build.lib.syntax.Type.INTEGER; |
| 20 | import static com.google.devtools.build.lib.syntax.Type.STRING; |
| 21 | import static com.google.devtools.build.lib.syntax.Type.STRING_LIST; |
Florian Weikert | 432d198 | 2015-12-01 14:38:06 +0000 | [diff] [blame] | 22 | import static org.junit.Assert.fail; |
Han-Wen Nienhuys | 3428dc9 | 2015-10-21 15:03:34 +0000 | [diff] [blame] | 23 | |
Googler | 72f3a10 | 2017-12-01 16:28:28 -0800 | [diff] [blame] | 24 | import com.google.common.base.Predicate; |
cpeyser | d78b374 | 2017-08-04 19:48:53 +0200 | [diff] [blame] | 25 | import com.google.common.collect.ImmutableList; |
cparsons | e2d200f | 2018-03-06 16:15:11 -0800 | [diff] [blame^] | 26 | import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException; |
cpeyser | d78b374 | 2017-08-04 19:48:53 +0200 | [diff] [blame] | 27 | import com.google.devtools.build.lib.cmdline.Label; |
Googler | 72f3a10 | 2017-12-01 16:28:28 -0800 | [diff] [blame] | 28 | import com.google.devtools.build.lib.packages.RuleClass.Builder.RuleClassNamePredicate; |
Han-Wen Nienhuys | 3428dc9 | 2015-10-21 15:03:34 +0000 | [diff] [blame] | 29 | import com.google.devtools.build.lib.packages.RuleClass.Builder.RuleClassType; |
Florian Weikert | cca703a | 2015-12-07 09:56:38 +0000 | [diff] [blame] | 30 | import com.google.devtools.build.lib.packages.util.PackageLoadingTestCase; |
Florian Weikert | 432d198 | 2015-12-01 14:38:06 +0000 | [diff] [blame] | 31 | import org.junit.Test; |
| 32 | import org.junit.runner.RunWith; |
| 33 | import org.junit.runners.JUnit4; |
Han-Wen Nienhuys | 3428dc9 | 2015-10-21 15:03:34 +0000 | [diff] [blame] | 34 | |
| 35 | /** |
| 36 | * Tests for the {@link RuleClass.Builder}. |
| 37 | */ |
Florian Weikert | 432d198 | 2015-12-01 14:38:06 +0000 | [diff] [blame] | 38 | @RunWith(JUnit4.class) |
Florian Weikert | cca703a | 2015-12-07 09:56:38 +0000 | [diff] [blame] | 39 | public class RuleClassBuilderTest extends PackageLoadingTestCase { |
cparsons | e2d200f | 2018-03-06 16:15:11 -0800 | [diff] [blame^] | 40 | private static final RuleClass.ConfiguredTargetFactory<Object, Object, Exception> |
Han-Wen Nienhuys | 3428dc9 | 2015-10-21 15:03:34 +0000 | [diff] [blame] | 41 | DUMMY_CONFIGURED_TARGET_FACTORY = |
cparsons | e2d200f | 2018-03-06 16:15:11 -0800 | [diff] [blame^] | 42 | new RuleClass.ConfiguredTargetFactory<Object, Object, Exception>() { |
Han-Wen Nienhuys | 3428dc9 | 2015-10-21 15:03:34 +0000 | [diff] [blame] | 43 | @Override |
cparsons | e2d200f | 2018-03-06 16:15:11 -0800 | [diff] [blame^] | 44 | public Object create(Object ruleContext) |
| 45 | throws InterruptedException, RuleErrorException, ActionConflictException { |
Han-Wen Nienhuys | 3428dc9 | 2015-10-21 15:03:34 +0000 | [diff] [blame] | 46 | throw new IllegalStateException(); |
| 47 | } |
| 48 | }; |
| 49 | |
Florian Weikert | 432d198 | 2015-12-01 14:38:06 +0000 | [diff] [blame] | 50 | @Test |
Han-Wen Nienhuys | 3428dc9 | 2015-10-21 15:03:34 +0000 | [diff] [blame] | 51 | 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 | |
lberki | aea56b3 | 2017-05-30 12:35:33 +0200 | [diff] [blame] | 60 | assertThat(ruleClassA.getName()).isEqualTo("ruleA"); |
| 61 | assertThat(ruleClassA.getAttributeCount()).isEqualTo(3); |
| 62 | assertThat(ruleClassA.hasBinaryOutput()).isTrue(); |
Han-Wen Nienhuys | 3428dc9 | 2015-10-21 15:03:34 +0000 | [diff] [blame] | 63 | |
lberki | aea56b3 | 2017-05-30 12:35:33 +0200 | [diff] [blame] | 64 | assertThat((int) ruleClassA.getAttributeIndex("srcs")).isEqualTo(0); |
| 65 | assertThat(ruleClassA.getAttributeByName("srcs")).isEqualTo(ruleClassA.getAttribute(0)); |
Han-Wen Nienhuys | 3428dc9 | 2015-10-21 15:03:34 +0000 | [diff] [blame] | 66 | |
lberki | aea56b3 | 2017-05-30 12:35:33 +0200 | [diff] [blame] | 67 | assertThat((int) ruleClassA.getAttributeIndex("tags")).isEqualTo(1); |
| 68 | assertThat(ruleClassA.getAttributeByName("tags")).isEqualTo(ruleClassA.getAttribute(1)); |
Han-Wen Nienhuys | 3428dc9 | 2015-10-21 15:03:34 +0000 | [diff] [blame] | 69 | |
lberki | aea56b3 | 2017-05-30 12:35:33 +0200 | [diff] [blame] | 70 | assertThat((int) ruleClassA.getAttributeIndex("X")).isEqualTo(2); |
| 71 | assertThat(ruleClassA.getAttributeByName("X")).isEqualTo(ruleClassA.getAttribute(2)); |
Han-Wen Nienhuys | 3428dc9 | 2015-10-21 15:03:34 +0000 | [diff] [blame] | 72 | } |
| 73 | |
Florian Weikert | 432d198 | 2015-12-01 14:38:06 +0000 | [diff] [blame] | 74 | @Test |
Han-Wen Nienhuys | 3428dc9 | 2015-10-21 15:03:34 +0000 | [diff] [blame] | 75 | 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(); |
lberki | aea56b3 | 2017-05-30 12:35:33 +0200 | [diff] [blame] | 86 | assertThat(ruleClassA.hasBinaryOutput()).isTrue(); |
Han-Wen Nienhuys | 3428dc9 | 2015-10-21 15:03:34 +0000 | [diff] [blame] | 87 | } |
| 88 | |
Florian Weikert | 432d198 | 2015-12-01 14:38:06 +0000 | [diff] [blame] | 89 | @Test |
Han-Wen Nienhuys | 3428dc9 | 2015-10-21 15:03:34 +0000 | [diff] [blame] | 90 | 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(); |
lberki | aea56b3 | 2017-05-30 12:35:33 +0200 | [diff] [blame] | 97 | assertThat(ruleClassA.hasBinaryOutput()).isFalse(); |
Han-Wen Nienhuys | 3428dc9 | 2015-10-21 15:03:34 +0000 | [diff] [blame] | 98 | } |
| 99 | |
Florian Weikert | 432d198 | 2015-12-01 14:38:06 +0000 | [diff] [blame] | 100 | @Test |
Han-Wen Nienhuys | 3428dc9 | 2015-10-21 15:03:34 +0000 | [diff] [blame] | 101 | 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 Weikert | 432d198 | 2015-12-01 14:38:06 +0000 | [diff] [blame] | 110 | @Test |
Han-Wen Nienhuys | 3428dc9 | 2015-10-21 15:03:34 +0000 | [diff] [blame] | 111 | 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 Weikert | 432d198 | 2015-12-01 14:38:06 +0000 | [diff] [blame] | 120 | @Test |
Han-Wen Nienhuys | 3428dc9 | 2015-10-21 15:03:34 +0000 | [diff] [blame] | 121 | 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 Weikert | 432d198 | 2015-12-01 14:38:06 +0000 | [diff] [blame] | 132 | @Test |
Han-Wen Nienhuys | 3428dc9 | 2015-10-21 15:03:34 +0000 | [diff] [blame] | 133 | 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 Weikert | 432d198 | 2015-12-01 14:38:06 +0000 | [diff] [blame] | 150 | @Test |
Han-Wen Nienhuys | 3428dc9 | 2015-10-21 15:03:34 +0000 | [diff] [blame] | 151 | 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 Weikert | 432d198 | 2015-12-01 14:38:06 +0000 | [diff] [blame] | 173 | @Test |
Han-Wen Nienhuys | 3428dc9 | 2015-10-21 15:03:34 +0000 | [diff] [blame] | 174 | 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(); |
lberki | aea56b3 | 2017-05-30 12:35:33 +0200 | [diff] [blame] | 186 | assertThat(c.hasAttr("a", STRING)).isFalse(); |
| 187 | assertThat(c.hasAttr("a", INTEGER)).isTrue(); |
| 188 | assertThat(c.hasAttr("b", STRING)).isFalse(); |
Han-Wen Nienhuys | 3428dc9 | 2015-10-21 15:03:34 +0000 | [diff] [blame] | 189 | |
| 190 | try { |
| 191 | builder.removeAttribute("c"); |
| 192 | fail(); |
| 193 | } catch (IllegalStateException e) { |
| 194 | // Expected exception. |
| 195 | } |
| 196 | } |
cpeyser | d78b374 | 2017-08-04 19:48:53 +0200 | [diff] [blame] | 197 | |
| 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 | } |
Googler | 72f3a10 | 2017-12-01 16:28:28 -0800 | [diff] [blame] | 213 | |
| 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 Nienhuys | 3428dc9 | 2015-10-21 15:03:34 +0000 | [diff] [blame] | 262 | } |