aboutsummaryrefslogtreecommitdiff
path: root/src/test/java/com/code_intelligence/jazzer/mutation/mutator/proto
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/java/com/code_intelligence/jazzer/mutation/mutator/proto')
-rw-r--r--src/test/java/com/code_intelligence/jazzer/mutation/mutator/proto/BUILD.bazel60
-rw-r--r--src/test/java/com/code_intelligence/jazzer/mutation/mutator/proto/BuilderAdaptersTest.java87
-rw-r--r--src/test/java/com/code_intelligence/jazzer/mutation/mutator/proto/BuilderMutatorProto2Test.java447
-rw-r--r--src/test/java/com/code_intelligence/jazzer/mutation/mutator/proto/BuilderMutatorProto3Test.java603
-rw-r--r--src/test/java/com/code_intelligence/jazzer/mutation/mutator/proto/MessageMutatorTest.java92
-rw-r--r--src/test/java/com/code_intelligence/jazzer/mutation/mutator/proto/proto2.proto161
-rw-r--r--src/test/java/com/code_intelligence/jazzer/mutation/mutator/proto/proto3.proto144
7 files changed, 1594 insertions, 0 deletions
diff --git a/src/test/java/com/code_intelligence/jazzer/mutation/mutator/proto/BUILD.bazel b/src/test/java/com/code_intelligence/jazzer/mutation/mutator/proto/BUILD.bazel
new file mode 100644
index 00000000..bf8b551d
--- /dev/null
+++ b/src/test/java/com/code_intelligence/jazzer/mutation/mutator/proto/BUILD.bazel
@@ -0,0 +1,60 @@
+load("@contrib_rules_jvm//java:defs.bzl", "java_test_suite")
+
+proto_library(
+ name = "proto3_proto",
+ srcs = ["proto3.proto"],
+ deps = [
+ "@com_google_protobuf//:any_proto",
+ ],
+)
+
+java_proto_library(
+ name = "proto3_java_proto",
+ testonly = True,
+ visibility = ["//src/test/java/com/code_intelligence/jazzer/mutation/mutator:__pkg__"],
+ deps = [":proto3_proto"],
+)
+
+proto_library(
+ name = "proto2_proto",
+ srcs = ["proto2.proto"],
+)
+
+java_proto_library(
+ name = "proto2_java_proto",
+ testonly = True,
+ visibility = [
+ "//src/test/java/com/code_intelligence/jazzer/mutation/mutator:__pkg__",
+ "//tests:__pkg__",
+ ],
+ deps = [":proto2_proto"],
+)
+
+cc_proto_library(
+ name = "proto2_cc_proto",
+ testonly = True,
+ visibility = [
+ "//tests:__pkg__",
+ ],
+ deps = [":proto2_proto"],
+)
+
+java_test_suite(
+ name = "ProtoTests",
+ size = "small",
+ srcs = glob(["*.java"]),
+ runner = "junit5",
+ deps = [
+ ":proto2_java_proto",
+ ":proto3_java_proto",
+ "//src/main/java/com/code_intelligence/jazzer/mutation/annotation",
+ "//src/main/java/com/code_intelligence/jazzer/mutation/annotation/proto",
+ "//src/main/java/com/code_intelligence/jazzer/mutation/api",
+ "//src/main/java/com/code_intelligence/jazzer/mutation/mutator/collection",
+ "//src/main/java/com/code_intelligence/jazzer/mutation/mutator/lang",
+ "//src/main/java/com/code_intelligence/jazzer/mutation/mutator/proto",
+ "//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/proto/BuilderAdaptersTest.java b/src/test/java/com/code_intelligence/jazzer/mutation/mutator/proto/BuilderAdaptersTest.java
new file mode 100644
index 00000000..7722a6ad
--- /dev/null
+++ b/src/test/java/com/code_intelligence/jazzer/mutation/mutator/proto/BuilderAdaptersTest.java
@@ -0,0 +1,87 @@
+/*
+ * 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.proto;
+
+import static com.code_intelligence.jazzer.mutation.mutator.proto.BuilderAdapters.makeMutableRepeatedFieldView;
+import static com.google.common.truth.Truth.assertThat;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import com.code_intelligence.jazzer.protobuf.Proto3.RepeatedIntegralField3;
+import com.google.protobuf.Descriptors.FieldDescriptor;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import org.junit.jupiter.api.Test;
+
+class BuilderAdaptersTest {
+ @Test
+ void testMakeMutableRepeatedFieldView() {
+ RepeatedIntegralField3.Builder builder = RepeatedIntegralField3.newBuilder();
+ FieldDescriptor someField = builder.getDescriptorForType().findFieldByNumber(1);
+ assertThat(someField).isNotNull();
+
+ List<Integer> view = makeMutableRepeatedFieldView(builder, someField);
+ assertThat(builder.build().getSomeFieldList()).isEmpty();
+
+ assertThat(view.add(1)).isTrue();
+ assertThat(view.get(0)).isEqualTo(1);
+ assertThat(view).hasSize(1);
+ assertThat(builder.build().getSomeFieldList()).containsExactly(1).inOrder();
+ assertThrows(IndexOutOfBoundsException.class, () -> view.get(1));
+
+ assertThat(view.add(2)).isTrue();
+ assertThat(view.add(3)).isTrue();
+ assertThat(view).hasSize(3);
+ assertThat(builder.build().getSomeFieldList()).containsExactly(1, 2, 3).inOrder();
+ assertThrows(IndexOutOfBoundsException.class, () -> view.get(3));
+
+ assertThat(view.set(1, 4)).isEqualTo(2);
+ assertThat(view).hasSize(3);
+ assertThat(builder.build().getSomeFieldList()).containsExactly(1, 4, 3).inOrder();
+
+ assertThat(view.set(1, 5)).isEqualTo(4);
+ assertThat(view).hasSize(3);
+ assertThat(builder.build().getSomeFieldList()).containsExactly(1, 5, 3).inOrder();
+
+ assertThat(view.remove(1)).isEqualTo(5);
+ assertThat(view).hasSize(2);
+ assertThat(builder.build().getSomeFieldList()).containsExactly(1, 3).inOrder();
+
+ assertThrows(IndexOutOfBoundsException.class, () -> view.remove(-1));
+ assertThrows(IndexOutOfBoundsException.class, () -> view.remove(2));
+
+ assertThat(view.addAll(1, Collections.emptyList())).isFalse();
+ assertThat(view).hasSize(2);
+ assertThat(builder.build().getSomeFieldList()).containsExactly(1, 3).inOrder();
+
+ assertThat(view.addAll(1, Arrays.asList(6, 7, 8))).isTrue();
+ assertThat(view).hasSize(5);
+ assertThat(builder.build().getSomeFieldList()).containsExactly(1, 6, 7, 8, 3).inOrder();
+
+ view.subList(2, 4).clear();
+ assertThat(view).hasSize(3);
+ assertThat(builder.build().getSomeFieldList()).containsExactly(1, 6, 3).inOrder();
+
+ assertThat(view.addAll(3, Arrays.asList(9, 10))).isTrue();
+ assertThat(view).hasSize(5);
+ assertThat(builder.build().getSomeFieldList()).containsExactly(1, 6, 3, 9, 10).inOrder();
+
+ view.clear();
+ assertThat(view).hasSize(0);
+ assertThat(builder.build().getSomeFieldList()).isEmpty();
+ }
+}
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
new file mode 100644
index 00000000..9492bcec
--- /dev/null
+++ b/src/test/java/com/code_intelligence/jazzer/mutation/mutator/proto/BuilderMutatorProto2Test.java
@@ -0,0 +1,447 @@
+/*
+ * 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.proto;
+
+import static com.code_intelligence.jazzer.mutation.support.TestSupport.mockPseudoRandom;
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.extensions.proto.ProtoTruth.assertThat;
+
+import com.code_intelligence.jazzer.mutation.annotation.NotNull;
+import com.code_intelligence.jazzer.mutation.api.ChainedMutatorFactory;
+import com.code_intelligence.jazzer.mutation.api.InPlaceMutator;
+import com.code_intelligence.jazzer.mutation.api.MutatorFactory;
+import com.code_intelligence.jazzer.mutation.mutator.collection.CollectionMutators;
+import com.code_intelligence.jazzer.mutation.mutator.lang.LangMutators;
+import com.code_intelligence.jazzer.mutation.support.TestSupport.MockPseudoRandom;
+import com.code_intelligence.jazzer.mutation.support.TypeHolder;
+import com.code_intelligence.jazzer.protobuf.Proto2.MessageField2;
+import com.code_intelligence.jazzer.protobuf.Proto2.OneOfField2;
+import com.code_intelligence.jazzer.protobuf.Proto2.PrimitiveField2;
+import com.code_intelligence.jazzer.protobuf.Proto2.RecursiveMessageField2;
+import com.code_intelligence.jazzer.protobuf.Proto2.RepeatedMessageField2;
+import com.code_intelligence.jazzer.protobuf.Proto2.RepeatedOptionalMessageField2;
+import com.code_intelligence.jazzer.protobuf.Proto2.RepeatedPrimitiveField2;
+import com.code_intelligence.jazzer.protobuf.Proto2.RequiredPrimitiveField2;
+import org.junit.jupiter.api.Test;
+
+class BuilderMutatorProto2Test {
+ private static final MutatorFactory FACTORY = new ChainedMutatorFactory(
+ LangMutators.newFactory(), CollectionMutators.newFactory(), ProtoMutators.newFactory());
+
+ @Test
+ void testPrimitiveField() {
+ InPlaceMutator<PrimitiveField2.Builder> mutator =
+ (InPlaceMutator<PrimitiveField2.Builder>) FACTORY.createInPlaceOrThrow(
+ new TypeHolder<PrimitiveField2.@NotNull Builder>() {}.annotatedType());
+ assertThat(mutator.toString()).isEqualTo("{Builder.Nullable<Boolean>}");
+
+ PrimitiveField2.Builder builder = PrimitiveField2.newBuilder();
+
+ try (MockPseudoRandom prng = mockPseudoRandom(
+ // present
+ false,
+ // boolean
+ false)) {
+ mutator.initInPlace(builder, prng);
+ }
+ assertThat(builder.hasSomeField()).isTrue();
+ assertThat(builder.getSomeField()).isFalse();
+
+ try (MockPseudoRandom prng = mockPseudoRandom(
+ // present
+ false,
+ // boolean
+ true)) {
+ mutator.initInPlace(builder, prng);
+ }
+ assertThat(builder.hasSomeField()).isTrue();
+ assertThat(builder.getSomeField()).isTrue();
+
+ try (MockPseudoRandom prng = mockPseudoRandom(
+ // mutate first field
+ 0,
+ // mutate as non-null Boolean
+ false)) {
+ mutator.mutateInPlace(builder, prng);
+ }
+ assertThat(builder.hasSomeField()).isTrue();
+ assertThat(builder.getSomeField()).isFalse();
+
+ try (MockPseudoRandom prng = mockPseudoRandom(
+ // not present
+ true)) {
+ mutator.initInPlace(builder, prng);
+ }
+ assertThat(builder.hasSomeField()).isFalse();
+ assertThat(builder.getSomeField()).isFalse();
+ }
+
+ @Test
+ void testRequiredPrimitiveField() {
+ InPlaceMutator<RequiredPrimitiveField2.Builder> mutator =
+ (InPlaceMutator<RequiredPrimitiveField2.Builder>) FACTORY.createInPlaceOrThrow(
+ new TypeHolder<RequiredPrimitiveField2.@NotNull Builder>() {}.annotatedType());
+ assertThat(mutator.toString()).isEqualTo("{Builder.Boolean}");
+
+ RequiredPrimitiveField2.Builder builder = RequiredPrimitiveField2.newBuilder();
+
+ try (MockPseudoRandom prng = mockPseudoRandom(true)) {
+ mutator.initInPlace(builder, prng);
+ }
+ assertThat(builder.getSomeField()).isTrue();
+
+ try (MockPseudoRandom prng = mockPseudoRandom(/* mutate first field */ 0)) {
+ mutator.mutateInPlace(builder, prng);
+ }
+ assertThat(builder.getSomeField()).isFalse();
+ }
+
+ @Test
+ void testRepeatedPrimitiveField() {
+ InPlaceMutator<RepeatedPrimitiveField2.Builder> mutator =
+ (InPlaceMutator<RepeatedPrimitiveField2.Builder>) FACTORY.createInPlaceOrThrow(
+ new TypeHolder<RepeatedPrimitiveField2.@NotNull Builder>() {}.annotatedType());
+ assertThat(mutator.toString()).isEqualTo("{Builder via List<Boolean>}");
+
+ RepeatedPrimitiveField2.Builder builder = RepeatedPrimitiveField2.newBuilder();
+
+ try (MockPseudoRandom prng = mockPseudoRandom(
+ // list size 1
+ 1,
+ // boolean,
+ true)) {
+ mutator.initInPlace(builder, prng);
+ }
+ assertThat(builder.getSomeFieldList()).containsExactly(true).inOrder();
+
+ try (MockPseudoRandom prng = mockPseudoRandom(
+ // mutate first field
+ 0,
+ // 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);
+ }
+ assertThat(builder.getSomeFieldList()).containsExactly(true, true).inOrder();
+
+ try (MockPseudoRandom prng = mockPseudoRandom(
+ // mutate first field
+ 0,
+ // 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 =
+ (InPlaceMutator<MessageField2.Builder>) FACTORY.createInPlaceOrThrow(
+ new TypeHolder<MessageField2.@NotNull Builder>() {}.annotatedType());
+ assertThat(mutator.toString()).isEqualTo("{Builder.Nullable<{Builder.Boolean} -> Message>}");
+
+ MessageField2.Builder builder = MessageField2.newBuilder();
+
+ try (MockPseudoRandom prng = mockPseudoRandom(
+ // init submessage
+ false,
+ // boolean submessage field
+ true)) {
+ mutator.initInPlace(builder, prng);
+ }
+
+ assertThat(builder.getMessageField())
+ .isEqualTo(RequiredPrimitiveField2.newBuilder().setSomeField(true).build());
+ assertThat(builder.hasMessageField()).isTrue();
+
+ try (MockPseudoRandom prng = mockPseudoRandom(
+ // mutate first field
+ 0,
+ // mutate submessage as non-null
+ false,
+ // mutate first field
+ 0)) {
+ mutator.mutateInPlace(builder, prng);
+ }
+ assertThat(builder.getMessageField())
+ .isEqualTo(RequiredPrimitiveField2.newBuilder().setSomeField(false).build());
+ assertThat(builder.hasMessageField()).isTrue();
+
+ try (MockPseudoRandom prng = mockPseudoRandom(
+ // mutate first field
+ 0,
+ // mutate submessage to null
+ true)) {
+ mutator.mutateInPlace(builder, prng);
+ }
+ assertThat(builder.hasMessageField()).isFalse();
+ }
+
+ @Test
+ void testRepeatedOptionalMessageField() {
+ InPlaceMutator<RepeatedOptionalMessageField2.Builder> mutator =
+ (InPlaceMutator<RepeatedOptionalMessageField2.Builder>) FACTORY.createInPlaceOrThrow(
+ new TypeHolder<RepeatedOptionalMessageField2.@NotNull Builder>() {}.annotatedType());
+ assertThat(mutator.toString())
+ .isEqualTo("{Builder via List<{Builder.Nullable<Boolean>} -> Message>}");
+
+ RepeatedOptionalMessageField2.Builder builder = RepeatedOptionalMessageField2.newBuilder();
+
+ try (MockPseudoRandom prng = mockPseudoRandom(
+ // list size 1
+ 1,
+ // boolean
+ true)) {
+ mutator.initInPlace(builder, prng);
+ }
+ assertThat(builder.getMessageFieldList().toString()).isEqualTo("[]");
+
+ try (MockPseudoRandom prng = mockPseudoRandom(
+ // mutate first field
+ 0,
+ // 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);
+ }
+ assertThat(builder.getMessageFieldList().size()).isEqualTo(2);
+ }
+
+ @Test
+ void testRepeatedRequiredMessageField() {
+ InPlaceMutator<RepeatedMessageField2.Builder> mutator =
+ (InPlaceMutator<RepeatedMessageField2.Builder>) FACTORY.createInPlaceOrThrow(
+ new TypeHolder<RepeatedMessageField2.@NotNull Builder>() {}.annotatedType());
+ assertThat(mutator.toString()).isEqualTo("{Builder via List<{Builder.Boolean} -> Message>}");
+
+ RepeatedMessageField2.Builder builder = RepeatedMessageField2.newBuilder();
+
+ try (MockPseudoRandom prng = mockPseudoRandom(
+ // list size 1
+ 1,
+ // boolean
+ true)) {
+ mutator.initInPlace(builder, prng);
+ }
+ assertThat(builder.getMessageFieldList())
+ .containsExactly(RequiredPrimitiveField2.newBuilder().setSomeField(true).build())
+ .inOrder();
+
+ try (MockPseudoRandom prng = mockPseudoRandom(
+ // mutate first field
+ 0,
+ // 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);
+ }
+ assertThat(builder.getMessageFieldList())
+ .containsExactly(RequiredPrimitiveField2.newBuilder().setSomeField(true).build(),
+ RequiredPrimitiveField2.newBuilder().setSomeField(true).build())
+ .inOrder();
+
+ try (MockPseudoRandom prng = mockPseudoRandom(
+ // mutate first field
+ 0,
+ // change an entry
+ 2,
+ // mutate a single element
+ 1,
+ // mutate the second element,
+ 1,
+ // mutate the first element
+ 0)) {
+ mutator.mutateInPlace(builder, prng);
+ }
+ assertThat(builder.getMessageFieldList())
+ .containsExactly(RequiredPrimitiveField2.newBuilder().setSomeField(true).build(),
+ RequiredPrimitiveField2.newBuilder().setSomeField(false).build())
+ .inOrder();
+ }
+
+ @Test
+ void testRecursiveMessageField() {
+ InPlaceMutator<RecursiveMessageField2.Builder> mutator =
+ (InPlaceMutator<RecursiveMessageField2.Builder>) FACTORY.createInPlaceOrThrow(
+ new TypeHolder<RecursiveMessageField2.@NotNull Builder>() {}.annotatedType());
+ assertThat(mutator.toString())
+ .isEqualTo("{Builder.Boolean, WithoutInit(Builder.Nullable<(cycle) -> Message>)}");
+ RecursiveMessageField2.Builder builder = RecursiveMessageField2.newBuilder();
+
+ try (MockPseudoRandom prng = mockPseudoRandom(
+ // boolean
+ true)) {
+ mutator.initInPlace(builder, prng);
+ }
+
+ assertThat(builder.build())
+ .isEqualTo(RecursiveMessageField2.newBuilder().setSomeField(true).build());
+ assertThat(builder.hasMessageField()).isFalse();
+
+ try (MockPseudoRandom prng = mockPseudoRandom(
+ // mutate message field (causes init to non-null)
+ 1,
+ // bool field in message field
+ false)) {
+ mutator.mutateInPlace(builder, prng);
+ }
+ // Nested message field *is* set explicitly and implicitly equal to the default
+ // instance.
+ assertThat(builder.build())
+ .isEqualTo(RecursiveMessageField2.newBuilder()
+ .setSomeField(true)
+ .setMessageField(RecursiveMessageField2.newBuilder().setSomeField(false))
+ .build());
+ assertThat(builder.hasMessageField()).isTrue();
+ assertThat(builder.getMessageField().hasMessageField()).isFalse();
+
+ try (MockPseudoRandom prng = mockPseudoRandom(
+ // mutate message field
+ 1,
+ // message field as not null
+ false,
+ // mutate message field
+ 1,
+ // nested boolean,
+ true)) {
+ mutator.mutateInPlace(builder, prng);
+ }
+ assertThat(builder.build())
+ .isEqualTo(RecursiveMessageField2.newBuilder()
+ .setSomeField(true)
+ .setMessageField(
+ RecursiveMessageField2.newBuilder().setSomeField(false).setMessageField(
+ RecursiveMessageField2.newBuilder().setSomeField(true)))
+ .build());
+ assertThat(builder.hasMessageField()).isTrue();
+ assertThat(builder.getMessageField().hasMessageField()).isTrue();
+ assertThat(builder.getMessageField().getMessageField().hasMessageField()).isFalse();
+ }
+
+ @Test
+ void testOneOfField2() {
+ InPlaceMutator<OneOfField2.Builder> mutator =
+ (InPlaceMutator<OneOfField2.Builder>) FACTORY.createInPlaceOrThrow(
+ new TypeHolder<OneOfField2.@NotNull Builder>() {}.annotatedType());
+ assertThat(mutator.toString())
+ .isEqualTo(
+ "{Builder.Boolean, Builder.Nullable<Boolean>, Builder.Nullable<Boolean> | Builder.Nullable<{Builder.Boolean} -> Message>}");
+ OneOfField2.Builder builder = OneOfField2.newBuilder();
+
+ try (MockPseudoRandom prng = mockPseudoRandom(
+ // other_field
+ true,
+ // yet_another_field
+ true,
+ // oneof: first field
+ 0,
+ // bool_field present
+ false,
+ // bool_field
+ true)) {
+ mutator.initInPlace(builder, prng);
+ }
+ assertThat(builder.build())
+ .isEqualTo(OneOfField2.newBuilder().setOtherField(true).setBoolField(true).build());
+ assertThat(builder.build().hasBoolField()).isTrue();
+
+ try (MockPseudoRandom prng = mockPseudoRandom(
+ // mutate oneof
+ 2,
+ // preserve oneof state
+ false,
+ // mutate bool_field as non-null
+ false)) {
+ mutator.mutateInPlace(builder, prng);
+ }
+ assertThat(builder.build())
+ .isEqualTo(OneOfField2.newBuilder().setOtherField(true).setBoolField(false).build());
+ assertThat(builder.build().hasBoolField()).isTrue();
+
+ try (MockPseudoRandom prng = mockPseudoRandom(
+ // mutate oneof
+ 2,
+ // switch oneof state
+ true,
+ // new oneof state
+ 1,
+ // init message_field as non-null
+ false,
+ // init some_field as true
+ true)) {
+ mutator.mutateInPlace(builder, prng);
+ }
+ assertThat(builder.build())
+ .isEqualTo(OneOfField2.newBuilder()
+ .setOtherField(true)
+ .setMessageField(RequiredPrimitiveField2.newBuilder().setSomeField(true))
+ .build());
+ assertThat(builder.build().hasMessageField()).isTrue();
+
+ try (MockPseudoRandom prng = mockPseudoRandom(
+ // mutate oneof
+ 2,
+ // preserve oneof state
+ false,
+ // mutate message_field as non-null
+ false,
+ // mutate some_field
+ 0)) {
+ mutator.mutateInPlace(builder, prng);
+ }
+ assertThat(builder.build())
+ .isEqualTo(OneOfField2.newBuilder()
+ .setOtherField(true)
+ .setMessageField(RequiredPrimitiveField2.newBuilder().setSomeField(false))
+ .build());
+ assertThat(builder.build().hasMessageField()).isTrue();
+
+ try (MockPseudoRandom prng = mockPseudoRandom(
+ // mutate oneof
+ 2,
+ // preserve oneof state
+ false,
+ // mutate message_field to null (and thus oneof state to indeterminate)
+ true)) {
+ mutator.mutateInPlace(builder, prng);
+ }
+ assertThat(builder.build()).isEqualTo(OneOfField2.newBuilder().setOtherField(true).build());
+ assertThat(builder.build().hasMessageField()).isFalse();
+ }
+}
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
new file mode 100644
index 00000000..ff298540
--- /dev/null
+++ b/src/test/java/com/code_intelligence/jazzer/mutation/mutator/proto/BuilderMutatorProto3Test.java
@@ -0,0 +1,603 @@
+/*
+ * 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.proto;
+
+import static com.code_intelligence.jazzer.mutation.support.TestSupport.mockPseudoRandom;
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.extensions.proto.ProtoTruth.assertThat;
+
+import com.code_intelligence.jazzer.mutation.annotation.NotNull;
+import com.code_intelligence.jazzer.mutation.annotation.proto.AnySource;
+import com.code_intelligence.jazzer.mutation.api.ChainedMutatorFactory;
+import com.code_intelligence.jazzer.mutation.api.InPlaceMutator;
+import com.code_intelligence.jazzer.mutation.api.MutatorFactory;
+import com.code_intelligence.jazzer.mutation.mutator.collection.CollectionMutators;
+import com.code_intelligence.jazzer.mutation.mutator.lang.LangMutators;
+import com.code_intelligence.jazzer.mutation.support.TestSupport.MockPseudoRandom;
+import com.code_intelligence.jazzer.mutation.support.TypeHolder;
+import com.code_intelligence.jazzer.protobuf.Proto3.AnyField3;
+import com.code_intelligence.jazzer.protobuf.Proto3.AnyField3.Builder;
+import com.code_intelligence.jazzer.protobuf.Proto3.EmptyMessage3;
+import com.code_intelligence.jazzer.protobuf.Proto3.EnumField3;
+import com.code_intelligence.jazzer.protobuf.Proto3.EnumField3.TestEnum;
+import com.code_intelligence.jazzer.protobuf.Proto3.EnumFieldOne3;
+import com.code_intelligence.jazzer.protobuf.Proto3.EnumFieldOne3.TestEnumOne;
+import com.code_intelligence.jazzer.protobuf.Proto3.EnumFieldOutside3;
+import com.code_intelligence.jazzer.protobuf.Proto3.EnumFieldRepeated3;
+import com.code_intelligence.jazzer.protobuf.Proto3.EnumFieldRepeated3.TestEnumRepeated;
+import com.code_intelligence.jazzer.protobuf.Proto3.MessageField3;
+import com.code_intelligence.jazzer.protobuf.Proto3.OneOfField3;
+import com.code_intelligence.jazzer.protobuf.Proto3.OptionalPrimitiveField3;
+import com.code_intelligence.jazzer.protobuf.Proto3.PrimitiveField3;
+import com.code_intelligence.jazzer.protobuf.Proto3.RecursiveMessageField3;
+import com.code_intelligence.jazzer.protobuf.Proto3.RepeatedMessageField3;
+import com.code_intelligence.jazzer.protobuf.Proto3.RepeatedPrimitiveField3;
+import com.code_intelligence.jazzer.protobuf.Proto3.TestEnumOutside3;
+import com.google.protobuf.InvalidProtocolBufferException;
+import java.util.Arrays;
+import org.junit.jupiter.api.Test;
+
+class BuilderMutatorProto3Test {
+ private static final MutatorFactory FACTORY = new ChainedMutatorFactory(
+ LangMutators.newFactory(), CollectionMutators.newFactory(), ProtoMutators.newFactory());
+
+ @Test
+ void testPrimitiveField() {
+ InPlaceMutator<PrimitiveField3.Builder> mutator =
+ (InPlaceMutator<PrimitiveField3.Builder>) FACTORY.createInPlaceOrThrow(
+ new TypeHolder<PrimitiveField3.@NotNull Builder>() {}.annotatedType());
+ assertThat(mutator.toString()).isEqualTo("{Builder.Boolean}");
+
+ PrimitiveField3.Builder builder = PrimitiveField3.newBuilder();
+
+ try (MockPseudoRandom prng = mockPseudoRandom(true)) {
+ mutator.initInPlace(builder, prng);
+ }
+ assertThat(builder.getSomeField()).isTrue();
+
+ try (MockPseudoRandom prng = mockPseudoRandom(/* mutate first field */ 0)) {
+ mutator.mutateInPlace(builder, prng);
+ }
+ assertThat(builder.getSomeField()).isFalse();
+ }
+
+ @Test
+ void testEnumField() {
+ InPlaceMutator<EnumField3.Builder> mutator =
+ (InPlaceMutator<EnumField3.Builder>) FACTORY.createInPlaceOrThrow(
+ new TypeHolder<EnumField3.@NotNull Builder>() {}.annotatedType());
+ assertThat(mutator.toString()).isEqualTo("{Builder.Enum<TestEnum>}");
+ EnumField3.Builder builder = EnumField3.newBuilder();
+ try (MockPseudoRandom prng = mockPseudoRandom(0)) {
+ mutator.initInPlace(builder, prng);
+ }
+ assertThat(builder.getSomeField()).isEqualTo(TestEnum.VAL1);
+ try (MockPseudoRandom prng = mockPseudoRandom(0, 1)) {
+ mutator.mutateInPlace(builder, prng);
+ }
+ assertThat(builder.getSomeField()).isEqualTo(TestEnum.VAL2);
+ }
+
+ @Test
+ void testEnumFieldOutside() {
+ InPlaceMutator<EnumFieldOutside3.Builder> mutator =
+ (InPlaceMutator<EnumFieldOutside3.Builder>) FACTORY.createInPlaceOrThrow(
+ new TypeHolder<EnumFieldOutside3.@NotNull Builder>() {}.annotatedType());
+ assertThat(mutator.toString()).isEqualTo("{Builder.Enum<TestEnumOutside3>}");
+ EnumFieldOutside3.Builder builder = EnumFieldOutside3.newBuilder();
+ try (MockPseudoRandom prng = mockPseudoRandom(0)) {
+ mutator.initInPlace(builder, prng);
+ }
+ assertThat(builder.getSomeField()).isEqualTo(TestEnumOutside3.VAL1);
+ try (MockPseudoRandom prng = mockPseudoRandom(0, 2)) {
+ mutator.mutateInPlace(builder, prng);
+ }
+ assertThat(builder.getSomeField()).isEqualTo(TestEnumOutside3.VAL3);
+ }
+
+ @Test
+ void testEnumFieldWithOneValue() {
+ InPlaceMutator<EnumFieldOne3.Builder> mutator =
+ (InPlaceMutator<EnumFieldOne3.Builder>) FACTORY.createInPlaceOrThrow(
+ new TypeHolder<EnumFieldOne3.@NotNull Builder>() {}.annotatedType());
+ assertThat(mutator.toString()).isEqualTo("{Builder.FixedValue(ONE)}");
+ EnumFieldOne3.Builder builder = EnumFieldOne3.newBuilder();
+ try (MockPseudoRandom prng = mockPseudoRandom()) {
+ mutator.initInPlace(builder, prng);
+ }
+ assertThat(builder.getSomeField()).isEqualTo(TestEnumOne.ONE);
+ try (MockPseudoRandom prng = mockPseudoRandom(0)) {
+ mutator.mutateInPlace(builder, prng);
+ }
+ assertThat(builder.getSomeField()).isEqualTo(TestEnumOne.ONE);
+ }
+
+ @Test
+ void testRepeatedEnumField() {
+ InPlaceMutator<EnumFieldRepeated3.Builder> mutator =
+ (InPlaceMutator<EnumFieldRepeated3.Builder>) FACTORY.createInPlaceOrThrow(
+ new TypeHolder<EnumFieldRepeated3.@NotNull Builder>() {}.annotatedType());
+ assertThat(mutator.toString()).isEqualTo("{Builder via List<Enum<TestEnumRepeated>>}");
+ EnumFieldRepeated3.Builder builder = EnumFieldRepeated3.newBuilder();
+ try (MockPseudoRandom prng = mockPseudoRandom(
+ // list size
+ 1, // Only possible start value
+ // enum values
+ 2)) {
+ mutator.initInPlace(builder, prng);
+ }
+ assertThat(builder.getSomeFieldList()).isEqualTo(Arrays.asList(TestEnumRepeated.VAL2));
+
+ try (MockPseudoRandom prng = mockPseudoRandom(
+ // mutate first field
+ 0,
+ // change an entry
+ 2,
+ // mutate a single element
+ 1,
+ // mutate to first enum field
+ 0,
+ // mutate to first enum value
+ 1)) {
+ mutator.mutateInPlace(builder, prng);
+ }
+ assertThat(builder.getSomeFieldList()).isEqualTo(Arrays.asList(TestEnumRepeated.VAL1));
+ }
+
+ @Test
+ void testOptionalPrimitiveField() {
+ InPlaceMutator<OptionalPrimitiveField3.Builder> mutator =
+ (InPlaceMutator<OptionalPrimitiveField3.Builder>) FACTORY.createInPlaceOrThrow(
+ new TypeHolder<OptionalPrimitiveField3.@NotNull Builder>() {}.annotatedType());
+ assertThat(mutator.toString()).isEqualTo("{Builder.Nullable<Boolean>}");
+
+ OptionalPrimitiveField3.Builder builder = OptionalPrimitiveField3.newBuilder();
+
+ try (MockPseudoRandom prng = mockPseudoRandom(
+ // present
+ false,
+ // boolean
+ false)) {
+ mutator.initInPlace(builder, prng);
+ }
+ assertThat(builder.hasSomeField()).isTrue();
+ assertThat(builder.getSomeField()).isFalse();
+
+ try (MockPseudoRandom prng = mockPseudoRandom(
+ // present
+ false,
+ // boolean
+ true)) {
+ mutator.initInPlace(builder, prng);
+ }
+ assertThat(builder.hasSomeField()).isTrue();
+ assertThat(builder.getSomeField()).isTrue();
+
+ try (MockPseudoRandom prng = mockPseudoRandom(
+ // mutate first field
+ 0,
+ // mutate as non-null Boolean
+ false)) {
+ mutator.mutateInPlace(builder, prng);
+ }
+ assertThat(builder.hasSomeField()).isTrue();
+ assertThat(builder.getSomeField()).isFalse();
+
+ try (MockPseudoRandom prng = mockPseudoRandom(
+ // not present
+ true)) {
+ mutator.initInPlace(builder, prng);
+ }
+ assertThat(builder.hasSomeField()).isFalse();
+ assertThat(builder.getSomeField()).isFalse();
+ }
+
+ @Test
+ void testRepeatedPrimitiveField() {
+ InPlaceMutator<RepeatedPrimitiveField3.Builder> mutator =
+ (InPlaceMutator<RepeatedPrimitiveField3.Builder>) FACTORY.createInPlaceOrThrow(
+ new TypeHolder<RepeatedPrimitiveField3.@NotNull Builder>() {}.annotatedType());
+ assertThat(mutator.toString()).isEqualTo("{Builder via List<Boolean>}");
+
+ RepeatedPrimitiveField3.Builder builder = RepeatedPrimitiveField3.newBuilder();
+
+ try (MockPseudoRandom prng = mockPseudoRandom(
+ // list size 1
+ 1,
+ // boolean,
+ true)) {
+ mutator.initInPlace(builder, prng);
+ }
+ assertThat(builder.getSomeFieldList()).containsExactly(true).inOrder();
+
+ try (MockPseudoRandom prng = mockPseudoRandom(
+ // mutate first field
+ 0,
+ // 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);
+ }
+ assertThat(builder.getSomeFieldList()).containsExactly(true, true).inOrder();
+
+ try (MockPseudoRandom prng = mockPseudoRandom(
+ // mutate first field
+ 0,
+ // 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<MessageField3.Builder> mutator =
+ (InPlaceMutator<MessageField3.Builder>) FACTORY.createInPlaceOrThrow(
+ new TypeHolder<MessageField3.@NotNull Builder>() {}.annotatedType());
+ assertThat(mutator.toString()).isEqualTo("{Builder.Nullable<{Builder.Boolean} -> Message>}");
+
+ MessageField3.Builder builder = MessageField3.newBuilder();
+
+ try (MockPseudoRandom prng = mockPseudoRandom(
+ // init submessage
+ false,
+ // boolean submessage field
+ true)) {
+ mutator.initInPlace(builder, prng);
+ }
+ assertThat(builder.getMessageField())
+ .isEqualTo(PrimitiveField3.newBuilder().setSomeField(true).build());
+ assertThat(builder.hasMessageField()).isTrue();
+
+ try (MockPseudoRandom prng = mockPseudoRandom(
+ // mutate first field
+ 0,
+ // mutate submessage as non-null
+ false,
+ // mutate first field
+ 0)) {
+ mutator.mutateInPlace(builder, prng);
+ }
+ assertThat(builder.getMessageField())
+ .isEqualTo(PrimitiveField3.newBuilder().setSomeField(false).build());
+ assertThat(builder.hasMessageField()).isTrue();
+
+ try (MockPseudoRandom prng = mockPseudoRandom(
+ // mutate first field
+ 0,
+ // mutate submessage to null
+ true)) {
+ mutator.mutateInPlace(builder, prng);
+ }
+ assertThat(builder.hasMessageField()).isFalse();
+ }
+
+ @Test
+ void testRepeatedMessageField() {
+ InPlaceMutator<RepeatedMessageField3.Builder> mutator =
+ (InPlaceMutator<RepeatedMessageField3.Builder>) FACTORY.createInPlaceOrThrow(
+ new TypeHolder<RepeatedMessageField3.@NotNull Builder>() {}.annotatedType());
+ assertThat(mutator.toString()).isEqualTo("{Builder via List<{Builder.Boolean} -> Message>}");
+
+ RepeatedMessageField3.Builder builder = RepeatedMessageField3.newBuilder();
+
+ try (MockPseudoRandom prng = mockPseudoRandom(
+ // list size 1
+ 1,
+ // boolean
+ true)) {
+ mutator.initInPlace(builder, prng);
+ }
+ assertThat(builder.getMessageFieldList())
+ .containsExactly(PrimitiveField3.newBuilder().setSomeField(true).build())
+ .inOrder();
+
+ try (MockPseudoRandom prng = mockPseudoRandom(
+ // mutate first field
+ 0,
+ // 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);
+ }
+ assertThat(builder.getMessageFieldList())
+ .containsExactly(PrimitiveField3.newBuilder().setSomeField(true).build(),
+ PrimitiveField3.newBuilder().setSomeField(true).build())
+ .inOrder();
+
+ try (MockPseudoRandom prng = mockPseudoRandom(
+ // mutate first field
+ 0,
+ // change an entry
+ 2,
+ // mutate a single element
+ 1,
+ // mutate the second element,
+ 1,
+ // mutate the first element
+ 0)) {
+ mutator.mutateInPlace(builder, prng);
+ }
+ assertThat(builder.getMessageFieldList())
+ .containsExactly(PrimitiveField3.newBuilder().setSomeField(true).build(),
+ PrimitiveField3.newBuilder().setSomeField(false).build())
+ .inOrder();
+ }
+
+ @Test
+ void testRecursiveMessageField() {
+ InPlaceMutator<RecursiveMessageField3.Builder> mutator =
+ (InPlaceMutator<RecursiveMessageField3.Builder>) FACTORY.createInPlaceOrThrow(
+ new TypeHolder<RecursiveMessageField3.@NotNull Builder>() {}.annotatedType());
+ assertThat(mutator.toString())
+ .isEqualTo("{Builder.Boolean, WithoutInit(Builder.Nullable<(cycle) -> Message>)}");
+ RecursiveMessageField3.Builder builder = RecursiveMessageField3.newBuilder();
+
+ try (MockPseudoRandom prng = mockPseudoRandom(
+ // boolean
+ true)) {
+ mutator.initInPlace(builder, prng);
+ }
+
+ assertThat(builder.build())
+ .isEqualTo(RecursiveMessageField3.newBuilder().setSomeField(true).build());
+ assertThat(builder.hasMessageField()).isFalse();
+
+ try (MockPseudoRandom prng = mockPseudoRandom(
+ // mutate message field (causes init to non-null)
+ 1,
+ // bool field in message field
+ false)) {
+ mutator.mutateInPlace(builder, prng);
+ }
+ // Nested message field *is* set explicitly and implicitly equal to the default
+ // instance.
+ assertThat(builder.build())
+ .isEqualTo(RecursiveMessageField3.newBuilder()
+ .setSomeField(true)
+ .setMessageField(RecursiveMessageField3.newBuilder().setSomeField(false))
+ .build());
+ assertThat(builder.hasMessageField()).isTrue();
+ assertThat(builder.getMessageField().hasMessageField()).isFalse();
+
+ try (MockPseudoRandom prng = mockPseudoRandom(
+ // mutate message field
+ 1,
+ // message field as not null
+ false,
+ // mutate message field
+ 1,
+ // nested boolean,
+ true)) {
+ mutator.mutateInPlace(builder, prng);
+ }
+ assertThat(builder.build())
+ .isEqualTo(RecursiveMessageField3.newBuilder()
+ .setSomeField(true)
+ .setMessageField(
+ RecursiveMessageField3.newBuilder().setSomeField(false).setMessageField(
+ RecursiveMessageField3.newBuilder().setSomeField(true)))
+ .build());
+ assertThat(builder.hasMessageField()).isTrue();
+ assertThat(builder.getMessageField().hasMessageField()).isTrue();
+ assertThat(builder.getMessageField().getMessageField().hasMessageField()).isFalse();
+ }
+
+ @Test
+ void testOneOfField3() {
+ InPlaceMutator<OneOfField3.Builder> mutator =
+ (InPlaceMutator<OneOfField3.Builder>) FACTORY.createInPlaceOrThrow(
+ new TypeHolder<OneOfField3.@NotNull Builder>() {}.annotatedType());
+ assertThat(mutator.toString())
+ .isEqualTo(
+ "{Builder.Boolean, Builder.Boolean, Builder.Nullable<Boolean> | Builder.Nullable<{Builder.Boolean} -> Message>}");
+ OneOfField3.Builder builder = OneOfField3.newBuilder();
+
+ try (MockPseudoRandom prng = mockPseudoRandom(
+ // other_field
+ true,
+ // yet_another_field
+ true,
+ // oneof: first field
+ 0,
+ // bool_field present
+ false,
+ // bool_field
+ true)) {
+ mutator.initInPlace(builder, prng);
+ }
+ assertThat(builder.build())
+ .isEqualTo(OneOfField3.newBuilder()
+ .setOtherField(true)
+ .setBoolField(true)
+ .setYetAnotherField(true)
+ .build());
+ assertThat(builder.build().hasBoolField()).isTrue();
+
+ try (MockPseudoRandom prng = mockPseudoRandom(
+ // mutate oneof
+ 2,
+ // preserve oneof state
+ false,
+ // mutate bool_field as non-null
+ false)) {
+ mutator.mutateInPlace(builder, prng);
+ }
+ assertThat(builder.build())
+ .isEqualTo(OneOfField3.newBuilder()
+ .setOtherField(true)
+ .setBoolField(false)
+ .setYetAnotherField(true)
+ .build());
+ assertThat(builder.build().hasBoolField()).isTrue();
+
+ try (MockPseudoRandom prng = mockPseudoRandom(
+ // mutate oneof
+ 2,
+ // switch oneof state
+ true,
+ // new oneof state
+ 1,
+ // init message_field as non-null
+ false,
+ // init some_field as true
+ true)) {
+ mutator.mutateInPlace(builder, prng);
+ }
+ assertThat(builder.build())
+ .isEqualTo(OneOfField3.newBuilder()
+ .setOtherField(true)
+ .setMessageField(PrimitiveField3.newBuilder().setSomeField(true))
+ .setYetAnotherField(true)
+ .build());
+ assertThat(builder.build().hasMessageField()).isTrue();
+
+ try (MockPseudoRandom prng = mockPseudoRandom(
+ // mutate oneof
+ 2,
+ // preserve oneof state
+ false,
+ // mutate message_field as non-null
+ false,
+ // mutate some_field
+ 0)) {
+ mutator.mutateInPlace(builder, prng);
+ }
+ assertThat(builder.build())
+ .isEqualTo(OneOfField3.newBuilder()
+ .setOtherField(true)
+ .setMessageField(PrimitiveField3.newBuilder().setSomeField(false))
+ .setYetAnotherField(true)
+ .build());
+ assertThat(builder.build().hasMessageField()).isTrue();
+
+ try (MockPseudoRandom prng = mockPseudoRandom(
+ // mutate oneof
+ 2,
+ // preserve oneof state
+ false,
+ // mutate message_field to null (and thus oneof state to indeterminate)
+ true)) {
+ mutator.mutateInPlace(builder, prng);
+ }
+ assertThat(builder.build())
+ .isEqualTo(OneOfField3.newBuilder().setOtherField(true).setYetAnotherField(true).build());
+ assertThat(builder.build().hasMessageField()).isFalse();
+ }
+
+ @Test
+ void testEmptyMessage3() {
+ InPlaceMutator<EmptyMessage3.Builder> mutator =
+ (InPlaceMutator<EmptyMessage3.Builder>) FACTORY.createInPlaceOrThrow(
+ new TypeHolder<EmptyMessage3.@NotNull Builder>() {}.annotatedType());
+ assertThat(mutator.toString()).isEqualTo("{<empty>}");
+ EmptyMessage3.Builder builder = EmptyMessage3.newBuilder();
+
+ try (MockPseudoRandom prng = mockPseudoRandom()) {
+ mutator.initInPlace(builder, prng);
+ }
+ assertThat(builder.build()).isEqualTo(EmptyMessage3.getDefaultInstance());
+
+ try (MockPseudoRandom prng = mockPseudoRandom()) {
+ mutator.mutateInPlace(builder, prng);
+ }
+ assertThat(builder.build()).isEqualTo(EmptyMessage3.getDefaultInstance());
+ }
+
+ @Test
+ void testAnyField3() throws InvalidProtocolBufferException {
+ InPlaceMutator<AnyField3.Builder> mutator =
+ (InPlaceMutator<AnyField3.Builder>) FACTORY.createInPlaceOrThrow(
+ new TypeHolder<@NotNull @AnySource(
+ {PrimitiveField3.class, MessageField3.class}) Builder>() {
+ }.annotatedType());
+ assertThat(mutator.toString())
+ .isEqualTo(
+ "{Builder.Nullable<Builder.{Builder.Boolean} -> Message | Builder.{Builder.Nullable<(cycle) -> Message>} -> Message -> Message>}");
+ AnyField3.Builder builder = AnyField3.newBuilder();
+
+ try (MockPseudoRandom prng = mockPseudoRandom(
+ // initialize message field
+ false,
+ // PrimitiveField3
+ 0,
+ // boolean field
+ true)) {
+ mutator.initInPlace(builder, prng);
+ }
+ assertThat(builder.build().getSomeField().unpack(PrimitiveField3.class))
+ .isEqualTo(PrimitiveField3.newBuilder().setSomeField(true).build());
+
+ try (MockPseudoRandom prng = mockPseudoRandom(
+ // mutate Any field
+ 0,
+ // keep non-null message field
+ false,
+ // keep Any state,
+ false,
+ // mutate boolean field
+ 0)) {
+ mutator.mutateInPlace(builder, prng);
+ }
+ assertThat(builder.build().getSomeField().unpack(PrimitiveField3.class))
+ .isEqualTo(PrimitiveField3.newBuilder().setSomeField(false).build());
+
+ try (MockPseudoRandom prng = mockPseudoRandom(
+ // mutate Any field
+ 0,
+ // keep non-null message field
+ false,
+ // switch Any state
+ true,
+ // new Any state
+ 1,
+ // non-null message
+ false,
+ // boolean field,
+ true)) {
+ mutator.mutateInPlace(builder, prng);
+ }
+ assertThat(builder.build().getSomeField().unpack(MessageField3.class))
+ .isEqualTo(MessageField3.newBuilder()
+ .setMessageField(PrimitiveField3.newBuilder().setSomeField(true))
+ .build());
+ }
+
+ @Test
+ void testAnyField3WithoutAnySourceDoesNotCrash() throws InvalidProtocolBufferException {
+ InPlaceMutator<AnyField3.Builder> mutator =
+ (InPlaceMutator<AnyField3.Builder>) FACTORY.createInPlaceOrThrow(
+ new TypeHolder<@NotNull Builder>() {}.annotatedType());
+ assertThat(mutator.toString())
+ .isEqualTo("{Builder.Nullable<{Builder.String, Builder.byte[] -> ByteString} -> Message>}");
+ }
+}
diff --git a/src/test/java/com/code_intelligence/jazzer/mutation/mutator/proto/MessageMutatorTest.java b/src/test/java/com/code_intelligence/jazzer/mutation/mutator/proto/MessageMutatorTest.java
new file mode 100644
index 00000000..b804c7fb
--- /dev/null
+++ b/src/test/java/com/code_intelligence/jazzer/mutation/mutator/proto/MessageMutatorTest.java
@@ -0,0 +1,92 @@
+/*
+ * 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.proto;
+
+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.api.ChainedMutatorFactory;
+import com.code_intelligence.jazzer.mutation.api.MutatorFactory;
+import com.code_intelligence.jazzer.mutation.api.SerializingMutator;
+import com.code_intelligence.jazzer.mutation.mutator.collection.CollectionMutators;
+import com.code_intelligence.jazzer.mutation.mutator.lang.LangMutators;
+import com.code_intelligence.jazzer.mutation.support.TestSupport.MockPseudoRandom;
+import com.code_intelligence.jazzer.mutation.support.TypeHolder;
+import com.code_intelligence.jazzer.protobuf.Proto2.ExtendedMessage2;
+import com.code_intelligence.jazzer.protobuf.Proto2.ExtendedSubmessage2;
+import com.code_intelligence.jazzer.protobuf.Proto2.OriginalMessage2;
+import com.code_intelligence.jazzer.protobuf.Proto2.OriginalSubmessage2;
+import com.code_intelligence.jazzer.protobuf.Proto3.PrimitiveField3;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import org.junit.jupiter.api.Test;
+
+class MessageMutatorTest {
+ private static final MutatorFactory FACTORY = new ChainedMutatorFactory(
+ LangMutators.newFactory(), CollectionMutators.newFactory(), ProtoMutators.newFactory());
+
+ @Test
+ void testSimpleMessage() {
+ SerializingMutator<PrimitiveField3> mutator = FACTORY.createOrThrow(PrimitiveField3.class);
+
+ PrimitiveField3 msg;
+
+ try (MockPseudoRandom prng = mockPseudoRandom(
+ // not null
+ false,
+ // boolean
+ false)) {
+ msg = mutator.init(prng);
+ assertThat(msg).isEqualTo(PrimitiveField3.getDefaultInstance());
+ }
+
+ try (MockPseudoRandom prng = mockPseudoRandom(
+ // not null,
+ false,
+ // mutate first field
+ 0)) {
+ msg = mutator.mutate(msg, prng);
+ assertThat(msg).isNotEqualTo(PrimitiveField3.getDefaultInstance());
+ }
+ }
+
+ @Test
+ void testIncompleteMessageWithRequiredFields() throws IOException {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ OriginalMessage2.newBuilder()
+ .setMessageField(OriginalSubmessage2.newBuilder().setNumericField(42).build())
+ .setBoolField(true)
+ .build()
+ .writeTo(out);
+ byte[] bytes = out.toByteArray();
+
+ SerializingMutator<ExtendedMessage2> mutator =
+ (SerializingMutator<ExtendedMessage2>) FACTORY.createOrThrow(
+ new TypeHolder<@NotNull ExtendedMessage2>() {}.annotatedType());
+ ExtendedMessage2 extendedMessage = mutator.readExclusive(new ByteArrayInputStream(bytes));
+ assertThat(extendedMessage)
+ .isEqualTo(ExtendedMessage2.newBuilder()
+ .setMessageField(
+ ExtendedSubmessage2.newBuilder().setNumericField(42).setMessageField(
+ OriginalSubmessage2.newBuilder().setNumericField(0).build()))
+ .setBoolField(true)
+ .setFloatField(0)
+ .build());
+ }
+}
diff --git a/src/test/java/com/code_intelligence/jazzer/mutation/mutator/proto/proto2.proto b/src/test/java/com/code_intelligence/jazzer/mutation/mutator/proto/proto2.proto
new file mode 100644
index 00000000..ea7c9999
--- /dev/null
+++ b/src/test/java/com/code_intelligence/jazzer/mutation/mutator/proto/proto2.proto
@@ -0,0 +1,161 @@
+// 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.
+
+syntax = "proto2";
+
+package com.code_intelligence.jazzer.protobuf;
+option java_package = "com.code_intelligence.jazzer.protobuf";
+
+message PrimitiveField2 {
+optional bool some_field = 1;
+}
+
+message RequiredPrimitiveField2 {
+required bool some_field = 1;
+}
+
+message RepeatedPrimitiveField2 {
+repeated bool some_field = 1;
+}
+
+message MessageField2 {
+optional RequiredPrimitiveField2 message_field = 1;
+}
+
+message RepeatedMessageField2 {
+repeated RequiredPrimitiveField2 message_field = 1;
+}
+
+message RepeatedOptionalMessageField2 {
+repeated PrimitiveField2 message_field = 1;
+}
+
+message RecursiveMessageField2 {
+required bool some_field = 1;
+optional RecursiveMessageField2 message_field = 2;
+}
+
+message RepeatedRecursiveMessageField2 {
+optional bool some_field = 1;
+repeated RepeatedRecursiveMessageField2 message_field = 2;
+}
+
+message OneOfField2 {
+required bool other_field = 4;
+oneof oneof_field {
+ bool bool_field = 7;
+ RequiredPrimitiveField2 message_field = 2;
+}
+optional bool yet_another_field = 1;
+}
+
+message IntegralField2 {
+optional uint32 some_field = 1;
+}
+
+message RepeatedIntegralField2 {
+repeated uint32 some_field = 1;
+}
+
+message BytesField2 {
+optional bytes some_field = 1;
+}
+
+message StringField2 {
+optional string some_field = 1;
+}
+
+message Parent {
+ optional Child child = 1;
+}
+
+message Child {
+ optional Parent parent = 1;
+}
+
+// Taken from
+// https://github.com/google/fuzztest/blob/c5fde4baee6134c84d4f2b618def9f60c7505151/fuzztest/internal/test_protobuf.proto#L24
+message TestSubProtobuf {
+ optional int32 subproto_i32 = 1;
+ repeated int32 subproto_rep_i32 = 2 [packed = true];
+ optional TestProtobuf parent = 3;
+}
+
+message TestProtobuf {
+ enum Enum {
+ Label1 = 0;
+ Label2 = 1;
+ Label3 = 2;
+ Label4 = 3;
+ Label5 = 4;
+ }
+
+ optional bool b = 1;
+ optional int32 i32 = 2;
+ optional uint32 u32 = 3;
+ optional int64 i64 = 4;
+ optional uint64 u64 = 5;
+ optional float f = 6;
+ optional double d = 7;
+ optional string str = 8;
+ optional Enum e = 9;
+ optional TestSubProtobuf subproto = 10;
+
+ repeated bool rep_b = 11;
+ repeated int32 rep_i32 = 12;
+ repeated uint32 rep_u32 = 13;
+ repeated int64 rep_i64 = 14;
+ repeated uint64 rep_u64 = 15;
+ repeated float rep_f = 16;
+ repeated double rep_d = 17;
+ repeated string rep_str = 18;
+ repeated Enum rep_e = 19;
+ repeated TestSubProtobuf rep_subproto = 20;
+
+ oneof oneof_field {
+ int32 oneof_i32 = 21;
+ int64 oneof_i64 = 22;
+ uint32 oneof_u32 = 24;
+ }
+
+ map<int32, int32> map_field = 25;
+
+ // Special cases
+ enum EnumOneLabel {
+ OnlyLabel = 17;
+ }
+ optional EnumOneLabel enum_one_label = 100;
+ message EmptyMessage {}
+ optional EmptyMessage empty_message = 101;
+}
+
+message OriginalSubmessage2 {
+ required int32 numeric_field = 1;
+}
+
+message OriginalMessage2 {
+ required OriginalSubmessage2 message_field = 1;
+ required bool bool_field = 2;
+}
+
+message ExtendedSubmessage2 {
+ required int32 numeric_field = 1;
+ required OriginalSubmessage2 message_field = 2;
+}
+
+message ExtendedMessage2 {
+ required ExtendedSubmessage2 message_field = 1;
+ required bool bool_field = 2;
+ required float float_field = 3;
+}
diff --git a/src/test/java/com/code_intelligence/jazzer/mutation/mutator/proto/proto3.proto b/src/test/java/com/code_intelligence/jazzer/mutation/mutator/proto/proto3.proto
new file mode 100644
index 00000000..7bd6ffeb
--- /dev/null
+++ b/src/test/java/com/code_intelligence/jazzer/mutation/mutator/proto/proto3.proto
@@ -0,0 +1,144 @@
+// 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.
+
+syntax = "proto3";
+
+import "google/protobuf/any.proto";
+
+option java_package = "com.code_intelligence.jazzer.protobuf";
+
+message PrimitiveField3 {
+ bool some_field = 1;
+}
+
+message OptionalPrimitiveField3 {
+ optional bool some_field = 1;
+}
+
+message RepeatedPrimitiveField3 {
+ repeated bool some_field = 1;
+}
+
+message MessageField3 {
+ PrimitiveField3 message_field = 1;
+}
+
+message RepeatedMessageField3 {
+ repeated PrimitiveField3 message_field = 1;
+}
+
+message RecursiveMessageField3 {
+ bool some_field = 1;
+ RecursiveMessageField3 message_field = 2;
+}
+
+message RepeatedRecursiveMessageField3 {
+ bool some_field = 1;
+ repeated RepeatedRecursiveMessageField3 message_field = 2;
+}
+
+message OneOfField3 {
+ bool other_field = 4;
+ oneof oneof_field {
+ bool bool_field = 7;
+ PrimitiveField3 message_field = 2;
+ }
+ bool yet_another_field = 1;
+}
+
+message IntegralField3 {
+ uint32 some_field = 1;
+}
+
+message RepeatedIntegralField3 {
+ repeated uint32 some_field = 1;
+}
+
+message BytesField3 {
+ bytes some_field = 1;
+}
+
+message StringField3 {
+ string some_field = 1;
+}
+
+message EnumField3 {
+ enum TestEnum {
+ VAL1 = 0;
+ VAL2 = 1;
+ }
+ TestEnum some_field = 1;
+}
+
+enum TestEnumOutside3 {
+ VAL1 = 0;
+ VAL2 = 1;
+ VAL3 = 3;
+}
+
+message EnumFieldOutside3 {
+ TestEnumOutside3 some_field = 1;
+}
+
+message EnumFieldOne3 {
+ enum TestEnumOne {
+ ONE = 0;
+ }
+ TestEnumOne some_field = 1;
+}
+
+message EnumFieldRepeated3 {
+ enum TestEnumRepeated {
+ UNASSIGNED = 0;
+ VAL1 = 1;
+ VAL2 = 2;
+ }
+ repeated TestEnumRepeated some_field = 1;
+}
+
+message MapField3 {
+ map<int32, string> some_field = 1;
+}
+
+message MessageMapField3 {
+ map<string, MapField3> some_field = 1;
+}
+
+message FloatField3 {
+ float some_field = 1;
+}
+
+message RepeatedFloatField3 {
+ repeated float some_field = 1;
+}
+
+message DoubleField3 {
+ double some_field = 1;
+}
+
+message RepeatedDoubleField3 {
+ repeated double some_field = 1;
+}
+
+message EmptyMessage3 {}
+
+message AnyField3 {
+ google.protobuf.Any some_field = 1;
+}
+
+message SingleOptionOneOfField3 {
+ oneof oneof_field {
+ bool bool_field = 1;
+ }
+}