// 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 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 originalMap = ImmutableMap.of( Label.parseAbsoluteUnchecked("//label:a"), "value", Label.parseAbsoluteUnchecked("//label:b"), "otherValue"); Map 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 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.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 values) { ConfigFeatureFlagOptions result = new ConfigFeatureFlagOptions(); result.replaceFlagValues(values); return result; } private ConfigFeatureFlagOptions getOptionsAndTrim( Map values, Set