diff --git a/google3/third_party/java_src/protobuf/current/javatests/com/google/protobuf/utf8validation/lite.awk b/google3/third_party/java_src/protobuf/current/javatests/com/google/protobuf/utf8validation/lite.awk new file mode 100644 index 0000000000000..b22d965b6fd02 --- /dev/null +++ b/google3/third_party/java_src/protobuf/current/javatests/com/google/protobuf/utf8validation/lite.awk @@ -0,0 +1,25 @@ +# Remove code enclosed by "BEGIN FULL-RUNTIME" and "END FULL-RUNTIME" to +# create the lite-only version of a test file. + +BEGIN { + in_full_runtime = 0; +} + +/BEGIN FULL-RUNTIME/ { + in_full_runtime = 1; + next; +} + +/END FULL-RUNTIME/ { + in_full_runtime = 0; + next; +} + +in_full_runtime { + # Skip full runtime code path. + next; +} + +{ + print; +} diff --git a/java/core/src/test/java/com/google/protobuf/utf8validation/Utf8ValidationEdition2023DynamicMessageTest.java b/java/core/src/test/java/com/google/protobuf/utf8validation/Utf8ValidationEdition2023DynamicMessageTest.java new file mode 100644 index 0000000000000..767a91bac4709 --- /dev/null +++ b/java/core/src/test/java/com/google/protobuf/utf8validation/Utf8ValidationEdition2023DynamicMessageTest.java @@ -0,0 +1,414 @@ +package com.google.protobuf.utf8validation; + +import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertThrows; + +import com.google.protobuf.Descriptors.Descriptor; +import com.google.protobuf.Descriptors.FieldDescriptor; +import com.google.protobuf.DynamicMessage; +import com.google.protobuf.ExtensionRegistry; +import com.google.protobuf.InvalidProtocolBufferException; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class Utf8ValidationEdition2023DynamicMessageTest { + // edition: 2023 + // regular field + // validates: yes + @Test + public void testUnsetUnset_validates() throws Exception { + Descriptor descriptor = Utf8TestEditions2023.getDescriptor(); + byte[] serialized = + new byte[] { + 10, // tag for field 1 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + assertThrows( + InvalidProtocolBufferException.class, + () -> + DynamicMessage.parseFrom(descriptor, serialized, ExtensionRegistry.getEmptyRegistry())); + } + + // edition: 2023 + // regular field + // validates: yes + @Test + public void testUnsetDefault_validates() throws Exception { + Descriptor descriptor = Utf8TestEditions2023.getDescriptor(); + byte[] serialized = + new byte[] { + 18, // tag for field 2 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + assertThrows( + InvalidProtocolBufferException.class, + () -> + DynamicMessage.parseFrom(descriptor, serialized, ExtensionRegistry.getEmptyRegistry())); + } + + // edition: 2023 + // regular field + // validates: yes + @Test + public void testUnsetVerify_validates() throws Exception { + Descriptor descriptor = Utf8TestEditions2023.getDescriptor(); + byte[] serialized = + new byte[] { + 26, // tag for field 3 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + assertThrows( + InvalidProtocolBufferException.class, + () -> + DynamicMessage.parseFrom(descriptor, serialized, ExtensionRegistry.getEmptyRegistry())); + } + + // edition: 2023 + // regular field + // validates: yes + @Test + public void testVerifyUnset_validates() throws Exception { + Descriptor descriptor = Utf8TestEditions2023.getDescriptor(); + byte[] serialized = + new byte[] { + 34, // tag for field 4 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + assertThrows( + InvalidProtocolBufferException.class, + () -> + DynamicMessage.parseFrom(descriptor, serialized, ExtensionRegistry.getEmptyRegistry())); + } + + // edition: 2023 + // regular field + // validates: yes + @Test + public void testVerifyDefault_validates() throws Exception { + Descriptor descriptor = Utf8TestEditions2023.getDescriptor(); + byte[] serialized = + new byte[] { + 42, // tag for field 5 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + assertThrows( + InvalidProtocolBufferException.class, + () -> + DynamicMessage.parseFrom(descriptor, serialized, ExtensionRegistry.getEmptyRegistry())); + } + + // edition: 2023 + // regular field + // validates: yes + @Test + public void testVerifyVerify_validates() throws Exception { + Descriptor descriptor = Utf8TestEditions2023.getDescriptor(); + byte[] serialized = + new byte[] { + 50, // tag for field 6 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + assertThrows( + InvalidProtocolBufferException.class, + () -> + DynamicMessage.parseFrom(descriptor, serialized, ExtensionRegistry.getEmptyRegistry())); + } + + // edition: 2023 + // regular field + // validates: no + @Test + public void testNoneUnset_doesNotValidate() throws Exception { + Descriptor descriptor = Utf8TestEditions2023.getDescriptor(); + FieldDescriptor field = descriptor.findFieldByName("none_unset"); + byte[] serialized = + new byte[] { + 58, // tag for field 7 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + DynamicMessage msg = + DynamicMessage.parseFrom(descriptor, serialized, ExtensionRegistry.getEmptyRegistry()); + assertThat(msg.hasField(field)).isTrue(); + assertThat(msg.getField(field)).isEqualTo("\uFFFD\uFFFD"); + } + + // edition: 2023 + // regular field + // validates: no + @Test + public void testNoneDefault_doesNotValidate() throws Exception { + Descriptor descriptor = Utf8TestEditions2023.getDescriptor(); + FieldDescriptor field = descriptor.findFieldByName("none_default"); + byte[] serialized = + new byte[] { + 66, // tag for field 8 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + DynamicMessage msg = + DynamicMessage.parseFrom(descriptor, serialized, ExtensionRegistry.getEmptyRegistry()); + assertThat(msg.hasField(field)).isTrue(); + assertThat(msg.getField(field)).isEqualTo("\uFFFD\uFFFD"); + } + + // edition: 2023 + // regular field + // validates: yes + @Test + public void testNoneVerify_validates() throws Exception { + Descriptor descriptor = Utf8TestEditions2023.getDescriptor(); + byte[] serialized = + new byte[] { + 74, // tag for field 9 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + assertThrows( + InvalidProtocolBufferException.class, + () -> + DynamicMessage.parseFrom(descriptor, serialized, ExtensionRegistry.getEmptyRegistry())); + } + + // edition: 2023 + // extension + // validates: yes + @Test + public void testUnsetUnsetExt_validates() throws Exception { + Descriptor descriptor = Utf8TestEditions2023.getDescriptor(); + FieldDescriptor extField = descriptor.getFile().findExtensionByName("ext_unset_unset"); + ExtensionRegistry registry = ExtensionRegistry.newInstance(); + registry.add(extField); + + byte[] serialized = + new byte[] { + (byte) 0xAA, + (byte) 0x06, // tag for ext 101 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + assertThrows( + InvalidProtocolBufferException.class, + () -> DynamicMessage.parseFrom(descriptor, serialized, registry)); + } + + // edition: 2023 + // extension + // validates: yes + @Test + public void testUnsetDefaultExt_validates() throws Exception { + Descriptor descriptor = Utf8TestEditions2023.getDescriptor(); + FieldDescriptor extField = descriptor.getFile().findExtensionByName("ext_unset_default"); + ExtensionRegistry registry = ExtensionRegistry.newInstance(); + registry.add(extField); + + byte[] serialized = + new byte[] { + (byte) 0xB2, + (byte) 0x06, // tag for ext 102 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + assertThrows( + InvalidProtocolBufferException.class, + () -> DynamicMessage.parseFrom(descriptor, serialized, registry)); + } + + // edition: 2023 + // extension + // validates: yes + @Test + public void testUnsetVerifyExt_validates() throws Exception { + Descriptor descriptor = Utf8TestEditions2023.getDescriptor(); + FieldDescriptor extField = descriptor.getFile().findExtensionByName("ext_unset_verify"); + ExtensionRegistry registry = ExtensionRegistry.newInstance(); + registry.add(extField); + + byte[] serialized = + new byte[] { + (byte) 0xBA, + (byte) 0x06, // tag for ext 103 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + assertThrows( + InvalidProtocolBufferException.class, + () -> DynamicMessage.parseFrom(descriptor, serialized, registry)); + } + + // edition: 2023 + // extension + // validates: yes + @Test + public void testVerifyUnsetExt_validates() throws Exception { + Descriptor descriptor = Utf8TestEditions2023.getDescriptor(); + FieldDescriptor extField = descriptor.getFile().findExtensionByName("ext_verify_unset"); + ExtensionRegistry registry = ExtensionRegistry.newInstance(); + registry.add(extField); + + byte[] serialized = + new byte[] { + (byte) 0xC2, + (byte) 0x06, // tag for ext 104 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + assertThrows( + InvalidProtocolBufferException.class, + () -> DynamicMessage.parseFrom(descriptor, serialized, registry)); + } + + // edition: 2023 + // extension + // validates: yes + @Test + public void testVerifyDefaultExt_validates() throws Exception { + Descriptor descriptor = Utf8TestEditions2023.getDescriptor(); + FieldDescriptor extField = descriptor.getFile().findExtensionByName("ext_verify_default"); + ExtensionRegistry registry = ExtensionRegistry.newInstance(); + registry.add(extField); + + byte[] serialized = + new byte[] { + (byte) 0xCA, + (byte) 0x06, // tag for ext 105 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + assertThrows( + InvalidProtocolBufferException.class, + () -> DynamicMessage.parseFrom(descriptor, serialized, registry)); + } + + // edition: 2023 + // extension + // validates: yes + @Test + public void testVerifyVerifyExt_validates() throws Exception { + Descriptor descriptor = Utf8TestEditions2023.getDescriptor(); + FieldDescriptor extField = descriptor.getFile().findExtensionByName("ext_verify_verify"); + ExtensionRegistry registry = ExtensionRegistry.newInstance(); + registry.add(extField); + + byte[] serialized = + new byte[] { + (byte) 0xD2, + (byte) 0x06, // tag for ext 106 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + assertThrows( + InvalidProtocolBufferException.class, + () -> DynamicMessage.parseFrom(descriptor, serialized, registry)); + } + + // edition: 2023 + // extension + // validates: no + @Test + public void testNoneUnsetExt_doesNotValidate() throws Exception { + Descriptor descriptor = Utf8TestEditions2023.getDescriptor(); + FieldDescriptor extField = descriptor.getFile().findExtensionByName("ext_none_unset"); + ExtensionRegistry registry = ExtensionRegistry.newInstance(); + registry.add(extField); + + byte[] serialized = + new byte[] { + (byte) 0xDA, + (byte) 0x06, // tag for ext 107 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + DynamicMessage msg = DynamicMessage.parseFrom(descriptor, serialized, registry); + assertThat(msg.hasField(extField)).isTrue(); + assertThat(msg.getField(extField)).isEqualTo("\uFFFD\uFFFD"); + } + + // edition: 2023 + // extension + // validates: no + @Test + public void testNoneDefaultExt_doesNotValidate() throws Exception { + Descriptor descriptor = Utf8TestEditions2023.getDescriptor(); + FieldDescriptor extField = descriptor.getFile().findExtensionByName("ext_none_default"); + ExtensionRegistry registry = ExtensionRegistry.newInstance(); + registry.add(extField); + + byte[] serialized = + new byte[] { + (byte) 0xE2, + (byte) 0x06, // tag for ext 108 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + DynamicMessage msg = DynamicMessage.parseFrom(descriptor, serialized, registry); + assertThat(msg.hasField(extField)).isTrue(); + assertThat(msg.getField(extField)).isEqualTo("\uFFFD\uFFFD"); + } + + // edition: 2023 + // extension + // validates: yes + @Test + public void testNoneVerifyExt_validates() throws Exception { + Descriptor descriptor = Utf8TestEditions2023.getDescriptor(); + FieldDescriptor extField = descriptor.getFile().findExtensionByName("ext_none_verify"); + ExtensionRegistry registry = ExtensionRegistry.newInstance(); + registry.add(extField); + + byte[] serialized = + new byte[] { + (byte) 0xEA, + (byte) 0x06, // tag for ext 109 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + assertThrows( + InvalidProtocolBufferException.class, + () -> DynamicMessage.parseFrom(descriptor, serialized, registry)); + } +} diff --git a/java/core/src/test/java/com/google/protobuf/utf8validation/Utf8ValidationEdition2023GeneratedTest.java b/java/core/src/test/java/com/google/protobuf/utf8validation/Utf8ValidationEdition2023GeneratedTest.java new file mode 100644 index 0000000000000..4c544715b6539 --- /dev/null +++ b/java/core/src/test/java/com/google/protobuf/utf8validation/Utf8ValidationEdition2023GeneratedTest.java @@ -0,0 +1,378 @@ +package com.google.protobuf.utf8validation; + +import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertThrows; + +import com.google.protobuf.ExtensionRegistryLite; +import com.google.protobuf.InvalidProtocolBufferException; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class Utf8ValidationEdition2023GeneratedTest { + // edition: 2023 + // regular field + // validates: yes + @Test + public void testUnsetUnset_validates() throws Exception { + byte[] serialized = + new byte[] { + 10, // tag for field 1 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + assertThrows( + InvalidProtocolBufferException.class, + () -> Utf8TestEditions2023.parseFrom(serialized, ExtensionRegistryLite.getEmptyRegistry())); + } + + // edition: 2023 + // regular field + // validates: yes + @Test + public void testUnsetDefault_validates() throws Exception { + byte[] serialized = + new byte[] { + 18, // tag for field 2 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + assertThrows( + InvalidProtocolBufferException.class, + () -> Utf8TestEditions2023.parseFrom(serialized, ExtensionRegistryLite.getEmptyRegistry())); + } + + // edition: 2023 + // regular field + // validates: yes + @Test + public void testUnsetVerify_validates() throws Exception { + byte[] serialized = + new byte[] { + 26, // tag for field 3 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + assertThrows( + InvalidProtocolBufferException.class, + () -> Utf8TestEditions2023.parseFrom(serialized, ExtensionRegistryLite.getEmptyRegistry())); + } + + // edition: 2023 + // regular field + // validates: yes + @Test + public void testVerifyUnset_validates() throws Exception { + byte[] serialized = + new byte[] { + 34, // tag for field 4 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + assertThrows( + InvalidProtocolBufferException.class, + () -> Utf8TestEditions2023.parseFrom(serialized, ExtensionRegistryLite.getEmptyRegistry())); + } + + // edition: 2023 + // regular field + // validates: yes + @Test + public void testVerifyDefault_validates() throws Exception { + byte[] serialized = + new byte[] { + 42, // tag for field 5 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + assertThrows( + InvalidProtocolBufferException.class, + () -> Utf8TestEditions2023.parseFrom(serialized, ExtensionRegistryLite.getEmptyRegistry())); + } + + // edition: 2023 + // regular field + // validates: yes + @Test + public void testVerifyVerify_validates() throws Exception { + byte[] serialized = + new byte[] { + 50, // tag for field 6 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + assertThrows( + InvalidProtocolBufferException.class, + () -> Utf8TestEditions2023.parseFrom(serialized, ExtensionRegistryLite.getEmptyRegistry())); + } + + // edition: 2023 + // regular field + // validates: no + @Test + public void testNoneUnset_doesNotValidate() throws Exception { + byte[] serialized = + new byte[] { + 58, // tag for field 7 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + Utf8TestEditions2023 msg = + Utf8TestEditions2023.parseFrom(serialized, ExtensionRegistryLite.getEmptyRegistry()); + assertThat(msg.hasNoneUnset()).isTrue(); + assertThat(msg.getNoneUnset()).isEqualTo("\uFFFD\uFFFD"); + } + + // edition: 2023 + // regular field + // validates: no + @Test + public void testNoneDefault_doesNotValidate() throws Exception { + byte[] serialized = + new byte[] { + 66, // tag for field 8 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + Utf8TestEditions2023 msg = + Utf8TestEditions2023.parseFrom(serialized, ExtensionRegistryLite.getEmptyRegistry()); + assertThat(msg.hasNoneDefault()).isTrue(); + assertThat(msg.getNoneDefault()).isEqualTo("\uFFFD\uFFFD"); + } + + // edition: 2023 + // regular field + // validates: yes + @Test + public void testNoneVerify_validates() throws Exception { + byte[] serialized = + new byte[] { + 74, // tag for field 9 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + assertThrows( + InvalidProtocolBufferException.class, + () -> Utf8TestEditions2023.parseFrom(serialized, ExtensionRegistryLite.getEmptyRegistry())); + } + + // BEGIN FULL-RUNTIME + // edition: 2023 + // extension + // validates: yes + @Test + public void testUnsetUnsetExt_validates() throws Exception { + ExtensionRegistryLite registry = ExtensionRegistryLite.newInstance(); + registry.add(Utf8TestEditions2023Proto.extUnsetUnset); + + byte[] serialized = + new byte[] { + (byte) 0xAA, + (byte) 0x06, // tag for ext 101 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + assertThrows( + InvalidProtocolBufferException.class, + () -> Utf8TestEditions2023.parseFrom(serialized, registry)); + } + + // edition: 2023 + // extension + // validates: yes + @Test + public void testUnsetDefaultExt_validates() throws Exception { + ExtensionRegistryLite registry = ExtensionRegistryLite.newInstance(); + registry.add(Utf8TestEditions2023Proto.extUnsetDefault); + + byte[] serialized = + new byte[] { + (byte) 0xB2, + (byte) 0x06, // tag for ext 102 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + assertThrows( + InvalidProtocolBufferException.class, + () -> Utf8TestEditions2023.parseFrom(serialized, registry)); + } + + // edition: 2023 + // extension + // validates: yes + @Test + public void testUnsetVerifyExt_validates() throws Exception { + ExtensionRegistryLite registry = ExtensionRegistryLite.newInstance(); + registry.add(Utf8TestEditions2023Proto.extUnsetVerify); + + byte[] serialized = + new byte[] { + (byte) 0xBA, + (byte) 0x06, // tag for ext 103 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + assertThrows( + InvalidProtocolBufferException.class, + () -> Utf8TestEditions2023.parseFrom(serialized, registry)); + } + + // edition: 2023 + // extension + // validates: yes + @Test + public void testVerifyUnsetExt_validates() throws Exception { + ExtensionRegistryLite registry = ExtensionRegistryLite.newInstance(); + registry.add(Utf8TestEditions2023Proto.extVerifyUnset); + + byte[] serialized = + new byte[] { + (byte) 0xC2, + (byte) 0x06, // tag for ext 104 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + assertThrows( + InvalidProtocolBufferException.class, + () -> Utf8TestEditions2023.parseFrom(serialized, registry)); + } + + // edition: 2023 + // extension + // validates: yes + @Test + public void testVerifyDefaultExt_validates() throws Exception { + ExtensionRegistryLite registry = ExtensionRegistryLite.newInstance(); + registry.add(Utf8TestEditions2023Proto.extVerifyDefault); + + byte[] serialized = + new byte[] { + (byte) 0xCA, + (byte) 0x06, // tag for ext 105 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + assertThrows( + InvalidProtocolBufferException.class, + () -> Utf8TestEditions2023.parseFrom(serialized, registry)); + } + + // edition: 2023 + // extension + // validates: yes + @Test + public void testVerifyVerifyExt_validates() throws Exception { + ExtensionRegistryLite registry = ExtensionRegistryLite.newInstance(); + registry.add(Utf8TestEditions2023Proto.extVerifyVerify); + + byte[] serialized = + new byte[] { + (byte) 0xD2, + (byte) 0x06, // tag for ext 106 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + assertThrows( + InvalidProtocolBufferException.class, + () -> Utf8TestEditions2023.parseFrom(serialized, registry)); + } + + // edition: 2023 + // extension + // validates: no + @Test + public void testNoneUnsetExt_doesNotValidate() throws Exception { + ExtensionRegistryLite registry = ExtensionRegistryLite.newInstance(); + registry.add(Utf8TestEditions2023Proto.extNoneUnset); + + byte[] serialized = + new byte[] { + (byte) 0xDA, + (byte) 0x06, // tag for ext 107 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + Utf8TestEditions2023 msg = Utf8TestEditions2023.parseFrom(serialized, registry); + assertThat(msg.hasExtension(Utf8TestEditions2023Proto.extNoneUnset)).isTrue(); + assertThat(msg.getExtension(Utf8TestEditions2023Proto.extNoneUnset)).isEqualTo("\uFFFD\uFFFD"); + } + + // edition: 2023 + // extension + // validates: no + @Test + public void testNoneDefaultExt_doesNotValidate() throws Exception { + ExtensionRegistryLite registry = ExtensionRegistryLite.newInstance(); + registry.add(Utf8TestEditions2023Proto.extNoneDefault); + + byte[] serialized = + new byte[] { + (byte) 0xE2, + (byte) 0x06, // tag for ext 108 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + Utf8TestEditions2023 msg = Utf8TestEditions2023.parseFrom(serialized, registry); + assertThat(msg.hasExtension(Utf8TestEditions2023Proto.extNoneDefault)).isTrue(); + assertThat(msg.getExtension(Utf8TestEditions2023Proto.extNoneDefault)) + .isEqualTo("\uFFFD\uFFFD"); + } + + // edition: 2023 + // extension + // validates: yes + @Test + public void testNoneVerifyExt_validates() throws Exception { + ExtensionRegistryLite registry = ExtensionRegistryLite.newInstance(); + registry.add(Utf8TestEditions2023Proto.extNoneVerify); + + byte[] serialized = + new byte[] { + (byte) 0xEA, + (byte) 0x06, // tag for ext 109 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + assertThrows( + InvalidProtocolBufferException.class, + () -> Utf8TestEditions2023.parseFrom(serialized, registry)); + } + // END FULL-RUNTIME +} diff --git a/java/core/src/test/java/com/google/protobuf/utf8validation/Utf8ValidationEdition2024DynamicMessageTest.java b/java/core/src/test/java/com/google/protobuf/utf8validation/Utf8ValidationEdition2024DynamicMessageTest.java new file mode 100644 index 0000000000000..b3887b6554976 --- /dev/null +++ b/java/core/src/test/java/com/google/protobuf/utf8validation/Utf8ValidationEdition2024DynamicMessageTest.java @@ -0,0 +1,414 @@ +package com.google.protobuf.utf8validation; + +import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertThrows; + +import com.google.protobuf.Descriptors.Descriptor; +import com.google.protobuf.Descriptors.FieldDescriptor; +import com.google.protobuf.DynamicMessage; +import com.google.protobuf.ExtensionRegistry; +import com.google.protobuf.InvalidProtocolBufferException; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class Utf8ValidationEdition2024DynamicMessageTest { + // edition: 2024 + // regular field + // validates: yes + @Test + public void testUnsetUnset_validates() throws Exception { + Descriptor descriptor = Utf8TestEditions2024.getDescriptor(); + byte[] serialized = + new byte[] { + 10, // tag for field 1 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + assertThrows( + InvalidProtocolBufferException.class, + () -> + DynamicMessage.parseFrom(descriptor, serialized, ExtensionRegistry.getEmptyRegistry())); + } + + // edition: 2024 + // regular field + // validates: yes + @Test + public void testUnsetDefault_validates() throws Exception { + Descriptor descriptor = Utf8TestEditions2024.getDescriptor(); + byte[] serialized = + new byte[] { + 18, // tag for field 2 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + assertThrows( + InvalidProtocolBufferException.class, + () -> + DynamicMessage.parseFrom(descriptor, serialized, ExtensionRegistry.getEmptyRegistry())); + } + + // edition: 2024 + // regular field + // validates: yes + @Test + public void testUnsetVerify_validates() throws Exception { + Descriptor descriptor = Utf8TestEditions2024.getDescriptor(); + byte[] serialized = + new byte[] { + 26, // tag for field 3 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + assertThrows( + InvalidProtocolBufferException.class, + () -> + DynamicMessage.parseFrom(descriptor, serialized, ExtensionRegistry.getEmptyRegistry())); + } + + // edition: 2024 + // regular field + // validates: yes + @Test + public void testVerifyUnset_validates() throws Exception { + Descriptor descriptor = Utf8TestEditions2024.getDescriptor(); + byte[] serialized = + new byte[] { + 34, // tag for field 4 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + assertThrows( + InvalidProtocolBufferException.class, + () -> + DynamicMessage.parseFrom(descriptor, serialized, ExtensionRegistry.getEmptyRegistry())); + } + + // edition: 2024 + // regular field + // validates: yes + @Test + public void testVerifyDefault_validates() throws Exception { + Descriptor descriptor = Utf8TestEditions2024.getDescriptor(); + byte[] serialized = + new byte[] { + 42, // tag for field 5 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + assertThrows( + InvalidProtocolBufferException.class, + () -> + DynamicMessage.parseFrom(descriptor, serialized, ExtensionRegistry.getEmptyRegistry())); + } + + // edition: 2024 + // regular field + // validates: yes + @Test + public void testVerifyVerify_validates() throws Exception { + Descriptor descriptor = Utf8TestEditions2024.getDescriptor(); + byte[] serialized = + new byte[] { + 50, // tag for field 6 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + assertThrows( + InvalidProtocolBufferException.class, + () -> + DynamicMessage.parseFrom(descriptor, serialized, ExtensionRegistry.getEmptyRegistry())); + } + + // edition: 2024 + // regular field + // validates: no + @Test + public void testNoneUnset_doesNotValidate() throws Exception { + Descriptor descriptor = Utf8TestEditions2024.getDescriptor(); + FieldDescriptor field = descriptor.findFieldByName("none_unset"); + byte[] serialized = + new byte[] { + 58, // tag for field 7 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + DynamicMessage msg = + DynamicMessage.parseFrom(descriptor, serialized, ExtensionRegistry.getEmptyRegistry()); + assertThat(msg.hasField(field)).isTrue(); + assertThat(msg.getField(field)).isEqualTo("\uFFFD\uFFFD"); + } + + // edition: 2024 + // regular field + // validates: no + @Test + public void testNoneDefault_doesNotValidate() throws Exception { + Descriptor descriptor = Utf8TestEditions2024.getDescriptor(); + FieldDescriptor field = descriptor.findFieldByName("none_default"); + byte[] serialized = + new byte[] { + 66, // tag for field 8 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + DynamicMessage msg = + DynamicMessage.parseFrom(descriptor, serialized, ExtensionRegistry.getEmptyRegistry()); + assertThat(msg.hasField(field)).isTrue(); + assertThat(msg.getField(field)).isEqualTo("\uFFFD\uFFFD"); + } + + // edition: 2024 + // regular field + // validates: yes + @Test + public void testNoneVerify_validates() throws Exception { + Descriptor descriptor = Utf8TestEditions2024.getDescriptor(); + byte[] serialized = + new byte[] { + 74, // tag for field 9 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + assertThrows( + InvalidProtocolBufferException.class, + () -> + DynamicMessage.parseFrom(descriptor, serialized, ExtensionRegistry.getEmptyRegistry())); + } + + // edition: 2024 + // extension + // validates: yes + @Test + public void testUnsetUnsetExt_validates() throws Exception { + Descriptor descriptor = Utf8TestEditions2024.getDescriptor(); + FieldDescriptor extField = descriptor.getFile().findExtensionByName("ext_unset_unset"); + ExtensionRegistry registry = ExtensionRegistry.newInstance(); + registry.add(extField); + + byte[] serialized = + new byte[] { + (byte) 0xAA, + (byte) 0x06, // tag for ext 101 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + assertThrows( + InvalidProtocolBufferException.class, + () -> DynamicMessage.parseFrom(descriptor, serialized, registry)); + } + + // edition: 2024 + // extension + // validates: yes + @Test + public void testUnsetDefaultExt_validates() throws Exception { + Descriptor descriptor = Utf8TestEditions2024.getDescriptor(); + FieldDescriptor extField = descriptor.getFile().findExtensionByName("ext_unset_default"); + ExtensionRegistry registry = ExtensionRegistry.newInstance(); + registry.add(extField); + + byte[] serialized = + new byte[] { + (byte) 0xB2, + (byte) 0x06, // tag for ext 102 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + assertThrows( + InvalidProtocolBufferException.class, + () -> DynamicMessage.parseFrom(descriptor, serialized, registry)); + } + + // edition: 2024 + // extension + // validates: yes + @Test + public void testUnsetVerifyExt_validates() throws Exception { + Descriptor descriptor = Utf8TestEditions2024.getDescriptor(); + FieldDescriptor extField = descriptor.getFile().findExtensionByName("ext_unset_verify"); + ExtensionRegistry registry = ExtensionRegistry.newInstance(); + registry.add(extField); + + byte[] serialized = + new byte[] { + (byte) 0xBA, + (byte) 0x06, // tag for ext 103 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + assertThrows( + InvalidProtocolBufferException.class, + () -> DynamicMessage.parseFrom(descriptor, serialized, registry)); + } + + // edition: 2024 + // extension + // validates: yes + @Test + public void testVerifyUnsetExt_validates() throws Exception { + Descriptor descriptor = Utf8TestEditions2024.getDescriptor(); + FieldDescriptor extField = descriptor.getFile().findExtensionByName("ext_verify_unset"); + ExtensionRegistry registry = ExtensionRegistry.newInstance(); + registry.add(extField); + + byte[] serialized = + new byte[] { + (byte) 0xC2, + (byte) 0x06, // tag for ext 104 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + assertThrows( + InvalidProtocolBufferException.class, + () -> DynamicMessage.parseFrom(descriptor, serialized, registry)); + } + + // edition: 2024 + // extension + // validates: yes + @Test + public void testVerifyDefaultExt_validates() throws Exception { + Descriptor descriptor = Utf8TestEditions2024.getDescriptor(); + FieldDescriptor extField = descriptor.getFile().findExtensionByName("ext_verify_default"); + ExtensionRegistry registry = ExtensionRegistry.newInstance(); + registry.add(extField); + + byte[] serialized = + new byte[] { + (byte) 0xCA, + (byte) 0x06, // tag for ext 105 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + assertThrows( + InvalidProtocolBufferException.class, + () -> DynamicMessage.parseFrom(descriptor, serialized, registry)); + } + + // edition: 2024 + // extension + // validates: yes + @Test + public void testVerifyVerifyExt_validates() throws Exception { + Descriptor descriptor = Utf8TestEditions2024.getDescriptor(); + FieldDescriptor extField = descriptor.getFile().findExtensionByName("ext_verify_verify"); + ExtensionRegistry registry = ExtensionRegistry.newInstance(); + registry.add(extField); + + byte[] serialized = + new byte[] { + (byte) 0xD2, + (byte) 0x06, // tag for ext 106 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + assertThrows( + InvalidProtocolBufferException.class, + () -> DynamicMessage.parseFrom(descriptor, serialized, registry)); + } + + // edition: 2024 + // extension + // validates: no + @Test + public void testNoneUnsetExt_doesNotValidate() throws Exception { + Descriptor descriptor = Utf8TestEditions2024.getDescriptor(); + FieldDescriptor extField = descriptor.getFile().findExtensionByName("ext_none_unset"); + ExtensionRegistry registry = ExtensionRegistry.newInstance(); + registry.add(extField); + + byte[] serialized = + new byte[] { + (byte) 0xDA, + (byte) 0x06, // tag for ext 107 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + DynamicMessage msg = DynamicMessage.parseFrom(descriptor, serialized, registry); + assertThat(msg.hasField(extField)).isTrue(); + assertThat(msg.getField(extField)).isEqualTo("\uFFFD\uFFFD"); + } + + // edition: 2024 + // extension + // validates: no + @Test + public void testNoneDefaultExt_doesNotValidate() throws Exception { + Descriptor descriptor = Utf8TestEditions2024.getDescriptor(); + FieldDescriptor extField = descriptor.getFile().findExtensionByName("ext_none_default"); + ExtensionRegistry registry = ExtensionRegistry.newInstance(); + registry.add(extField); + + byte[] serialized = + new byte[] { + (byte) 0xE2, + (byte) 0x06, // tag for ext 108 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + DynamicMessage msg = DynamicMessage.parseFrom(descriptor, serialized, registry); + assertThat(msg.hasField(extField)).isTrue(); + assertThat(msg.getField(extField)).isEqualTo("\uFFFD\uFFFD"); + } + + // edition: 2024 + // extension + // validates: yes + @Test + public void testNoneVerifyExt_validates() throws Exception { + Descriptor descriptor = Utf8TestEditions2024.getDescriptor(); + FieldDescriptor extField = descriptor.getFile().findExtensionByName("ext_none_verify"); + ExtensionRegistry registry = ExtensionRegistry.newInstance(); + registry.add(extField); + + byte[] serialized = + new byte[] { + (byte) 0xEA, + (byte) 0x06, // tag for ext 109 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + assertThrows( + InvalidProtocolBufferException.class, + () -> DynamicMessage.parseFrom(descriptor, serialized, registry)); + } +} diff --git a/java/core/src/test/java/com/google/protobuf/utf8validation/Utf8ValidationEdition2024GeneratedTest.java b/java/core/src/test/java/com/google/protobuf/utf8validation/Utf8ValidationEdition2024GeneratedTest.java new file mode 100644 index 0000000000000..2b306341b2374 --- /dev/null +++ b/java/core/src/test/java/com/google/protobuf/utf8validation/Utf8ValidationEdition2024GeneratedTest.java @@ -0,0 +1,378 @@ +package com.google.protobuf.utf8validation; + +import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertThrows; + +import com.google.protobuf.ExtensionRegistryLite; +import com.google.protobuf.InvalidProtocolBufferException; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class Utf8ValidationEdition2024GeneratedTest { + // edition: 2024 + // regular field + // validates: yes + @Test + public void testUnsetUnset_validates() throws Exception { + byte[] serialized = + new byte[] { + 10, // tag for field 1 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + assertThrows( + InvalidProtocolBufferException.class, + () -> Utf8TestEditions2024.parseFrom(serialized, ExtensionRegistryLite.getEmptyRegistry())); + } + + // edition: 2024 + // regular field + // validates: yes + @Test + public void testUnsetDefault_validates() throws Exception { + byte[] serialized = + new byte[] { + 18, // tag for field 2 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + assertThrows( + InvalidProtocolBufferException.class, + () -> Utf8TestEditions2024.parseFrom(serialized, ExtensionRegistryLite.getEmptyRegistry())); + } + + // edition: 2024 + // regular field + // validates: yes + @Test + public void testUnsetVerify_validates() throws Exception { + byte[] serialized = + new byte[] { + 26, // tag for field 3 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + assertThrows( + InvalidProtocolBufferException.class, + () -> Utf8TestEditions2024.parseFrom(serialized, ExtensionRegistryLite.getEmptyRegistry())); + } + + // edition: 2024 + // regular field + // validates: yes + @Test + public void testVerifyUnset_validates() throws Exception { + byte[] serialized = + new byte[] { + 34, // tag for field 4 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + assertThrows( + InvalidProtocolBufferException.class, + () -> Utf8TestEditions2024.parseFrom(serialized, ExtensionRegistryLite.getEmptyRegistry())); + } + + // edition: 2024 + // regular field + // validates: yes + @Test + public void testVerifyDefault_validates() throws Exception { + byte[] serialized = + new byte[] { + 42, // tag for field 5 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + assertThrows( + InvalidProtocolBufferException.class, + () -> Utf8TestEditions2024.parseFrom(serialized, ExtensionRegistryLite.getEmptyRegistry())); + } + + // edition: 2024 + // regular field + // validates: yes + @Test + public void testVerifyVerify_validates() throws Exception { + byte[] serialized = + new byte[] { + 50, // tag for field 6 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + assertThrows( + InvalidProtocolBufferException.class, + () -> Utf8TestEditions2024.parseFrom(serialized, ExtensionRegistryLite.getEmptyRegistry())); + } + + // edition: 2024 + // regular field + // validates: no + @Test + public void testNoneUnset_doesNotValidate() throws Exception { + byte[] serialized = + new byte[] { + 58, // tag for field 7 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + Utf8TestEditions2024 msg = + Utf8TestEditions2024.parseFrom(serialized, ExtensionRegistryLite.getEmptyRegistry()); + assertThat(msg.hasNoneUnset()).isTrue(); + assertThat(msg.getNoneUnset()).isEqualTo("\uFFFD\uFFFD"); + } + + // edition: 2024 + // regular field + // validates: no + @Test + public void testNoneDefault_doesNotValidate() throws Exception { + byte[] serialized = + new byte[] { + 66, // tag for field 8 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + Utf8TestEditions2024 msg = + Utf8TestEditions2024.parseFrom(serialized, ExtensionRegistryLite.getEmptyRegistry()); + assertThat(msg.hasNoneDefault()).isTrue(); + assertThat(msg.getNoneDefault()).isEqualTo("\uFFFD\uFFFD"); + } + + // edition: 2024 + // regular field + // validates: yes + @Test + public void testNoneVerify_validates() throws Exception { + byte[] serialized = + new byte[] { + 74, // tag for field 9 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + assertThrows( + InvalidProtocolBufferException.class, + () -> Utf8TestEditions2024.parseFrom(serialized, ExtensionRegistryLite.getEmptyRegistry())); + } + + // BEGIN FULL-RUNTIME + // edition: 2024 + // extension + // validates: yes + @Test + public void testUnsetUnsetExt_validates() throws Exception { + ExtensionRegistryLite registry = ExtensionRegistryLite.newInstance(); + registry.add(Utf8TestEditions2024Proto.extUnsetUnset); + + byte[] serialized = + new byte[] { + (byte) 0xAA, + (byte) 0x06, // tag for ext 101 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + assertThrows( + InvalidProtocolBufferException.class, + () -> Utf8TestEditions2024.parseFrom(serialized, registry)); + } + + // edition: 2024 + // extension + // validates: yes + @Test + public void testUnsetDefaultExt_validates() throws Exception { + ExtensionRegistryLite registry = ExtensionRegistryLite.newInstance(); + registry.add(Utf8TestEditions2024Proto.extUnsetDefault); + + byte[] serialized = + new byte[] { + (byte) 0xB2, + (byte) 0x06, // tag for ext 102 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + assertThrows( + InvalidProtocolBufferException.class, + () -> Utf8TestEditions2024.parseFrom(serialized, registry)); + } + + // edition: 2024 + // extension + // validates: yes + @Test + public void testUnsetVerifyExt_validates() throws Exception { + ExtensionRegistryLite registry = ExtensionRegistryLite.newInstance(); + registry.add(Utf8TestEditions2024Proto.extUnsetVerify); + + byte[] serialized = + new byte[] { + (byte) 0xBA, + (byte) 0x06, // tag for ext 103 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + assertThrows( + InvalidProtocolBufferException.class, + () -> Utf8TestEditions2024.parseFrom(serialized, registry)); + } + + // edition: 2024 + // extension + // validates: yes + @Test + public void testVerifyUnsetExt_validates() throws Exception { + ExtensionRegistryLite registry = ExtensionRegistryLite.newInstance(); + registry.add(Utf8TestEditions2024Proto.extVerifyUnset); + + byte[] serialized = + new byte[] { + (byte) 0xC2, + (byte) 0x06, // tag for ext 104 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + assertThrows( + InvalidProtocolBufferException.class, + () -> Utf8TestEditions2024.parseFrom(serialized, registry)); + } + + // edition: 2024 + // extension + // validates: yes + @Test + public void testVerifyDefaultExt_validates() throws Exception { + ExtensionRegistryLite registry = ExtensionRegistryLite.newInstance(); + registry.add(Utf8TestEditions2024Proto.extVerifyDefault); + + byte[] serialized = + new byte[] { + (byte) 0xCA, + (byte) 0x06, // tag for ext 105 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + assertThrows( + InvalidProtocolBufferException.class, + () -> Utf8TestEditions2024.parseFrom(serialized, registry)); + } + + // edition: 2024 + // extension + // validates: yes + @Test + public void testVerifyVerifyExt_validates() throws Exception { + ExtensionRegistryLite registry = ExtensionRegistryLite.newInstance(); + registry.add(Utf8TestEditions2024Proto.extVerifyVerify); + + byte[] serialized = + new byte[] { + (byte) 0xD2, + (byte) 0x06, // tag for ext 106 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + assertThrows( + InvalidProtocolBufferException.class, + () -> Utf8TestEditions2024.parseFrom(serialized, registry)); + } + + // edition: 2024 + // extension + // validates: no + @Test + public void testNoneUnsetExt_doesNotValidate() throws Exception { + ExtensionRegistryLite registry = ExtensionRegistryLite.newInstance(); + registry.add(Utf8TestEditions2024Proto.extNoneUnset); + + byte[] serialized = + new byte[] { + (byte) 0xDA, + (byte) 0x06, // tag for ext 107 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + Utf8TestEditions2024 msg = Utf8TestEditions2024.parseFrom(serialized, registry); + assertThat(msg.hasExtension(Utf8TestEditions2024Proto.extNoneUnset)).isTrue(); + assertThat(msg.getExtension(Utf8TestEditions2024Proto.extNoneUnset)).isEqualTo("\uFFFD\uFFFD"); + } + + // edition: 2024 + // extension + // validates: no + @Test + public void testNoneDefaultExt_doesNotValidate() throws Exception { + ExtensionRegistryLite registry = ExtensionRegistryLite.newInstance(); + registry.add(Utf8TestEditions2024Proto.extNoneDefault); + + byte[] serialized = + new byte[] { + (byte) 0xE2, + (byte) 0x06, // tag for ext 108 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + Utf8TestEditions2024 msg = Utf8TestEditions2024.parseFrom(serialized, registry); + assertThat(msg.hasExtension(Utf8TestEditions2024Proto.extNoneDefault)).isTrue(); + assertThat(msg.getExtension(Utf8TestEditions2024Proto.extNoneDefault)) + .isEqualTo("\uFFFD\uFFFD"); + } + + // edition: 2024 + // extension + // validates: yes + @Test + public void testNoneVerifyExt_validates() throws Exception { + ExtensionRegistryLite registry = ExtensionRegistryLite.newInstance(); + registry.add(Utf8TestEditions2024Proto.extNoneVerify); + + byte[] serialized = + new byte[] { + (byte) 0xEA, + (byte) 0x06, // tag for ext 109 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + assertThrows( + InvalidProtocolBufferException.class, + () -> Utf8TestEditions2024.parseFrom(serialized, registry)); + } + // END FULL-RUNTIME +} diff --git a/java/core/src/test/java/com/google/protobuf/utf8validation/Utf8ValidationProto2DynamicMessageTest.java b/java/core/src/test/java/com/google/protobuf/utf8validation/Utf8ValidationProto2DynamicMessageTest.java new file mode 100644 index 0000000000000..cac660498b498 --- /dev/null +++ b/java/core/src/test/java/com/google/protobuf/utf8validation/Utf8ValidationProto2DynamicMessageTest.java @@ -0,0 +1,306 @@ +package com.google.protobuf.utf8validation; + +import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertThrows; + +import com.google.protobuf.DescriptorProtos.DescriptorProto; +import com.google.protobuf.DescriptorProtos.FeatureSet.Utf8Validation; +import com.google.protobuf.DescriptorProtos.FieldDescriptorProto; +import com.google.protobuf.DescriptorProtos.FieldOptions; +import com.google.protobuf.DescriptorProtos.FileDescriptorProto; +import com.google.protobuf.DescriptorProtos.FileOptions; +import com.google.protobuf.Descriptors.Descriptor; +import com.google.protobuf.Descriptors.FieldDescriptor; +import com.google.protobuf.Descriptors.FileDescriptor; +import com.google.protobuf.DynamicMessage; +import com.google.protobuf.ExtensionRegistry; +import com.google.protobuf.InvalidProtocolBufferException; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class Utf8ValidationProto2DynamicMessageTest { + // syntax: proto2 + // java_string_check_utf8: unset + // enforce_utf8: unset + // regular field + // validates: no + @Test + public void testUnsetUnset_doesNotValidate() throws Exception { + // Proto2 default: No validation + Descriptor descriptor = Utf8TestProto2.getDescriptor(); + FieldDescriptor field = descriptor.findFieldByName("unset_unset"); + byte[] serialized = + new byte[] { + (byte) ((field.getNumber() << 3) | 2), // tag + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + DynamicMessage msg = + DynamicMessage.parseFrom(descriptor, serialized, ExtensionRegistry.getEmptyRegistry()); + // Parsing succeeded without exception + assertThat(msg.hasField(field)).isTrue(); + assertThat(msg.getField(field)).isEqualTo("\uFFFD\uFFFD"); + } + + // syntax: proto2 + // java_string_check_utf8: unset + // enforce_utf8: true + // regular field + // validates: no + @Test + public void testUnsetEnforced_doesNotValidate() throws Exception { + // Proto2 with [enforce_utf8 = true] on normal field: No validation in DynamicMessage + Descriptor descriptor = Utf8TestProto2.getDescriptor(); + FieldDescriptor field = descriptor.findFieldByName("unset_enforced"); + byte[] serialized = + new byte[] { + (byte) ((field.getNumber() << 3) | 2), // tag + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + DynamicMessage msg = + DynamicMessage.parseFrom(descriptor, serialized, ExtensionRegistry.getEmptyRegistry()); + // Parsing succeeded without exception + assertThat(msg.hasField(field)).isTrue(); + assertThat(msg.getField(field)).isEqualTo("\uFFFD\uFFFD"); + } + + // syntax: proto2 + // java_string_check_utf8: false + // enforce_utf8: unset + // regular field + // validates: no + @Test + public void testUncheckedUnset_doesNotValidate() throws Exception { + Descriptor descriptor = buildDescriptor(null, false); + FieldDescriptor field = descriptor.findFieldByName("value"); + byte[] serialized = + new byte[] { + (byte) ((field.getNumber() << 3) | 2), // tag + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + DynamicMessage msg = + DynamicMessage.parseFrom(descriptor, serialized, ExtensionRegistry.getEmptyRegistry()); + // Parsing succeeded without exception + assertThat(msg.hasField(field)).isTrue(); + assertThat(msg.getField(field)).isEqualTo("\uFFFD\uFFFD"); + } + + // syntax: proto2 + // java_string_check_utf8: false + // enforce_utf8: true + // regular field + // validates: no + @Test + public void testUncheckedEnforced_doesNotValidate() throws Exception { + Descriptor descriptor = buildDescriptor(true, false); + FieldDescriptor field = descriptor.findFieldByName("value"); + byte[] serialized = + new byte[] { + (byte) ((field.getNumber() << 3) | 2), // tag + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + DynamicMessage msg = + DynamicMessage.parseFrom(descriptor, serialized, ExtensionRegistry.getEmptyRegistry()); + // Parsing succeeded without exception + assertThat(msg.hasField(field)).isTrue(); + assertThat(msg.getField(field)).isEqualTo("\uFFFD\uFFFD"); + } + + // syntax: proto2 + // java_string_check_utf8: true + // enforce_utf8: unset + // regular field + // validates: yes + @Test + public void testCheckedUnset_validates() throws Exception { + // Proto2 with java_string_check_utf8 = true: Validation enabled + Descriptor descriptor = Utf8TestProto2Checked.getDescriptor(); + FieldDescriptor field = descriptor.findFieldByName("checked_unset"); + byte[] serialized = + new byte[] { + (byte) ((field.getNumber() << 3) | 2), // tag + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + assertThrows( + InvalidProtocolBufferException.class, + () -> + DynamicMessage.parseFrom(descriptor, serialized, ExtensionRegistry.getEmptyRegistry())); + } + + // syntax: proto2 + // java_string_check_utf8: true + // enforce_utf8: true + // regular field + // validates: yes + @Test + public void testCheckedEnforced_validates() throws Exception { + Descriptor descriptor = Utf8TestProto2Checked.getDescriptor(); + FieldDescriptor field = descriptor.findFieldByName("checked_enforced"); + byte[] serialized = + new byte[] { + (byte) ((field.getNumber() << 3) | 2), // tag + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + assertThrows( + InvalidProtocolBufferException.class, + () -> + DynamicMessage.parseFrom(descriptor, serialized, ExtensionRegistry.getEmptyRegistry())); + } + + // syntax: proto2 + // java_string_check_utf8: true + // enforce_utf8: false + // regular field + // validates: yes + @Test + public void testCheckedUnenforced_validates() throws Exception { + Descriptor descriptor = buildDescriptor(false, true); + FieldDescriptor field = descriptor.findFieldByName("value"); + byte[] serialized = + new byte[] { + (byte) ((field.getNumber() << 3) | 2), // tag + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + assertThrows( + InvalidProtocolBufferException.class, + () -> + DynamicMessage.parseFrom(descriptor, serialized, ExtensionRegistry.getEmptyRegistry())); + } + + // syntax: proto2 + // java_string_check_utf8: unset + // enforce_utf8: true + // extension + // validates: no + @Test + public void testUnsetEnforcedExt_doesNotValidate() throws Exception { + // Proto2 with [enforce_utf8 = true] on extension: No validation in DynamicMessage + Descriptor descriptor = Utf8TestProto2.getDescriptor(); + FieldDescriptor extField = descriptor.getFile().findExtensionByName("ext_unset_enforced"); + ExtensionRegistry registry = ExtensionRegistry.newInstance(); + registry.add(extField); + + byte[] serialized = + new byte[] { + (byte) 0xB2, + (byte) 0x06, // tag for field 102 (102 << 3 | 2 = 818 = 0xB2 0x06 in varint) + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + DynamicMessage msg = DynamicMessage.parseFrom(descriptor, serialized, registry); + // Parsing succeeded without exception + assertThat(msg.hasField(extField)).isTrue(); + assertThat(msg.getField(extField)).isEqualTo("\uFFFD\uFFFD"); + } + + // syntax: proto2 + // java_string_check_utf8: unset + // enforce_utf8: unset + // extension + // validates: no + @Test + public void testUnsetUnsetExt_doesNotValidate() throws Exception { + // Proto2 with [enforce_utf8 = false] on extension: No validation + Descriptor descriptor = Utf8TestProto2.getDescriptor(); + FieldDescriptor extField = descriptor.getFile().findExtensionByName("ext_unset_unset"); + ExtensionRegistry registry = ExtensionRegistry.newInstance(); + registry.add(extField); + + byte[] serialized = + new byte[] { + (byte) 0xA2, + (byte) 0x06, // tag for field 100 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + DynamicMessage msg = DynamicMessage.parseFrom(descriptor, serialized, registry); + // Parsing succeeded without exception + assertThat(msg.hasField(extField)).isTrue(); + assertThat(msg.getField(extField)).isEqualTo("\uFFFD\uFFFD"); + } + + // syntax: proto2 + // java_string_check_utf8: true + // extension + // validates: yes + @Test + public void testCheckedUnsetExt_validates() throws Exception { + Descriptor descriptor = Utf8TestProto2Checked.getDescriptor(); + FieldDescriptor extField = descriptor.getFile().findExtensionByName("ext_checked_unset"); + ExtensionRegistry registry = ExtensionRegistry.newInstance(); + registry.add(extField); + + byte[] serialized = + new byte[] { + (byte) 0xA2, + (byte) 0x06, // tag for field 100 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + assertThrows( + InvalidProtocolBufferException.class, + () -> DynamicMessage.parseFrom(descriptor, serialized, registry)); + } + + private static Descriptor buildDescriptor(Boolean enforceUtf8, Boolean javaStringCheckUtf8) + throws Exception { + FileDescriptorProto.Builder fileBuilder = + FileDescriptorProto.newBuilder().setName("test_proto2_dynamic.proto").setSyntax("proto2"); + + if (javaStringCheckUtf8 != null) { + fileBuilder.setOptions(FileOptions.newBuilder().setJavaStringCheckUtf8(javaStringCheckUtf8)); + } + + DescriptorProto.Builder msgBuilder = DescriptorProto.newBuilder().setName("Utf8TestMessage"); + + FieldDescriptorProto.Builder fieldBuilder = + FieldDescriptorProto.newBuilder() + .setName("value") + .setNumber(1) + .setType(FieldDescriptorProto.Type.TYPE_STRING) + .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL); + + if (enforceUtf8 != null) { + FieldOptions.Builder optionsBuilder = FieldOptions.newBuilder().setEnforceUtf8(enforceUtf8); + if (!enforceUtf8) { + optionsBuilder.getFeaturesBuilder().setUtf8Validation(Utf8Validation.NONE); + } + fieldBuilder.setOptions(optionsBuilder); + } + + msgBuilder.addField(fieldBuilder); + fileBuilder.addMessageType(msgBuilder); + + FileDescriptor fileDescriptor = + FileDescriptor.buildFrom(fileBuilder.build(), new FileDescriptor[0]); + return fileDescriptor.findMessageTypeByName("Utf8TestMessage"); + } +} diff --git a/java/core/src/test/java/com/google/protobuf/utf8validation/Utf8ValidationProto2GeneratedTest.java b/java/core/src/test/java/com/google/protobuf/utf8validation/Utf8ValidationProto2GeneratedTest.java new file mode 100644 index 0000000000000..4084a88f12965 --- /dev/null +++ b/java/core/src/test/java/com/google/protobuf/utf8validation/Utf8ValidationProto2GeneratedTest.java @@ -0,0 +1,187 @@ +package com.google.protobuf.utf8validation; + +import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertThrows; + +import com.google.protobuf.ExtensionRegistryLite; +import com.google.protobuf.InvalidProtocolBufferException; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class Utf8ValidationProto2GeneratedTest { + private boolean isLite = true; + + // BEGIN FULL-RUNTIME + @Before + public void setUp() { + isLite = false; + } + + // END FULL-RUNTIME + + // syntax: proto2 + // java_string_check_utf8: unset + // enforce_utf8: unset + // regular field + // validates: no + @Test + public void testUnsetUnset_doesNotValidate() throws Exception { + byte[] serialized = + new byte[] { + 10, // tag for field 1 (1 << 3) | 2 = 10 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + Utf8TestProto2 msg = + Utf8TestProto2.parseFrom(serialized, ExtensionRegistryLite.getEmptyRegistry()); + assertThat(msg.hasUnsetUnset()).isTrue(); + assertThat(msg.getUnsetUnset()).isEqualTo("\uFFFD\uFFFD"); + } + + // syntax: proto2 + // java_string_check_utf8: false + // enforce_utf8: unset + // regular field + // validates: no + @Test + public void testUncheckedUnset_doesNotValidate() throws Exception { + byte[] serialized = + new byte[] { + 10, // tag for field 1 (1 << 3) | 2 = 10 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + Utf8TestProto2Unchecked msg = + Utf8TestProto2Unchecked.parseFrom(serialized, ExtensionRegistryLite.getEmptyRegistry()); + assertThat(msg.hasUncheckedUnset()).isTrue(); + assertThat(msg.getUncheckedUnset()).isEqualTo("\uFFFD\uFFFD"); + } + + // syntax: proto2 + // java_string_check_utf8: false + // enforce_utf8: true + // regular field + // validates: no + @Test + public void testUncheckedEnforced_doesNotValidate() throws Exception { + byte[] serialized = + new byte[] { + 26, // tag for field 3 (3 << 3) | 2 = 26 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + Utf8TestProto2Unchecked msg = + Utf8TestProto2Unchecked.parseFrom(serialized, ExtensionRegistryLite.getEmptyRegistry()); + assertThat(msg.hasUncheckedEnforced()).isTrue(); + assertThat(msg.getUncheckedEnforced()).isEqualTo("\uFFFD\uFFFD"); + } + + // syntax: proto2 + // java_string_check_utf8: true + // enforce_utf8: unset + // regular field + // validates: yes + @Test + public void testCheckedUnset_validates() throws Exception { + byte[] serialized = + new byte[] { + 10, // tag for field 1 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + // Full-runtime validates string fields. + assertThrows( + InvalidProtocolBufferException.class, + () -> + Utf8TestProto2Checked.parseFrom(serialized, ExtensionRegistryLite.getEmptyRegistry())); + } + + // syntax: proto2 + // java_string_check_utf8: true + // enforce_utf8: true + // regular field + // validates: yes + @Test + public void testCheckedEnforced_validates() throws Exception { + byte[] serialized = + new byte[] { + 26, // tag for field 3 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + assertThrows( + InvalidProtocolBufferException.class, + () -> + Utf8TestProto2Checked.parseFrom(serialized, ExtensionRegistryLite.getEmptyRegistry())); + } + + // syntax: proto2 + // java_string_check_utf8: unset + // enforce_utf8: true + // extension + // validates: no + @Test + public void testUnsetEnforcedExt_doesNotValidate() throws Exception { + // [enforce_utf8 = true] has no effect in proto2 + ExtensionRegistryLite registry = ExtensionRegistryLite.newInstance(); + registry.add(Utf8TestProto2Proto.extUnsetEnforced); + + byte[] serialized = + new byte[] { + (byte) 0xB2, + (byte) 0x06, // tag for field 102 (102 << 3 | 2 = 818 = 0xB2 0x06 in varint) + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + Utf8TestProto2 msg = Utf8TestProto2.parseFrom(serialized, registry); + assertThat(msg.hasExtension(Utf8TestProto2Proto.extUnsetEnforced)).isTrue(); + assertThat(msg.getExtension(Utf8TestProto2Proto.extUnsetEnforced)).isEqualTo("\uFFFD\uFFFD"); + } + + // syntax: proto2 + // java_string_check_utf8: true + // extension + // validates: full-runtime only + @Test + public void testCheckedUnsetExt() throws Exception { + ExtensionRegistryLite registry = ExtensionRegistryLite.newInstance(); + registry.add(Utf8TestProto2CheckedProto.extCheckedUnset); + + byte[] serialized = + new byte[] { + (byte) 0xA2, + (byte) 0x06, // tag for field 100 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + if (isLite) { + // Lite does not validate string extensions. + Utf8TestProto2Checked msg = Utf8TestProto2Checked.parseFrom(serialized, registry); + assertThat(msg.hasExtension(Utf8TestProto2CheckedProto.extCheckedUnset)).isTrue(); + assertThat(msg.getExtension(Utf8TestProto2CheckedProto.extCheckedUnset)) + .isEqualTo("\uFFFD\uFFFD"); + } else { + // Full-runtime validates string extensions. + assertThrows( + InvalidProtocolBufferException.class, + () -> Utf8TestProto2Checked.parseFrom(serialized, registry)); + } + } +} diff --git a/java/core/src/test/java/com/google/protobuf/utf8validation/Utf8ValidationProto3DynamicMessageTest.java b/java/core/src/test/java/com/google/protobuf/utf8validation/Utf8ValidationProto3DynamicMessageTest.java new file mode 100644 index 0000000000000..05dc12235ec18 --- /dev/null +++ b/java/core/src/test/java/com/google/protobuf/utf8validation/Utf8ValidationProto3DynamicMessageTest.java @@ -0,0 +1,246 @@ +package com.google.protobuf.utf8validation; + +import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertThrows; + +import com.google.protobuf.DescriptorProtos.DescriptorProto; +import com.google.protobuf.DescriptorProtos.FieldDescriptorProto; +import com.google.protobuf.DescriptorProtos.FieldOptions; +import com.google.protobuf.DescriptorProtos.FileDescriptorProto; +import com.google.protobuf.DescriptorProtos.FileOptions; +import com.google.protobuf.Descriptors.Descriptor; +import com.google.protobuf.Descriptors.FieldDescriptor; +import com.google.protobuf.Descriptors.FileDescriptor; +import com.google.protobuf.DynamicMessage; +import com.google.protobuf.ExtensionRegistry; +import com.google.protobuf.InvalidProtocolBufferException; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class Utf8ValidationProto3DynamicMessageTest { + // syntax: proto3 + // java_string_check_utf8: unset + // enforce_utf8: unset + // regular field + // validates: yes + @Test + public void testUnsetUnset_validates() throws Exception { + // Proto3 default: Validation enabled + Descriptor descriptor = buildDescriptor(null, null); + FieldDescriptor field = descriptor.findFieldByName("value"); + byte[] serialized = + new byte[] { + (byte) ((field.getNumber() << 3) | 2), // tag + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + assertThrows( + InvalidProtocolBufferException.class, + () -> + DynamicMessage.parseFrom( + descriptor, serialized, ExtensionRegistry.getGeneratedRegistry())); + } + + // syntax: proto3 + // java_string_check_utf8: true + // enforce_utf8: unset + // regular field + // validates: yes + @Test + public void testCheckedUnset_validates() throws Exception { + Descriptor descriptor = buildDescriptor(null, true); + FieldDescriptor field = descriptor.findFieldByName("value"); + byte[] serialized = + new byte[] { + (byte) ((field.getNumber() << 3) | 2), // tag + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + assertThrows( + InvalidProtocolBufferException.class, + () -> + DynamicMessage.parseFrom( + descriptor, serialized, ExtensionRegistry.getGeneratedRegistry())); + } + + // syntax: proto3 + // java_string_check_utf8: false + // enforce_utf8: unset + // regular field + // validates: yes + @Test + public void testUncheckedUnset_validates() throws Exception { + Descriptor descriptor = buildDescriptor(null, false); + FieldDescriptor field = descriptor.findFieldByName("value"); + byte[] serialized = + new byte[] { + (byte) ((field.getNumber() << 3) | 2), // tag + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + assertThrows( + InvalidProtocolBufferException.class, + () -> + DynamicMessage.parseFrom( + descriptor, serialized, ExtensionRegistry.getGeneratedRegistry())); + } + + // syntax: proto3 + // java_string_check_utf8: true + // enforce_utf8: true + // regular field + // validates: yes + @Test + public void testCheckedEnforced_validates() throws Exception { + Descriptor descriptor = buildDescriptor(true, true); + FieldDescriptor field = descriptor.findFieldByName("value"); + byte[] serialized = + new byte[] { + (byte) ((field.getNumber() << 3) | 2), // tag + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + assertThrows( + InvalidProtocolBufferException.class, + () -> + DynamicMessage.parseFrom( + descriptor, serialized, ExtensionRegistry.getGeneratedRegistry())); + } + + // syntax: proto3 + // java_string_check_utf8: false + // enforce_utf8: true + // regular field + // validates: yes + @Test + public void testUncheckedEnforced_validates() throws Exception { + Descriptor descriptor = buildDescriptor(true, false); + FieldDescriptor field = descriptor.findFieldByName("value"); + byte[] serialized = + new byte[] { + (byte) ((field.getNumber() << 3) | 2), // tag + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + assertThrows( + InvalidProtocolBufferException.class, + () -> + DynamicMessage.parseFrom( + descriptor, serialized, ExtensionRegistry.getGeneratedRegistry())); + } + + // syntax: proto3 + // java_string_check_utf8: unset + // enforce_utf8: false + // regular field + // validates: no + @Test + public void testUnsetUnenforced_doesNotValidate() throws Exception { + // Proto3 with [enforce_utf8 = false]: No validation + Descriptor descriptor = buildDescriptor(false, null); + FieldDescriptor field = descriptor.findFieldByName("value"); + byte[] serialized = + new byte[] { + (byte) ((field.getNumber() << 3) | 2), // tag + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + DynamicMessage msg = + DynamicMessage.parseFrom(descriptor, serialized, ExtensionRegistry.getGeneratedRegistry()); + // Parsing succeeded without exception + assertThat(msg.hasField(field)).isTrue(); + assertThat(msg.getField(field)).isEqualTo("\uFFFD\uFFFD"); + } + + // syntax: proto3 + // java_string_check_utf8: true + // enforce_utf8: false + // regular field + // validates: no + @Test + public void testCheckedUnenforced_doesNotValidate() throws Exception { + Descriptor descriptor = buildDescriptor(false, true); + FieldDescriptor field = descriptor.findFieldByName("value"); + byte[] serialized = + new byte[] { + (byte) ((field.getNumber() << 3) | 2), // tag + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + DynamicMessage msg = + DynamicMessage.parseFrom(descriptor, serialized, ExtensionRegistry.getGeneratedRegistry()); + // Parsing succeeded without exception + assertThat(msg.hasField(field)).isTrue(); + assertThat(msg.getField(field)).isEqualTo("\uFFFD\uFFFD"); + } + + // syntax: proto3 + // java_string_check_utf8: false + // enforce_utf8: false + // regular field + // validates: no + @Test + public void testUncheckedUnenforced_doesNotValidate() throws Exception { + Descriptor descriptor = buildDescriptor(false, false); + FieldDescriptor field = descriptor.findFieldByName("value"); + byte[] serialized = + new byte[] { + (byte) ((field.getNumber() << 3) | 2), // tag + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + DynamicMessage msg = + DynamicMessage.parseFrom(descriptor, serialized, ExtensionRegistry.getGeneratedRegistry()); + // Parsing succeeded without exception + assertThat(msg.hasField(field)).isTrue(); + assertThat(msg.getField(field)).isEqualTo("\uFFFD\uFFFD"); + } + + private static Descriptor buildDescriptor(Boolean enforceUtf8, Boolean javaStringCheckUtf8) + throws Exception { + FileDescriptorProto.Builder fileBuilder = + FileDescriptorProto.newBuilder().setName("test_proto3.proto").setSyntax("proto3"); + + if (javaStringCheckUtf8 != null) { + fileBuilder.setOptions(FileOptions.newBuilder().setJavaStringCheckUtf8(javaStringCheckUtf8)); + } + + DescriptorProto.Builder msgBuilder = DescriptorProto.newBuilder().setName("Utf8TestMessage"); + + FieldDescriptorProto.Builder fieldBuilder = + FieldDescriptorProto.newBuilder() + .setName("value") + .setNumber(1) + .setType(FieldDescriptorProto.Type.TYPE_STRING) + .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL); + + if (enforceUtf8 != null) { + fieldBuilder.setOptions(FieldOptions.newBuilder().setEnforceUtf8(enforceUtf8)); + } + + msgBuilder.addField(fieldBuilder); + fileBuilder.addMessageType(msgBuilder); + + FileDescriptor fileDescriptor = + FileDescriptor.buildFrom(fileBuilder.build(), new FileDescriptor[0]); + return fileDescriptor.findMessageTypeByName("Utf8TestMessage"); + } +} diff --git a/java/core/src/test/java/com/google/protobuf/utf8validation/Utf8ValidationProto3GeneratedTest.java b/java/core/src/test/java/com/google/protobuf/utf8validation/Utf8ValidationProto3GeneratedTest.java new file mode 100644 index 0000000000000..2d05657a0c998 --- /dev/null +++ b/java/core/src/test/java/com/google/protobuf/utf8validation/Utf8ValidationProto3GeneratedTest.java @@ -0,0 +1,77 @@ +package com.google.protobuf.utf8validation; + +import static org.junit.Assert.assertThrows; + +import com.google.protobuf.ExtensionRegistryLite; +import com.google.protobuf.InvalidProtocolBufferException; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class Utf8ValidationProto3GeneratedTest { + // syntax: proto3 + // java_string_check_utf8: unset + // enforce_utf8: unset + // regular field + // validates: yes + @Test + public void testUnsetUnset_validates() throws Exception { + // Proto3 default: Validation enabled + byte[] serialized = + new byte[] { + 10, // tag for field 1 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + assertThrows( + InvalidProtocolBufferException.class, + () -> Utf8TestProto3.parseFrom(serialized, ExtensionRegistryLite.getEmptyRegistry())); + } + + // syntax: proto3 + // java_string_check_utf8: true + // enforce_utf8: unset + // regular field + // validates: yes + @Test + public void testCheckedUnset_validates() throws Exception { + // Proto3 with java_string_check_utf8 = true: Validation enabled + byte[] serialized = + new byte[] { + 10, // tag for field 1 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + assertThrows( + InvalidProtocolBufferException.class, + () -> + Utf8TestProto3Checked.parseFrom(serialized, ExtensionRegistryLite.getEmptyRegistry())); + } + + // syntax: proto3 + // java_string_check_utf8: false + // enforce_utf8: unset + // regular field + // validates: yes + @Test + public void testUncheckedUnset_validates() throws Exception { + byte[] serialized = + new byte[] { + 10, // tag for field 1 + 2, // length + (byte) 0xC0, + (byte) 0x80 + }; + + assertThrows( + InvalidProtocolBufferException.class, + () -> + Utf8TestProto3Unchecked.parseFrom( + serialized, ExtensionRegistryLite.getEmptyRegistry())); + } +} diff --git a/java/core/src/test/proto/com/google/protobuf/utf8validation/utf8_test_editions_2023.proto b/java/core/src/test/proto/com/google/protobuf/utf8validation/utf8_test_editions_2023.proto new file mode 100644 index 0000000000000..3f096f3880fca --- /dev/null +++ b/java/core/src/test/proto/com/google/protobuf/utf8validation/utf8_test_editions_2023.proto @@ -0,0 +1,77 @@ + +edition = "2023"; + +package utf8validation; + +import "google/protobuf/java_features.proto"; + +option java_package = "com.google.protobuf.utf8validation"; +option java_outer_classname = "Utf8TestEditions2023Proto"; +option java_multiple_files = true; + +message Utf8TestEditions2023 { + // Regular fields + string unset_unset = 1; + + string unset_default = 2 [features.(pb.java).utf8_validation = DEFAULT]; + + string unset_verify = 3 [features.(pb.java).utf8_validation = VERIFY]; + + string verify_unset = 4 [features.utf8_validation = VERIFY]; + + string verify_default = 5 [ + features.utf8_validation = VERIFY, + features.(pb.java).utf8_validation = DEFAULT + ]; + + string verify_verify = 6 [ + features.utf8_validation = VERIFY, + features.(pb.java).utf8_validation = VERIFY + ]; + + string none_unset = 7 [features.utf8_validation = NONE]; + + string none_default = 8 [ + features.utf8_validation = NONE, + features.(pb.java).utf8_validation = DEFAULT + ]; + + string none_verify = 9 [ + features.utf8_validation = NONE, + features.(pb.java).utf8_validation = VERIFY + ]; + + extensions 100 to 200; +} + +extend Utf8TestEditions2023 { + string ext_unset_unset = 101; + + string ext_unset_default = 102 [features.(pb.java).utf8_validation = DEFAULT]; + + string ext_unset_verify = 103 [features.(pb.java).utf8_validation = VERIFY]; + + string ext_verify_unset = 104 [features.utf8_validation = VERIFY]; + + string ext_verify_default = 105 [ + features.utf8_validation = VERIFY, + features.(pb.java).utf8_validation = DEFAULT + ]; + + string ext_verify_verify = 106 [ + features.utf8_validation = VERIFY, + features.(pb.java).utf8_validation = VERIFY + ]; + + string ext_none_unset = 107 [features.utf8_validation = NONE]; + + string ext_none_default = 108 [ + features.utf8_validation = NONE, + features.(pb.java).utf8_validation = DEFAULT + ]; + + string ext_none_verify = 109 [ + features.utf8_validation = NONE, + features.(pb.java).utf8_validation = VERIFY + ]; +} diff --git a/java/core/src/test/proto/com/google/protobuf/utf8validation/utf8_test_editions_2024.proto b/java/core/src/test/proto/com/google/protobuf/utf8validation/utf8_test_editions_2024.proto new file mode 100644 index 0000000000000..110af652661b0 --- /dev/null +++ b/java/core/src/test/proto/com/google/protobuf/utf8validation/utf8_test_editions_2024.proto @@ -0,0 +1,75 @@ + +edition = "2024"; + +package utf8validation; + +import "google/protobuf/java_features.proto"; + +option java_package = "com.google.protobuf.utf8validation"; + +message Utf8TestEditions2024 { + // Regular fields + string unset_unset = 1; + + string unset_default = 2 [features.(pb.java).utf8_validation = DEFAULT]; + + string unset_verify = 3 [features.(pb.java).utf8_validation = VERIFY]; + + string verify_unset = 4 [features.utf8_validation = VERIFY]; + + string verify_default = 5 [ + features.utf8_validation = VERIFY, + features.(pb.java).utf8_validation = DEFAULT + ]; + + string verify_verify = 6 [ + features.utf8_validation = VERIFY, + features.(pb.java).utf8_validation = VERIFY + ]; + + string none_unset = 7 [features.utf8_validation = NONE]; + + string none_default = 8 [ + features.utf8_validation = NONE, + features.(pb.java).utf8_validation = DEFAULT + ]; + + string none_verify = 9 [ + features.utf8_validation = NONE, + features.(pb.java).utf8_validation = VERIFY + ]; + + extensions 100 to 200; +} + +extend Utf8TestEditions2024 { + string ext_unset_unset = 101; + + string ext_unset_default = 102 [features.(pb.java).utf8_validation = DEFAULT]; + + string ext_unset_verify = 103 [features.(pb.java).utf8_validation = VERIFY]; + + string ext_verify_unset = 104 [features.utf8_validation = VERIFY]; + + string ext_verify_default = 105 [ + features.utf8_validation = VERIFY, + features.(pb.java).utf8_validation = DEFAULT + ]; + + string ext_verify_verify = 106 [ + features.utf8_validation = VERIFY, + features.(pb.java).utf8_validation = VERIFY + ]; + + string ext_none_unset = 107 [features.utf8_validation = NONE]; + + string ext_none_default = 108 [ + features.utf8_validation = NONE, + features.(pb.java).utf8_validation = DEFAULT + ]; + + string ext_none_verify = 109 [ + features.utf8_validation = NONE, + features.(pb.java).utf8_validation = VERIFY + ]; +} diff --git a/java/core/src/test/proto/com/google/protobuf/utf8validation/utf8_test_proto2.proto b/java/core/src/test/proto/com/google/protobuf/utf8validation/utf8_test_proto2.proto new file mode 100644 index 0000000000000..3d1bfc1266263 --- /dev/null +++ b/java/core/src/test/proto/com/google/protobuf/utf8validation/utf8_test_proto2.proto @@ -0,0 +1,27 @@ +syntax = "proto2"; + +package utf8validation; + +option java_package = "com.google.protobuf.utf8validation"; +option java_outer_classname = "Utf8TestProto2Proto"; +option java_multiple_files = true; + +message Utf8TestProto2 { + optional string unset_unset = 1; + + // TODO: Enable once allowlist entry is built into protoc. + // optional string unset_unenforced = 2 [enforce_utf8 = false]; + + optional string unset_enforced = 3 [enforce_utf8 = true]; + + extensions 100 to 200; +} + +extend Utf8TestProto2 { + optional string ext_unset_unset = 100; + + // TODO: Enable once allowlist entry is built into protoc. + // optional string ext_unset_unenforced = 101 [enforce_utf8 = false]; + + optional string ext_unset_enforced = 102 [enforce_utf8 = true]; +} diff --git a/java/core/src/test/proto/com/google/protobuf/utf8validation/utf8_test_proto2_checked.proto b/java/core/src/test/proto/com/google/protobuf/utf8validation/utf8_test_proto2_checked.proto new file mode 100644 index 0000000000000..bf11da5b66b53 --- /dev/null +++ b/java/core/src/test/proto/com/google/protobuf/utf8validation/utf8_test_proto2_checked.proto @@ -0,0 +1,25 @@ +syntax = "proto2"; + +package utf8validation; + +option java_package = "com.google.protobuf.utf8validation"; +option java_outer_classname = "Utf8TestProto2CheckedProto"; +option java_multiple_files = true; +option java_string_check_utf8 = true; + +message Utf8TestProto2Checked { + optional string checked_unset = 1; + + // TODO: Enable once allowlist entry is built into protoc. + // optional string checked_unenforced = 2 [enforce_utf8 = false]; + + optional string checked_enforced = 3 [enforce_utf8 = true]; + + extensions 100 to 200; +} + +extend Utf8TestProto2Checked { + optional string ext_checked_unset = 100; + // optional string ext_checked_unenforced = 101 [enforce_utf8 = false]; + optional string ext_checked_enforced = 102 [enforce_utf8 = true]; +} diff --git a/java/core/src/test/proto/com/google/protobuf/utf8validation/utf8_test_proto2_unchecked.proto b/java/core/src/test/proto/com/google/protobuf/utf8validation/utf8_test_proto2_unchecked.proto new file mode 100644 index 0000000000000..faa376b6ec7fa --- /dev/null +++ b/java/core/src/test/proto/com/google/protobuf/utf8validation/utf8_test_proto2_unchecked.proto @@ -0,0 +1,28 @@ +syntax = "proto2"; + +package utf8validation; + +option java_package = "com.google.protobuf.utf8validation"; +option java_outer_classname = "Utf8TestProto2UncheckedProto"; +option java_multiple_files = true; +option java_string_check_utf8 = false; + +message Utf8TestProto2Unchecked { + optional string unchecked_unset = 1; + + // TODO: Enable once allowlist entry is built into protoc. + // optional string unchecked_unenforced = 2 [enforce_utf8 = false]; + + optional string unchecked_enforced = 3 [enforce_utf8 = true]; + + extensions 100 to 200; +} + +extend Utf8TestProto2Unchecked { + optional string ext_unchecked_unset = 100; + + // TODO: Enable once allowlist entry is built into protoc. + // optional string ext_unchecked_unenforced = 101 [enforce_utf8 = false]; + + optional string ext_unchecked_enforced = 102 [enforce_utf8 = true]; +} diff --git a/java/core/src/test/proto/com/google/protobuf/utf8validation/utf8_test_proto3.proto b/java/core/src/test/proto/com/google/protobuf/utf8validation/utf8_test_proto3.proto new file mode 100644 index 0000000000000..594ee7c9544b9 --- /dev/null +++ b/java/core/src/test/proto/com/google/protobuf/utf8validation/utf8_test_proto3.proto @@ -0,0 +1,16 @@ +syntax = "proto3"; + +package utf8validation; + +option java_package = "com.google.protobuf.utf8validation"; +option java_outer_classname = "Utf8TestProto3Proto"; +option java_multiple_files = true; + +message Utf8TestProto3 { + optional string unset_unset = 1; + + // TODO: Enable once allowlist entry is built into protoc. + // optional string unset_unenforced = 2 [enforce_utf8 = false]; + + optional string unset_enforced = 3 [enforce_utf8 = true]; +} diff --git a/java/core/src/test/proto/com/google/protobuf/utf8validation/utf8_test_proto3_checked.proto b/java/core/src/test/proto/com/google/protobuf/utf8validation/utf8_test_proto3_checked.proto new file mode 100644 index 0000000000000..86536dde01ff9 --- /dev/null +++ b/java/core/src/test/proto/com/google/protobuf/utf8validation/utf8_test_proto3_checked.proto @@ -0,0 +1,17 @@ +syntax = "proto3"; + +package utf8validation; + +option java_package = "com.google.protobuf.utf8validation"; +option java_outer_classname = "Utf8TestProto3CheckedProto"; +option java_multiple_files = true; +option java_string_check_utf8 = true; + +message Utf8TestProto3Checked { + optional string checked_unset = 1; + + // TODO: Enable once allowlist entry is built into protoc. + // optional string checked_unenforced = 2 [enforce_utf8 = false]; + + optional string checked_enforced = 3 [enforce_utf8 = true]; +} diff --git a/java/core/src/test/proto/com/google/protobuf/utf8validation/utf8_test_proto3_unchecked.proto b/java/core/src/test/proto/com/google/protobuf/utf8validation/utf8_test_proto3_unchecked.proto new file mode 100644 index 0000000000000..5f4b472705641 --- /dev/null +++ b/java/core/src/test/proto/com/google/protobuf/utf8validation/utf8_test_proto3_unchecked.proto @@ -0,0 +1,17 @@ +syntax = "proto3"; + +package utf8validation; + +option java_package = "com.google.protobuf.utf8validation"; +option java_outer_classname = "Utf8TestProto3UncheckedProto"; +option java_multiple_files = true; +option java_string_check_utf8 = false; + +message Utf8TestProto3Unchecked { + optional string unchecked_unset = 1; + + // TODO: Enable once allowlist entry is built into protoc. + // optional string unchecked_unenforced = 2 [enforce_utf8 = false]; + + optional string unchecked_enforced = 3 [enforce_utf8 = true]; +}