aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/test/java/com/google
diff options
context:
space:
mode:
authorGravatar Dmitry Lomov <dslomov@google.com>2015-11-26 15:31:32 +0000
committerGravatar Kristina Chodorow <kchodorow@google.com>2015-11-30 18:25:37 +0000
commit886ee6497cc76b6edc0415b3e887dce15b50f6ed (patch)
tree86bc676404d602e73ab7b3205c0df5238ebe9582 /src/test/java/com/google
parent10df952870cfc453421af5a61798a2eeaa1bb53a (diff)
Open-source some tests for cpp rules.
-- MOS_MIGRATED_REVID=108794003
Diffstat (limited to 'src/test/java/com/google')
-rw-r--r--src/test/java/com/google/devtools/build/lib/BUILD22
-rw-r--r--src/test/java/com/google/devtools/build/lib/rules/cpp/CcToolchainFeaturesTest.java545
-rw-r--r--src/test/java/com/google/devtools/build/lib/rules/cpp/CcToolchainSuiteTest.java118
-rw-r--r--src/test/java/com/google/devtools/build/lib/rules/cpp/CcToolchainTest.java79
-rw-r--r--src/test/java/com/google/devtools/build/lib/rules/cpp/CppFileTypesTest.java50
5 files changed, 814 insertions, 0 deletions
diff --git a/src/test/java/com/google/devtools/build/lib/BUILD b/src/test/java/com/google/devtools/build/lib/BUILD
index fdb1029b73..c12e7f17c9 100644
--- a/src/test/java/com/google/devtools/build/lib/BUILD
+++ b/src/test/java/com/google/devtools/build/lib/BUILD
@@ -829,6 +829,28 @@ java_test(
)
java_test(
+ name = "cpp-rules-tests",
+ srcs = glob(["rules/cpp/*.java"]),
+ args = ["com.google.devtools.build.lib.AllTests"],
+ tags = ["rules"],
+ deps = [
+ ":actions_testutil",
+ ":analysis_testutil",
+ ":testutil",
+ "//src/main/java/com/google/devtools/build/lib:analysis-exec-rules-skyframe",
+ "//src/main/java/com/google/devtools/build/lib:bazel-core",
+ "//src/main/java/com/google/devtools/build/lib:vfs",
+ "//src/main/protobuf:crosstool_config_proto",
+ "//third_party:guava",
+ "//third_party:guava-testlib",
+ "//third_party:jsr305",
+ "//third_party:junit4",
+ "//third_party:protobuf",
+ "//third_party:truth",
+ ],
+)
+
+java_test(
name = "bazel-rules-tests",
srcs = glob([
"bazel/rules/**/*.java",
diff --git a/src/test/java/com/google/devtools/build/lib/rules/cpp/CcToolchainFeaturesTest.java b/src/test/java/com/google/devtools/build/lib/rules/cpp/CcToolchainFeaturesTest.java
new file mode 100644
index 0000000000..f06f34bf82
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/lib/rules/cpp/CcToolchainFeaturesTest.java
@@ -0,0 +1,545 @@
+// Copyright 2014 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.cpp;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.fail;
+
+import com.google.common.base.Joiner;
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Multimap;
+import com.google.devtools.build.lib.analysis.config.InvalidConfigurationException;
+import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.ExpansionException;
+import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.FeatureConfiguration;
+import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.Variables;
+import com.google.devtools.build.lib.testutil.Suite;
+import com.google.devtools.build.lib.testutil.TestSpec;
+import com.google.devtools.build.lib.testutil.TestUtils;
+import com.google.devtools.build.lib.view.config.crosstool.CrosstoolConfig.CToolchain;
+import com.google.protobuf.TextFormat;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Tests for toolchain features.
+ */
+@RunWith(JUnit4.class)
+@TestSpec(size = Suite.MEDIUM_TESTS)
+public class CcToolchainFeaturesTest {
+
+ /**
+ * Creates a {@code Variables} configuration from a list of key/value pairs.
+ *
+ * <p>If there are multiple entries with the same key, the variable will be treated as sequence
+ * type.
+ */
+ private Variables createVariables(String... entries) {
+ if (entries.length % 2 != 0) {
+ throw new IllegalArgumentException(
+ "createVariables takes an even number of arguments (key/value pairs)");
+ }
+ Multimap<String, String> entryMap = ArrayListMultimap.create();
+ for (int i = 0; i < entries.length; i += 2) {
+ entryMap.put(entries[i], entries[i + 1]);
+ }
+ Variables.Builder variables = new Variables.Builder();
+ for (String name : entryMap.keySet()) {
+ Collection<String> value = entryMap.get(name);
+ if (value.size() > 1) {
+ variables.addSequenceVariable(name, value);
+ } else {
+ variables.addVariable(name, value.iterator().next());
+ }
+ }
+ return variables.build();
+ }
+
+ private CcToolchainFeatures buildFeatures(String... toolchain) throws Exception {
+ CToolchain.Builder toolchainBuilder = CToolchain.newBuilder();
+ TextFormat.merge(Joiner.on("").join(toolchain), toolchainBuilder);
+ return new CcToolchainFeatures(toolchainBuilder.buildPartial());
+ }
+
+ private Set<String> getEnabledFeatures(CcToolchainFeatures features,
+ String... requestedFeatures) throws Exception {
+ FeatureConfiguration configuration =
+ features.getFeatureConfiguration(Arrays.asList(requestedFeatures));
+ ImmutableSet.Builder<String> enabledFeatures = ImmutableSet.builder();
+ for (String feature : features.getFeatureNames()) {
+ if (configuration.isEnabled(feature)) {
+ enabledFeatures.add(feature);
+ }
+ }
+ return enabledFeatures.build();
+ }
+
+ @Test
+ public void testUnconditionalFeature() throws Exception {
+ assertThat(buildFeatures("").getFeatureConfiguration("a")
+ .isEnabled("a")).isFalse();
+ assertThat(buildFeatures("feature { name: 'a' }").getFeatureConfiguration("b")
+ .isEnabled("a")).isFalse();
+ assertThat(buildFeatures("feature { name: 'a' }").getFeatureConfiguration("a")
+ .isEnabled("a")).isTrue();
+ }
+
+ @Test
+ public void testUnsupportedAction() throws Exception {
+ FeatureConfiguration configuration = buildFeatures("").getFeatureConfiguration();
+ assertThat(configuration.getCommandLine("invalid-action", createVariables())).isEmpty();
+ }
+
+ @Test
+ public void testFlagOrderEqualsSpecOrder() throws Exception {
+ FeatureConfiguration configuration = buildFeatures(
+ "feature {",
+ " name: 'a'",
+ " flag_set {",
+ " action: 'c++-compile'",
+ " flag_group { flag: '-a-c++-compile' }",
+ " }",
+ " flag_set {",
+ " action: 'link'",
+ " flag_group { flag: '-a-c++-compile' }",
+ " }",
+ "}",
+ "feature {",
+ " name: 'b'",
+ " flag_set {",
+ " action: 'c++-compile'",
+ " flag_group { flag: '-b-c++-compile' }",
+ " }",
+ " flag_set {",
+ " action: 'link'",
+ " flag_group { flag: '-b-link' }",
+ " }",
+ "}").getFeatureConfiguration("a", "b");
+ List<String> commandLine = configuration.getCommandLine(
+ CppCompileAction.CPP_COMPILE, createVariables());
+ assertThat(commandLine).containsExactly("-a-c++-compile", "-b-c++-compile").inOrder();
+ }
+
+ private String getExpansionOfFlag(String value) throws Exception {
+ return getExpansionOfFlag(value, createVariables());
+ }
+
+ private List<String> getCommandLineForFlagGroups(String groups, Variables variables)
+ throws Exception {
+ FeatureConfiguration configuration = buildFeatures(
+ "feature {",
+ " name: 'a'",
+ " flag_set {",
+ " action: 'c++-compile'",
+ " " + groups,
+ " }",
+ "}").getFeatureConfiguration("a");
+ return configuration.getCommandLine(CppCompileAction.CPP_COMPILE, variables);
+ }
+
+ private List<String> getCommandLineForFlag(String value, Variables variables) throws Exception {
+ return getCommandLineForFlagGroups("flag_group { flag: '" + value + "' }", variables);
+ }
+
+ private String getExpansionOfFlag(String value, Variables variables) throws Exception {
+ return getCommandLineForFlag(value, variables).get(0);
+ }
+
+ private String getFlagParsingError(String value) throws Exception {
+ try {
+ getExpansionOfFlag(value);
+ fail("Expected InvalidConfigurationException");
+ return "";
+ } catch (InvalidConfigurationException e) {
+ return e.getMessage();
+ }
+ }
+
+ private String getFlagExpansionError(String value, Variables variables) throws Exception {
+ try {
+ getExpansionOfFlag(value, variables);
+ fail("Expected ExpansionException");
+ return "";
+ } catch (ExpansionException e) {
+ return e.getMessage();
+ }
+ }
+
+ @Test
+ public void testVariableExpansion() throws Exception {
+ assertThat(getExpansionOfFlag("%%")).isEqualTo("%");
+ assertThat(getExpansionOfFlag("%% a %% b %%")).isEqualTo("% a % b %");
+ assertThat(getExpansionOfFlag("%%{var}")).isEqualTo("%{var}");
+ assertThat(getExpansionOfFlag("%{v}", createVariables("v", "<flag>"))).isEqualTo("<flag>");
+ assertThat(getExpansionOfFlag(" %{v1} %{v2} ", createVariables("v1", "1", "v2", "2")))
+ .isEqualTo(" 1 2 ");
+ assertThat(getFlagParsingError("%")).contains("expected '{'");
+ assertThat(getFlagParsingError("% ")).contains("expected '{'");
+ assertThat(getFlagParsingError("%{")).contains("expected variable name");
+ assertThat(getFlagParsingError("%{}")).contains("expected variable name");
+ assertThat(getCommandLineForFlag("%{v}",
+ new Variables.Builder().addSequenceVariable("v", ImmutableList.<String>of()).build()))
+ .isEmpty();
+ assertThat(getFlagExpansionError("%{v}", createVariables())).contains("unknown variable 'v'");
+ assertThat(getFlagExpansionError("%{v}", new Variables.Builder()
+ .addSequenceVariable("v", ImmutableList.<String>of("1"))
+ .addVariable("v", "2").build()))
+ .contains("variable 'v'");
+ }
+
+ @Test
+ public void testListVariableExpansion() throws Exception {
+ assertThat(getCommandLineForFlag("%{v}", createVariables("v", "1", "v", "2")))
+ .containsExactly("1", "2");
+ assertThat(getCommandLineForFlag("%{v1} %{v2}",
+ createVariables("v1", "a1", "v1", "a2", "v2", "b")))
+ .containsExactly("a1 b", "a2 b");
+ assertThat(getFlagExpansionError("%{v1} %{v2}",
+ createVariables("v1", "a1", "v1", "a2", "v2", "b1", "v2", "b2")))
+ .contains("'v1' and 'v2'");
+ }
+
+ @Test
+ public void testFlagGroupVariableExpansion() throws Exception {
+ assertThat(getCommandLineForFlagGroups(
+ "flag_group { flag: '-f' flag: '%{v}' } flag_group { flag: '-end' }",
+ createVariables("v", "1", "v", "2")))
+ .containsExactly("-f", "1", "-f", "2", "-end");
+ assertThat(getCommandLineForFlagGroups(
+ "flag_group { flag: '-f' flag: '%{v}' } flag_group { flag: '%{v}' }",
+ createVariables("v", "1", "v", "2")))
+ .containsExactly("-f", "1", "-f", "2", "1", "2");
+ assertThat(getCommandLineForFlagGroups(
+ "flag_group { flag: '-f' flag: '%{v}' } flag_group { flag: '%{v}' }",
+ createVariables("v", "1", "v", "2")))
+ .containsExactly("-f", "1", "-f", "2", "1", "2");
+ try {
+ getCommandLineForFlagGroups(
+ "flag_group { flag: '%{v1}' flag: '%{v2}' }",
+ createVariables("v1", "1", "v1", "2", "v2", "1", "v2", "2"));
+ fail("Expected ExpansionException");
+ } catch (ExpansionException e) {
+ assertThat(e.getMessage()).contains("'v1' and 'v2'");
+ }
+ }
+
+ private Variables.NestedSequence createNestedSequence(int depth, int count, String prefix) {
+ Variables.NestedSequence.Builder builder = new Variables.NestedSequence.Builder();
+ for (int i = 0; i < count; ++i) {
+ String value = prefix + String.valueOf(i);
+ if (depth == 0) {
+ builder.addValue(value);
+ } else {
+ builder.addSequence(createNestedSequence(depth - 1, count, value));
+ }
+ }
+ return builder.build();
+ }
+
+ private Variables createNestedVariables(String name, int depth, int count) {
+ return new Variables.Builder()
+ .addSequence(name, createNestedSequence(depth, count, "")).build();
+ }
+
+ @Test
+ public void testFlagTreeVariableExpansion() throws Exception {
+ String nestedGroup =
+ ""
+ + "flag_group {"
+ + " flag_group { flag: '-a' }"
+ + " flag_group {"
+ + " flag: '%{v}'"
+ + " }"
+ + " flag_group { flag: '-b' }"
+ + "}";
+ assertThat(getCommandLineForFlagGroups(nestedGroup, createNestedVariables("v", 1, 3)))
+ .containsExactly(
+ "-a", "00", "01", "02", "-b", "-a", "10", "11", "12", "-b", "-a", "20", "21", "22",
+ "-b");
+
+ assertThat(getCommandLineForFlagGroups(nestedGroup, createNestedVariables("v", 0, 3)))
+ .containsExactly("-a", "0", "-b", "-a", "1", "-b", "-a", "2", "-b");
+
+ try {
+ getCommandLineForFlagGroups(nestedGroup, createNestedVariables("v", 2, 3));
+ fail("Expected ExpansionException");
+ } catch (ExpansionException e) {
+ assertThat(e.getMessage()).contains("'v'");
+ }
+
+ try {
+ buildFeatures(
+ "feature {",
+ " name: 'a'",
+ " flag_set {",
+ " action: 'c++-compile'",
+ " flag_group {",
+ " flag_group { flag: '-f' }",
+ " flag: '-f'",
+ " }",
+ " }",
+ "}");
+ fail("Expected ExpansionException");
+ } catch (ExpansionException e) {
+ assertThat(e.getMessage()).contains("Invalid toolchain configuration");
+ }
+ }
+
+ @Test
+ public void testImplies() throws Exception {
+ CcToolchainFeatures features = buildFeatures(
+ "feature { name: 'a' implies: 'b' implies: 'c' }",
+ "feature { name: 'b' }",
+ "feature { name: 'c' implies: 'd' }",
+ "feature { name: 'd' }",
+ "feature { name: 'e' }");
+ assertThat(getEnabledFeatures(features, "a")).containsExactly("a", "b", "c", "d");
+ }
+
+ @Test
+ public void testRequires() throws Exception {
+ CcToolchainFeatures features = buildFeatures(
+ "feature { name: 'a' requires: { feature: 'b' } }",
+ "feature { name: 'b' requires: { feature: 'c' } }",
+ "feature { name: 'c' }");
+ assertThat(getEnabledFeatures(features, "a")).isEmpty();
+ assertThat(getEnabledFeatures(features, "a", "b")).isEmpty();
+ assertThat(getEnabledFeatures(features, "a", "c")).containsExactly("c");
+ assertThat(getEnabledFeatures(features, "a", "b", "c")).containsExactly("a", "b", "c");
+ }
+
+ @Test
+ public void testDisabledRequirementChain() throws Exception {
+ CcToolchainFeatures features = buildFeatures(
+ "feature { name: 'a' }",
+ "feature { name: 'b' requires: { feature: 'c' } implies: 'a' }",
+ "feature { name: 'c' }");
+ assertThat(getEnabledFeatures(features, "b")).isEmpty();
+ features = buildFeatures(
+ "feature { name: 'a' }",
+ "feature { name: 'b' requires: { feature: 'a' } implies: 'c' }",
+ "feature { name: 'c' }",
+ "feature { name: 'd' requires: { feature: 'c' } implies: 'e' }",
+ "feature { name: 'e' }");
+ assertThat(getEnabledFeatures(features, "b", "d")).isEmpty();
+ }
+
+ @Test
+ public void testEnabledRequirementChain() throws Exception {
+ CcToolchainFeatures features = buildFeatures(
+ "feature { name: '0' implies: 'a' }",
+ "feature { name: 'a' }",
+ "feature { name: 'b' requires: { feature: 'a' } implies: 'c' }",
+ "feature { name: 'c' }",
+ "feature { name: 'd' requires: { feature: 'c' } implies: 'e' }",
+ "feature { name: 'e' }");
+ assertThat(getEnabledFeatures(features, "0", "b", "d")).containsExactly(
+ "0", "a", "b", "c", "d", "e");
+ }
+
+ @Test
+ public void testLogicInRequirements() throws Exception {
+ CcToolchainFeatures features = buildFeatures(
+ "feature { name: 'a' requires: { feature: 'b' feature: 'c' } requires: { feature: 'd' } }",
+ "feature { name: 'b' }",
+ "feature { name: 'c' }",
+ "feature { name: 'd' }");
+ assertThat(getEnabledFeatures(features, "a", "b", "c")).containsExactly("a", "b", "c");
+ assertThat(getEnabledFeatures(features, "a", "b")).containsExactly("b");
+ assertThat(getEnabledFeatures(features, "a", "c")).containsExactly("c");
+ assertThat(getEnabledFeatures(features, "a", "d")).containsExactly("a", "d");
+ }
+
+ @Test
+ public void testImpliesImpliesRequires() throws Exception {
+ CcToolchainFeatures features = buildFeatures(
+ "feature { name: 'a' implies: 'b' }",
+ "feature { name: 'b' requires: { feature: 'c' } }",
+ "feature { name: 'c' }");
+ assertThat(getEnabledFeatures(features, "a")).isEmpty();
+ }
+
+ @Test
+ public void testMultipleImplies() throws Exception {
+ CcToolchainFeatures features = buildFeatures(
+ "feature { name: 'a' implies: 'b' implies: 'c' implies: 'd' }",
+ "feature { name: 'b' }",
+ "feature { name: 'c' requires: { feature: 'e' } }",
+ "feature { name: 'd' }",
+ "feature { name: 'e' }");
+ assertThat(getEnabledFeatures(features, "a")).isEmpty();
+ assertThat(getEnabledFeatures(features, "a", "e")).containsExactly("a", "b", "c", "d", "e");
+ }
+
+ @Test
+ public void testDisabledFeaturesDoNotEnableImplications() throws Exception {
+ CcToolchainFeatures features = buildFeatures(
+ "feature { name: 'a' implies: 'b' requires: { feature: 'c' } }",
+ "feature { name: 'b' }",
+ "feature { name: 'c' }");
+ assertThat(getEnabledFeatures(features, "a")).isEmpty();
+ }
+
+ @Test
+ public void testFeatureNameCollision() throws Exception {
+ try {
+ buildFeatures(
+ "feature { name: '<<<collision>>>' }",
+ "feature { name: '<<<collision>>>' }");
+ fail("Expected InvalidConfigurationException");
+ } catch (InvalidConfigurationException e) {
+ assertThat(e.getMessage()).contains("<<<collision>>>");
+ }
+ }
+
+ @Test
+ public void testReferenceToUndefinedFeature() throws Exception {
+ try {
+ buildFeatures("feature { name: 'a' implies: '<<<undefined>>>' }");
+ fail("Expected InvalidConfigurationException");
+ } catch (InvalidConfigurationException e) {
+ assertThat(e.getMessage()).contains("<<<undefined>>>");
+ }
+ }
+
+ @Test
+ public void testImpliesWithCycle() throws Exception {
+ CcToolchainFeatures features = buildFeatures(
+ "feature { name: 'a' implies: 'b' }",
+ "feature { name: 'b' implies: 'a' }");
+ assertThat(getEnabledFeatures(features, "a")).containsExactly("a", "b");
+ assertThat(getEnabledFeatures(features, "b")).containsExactly("a", "b");
+ }
+
+ @Test
+ public void testMultipleImpliesCycle() throws Exception {
+ CcToolchainFeatures features = buildFeatures(
+ "feature { name: 'a' implies: 'b' implies: 'c' implies: 'd' }",
+ "feature { name: 'b' }",
+ "feature { name: 'c' requires: { feature: 'e' } }",
+ "feature { name: 'd' requires: { feature: 'f' } }",
+ "feature { name: 'e' requires: { feature: 'c' } }",
+ "feature { name: 'f' }");
+ assertThat(getEnabledFeatures(features, "a", "e")).isEmpty();
+ assertThat(getEnabledFeatures(features, "a", "e", "f")).containsExactly(
+ "a", "b", "c", "d", "e", "f");
+ }
+
+ @Test
+ public void testRequiresWithCycle() throws Exception {
+ CcToolchainFeatures features = buildFeatures(
+ "feature { name: 'a' requires: { feature: 'b' } }",
+ "feature { name: 'b' requires: { feature: 'a' } }",
+ "feature { name: 'c' implies: 'a' }",
+ "feature { name: 'd' implies: 'b' }");
+ assertThat(getEnabledFeatures(features, "c")).isEmpty();
+ assertThat(getEnabledFeatures(features, "d")).isEmpty();
+ assertThat(getEnabledFeatures(features, "c", "d")).containsExactly("a", "b", "c", "d");
+ }
+
+ @Test
+ public void testImpliedByOneEnabledAndOneDisabledFeature() throws Exception {
+ CcToolchainFeatures features = buildFeatures(
+ "feature { name: 'a' }",
+ "feature { name: 'b' requires: { feature: 'a' } implies: 'd' }",
+ "feature { name: 'c' implies: 'd' }",
+ "feature { name: 'd' }");
+ assertThat(getEnabledFeatures(features, "b", "c")).containsExactly("c", "d");
+ }
+
+ @Test
+ public void testRequiresOneEnabledAndOneUnsupportedFeature() throws Exception {
+ CcToolchainFeatures features = buildFeatures(
+ "feature { name: 'a' requires: { feature: 'b' } requires: { feature: 'c' } }",
+ "feature { name: 'b' }",
+ "feature { name: 'c' requires: { feature: 'd' } }",
+ "feature { name: 'd' }");
+ assertThat(getEnabledFeatures(features, "a", "b", "c")).containsExactly("a", "b");
+ }
+
+ @Test
+ public void testSuppressionViaMissingBuildVariable() throws Exception {
+ FeatureConfiguration configuration =
+ buildFeatures(
+ "feature {",
+ " name: 'a'",
+ " flag_set {",
+ " action: 'c++-compile'",
+ " expand_if_all_available: 'v'",
+ " flag_group { flag: '%{v}' }",
+ " }",
+ " flag_set {",
+ " action: 'c++-compile'",
+ " expand_if_all_available: 'v'",
+ " expand_if_all_available: 'w'",
+ " flag_group { flag: '%{v}%{w}' }",
+ " }",
+ " flag_set {",
+ " action: 'c++-compile'",
+ " flag_group { flag: 'unconditional' }",
+ " }",
+ "}")
+ .getFeatureConfiguration("a");
+
+ assertThat(configuration.getCommandLine(CppCompileAction.CPP_COMPILE, createVariables()))
+ .containsExactly("unconditional");
+ assertThat(
+ configuration.getCommandLine(CppCompileAction.CPP_COMPILE, createVariables("v", "1")))
+ .containsExactly("1", "unconditional");
+ assertThat(
+ configuration.getCommandLine(
+ CppCompileAction.CPP_COMPILE, createVariables("v", "1", "v", "2")))
+ .containsExactly("1", "2", "unconditional")
+ .inOrder();
+ assertThat(
+ configuration.getCommandLine(
+ CppCompileAction.CPP_COMPILE, createVariables("v", "1", "v", "2", "w", "3")))
+ .containsExactly("1", "2", "13", "23", "unconditional")
+ .inOrder();
+ }
+
+ @Test
+ public void testConfiguration() throws Exception {
+ CcToolchainFeatures features = buildFeatures(
+ "feature {",
+ " name: 'a'",
+ " flag_set {",
+ " action: 'c++-compile'",
+ " flag_group {",
+ " flag: '-f'",
+ " flag: '%{v}'",
+ " }",
+ " }",
+ "}",
+ "feature { name: 'b' implies: 'a' }");
+ assertThat(getEnabledFeatures(features, "b")).containsExactly("a", "b");
+ assertThat(features.getFeatureConfiguration("b").getCommandLine(CppCompileAction.CPP_COMPILE,
+ createVariables("v", "1"))).containsExactly("-f", "1");
+ byte[] serialized = TestUtils.serializeObject(features);
+ CcToolchainFeatures deserialized =
+ (CcToolchainFeatures) TestUtils.deserializeObject(serialized);
+ assertThat(getEnabledFeatures(deserialized, "b")).containsExactly("a", "b");
+ assertThat(features.getFeatureConfiguration("b").getCommandLine(CppCompileAction.CPP_COMPILE,
+ createVariables("v", "1"))).containsExactly("-f", "1");
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/lib/rules/cpp/CcToolchainSuiteTest.java b/src/test/java/com/google/devtools/build/lib/rules/cpp/CcToolchainSuiteTest.java
new file mode 100644
index 0000000000..6cca877891
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/lib/rules/cpp/CcToolchainSuiteTest.java
@@ -0,0 +1,118 @@
+// Copyright 2014 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.cpp;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.devtools.build.lib.analysis.util.BuildViewTestCaseForJunit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Unit tests for the {@code cc_toolchain_suite} rule.
+ */
+@RunWith(JUnit4.class)
+public class CcToolchainSuiteTest extends BuildViewTestCaseForJunit4 {
+ @Test
+ public void testSmoke() throws Exception {
+ scratch.file("cc/BUILD",
+ "cc_toolchain_suite(",
+ " name = 'suite',",
+ " toolchains = { ",
+ " 'cpu': ':cc-toolchain', 'k8': ':cc-toolchain', 'darwin': ':cc-toolchain' ",
+ " },",
+ " proto = \"\"\"",
+ "major_version: 'v1'",
+ "minor_version: '0'",
+ "default_target_cpu: 'cpu'",
+ "default_toolchain {",
+ " cpu: 'cpu'",
+ " toolchain_identifier: 'cpu-toolchain'",
+ "}",
+ "default_toolchain {",
+ " cpu: 'darwin'",
+ " toolchain_identifier: 'cpu-toolchain'",
+ "}",
+ "default_toolchain {",
+ " cpu: 'k8'",
+ " toolchain_identifier: 'k8-toolchain'",
+ "}",
+ "toolchain {",
+ " compiler: 'cpu-compiler'",
+ " target_cpu: 'cpu'",
+ " toolchain_identifier: 'cpu-toolchain'",
+ " host_system_name: 'linux'",
+ " target_system_name: 'linux'",
+ " abi_version: 'cpu-abi'",
+ " abi_libc_version: ''",
+ " target_libc: ''",
+ " builtin_sysroot: 'sysroot'",
+ " default_grte_top: '//cc:grtetop'",
+ " tool_path { name: 'cpu-compiler', path: 'cpu/compiler' }",
+ " tool_path { name: 'ar', path: 'cpu/ar' }",
+ " tool_path { name: 'cpp', path: 'cpu/cpp' }",
+ " tool_path { name: 'gcc', path: 'cpu/gcc' }",
+ " tool_path { name: 'gcov', path: 'cpu/gcov' }",
+ " tool_path { name: 'ld', path: 'cpu/ld' }",
+ " tool_path { name: 'nm', path: 'cpu/nm' }",
+ " tool_path { name: 'objcopy', path: 'cpu/objcopy' }",
+ " tool_path { name: 'objdump', path: 'cpu/objdump' }",
+ " tool_path { name: 'strip', path: 'cpu/strip' }",
+ "}",
+ "toolchain {",
+ " compiler: 'k8-compiler'",
+ " target_cpu: 'k8'",
+ " toolchain_identifier: 'k8-toolchain'",
+ " host_system_name: 'linux'",
+ " target_system_name: 'linux'",
+ " abi_version: ''",
+ " abi_libc_version: ''",
+ " target_libc: ''",
+ " builtin_sysroot: 'sysroot'",
+ " default_grte_top: '//cc:grtetop'",
+ " tool_path { name: 'k8-compiler', path: 'k8/compiler' }",
+ " tool_path { name: 'ar', path: 'k8/ar' }",
+ " tool_path { name: 'cpp', path: 'k8/cpp' }",
+ " tool_path { name: 'gcc', path: 'k8/gcc' }",
+ " tool_path { name: 'gcov', path: 'k8/gcov' }",
+ " tool_path { name: 'ld', path: 'k8/ld' }",
+ " tool_path { name: 'nm', path: 'k8/nm' }",
+ " tool_path { name: 'objcopy', path: 'k8/objcopy' }",
+ " tool_path { name: 'objdump', path: 'k8/objdump' }",
+ " tool_path { name: 'strip', path: 'k8/strip' }",
+ "}",
+ "\"\"\")",
+ "cc_toolchain(",
+ " name = 'cc-toolchain',",
+ " module_map = 'map',",
+ " cpu = 'cpu',",
+ " compiler_files = 'compile',",
+ " dwp_files = 'dwp',",
+ " linker_files = 'link',",
+ " strip_files = ':strip',",
+ " objcopy_files = 'objcopy',",
+ " all_files = ':every-file',",
+ " dynamic_runtime_libs = ['dynamic-runtime-libs'],",
+ " static_runtime_libs = ['static-runtime-libs'])");
+
+ invalidatePackages();
+ useConfiguration("--crosstool_top=//cc:suite");
+ CppConfiguration cppConfig = getTargetConfiguration().getFragment(CppConfiguration.class);
+ assertThat(cppConfig.getTargetCpu()).isEqualTo("cpu");
+ assertThat(cppConfig.getAbi()).isEqualTo("cpu-abi");
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/lib/rules/cpp/CcToolchainTest.java b/src/test/java/com/google/devtools/build/lib/rules/cpp/CcToolchainTest.java
new file mode 100644
index 0000000000..9099dbd721
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/lib/rules/cpp/CcToolchainTest.java
@@ -0,0 +1,79 @@
+// Copyright 2014 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.cpp;
+
+import com.google.devtools.build.lib.analysis.util.BuildViewTestCaseForJunit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Tests for toolchain features.
+ */
+@RunWith(JUnit4.class)
+public class CcToolchainTest extends BuildViewTestCaseForJunit4 {
+
+ @Test
+ public void testModuleMapAttribute() throws Exception {
+ scratchConfiguredTarget("modules/map", "c",
+ "cc_toolchain(",
+ " name = 'c',",
+ " module_map = 'map',",
+ " cpu = 'cherry',",
+ " compiler_files = 'compile-cherry',",
+ " dwp_files = 'dwp-cherry',",
+ " linker_files = 'link-cherry',",
+ " strip_files = ':every-file',",
+ " objcopy_files = 'objcopy-cherry',",
+ " all_files = ':every-file',",
+ " dynamic_runtime_libs = ['dynamic-runtime-libs-cherry'],",
+ " static_runtime_libs = ['static-runtime-libs-cherry'])");
+ }
+
+ @Test
+ public void testModuleMapAttributeOptional() throws Exception {
+ scratchConfiguredTarget("modules/map", "c",
+ "cc_toolchain(",
+ " name = 'c',",
+ " cpu = 'cherry',",
+ " compiler_files = 'compile-cherry',",
+ " dwp_files = 'dwp-cherry',",
+ " linker_files = 'link-cherry',",
+ " strip_files = ':every-file',",
+ " objcopy_files = 'objcopy-cherry',",
+ " all_files = ':every-file',",
+ " dynamic_runtime_libs = ['dynamic-runtime-libs-cherry'],",
+ " static_runtime_libs = ['static-runtime-libs-cherry'])");
+ }
+
+ @Test
+ public void testFailWithMultipleModuleMaps() throws Exception {
+ checkError("modules/multiple", "c", "expected a single artifact",
+ "filegroup(name = 'multiple-maps', srcs = ['a.cppmap', 'b.cppmap'])",
+ "cc_toolchain(",
+ " name = 'c',",
+ " module_map = ':multiple-maps',",
+ " cpu = 'cherry',",
+ " compiler_files = 'compile-cherry',",
+ " dwp_files = 'dwp-cherry',",
+ " linker_files = 'link-cherry',",
+ " strip_files = ':every-file',",
+ " objcopy_files = 'objcopy-cherry',",
+ " all_files = ':every-file',",
+ " dynamic_runtime_libs = ['dynamic-runtime-libs-cherry'],",
+ " static_runtime_libs = ['static-runtime-libs-cherry'])");
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/lib/rules/cpp/CppFileTypesTest.java b/src/test/java/com/google/devtools/build/lib/rules/cpp/CppFileTypesTest.java
new file mode 100644
index 0000000000..7970273005
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/lib/rules/cpp/CppFileTypesTest.java
@@ -0,0 +1,50 @@
+// Copyright 2014 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.cpp;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Test for {@link CppFileTypes}.
+ */
+@RunWith(JUnit4.class)
+public class CppFileTypesTest {
+
+ @Test
+ public void testTwoDotExtensions() {
+ assertTrue(CppFileTypes.OBJECT_FILE.matches("test.o"));
+ assertTrue(CppFileTypes.PIC_OBJECT_FILE.matches("test.pic.o"));
+ assertFalse(CppFileTypes.OBJECT_FILE.matches("test.pic.o"));
+ }
+
+ @Test
+ public void testVersionedSharedLibraries() {
+ assertTrue(CppFileTypes.SHARED_LIBRARY.matches("somelibrary.so"));
+ assertTrue(CppFileTypes.VERSIONED_SHARED_LIBRARY.matches("somelibrary.so.2"));
+ assertTrue(CppFileTypes.VERSIONED_SHARED_LIBRARY.matches("somelibrary.so.20"));
+ assertTrue(CppFileTypes.VERSIONED_SHARED_LIBRARY.matches("somelibrary.so.20.2"));
+ assertTrue(CppFileTypes.VERSIONED_SHARED_LIBRARY.matches("a/somelibrary.so.2"));
+ assertFalse(CppFileTypes.VERSIONED_SHARED_LIBRARY.matches("somelibrary.so.e"));
+ assertFalse(CppFileTypes.VERSIONED_SHARED_LIBRARY.matches("somelibrary.so.2e"));
+ assertFalse(CppFileTypes.VERSIONED_SHARED_LIBRARY.matches("somelibrary.so.e2"));
+ assertFalse(CppFileTypes.VERSIONED_SHARED_LIBRARY.matches("somelibrary.so.20.e2"));
+ assertFalse(CppFileTypes.VERSIONED_SHARED_LIBRARY.matches("somelibrary.a.2"));
+ }
+}