org.mutabilitydetector.unittesting.AllowedReason Maven / Gradle / Ivy
Show all versions of MutabilityDetector Show documentation
package org.mutabilitydetector.unittesting;
/*
* #%L
* MutabilityDetector
* %%
* Copyright (C) 2008 - 2014 Graham Allan
* %%
* 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.
* #L%
*/
import static com.google.common.collect.ImmutableSet.copyOf;
import static com.google.common.collect.Iterables.transform;
import static java.util.Arrays.asList;
import static org.mutabilitydetector.locations.Dotted.CLASS_TO_DOTTED;
import static org.mutabilitydetector.locations.Dotted.dotted;
import static org.mutabilitydetector.locations.Dotted.fromClass;
import org.hamcrest.Matcher;
import org.mutabilitydetector.MutableReasonDetail;
import org.mutabilitydetector.unittesting.matchers.reasons.AllowingForSubclassing;
import org.mutabilitydetector.unittesting.matchers.reasons.AllowingNonFinalFields;
import org.mutabilitydetector.unittesting.matchers.reasons.FieldAssumptions;
import org.mutabilitydetector.unittesting.matchers.reasons.NoReasonsAllowed;
import org.mutabilitydetector.unittesting.matchers.reasons.ProvidedOtherClass;
import com.google.common.collect.ImmutableSet;
/**
* Provides ways to suppress false positives generated by Mutability Detector.
*
* Regretfully, Mutability Detector may produce false positives, which cause
* your unit tests to fail, even though your class is immutable. In order to get
* around this fault in Mutability Detector, you can provide an "allowed reason"
* for mutability. This is preferable to deleting the test, or marking it as
* ignored, as it allows checking for all other violations except those you have
* explicitly sanctioned.
*
* All types returned from the static methods on AllowedReason are
* implementations of Hamcrest {@link Matcher}, generic on the type
* {@link MutableReasonDetail}.
*
* For more information on configuring a mutability assertion, see
* {@link MutabilityAssert}.
*
* @see MutabilityAssert
* @see MutableReasonDetail
*
* @see ProvidedOtherClass
* @see AllowingForSubclassing
* @see AllowingNonFinalFields
* @see FieldAssumptions
* @see NoReasonsAllowed
*
*/
public final class AllowedReason {
private AllowedReason() {
}
/**
* Please see the JavaDoc listed with {@link MutabilityAssert} for an
* introduction on using this method.
*
* @see MutabilityAssert
*/
public static ProvidedOtherClass provided(String dottedClassName) {
return ProvidedOtherClass.provided(dotted(dottedClassName));
}
/**
* Please see the JavaDoc listed with {@link MutabilityAssert} for an
* introduction on using this method.
*
* @see MutabilityAssert
*/
public static ProvidedOtherClass provided(Class> clazz) {
return ProvidedOtherClass.provided(fromClass(clazz));
}
/**
* Please see the JavaDoc listed with {@link MutabilityAssert} for an
* introduction on using this method.
*
* @see MutabilityAssert
*/
public static ProvidedOtherClass provided(Class>... classes) {
return ProvidedOtherClass.provided(transform(asList(classes), CLASS_TO_DOTTED));
}
/**
* Please see the JavaDoc listed with {@link MutabilityAssert} for an
* introduction on using this method.
*
* @see MutabilityAssert
*/
public static AllowingForSubclassing allowingForSubclassing() {
return new AllowingForSubclassing();
}
/**
* Insists that non-final fields are acceptable.
*
* Please see the JavaDoc listed with {@link MutabilityAssert} for an
* introduction on using this method.
*
* Example usage:
*
* @Immutable
* public final class HasNonFinalField {
* private int someValue;
*
* public HasNonFinalField(int value) {
* this.someValue = value;
* }
*
* // may have getter methods, but definitely no setter methods or reassignments.
* }
*
* // a warning will be raised because field 'someValue' is not declared final
* assertInstancesOf(HasNonFinalField.class, areImmutable());
*
* // use AllowingNonFinalFields to permit this
* // must be used if matching result with areEffectivelyImmutable()
* assertInstancesOf(UsesInternalMapForCaching.class,
* areImmutable(),
* allowingNonFinalFields());
*
*
* Must be used if matching with {@link MutabilityMatchers#areEffectivelyImmutable()}.
*
* @see MutabilityAssert
*/
public static AllowingNonFinalFields allowingNonFinalFields() {
return new AllowingNonFinalFields();
}
/**
* Allowed reasons for mutability warnings related to fields.
*
* Please see the JavaDoc listed with {@link MutabilityAssert} for an
* introduction on using this method.
*
* Several warnings raised by Mutability Detector relate to the definition, or
* the use, of a field in a class. For example: the definition of a field may
* include declaring that the type of the field is mutable; or the use of a
* field may include reassigning it outwith the constructor.
* {@link FieldAssumptions} provides several methods which allow this category
* of reasons.
*
* Reasons are allowed by matching the field by it's name and then
* matching the reasons that particular field causes mutability.
*
* Example usage:
*
*
* @Immutable
* public final class UsesInternalMapForCaching {
* private final Map internalCache = new HashMap();
* // ... constructor, and methods which mutate the map for caching
* }
*
* // a warning will be raised because field 'internalCache' is a mutable type.
* assertInstancesOf(UsesInternalMapForCaching.class, areImmutable());
*
* // use FieldAssumptions to insist the usage is safe
* assertInstancesOf(UsesInternalMapForCaching.class,
* areImmutable(),
* assumingFields("internalCache").areModifiedAsPartOfAnUnobservableCachingStrategy());
*
*
* This method is also available in Iterable$lt;String> form {@link #assumingFields(Iterable))}.
*
*
* @see MutabilityAssert
*/
public static FieldAssumptions assumingFields(String firstFieldName, String... otherFieldNames) {
return FieldAssumptions.named(ImmutableSet.builder().add(firstFieldName).add(otherFieldNames).build());
}
/**
* Allowed reasons for mutability warnings related to fields.
*
* Please see the JavaDoc listed with {@link MutabilityAssert} for an
* introduction on using this method.
*
* Several warnings raised by Mutability Detector relate to the definition, or
* the use, of a field in a class. For example: the definition of a field may
* include declaring that the type of the field is mutable; or the use of a
* field may include reassigning it outwith the constructor.
* {@link FieldAssumptions} provides several methods which allow this category
* of reasons.
*
* Reasons are allowed by matching the field by it's name and then
* matching the reasons that particular field causes mutability.
*
* Example usage:
*
*
* @Immutable
* public final class UsesInternalMapForCaching {
* private final Map internalCache = new HashMap();
* // ... constructor, and methods which mutate the map for caching
* }
*
* // a warning will be raised because field 'internalCache' is a mutable type.
* assertImmutable(UsesInternalMapForCaching.class, areImmutable());
*
* // use FieldAssumptions to insist the usage is safe
* assertImmutable(UsesInternalMapForCaching.class,
* areImmutable(),
* assumingFields(Arrays.asList("internalCache")).areModifiedAsPartOfAnUnobservableCachingStrategy());
*
*
* This method is also available in varargs form {@link #assumingFields(String, String...)}.
*
*
* @see MutabilityAssert
*/
public static FieldAssumptions assumingFields(Iterable named) {
return FieldAssumptions.named(copyOf(named));
}
}