blob: a744b6e38daaa5b00861fa3583e40f3189164857 [file] [log] [blame]
// 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.config;
import static com.google.common.collect.MoreCollectors.onlyElement;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth8.assertThat;
import static org.junit.Assert.fail;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedMap;
import com.google.common.collect.ImmutableSortedSet;
import com.google.common.testing.EqualsTester;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.common.options.Options;
import com.google.devtools.common.options.OptionsParser;
import com.google.devtools.common.options.OptionsParsingException;
import java.util.Map;
import java.util.Set;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/** Tests for feature flag option fragments. */
@RunWith(JUnit4.class)
public final class ConfigFeatureFlagOptionsTest {
@Test
public void flagState_startsEmpty() throws Exception {
assertThat(new ConfigFeatureFlagOptions().getFlagValues()).isEmpty();
assertThat(new ConfigFeatureFlagOptions().getKnownDefaultFlags()).isEmpty();
assertThat(new ConfigFeatureFlagOptions().getUnknownFlags()).isEmpty();
}
@Test
public void replaceFlagValues_reflectedInGetFlagValues() throws Exception {
Map<Label, String> originalMap =
ImmutableMap.of(
Label.parseAbsoluteUnchecked("//label:a"), "value",
Label.parseAbsoluteUnchecked("//label:b"), "otherValue");
ConfigFeatureFlagOptions options = new ConfigFeatureFlagOptions();
options.replaceFlagValues(originalMap);
assertThat(options.getFlagValues()).containsExactlyEntriesIn(originalMap);
}
@Test
public void replaceFlagValues_totallyReplacesFlagValuesMap() throws Exception {
Map<Label, String> originalMap =
ImmutableMap.of(
Label.parseAbsoluteUnchecked("//label:a"), "value",
Label.parseAbsoluteUnchecked("//label:b"), "otherValue");
Map<Label, String> newMap =
ImmutableMap.of(
Label.parseAbsoluteUnchecked("//label:a"), "differentValue",
Label.parseAbsoluteUnchecked("//label:c"), "differentFlag");
ConfigFeatureFlagOptions options = new ConfigFeatureFlagOptions();
options.replaceFlagValues(originalMap);
options.replaceFlagValues(newMap);
assertThat(options.getFlagValues()).containsExactlyEntriesIn(newMap);
}
@Test
public void replaceFlagValues_emptiesKnownDefaultFlagsAndUnknownFlags() throws Exception {
Map<Label, String> originalMap =
ImmutableMap.of(
Label.parseAbsoluteUnchecked("//label:a"), "value",
Label.parseAbsoluteUnchecked("//label:b"), "otherValue");
ConfigFeatureFlagOptions options = new ConfigFeatureFlagOptions();
options.replaceFlagValues(originalMap);
options.trimFlagValues(
ImmutableSortedSet.of(
Label.parseAbsoluteUnchecked("//label:a"),
Label.parseAbsoluteUnchecked("//label:c"),
Label.parseAbsoluteUnchecked("//label:d")));
options.replaceFlagValues(originalMap);
assertThat(options.getKnownDefaultFlags()).isEmpty();
assertThat(options.getUnknownFlags()).isEmpty();
}
@Test
public void trimFlagValues_defaults_toEmptySetProducesEmptyOptions() throws Exception {
ConfigFeatureFlagOptions options = new ConfigFeatureFlagOptions();
options.trimFlagValues(ImmutableSet.of());
assertThat(options.getFlagValues()).isEmpty();
assertThat(options.getKnownDefaultFlags()).isPresent();
assertThat(options.getKnownDefaultFlags().get()).isEmpty();
assertThat(options.getUnknownFlags()).isEmpty();
}
@Test
public void trimFlagValues_defaults_toPopulatedSetPopulatesKnownDefaultFlags() throws Exception {
ConfigFeatureFlagOptions options = new ConfigFeatureFlagOptions();
options.trimFlagValues(
ImmutableSet.of(
Label.parseAbsoluteUnchecked("//label:a"),
Label.parseAbsoluteUnchecked("//label:b"),
Label.parseAbsoluteUnchecked("//label:c")));
assertThat(options.getFlagValues()).isEmpty();
assertThat(options.getKnownDefaultFlags()).isPresent();
assertThat(options.getKnownDefaultFlags().get())
.containsExactly(
Label.parseAbsoluteUnchecked("//label:a"),
Label.parseAbsoluteUnchecked("//label:b"),
Label.parseAbsoluteUnchecked("//label:c"));
assertThat(options.getUnknownFlags()).isEmpty();
}
@Test
public void trimFlagValues_withFlagsSet_toEmptySetProducesEmptyOptions() throws Exception {
ConfigFeatureFlagOptions options = new ConfigFeatureFlagOptions();
options.replaceFlagValues(
ImmutableMap.of(
Label.parseAbsoluteUnchecked("//label:a"),
"value",
Label.parseAbsoluteUnchecked("//label:d"),
"otherValue"));
options.trimFlagValues(ImmutableSet.of());
assertThat(options.getFlagValues()).isEmpty();
assertThat(options.getKnownDefaultFlags()).isPresent();
assertThat(options.getKnownDefaultFlags().get()).isEmpty();
assertThat(options.getUnknownFlags()).isEmpty();
}
@Test
public void trimFlagValues_withFlagsSet_toPopulatedSetPopulatesFlagValuesAndKnownDefaultFlags()
throws Exception {
ConfigFeatureFlagOptions options = new ConfigFeatureFlagOptions();
options.replaceFlagValues(
ImmutableMap.of(
Label.parseAbsoluteUnchecked("//label:a"),
"value",
Label.parseAbsoluteUnchecked("//label:d"),
"otherValue"));
options.trimFlagValues(
ImmutableSet.of(
Label.parseAbsoluteUnchecked("//label:a"),
Label.parseAbsoluteUnchecked("//label:b"),
Label.parseAbsoluteUnchecked("//label:c")));
assertThat(options.getFlagValues())
.containsExactly(Label.parseAbsoluteUnchecked("//label:a"), "value");
assertThat(options.getKnownDefaultFlags()).isPresent();
assertThat(options.getKnownDefaultFlags().get())
.containsExactly(
Label.parseAbsoluteUnchecked("//label:b"), Label.parseAbsoluteUnchecked("//label:c"));
assertThat(options.getUnknownFlags()).isEmpty();
}
@Test
public void trimFlagValues_withTrimmedFlagsSet_toEmptySetProducesEmptyOptions() throws Exception {
ConfigFeatureFlagOptions options = new ConfigFeatureFlagOptions();
options.replaceFlagValues(
ImmutableMap.of(
Label.parseAbsoluteUnchecked("//label:a"),
"value",
Label.parseAbsoluteUnchecked("//label:d"),
"otherValue"));
options.trimFlagValues(
ImmutableSet.of(
Label.parseAbsoluteUnchecked("//label:a"), Label.parseAbsoluteUnchecked("//label:b")));
options.trimFlagValues(ImmutableSet.of());
assertThat(options.getFlagValues()).isEmpty();
assertThat(options.getKnownDefaultFlags()).isPresent();
assertThat(options.getKnownDefaultFlags().get()).isEmpty();
assertThat(options.getUnknownFlags()).isEmpty();
}
@Test
public void trimFlagValues_withTrimmedFlagsSet_toPopulatedSetPopulatesFlagState()
throws Exception {
ConfigFeatureFlagOptions options = new ConfigFeatureFlagOptions();
options.replaceFlagValues(
ImmutableMap.of(
Label.parseAbsoluteUnchecked("//label:a"),
"value",
Label.parseAbsoluteUnchecked("//label:d"),
"otherValue"));
options.trimFlagValues(
ImmutableSet.of(
Label.parseAbsoluteUnchecked("//label:a"), Label.parseAbsoluteUnchecked("//label:b")));
options.trimFlagValues(
ImmutableSet.of(
Label.parseAbsoluteUnchecked("//label:a"),
Label.parseAbsoluteUnchecked("//label:b"),
Label.parseAbsoluteUnchecked("//label:c")));
assertThat(options.getFlagValues())
.containsExactly(Label.parseAbsoluteUnchecked("//label:a"), "value");
assertThat(options.getKnownDefaultFlags()).isPresent();
assertThat(options.getKnownDefaultFlags().get())
.containsExactly(Label.parseAbsoluteUnchecked("//label:b"));
assertThat(options.getUnknownFlags())
.containsExactly(Label.parseAbsoluteUnchecked("//label:c"));
}
@Test
public void hostMode_clearsFlagState() throws Exception {
ConfigFeatureFlagOptions options = new ConfigFeatureFlagOptions();
options.enforceTransitiveConfigsForConfigFeatureFlag = true;
options.replaceFlagValues(
ImmutableMap.of(
Label.parseAbsoluteUnchecked("//label:a"),
"value",
Label.parseAbsoluteUnchecked("//label:d"),
"otherValue"));
options.trimFlagValues(
ImmutableSet.of(
Label.parseAbsoluteUnchecked("//label:a"), Label.parseAbsoluteUnchecked("//label:b")));
options.trimFlagValues(
ImmutableSet.of(
Label.parseAbsoluteUnchecked("//label:a"),
Label.parseAbsoluteUnchecked("//label:b"),
Label.parseAbsoluteUnchecked("//label:c")));
ConfigFeatureFlagOptions hostOptions = (ConfigFeatureFlagOptions) options.getHost();
assertThat(hostOptions.enforceTransitiveConfigsForConfigFeatureFlag).isFalse();
assertThat(hostOptions.getFlagValues()).isEmpty();
assertThat(hostOptions.getKnownDefaultFlags()).isEmpty();
assertThat(hostOptions.getUnknownFlags()).isEmpty();
}
@Test
public void equals_forEquivalentMaps() throws Exception {
new EqualsTester()
.addEqualityGroup(
// Empty with all flags set to default values
getOptionsWith(ImmutableMap.<Label, String>of()),
new ConfigFeatureFlagOptions(),
new ConfigFeatureFlagOptions().getDefault(),
new ConfigFeatureFlagOptions().getHost(),
new ConfigFeatureFlagOptions().getHost())
.addEqualityGroup(
// Empty with all flags trimmed
getOptionsAndTrim(ImmutableMap.of(), ImmutableSet.of()),
getOptionsAndTrim(
ImmutableMap.of(Label.parseAbsolute("//a:a", ImmutableMap.of()), "a"),
ImmutableSet.of()),
getOptionsAndTrim(
ImmutableMap.of(
Label.parseAbsolute("//a:a", ImmutableMap.of()),
"a",
Label.parseAbsolute("//b:b", ImmutableMap.of()),
"b"),
ImmutableSet.of()))
.addEqualityGroup(
// Only //a:a => a, others default
getOptionsWith(ImmutableMap.of(Label.parseAbsolute("//a:a", ImmutableMap.of()), "a")),
getOptionsWith(ImmutableMap.of(Label.parseAbsolute("//a:a", ImmutableMap.of()), "a")))
.addEqualityGroup(
// Error: //a:a is absent
getOptionsAndTrim(
ImmutableMap.of(),
ImmutableSet.of(Label.parseAbsolute("//a:a", ImmutableMap.of()))),
getOptionsAndTrim(
ImmutableMap.of(Label.parseAbsolute("//b:b", ImmutableMap.of()), "b"),
ImmutableSet.of(Label.parseAbsolute("//a:a", ImmutableMap.of()))))
.addEqualityGroup(
// Only //a:a => a, others trimmed
getOptionsAndTrim(
ImmutableMap.of(Label.parseAbsolute("//a:a", ImmutableMap.of()), "a"),
ImmutableSet.of(Label.parseAbsolute("//a:a", ImmutableMap.of()))),
getOptionsAndTrim(
ImmutableMap.of(
Label.parseAbsolute("//a:a", ImmutableMap.of()),
"a",
Label.parseAbsolute("//b:b", ImmutableMap.of()),
"b"),
ImmutableSet.of(Label.parseAbsolute("//a:a", ImmutableMap.of()))))
.addEqualityGroup(
// Only //b:b => a, others default
getOptionsWith(ImmutableMap.of(Label.parseAbsolute("//b:b", ImmutableMap.of()), "a")))
.addEqualityGroup(
// Only //a:a => b, others default
getOptionsWith(ImmutableMap.of(Label.parseAbsolute("//a:a", ImmutableMap.of()), "b")))
.addEqualityGroup(
// Only //b:b => b, others default
getOptionsWith(ImmutableMap.of(Label.parseAbsolute("//b:b", ImmutableMap.of()), "b")))
.addEqualityGroup(
// //a:a => b and //b:b => a, others default (order doesn't matter)
getOptionsWith(
ImmutableMap.of(
Label.parseAbsolute("//a:a", ImmutableMap.of()), "b",
Label.parseAbsolute("//b:b", ImmutableMap.of()), "a")),
getOptionsWith(
ImmutableMap.of(
Label.parseAbsolute("//b:b", ImmutableMap.of()), "a",
Label.parseAbsolute("//a:a", ImmutableMap.of()), "b")))
.addEqualityGroup(
// //a:a => b and //b:b => a, others trimmed (order doesn't matter)
getOptionsAndTrim(
ImmutableMap.of(
Label.parseAbsolute("//a:a", ImmutableMap.of()), "b",
Label.parseAbsolute("//b:b", ImmutableMap.of()), "a"),
ImmutableSet.of(
Label.parseAbsolute("//a:a", ImmutableMap.of()),
Label.parseAbsolute("//b:b", ImmutableMap.of()))),
getOptionsAndTrim(
ImmutableMap.of(
Label.parseAbsolute("//a:a", ImmutableMap.of()), "b",
Label.parseAbsolute("//b:b", ImmutableMap.of()), "a"),
ImmutableSet.of(
Label.parseAbsolute("//b:b", ImmutableMap.of()),
Label.parseAbsolute("//a:a", ImmutableMap.of()))),
getOptionsAndTrim(
ImmutableMap.of(
Label.parseAbsolute("//b:b", ImmutableMap.of()), "a",
Label.parseAbsolute("//a:a", ImmutableMap.of()), "b"),
ImmutableSet.of(
Label.parseAbsolute("//a:a", ImmutableMap.of()),
Label.parseAbsolute("//b:b", ImmutableMap.of()))),
getOptionsAndTrim(
ImmutableMap.of(
Label.parseAbsolute("//b:b", ImmutableMap.of()), "a",
Label.parseAbsolute("//a:a", ImmutableMap.of()), "b"),
ImmutableSet.of(
Label.parseAbsolute("//b:b", ImmutableMap.of()),
Label.parseAbsolute("//a:a", ImmutableMap.of()))))
.testEquals();
}
private ConfigFeatureFlagOptions getOptionsWith(Map<Label, String> values) {
ConfigFeatureFlagOptions result = new ConfigFeatureFlagOptions();
result.replaceFlagValues(values);
return result;
}
private ConfigFeatureFlagOptions getOptionsAndTrim(
Map<Label, String> values, Set<Label> trimming) {
ConfigFeatureFlagOptions result = getOptionsWith(values);
result.trimFlagValues(trimming);
return result;
}
@Test
public void parser_doesNotAllowFlagValuesToBeParsed() throws Exception {
ConfigFeatureFlagOptions options = Options.getDefaults(ConfigFeatureFlagOptions.class);
ImmutableSortedMap<Label, String> testValue =
ImmutableSortedMap.of(Label.parseAbsolute("//what:heck", ImmutableMap.of()), "something");
options.flagValues = testValue;
String flagValuesOption =
options
.asMap()
.entrySet()
.stream()
.filter((entry) -> testValue.equals(entry.getValue()))
.map(Map.Entry::getKey)
.collect(onlyElement());
OptionsParser parser = OptionsParser.newOptionsParser(ConfigFeatureFlagOptions.class);
try {
parser.parse("--" + flagValuesOption + "={}");
fail("Flags successfully parsed despite passing a private flag.");
} catch (OptionsParsingException expected) {
assertThat(expected).hasMessageThat().contains("Unrecognized option:");
}
}
@Test
public void parser_doesNotAllowKnownDefaultValuesToBeParsed() throws Exception {
ConfigFeatureFlagOptions options = Options.getDefaults(ConfigFeatureFlagOptions.class);
ImmutableSortedSet<Label> testValue =
ImmutableSortedSet.of(Label.parseAbsolute("//what:heck", ImmutableMap.of()));
options.knownDefaultFlags = testValue;
String defaultValuesOption =
options
.asMap()
.entrySet()
.stream()
.filter((entry) -> testValue.equals(entry.getValue()))
.map(Map.Entry::getKey)
.collect(onlyElement());
OptionsParser parser = OptionsParser.newOptionsParser(ConfigFeatureFlagOptions.class);
try {
parser.parse("--" + defaultValuesOption + "={}");
fail("Flags successfully parsed despite passing a private flag.");
} catch (OptionsParsingException expected) {
assertThat(expected).hasMessageThat().contains("Unrecognized option:");
}
}
@Test
public void parser_doesNotAllowUnknownValuesToBeParsed() throws Exception {
ConfigFeatureFlagOptions options = Options.getDefaults(ConfigFeatureFlagOptions.class);
ImmutableSortedSet<Label> testValue =
ImmutableSortedSet.of(Label.parseAbsolute("//what:heck", ImmutableMap.of()));
options.unknownFlags = testValue;
String unknownFlagsOption =
options
.asMap()
.entrySet()
.stream()
.filter((entry) -> testValue.equals(entry.getValue()))
.map(Map.Entry::getKey)
.collect(onlyElement());
OptionsParser parser = OptionsParser.newOptionsParser(ConfigFeatureFlagOptions.class);
try {
parser.parse("--" + unknownFlagsOption + "={}");
fail("Flags successfully parsed despite passing a private flag.");
} catch (OptionsParsingException expected) {
assertThat(expected).hasMessageThat().contains("Unrecognized option:");
}
}
}