diff options
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.java | 145 |
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; + } +} |