aboutsummaryrefslogtreecommitdiff
path: root/src/test
diff options
context:
space:
mode:
author434b <christopher.krah@code-intelligence.com>2023-04-03 12:31:13 +0200
committerFabian Meumertzheim <fabian@meumertzhe.im>2023-04-14 15:10:58 +0200
commit26ab4cac66986d9bd27509a7ece8f21e8074bfe5 (patch)
tree33501edc283455798e50b45c03de2a21a2d0eddd /src/test
parent07550edc952c749053946c23afb5555b4d5bd849 (diff)
downloadjazzer-api-26ab4cac66986d9bd27509a7ece8f21e8074bfe5.tar.gz
mutation: Improve ListMutator
Adds chunk-based mutations to the list mutator mimicking fuzztest's mutation. The size of the chunks is chosen according to a Zipf distribution, which ensures that chunks tend to be small (and often have length 1), which should result in more stable mutations and also makes separate individual element mutations unnecessary. Co-authored-by: Fabian Meumertzheim <meumertzheim@code-intelligence.com>
Diffstat (limited to 'src/test')
-rw-r--r--src/test/java/com/code_intelligence/jazzer/mutation/ArgumentsMutatorTest.java80
-rw-r--r--src/test/java/com/code_intelligence/jazzer/mutation/engine/SeededPseudoRandomTest.java33
-rw-r--r--src/test/java/com/code_intelligence/jazzer/mutation/mutator/collection/BUILD.bazel1
-rw-r--r--src/test/java/com/code_intelligence/jazzer/mutation/mutator/collection/ChunkMutationsTest.java65
-rw-r--r--src/test/java/com/code_intelligence/jazzer/mutation/mutator/collection/ListMutatorTest.java224
-rw-r--r--src/test/java/com/code_intelligence/jazzer/mutation/mutator/proto/BuilderMutatorProto2Test.java45
-rw-r--r--src/test/java/com/code_intelligence/jazzer/mutation/mutator/proto/BuilderMutatorProto3Test.java46
-rw-r--r--src/test/java/com/code_intelligence/jazzer/mutation/support/TestSupport.java93
8 files changed, 513 insertions, 74 deletions
diff --git a/src/test/java/com/code_intelligence/jazzer/mutation/ArgumentsMutatorTest.java b/src/test/java/com/code_intelligence/jazzer/mutation/ArgumentsMutatorTest.java
index 03b592f1..61579205 100644
--- a/src/test/java/com/code_intelligence/jazzer/mutation/ArgumentsMutatorTest.java
+++ b/src/test/java/com/code_intelligence/jazzer/mutation/ArgumentsMutatorTest.java
@@ -80,17 +80,21 @@ class ArgumentsMutatorTest {
try (MockPseudoRandom prng = mockPseudoRandom(
// mutate first argument
0,
- // outer list not null
- false,
- // outer list mutate element
+ // Nullable mutator
false,
- // outer list mutate first element
+ // Action mutate in outer list
+ 2,
+ // Mutate one element,
+ 1,
+ // index to get to inner list
0,
- // inner list not null
- false,
- // inner list mutate element
+ // Nullable mutator
false,
- // inner list mutate first element
+ // Action mutate inner list
+ 2,
+ // Mutate one element,
+ 1,
+ // index to get boolean value
0)) {
mutator.mutate(prng);
}
@@ -108,17 +112,21 @@ class ArgumentsMutatorTest {
try (MockPseudoRandom prng = mockPseudoRandom(
// mutate first argument
0,
- // outer list not null
- false,
- // outer list mutate element
+ // Nullable mutator
false,
- // outer list mutate first element
+ // Action mutate in outer list
+ 2,
+ // Mutate one element,
+ 1,
+ // index to get to inner list
0,
- // inner list not null
- false,
- // inner list mutate element
+ // Nullable mutator
false,
- // inner list mutate first element
+ // Action mutate inner list
+ 2,
+ // Mutate one element,
+ 1,
+ // index to get boolean value
0)) {
mutator.mutate(prng);
}
@@ -178,17 +186,21 @@ class ArgumentsMutatorTest {
try (MockPseudoRandom prng = mockPseudoRandom(
// mutate first argument
0,
- // outer list not null
- false,
- // outer list mutate element
+ // Nullable mutator
false,
- // outer list mutate first element
+ // Action mutate in outer list
+ 2,
+ // Mutate one element,
+ 1,
+ // index to get to inner list
0,
- // inner list not null
- false,
- // inner list mutate element
+ // Nullable mutator
false,
- // inner list mutate first element
+ // Action mutate inner list
+ 2,
+ // Mutate one element,
+ 1,
+ // index to get boolean value
0)) {
mutator.mutate(prng);
}
@@ -206,17 +218,21 @@ class ArgumentsMutatorTest {
try (MockPseudoRandom prng = mockPseudoRandom(
// mutate first argument
0,
- // outer list not null
- false,
- // outer list mutate element
+ // Nullable mutator
false,
- // outer list mutate first element
+ // Action mutate in outer list
+ 2,
+ // Mutate one element,
+ 1,
+ // index to get to inner list
0,
- // inner list not null
- false,
- // inner list mutate element
+ // Nullable mutator
false,
- // inner list mutate first element
+ // Action mutate inner list
+ 2,
+ // Mutate one element,
+ 1,
+ // index to get boolean value
0)) {
mutator.mutate(prng);
}
diff --git a/src/test/java/com/code_intelligence/jazzer/mutation/engine/SeededPseudoRandomTest.java b/src/test/java/com/code_intelligence/jazzer/mutation/engine/SeededPseudoRandomTest.java
index 4ff95e1b..38ab2eb2 100644
--- a/src/test/java/com/code_intelligence/jazzer/mutation/engine/SeededPseudoRandomTest.java
+++ b/src/test/java/com/code_intelligence/jazzer/mutation/engine/SeededPseudoRandomTest.java
@@ -17,10 +17,16 @@
package com.code_intelligence.jazzer.mutation.engine;
import static com.google.common.truth.Truth.assertThat;
+import static java.util.stream.Collectors.collectingAndThen;
+import static java.util.stream.Collectors.counting;
+import static java.util.stream.Collectors.groupingBy;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.params.provider.Arguments.arguments;
+import com.google.common.truth.Correspondence;
+import java.util.Map;
import java.util.stream.Stream;
+import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
@@ -107,4 +113,31 @@ public class SeededPseudoRandomTest {
}
}
}
+
+ @Test
+ void testClosedRangeBiasedTowardsSmall() {
+ SeededPseudoRandom prng = new SeededPseudoRandom(1337133371337L);
+
+ assertThrows(IllegalArgumentException.class, () -> prng.closedRangeBiasedTowardsSmall(-1));
+ assertThrows(IllegalArgumentException.class, () -> prng.closedRangeBiasedTowardsSmall(2, 1));
+ assertThat(prng.closedRangeBiasedTowardsSmall(0)).isEqualTo(0);
+ assertThat(prng.closedRangeBiasedTowardsSmall(5, 5)).isEqualTo(5);
+ }
+
+ @Test
+ void testClosedRangeBiasedTowardsSmall_distribution() {
+ int num = 5000000;
+ SeededPseudoRandom prng = new SeededPseudoRandom(1337133371337L);
+ Map<Integer, Double> frequencies =
+ Stream.generate(() -> prng.closedRangeBiasedTowardsSmall(9))
+ .limit(num)
+ .collect(
+ groupingBy(i -> i, collectingAndThen(counting(), count -> ((double) count) / num)));
+ // Reference values obtained from
+ // https://www.wolframalpha.com/input?i=N%5BTable%5BPDF%5BZipfDistribution%5B10%2C+1%5D%2C+i%5D%2C+%7Bi%2C+1%2C+10%7D%5D%5D
+ assertThat(frequencies)
+ .comparingValuesUsing(Correspondence.tolerance(0.0005))
+ .containsExactly(0, 0.645, 1, 0.161, 2, 0.072, 3, 0.040, 4, 0.026, 5, 0.018, 6, 0.013, 7,
+ 0.01, 8, 0.008, 9, 0.006);
+ }
}
diff --git a/src/test/java/com/code_intelligence/jazzer/mutation/mutator/collection/BUILD.bazel b/src/test/java/com/code_intelligence/jazzer/mutation/mutator/collection/BUILD.bazel
index bfd3fd49..0b203a9c 100644
--- a/src/test/java/com/code_intelligence/jazzer/mutation/mutator/collection/BUILD.bazel
+++ b/src/test/java/com/code_intelligence/jazzer/mutation/mutator/collection/BUILD.bazel
@@ -10,6 +10,7 @@ java_test_suite(
"//src/main/java/com/code_intelligence/jazzer/mutation/annotation",
"//src/main/java/com/code_intelligence/jazzer/mutation/api",
"//src/main/java/com/code_intelligence/jazzer/mutation/mutator",
+ "//src/main/java/com/code_intelligence/jazzer/mutation/mutator/collection",
"//src/main/java/com/code_intelligence/jazzer/mutation/support",
"//src/test/java/com/code_intelligence/jazzer/mutation/support:test_support",
"@com_google_protobuf//java/core",
diff --git a/src/test/java/com/code_intelligence/jazzer/mutation/mutator/collection/ChunkMutationsTest.java b/src/test/java/com/code_intelligence/jazzer/mutation/mutator/collection/ChunkMutationsTest.java
new file mode 100644
index 00000000..2667aa27
--- /dev/null
+++ b/src/test/java/com/code_intelligence/jazzer/mutation/mutator/collection/ChunkMutationsTest.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2023 Code Intelligence GmbH
+ *
+ * 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.
+ */
+
+package com.code_intelligence.jazzer.mutation.mutator.collection;
+
+import static com.code_intelligence.jazzer.mutation.support.TestSupport.mockInitializer;
+import static com.code_intelligence.jazzer.mutation.support.TestSupport.mockMutator;
+import static com.code_intelligence.jazzer.mutation.support.TestSupport.mockPseudoRandom;
+import static com.google.common.truth.Truth.assertThat;
+import static java.util.stream.Collectors.toList;
+
+import com.code_intelligence.jazzer.mutation.support.TestSupport.MockPseudoRandom;
+import java.util.List;
+import java.util.stream.Stream;
+import org.junit.jupiter.api.Test;
+
+class ChunkMutationsTest {
+ @Test
+ void testDeleteRandomChunk() {
+ List<Integer> list = Stream.of(1, 2, 3, 4, 5, 6).collect(toList());
+
+ try (MockPseudoRandom prng = mockPseudoRandom(2, 3)) {
+ ChunkMutations.deleteRandomChunk(list, 2, prng);
+ }
+ assertThat(list).containsExactly(1, 2, 3, 6).inOrder();
+ }
+
+ @Test
+ void testInsertRandomChunk() {
+ List<String> list = Stream.of("1", "2", "3", "4", "5", "6").collect(toList());
+
+ try (MockPseudoRandom prng = mockPseudoRandom(2, 3)) {
+ ChunkMutations.insertRandomChunk(list, 10, mockInitializer(() -> "7", String::new), prng);
+ }
+ assertThat(list).containsExactly("1", "2", "3", "7", "7", "4", "5", "6").inOrder();
+ String firstNewValue = list.get(3);
+ String secondNewValue = list.get(4);
+ assertThat(firstNewValue).isEqualTo(secondNewValue);
+ // Verify that the individual new elements were detached.
+ assertThat(firstNewValue).isNotSameInstanceAs(secondNewValue);
+ }
+
+ @Test
+ void testMutateChunk() {
+ List<Integer> list = Stream.of(1, 2, 3, 4, 5, 6).collect(toList());
+
+ try (MockPseudoRandom prng = mockPseudoRandom(2, 3)) {
+ ChunkMutations.mutateRandomChunk(list, mockMutator(1, i -> 2 * i), prng);
+ }
+ assertThat(list).containsExactly(1, 2, 3, 8, 10, 6).inOrder();
+ }
+}
diff --git a/src/test/java/com/code_intelligence/jazzer/mutation/mutator/collection/ListMutatorTest.java b/src/test/java/com/code_intelligence/jazzer/mutation/mutator/collection/ListMutatorTest.java
new file mode 100644
index 00000000..0474e17f
--- /dev/null
+++ b/src/test/java/com/code_intelligence/jazzer/mutation/mutator/collection/ListMutatorTest.java
@@ -0,0 +1,224 @@
+/*
+ * Copyright 2023 Code Intelligence GmbH
+ *
+ * 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.
+ */
+
+package com.code_intelligence.jazzer.mutation.mutator.collection;
+
+import static com.code_intelligence.jazzer.mutation.support.TestSupport.mockPseudoRandom;
+import static com.google.common.truth.Truth.assertThat;
+
+import com.code_intelligence.jazzer.mutation.annotation.NotNull;
+import com.code_intelligence.jazzer.mutation.annotation.WithSize;
+import com.code_intelligence.jazzer.mutation.api.MutatorFactory;
+import com.code_intelligence.jazzer.mutation.api.SerializingMutator;
+import com.code_intelligence.jazzer.mutation.mutator.Mutators;
+import com.code_intelligence.jazzer.mutation.support.TestSupport.MockPseudoRandom;
+import com.code_intelligence.jazzer.mutation.support.TypeHolder;
+import java.lang.reflect.AnnotatedType;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class ListMutatorTest {
+ public static final MutatorFactory FACTORY = Mutators.newFactory();
+
+ @Test
+ void testInit() {
+ AnnotatedType type = new TypeHolder<@NotNull List<@NotNull Integer>>() {}.annotatedType();
+
+ SerializingMutator<@NotNull List<@NotNull Integer>> mutator =
+ (SerializingMutator<@NotNull List<@NotNull Integer>>) FACTORY.createOrThrow(type);
+
+ assertThat(mutator.toString()).isEqualTo("List<Integer>");
+
+ List<Integer> list;
+ try (MockPseudoRandom prng = mockPseudoRandom(
+ // targetSize
+ 1,
+ // elementMutator.init
+ 1)) {
+ list = mutator.init(prng);
+ }
+ assertThat(list).containsExactly(0);
+ }
+
+ @Test
+ void testInitMaxSize() {
+ AnnotatedType type =
+ new TypeHolder<@NotNull @WithSize(min = 2, max = 3) List<@NotNull Integer>>(){}
+ .annotatedType();
+
+ SerializingMutator<@NotNull List<@NotNull Integer>> mutator =
+ (SerializingMutator<@NotNull List<@NotNull Integer>>) FACTORY.createOrThrow(type);
+
+ assertThat(mutator.toString()).isEqualTo("List<Integer>");
+ List<Integer> list;
+ try (MockPseudoRandom prng = mockPseudoRandom(2, 4, 42L, 4, 43L)) {
+ list = mutator.init(prng);
+ }
+
+ assertThat(list).containsExactly(42, 43);
+ }
+
+ @Test
+ void testRemoveSingleElement() {
+ AnnotatedType type = new TypeHolder<@NotNull List<@NotNull Integer>>() {}.annotatedType();
+
+ SerializingMutator<@NotNull List<@NotNull Integer>> mutator =
+ (SerializingMutator<@NotNull List<@NotNull Integer>>) FACTORY.createOrThrow(type);
+
+ List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9));
+
+ try (MockPseudoRandom prng = mockPseudoRandom(
+ // action
+ 0,
+ // number of elements to remove
+ 1,
+ // index to remove
+ 2)) {
+ list = mutator.mutate(list, prng);
+ }
+ assertThat(list).containsExactly(1, 2, 4, 5, 6, 7, 8, 9);
+ }
+
+ @Test
+ void testRemoveChunk() {
+ AnnotatedType type = new TypeHolder<@NotNull List<@NotNull Integer>>() {}.annotatedType();
+
+ SerializingMutator<@NotNull List<@NotNull Integer>> mutator =
+ (SerializingMutator<@NotNull List<@NotNull Integer>>) FACTORY.createOrThrow(type);
+
+ List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9));
+
+ try (MockPseudoRandom prng = mockPseudoRandom(
+ // action
+ 0,
+ // chunk size
+ 2,
+ // chunk offset
+ 3)) {
+ list = mutator.mutate(list, prng);
+ }
+
+ assertThat(list).containsExactly(1, 2, 3, 6, 7, 8, 9);
+ }
+
+ @Test
+ void testAddSingleElement() {
+ AnnotatedType type = new TypeHolder<@NotNull List<@NotNull Integer>>() {}.annotatedType();
+
+ SerializingMutator<@NotNull List<@NotNull Integer>> mutator =
+ (SerializingMutator<@NotNull List<@NotNull Integer>>) FACTORY.createOrThrow(type);
+
+ List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9));
+
+ try (MockPseudoRandom prng = mockPseudoRandom(
+ // action
+ 1,
+ // add single element,
+ 1,
+ // offset,
+ 9,
+ // Integral initImpl sentinel value
+ 4,
+ // value
+ 42L)) {
+ list = mutator.mutate(list, prng);
+ }
+
+ assertThat(list).containsExactly(1, 2, 3, 4, 5, 6, 7, 8, 9, 42);
+ }
+
+ @Test
+ void testAddChunk() {
+ AnnotatedType type = new TypeHolder<@NotNull List<@NotNull Integer>>() {}.annotatedType();
+
+ SerializingMutator<@NotNull List<@NotNull Integer>> mutator =
+ (SerializingMutator<@NotNull List<@NotNull Integer>>) FACTORY.createOrThrow(type);
+
+ List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9));
+
+ try (MockPseudoRandom prng = mockPseudoRandom(
+ // action
+ 1,
+ // chunkSize
+ 2,
+ // chunkOffset
+ 3,
+ // Integral initImpl
+ 4,
+ // val
+ 42L)) {
+ list = mutator.mutate(list, prng);
+ }
+ assertThat(list).containsExactly(1, 2, 3, 42, 42, 4, 5, 6, 7, 8, 9);
+ }
+
+ @Test
+ void testChangeSingleElement() {
+ AnnotatedType type = new TypeHolder<@NotNull List<@NotNull Integer>>() {}.annotatedType();
+
+ SerializingMutator<@NotNull List<@NotNull Integer>> mutator =
+ (SerializingMutator<@NotNull List<@NotNull Integer>>) FACTORY.createOrThrow(type);
+
+ List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9));
+
+ try (MockPseudoRandom prng = mockPseudoRandom(
+ // action
+ 2,
+ // number of elements to mutate
+ 1,
+ // first index to mutate at
+ 2,
+ // mutation choice based on `IntegralMutatorFactory`
+ // 2 == closedRange
+ 2,
+ // value
+ 55L)) {
+ list = mutator.mutate(list, prng);
+ }
+ assertThat(list).containsExactly(1, 2, 55, 4, 5, 6, 7, 8, 9);
+ }
+
+ @Test
+ void testChangeChunk() {
+ AnnotatedType type = new TypeHolder<@NotNull List<@NotNull Integer>>() {}.annotatedType();
+
+ SerializingMutator<@NotNull List<@NotNull Integer>> mutator =
+ (SerializingMutator<@NotNull List<@NotNull Integer>>) FACTORY.createOrThrow(type);
+
+ List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11));
+
+ try (MockPseudoRandom prng = mockPseudoRandom(
+ // action
+ 2,
+ // number of elements to mutate
+ 2,
+ // first index to mutate at
+ 5,
+ // mutation: 0 == bitflip
+ 0,
+ // shift constant
+ 13,
+ // and again
+ 0, 12)) {
+ list = mutator.mutate(list, prng);
+ }
+ assertThat(list).containsExactly(1, 2, 3, 4, 5, 8198, 4103, 8, 9, 10, 11);
+ }
+}
diff --git a/src/test/java/com/code_intelligence/jazzer/mutation/mutator/proto/BuilderMutatorProto2Test.java b/src/test/java/com/code_intelligence/jazzer/mutation/mutator/proto/BuilderMutatorProto2Test.java
index 55367bb6..f992d502 100644
--- a/src/test/java/com/code_intelligence/jazzer/mutation/mutator/proto/BuilderMutatorProto2Test.java
+++ b/src/test/java/com/code_intelligence/jazzer/mutation/mutator/proto/BuilderMutatorProto2Test.java
@@ -131,7 +131,13 @@ class BuilderMutatorProto2Test {
try (MockPseudoRandom prng = mockPseudoRandom(
// mutate first field
0,
- // mutate the list itself by duplicating an entry
+ // mutate the list itself by adding an entry
+ 1,
+ // add a single element
+ 1,
+ // add the element at the end
+ 1,
+ // value to add
true)) {
mutator.mutateInPlace(builder, prng);
}
@@ -140,14 +146,17 @@ class BuilderMutatorProto2Test {
try (MockPseudoRandom prng = mockPseudoRandom(
// mutate first field
0,
- // mutate a list element,
- false,
- // mutate the second element,
+ // mutate the list itself by changing an entry
+ 2,
+ // mutate a single element
+ 1,
+ // mutate the second element
1)) {
mutator.mutateInPlace(builder, prng);
}
assertThat(builder.getSomeFieldList()).containsExactly(true, false).inOrder();
}
+
@Test
void testMessageField() {
InPlaceMutator<MessageField2.Builder> mutator =
@@ -214,7 +223,15 @@ class BuilderMutatorProto2Test {
try (MockPseudoRandom prng = mockPseudoRandom(
// mutate first field
0,
- // mutate the list itself by duplicating an entry
+ // mutate the list itself by adding an entry
+ 1,
+ // add a single element
+ 1,
+ // add the element at the end
+ 1,
+ // Nullable mutator init
+ false,
+ // duplicate entry
true)) {
mutator.mutateInPlace(builder, prng);
}
@@ -244,7 +261,13 @@ class BuilderMutatorProto2Test {
try (MockPseudoRandom prng = mockPseudoRandom(
// mutate first field
0,
- // mutate the list itself by duplicating an entry
+ // mutate the list itself by adding an entry
+ 1,
+ // add a single element
+ 1,
+ // add the element at the end
+ 1,
+ // value to add
true)) {
mutator.mutateInPlace(builder, prng);
}
@@ -256,11 +279,13 @@ class BuilderMutatorProto2Test {
try (MockPseudoRandom prng = mockPseudoRandom(
// mutate first field
0,
- // mutate a list element
- false,
- // mutate the second element
+ // change an entry
+ 2,
+ // mutate a single element
+ 1,
+ // mutate the second element,
1,
- // mutate the first field
+ // mutate the first element
0)) {
mutator.mutateInPlace(builder, prng);
}
diff --git a/src/test/java/com/code_intelligence/jazzer/mutation/mutator/proto/BuilderMutatorProto3Test.java b/src/test/java/com/code_intelligence/jazzer/mutation/mutator/proto/BuilderMutatorProto3Test.java
index 608191ee..c39376a2 100644
--- a/src/test/java/com/code_intelligence/jazzer/mutation/mutator/proto/BuilderMutatorProto3Test.java
+++ b/src/test/java/com/code_intelligence/jazzer/mutation/mutator/proto/BuilderMutatorProto3Test.java
@@ -145,8 +145,10 @@ class BuilderMutatorProto3Test {
try (MockPseudoRandom prng = mockPseudoRandom(
// mutate first field
0,
- // mutate operation
- false,
+ // change an entry
+ 2,
+ // mutate a single element
+ 1,
// mutate to first enum field
0,
// mutate to first enum value
@@ -225,7 +227,13 @@ class BuilderMutatorProto3Test {
try (MockPseudoRandom prng = mockPseudoRandom(
// mutate first field
0,
- // mutate the list itself by duplicating an entry
+ // mutate the list itself by adding an entry
+ 1,
+ // add a single element
+ 1,
+ // add the element at the end
+ 1,
+ // value to add
true)) {
mutator.mutateInPlace(builder, prng);
}
@@ -234,9 +242,11 @@ class BuilderMutatorProto3Test {
try (MockPseudoRandom prng = mockPseudoRandom(
// mutate first field
0,
- // mutate a list element,
- false,
- // mutate the second element,
+ // mutate the list itself by changing an entry
+ 2,
+ // mutate a single element
+ 1,
+ // mutate the second element
1)) {
mutator.mutateInPlace(builder, prng);
}
@@ -309,7 +319,13 @@ class BuilderMutatorProto3Test {
try (MockPseudoRandom prng = mockPseudoRandom(
// mutate first field
0,
- // mutate the list itself by duplicating an entry
+ // mutate the list itself by adding an entry
+ 1,
+ // add a single element
+ 1,
+ // add the element at the end
+ 1,
+ // value to add
true)) {
mutator.mutateInPlace(builder, prng);
}
@@ -321,11 +337,13 @@ class BuilderMutatorProto3Test {
try (MockPseudoRandom prng = mockPseudoRandom(
// mutate first field
0,
- // mutate a list element
- false,
- // mutate the second element
+ // change an entry
+ 2,
+ // mutate a single element
+ 1,
+ // mutate the second element,
1,
- // mutate the first field
+ // mutate the first element
0)) {
mutator.mutateInPlace(builder, prng);
}
@@ -355,7 +373,8 @@ class BuilderMutatorProto3Test {
true)) {
mutator.initInPlace(builder, prng);
}
- // Nested message field is *not* set explicitly and implicitly equal to the default instance.
+ // Nested message field is *not* set explicitly and implicitly equal to the
+ // default instance.
assertThat(builder.build())
.isEqualTo(RecursiveMessageField3.newBuilder()
.setSomeField(true)
@@ -376,7 +395,8 @@ class BuilderMutatorProto3Test {
true)) {
mutator.mutateInPlace(builder, prng);
}
- // Nested message field *is* set explicitly and implicitly equal to the default instance.
+ // Nested message field *is* set explicitly and implicitly equal to the default
+ // instance.
assertThat(builder.build())
.isEqualTo(RecursiveMessageField3.newBuilder()
.setSomeField(true)
diff --git a/src/test/java/com/code_intelligence/jazzer/mutation/support/TestSupport.java b/src/test/java/com/code_intelligence/jazzer/mutation/support/TestSupport.java
index 1f863d24..5d6cf33b 100644
--- a/src/test/java/com/code_intelligence/jazzer/mutation/support/TestSupport.java
+++ b/src/test/java/com/code_intelligence/jazzer/mutation/support/TestSupport.java
@@ -35,6 +35,8 @@ import java.util.List;
import java.util.Queue;
import java.util.function.Function;
import java.util.function.Predicate;
+import java.util.function.Supplier;
+import java.util.function.UnaryOperator;
public final class TestSupport {
private static final DataOutputStream nullDataOutputStream =
@@ -69,42 +71,73 @@ public final class TestSupport {
@CheckReturnValue
public static <T> SerializingMutator<T> mockMutator(T initialValue, Function<T, T> mutate) {
- return new SerializingMutator<T>() {
+ return new AbstractMockMutator<T>() {
@Override
- public T read(DataInputStream in) {
+ protected T nextInitialValue() {
return initialValue;
}
@Override
- public void write(T value, DataOutputStream out) {
- throw new UnsupportedOperationException("mockMutator does not support write");
+ public T mutate(T value, PseudoRandom prng) {
+ return mutate.apply(value);
}
+ };
+ }
+ @CheckReturnValue
+ public static <T> SerializingMutator<T> mockInitializer(
+ Supplier<T> getInitialValues, UnaryOperator<T> detach) {
+ return new AbstractMockMutator<T>() {
@Override
- public T init(PseudoRandom prng) {
- return initialValue;
+ protected T nextInitialValue() {
+ return getInitialValues.get();
}
@Override
public T mutate(T value, PseudoRandom prng) {
- return mutate.apply(value);
- }
-
- @Override
- public String toDebugString(Predicate<Debuggable> isInCycle) {
- if (initialValue == null) {
- return "null";
- }
- return initialValue.getClass().getSimpleName();
+ throw new UnsupportedOperationException();
}
@Override
public T detach(T value) {
- return value;
+ return detach.apply(value);
}
};
}
+ private static abstract class AbstractMockMutator<T> extends SerializingMutator<T> {
+ abstract protected T nextInitialValue();
+
+ @Override
+ public T read(DataInputStream in) {
+ return nextInitialValue();
+ }
+
+ @Override
+ public void write(T value, DataOutputStream out) {
+ throw new UnsupportedOperationException("mockMutator does not support write");
+ }
+
+ @Override
+ public T init(PseudoRandom prng) {
+ return nextInitialValue();
+ }
+
+ @Override
+ public String toDebugString(Predicate<Debuggable> isInCycle) {
+ T initialValue = nextInitialValue();
+ if (initialValue == null) {
+ return "null";
+ }
+ return initialValue.getClass().getSimpleName();
+ }
+
+ @Override
+ public T detach(T value) {
+ return value;
+ }
+ }
+
public static final class MockPseudoRandom implements PseudoRandom, AutoCloseable {
private final Queue<Object> elements;
@@ -161,7 +194,7 @@ public final class TestSupport {
@Override
public int indexIn(int range) {
- assertThat(range).isAtLeast(2);
+ assertThat(range).isAtLeast(1);
assertThat(elements).isNotEmpty();
return (int) elements.poll();
@@ -185,7 +218,7 @@ public final class TestSupport {
@Override
public int closedRange(int lowerInclusive, int upperInclusive) {
- assertThat(lowerInclusive).isLessThan(upperInclusive);
+ assertThat(lowerInclusive).isAtMost(upperInclusive);
assertThat(elements).isNotEmpty();
int result = (int) elements.poll();
@@ -196,7 +229,7 @@ public final class TestSupport {
@Override
public long closedRange(long lowerInclusive, long upperInclusive) {
- assertThat(lowerInclusive).isLessThan(upperInclusive);
+ assertThat(lowerInclusive).isAtMost(upperInclusive);
assertThat(elements).isNotEmpty();
long result = (long) elements.poll();
@@ -226,6 +259,28 @@ public final class TestSupport {
}
@Override
+ public int closedRangeBiasedTowardsSmall(int upperInclusive) {
+ assertThat(upperInclusive).isAtLeast(0);
+
+ assertThat(elements).isNotEmpty();
+ int result = (int) elements.poll();
+ assertThat(result).isAtLeast(0);
+ assertThat(result).isAtMost(upperInclusive);
+ return result;
+ }
+
+ @Override
+ public int closedRangeBiasedTowardsSmall(int lowerInclusive, int upperInclusive) {
+ assertThat(lowerInclusive).isAtMost(upperInclusive);
+
+ assertThat(elements).isNotEmpty();
+ int result = (int) elements.poll();
+ assertThat(result).isAtLeast(lowerInclusive);
+ assertThat(result).isAtMost(upperInclusive);
+ return result;
+ }
+
+ @Override
public void bytes(byte[] bytes) {
assertThat(elements).isNotEmpty();
byte[] result = (byte[]) elements.poll();