aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/test/java
diff options
context:
space:
mode:
authorGravatar gregce <gregce@google.com>2017-07-25 22:29:02 +0200
committerGravatar Jakob Buchgraber <buchgr@google.com>2017-07-26 10:35:01 +0200
commit6ab1d669563c4ae9483ebd6b55e20255cd2a2ec2 (patch)
tree98231fa4c07a5cfb2ac2384b4d3161e20e90c759 /src/test/java
parent6a9f4c051dde36bcb37e2c5ff8296cb6e81361b2 (diff)
Create standardized interfaces for mock rule class creation.
Generally speaking, it should be as easy as possible to create custom rule classes in tests. Aside from the tests that *need* this, this also helps disentangle traditional tests from the implementation logic of predefined rules. This nudges us further forward toward the paradigm of Bazel as "build execution engine" with all rule implementations (and tests) in Skylark. PiperOrigin-RevId: 163114414
Diffstat (limited to 'src/test/java')
-rw-r--r--src/test/java/com/google/devtools/build/lib/analysis/util/MockConfiguredTargetFactory.java39
-rw-r--r--src/test/java/com/google/devtools/build/lib/analysis/util/MockRule.java142
2 files changed, 181 insertions, 0 deletions
diff --git a/src/test/java/com/google/devtools/build/lib/analysis/util/MockConfiguredTargetFactory.java b/src/test/java/com/google/devtools/build/lib/analysis/util/MockConfiguredTargetFactory.java
new file mode 100644
index 0000000000..2736b5d4c4
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/lib/analysis/util/MockConfiguredTargetFactory.java
@@ -0,0 +1,39 @@
+// 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.actions.Artifact;
+import com.google.devtools.build.lib.analysis.ConfiguredTarget;
+import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder;
+import com.google.devtools.build.lib.analysis.RuleContext;
+import com.google.devtools.build.lib.analysis.Runfiles;
+import com.google.devtools.build.lib.analysis.RunfilesProvider;
+import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
+import com.google.devtools.build.lib.collect.nestedset.Order;
+import com.google.devtools.build.lib.rules.RuleConfiguredTargetFactory;
+
+/**
+ * A simple rule configured target factory for custom test rules.
+ */
+public class MockConfiguredTargetFactory implements RuleConfiguredTargetFactory {
+ @Override
+ public ConfiguredTarget create(RuleContext ruleContext) throws InterruptedException {
+ return
+ new RuleConfiguredTargetBuilder(ruleContext)
+ .setFilesToBuild(NestedSetBuilder.<Artifact>create(Order.STABLE_ORDER))
+ .setRunfilesSupport(null, null)
+ .add(RunfilesProvider.class, RunfilesProvider.simple(Runfiles.EMPTY))
+ .build();
+ }
+}
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
new file mode 100644
index 0000000000..9446a04ded
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/lib/analysis/util/MockRule.java
@@ -0,0 +1,142 @@
+// 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 static com.google.devtools.build.lib.packages.Attribute.ConfigurationTransition.HOST;
+import static com.google.devtools.build.lib.packages.Attribute.attr;
+import static com.google.devtools.build.lib.packages.BuildType.LABEL_LIST;
+import static com.google.devtools.build.lib.packages.BuildType.NODEP_LABEL_LIST;
+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.devtools.build.lib.analysis.BaseRuleClasses;
+import com.google.devtools.build.lib.analysis.ConfiguredRuleClassProvider;
+import com.google.devtools.build.lib.analysis.RuleDefinition;
+import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
+import com.google.devtools.build.lib.packages.Attribute;
+import com.google.devtools.build.lib.packages.BuildType;
+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:
+ *
+ * <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:
+ *
+ * <pre>
+ * class MyCustomRuleClass implements MockRule {
+ * &#064;Override
+ * public MockRule.State define() {
+ * return MockRule.define("my_custom_rule");
+ * }
+ *
+ * &#064;Override
+ * public void customize(RuleClass.Builder builder, RuleDefinitionEnvironment environment) {
+ * builder.depsCfg(HostTransition.INSTANCE);
+ * }
+ * }
+ * </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.
+ */
+public interface MockRule extends RuleDefinition {
+ /**
+ * Container for the desired name and custom attributes for this rule class.
+ */
+ class State {
+ private final String name;
+ private final List<Attribute.Builder<?>> attributes;
+
+ State(String ruleClassName, Attribute.Builder<?>... attributes) {
+ this.name = ruleClassName;
+ this.attributes = Arrays.asList(attributes);
+ }
+ }
+
+ /**
+ * Returns a new {@link State} for this rule class. 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);
+ }
+
+ /**
+ * Returns the basic state that defines this rule class. This is the only interface method
+ * implementers must override.
+ */
+ State define();
+
+ /**
+ * Allows for custom builder configuration beyond setting attributes.
+ */
+ default void customize(RuleClass.Builder builder, RuleDefinitionEnvironment environment) {
+ }
+
+ /**
+ * 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}.
+ */
+ @Override
+ default RuleClass build(RuleClass.Builder builder, RuleDefinitionEnvironment environment) {
+ builder
+ .add(attr("deps", BuildType.LABEL_LIST).allowedFileTypes())
+ .add(attr("testonly", BOOLEAN).nonconfigurable("test").value(false))
+ .add(attr("deprecation", STRING).nonconfigurable("test").value((String) null))
+ .add(attr("tags", STRING_LIST))
+ .add(attr("visibility", NODEP_LABEL_LIST).orderIndependent().cfg(HOST)
+ .nonconfigurable("test"))
+ .add(attr(RuleClass.COMPATIBLE_ENVIRONMENT_ATTR, LABEL_LIST)
+ .allowedFileTypes(FileTypeSet.NO_FILE))
+ .add(attr(RuleClass.RESTRICTED_ENVIRONMENT_ATTR, LABEL_LIST)
+ .allowedFileTypes(FileTypeSet.NO_FILE));
+ for (Attribute.Builder<?> customAttribute : define().attributes) {
+ builder.add(customAttribute);
+ }
+ customize(builder, environment);
+ return builder.build();
+ }
+
+ /**
+ * Sets this rule class's metadata with the name defined by {@link State}.
+ */
+ @Override
+ default RuleDefinition.Metadata getMetadata() {
+ return RuleDefinition.Metadata.builder()
+ .name(define().name)
+ .type(RuleClass.Builder.RuleClassType.NORMAL)
+ .factoryClass(MockConfiguredTargetFactory.class)
+ .ancestors(BaseRuleClasses.RootRule.class)
+ .build();
+ }
+}