aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/test/java/com/google/devtools/build/lib/analysis/util
diff options
context:
space:
mode:
authorGravatar gregce <gregce@google.com>2017-07-28 19:07:10 +0200
committerGravatar Dmitry Lomov <dslomov@google.com>2017-07-31 16:32:09 +0200
commited08fcfcfe42b96e13570c5cc0060a337b8a55bb (patch)
treeb1d76651b13f2268d11d0a7e3410274879facb41 /src/test/java/com/google/devtools/build/lib/analysis/util
parent644bb1101a368ef68401c251ca4ac3d634dc205b (diff)
Provide a lambda interface for custom mock rule class behavior.
This extends the "easy use" idea of MockRule from just custom attributes to full-on custom behavior. For a proof of concept, also port Bazel's late-bound attribute tests. PiperOrigin-RevId: 163483121
Diffstat (limited to 'src/test/java/com/google/devtools/build/lib/analysis/util')
-rw-r--r--src/test/java/com/google/devtools/build/lib/analysis/util/MockRule.java91
-rw-r--r--src/test/java/com/google/devtools/build/lib/analysis/util/MockRuleCustomBehavior.java54
2 files changed, 110 insertions, 35 deletions
diff --git a/src/test/java/com/google/devtools/build/lib/analysis/util/MockRule.java b/src/test/java/com/google/devtools/build/lib/analysis/util/MockRule.java
index bba074bec4..9c97e7d52d 100644
--- a/src/test/java/com/google/devtools/build/lib/analysis/util/MockRule.java
+++ b/src/test/java/com/google/devtools/build/lib/analysis/util/MockRule.java
@@ -21,6 +21,7 @@ import static com.google.devtools.build.lib.syntax.Type.BOOLEAN;
import static com.google.devtools.build.lib.syntax.Type.STRING;
import static com.google.devtools.build.lib.syntax.Type.STRING_LIST;
+import com.google.common.base.Preconditions;
import com.google.devtools.build.lib.analysis.BaseRuleClasses;
import com.google.devtools.build.lib.analysis.ConfiguredRuleClassProvider;
import com.google.devtools.build.lib.analysis.RuleDefinition;
@@ -31,75 +32,94 @@ import com.google.devtools.build.lib.packages.RuleClass;
import com.google.devtools.build.lib.util.FileTypeSet;
import java.util.Arrays;
-import java.util.List;
/**
* Provides a simple API for creating custom rule classes for tests.
*
- * <p>Usage:
+ * <p>Usage (for a custom rule type that just needs to exist):
*
* <pre>
* MockRule fooRule = () -> MockRule.define("foo_rule");
- * MockRule ruleWithCustomAttr = () -> MockRule.define("attr_rule", attr("myattr", Type.STRING));
* </pre>
*
- * <p>If you need special behavior beyond custom attributes:
+ * <p>Usage (for custom attributes):
*
* <pre>
- * class MyCustomRuleClass implements MockRule {
- * &#064;Override
- * public MockRule.State define() {
- * return MockRule.define("my_custom_rule");
- * }
+ * MockRule fooRule = () -> MockRule.define("foo_rule", attr("myattr", Type.STRING));
+ * </pre>
+ *
+ * <p>Usage (for arbitrary customization):
*
- * &#064;Override
- * public void customize(RuleClass.Builder builder, RuleDefinitionEnvironment environment) {
- * builder.depsCfg(HostTransition.INSTANCE);
- * }
- * }
+ * <pre>
+ * MockRule fooRule = () -> MockRule.define(
+ * "foo_rule",
+ * (builder, env) ->
+ * builder
+ * .removeAttribute("tags")
+ * .requiresConfigurationFragments(FooConfiguration.class);
+ * );
* </pre>
*
+ *
* <p>We use lambdas for custom rule classes because {@link ConfiguredRuleClassProvider} indexes
* rule class definitions by their Java class names. So each definition has to have its own
* unique Java class.
+ *
+ * <p>Both of the following forms are valid:
+ *
+ * <pre>MockRule fooRule = () -> MockRule.define("foo_rule");</pre>
+ * <pre>RuleDefinition fooRule = (MockRule) () -> MockRule.define("foo_rule");</pre>
+ *
+ * <p>Use discretion in choosing your preferred form. The first is more compact. But the second
+ * makes it clearer that <code>fooRule</code> is a proper rule class definition.
*/
public interface MockRule extends RuleDefinition {
/**
- * Container for the desired name and custom attributes for this rule class.
+ * Container for the desired name and custom settings for this rule class.
*/
class State {
private final String name;
- private final List<Attribute.Builder<?>> attributes;
+ private final MockRuleCustomBehavior customBehavior;
- State(String ruleClassName, Attribute.Builder<?>... attributes) {
- this.name = ruleClassName;
- this.attributes = Arrays.asList(attributes);
+ State(String ruleClassName, MockRuleCustomBehavior customBehavior) {
+ this.name = Preconditions.checkNotNull(ruleClassName);
+ this.customBehavior = Preconditions.checkNotNull(customBehavior);
}
}
/**
- * Returns a new {@link State} for this rule class. This is a convenience method for lambda
- * definitions:
+ * Returns a new {@link State} for this rule class with custom attributes. This is a convenience
+ * method for lambda definitions:
*
* <pre>
* MockRule myRule = () -> MockRule.define("my_rule", attr("myattr", Type.STRING));
* </pre>
*/
static State define(String ruleClassName, Attribute.Builder<?>... attributes) {
- return new State(ruleClassName, attributes);
+ return new State(
+ ruleClassName,
+ new MockRuleCustomBehavior.CustomAttributes(Arrays.asList(attributes)));
}
/**
- * Returns the basic state that defines this rule class. This is the only interface method
- * implementers must override.
+ * Returns a new {@link State} for this rule class with arbitrary custom behavior. This is a
+ * convenience method for lambda definitions:
+ *
+ * <pre>
+ * MockRule myRule = () -> MockRule.define(
+ * "my_rule",
+ * (builder, env) -> builder.requiresConfigurationFragments(FooConfiguration.class));
+ * </pre>
*/
- State define();
+ static State define(String ruleClassName, MockRuleCustomBehavior customBehavior) {
+ return new State(ruleClassName, customBehavior);
+ }
/**
- * Allows for custom builder configuration beyond setting attributes.
+ * Returns the basic state that defines this rule class. This is the only interface method
+ * implementers must override.
*/
- default void customize(RuleClass.Builder builder, RuleDefinitionEnvironment environment) {
- }
+ State define();
/**
* Default <code>"deps"</code> attribute for rule classes that don't need special behavior.
@@ -110,10 +130,12 @@ public interface MockRule extends RuleDefinition {
* Builds out this rule with default attributes Blaze expects of all rules plus the custom
* attributes defined by this implementation's {@link State}.
*
- * <p>Do not override this method. For extra custom behavior, override {@link #customize}.
+ * <p>Do not override this method. For extra custom behavior, use
+ * {@link #define(String, MockRuleCustomBehavior)}
*/
@Override
default RuleClass build(RuleClass.Builder builder, RuleDefinitionEnvironment environment) {
+ State state = define();
builder
.add(attr("testonly", BOOLEAN).nonconfigurable("test").value(false))
.add(attr("deprecation", STRING).nonconfigurable("test").value((String) null))
@@ -121,13 +143,12 @@ public interface MockRule extends RuleDefinition {
.add(attr("visibility", NODEP_LABEL_LIST).orderIndependent().cfg(HOST)
.nonconfigurable("test"))
.add(attr(RuleClass.COMPATIBLE_ENVIRONMENT_ATTR, LABEL_LIST)
- .allowedFileTypes(FileTypeSet.NO_FILE))
+ .allowedFileTypes(FileTypeSet.NO_FILE)
+ .dontCheckConstraints())
.add(attr(RuleClass.RESTRICTED_ENVIRONMENT_ATTR, LABEL_LIST)
- .allowedFileTypes(FileTypeSet.NO_FILE));
- for (Attribute.Builder<?> customAttribute : define().attributes) {
- builder.add(customAttribute);
- }
- customize(builder, environment);
+ .allowedFileTypes(FileTypeSet.NO_FILE)
+ .dontCheckConstraints());
+ state.customBehavior.customize(builder, environment);
return builder.build();
}
diff --git a/src/test/java/com/google/devtools/build/lib/analysis/util/MockRuleCustomBehavior.java b/src/test/java/com/google/devtools/build/lib/analysis/util/MockRuleCustomBehavior.java
new file mode 100644
index 0000000000..2d811dcdd9
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/lib/analysis/util/MockRuleCustomBehavior.java
@@ -0,0 +1,54 @@
+// Copyright 2017 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package com.google.devtools.build.lib.analysis.util;
+
+import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
+import com.google.devtools.build.lib.packages.Attribute;
+import com.google.devtools.build.lib.packages.RuleClass;
+
+/**
+ * Interface for supporting arbitary custom behavior in mock rule classes.
+ *
+ * <p>See {@link MockRule} for details and usage instructions.
+ */
+public interface MockRuleCustomBehavior {
+
+ /**
+ * Adds custom behavior to a mock rule class.
+ *
+ * <p>It's not necessary to call {@link RuleClass.Builder#build} here.
+ */
+ void customize(RuleClass.Builder builder, RuleDefinitionEnvironment env);
+
+ /* Predefined no-op behavior. */
+ MockRuleCustomBehavior NOOP = (builder, env) -> {};
+
+ /**
+ * Predefined behavior that populates a list of attributes.
+ */
+ class CustomAttributes implements MockRuleCustomBehavior {
+ private final Iterable<Attribute.Builder<?>> attributes;
+
+ CustomAttributes(Iterable<Attribute.Builder<?>> attributes) {
+ this.attributes = attributes;
+ }
+
+ @Override
+ public void customize(RuleClass.Builder builder, RuleDefinitionEnvironment env) {
+ for (Attribute.Builder<?> attribute : attributes) {
+ builder.add(attribute);
+ }
+ }
+ }
+}