net.openhft.chronicle.testframework.internal.dto.StandardDtoTester Maven / Gradle / Ivy
package net.openhft.chronicle.testframework.internal.dto;
import net.openhft.chronicle.testframework.Combination;
import net.openhft.chronicle.testframework.dto.DtoTester;
import net.openhft.chronicle.testframework.internal.dto.DtoTesterBuilder.NamedMutator;
import org.jetbrains.annotations.NotNull;
import java.util.*;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import static java.util.Objects.requireNonNull;
final class StandardDtoTester implements DtoTester {
private static final int MAX_COMBINATION_INPUT = 14;
private final DtoTesterBuilder builder;
StandardDtoTester(@NotNull final DtoTesterBuilder builder) {
this.builder = requireNonNull(builder);
}
@Override
public void test() {
assertInstanceCanBeCreated();
assertConstructorNonReuse();
assertEqualsWorksOnFresh();
assertResettable();
checkHashCode();
assertValidationRules();
}
private void assertInstanceCanBeCreated() {
if (createInstance() == null)
throw new AssertionError("Instance was null");
}
private void assertConstructorNonReuse() {
if (createInstance() == createInstance())
throw new AssertionError("The constructor must produce new fresh instances");
}
private void assertEqualsWorksOnFresh() {
if (!createInstance().equals(createInstance()))
throw new AssertionError("Two distinct fresh instances do not equals() each other");
}
private void assertResettable() {
if (builder.resetter() == null)
// Nothing to assert
return;
final T fresh = createInstance();
final List failed = newList();
for (NamedMutator namedMutator : builder.allMutators()) {
final T t = createInstance();
namedMutator.mutator().accept(t);
builder.resetter().accept(t);
if (!fresh.equals(t)) {
failed.add(namedMutator.name());
}
}
if (!failed.isEmpty())
throw new AssertionError("Resettable: The mutators " + failed + " were applied but the resetter did not reset these mutations");
}
private void checkHashCode() {
final T fresh = createInstance();
final List failed = newList();
for (NamedMutator namedMutator : builder.allMutators()) {
final T t = createInstance();
namedMutator.mutator().accept(t);
if (fresh.hashCode() == t.hashCode()) {
failed.add(namedMutator.name());
}
}
failed.forEach(n -> System.err.println("WARNING: hashCode() for the mutator " + n + " was not changed"));
}
private void assertValidationRules() {
if (builder.validator() == null)
// Nothing to assert
return;
if (!builder.mandatoryMutators().isEmpty()) {
// If there is at least one mandatory mutator,
// there should be no combination of optional mutators
// that puts the instance in a valid state
final List> optionalMutators = builder.optionalMutators();
if (optionalMutators.size() > MAX_COMBINATION_INPUT) {
System.out.println("Warning: Fallback to simpler testing because there are so many (" + optionalMutators.size() + ") optional mutators which is more than " + MAX_COMBINATION_INPUT);
optionalMutators.stream().map(Collections::singleton).forEach(this::assertOptionalsDoesNotPass);
} else {
Combination.of(optionalMutators).forEach(this::assertOptionalsDoesNotPass);
}
}
final List applied = newList();
final T t = createInstance();
for (NamedMutator namedMutator : builder.mandatoryMutators()) {
try {
builder.validator().accept(t);
throw new AssertionError("The mandatory mutators are " +
builder.mandatoryMutators().stream().map(DtoTesterBuilder.AbstractNamedHolderRecord::name).collect(Collectors.joining(", ", "[", "]")) +
" but the validator passed without throwing" +
" an Exception on using only " + applied + " applied on a fresh instance -> " + t);
} catch (Exception e) {
// Happy path
}
namedMutator.mutator().accept(t);
applied.add(namedMutator.name());
}
// We should now pass as all mandatory mutators are applied
try {
builder.validator().accept(t);
} catch (Exception e) {
throw new AssertionError("Validation did not pass despite having applied " + applied + " -> " + t, e);
}
for (NamedMutator namedMutator : builder.optionalMutators()) {
namedMutator.mutator().accept(t);
// We shall also pass validation using any and all optional mutators
builder.validator().accept(t);
}
}
private void assertOptionalsDoesNotPass(@NotNull final Set> set) {
requireNonNull(set);
final List optionalApplied = newList();
final T optionalTarget = createInstance();
for (NamedMutator namedMutator : set) {
namedMutator.mutator().accept(optionalTarget);
// We shall never pass when an optional mutator is passed
try {
builder.validator().accept(optionalTarget);
throw new AssertionError("There are at least one mandatory mutator but the validator passed without throwing " +
"an Exception on using only optional mutators " + optionalApplied + " applied on a fresh instance -> " + optionalTarget);
} catch (Exception e) {
// Happy path
}
}
}
private Collection check(final Consumer super T> postMutatorAction,
final BiFunction tester) {
final T fresh = createInstance();
final List failed = newList();
for (NamedMutator namedMutator : builder.allMutators()) {
final T t = createInstance();
namedMutator.mutator().accept(t);
postMutatorAction.accept(t);
if (tester.apply(fresh, t)) {
failed.add(namedMutator.name());
}
}
return failed;
}
private T createInstance() {
return builder.supplier().get();
}
private List newList() {
return new ArrayList<>();
}
} © 2015 - 2025 Weber Informatics LLC | Privacy Policy