aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFabian Meumertzheim <meumertzheim@code-intelligence.com>2023-02-08 14:32:07 +0100
committerFabian Meumertzheim <fabian@meumertzhe.im>2023-02-16 12:42:32 +0100
commit34f4650190e10c9e8d7660dc2c8c891fd645c0ec (patch)
treeafb0de1cc66a642103555e9191673d83513a2224
parenta445deac54d91df40a15778d821dae821e8e7428 (diff)
downloadjazzer-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.
-rw-r--r--src/main/java/com/code_intelligence/jazzer/mutation/api/MutatorFactory.java4
-rw-r--r--src/main/java/com/code_intelligence/jazzer/mutation/combinator/MutatorCombinators.java71
-rw-r--r--src/main/java/com/code_intelligence/jazzer/mutation/support/TypeSupport.java19
-rw-r--r--src/test/java/com/code_intelligence/jazzer/mutation/support/TypeSupportTest.java13
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();
+ }
}