diff options
Diffstat (limited to 'src/test/java/com/code_intelligence/jazzer/mutation/mutator/proto')
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; + } +} |