package org.mutabilitydetector;
/*
* #%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 org.junit.Test;
import org.mutabilitydetector.checkers.CheckerRunner.ExceptionPolicy;
import org.mutabilitydetector.checkers.MutabilityAnalysisException;
import org.mutabilitydetector.checkers.MutabilityCheckerFactory.ReassignedFieldAnalysisChoice;
import org.mutabilitydetector.checkers.info.CopyMethod;
import org.mutabilitydetector.config.HardcodedResultsUsage;
import org.mutabilitydetector.locations.Dotted;
import org.mutabilitydetector.unittesting.internal.CloneList;
import java.util.List;
import java.util.Map;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.hasEntry;
import static org.hamcrest.Matchers.hasKey;
import static org.hamcrest.Matchers.is;
import static org.mutabilitydetector.AnalysisResult.analysisResult;
import static org.mutabilitydetector.AnalysisResult.definitelyImmutable;
import static org.mutabilitydetector.checkers.CheckerRunner.ExceptionPolicy.CARRY_ON;
import static org.mutabilitydetector.checkers.CheckerRunner.ExceptionPolicy.FAIL_FAST;
import static org.mutabilitydetector.checkers.MutabilityCheckerFactory.ReassignedFieldAnalysisChoice.NAIVE_PUT_FIELD_ANALYSIS;
import static org.mutabilitydetector.config.HardcodedResultsUsage.DIRECTLY_IN_ASSERTION;
import static org.mutabilitydetector.config.HardcodedResultsUsage.LOOKUP_WHEN_REFERENCED;
import static org.mutabilitydetector.locations.Dotted.dotted;
import static org.mutabilitydetector.unittesting.AllowedReason.provided;
import static org.mutabilitydetector.unittesting.MutabilityAssert.assertInstancesOf;
import static org.mutabilitydetector.unittesting.MutabilityMatchers.areImmutable;
public class ConfigurationBuilderTest {
@Test
public void canMergeResultsFromExistingConfiguration() throws Exception {
final Configuration existing = new ConfigurationBuilder() {
@Override public void configure() {
hardcodeResult(definitelyImmutable("hardcoded.in.other.Configuration"));
}
}.build();
final Configuration current = new ConfigurationBuilder() {
@Override public void configure() {
mergeHardcodedResultsFrom(existing);
}
}.build();
assertThat(current.hardcodedResults(), hasKey(dotted("hardcoded.in.other.Configuration")));
}
@Test
public void mergeReplacesExistingHardcodedResultForClassWithCurrentHardcodedResult() throws Exception {
final AnalysisResult resultInCurrentConfig = analysisResult("hardcoded.in.both.Configurations",
IsImmutable.NOT_IMMUTABLE,
TestUtil.unusedMutableReasonDetail());
final Configuration mergedIn = new ConfigurationBuilder() {
@Override public void configure() {
hardcodeResult(resultInCurrentConfig);
hardcodeResult(definitelyImmutable("only.in.existing.Configuration"));
}
}.build();
final Configuration current = new ConfigurationBuilder() {
@Override public void configure() {
hardcodeResult(definitelyImmutable("hardcoded.in.both.Configurations"));
hardcodeResult(definitelyImmutable("only.in.current.Configuration"));
mergeHardcodedResultsFrom(mergedIn);
}
}.build();
Map<Dotted, AnalysisResult> hardcodedResults = current.hardcodedResults();
assertThat(hardcodedResults.size(), is(3));
assertThat(hardcodedResults, hasEntry(dotted("hardcoded.in.both.Configurations"), resultInCurrentConfig));
assertThat(hardcodedResults, hasEntry(dotted("only.in.existing.Configuration"), definitelyImmutable("only.in.existing.Configuration")));
assertThat(hardcodedResults, hasEntry(dotted("only.in.current.Configuration"), definitelyImmutable("only.in.current.Configuration")));
}
@Test
public void builtConfigurationsAreImmutable() throws Exception {
ConfigurationBuilder configurationBuilder = new ConfigurationBuilder() {
@Override public void configure() { }
};
assertInstancesOf(configurationBuilder.build().getClass(),
areImmutable(),
provided(AnalysisResult.class, Dotted.class).areAlsoImmutable());
}
@Test
public void canMergeEntireConfigurations() throws Exception {
final Configuration first = new ConfigurationBuilder() {
@Override public void configure() {
hardcodeResult(definitelyImmutable("hardcoded.in.both.Configurations"));
hardcodeResult(definitelyImmutable("only.in.existing.Configuration"));
useAdvancedReassignedFieldAlgorithm();
setHowToUseHardcodedResults(DIRECTLY_IN_ASSERTION);
}
}.build();
final Configuration second = new ConfigurationBuilder() {
@Override public void configure() {
hardcodeAsDefinitelyImmutable("only.in.second.Configuration");
hardcodeAsImmutableContainerType("container.only.in.second.Configuration");
hardcodeValidCopyMethod(List.class, "com.google.common.collect.Lists.newArrayList", Iterable.class);
setExceptionPolicy(FAIL_FAST);
setHowToUseHardcodedResults(LOOKUP_WHEN_REFERENCED);
}
}.build();
final AnalysisResult resultInCurrentConfig = analysisResult("hardcoded.in.both.Configurations",
IsImmutable.NOT_IMMUTABLE,
TestUtil.unusedMutableReasonDetail());
final Configuration current = new ConfigurationBuilder() {
@Override public void configure() {
setExceptionPolicy(CARRY_ON);
setHowToUseHardcodedResults(DIRECTLY_IN_ASSERTION);
hardcodeResult(resultInCurrentConfig);
merge(first);
merge(second);
}
}.build();
assertThat(current.hardcodedResults().size(), is(3));
assertThat(current.immutableContainerClasses(), contains(Dotted.dotted("container.only.in.second.Configuration")));
assertThat(current.hardcodedCopyMethods().get("java.util.List"),
contains(new CopyMethod(dotted("com.google.common.collect.Lists"), "newArrayList", "(Ljava/lang/Iterable;)Ljava/util/ArrayList;")));
assertThat(current.exceptionPolicy(), is(CARRY_ON));
assertThat(current.howToUseHardcodedResults(), is(DIRECTLY_IN_ASSERTION));
assertThat(current.reassignedFieldAlgorithm(), is(NAIVE_PUT_FIELD_ANALYSIS));
}
@Test
public void mergeCopyMethodsDoesNotCauseDuplicates() {
final CopyMethod a = new CopyMethod(dotted("any"), "method", "A");
final CopyMethod b = new CopyMethod(dotted("any"), "method", "B");
final CopyMethod c = new CopyMethod(dotted("any"), "method", "C");
final CopyMethod a2 = new CopyMethod(dotted("any"), "method", "A");
final Configuration original = new ConfigurationBuilder() {
@Override public void configure() {
hardcodeValidCopyMethod(List.class, a);
hardcodeValidCopyMethod(List.class, b);
}
}.build();
final Configuration merged = new ConfigurationBuilder() {
@Override public void configure() {
hardcodeValidCopyMethod(List.class, c);
hardcodeValidCopyMethod(List.class, a2);
mergeValidCopyMethodsFrom(original);
}
}.build();
assertThat(merged.hardcodedCopyMethods().values(), containsInAnyOrder(a, b, c));
}
@Test (expected=MutabilityAnalysisException.class)
public void shouldThrowIfClassOfCopyMethodIsNotKnown() {
new ConfigurationBuilder() {
@Override public void configure() {
hardcodeValidCopyMethod(List.class, "non.existent.Collection.<init>", List.class);
}
}.build();
}
@Test (expected=MutabilityAnalysisException.class)
public void shouldThrowIfCopyMethodDoesNotExist() {
new ConfigurationBuilder() {
@Override public void configure() {
hardcodeValidCopyMethod(List.class, "com.google.common.collect.Lists.doesNotExist", List.class);
}
}.build();
}
@Test
public void constructorsCanBeValidCopyMethods() {
final Configuration cfg = new ConfigurationBuilder() {
@Override public void configure() {
hardcodeValidCopyMethod(CloneList.class,
"org.mutabilitydetector.unittesting.internal.CloneList.<init>", List.class);
}
}.build();
assertThat(cfg.hardcodedCopyMethods().size(), is(1));
}
}