diff options
author | Fabian Meumertzheim <meumertzheim@code-intelligence.com> | 2023-02-08 14:32:07 +0100 |
---|---|---|
committer | Fabian Meumertzheim <fabian@meumertzhe.im> | 2023-02-16 12:42:32 +0100 |
commit | 34f4650190e10c9e8d7660dc2c8c891fd645c0ec (patch) | |
tree | afb0de1cc66a642103555e9191673d83513a2224 | |
parent | a445deac54d91df40a15778d821dae821e8e7428 (diff) | |
download | jazzer-api-34f4650190e10c9e8d7660dc2c8c891fd645c0ec.tar.gz |
mutation: Add a few utility methods
This adds:
* asSubclassOrEmpty as a variant of Class#asSubclass;
* an overload of combine that assembles a SerializingInPlaceMutator;
* an overload of MutatorFactory#createInPlaceOrThrow for AnnotatedType.
4 files changed, 107 insertions, 0 deletions
diff --git a/src/main/java/com/code_intelligence/jazzer/mutation/api/MutatorFactory.java b/src/main/java/com/code_intelligence/jazzer/mutation/api/MutatorFactory.java index 4387711e..120c1a8a 100644 --- a/src/main/java/com/code_intelligence/jazzer/mutation/api/MutatorFactory.java +++ b/src/main/java/com/code_intelligence/jazzer/mutation/api/MutatorFactory.java @@ -35,6 +35,10 @@ public abstract class MutatorFactory { return maybeMutator.get(); } + public final <T> SerializingInPlaceMutator<T> createInPlaceOrThrow(Class<T> clazz) { + return (SerializingInPlaceMutator<T>) createOrThrow(asAnnotatedType(clazz)); + } + public final SerializingInPlaceMutator<?> createInPlaceOrThrow(AnnotatedType type) { SerializingMutator<?> mutator = createOrThrow(type); require(mutator instanceof InPlaceMutator<?>, diff --git a/src/main/java/com/code_intelligence/jazzer/mutation/combinator/MutatorCombinators.java b/src/main/java/com/code_intelligence/jazzer/mutation/combinator/MutatorCombinators.java index a9d0ddd1..b131b8e4 100644 --- a/src/main/java/com/code_intelligence/jazzer/mutation/combinator/MutatorCombinators.java +++ b/src/main/java/com/code_intelligence/jazzer/mutation/combinator/MutatorCombinators.java @@ -24,11 +24,19 @@ import static java.util.stream.Collectors.joining; import com.code_intelligence.jazzer.mutation.api.InPlaceMutator; import com.code_intelligence.jazzer.mutation.api.PseudoRandom; +import com.code_intelligence.jazzer.mutation.api.Serializer; +import com.code_intelligence.jazzer.mutation.api.SerializingInPlaceMutator; import com.code_intelligence.jazzer.mutation.api.SerializingMutator; import com.code_intelligence.jazzer.mutation.api.ValueMutator; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; import java.util.Arrays; import java.util.function.BiConsumer; import java.util.function.Function; +import java.util.function.Supplier; import net.jodah.typetools.TypeResolver; public final class MutatorCombinators { @@ -113,6 +121,69 @@ public final class MutatorCombinators { }; } + /** + * Assembles the parameters into a full implementation of {@link SerializingInPlaceMutator<T>}: + * + * @param makeDefaultInstance constructs a mutable default instance of {@code T} + * @param serializerDelegate implementation of the {@link Serializer<T>} part + * @param partialMutators one or more mutators that are combined with + * {@link #combine(InPlaceMutator[])} + */ + @SafeVarargs + public static <T> SerializingInPlaceMutator<T> combine(Supplier<T> makeDefaultInstance, + Serializer<T> serializerDelegate, InPlaceMutator<T>... partialMutators) { + requireNonNull(makeDefaultInstance); + requireNonNull(serializerDelegate); + + InPlaceMutator<T> mutatorDelegate = combine(partialMutators); + return new SerializingInPlaceMutator<T>() { + @Override + public void initInPlace(T reference, PseudoRandom prng) { + mutatorDelegate.initInPlace(reference, prng); + } + + @Override + public void mutateInPlace(T reference, PseudoRandom prng) { + mutatorDelegate.mutateInPlace(reference, prng); + } + + @Override + protected T makeDefaultInstance() { + return makeDefaultInstance.get(); + } + + @Override + public String toString() { + return mutatorDelegate.toString(); + } + + @Override + public T read(DataInputStream in) throws IOException { + return serializerDelegate.read(in); + } + + @Override + public void write(T value, DataOutputStream out) throws IOException { + serializerDelegate.write(value, out); + } + + @Override + public T readExclusive(InputStream in) throws IOException { + return serializerDelegate.readExclusive(in); + } + + @Override + public void writeExclusive(T value, OutputStream out) throws IOException { + serializerDelegate.writeExclusive(value, out); + } + + @Override + public T detach(T value) { + return serializerDelegate.detach(value); + } + }; + } + public static <T, R> SerializingMutator<R> mutateThenMap( SerializingMutator<T> mutator, Function<T, R> map, Function<R, T> inverse) { return new PostComposedMutator<T, R>(mutator, map, inverse) {}; diff --git a/src/main/java/com/code_intelligence/jazzer/mutation/support/TypeSupport.java b/src/main/java/com/code_intelligence/jazzer/mutation/support/TypeSupport.java index ecf07b77..e8ff2182 100644 --- a/src/main/java/com/code_intelligence/jazzer/mutation/support/TypeSupport.java +++ b/src/main/java/com/code_intelligence/jazzer/mutation/support/TypeSupport.java @@ -59,6 +59,25 @@ public final class TypeSupport { return annotation.annotationType().getDeclaredAnnotation(Inherited.class) != null; } + /** + * Returns {@code type} as a {@code Class<T>} if it is a subclass of T, otherwise empty. + * + * <p>This function also returns an empty {@link Optional} for more complex (e.g. parameterized) + * types. + */ + public static <T> Optional<Class<T>> asSubclassOrEmpty(AnnotatedType type, Class<T> superclass) { + if (!(type.getType() instanceof Class<?>) ) { + return Optional.empty(); + } + + Class<?> actualClazz = (Class<?>) type.getType(); + if (!superclass.isAssignableFrom(actualClazz)) { + return Optional.empty(); + } + + return Optional.of(actualClazz.asSubclass(superclass)); + } + public static AnnotatedType asAnnotatedType(Class<?> clazz) { requireNonNull(clazz); return new AnnotatedType() { diff --git a/src/test/java/com/code_intelligence/jazzer/mutation/support/TypeSupportTest.java b/src/test/java/com/code_intelligence/jazzer/mutation/support/TypeSupportTest.java index 6248d799..dcf090b2 100644 --- a/src/test/java/com/code_intelligence/jazzer/mutation/support/TypeSupportTest.java +++ b/src/test/java/com/code_intelligence/jazzer/mutation/support/TypeSupportTest.java @@ -17,8 +17,10 @@ package com.code_intelligence.jazzer.mutation.support; import static com.code_intelligence.jazzer.mutation.support.TypeSupport.asAnnotatedType; +import static com.code_intelligence.jazzer.mutation.support.TypeSupport.asSubclassOrEmpty; import static com.code_intelligence.jazzer.mutation.support.TypeSupport.withTypeArguments; import static com.google.common.truth.Truth.assertThat; +import static com.google.common.truth.Truth8.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; import com.code_intelligence.jazzer.mutation.annotation.NotNull; @@ -191,4 +193,15 @@ class TypeSupportTest { assertThrows(IllegalArgumentException.class, () -> withTypeArguments(new TypeHolder<List<?>>() { }.annotatedType(), asAnnotatedType(String.class))); } + + @Test + void testAsSubclassOrEmpty() { + assertThat(asSubclassOrEmpty(asAnnotatedType(String.class), String.class)) + .hasValue(String.class); + assertThat(asSubclassOrEmpty(asAnnotatedType(String.class), CharSequence.class)) + .hasValue(String.class); + assertThat(asSubclassOrEmpty(asAnnotatedType(CharSequence.class), String.class)).isEmpty(); + assertThat(asSubclassOrEmpty(new TypeHolder<List<String>>() { + }.annotatedType(), List.class)).isEmpty(); + } } |