aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/test/java/com/google/devtools/build/lib/rules/objc/RuleType.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/java/com/google/devtools/build/lib/rules/objc/RuleType.java')
-rw-r--r--src/test/java/com/google/devtools/build/lib/rules/objc/RuleType.java145
1 files changed, 145 insertions, 0 deletions
diff --git a/src/test/java/com/google/devtools/build/lib/rules/objc/RuleType.java b/src/test/java/com/google/devtools/build/lib/rules/objc/RuleType.java
new file mode 100644
index 0000000000..18875c680d
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/lib/rules/objc/RuleType.java
@@ -0,0 +1,145 @@
+// 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.rules.objc;
+
+import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableMap;
+import com.google.devtools.build.lib.testutil.Scratch;
+import com.google.devtools.build.lib.util.Preconditions;
+import java.io.IOException;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Provides utilities to help test a certain rule type without requiring the calling code to know
+ * exactly what kind of rule is being tested. Only one instance is needed per rule type (e.g. one
+ * instance for {@code objc_library}).
+ */
+public abstract class RuleType {
+ /**
+ * What to pass as the value of some attribute to indicate an attribute should not be added to the
+ * rule. This can either be to test an error condition, or to use an alternative attribute to
+ * supply the value.
+ */
+ public static final String OMIT_REQUIRED_ATTR = "<OMIT_REQUIRED_ATTR>";
+
+ private final String ruleTypeName;
+
+ RuleType(String ruleTypeName) {
+ this.ruleTypeName = ruleTypeName;
+ }
+
+ /**
+ * The name of this type as it appears in {@code BUILD} files, such as {@code objc_library}.
+ */
+ final String getRuleTypeName() {
+ return ruleTypeName;
+ }
+
+ /**
+ * Returns whether this type exports companion library target in Xcode.
+ */
+ final boolean exportsXcodeCompanionTarget() {
+ return ruleTypeName.equals("objc_binary");
+ }
+
+ /**
+ * Returns the bundle extension for the bundles generated by the rule.
+ */
+ final String bundleExtension() {
+ return ruleTypeName.equals("ios_test") ? "xctest" : "app";
+ }
+
+ /**
+ * Returns names and values, and otherwise prepares, extra attributes required for this rule type
+ * to be without error. For instance, if this rule type requires 'srcs' and 'infoplist'
+ * attributes, this method may be implemented as follows:
+ * <pre>
+ * {@code
+ * List<String> attributes = new ArrayList<>();
+ * if (!alreadyAdded.contains("srcs")) {
+ * scratch.file("/workspace_root/" + packageDir + "/a.m");
+ * attributes.add("srcs = ['a.m']");
+ * }
+ * if (!alreadyAdded.contains(INFOPLIST_ATTR)) {
+ * scratch.file("/workspace_root/" + packageDir + "Info.plist");
+ * attributes.add("infoplist = ['Info.plist']");
+ * }
+ * return attributes;
+ * </pre>
+ * }
+ *
+ * @throws IOException for whatever reason the implementator feels like, but mostly just when
+ * a scratch file couldn't be created
+ */
+ abstract Iterable<String> requiredAttributes(
+ Scratch scratch, String packageDir, Set<String> alreadyAdded) throws IOException;
+
+ private ImmutableMap<String, String> map(String... attrs) {
+ ImmutableMap.Builder<String, String> map = new ImmutableMap.Builder<>();
+ Preconditions.checkArgument((attrs.length & 1) == 0,
+ "attrs must have an even number of elements");
+ for (int i = 0; i < attrs.length; i += 2) {
+ map.put(attrs[i], attrs[i + 1]);
+ }
+ return map.build();
+ }
+
+ /**
+ * Generates the String necessary to define a target of this rule type.
+ *
+ * @param packageDir the package in which to create the target
+ * @param name the name of the target
+ * @param checkSpecificAttrs alternating name/values of attributes to add to the rule that are
+ * required for the check being performed to be defined a certain way. Pass
+ * {@link #OMIT_REQUIRED_ATTR} for a value to prevent an attribute from being automatically
+ * defined.
+ */
+ final String target(
+ Scratch scratch, String packageDir, String name, String... checkSpecificAttrs)
+ throws IOException {
+ ImmutableMap<String, String> checkSpecific = map(checkSpecificAttrs);
+ StringBuilder target = new StringBuilder(ruleTypeName)
+ .append("(name = '")
+ .append(name)
+ .append("',");
+ for (Map.Entry<String, String> entry : checkSpecific.entrySet()) {
+ if (entry.getValue().equals(OMIT_REQUIRED_ATTR)) {
+ continue;
+ }
+ target.append(entry.getKey())
+ .append("=")
+ .append(entry.getValue())
+ .append(",");
+ }
+ Joiner.on(",").appendTo(
+ target,
+ requiredAttributes(scratch, packageDir, checkSpecific.keySet()));
+ target.append(')');
+ return target.toString();
+
+ }
+
+ /**
+ * Creates a target at //x:x which is the only target in the BUILD file. Returns the string that
+ * is written to the scratch file as it is often useful for debugging purposes.
+ */
+ public final String scratchTarget(Scratch scratch, String... checkSpecificAttrs)
+ throws IOException {
+ String target = target(scratch, "x", "x", checkSpecificAttrs);
+ scratch.file("x/BUILD", target);
+ return target;
+ }
+}