blob: 808f77be13a7d8371a51d9122f08075de9f5dfac [file] [log] [blame]
// 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.analysis.config;
import static com.google.common.truth.Truth.assertThat;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.devtools.common.options.Converter;
import com.google.devtools.common.options.Option;
import com.google.devtools.common.options.OptionDocumentationCategory;
import com.google.devtools.common.options.OptionEffectTag;
import com.google.devtools.common.options.OptionMetadataTag;
import com.google.devtools.common.options.OptionsBase;
import com.google.devtools.common.options.OptionsParser;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/** Tests for {@link TransitiveOptionDetails}. */
@RunWith(JUnit4.class)
public class TransitiveOptionDetailsTest {
/** Instantiates the given options classes, parsing the given options as well. */
public Iterable<OptionsBase> parseOptions(
Iterable<? extends Class<? extends OptionsBase>> optionsClasses, String... options)
throws Exception {
OptionsParser optionsParser = OptionsParser.newOptionsParser(optionsClasses);
optionsParser.setAllowResidue(false);
optionsParser.parse(options);
ImmutableList.Builder<OptionsBase> output = new ImmutableList.Builder<OptionsBase>();
for (Class<? extends OptionsBase> optionsClass : optionsClasses) {
output.add(optionsParser.getOptions(optionsClass));
}
return output.build();
}
/** Example converter for working with options with converters. */
public static final class Optionalizer implements Converter<Optional<String>> {
@Override
public Optional<String> convert(String input) {
if ("".equals(input)) {
return Optional.<String>absent();
}
return Optional.of(input);
}
@Override
public String getTypeDescription() {
return "a string";
}
}
/** Example options class for testing options lookup. */
public static final class Options extends OptionsBase {
@Option(
name = "boolean_option",
documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
effectTags = {OptionEffectTag.NO_OP},
defaultValue = "true"
)
public boolean booleanOption;
@Option(
name = "convertible_option",
converter = Optionalizer.class,
documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
effectTags = {OptionEffectTag.NO_OP},
defaultValue = ""
)
public Optional<String> convertibleOption;
@Option(
name = "null_default",
documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
effectTags = {OptionEffectTag.NO_OP},
defaultValue = "null"
)
public String nullDefault;
@Option(
name = "late_bound_default",
documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
effectTags = {OptionEffectTag.NO_OP},
defaultValue = "null"
)
public String lateBoundDefault;
@Option(
name = "multi_option",
documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
effectTags = {OptionEffectTag.NO_OP},
defaultValue = "n/a (allows multiple)",
allowMultiple = true
)
public List<String> multiOption;
@Option(
name = "internal option",
defaultValue = "secret",
documentationCategory = OptionDocumentationCategory.UNDOCUMENTED,
effectTags = {OptionEffectTag.NO_OP},
metadataTags = {OptionMetadataTag.INTERNAL}
)
public String internalOption;
@Option(
name = "internal multi option",
documentationCategory = OptionDocumentationCategory.UNDOCUMENTED,
effectTags = {OptionEffectTag.NO_OP},
defaultValue = "n/a",
metadataTags = {OptionMetadataTag.INTERNAL},
allowMultiple = true
)
public List<String> internalMultiOption;
}
/** Additional options class for testing options lookup. */
public static final class MoreOptions extends OptionsBase {
@Option(
name = "other_option",
documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
effectTags = {OptionEffectTag.NO_OP},
defaultValue = ""
)
public String otherOption;
}
@Test
public void getOptionClass_ReturnsClassOfPresentOptions() throws Exception {
TransitiveOptionDetails details =
TransitiveOptionDetails.forOptionsWithDefaults(
parseOptions(ImmutableList.of(Options.class)), ImmutableMap.<String, Object>of());
assertThat(details.getOptionClass("boolean_option")).isEqualTo(Options.class);
}
@Test
public void getOptionClass_SelectsCorrectClassWhenMultipleArePresent() throws Exception {
TransitiveOptionDetails details =
TransitiveOptionDetails.forOptionsWithDefaults(
parseOptions(ImmutableList.of(Options.class, MoreOptions.class)),
ImmutableMap.<String, Object>of());
assertThat(details.getOptionClass("boolean_option")).isEqualTo(Options.class);
assertThat(details.getOptionClass("other_option")).isEqualTo(MoreOptions.class);
}
@Test
public void getOptionClass_ReturnsNullIfOptionsClassIsNotPartOfOptionDetails() throws Exception {
TransitiveOptionDetails details =
TransitiveOptionDetails.forOptionsWithDefaults(
parseOptions(ImmutableList.of(Options.class)), ImmutableMap.<String, Object>of());
assertThat(details.getOptionClass("other_option")).isNull();
}
@Test
public void getOptionClass_SelectsCorrectClassEvenWhenOverridden() throws Exception {
TransitiveOptionDetails details =
TransitiveOptionDetails.forOptionsWithDefaults(
parseOptions(ImmutableList.of(Options.class)),
ImmutableMap.<String, Object>of("late_bound_default", "late bound replacement"));
assertThat(details.getOptionClass("late_bound_default")).isEqualTo(Options.class);
}
@Test
public void getOptionClass_SelectsCorrectClassEvenWhenValueIsNull() throws Exception {
TransitiveOptionDetails details =
TransitiveOptionDetails.forOptionsWithDefaults(
parseOptions(ImmutableList.of(Options.class)), ImmutableMap.<String, Object>of());
assertThat(details.getOptionClass("null_default")).isEqualTo(Options.class);
}
@Test
public void getOptionClass_ReturnsNullWhenOptionIsUndefined() throws Exception {
TransitiveOptionDetails details =
TransitiveOptionDetails.forOptionsWithDefaults(
parseOptions(ImmutableList.of(Options.class)), ImmutableMap.<String, Object>of());
assertThat(details.getOptionClass("undefined_option")).isNull();
}
@Test
public void getOptionClass_ReturnsNullWhenOptionIsUndefinedEvenWhenOverridden() throws Exception {
TransitiveOptionDetails details =
TransitiveOptionDetails.forOptionsWithDefaults(
parseOptions(ImmutableList.of(Options.class)),
ImmutableMap.<String, Object>of("undefined_option", "override"));
assertThat(details.getOptionClass("undefined_option")).isNull();
}
@Test
public void getOptionClass_ReturnsNullIfOptionIsInternal() throws Exception {
TransitiveOptionDetails details =
TransitiveOptionDetails.forOptionsWithDefaults(
parseOptions(ImmutableList.of(Options.class)), ImmutableMap.<String, Object>of());
assertThat(details.getOptionClass("internal option")).isNull();
}
@Test
public void getOptionValue_ReturnsDefaultValueIfNotSet() throws Exception {
TransitiveOptionDetails details =
TransitiveOptionDetails.forOptionsWithDefaults(
parseOptions(ImmutableList.of(Options.class)), ImmutableMap.<String, Object>of());
assertThat(details.getOptionValue("boolean_option")).isEqualTo(true);
}
@Test
public void getOptionValue_ReturnsCommandLineValueIfSet() throws Exception {
TransitiveOptionDetails details =
TransitiveOptionDetails.forOptionsWithDefaults(
parseOptions(ImmutableList.of(Options.class), "--noboolean_option"),
ImmutableMap.<String, Object>of());
assertThat(details.getOptionValue("boolean_option")).isEqualTo(false);
}
@Test
public void getOptionValue_ReturnsEmptyListForUnspecifiedMultiOptions() throws Exception {
TransitiveOptionDetails details =
TransitiveOptionDetails.forOptionsWithDefaults(
parseOptions(ImmutableList.of(Options.class), "--noboolean_option"),
ImmutableMap.<String, Object>of());
assertThat(details.getOptionValue("multi_option")).isEqualTo(ImmutableList.<String>of());
}
@Test
public void getOptionValue_ReturnsListOfValuesForSpecifiedMultiOptions() throws Exception {
TransitiveOptionDetails details =
TransitiveOptionDetails.forOptionsWithDefaults(
parseOptions(
ImmutableList.of(Options.class),
"--multi_option=one",
"--multi_option=2",
"--multi_option=iii"),
ImmutableMap.<String, Object>of());
assertThat(details.getOptionValue("multi_option"))
.isEqualTo(ImmutableList.of("one", "2", "iii"));
}
@Test
public void getOptionValue_DrawsValuesFromAllOptionsClasses() throws Exception {
TransitiveOptionDetails details =
TransitiveOptionDetails.forOptionsWithDefaults(
parseOptions(ImmutableList.of(Options.class, MoreOptions.class), "--other_option=set"),
ImmutableMap.<String, Object>of());
assertThat(details.getOptionValue("other_option")).isEqualTo("set");
}
@Test
public void getOptionValue_UsesConvertersIfSpecified() throws Exception {
TransitiveOptionDetails details =
TransitiveOptionDetails.forOptionsWithDefaults(
parseOptions(ImmutableList.of(Options.class), "--convertible_option=Set"),
ImmutableMap.<String, Object>of());
assertThat(details.getOptionValue("convertible_option")).isEqualTo(Optional.of("Set"));
}
@Test
public void getOptionValue_UsesConvertersForDefaultsIfSpecified() throws Exception {
TransitiveOptionDetails details =
TransitiveOptionDetails.forOptionsWithDefaults(
parseOptions(ImmutableList.of(Options.class)), ImmutableMap.<String, Object>of());
assertThat(details.getOptionValue("convertible_option")).isEqualTo(Optional.<String>absent());
}
@Test
public void getOptionValue_ReturnsNullIfOptionIsNotDefined() throws Exception {
TransitiveOptionDetails details =
TransitiveOptionDetails.forOptionsWithDefaults(
parseOptions(ImmutableList.of(Options.class)), ImmutableMap.<String, Object>of());
assertThat(details.getOptionValue("undefined_option")).isNull();
}
@Test
public void getOptionValue_ReturnsNullIfOptionIsInternal() throws Exception {
TransitiveOptionDetails details =
TransitiveOptionDetails.forOptionsWithDefaults(
parseOptions(ImmutableList.of(Options.class)), ImmutableMap.<String, Object>of());
assertThat(details.getOptionValue("internal option")).isNull();
}
@Test
public void getOptionValue_ReturnsNullIfOptionIsDefinedInNonIncludedOptionsClass()
throws Exception {
TransitiveOptionDetails details =
TransitiveOptionDetails.forOptionsWithDefaults(
parseOptions(ImmutableList.of(Options.class)), ImmutableMap.<String, Object>of());
assertThat(details.getOptionValue("other_option")).isNull();
}
@Test
public void getOptionValue_ReturnsNullIfOptionIsNotDefinedEvenIfOverridden() throws Exception {
TransitiveOptionDetails details =
TransitiveOptionDetails.forOptionsWithDefaults(
parseOptions(ImmutableList.of(Options.class)),
ImmutableMap.<String, Object>of("undefined_option_with_override", "default"));
assertThat(details.getOptionValue("undefined_option_with_override")).isNull();
}
@Test
public void getOptionValue_ReturnsNullIfOptionDefaultValueIsNull() throws Exception {
TransitiveOptionDetails details =
TransitiveOptionDetails.forOptionsWithDefaults(
parseOptions(ImmutableList.of(Options.class)), ImmutableMap.<String, Object>of());
assertThat(details.getOptionValue("null_option")).isNull();
}
@Test
public void getOptionValue_ReturnsOverrideValueIfOptionIsOverriddenAndDefaultsNull()
throws Exception {
TransitiveOptionDetails details =
TransitiveOptionDetails.forOptionsWithDefaults(
parseOptions(ImmutableList.of(Options.class)),
ImmutableMap.<String, Object>of("late_bound_default", "late bound replacement"));
assertThat(details.getOptionValue("late_bound_default")).isEqualTo("late bound replacement");
}
@Test
public void getOptionValue_ReturnsCommandLineValueIfOptionIsSetOnCommandLineEvenIfOverridden()
throws Exception {
TransitiveOptionDetails details =
TransitiveOptionDetails.forOptionsWithDefaults(
parseOptions(ImmutableList.of(Options.class), "--late_bound_default=commando"),
ImmutableMap.<String, Object>of("late_bound_default", "late bound replacement"));
assertThat(details.getOptionValue("late_bound_default")).isEqualTo("commando");
}
@Test
public void getOptionValue_ReturnsDefaultValueIfOptionDefaultsNonNullEvenIfOverridden()
throws Exception {
TransitiveOptionDetails details =
TransitiveOptionDetails.forOptionsWithDefaults(
parseOptions(ImmutableList.of(Options.class)),
ImmutableMap.<String, Object>of("convertible_option", "late bound replacement"));
assertThat(details.getOptionValue("convertible_option")).isEqualTo(Optional.<String>absent());
}
@Test
public void allowsMultipleValues_ReturnsFalseForUndefinedOption() throws Exception {
TransitiveOptionDetails details =
TransitiveOptionDetails.forOptionsWithDefaults(
parseOptions(ImmutableList.of(Options.class)), ImmutableMap.<String, Object>of());
assertThat(details.allowsMultipleValues("undefined_option")).isFalse();
}
@Test
public void allowsMultipleValues_ReturnsFalseForNonMultiOption() throws Exception {
TransitiveOptionDetails details =
TransitiveOptionDetails.forOptionsWithDefaults(
parseOptions(ImmutableList.of(Options.class)), ImmutableMap.<String, Object>of());
assertThat(details.allowsMultipleValues("boolean_option")).isFalse();
}
@Test
public void allowsMultipleValues_ReturnsFalseForInternalNonMultiOption() throws Exception {
TransitiveOptionDetails details =
TransitiveOptionDetails.forOptionsWithDefaults(
parseOptions(ImmutableList.of(Options.class)), ImmutableMap.<String, Object>of());
assertThat(details.allowsMultipleValues("internal option")).isFalse();
}
@Test
public void allowsMultipleValues_ReturnsFalseForInternalMultiOption() throws Exception {
TransitiveOptionDetails details =
TransitiveOptionDetails.forOptionsWithDefaults(
parseOptions(ImmutableList.of(Options.class)), ImmutableMap.<String, Object>of());
assertThat(details.allowsMultipleValues("internal multi option")).isFalse();
}
@Test
public void allowsMultipleValues_ReturnsTrueForMultiOption() throws Exception {
TransitiveOptionDetails details =
TransitiveOptionDetails.forOptionsWithDefaults(
parseOptions(ImmutableList.of(Options.class)), ImmutableMap.<String, Object>of());
assertThat(details.allowsMultipleValues("multi_option")).isTrue();
}
}