aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/test/java/com/google/devtools/build/lib/generatedprojecttest/util
diff options
context:
space:
mode:
authorGravatar Kristina Chodorow <kchodorow@google.com>2015-11-17 21:07:28 +0000
committerGravatar Lukacs Berki <lberki@google.com>2015-11-18 15:30:23 +0000
commite624fb9ef4e966251b9f0c193f37d2d7f39d9a5e (patch)
tree8e96e9c16c9beb67c9150cce0220a937c876b03a /src/test/java/com/google/devtools/build/lib/generatedprojecttest/util
parent0a89fff21a26d1bd19bf4a122b45c2af0c3d7567 (diff)
Open source test project generation utils
-- MOS_MIGRATED_REVID=108070691
Diffstat (limited to 'src/test/java/com/google/devtools/build/lib/generatedprojecttest/util')
-rw-r--r--src/test/java/com/google/devtools/build/lib/generatedprojecttest/util/BuildFileContentsGenerator.java128
-rw-r--r--src/test/java/com/google/devtools/build/lib/generatedprojecttest/util/FileContentsGenerator.java28
-rw-r--r--src/test/java/com/google/devtools/build/lib/generatedprojecttest/util/RuleSetUtils.java188
-rw-r--r--src/test/java/com/google/devtools/build/lib/generatedprojecttest/util/TestProjectBuilder.java92
4 files changed, 436 insertions, 0 deletions
diff --git a/src/test/java/com/google/devtools/build/lib/generatedprojecttest/util/BuildFileContentsGenerator.java b/src/test/java/com/google/devtools/build/lib/generatedprojecttest/util/BuildFileContentsGenerator.java
new file mode 100644
index 0000000000..18460358de
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/lib/generatedprojecttest/util/BuildFileContentsGenerator.java
@@ -0,0 +1,128 @@
+// Copyright 2015 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.generatedprojecttest.util;
+
+import com.google.common.base.Joiner;
+import com.google.devtools.build.lib.testutil.BuildRuleBuilder;
+
+/**
+ * A generator of the contents of a Build File. It contains functions to aid in generating build
+ * files for specific purposes.
+ */
+public final class BuildFileContentsGenerator implements FileContentsGenerator {
+
+ /**
+ * Builds a string of the file contents.
+ */
+ private final StringBuilder contents = new StringBuilder();
+
+ /**
+ * Boolean to track if default package visibility has been set - it may only happen once.
+ */
+ private boolean defaultPackageVisibilityIsSet = false;
+
+ /**
+ * Index for generated rule names, so they are all unique within a file.
+ */
+ private int index = 0;
+
+ /**
+ * @return a new unique rule name
+ */
+ public String uniqueRuleName() {
+ index++;
+ return "rule" + index;
+ }
+
+ /**
+ * Set the default package visibility for this build file. If this function is never called, the
+ * default package visibility is ['//visibility:public'].
+ */
+ public FileContentsGenerator setDefaultPackageVisibility(String... visibilityLabelList) {
+ if (defaultPackageVisibilityIsSet) {
+ throw new IllegalStateException("setDefaultPackageVisibility was called twice.");
+ }
+ contents.insert(0,
+ "package(default_visibility = ['" + Joiner.on("', '").join(visibilityLabelList) + "'])\n");
+ defaultPackageVisibilityIsSet = true;
+ return this;
+ }
+
+ /**
+ * Appends the rule built from the provided BuildRuleBuilder along with the other rules
+ * generated in order to this rule to be able to build.
+ */
+ public FileContentsGenerator addRule(BuildRuleBuilder ruleBuilder) {
+ contents.append(ruleBuilder.build());
+ for (BuildRuleBuilder generatedRuleBuilder : ruleBuilder.getRulesToGenerate()) {
+ contents.append(generatedRuleBuilder.build());
+ }
+ return this;
+ }
+
+ /**
+ * Appends a chain of ruleClass rules, each depending on the one before it.
+ *
+ * @param ruleClass Name of the rule class to instantiate.
+ * @param chainLength Number of rules to create in the chain.
+ * @return this
+ */
+ public FileContentsGenerator addDependencyChainOfRule(String ruleClass, int chainLength) {
+ BuildRuleBuilder previous;
+ BuildRuleBuilder current = new BuildRuleBuilder(ruleClass, uniqueRuleName());
+ contents.append(current.build());
+
+ while (chainLength > 1) {
+ previous = current;
+ current = new BuildRuleBuilder(ruleClass, uniqueRuleName());
+ if (ruleClass.equals("java_library")) {
+ current.dependsVia("exports").on(previous);
+ } else {
+ current.dependsVia("deps").on(previous);
+ }
+ contents.append(current.build());
+ chainLength--;
+ }
+ return this;
+ }
+
+ /**
+ * Appends a chain of ruleClass rules, and one master rule which depends on all the other rules.
+ *
+ * @param ruleClass Name of the rule class to instantiate.
+ * @param noOfDeps Number of rules to create as dependencies for the first rule.
+ * @return this
+ */
+ public FileContentsGenerator addRuleWithDependencies(String ruleClass, int noOfDeps) {
+ BuildRuleBuilder masterRule = new BuildRuleBuilder(ruleClass, uniqueRuleName());
+ for (int i = 0; i < noOfDeps; i++) {
+ BuildRuleBuilder dependentRule = new BuildRuleBuilder(ruleClass, uniqueRuleName());
+ masterRule.dependsVia("deps").on(dependentRule);
+ contents.append(dependentRule.build());
+ }
+ contents.append(masterRule.build());
+ return this;
+ }
+
+ @Override
+ public String getContents() {
+ try {
+ setDefaultPackageVisibility("//visibility:public");
+ } catch (IllegalStateException e) {
+ // Default Package Visibility already set, do nothing.
+ }
+ return contents.toString();
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/lib/generatedprojecttest/util/FileContentsGenerator.java b/src/test/java/com/google/devtools/build/lib/generatedprojecttest/util/FileContentsGenerator.java
new file mode 100644
index 0000000000..e3ff1002b9
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/lib/generatedprojecttest/util/FileContentsGenerator.java
@@ -0,0 +1,28 @@
+// Copyright 2015 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.generatedprojecttest.util;
+
+/**
+ * Interface to generate the contents of useful files for tests.
+ * It should be implemented to generate the contents of BUILD files, and any other
+ * required files, for use in generated test projects.
+ */
+public interface FileContentsGenerator {
+
+ /**
+ * @return The generated file contents for the implementation.
+ */
+ String getContents();
+}
diff --git a/src/test/java/com/google/devtools/build/lib/generatedprojecttest/util/RuleSetUtils.java b/src/test/java/com/google/devtools/build/lib/generatedprojecttest/util/RuleSetUtils.java
new file mode 100644
index 0000000000..a9dbbc8aa8
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/lib/generatedprojecttest/util/RuleSetUtils.java
@@ -0,0 +1,188 @@
+// Copyright 2015 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.generatedprojecttest.util;
+
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Iterators;
+import com.google.common.collect.Lists;
+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.packages.RuleClass.Builder.RuleClassType;
+import com.google.devtools.build.lib.syntax.Type;
+import com.google.devtools.build.lib.util.Pair;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Utility class for providing static predicates for rules, to help filter the rules.
+ */
+public class RuleSetUtils {
+
+ /**
+ * Predicate for checking if a rule is hidden.
+ */
+ public static final Predicate<String> HIDDEN_RULE = new Predicate<String>() {
+ @Override
+ public boolean apply(final String input) {
+ try {
+ RuleClassType.INVISIBLE.checkName(input);
+ return true;
+ } catch (IllegalArgumentException e) {
+ return input.equals("testing_dummy_rule");
+ }
+ }
+ };
+
+ /**
+ * Predicate for checking if a rule has any mandatory attributes.
+ */
+ public static final Predicate<RuleClass> MANDATORY_ATTRIBUTES = new Predicate<RuleClass>() {
+ @Override
+ public boolean apply(final RuleClass input) {
+ List<Attribute> li = new ArrayList<>(input.getAttributes());
+ return Iterables.any(li, MANDATORY);
+ }
+ };
+
+ /**
+ * Predicate for checking if a rule allows an empty srcs attribute.
+ */
+ public static final Predicate<RuleClass> EMPTY_SOURCES_ALLOWED = new Predicate<RuleClass>() {
+ @Override
+ public boolean apply(final RuleClass input) {
+ return !input.getAttributeByName("srcs").isNonEmpty();
+ }
+ };
+
+ /**
+ * Predicate for checking that the rule can have a deps attribute, and does not have any
+ * other mandatory attributes besides deps.
+ */
+ public static final Predicate<RuleClass> DEPS_ONLY_ALLOWED = new Predicate<RuleClass>() {
+ @Override
+ public boolean apply(final RuleClass input) {
+ List<Attribute> li = new ArrayList<>(input.getAttributes());
+ // TODO(bazel-team): after the API migration we shouldn't check srcs separately
+ boolean emptySrcsAllowed = input.hasAttr("srcs", BuildType.LABEL_LIST)
+ ? !input.getAttributeByName("srcs").isNonEmpty() : true;
+ if (!(emptySrcsAllowed && Iterables.any(li, DEPS))) {
+ return false;
+ }
+
+ Iterator<Attribute> it = li.iterator();
+ boolean mandatoryAttributesBesidesDeps =
+ Iterables.any(Lists.newArrayList(Iterators.filter(it, MANDATORY)), Predicates.not(DEPS));
+ return !mandatoryAttributesBesidesDeps;
+ }
+ };
+
+ /**
+ * Predicate for checking if a RuleClass has certain attributes
+ */
+ public static class HasAttributes implements Predicate<RuleClass> {
+
+ private static enum Operator {
+ ANY, ALL
+ }
+
+ private final List<Pair<String, Type<?>>> attributes;
+ private final Operator operator;
+
+ public HasAttributes(Collection<Pair<String, Type<?>>> attributes, Operator operator) {
+ this.attributes = ImmutableList.copyOf(attributes);
+ this.operator = operator;
+ }
+
+ @Override
+ public boolean apply(final RuleClass input) {
+ switch (operator) {
+ case ANY:
+ for (Pair<String, Type<?>> attribute : attributes) {
+ if (input.hasAttr(attribute.first, attribute.second)) {
+ return true;
+ }
+ }
+ return false;
+ case ALL:
+ for (Pair<String, Type<?>> attribute : attributes) {
+ if (!input.hasAttr(attribute.first, attribute.second)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+ }
+
+ public static final Predicate<RuleClass> hasAnyAttributes(
+ Collection<Pair<String, Type<?>>> attributes) {
+ return new HasAttributes(attributes, HasAttributes.Operator.ANY);
+ }
+
+ public static final Predicate<RuleClass> hasAllAttributes(
+ Collection<Pair<String, Type<?>>> attributes) {
+ return new HasAttributes(attributes, HasAttributes.Operator.ALL);
+ }
+
+ /**
+ * Predicate for checking if an attribute is mandatory.
+ */
+ private static final Predicate<Attribute> MANDATORY = new Predicate<Attribute>() {
+ @Override
+ public boolean apply(final Attribute input) {
+ return input.isMandatory();
+ }
+ };
+
+ /**
+ * Predicate for checking if an attribute is the "deps" attribute.
+ */
+ private static final Predicate<Attribute> DEPS = new Predicate<Attribute>() {
+ @Override
+ public boolean apply(final Attribute input) {
+ return input.getName().equals("deps");
+ }
+ };
+
+ /**
+ * Predicate for checking if all the strings in a list of strings are different.
+ */
+ public static final Predicate<List<String>> ELEMENTS_ALL_DIFFERENT =
+ new Predicate<List<String>>() {
+ @Override
+ public boolean apply(final List<String> input) {
+ Set<String> inputAsSet = new HashSet<>(input);
+ return input.size() == inputAsSet.size();
+ }
+ };
+
+ /**
+ * Predicate for checking if a rule class is not in excluded.
+ */
+ public static Predicate<String> notContainsAnyOf(final ImmutableSet<String> excluded) {
+ return Predicates.not(Predicates.in(excluded));
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/lib/generatedprojecttest/util/TestProjectBuilder.java b/src/test/java/com/google/devtools/build/lib/generatedprojecttest/util/TestProjectBuilder.java
new file mode 100644
index 0000000000..ee32d724e6
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/lib/generatedprojecttest/util/TestProjectBuilder.java
@@ -0,0 +1,92 @@
+// Copyright 2015 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.generatedprojecttest.util;
+
+import com.google.devtools.build.lib.testutil.BuildRuleBuilder;
+import com.google.devtools.build.lib.testutil.Scratch;
+
+import java.io.IOException;
+
+/**
+ * A builder that generates whole test projects in a scratch file system.
+ */
+
+// TODO(blaze-team): (2012) generate valid parameterized BUILD rules.
+// TODO(blaze-team): (2012) generate any required src or data or other files.
+
+public final class TestProjectBuilder {
+
+ // Default workspace name.
+ private static final String WORKSPACE = "workspace";
+
+ // The directory name to use for the workspace.
+ private final String workspace;
+ /**
+ * Provides functionality to create and manipulate a scratch file system.
+ */
+ private final Scratch scratch = new Scratch();
+
+ /**
+ * Creates a builder that will use the default workspace name as the directory.
+ */
+ public TestProjectBuilder() {
+ this(WORKSPACE);
+ }
+
+ /**
+ * Creates a builder that will use the given workspace name as the directory.
+ */
+ public TestProjectBuilder(String workspace) {
+ this.workspace = workspace;
+ }
+
+ /**
+ * Creates a file in the specified directory with the given content.
+ *
+ * @param dirName directory to create a new file within
+ * @param fileName file Name of the new file (must be unique within the directory)
+ * @param generator FileContentsGenerator implementation
+ * @throws IOException if the input dirName was not valid, or the file already existed
+ */
+ public void createFileInDir(String dirName, String fileName, FileContentsGenerator generator)
+ throws IOException {
+ scratch.file(
+ String.format("/%s/%s/%s", workspace, dirName, fileName), generator.getContents());
+ }
+
+ /**
+ * Returns the {@link Scratch} containing the Test Project that has been built.
+ */
+ public Scratch getScratch() {
+ return this.scratch;
+ }
+
+ /**
+ * Creates a dummy file with 'dummy' as content in the given package with the given name.
+ * @throws IOException
+ */
+ public void createDummyFileInDir(String pkg, String fileName) throws IOException {
+ scratch.file(String.format("%s/%s", pkg, fileName), "dummy");
+ }
+
+ /**
+ * Generates the files necessary for the rule.
+ */
+ public void createFilesToGenerate(BuildRuleBuilder ruleBuilder) throws IOException {
+ for (String file : ruleBuilder.getFilesToGenerate()) {
+ scratch.file(file, "dummy");
+ }
+ }
+}