// 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.packages; import static com.google.common.truth.Truth.assertThat; import static com.google.devtools.build.lib.testutil.MoreAsserts.assertThrows; import static org.junit.Assert.fail; import com.google.common.base.Joiner; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.devtools.build.lib.cmdline.Label; import com.google.devtools.build.lib.cmdline.LabelSyntaxException; import com.google.devtools.build.lib.cmdline.RepositoryName; import com.google.devtools.build.lib.events.Location; import com.google.devtools.build.lib.packages.BuildType.LabelConversionContext; import com.google.devtools.build.lib.packages.BuildType.Selector; import com.google.devtools.build.lib.syntax.EvalException; import com.google.devtools.build.lib.syntax.EvalUtils; import com.google.devtools.build.lib.syntax.Printer; import com.google.devtools.build.lib.syntax.SelectorList; import com.google.devtools.build.lib.syntax.SelectorValue; import com.google.devtools.build.lib.syntax.Type; import com.google.devtools.build.lib.syntax.Type.ConversionException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; /** * Test of type-conversions for build-specific types. */ @RunWith(JUnit4.class) public class BuildTypeTest { private Label currentRule; private LabelConversionContext labelConversionContext; @Before public final void setCurrentRule() throws Exception { this.currentRule = Label.parseAbsolute("//quux:baz", ImmutableMap.of()); this.labelConversionContext = new LabelConversionContext(currentRule, /* repositoryMapping= */ ImmutableMap.of()); } @Test public void testKeepsDictOrdering() throws Exception { Map input = new ImmutableMap.Builder() .put("c", "//c") .put("b", "//b") .put("a", "//a") .put("f", "//f") .put("e", "//e") .put("d", "//d") .build(); assertThat(BuildType.LABEL_DICT_UNARY.convert(input, null, labelConversionContext).keySet()) .containsExactly("c", "b", "a", "f", "e", "d") .inOrder(); } @Test public void testLabelKeyedStringDictConvertsToMapFromLabelToString() throws Exception { Map input = new ImmutableMap.Builder() .put("//absolute:label", "absolute value") .put(":relative", "theory of relativity") .put("nocolon", "colonial times") .put("//current/package:explicit", "explicit content") .put( Label.parseAbsolute("//i/was/already/a/label", ImmutableMap.of()), "and that's okay") .build(); Label context = Label.parseAbsolute("//current/package:this", ImmutableMap.of()); Map expected = new ImmutableMap.Builder() .put(Label.parseAbsolute("//absolute:label", ImmutableMap.of()), "absolute value") .put( Label.parseAbsolute("//current/package:relative", ImmutableMap.of()), "theory of relativity") .put( Label.parseAbsolute("//current/package:nocolon", ImmutableMap.of()), "colonial times") .put( Label.parseAbsolute("//current/package:explicit", ImmutableMap.of()), "explicit content") .put( Label.parseAbsolute("//i/was/already/a/label", ImmutableMap.of()), "and that's okay") .build(); assertThat(BuildType.LABEL_KEYED_STRING_DICT.convert(input, null, context)) .containsExactlyEntriesIn(expected); } @Test public void testLabelKeyedStringDictConvertingStringShouldFail() throws Exception { try { BuildType.LABEL_KEYED_STRING_DICT.convert("//actually/a:label", null, currentRule); fail("Expected a conversion exception to be thrown."); } catch (ConversionException expected) { assertThat(expected) .hasMessage( "expected value of type 'dict(label, string)', " + "but got \"//actually/a:label\" (string)"); } } @Test public void testLabelKeyedStringDictConvertingListShouldFail() throws Exception { try { BuildType.LABEL_KEYED_STRING_DICT.convert( ImmutableList.of("//actually/a:label"), null, currentRule); fail("Expected a conversion exception to be thrown."); } catch (ConversionException expected) { assertThat(expected) .hasMessage( "expected value of type 'dict(label, string)', " + "but got [\"//actually/a:label\"] (List)"); } } @Test public void testLabelKeyedStringDictConvertingMapWithNonStringKeyShouldFail() throws Exception { try { BuildType.LABEL_KEYED_STRING_DICT.convert(ImmutableMap.of(1, "OK"), null, currentRule); fail("Expected a conversion exception to be thrown."); } catch (ConversionException expected) { assertThat(expected) .hasMessage("expected value of type 'string' for dict key element, but got 1 (int)"); } } @Test public void testLabelKeyedStringDictConvertingMapWithNonStringValueShouldFail() throws Exception { try { BuildType.LABEL_KEYED_STRING_DICT.convert( ImmutableMap.of("//actually/a:label", 3), null, currentRule); fail("Expected a conversion exception to be thrown."); } catch (ConversionException expected) { assertThat(expected) .hasMessage("expected value of type 'string' for dict value element, but got 3 (int)"); } } @Test public void testLabelKeyedStringDictConvertingMapWithInvalidLabelKeyShouldFail() throws Exception { try { BuildType.LABEL_KEYED_STRING_DICT.convert( ImmutableMap.of("//uplevel/references/are:../../forbidden", "OK"), null, currentRule); fail("Expected a conversion exception to be thrown."); } catch (ConversionException expected) { assertThat(expected) .hasMessage( "invalid label '//uplevel/references/are:../../forbidden' in " + "dict key element: invalid target name '../../forbidden': " + "target names may not contain up-level references '..'"); } } @Test public void testLabelKeyedStringDictConvertingMapWithMultipleEquivalentKeysShouldFail() throws Exception { Label context = Label.parseAbsolute("//current/package:this", ImmutableMap.of()); Map input = new ImmutableMap.Builder() .put(":reference", "value1") .put("//current/package:reference", "value2") .build(); try { BuildType.LABEL_KEYED_STRING_DICT.convert(input, null, context); fail("Expected a conversion exception to be thrown."); } catch (ConversionException expected) { assertThat(expected) .hasMessage( "duplicate labels: //current/package:reference " + "(as [\":reference\", \"//current/package:reference\"])"); } } @Test public void testLabelKeyedStringDictConvertingMapWithMultipleSetsOfEquivalentKeysShouldFail() throws Exception { Label context = Label.parseAbsolute("//current/rule:sibling", ImmutableMap.of()); Map input = new ImmutableMap.Builder() .put(":rule", "first set") .put("//current/rule:rule", "also first set") .put("//other/package:package", "interrupting rule") .put("//other/package", "interrupting rule's friend") .put("//current/rule", "part of first set but non-contiguous in iteration order") .put("//not/involved/in/any:collisions", "same value") .put("//also/not/involved/in/any:collisions", "same value") .build(); try { BuildType.LABEL_KEYED_STRING_DICT.convert(input, null, context); fail("Expected a conversion exception to be thrown."); } catch (ConversionException expected) { assertThat(expected) .hasMessage( "duplicate labels: //current/rule:rule " + "(as [\":rule\", \"//current/rule:rule\", \"//current/rule\"]), " + "//other/package:package " + "(as [\"//other/package:package\", \"//other/package\"])"); } } @Test public void testLabelKeyedStringDictErrorConvertingMapWithMultipleEquivalentKeysIncludesContext() throws Exception { Label context = Label.parseAbsolute("//current/package:this", ImmutableMap.of()); Map input = new ImmutableMap.Builder() .put(":reference", "value1") .put("//current/package:reference", "value2") .build(); try { BuildType.LABEL_KEYED_STRING_DICT.convert(input, "flag map", context); fail("Expected a conversion exception to be thrown."); } catch (ConversionException expected) { assertThat(expected) .hasMessage( "duplicate labels in flag map: //current/package:reference " + "(as [\":reference\", \"//current/package:reference\"])"); } } @Test public void testLabelKeyedStringDictCollectLabels() throws Exception { Map input = new ImmutableMap.Builder() .put(Label.parseAbsolute("//absolute:label", ImmutableMap.of()), "absolute value") .put( Label.parseAbsolute("//current/package:relative", ImmutableMap.of()), "theory of relativity") .put( Label.parseAbsolute("//current/package:nocolon", ImmutableMap.of()), "colonial times") .put( Label.parseAbsolute("//current/package:explicit", ImmutableMap.of()), "explicit content") .put( Label.parseAbsolute("//i/was/already/a/label", ImmutableMap.of()), "and that's okay") .build(); ImmutableList