// 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.common.options.testing; import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.fail; 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.OptionsBase; import java.util.List; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; /** Tests for the OptionsTester. */ @RunWith(JUnit4.class) public final class OptionsTesterTest { @Test public void optionAnnotationCheck_PassesWhenAllFieldsAnnotated() throws Exception { new OptionsTester(OptionAnnotationCheckAllFieldsAnnotated.class) .testAllInstanceFieldsAnnotatedWithOption(); } /** Test options class for optionAnnotationCheck_PassesWhenAllFieldsAnnotated. */ public static class BaseAllFieldsAnnotated extends OptionsBase { @Option( name = "public_inherited_field_with_annotation", documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, effectTags = {OptionEffectTag.NO_OP}, defaultValue = "defaultFoo" ) public String inheritedField; } /** Test options class for optionAnnotationCheck_PassesWhenAllFieldsAnnotated. */ public static final class OptionAnnotationCheckAllFieldsAnnotated extends BaseAllFieldsAnnotated { @Option( name = "public_declared_field_with_annotation", documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, effectTags = {OptionEffectTag.NO_OP}, defaultValue = "defaultFoo" ) public String publicField; @Option( name = "other_public_declared_field_with_annotation", documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, effectTags = {OptionEffectTag.NO_OP}, defaultValue = "defaultFoo" ) public String publicField2; } @Test public void optionAnnotationCheck_AllowsUnAnnotatedStaticFields() throws Exception { new OptionsTester(OptionAnnotationCheckUnAnnotatedStaticField.class) .testAllInstanceFieldsAnnotatedWithOption(); } /** Test options class for optionAnnotationCheck_AllowsUnAnnotatedStaticFields. */ public static class BaseUnAnnotatedStaticField extends OptionsBase { public static String parentClassUnAnnotatedStaticField; } /** Test options class for optionAnnotationCheck_AllowsUnAnnotatedStaticFields. */ public static final class OptionAnnotationCheckUnAnnotatedStaticField extends BaseUnAnnotatedStaticField { @SuppressWarnings("unused") private static String privateDeclaredUnAnnotatedStaticField; } @Test public void optionAnnotationCheck_FailsWhenFieldNotAnnotated() throws Exception { try { new OptionsTester(OptionAnnotationCheckUnAnnotatedField.class) .testAllInstanceFieldsAnnotatedWithOption(); } catch (AssertionError expected) { assertThat(expected).hasMessageThat().contains("unAnnotatedField"); return; } fail("test is expected to have failed"); } /** Test options class for optionAnnotationCheck_FailsWhenFieldNotAnnotated. */ public static class OptionAnnotationCheckUnAnnotatedField extends OptionsBase { public String unAnnotatedField; } @Test public void optionAnnotationCheck_FailsForUnAnnotatedFieldsInSuperclass() throws Exception { try { new OptionsTester(OptionAnnotationCheckInheritedUnAnnotatedField.class) .testAllInstanceFieldsAnnotatedWithOption(); } catch (AssertionError expected) { assertThat(expected).hasMessageThat().contains("unAnnotatedField"); return; } fail("test is expected to have failed"); } /** Test options class for optionAnnotationCheck_FailsForUnAnnotatedFieldsInSuperclass. */ public static final class OptionAnnotationCheckInheritedUnAnnotatedField extends OptionAnnotationCheckUnAnnotatedField {} @Test public void optionAnnotationCheck_FailsForPrivateUnAnnotatedField() throws Exception { try { new OptionsTester(OptionAnnotationCheckPrivateUnAnnotatedField.class) .testAllInstanceFieldsAnnotatedWithOption(); } catch (AssertionError expected) { assertThat(expected).hasMessageThat().contains("privateUnAnnotatedField"); return; } fail("test is expected to have failed"); } /** Test options class for optionAnnotationCheck_FailsForPrivateUnAnnotatedField. */ public static final class OptionAnnotationCheckPrivateUnAnnotatedField extends OptionsBase { @SuppressWarnings("unused") private String privateUnAnnotatedField; } /** Test options class for optionAccessCheck_PassesWhenAllFieldsPublicNotStaticNotFinal. */ public static class BaseAllFieldsPublicNotStaticNotFinal extends OptionsBase { @Option( name = "public_inherited_field_with_annotation", documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, effectTags = {OptionEffectTag.NO_OP}, defaultValue = "defaultFoo" ) public String inheritedField; } /** Test options class for optionAccessCheck_PassesWhenAllFieldsPublicNotStaticNotFinal. */ public static final class OptionAccessCheckAllFieldsPublicNotStaticNotFinal extends BaseAllFieldsPublicNotStaticNotFinal { @Option( name = "public_declared_field_with_annotation", documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, effectTags = {OptionEffectTag.NO_OP}, defaultValue = "defaultFoo" ) public String annotatedField; } /** Test options class for optionAccessCheck_IgnoresNonAnnotatedFields. */ public static class BaseNonAnnotatedFields extends OptionsBase { protected static String parentClassUnAnnotatedStaticField; final String parentClassUnAnnotatedFinalField = ""; } /** Test options class for optionAccessCheck_IgnoresNonAnnotatedFields. */ public static final class OptionAccessCheckNonAnnotatedFields extends BaseNonAnnotatedFields { @SuppressWarnings("unused") private static String privateDeclaredUnAnnotatedStaticFinalField; public static final String PUBLIC_DECLARED_UN_ANNOTATED_STATIC_FIELD = ""; protected String protectedDeclaredField; } /** Test converter class for testing testAllDefaultValuesTestedBy. */ public static final class TestConverter implements Converter { @Override public String convert(String input) { return input; } @Override public String getTypeDescription() { return "a string"; } } @Test public void defaultTestCheck_PassesIfAllDefaultsTestedIgnoringNullAndAllowMultiple() { new OptionsTester(DefaultTestCheck.class) .testAllDefaultValuesTestedBy( new ConverterTesterMap.Builder() .add( new ConverterTester(TestConverter.class) .addEqualityGroup("testedDefault", "otherTestedDefault")) .build()); } /** Test options class for defaultTestCheck_PassesIfAllDefaultsTested. */ public static final class DefaultTestCheck extends OptionsBase { @Option( name = "tested_field", documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, effectTags = {OptionEffectTag.NO_OP}, converter = TestConverter.class, defaultValue = "testedDefault" ) public String testedField; @Option( name = "field_implicitly_using_default_converter", documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, effectTags = {OptionEffectTag.NO_OP}, defaultValue = "implicitConverterDefault" ) public String implicitConverterField; @Option( name = "other_tested_field", documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, effectTags = {OptionEffectTag.NO_OP}, converter = TestConverter.class, defaultValue = "otherTestedDefault" ) public String otherTestedField; @Option( name = "field_with_null_default", documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, effectTags = {OptionEffectTag.NO_OP}, converter = TestConverter.class, defaultValue = "null" ) public String nullDefaultField; @Option( name = "allowMultiple_field", documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, effectTags = {OptionEffectTag.NO_OP}, converter = TestConverter.class, defaultValue = "allowMultipleDefault", allowMultiple = true ) public List allowMultipleField; } @Test public void defaultTestCheck_FailsIfTesterIsPresentButValueIsNotTested() { try { new OptionsTester(DefaultTestCheckUntestedField.class) .testAllDefaultValuesTestedBy( new ConverterTesterMap.Builder() .add(new ConverterTester(TestConverter.class).addEqualityGroup("testedDefault")) .build()); } catch (AssertionError expected) { assertThat(expected).hasMessageThat().contains("untestedField"); assertThat(expected).hasMessageThat().contains("untestedDefault"); return; } fail("test is expected to have failed"); } @Test public void defaultTestCheck_FailsIfTesterIsAbsent() { try { new OptionsTester(DefaultTestCheckUntestedField.class) .testAllDefaultValuesTestedBy(new ConverterTesterMap.Builder().build()); } catch (AssertionError expected) { assertThat(expected).hasMessageThat().contains("TestConverter"); return; } fail("test is expected to have failed"); } /** * Test options class for defaultTestCheck_FailsIfTesterIsPresentButValueIsNotTested and * defaultTestCheck_FailsIfTesterIsAbsent. */ public static final class DefaultTestCheckUntestedField extends OptionsBase { @Option( name = "untested_field", documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, effectTags = {OptionEffectTag.NO_OP}, converter = TestConverter.class, defaultValue = "untestedDefault" ) public String untestedField; } @Test public void defaultTestCheck_FailsIfTesterIsAbsentEvenForNullDefault() { try { new OptionsTester(DefaultTestCheckUntestedNullField.class) .testAllDefaultValuesTestedBy(new ConverterTesterMap.Builder().build()); } catch (AssertionError expected) { assertThat(expected).hasMessageThat().contains("TestConverter"); return; } fail("test is expected to have failed"); } /** Test options class for defaultTestCheck_FailsIfTesterIsAbsentEvenForNullDefault. */ public static final class DefaultTestCheckUntestedNullField extends OptionsBase { @Option( name = "untested_field", documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, effectTags = {OptionEffectTag.NO_OP}, converter = TestConverter.class, defaultValue = "null" ) public String untestedNullField; } @Test public void defaultTestCheck_FailsIfTesterIsAbsentEvenForAllowMultiple() { try { new OptionsTester(DefaultTestCheckUntestedMultipleField.class) .testAllDefaultValuesTestedBy(new ConverterTesterMap.Builder().build()); } catch (AssertionError expected) { assertThat(expected).hasMessageThat().contains("TestConverter"); return; } fail("test is expected to have failed"); } /** Test options class for defaultTestCheck_FailsIfTesterIsAbsentEvenForAllowMultiple. */ public static final class DefaultTestCheckUntestedMultipleField extends OptionsBase { @Option( name = "untested_field", documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, effectTags = {OptionEffectTag.NO_OP}, converter = TestConverter.class, defaultValue = "untestedDefault", allowMultiple = true ) public List untestedMultipleField; } }