• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc.  All rights reserved.
3 //
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file or at
6 // https://developers.google.com/open-source/licenses/bsd
7 
8 package com.google.protobuf;
9 
10 import static com.google.common.truth.Truth.assertThat;
11 import static com.google.common.truth.Truth.assertWithMessage;
12 import static com.google.protobuf.TestUtil.TEST_REQUIRED_INITIALIZED;
13 import static com.google.protobuf.TestUtil.TEST_REQUIRED_UNINITIALIZED;
14 import static protobuf_unittest.UnittestProto.optionalInt32Extension;
15 import static org.junit.Assert.assertThrows;
16 
17 import com.google.protobuf.DescriptorProtos.DescriptorProto;
18 import com.google.protobuf.DescriptorProtos.FieldDescriptorProto;
19 import com.google.protobuf.DescriptorProtos.FileDescriptorProto;
20 import com.google.protobuf.Descriptors.Descriptor;
21 import com.google.protobuf.Descriptors.FieldDescriptor;
22 import com.google.protobuf.Descriptors.FileDescriptor;
23 import com.google.protobuf.TextFormat.InvalidEscapeSequenceException;
24 import com.google.protobuf.TextFormat.Parser.SingularOverwritePolicy;
25 import com.google.protobuf.testing.proto.TestProto3Optional;
26 import com.google.protobuf.testing.proto.TestProto3Optional.NestedEnum;
27 import any_test.AnyTestProto.TestAny;
28 import editions_unittest.GroupLikeFileScope;
29 import editions_unittest.MessageImport;
30 import editions_unittest.NotGroupLikeScope;
31 import editions_unittest.TestDelimited;
32 import editions_unittest.UnittestDelimited;
33 import map_test.MapTestProto.TestMap;
34 import protobuf_unittest.UnittestMset.TestMessageSetExtension1;
35 import protobuf_unittest.UnittestMset.TestMessageSetExtension2;
36 import protobuf_unittest.UnittestProto.OneString;
37 import protobuf_unittest.UnittestProto.TestAllExtensions;
38 import protobuf_unittest.UnittestProto.TestAllTypes;
39 import protobuf_unittest.UnittestProto.TestAllTypes.NestedMessage;
40 import protobuf_unittest.UnittestProto.TestEmptyMessage;
41 import protobuf_unittest.UnittestProto.TestOneof2;
42 import protobuf_unittest.UnittestProto.TestRecursiveMessage;
43 import protobuf_unittest.UnittestProto.TestRequired;
44 import protobuf_unittest.UnittestProto.TestReservedFields;
45 import proto2_wireformat_unittest.UnittestMsetWireFormat.TestMessageSet;
46 import java.io.StringReader;
47 import java.util.Arrays;
48 import java.util.List;
49 import java.util.logging.Logger;
50 import org.junit.Test;
51 import org.junit.function.ThrowingRunnable;
52 import org.junit.runner.RunWith;
53 import org.junit.runners.JUnit4;
54 
55 /** Test case for {@link TextFormat}. */
56 @RunWith(JUnit4.class)
57 public class TextFormatTest {
58 
59   // A basic string with different escapable characters for testing.
60   private static final String ESCAPE_TEST_STRING =
61       "\"A string with ' characters \n and \r newlines and \t tabs and \001 slashes \\";
62 
63   // A representation of the above string with all the characters escaped.
64   private static final String ESCAPE_TEST_STRING_ESCAPED =
65       "\\\"A string with \\' characters \\n and \\r newlines "
66           + "and \\t tabs and \\001 slashes \\\\";
67 
68   private static final String EXOTIC_TEXT =
69       ""
70           + "repeated_int32: -1\n"
71           + "repeated_int32: -2147483648\n"
72           + "repeated_int64: -1,\n"
73           + "repeated_int64: -9223372036854775808\n"
74           + "repeated_uint32: 4294967295\n"
75           + "repeated_uint32: 2147483648\n"
76           + "repeated_uint64: 18446744073709551615\n"
77           + "repeated_uint64: 9223372036854775808\n"
78           + "repeated_double: 123.0\n"
79           + "repeated_double: 123.5\n"
80           + "repeated_double: 0.125\n"
81           + "repeated_double: .125\n"
82           + "repeated_double: -.125\n"
83           + "repeated_double: 1.23E17\n"
84           + "repeated_double: 1.23E+17\n"
85           + "repeated_double: -1.23e-17\n"
86           + "repeated_double: .23e+17\n"
87           + "repeated_double: -.23E17\n"
88           + "repeated_double: 1.235E22\n"
89           + "repeated_double: 1.235E-18\n"
90           + "repeated_double: 123.456789\n"
91           + "repeated_double: Infinity\n"
92           + "repeated_double: -Infinity\n"
93           + "repeated_double: NaN\n"
94           + "repeated_string: \"\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\""
95           + "\\341\\210\\264\"\n"
96           + "repeated_bytes: \"\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\"\\376\"\n";
97 
98   private static final String CANONICAL_EXOTIC_TEXT =
99       EXOTIC_TEXT
100           .replace(": .", ": 0.")
101           .replace(": -.", ": -0.") // short-form double
102           .replace("23e", "23E")
103           .replace("E+", "E")
104           .replace("0.23E17", "2.3E16")
105           .replace(",", "");
106 
107   private static final String MESSAGE_SET_TEXT =
108       ""
109           + "[protobuf_unittest.TestMessageSetExtension1] {\n"
110           + "  i: 123\n"
111           + "}\n"
112           + "[protobuf_unittest.TestMessageSetExtension2] {\n"
113           + "  str: \"foo\"\n"
114           + "}\n";
115 
116   private static final String MESSAGE_SET_TEXT_WITH_REPEATED_EXTENSION =
117       ""
118           + "[protobuf_unittest.TestMessageSetExtension1] {\n"
119           + "  i: 123\n"
120           + "}\n"
121           + "[protobuf_unittest.TestMessageSetExtension1] {\n"
122           + "  i: 456\n"
123           + "}\n";
124 
125   private static final TextFormat.Parser PARSER_ALLOWING_UNKNOWN_FIELDS =
126       TextFormat.Parser.newBuilder().setAllowUnknownFields(true).build();
127 
128   private static final TextFormat.Parser PARSER_ALLOWING_UNKNOWN_EXTENSIONS =
129       TextFormat.Parser.newBuilder().setAllowUnknownExtensions(true).build();
130 
131   private static final TextFormat.Parser PARSER_WITH_OVERWRITE_FORBIDDEN =
132       TextFormat.Parser.newBuilder()
133           .setSingularOverwritePolicy(SingularOverwritePolicy.FORBID_SINGULAR_OVERWRITES)
134           .build();
135 
136   private static final TextFormat.Parser DEFAULT_PARSER = TextFormat.Parser.newBuilder().build();
137 
138   /** Print TestAllTypes and compare with golden file. */
139   @Test
testPrintMessage()140   public void testPrintMessage() throws Exception {
141     String javaText = TextFormat.printer().printToString(TestUtil.getAllSet());
142 
143     assertThat(javaText).isEqualTo(TestUtil.ALL_FIELDS_SET_TEXT);
144   }
145 
146   @Test
147   // https://github.com/protocolbuffers/protobuf/issues/9447
testCharacterNotInUnicodeBlock()148   public void testCharacterNotInUnicodeBlock() throws TextFormat.InvalidEscapeSequenceException {
149     ByteString actual = TextFormat.unescapeBytes("\\U000358da");
150     assertThat(actual.size()).isEqualTo(4);
151   }
152 
153   /** Print TestAllTypes as Builder and compare with golden file. */
154   @Test
testPrintMessageBuilder()155   public void testPrintMessageBuilder() throws Exception {
156     String javaText = TextFormat.printer().printToString(TestUtil.getAllSetBuilder());
157 
158     assertThat(javaText).isEqualTo(TestUtil.ALL_FIELDS_SET_TEXT);
159   }
160 
161   /** Print TestAllExtensions and compare with golden file. */
162   @Test
testPrintExtensions()163   public void testPrintExtensions() throws Exception {
164     String javaText = TextFormat.printer().printToString(TestUtil.getAllExtensionsSet());
165 
166     assertThat(javaText).isEqualTo(TestUtil.ALL_EXTENSIONS_SET_TEXT);
167   }
168 
169   // Creates an example unknown field set.
makeUnknownFieldSet()170   private UnknownFieldSet makeUnknownFieldSet() {
171 
172     return UnknownFieldSet.newBuilder()
173         .addField(
174             5,
175             UnknownFieldSet.Field.newBuilder()
176                 .addVarint(1)
177                 .addFixed32(2)
178                 .addFixed64(3)
179                 .addLengthDelimited(ByteString.copyFromUtf8("4"))
180                 .addLengthDelimited(
181                     UnknownFieldSet.newBuilder()
182                         .addField(12, UnknownFieldSet.Field.newBuilder().addVarint(6).build())
183                         .build()
184                         .toByteString())
185                 .addGroup(
186                     UnknownFieldSet.newBuilder()
187                         .addField(10, UnknownFieldSet.Field.newBuilder().addVarint(5).build())
188                         .build())
189                 .build())
190         .addField(
191             8, UnknownFieldSet.Field.newBuilder().addVarint(1).addVarint(2).addVarint(3).build())
192         .addField(
193             15,
194             UnknownFieldSet.Field.newBuilder()
195                 .addVarint(0xABCDEF1234567890L)
196                 .addFixed32(0xABCD1234)
197                 .addFixed64(0xABCDEF1234567890L)
198                 .build())
199         .build();
200   }
201 
202   @Test
testPrintUnknownFields()203   public void testPrintUnknownFields() throws Exception {
204     // Test printing of unknown fields in a message.
205 
206     TestEmptyMessage message =
207         TestEmptyMessage.newBuilder().setUnknownFields(makeUnknownFieldSet()).build();
208 
209     assertThat(TextFormat.printer().printToString(message))
210         .isEqualTo(
211             "5: 1\n"
212                 + "5: 0x00000002\n"
213                 + "5: 0x0000000000000003\n"
214                 + "5: \"4\"\n"
215                 + "5: {\n"
216                 + "  12: 6\n"
217                 + "}\n"
218                 + "5 {\n"
219                 + "  10: 5\n"
220                 + "}\n"
221                 + "8: 1\n"
222                 + "8: 2\n"
223                 + "8: 3\n"
224                 + "15: 12379813812177893520\n"
225                 + "15: 0xabcd1234\n"
226                 + "15: 0xabcdef1234567890\n");
227   }
228 
229   @Test
testPrintField()230   public void testPrintField() throws Exception {
231     final FieldDescriptor dataField = OneString.getDescriptor().findFieldByName("data");
232     assertThat(TextFormat.printer().printFieldToString(dataField, "test data"))
233         .isEqualTo("data: \"test data\"\n");
234 
235     final FieldDescriptor optionalField =
236         TestAllTypes.getDescriptor().findFieldByName("optional_nested_message");
237     final Object value = NestedMessage.newBuilder().setBb(42).build();
238 
239     assertThat(TextFormat.printer().printFieldToString(optionalField, value))
240         .isEqualTo("optional_nested_message {\n  bb: 42\n}\n");
241   }
242 
243   /**
244    * Helper to construct a ByteString from a String containing only 8-bit characters. The characters
245    * are converted directly to bytes, *not* encoded using UTF-8.
246    */
bytes(String str)247   private ByteString bytes(String str) {
248     return ByteString.copyFrom(str.getBytes(Internal.ISO_8859_1));
249   }
250 
251   /**
252    * Helper to construct a ByteString from a bunch of bytes. The inputs are actually ints so that I
253    * can use hex notation and not get stupid errors about precision.
254    */
bytes(int... bytesAsInts)255   private ByteString bytes(int... bytesAsInts) {
256     byte[] bytes = new byte[bytesAsInts.length];
257     for (int i = 0; i < bytesAsInts.length; i++) {
258       bytes[i] = (byte) bytesAsInts[i];
259     }
260     return ByteString.copyFrom(bytes);
261   }
262 
263   @Test
testPrintExotic()264   public void testPrintExotic() throws Exception {
265     Message message =
266         TestAllTypes.newBuilder()
267             // Signed vs. unsigned numbers.
268             .addRepeatedInt32(-1)
269             .addRepeatedUint32(-1)
270             .addRepeatedInt64(-1)
271             .addRepeatedUint64(-1)
272             .addRepeatedInt32(1 << 31)
273             .addRepeatedUint32(1 << 31)
274             .addRepeatedInt64(1L << 63)
275             .addRepeatedUint64(1L << 63)
276 
277             // Floats of various precisions and exponents.
278             .addRepeatedDouble(123)
279             .addRepeatedDouble(123.5)
280             .addRepeatedDouble(0.125)
281             .addRepeatedDouble(.125)
282             .addRepeatedDouble(-.125)
283             .addRepeatedDouble(123e15)
284             .addRepeatedDouble(123e15)
285             .addRepeatedDouble(-1.23e-17)
286             .addRepeatedDouble(.23e17)
287             .addRepeatedDouble(-23e15)
288             .addRepeatedDouble(123.5e20)
289             .addRepeatedDouble(123.5e-20)
290             .addRepeatedDouble(123.456789)
291             .addRepeatedDouble(Double.POSITIVE_INFINITY)
292             .addRepeatedDouble(Double.NEGATIVE_INFINITY)
293             .addRepeatedDouble(Double.NaN)
294 
295             // Strings and bytes that needing escaping.
296             .addRepeatedString("\0\001\007\b\f\n\r\t\013\\\'\"\u1234")
297             .addRepeatedBytes(bytes("\0\001\007\b\f\n\r\t\013\\\'\"\u00fe"))
298             .build();
299 
300     assertThat(message.toString()).isEqualTo(CANONICAL_EXOTIC_TEXT);
301   }
302 
303   @Test
testRoundtripProto3Optional()304   public void testRoundtripProto3Optional() throws Exception {
305     Message message =
306         TestProto3Optional.newBuilder()
307             .setOptionalInt32(1)
308             .setOptionalInt64(2)
309             .setOptionalNestedEnum(NestedEnum.BAZ)
310             .build();
311     TestProto3Optional.Builder message2 = TestProto3Optional.newBuilder();
312     TextFormat.merge(message.toString(), message2);
313 
314     assertThat(message2.hasOptionalInt32()).isTrue();
315     assertThat(message2.hasOptionalInt64()).isTrue();
316     assertThat(message2.hasOptionalNestedEnum()).isTrue();
317     assertThat(message2.getOptionalInt32()).isEqualTo(1);
318     assertThat(message2.getOptionalInt64()).isEqualTo(2);
319     assertThat(message2.getOptionalNestedEnum()).isEqualTo(NestedEnum.BAZ);
320   }
321 
322   @Test
testPrintMessageSet()323   public void testPrintMessageSet() throws Exception {
324     TestMessageSet messageSet =
325         TestMessageSet.newBuilder()
326             .setExtension(
327                 TestMessageSetExtension1.messageSetExtension,
328                 TestMessageSetExtension1.newBuilder().setI(123).build())
329             .setExtension(
330                 TestMessageSetExtension2.messageSetExtension,
331                 TestMessageSetExtension2.newBuilder().setStr("foo").build())
332             .build();
333 
334     assertThat(messageSet.toString()).isEqualTo(MESSAGE_SET_TEXT);
335   }
336 
337   // =================================================================
338 
339   @Test
testMerge()340   public void testMerge() throws Exception {
341     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
342     TextFormat.merge(TestUtil.ALL_FIELDS_SET_TEXT, builder);
343     TestUtil.assertAllFieldsSet(builder.build());
344   }
345 
346   @Test
testParse()347   public void testParse() throws Exception {
348     TestUtil.assertAllFieldsSet(TextFormat.parse(TestUtil.ALL_FIELDS_SET_TEXT, TestAllTypes.class));
349   }
350 
351   @Test
testMergeInitialized()352   public void testMergeInitialized() throws Exception {
353     TestRequired.Builder builder = TestRequired.newBuilder();
354     TextFormat.merge(TEST_REQUIRED_INITIALIZED.toString(), builder);
355     assertThat(builder.buildPartial().toString()).isEqualTo(TEST_REQUIRED_INITIALIZED.toString());
356     assertThat(builder.isInitialized()).isTrue();
357   }
358 
359   @Test
testParseInitialized()360   public void testParseInitialized() throws Exception {
361     TestRequired parsed =
362         TextFormat.parse(TEST_REQUIRED_INITIALIZED.toString(), TestRequired.class);
363     assertThat(parsed.toString()).isEqualTo(TEST_REQUIRED_INITIALIZED.toString());
364     assertThat(parsed.isInitialized()).isTrue();
365   }
366 
367   @Test
testMergeUninitialized()368   public void testMergeUninitialized() throws Exception {
369     TestRequired.Builder builder = TestRequired.newBuilder();
370     TextFormat.merge(TEST_REQUIRED_UNINITIALIZED.toString(), builder);
371     assertThat(builder.buildPartial().toString()).isEqualTo(TEST_REQUIRED_UNINITIALIZED.toString());
372     assertThat(builder.isInitialized()).isFalse();
373   }
374 
375   @Test
testParseUninitialized()376   public void testParseUninitialized() throws Exception {
377     try {
378       TextFormat.parse(TEST_REQUIRED_UNINITIALIZED.toString(), TestRequired.class);
379       assertWithMessage("Expected UninitializedMessageException.").fail();
380     } catch (UninitializedMessageException e) {
381       assertThat(e).hasMessageThat().isEqualTo("Message missing required fields: b, c");
382     }
383   }
384 
385   @Test
testMergeReader()386   public void testMergeReader() throws Exception {
387     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
388     TextFormat.merge(new StringReader(TestUtil.ALL_FIELDS_SET_TEXT), builder);
389     TestUtil.assertAllFieldsSet(builder.build());
390   }
391 
392   @Test
testMergeExtensions()393   public void testMergeExtensions() throws Exception {
394     TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
395     TextFormat.merge(
396         TestUtil.ALL_EXTENSIONS_SET_TEXT, TestUtil.getFullExtensionRegistry(), builder);
397     TestUtil.assertAllExtensionsSet(builder.build());
398   }
399 
400   @Test
testParseExtensions()401   public void testParseExtensions() throws Exception {
402     TestUtil.assertAllExtensionsSet(
403         TextFormat.parse(
404             TestUtil.ALL_EXTENSIONS_SET_TEXT,
405             TestUtil.getFullExtensionRegistry(),
406             TestAllExtensions.class));
407   }
408 
409   @Test
testMergeAndParseCompatibility()410   public void testMergeAndParseCompatibility() throws Exception {
411     String original =
412         "repeated_float: inf\n"
413             + "repeated_float: -inf\n"
414             + "repeated_float: nan\n"
415             + "repeated_float: inff\n"
416             + "repeated_float: -inff\n"
417             + "repeated_float: nanf\n"
418             + "repeated_float: 1.0f\n"
419             + "repeated_float: infinityf\n"
420             + "repeated_float: -Infinityf\n"
421             + "repeated_double: infinity\n"
422             + "repeated_double: -infinity\n"
423             + "repeated_double: nan\n";
424     String canonical =
425         "repeated_float: Infinity\n"
426             + "repeated_float: -Infinity\n"
427             + "repeated_float: NaN\n"
428             + "repeated_float: Infinity\n"
429             + "repeated_float: -Infinity\n"
430             + "repeated_float: NaN\n"
431             + "repeated_float: 1.0\n"
432             + "repeated_float: Infinity\n"
433             + "repeated_float: -Infinity\n"
434             + "repeated_double: Infinity\n"
435             + "repeated_double: -Infinity\n"
436             + "repeated_double: NaN\n";
437 
438     // Test merge().
439     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
440     TextFormat.merge(original, builder);
441     assertThat(builder.build().toString()).isEqualTo(canonical);
442 
443     // Test parse().
444     assertThat(TextFormat.parse(original, TestAllTypes.class).toString()).isEqualTo(canonical);
445   }
446 
447   @Test
testMergeAndParseExotic()448   public void testMergeAndParseExotic() throws Exception {
449     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
450     TextFormat.merge(EXOTIC_TEXT, builder);
451 
452     // Too lazy to check things individually.  Don't try to debug this
453     // if testPrintExotic() is failing.
454     assertThat(builder.build().toString()).isEqualTo(CANONICAL_EXOTIC_TEXT);
455     assertThat(TextFormat.parse(EXOTIC_TEXT, TestAllTypes.class).toString())
456         .isEqualTo(CANONICAL_EXOTIC_TEXT);
457   }
458 
459   @Test
testMergeMessageSet()460   public void testMergeMessageSet() throws Exception {
461     ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance();
462     extensionRegistry.add(TestMessageSetExtension1.messageSetExtension);
463     extensionRegistry.add(TestMessageSetExtension2.messageSetExtension);
464 
465     TestMessageSet.Builder builder = TestMessageSet.newBuilder();
466     TextFormat.merge(MESSAGE_SET_TEXT, extensionRegistry, builder);
467     TestMessageSet messageSet = builder.build();
468 
469     assertThat(messageSet.hasExtension(TestMessageSetExtension1.messageSetExtension)).isTrue();
470     assertThat(messageSet.getExtension(TestMessageSetExtension1.messageSetExtension).getI())
471         .isEqualTo(123);
472     assertThat(messageSet.hasExtension(TestMessageSetExtension2.messageSetExtension)).isTrue();
473     assertThat(messageSet.getExtension(TestMessageSetExtension2.messageSetExtension).getStr())
474         .isEqualTo("foo");
475 
476     builder = TestMessageSet.newBuilder();
477     TextFormat.merge(MESSAGE_SET_TEXT_WITH_REPEATED_EXTENSION, extensionRegistry, builder);
478     messageSet = builder.build();
479     assertThat(messageSet.getExtension(TestMessageSetExtension1.messageSetExtension).getI())
480         .isEqualTo(456);
481   }
482 
483   @Test
testMergeMessageSetWithOverwriteForbidden()484   public void testMergeMessageSetWithOverwriteForbidden() throws Exception {
485     ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance();
486     extensionRegistry.add(TestMessageSetExtension1.messageSetExtension);
487     extensionRegistry.add(TestMessageSetExtension2.messageSetExtension);
488 
489     TestMessageSet.Builder builder = TestMessageSet.newBuilder();
490     PARSER_WITH_OVERWRITE_FORBIDDEN.merge(MESSAGE_SET_TEXT, extensionRegistry, builder);
491     TestMessageSet messageSet = builder.build();
492     assertThat(messageSet.getExtension(TestMessageSetExtension1.messageSetExtension).getI())
493         .isEqualTo(123);
494     assertThat(messageSet.getExtension(TestMessageSetExtension2.messageSetExtension).getStr())
495         .isEqualTo("foo");
496 
497     builder = TestMessageSet.newBuilder();
498     try {
499       PARSER_WITH_OVERWRITE_FORBIDDEN.merge(
500           MESSAGE_SET_TEXT_WITH_REPEATED_EXTENSION, extensionRegistry, builder);
501       assertWithMessage("expected parse exception").fail();
502     } catch (TextFormat.ParseException e) {
503       assertThat(e)
504           .hasMessageThat()
505           .isEqualTo(
506               "4:44: Non-repeated field "
507                   + "\"protobuf_unittest.TestMessageSetExtension1.message_set_extension\""
508                   + " cannot be overwritten.");
509     }
510   }
511 
512   @Test
testMergeNumericEnum()513   public void testMergeNumericEnum() throws Exception {
514     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
515     TextFormat.merge("optional_nested_enum: 2", builder);
516     assertThat(builder.getOptionalNestedEnum()).isEqualTo(TestAllTypes.NestedEnum.BAR);
517   }
518 
519   @Test
testMergeAngleBrackets()520   public void testMergeAngleBrackets() throws Exception {
521     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
522     TextFormat.merge("OptionalGroup: < a: 1 >", builder);
523     assertThat(builder.hasOptionalGroup()).isTrue();
524     assertThat(builder.getOptionalGroup().getA()).isEqualTo(1);
525   }
526 
527   @Test
testMergeComment()528   public void testMergeComment() throws Exception {
529     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
530     TextFormat.merge(
531         "# this is a comment\n"
532             + "optional_int32: 1  # another comment\n"
533             + "optional_int64: 2\n"
534             + "# EOF comment",
535         builder);
536     assertThat(builder.getOptionalInt32()).isEqualTo(1);
537     assertThat(builder.getOptionalInt64()).isEqualTo(2);
538   }
539 
540   @Test
testPrintAny_customBuiltTypeRegistry()541   public void testPrintAny_customBuiltTypeRegistry() throws Exception {
542     TestAny testAny =
543         TestAny.newBuilder()
544             .setValue(
545                 Any.newBuilder()
546                     .setTypeUrl("type.googleapis.com/" + TestAllTypes.getDescriptor().getFullName())
547                     .setValue(
548                         TestAllTypes.newBuilder().setOptionalInt32(12345).build().toByteString())
549                     .build())
550             .build();
551     String actual =
552         TextFormat.printer()
553             .usingTypeRegistry(TypeRegistry.newBuilder().add(TestAllTypes.getDescriptor()).build())
554             .printToString(testAny);
555     String expected =
556         "value {\n"
557             + "  [type.googleapis.com/protobuf_unittest.TestAllTypes] {\n"
558             + "    optional_int32: 12345\n"
559             + "  }\n"
560             + "}\n";
561     assertThat(actual).isEqualTo(expected);
562   }
563 
createDescriptorForAny(FieldDescriptorProto... fields)564   private static Descriptor createDescriptorForAny(FieldDescriptorProto... fields)
565       throws Exception {
566     FileDescriptor fileDescriptor =
567         FileDescriptor.buildFrom(
568             FileDescriptorProto.newBuilder()
569                 .setName("any.proto")
570                 .setPackage("google.protobuf")
571                 .setSyntax("proto3")
572                 .addMessageType(
573                     DescriptorProto.newBuilder().setName("Any").addAllField(Arrays.asList(fields)))
574                 .build(),
575             new FileDescriptor[0]);
576     return fileDescriptor.getMessageTypes().get(0);
577   }
578 
579   @Test
testPrintAny_anyWithDynamicMessage()580   public void testPrintAny_anyWithDynamicMessage() throws Exception {
581     Descriptor descriptor =
582         createDescriptorForAny(
583             FieldDescriptorProto.newBuilder()
584                 .setName("type_url")
585                 .setNumber(1)
586                 .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
587                 .setType(FieldDescriptorProto.Type.TYPE_STRING)
588                 .build(),
589             FieldDescriptorProto.newBuilder()
590                 .setName("value")
591                 .setNumber(2)
592                 .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
593                 .setType(FieldDescriptorProto.Type.TYPE_BYTES)
594                 .build());
595     DynamicMessage testAny =
596         DynamicMessage.newBuilder(descriptor)
597             .setField(
598                 descriptor.findFieldByNumber(1),
599                 "type.googleapis.com/" + TestAllTypes.getDescriptor().getFullName())
600             .setField(
601                 descriptor.findFieldByNumber(2),
602                 TestAllTypes.newBuilder().setOptionalInt32(12345).build().toByteString())
603             .build();
604     String actual =
605         TextFormat.printer()
606             .usingTypeRegistry(TypeRegistry.newBuilder().add(TestAllTypes.getDescriptor()).build())
607             .printToString(testAny);
608     String expected =
609         "[type.googleapis.com/protobuf_unittest.TestAllTypes] {\n"
610             + "  optional_int32: 12345\n"
611             + "}\n";
612     assertThat(actual).isEqualTo(expected);
613   }
614 
615   @Test
testPrintAny_anyWithDynamicMessageContainingExtensionTreatedAsUnknown()616   public void testPrintAny_anyWithDynamicMessageContainingExtensionTreatedAsUnknown()
617       throws Exception {
618     Descriptor descriptor =
619         createDescriptorForAny(
620             FieldDescriptorProto.newBuilder()
621                 .setName("type_url")
622                 .setNumber(1)
623                 .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
624                 .setType(FieldDescriptorProto.Type.TYPE_STRING)
625                 .build(),
626             FieldDescriptorProto.newBuilder()
627                 .setName("value")
628                 .setNumber(2)
629                 .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
630                 .setType(FieldDescriptorProto.Type.TYPE_BYTES)
631                 .build());
632     DynamicMessage testAny =
633         DynamicMessage.newBuilder(descriptor)
634             .setField(
635                 descriptor.findFieldByNumber(1),
636                 "type.googleapis.com/" + TestAllExtensions.getDescriptor().getFullName())
637             .setField(
638                 descriptor.findFieldByNumber(2),
639                 TestAllExtensions.newBuilder()
640                     .setExtension(optionalInt32Extension, 12345)
641                     .build()
642                     .toByteString())
643             .build();
644     String actual =
645         TextFormat.printer()
646             .usingTypeRegistry(TypeRegistry.newBuilder().add(TestAllTypes.getDescriptor()).build())
647             .printToString(testAny);
648     String expected = "[type.googleapis.com/protobuf_unittest.TestAllExtensions] {\n  1: 12345\n}\n";
649     assertThat(actual).isEqualTo(expected);
650   }
651 
652   @Test
testPrintAny_anyWithDynamicMessageContainingExtensionWithRegistry()653   public void testPrintAny_anyWithDynamicMessageContainingExtensionWithRegistry() throws Exception {
654     Descriptor descriptor =
655         createDescriptorForAny(
656             FieldDescriptorProto.newBuilder()
657                 .setName("type_url")
658                 .setNumber(1)
659                 .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
660                 .setType(FieldDescriptorProto.Type.TYPE_STRING)
661                 .build(),
662             FieldDescriptorProto.newBuilder()
663                 .setName("value")
664                 .setNumber(2)
665                 .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
666                 .setType(FieldDescriptorProto.Type.TYPE_BYTES)
667                 .build());
668     DynamicMessage testAny =
669         DynamicMessage.newBuilder(descriptor)
670             .setField(
671                 descriptor.findFieldByNumber(1),
672                 "type.googleapis.com/" + TestAllExtensions.getDescriptor().getFullName())
673             .setField(
674                 descriptor.findFieldByNumber(2),
675                 TestAllExtensions.newBuilder()
676                     .setExtension(optionalInt32Extension, 12345)
677                     .build()
678                     .toByteString())
679             .build();
680     String actual =
681         TextFormat.printer()
682             .usingTypeRegistry(TypeRegistry.newBuilder().add(TestAllTypes.getDescriptor()).build())
683             .usingExtensionRegistry(TestUtil.getFullExtensionRegistry())
684             .printToString(testAny);
685     String expected =
686         "[type.googleapis.com/protobuf_unittest.TestAllExtensions] {\n"
687             + "  [protobuf_unittest.optional_int32_extension]: 12345\n"
688             + "}\n";
689     assertThat(actual).isEqualTo(expected);
690   }
691 
692   @Test
testPrintAny_anyFromWithNoValueField()693   public void testPrintAny_anyFromWithNoValueField() throws Exception {
694     Descriptor descriptor =
695         createDescriptorForAny(
696             FieldDescriptorProto.newBuilder()
697                 .setName("type_url")
698                 .setNumber(1)
699                 .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
700                 .setType(FieldDescriptorProto.Type.TYPE_STRING)
701                 .build());
702     DynamicMessage testAny =
703         DynamicMessage.newBuilder(descriptor)
704             .setField(
705                 descriptor.findFieldByNumber(1),
706                 "type.googleapis.com/" + TestAllTypes.getDescriptor().getFullName())
707             .build();
708     String actual =
709         TextFormat.printer()
710             .usingTypeRegistry(TypeRegistry.newBuilder().add(TestAllTypes.getDescriptor()).build())
711             .printToString(testAny);
712     String expected = "type_url: \"type.googleapis.com/protobuf_unittest.TestAllTypes\"\n";
713     assertThat(actual).isEqualTo(expected);
714   }
715 
716   @Test
testPrintAny_anyFromWithNoTypeUrlField()717   public void testPrintAny_anyFromWithNoTypeUrlField() throws Exception {
718     Descriptor descriptor =
719         createDescriptorForAny(
720             FieldDescriptorProto.newBuilder()
721                 .setName("value")
722                 .setNumber(2)
723                 .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
724                 .setType(FieldDescriptorProto.Type.TYPE_BYTES)
725                 .build());
726     DynamicMessage testAny =
727         DynamicMessage.newBuilder(descriptor)
728             .setField(
729                 descriptor.findFieldByNumber(2),
730                 TestAllTypes.newBuilder().setOptionalInt32(12345).build().toByteString())
731             .build();
732     String actual =
733         TextFormat.printer()
734             .usingTypeRegistry(TypeRegistry.newBuilder().add(TestAllTypes.getDescriptor()).build())
735             .printToString(testAny);
736     String expected = "value: \"\\b\\271`\"\n";
737     assertThat(actual).isEqualTo(expected);
738   }
739 
740   @Test
testPrintAny_anyWithInvalidFieldType()741   public void testPrintAny_anyWithInvalidFieldType() throws Exception {
742     Descriptor descriptor =
743         createDescriptorForAny(
744             FieldDescriptorProto.newBuilder()
745                 .setName("type_url")
746                 .setNumber(1)
747                 .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
748                 .setType(FieldDescriptorProto.Type.TYPE_STRING)
749                 .build(),
750             FieldDescriptorProto.newBuilder()
751                 .setName("value")
752                 .setNumber(2)
753                 .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
754                 .setType(FieldDescriptorProto.Type.TYPE_STRING)
755                 .build());
756     DynamicMessage testAny =
757         DynamicMessage.newBuilder(descriptor)
758             .setField(
759                 descriptor.findFieldByNumber(1),
760                 "type.googleapis.com/" + TestAllTypes.getDescriptor().getFullName())
761             .setField(descriptor.findFieldByNumber(2), "test")
762             .build();
763     String actual =
764         TextFormat.printer()
765             .usingTypeRegistry(TypeRegistry.newBuilder().add(TestAllTypes.getDescriptor()).build())
766             .printToString(testAny);
767     String expected =
768         "type_url: \"type.googleapis.com/protobuf_unittest.TestAllTypes\"\n" + "value: \"test\"\n";
769     assertThat(actual).isEqualTo(expected);
770   }
771 
772   @Test
testMergeAny_customBuiltTypeRegistry()773   public void testMergeAny_customBuiltTypeRegistry() throws Exception {
774     TestAny.Builder builder = TestAny.newBuilder();
775     TextFormat.Parser.newBuilder()
776         .setTypeRegistry(TypeRegistry.newBuilder().add(TestAllTypes.getDescriptor()).build())
777         .build()
778         .merge(
779             "value: {\n"
780                 + "[type.googleapis.com/protobuf_unittest.TestAllTypes] {\n"
781                 + "optional_int32: 12345\n"
782                 + "optional_nested_message {\n"
783                 + "  bb: 123\n"
784                 + "}\n"
785                 + "}\n"
786                 + "}",
787             builder);
788     assertThat(builder.build())
789         .isEqualTo(
790             TestAny.newBuilder()
791                 .setValue(
792                     Any.newBuilder()
793                         .setTypeUrl(
794                             "type.googleapis.com/" + TestAllTypes.getDescriptor().getFullName())
795                         .setValue(
796                             TestAllTypes.newBuilder()
797                                 .setOptionalInt32(12345)
798                                 .setOptionalNestedMessage(
799                                     TestAllTypes.NestedMessage.newBuilder().setBb(123))
800                                 .build()
801                                 .toByteString())
802                         .build())
803                 .build());
804   }
805 
assertParseError(String error, String text)806   private void assertParseError(String error, String text) {
807     // Test merge().
808     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
809     try {
810       TextFormat.merge(text, TestUtil.getFullExtensionRegistry(), builder);
811       assertWithMessage("Expected parse exception.").fail();
812     } catch (TextFormat.ParseException e) {
813       assertThat(e).hasMessageThat().isEqualTo(error);
814     }
815 
816     // Test parse().
817     try {
818       TextFormat.parse(text, TestUtil.getFullExtensionRegistry(), TestAllTypes.class);
819       assertWithMessage("Expected parse exception.").fail();
820     } catch (TextFormat.ParseException e) {
821       assertThat(e).hasMessageThat().isEqualTo(error);
822     }
823   }
824 
assertParseErrorWithUnknownFields(String error, String text)825   private void assertParseErrorWithUnknownFields(String error, String text) {
826     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
827     try {
828       PARSER_ALLOWING_UNKNOWN_FIELDS.merge(text, TestUtil.getFullExtensionRegistry(), builder);
829       assertWithMessage("Expected parse exception.").fail();
830     } catch (TextFormat.ParseException e) {
831       assertThat(e).hasMessageThat().isEqualTo(error);
832     }
833   }
834 
assertParseSuccessWithUnknownFields(String text)835   private TestAllTypes assertParseSuccessWithUnknownFields(String text)
836       throws TextFormat.ParseException {
837     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
838     PARSER_ALLOWING_UNKNOWN_FIELDS.merge(text, TestUtil.getFullExtensionRegistry(), builder);
839     return builder.build();
840   }
841 
assertParseErrorWithUnknownExtensions(String error, String text)842   private void assertParseErrorWithUnknownExtensions(String error, String text) {
843     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
844     try {
845       PARSER_ALLOWING_UNKNOWN_EXTENSIONS.merge(text, builder);
846       assertWithMessage("Expected parse exception.").fail();
847     } catch (TextFormat.ParseException e) {
848       assertThat(e).hasMessageThat().isEqualTo(error);
849     }
850   }
851 
assertParseSuccessWithUnknownExtensions(String text)852   private TestAllTypes assertParseSuccessWithUnknownExtensions(String text)
853       throws TextFormat.ParseException {
854     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
855     PARSER_ALLOWING_UNKNOWN_EXTENSIONS.merge(text, builder);
856     return builder.build();
857   }
858 
assertParseErrorWithOverwriteForbidden(String error, String text)859   private void assertParseErrorWithOverwriteForbidden(String error, String text) {
860     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
861     try {
862       PARSER_WITH_OVERWRITE_FORBIDDEN.merge(text, TestUtil.getFullExtensionRegistry(), builder);
863       assertWithMessage("Expected parse exception.").fail();
864     } catch (TextFormat.ParseException e) {
865       assertThat(e).hasMessageThat().isEqualTo(error);
866     }
867   }
868 
869   @CanIgnoreReturnValue
assertParseSuccessWithOverwriteForbidden(String text)870   private TestAllTypes assertParseSuccessWithOverwriteForbidden(String text)
871       throws TextFormat.ParseException {
872     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
873     PARSER_WITH_OVERWRITE_FORBIDDEN.merge(text, TestUtil.getFullExtensionRegistry(), builder);
874     return builder.build();
875   }
876 
877   @Test
testParseErrors()878   public void testParseErrors() throws Exception {
879     assertParseError("1:16: Expected \":\".", "optional_int32 123");
880     assertParseError("1:23: Expected identifier. Found '?'", "optional_nested_enum: ?");
881     assertParseError(
882         "1:18: Couldn't parse integer: Number must be positive: -1", "optional_uint32: -1");
883     assertParseError(
884         "1:17: Couldn't parse integer: Number out of range for 32-bit signed "
885             + "integer: 82301481290849012385230157",
886         "optional_int32: 82301481290849012385230157");
887     assertParseError(
888         "1:16: Expected \"true\" or \"false\". Found \"maybe\".", "optional_bool: maybe");
889     assertParseError("1:16: Expected \"true\" or \"false\". Found \"2\".", "optional_bool: 2");
890     assertParseError("1:18: Expected string.", "optional_string: 123");
891     assertParseError("1:18: String missing ending quote.", "optional_string: \"ueoauaoe");
892     assertParseError(
893         "1:18: String missing ending quote.", "optional_string: \"ueoauaoe\noptional_int32: 123");
894     assertParseError("1:18: Invalid escape sequence: '\\z'", "optional_string: \"\\z\"");
895     assertParseError(
896         "1:18: String missing ending quote.", "optional_string: \"ueoauaoe\noptional_int32: 123");
897     assertParseError(
898         "1:2: Input contains unknown fields and/or extensions:\n"
899             + "1:2:\tprotobuf_unittest.TestAllTypes.[nosuchext]",
900         "[nosuchext]: 123");
901     assertParseError(
902         "1:20: Extension \"protobuf_unittest.optional_int32_extension\" does "
903             + "not extend message type \"protobuf_unittest.TestAllTypes\".",
904         "[protobuf_unittest.optional_int32_extension]: 123");
905     assertParseError(
906         "1:1: Input contains unknown fields and/or extensions:\n"
907             + "1:1:\tprotobuf_unittest.TestAllTypes.nosuchfield",
908         "nosuchfield: 123");
909     assertParseError("1:21: Expected \">\".", "OptionalGroup < a: 1");
910     assertParseError(
911         "1:23: Enum type \"protobuf_unittest.TestAllTypes.NestedEnum\" has no "
912             + "value named \"NO_SUCH_VALUE\".",
913         "optional_nested_enum: NO_SUCH_VALUE");
914     assertParseError(
915         "1:23: Enum type \"protobuf_unittest.TestAllTypes.NestedEnum\" has no "
916             + "value with number 123.",
917         "optional_nested_enum: 123");
918 
919     // Delimiters must match.
920     assertParseError("1:22: Expected identifier. Found '}'", "OptionalGroup < a: 1 }");
921     assertParseError("1:22: Expected identifier. Found '>'", "OptionalGroup { a: 1 >");
922   }
923 
924   // =================================================================
925   @Test
testEscapeQuestionMark()926   public void testEscapeQuestionMark() throws InvalidEscapeSequenceException {
927     assertThat(TextFormat.unescapeText("?")).isEqualTo("?");
928     assertThat(TextFormat.unescapeText("\\?")).isEqualTo("?");
929   }
930 
931   @Test
testEscape()932   public void testEscape() throws Exception {
933     // Escape sequences.
934     assertThat(TextFormat.escapeBytes(bytes("\0\001\007\b\f\n\r\t\013\\\'\"\177")))
935         .isEqualTo("\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\"\\177");
936     assertThat(TextFormat.escapeText("\0\001\007\b\f\n\r\t\013\\\'\"\177"))
937         .isEqualTo("\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\"\\177");
938     assertThat(TextFormat.unescapeBytes("\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\""))
939         .isEqualTo(bytes("\0\001\007\b\f\n\r\t\013\\\'\""));
940     assertThat(TextFormat.unescapeText("\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\""))
941         .isEqualTo("\0\001\007\b\f\n\r\t\013\\\'\"");
942     assertThat(TextFormat.escapeText(ESCAPE_TEST_STRING)).isEqualTo(ESCAPE_TEST_STRING_ESCAPED);
943     assertThat(TextFormat.unescapeText(ESCAPE_TEST_STRING_ESCAPED)).isEqualTo(ESCAPE_TEST_STRING);
944 
945     // Invariant
946     assertThat(TextFormat.escapeBytes(bytes("hello"))).isEqualTo("hello");
947     assertThat(TextFormat.escapeText("hello")).isEqualTo("hello");
948     assertThat(TextFormat.unescapeBytes("hello")).isEqualTo(bytes("hello"));
949     assertThat(TextFormat.unescapeText("hello")).isEqualTo("hello");
950 
951     // Unicode handling.
952     assertThat(TextFormat.escapeText("\u1234")).isEqualTo("\\341\\210\\264");
953     assertThat(TextFormat.escapeBytes(bytes(0xe1, 0x88, 0xb4))).isEqualTo("\\341\\210\\264");
954     assertThat(TextFormat.unescapeText("\\341\\210\\264")).isEqualTo("\u1234");
955     assertThat(TextFormat.unescapeBytes("\\341\\210\\264")).isEqualTo(bytes(0xe1, 0x88, 0xb4));
956     assertThat(TextFormat.unescapeText("\\xe1\\x88\\xb4")).isEqualTo("\u1234");
957     assertThat(TextFormat.unescapeBytes("\\xe1\\x88\\xb4")).isEqualTo(bytes(0xe1, 0x88, 0xb4));
958     assertThat(TextFormat.unescapeText("\\u1234")).isEqualTo("\u1234");
959     assertThat(TextFormat.unescapeBytes("\\u1234")).isEqualTo(bytes(0xe1, 0x88, 0xb4));
960     assertThat(TextFormat.unescapeBytes("\\U00001234")).isEqualTo(bytes(0xe1, 0x88, 0xb4));
961     assertThat(TextFormat.unescapeText("\\xf0\\x90\\x90\\xb7"))
962         .isEqualTo(new String(new int[] {0x10437}, 0, 1));
963     assertThat(TextFormat.unescapeBytes("\\U00010437")).isEqualTo(bytes(0xf0, 0x90, 0x90, 0xb7));
964 
965     // Handling of strings with unescaped Unicode characters > 255.
966     final String zh = "\u9999\u6e2f\u4e0a\u6d77\ud84f\udf80\u8c50\u9280\u884c";
967     ByteString zhByteString = ByteString.copyFromUtf8(zh);
968     assertThat(TextFormat.unescapeBytes(zh)).isEqualTo(zhByteString);
969 
970     // Errors.
971     try {
972       TextFormat.unescapeText("\\x");
973       assertWithMessage("Should have thrown an exception.").fail();
974     } catch (TextFormat.InvalidEscapeSequenceException e) {
975       // success
976     }
977 
978     try {
979       TextFormat.unescapeText("\\z");
980       assertWithMessage("Should have thrown an exception.").fail();
981     } catch (TextFormat.InvalidEscapeSequenceException e) {
982       // success
983     }
984 
985     try {
986       TextFormat.unescapeText("\\");
987       assertWithMessage("Should have thrown an exception.").fail();
988     } catch (TextFormat.InvalidEscapeSequenceException e) {
989       // success
990     }
991 
992     try {
993       TextFormat.unescapeText("\\u");
994       assertWithMessage("Should have thrown an exception.").fail();
995     } catch (TextFormat.InvalidEscapeSequenceException e) {
996       assertThat(e)
997           .hasMessageThat()
998           .isEqualTo("Invalid escape sequence: '\\u' with too few hex chars");
999     }
1000 
1001     try {
1002       TextFormat.unescapeText("\\ud800");
1003       assertWithMessage("Should have thrown an exception.").fail();
1004     } catch (TextFormat.InvalidEscapeSequenceException e) {
1005       assertThat(e)
1006           .hasMessageThat()
1007           .isEqualTo("Invalid escape sequence: '\\u' refers to a surrogate");
1008     }
1009 
1010     try {
1011       TextFormat.unescapeText("\\ud800\\u1234");
1012       assertWithMessage("Should have thrown an exception.").fail();
1013     } catch (TextFormat.InvalidEscapeSequenceException e) {
1014       assertThat(e)
1015           .hasMessageThat()
1016           .isEqualTo("Invalid escape sequence: '\\u' refers to a surrogate");
1017     }
1018 
1019     try {
1020       TextFormat.unescapeText("\\udc00");
1021       assertWithMessage("Should have thrown an exception.").fail();
1022     } catch (TextFormat.InvalidEscapeSequenceException e) {
1023       assertThat(e)
1024           .hasMessageThat()
1025           .isEqualTo("Invalid escape sequence: '\\u' refers to a surrogate");
1026     }
1027 
1028     try {
1029       TextFormat.unescapeText("\\ud801\\udc37");
1030       assertWithMessage("Should have thrown an exception.").fail();
1031     } catch (TextFormat.InvalidEscapeSequenceException e) {
1032       assertThat(e)
1033           .hasMessageThat()
1034           .isEqualTo("Invalid escape sequence: '\\u' refers to a surrogate");
1035     }
1036 
1037     try {
1038       TextFormat.unescapeText("\\U1234");
1039       assertWithMessage("Should have thrown an exception.").fail();
1040     } catch (TextFormat.InvalidEscapeSequenceException e) {
1041       assertThat(e)
1042           .hasMessageThat()
1043           .isEqualTo("Invalid escape sequence: '\\U' with too few hex chars");
1044     }
1045 
1046     try {
1047       TextFormat.unescapeText("\\U1234no more hex");
1048       assertWithMessage("Should have thrown an exception.").fail();
1049     } catch (TextFormat.InvalidEscapeSequenceException e) {
1050       assertThat(e)
1051           .hasMessageThat()
1052           .isEqualTo("Invalid escape sequence: '\\U' with too few hex chars");
1053     }
1054 
1055     try {
1056       TextFormat.unescapeText("\\U00110000");
1057       assertWithMessage("Should have thrown an exception.").fail();
1058     } catch (TextFormat.InvalidEscapeSequenceException e) {
1059       assertThat(e)
1060           .hasMessageThat()
1061           .isEqualTo("Invalid escape sequence: '\\U00110000' is not a valid code point value");
1062     }
1063 
1064     try {
1065       TextFormat.unescapeText("\\U0000d801\\U00000dc37");
1066       assertWithMessage("Should have thrown an exception.").fail();
1067     } catch (TextFormat.InvalidEscapeSequenceException e) {
1068       assertThat(e)
1069           .hasMessageThat()
1070           .isEqualTo("Invalid escape sequence: '\\U0000d801' refers to a surrogate code unit");
1071     }
1072   }
1073 
1074   @Test
testParseInteger()1075   public void testParseInteger() throws Exception {
1076     assertThat(TextFormat.parseInt32("0")).isEqualTo(0);
1077     assertThat(TextFormat.parseInt32("1")).isEqualTo(1);
1078     assertThat(TextFormat.parseInt32("-1")).isEqualTo(-1);
1079     assertThat(TextFormat.parseInt32("12345")).isEqualTo(12345);
1080     assertThat(TextFormat.parseInt32("-12345")).isEqualTo(-12345);
1081     assertThat(TextFormat.parseInt32("2147483647")).isEqualTo(2147483647);
1082     assertThat(TextFormat.parseInt32("-2147483648")).isEqualTo(-2147483648);
1083 
1084     assertThat(TextFormat.parseUInt32("0")).isEqualTo(0);
1085     assertThat(TextFormat.parseUInt32("1")).isEqualTo(1);
1086     assertThat(TextFormat.parseUInt32("12345")).isEqualTo(12345);
1087     assertThat(TextFormat.parseUInt32("2147483647")).isEqualTo(2147483647);
1088     assertThat(TextFormat.parseUInt32("2147483648")).isEqualTo((int) 2147483648L);
1089     assertThat(TextFormat.parseUInt32("4294967295")).isEqualTo((int) 4294967295L);
1090 
1091     assertThat(TextFormat.parseInt64("0")).isEqualTo(0L);
1092     assertThat(TextFormat.parseInt64("1")).isEqualTo(1L);
1093     assertThat(TextFormat.parseInt64("-1")).isEqualTo(-1L);
1094     assertThat(TextFormat.parseInt64("12345")).isEqualTo(12345L);
1095     assertThat(TextFormat.parseInt64("-12345")).isEqualTo(-12345L);
1096     assertThat(TextFormat.parseInt64("2147483647")).isEqualTo(2147483647L);
1097     assertThat(TextFormat.parseInt64("-2147483648")).isEqualTo(-2147483648L);
1098     assertThat(TextFormat.parseInt64("4294967295")).isEqualTo(4294967295L);
1099     assertThat(TextFormat.parseInt64("4294967296")).isEqualTo(4294967296L);
1100     assertThat(TextFormat.parseInt64("9223372036854775807")).isEqualTo(9223372036854775807L);
1101     assertThat(TextFormat.parseInt64("-9223372036854775808")).isEqualTo(-9223372036854775808L);
1102 
1103     assertThat(TextFormat.parseUInt64("0")).isEqualTo(0L);
1104     assertThat(TextFormat.parseUInt64("1")).isEqualTo(1L);
1105     assertThat(TextFormat.parseUInt64("12345")).isEqualTo(12345L);
1106     assertThat(TextFormat.parseUInt64("2147483647")).isEqualTo(2147483647L);
1107     assertThat(TextFormat.parseUInt64("4294967295")).isEqualTo(4294967295L);
1108     assertThat(TextFormat.parseUInt64("4294967296")).isEqualTo(4294967296L);
1109     assertThat(TextFormat.parseUInt64("9223372036854775807")).isEqualTo(9223372036854775807L);
1110     assertThat(TextFormat.parseUInt64("9223372036854775808")).isEqualTo(-9223372036854775808L);
1111     assertThat(TextFormat.parseUInt64("18446744073709551615")).isEqualTo(-1L);
1112 
1113     // Hex
1114     assertThat(TextFormat.parseInt32("0x1234abcd")).isEqualTo(0x1234abcd);
1115     assertThat(TextFormat.parseInt32("-0x1234abcd")).isEqualTo(-0x1234abcd);
1116     assertThat(TextFormat.parseUInt64("0xffffffffffffffff")).isEqualTo(-1);
1117     assertThat(TextFormat.parseInt64("0x7fffffffffffffff")).isEqualTo(0x7fffffffffffffffL);
1118 
1119     // Octal
1120     assertThat(TextFormat.parseInt32("01234567")).isEqualTo(01234567);
1121 
1122     // Out-of-range
1123     try {
1124       TextFormat.parseInt32("2147483648");
1125       assertWithMessage("Should have thrown an exception.").fail();
1126     } catch (NumberFormatException e) {
1127       // success
1128     }
1129 
1130     try {
1131       TextFormat.parseInt32("-2147483649");
1132       assertWithMessage("Should have thrown an exception.").fail();
1133     } catch (NumberFormatException e) {
1134       // success
1135     }
1136 
1137     try {
1138       TextFormat.parseUInt32("4294967296");
1139       assertWithMessage("Should have thrown an exception.").fail();
1140     } catch (NumberFormatException e) {
1141       // success
1142     }
1143 
1144     try {
1145       TextFormat.parseUInt32("-1");
1146       assertWithMessage("Should have thrown an exception.").fail();
1147     } catch (NumberFormatException e) {
1148       // success
1149     }
1150 
1151     try {
1152       TextFormat.parseInt64("9223372036854775808");
1153       assertWithMessage("Should have thrown an exception.").fail();
1154     } catch (NumberFormatException e) {
1155       // success
1156     }
1157 
1158     try {
1159       TextFormat.parseInt64("-9223372036854775809");
1160       assertWithMessage("Should have thrown an exception.").fail();
1161     } catch (NumberFormatException e) {
1162       // success
1163     }
1164 
1165     try {
1166       TextFormat.parseUInt64("18446744073709551616");
1167       assertWithMessage("Should have thrown an exception.").fail();
1168     } catch (NumberFormatException e) {
1169       // success
1170     }
1171 
1172     try {
1173       TextFormat.parseUInt64("-1");
1174       assertWithMessage("Should have thrown an exception.").fail();
1175     } catch (NumberFormatException e) {
1176       // success
1177     }
1178 
1179     // Not a number.
1180     try {
1181       TextFormat.parseInt32("abcd");
1182       assertWithMessage("Should have thrown an exception.").fail();
1183     } catch (NumberFormatException e) {
1184       // success
1185     }
1186   }
1187 
1188   @Test
testParseString()1189   public void testParseString() throws Exception {
1190     final String zh = "\u9999\u6e2f\u4e0a\u6d77\ud84f\udf80\u8c50\u9280\u884c";
1191     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
1192     TextFormat.merge("optional_string: \"" + zh + "\"", builder);
1193     assertThat(builder.getOptionalString()).isEqualTo(zh);
1194   }
1195 
1196   @Test
testParseLongString()1197   public void testParseLongString() throws Exception {
1198     String longText =
1199         "123456789012345678901234567890123456789012345678901234567890"
1200             + "123456789012345678901234567890123456789012345678901234567890"
1201             + "123456789012345678901234567890123456789012345678901234567890"
1202             + "123456789012345678901234567890123456789012345678901234567890"
1203             + "123456789012345678901234567890123456789012345678901234567890"
1204             + "123456789012345678901234567890123456789012345678901234567890"
1205             + "123456789012345678901234567890123456789012345678901234567890"
1206             + "123456789012345678901234567890123456789012345678901234567890"
1207             + "123456789012345678901234567890123456789012345678901234567890"
1208             + "123456789012345678901234567890123456789012345678901234567890"
1209             + "123456789012345678901234567890123456789012345678901234567890"
1210             + "123456789012345678901234567890123456789012345678901234567890"
1211             + "123456789012345678901234567890123456789012345678901234567890"
1212             + "123456789012345678901234567890123456789012345678901234567890"
1213             + "123456789012345678901234567890123456789012345678901234567890"
1214             + "123456789012345678901234567890123456789012345678901234567890"
1215             + "123456789012345678901234567890123456789012345678901234567890"
1216             + "123456789012345678901234567890123456789012345678901234567890"
1217             + "123456789012345678901234567890123456789012345678901234567890"
1218             + "123456789012345678901234567890123456789012345678901234567890";
1219 
1220     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
1221     TextFormat.merge("optional_string: \"" + longText + "\"", builder);
1222     assertThat(builder.getOptionalString()).isEqualTo(longText);
1223   }
1224 
1225   @Test
testParseBoolean()1226   public void testParseBoolean() throws Exception {
1227     String goodText =
1228         "repeated_bool: t  repeated_bool : 0\n"
1229             + "repeated_bool :f repeated_bool:1\n"
1230             + "repeated_bool: False repeated_bool: True";
1231     String goodTextCanonical =
1232         "repeated_bool: true\n"
1233             + "repeated_bool: false\n"
1234             + "repeated_bool: false\n"
1235             + "repeated_bool: true\n"
1236             + "repeated_bool: false\n"
1237             + "repeated_bool: true\n";
1238     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
1239     TextFormat.merge(goodText, builder);
1240     assertThat(builder.build().toString()).isEqualTo(goodTextCanonical);
1241 
1242     try {
1243       TestAllTypes.Builder badBuilder = TestAllTypes.newBuilder();
1244       TextFormat.merge("optional_bool:2", badBuilder);
1245       assertWithMessage("Should have thrown an exception.").fail();
1246     } catch (TextFormat.ParseException e) {
1247       // success
1248     }
1249     try {
1250       TestAllTypes.Builder badBuilder = TestAllTypes.newBuilder();
1251       TextFormat.merge("optional_bool: foo", badBuilder);
1252       assertWithMessage("Should have thrown an exception.").fail();
1253     } catch (TextFormat.ParseException e) {
1254       // success
1255     }
1256   }
1257 
1258   @Test
testParseAdjacentStringLiterals()1259   public void testParseAdjacentStringLiterals() throws Exception {
1260     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
1261     TextFormat.merge("optional_string: \"foo\" 'corge' \"grault\"", builder);
1262     assertThat(builder.getOptionalString()).isEqualTo("foocorgegrault");
1263   }
1264 
1265   @Test
testPrintFieldValue()1266   public void testPrintFieldValue() throws Exception {
1267     assertPrintFieldValue("\"Hello\"", "Hello", "repeated_string");
1268     assertPrintFieldValue("123.0", 123f, "repeated_float");
1269     assertPrintFieldValue("123.0", 123d, "repeated_double");
1270     assertPrintFieldValue("123", 123, "repeated_int32");
1271     assertPrintFieldValue("123", 123L, "repeated_int64");
1272     assertPrintFieldValue("true", true, "repeated_bool");
1273     assertPrintFieldValue("4294967295", 0xFFFFFFFF, "repeated_uint32");
1274     assertPrintFieldValue("18446744073709551615", 0xFFFFFFFFFFFFFFFFL, "repeated_uint64");
1275     assertPrintFieldValue(
1276         "\"\\001\\002\\003\"", ByteString.copyFrom(new byte[] {1, 2, 3}), "repeated_bytes");
1277   }
1278 
assertPrintFieldValue(String expect, Object value, String fieldName)1279   private void assertPrintFieldValue(String expect, Object value, String fieldName)
1280       throws Exception {
1281     StringBuilder sb = new StringBuilder();
1282     TextFormat.printer()
1283         .printFieldValue(TestAllTypes.getDescriptor().findFieldByName(fieldName), value, sb);
1284     assertThat(sb.toString()).isEqualTo(expect);
1285   }
1286 
1287   @Test
testPrintFieldValueThrows()1288   public void testPrintFieldValueThrows() throws Exception {
1289     assertPrintFieldThrowsClassCastException(5, "repeated_string");
1290     assertPrintFieldThrowsClassCastException(5L, "repeated_string");
1291     assertPrintFieldThrowsClassCastException(ByteString.EMPTY, "repeated_string");
1292     assertPrintFieldThrowsClassCastException(5, "repeated_float");
1293     assertPrintFieldThrowsClassCastException(5D, "repeated_float");
1294     assertPrintFieldThrowsClassCastException("text", "repeated_float");
1295     assertPrintFieldThrowsClassCastException(5, "repeated_double");
1296     assertPrintFieldThrowsClassCastException(5F, "repeated_double");
1297     assertPrintFieldThrowsClassCastException("text", "repeated_double");
1298     assertPrintFieldThrowsClassCastException(123L, "repeated_int32");
1299     assertPrintFieldThrowsClassCastException(123, "repeated_int64");
1300     assertPrintFieldThrowsClassCastException(1, "repeated_bytes");
1301   }
1302 
assertPrintFieldThrowsClassCastException(final Object value, String fieldName)1303   private void assertPrintFieldThrowsClassCastException(final Object value, String fieldName)
1304       throws Exception {
1305     final StringBuilder stringBuilder = new StringBuilder();
1306     final FieldDescriptor fieldDescriptor = TestAllTypes.getDescriptor().findFieldByName(fieldName);
1307     assertThrows(
1308         ClassCastException.class,
1309         new ThrowingRunnable() {
1310           @Override
1311           public void run() throws Throwable {
1312             TextFormat.printer().printFieldValue(fieldDescriptor, value, stringBuilder);
1313           }
1314         });
1315   }
1316 
1317   @Test
testShortDebugString()1318   public void testShortDebugString() {
1319     assertThat(
1320             TextFormat.shortDebugString(
1321                 TestAllTypes.newBuilder()
1322                     .addRepeatedInt32(1)
1323                     .addRepeatedUint32(2)
1324                     .setOptionalNestedMessage(NestedMessage.newBuilder().setBb(42).build())
1325                     .build()))
1326         .isEqualTo("optional_nested_message { bb: 42 } repeated_int32: 1 repeated_uint32: 2");
1327   }
1328 
1329   @Test
testShortDebugString_field()1330   public void testShortDebugString_field() {
1331     final FieldDescriptor dataField = OneString.getDescriptor().findFieldByName("data");
1332     assertThat(TextFormat.printer().shortDebugString(dataField, "test data"))
1333         .isEqualTo("data: \"test data\"");
1334 
1335     final FieldDescriptor optionalField =
1336         TestAllTypes.getDescriptor().findFieldByName("optional_nested_message");
1337     final Object value = NestedMessage.newBuilder().setBb(42).build();
1338 
1339     assertThat(TextFormat.printer().shortDebugString(optionalField, value))
1340         .isEqualTo("optional_nested_message { bb: 42 }");
1341   }
1342 
1343   @Test
testShortDebugString_unknown()1344   public void testShortDebugString_unknown() {
1345     assertThat(TextFormat.printer().shortDebugString(makeUnknownFieldSet()))
1346         .isEqualTo(
1347             "5: 1 5: 0x00000002 5: 0x0000000000000003 5: \"4\" 5: { 12: 6 } 5 { 10: 5 }"
1348                 + " 8: 1 8: 2 8: 3 15: 12379813812177893520 15: 0xabcd1234 15:"
1349                 + " 0xabcdef1234567890");
1350   }
1351 
1352   @Test
testPrintToUnicodeString()1353   public void testPrintToUnicodeString() throws Exception {
1354     assertThat(
1355             TextFormat.printer()
1356                 .escapingNonAscii(false)
1357                 .printToString(
1358                     TestAllTypes.newBuilder()
1359                         .setOptionalString("abc\u3042efg")
1360                         .setOptionalBytes(bytes(0xe3, 0x81, 0x82))
1361                         .addRepeatedString("\u3093XYZ")
1362                         .build()))
1363         .isEqualTo(
1364             "optional_string: \"abc\u3042efg\"\n"
1365                 + "optional_bytes: \"\\343\\201\\202\"\n"
1366                 + "repeated_string: \"\u3093XYZ\"\n");
1367 
1368     // Double quotes and backslashes should be escaped
1369     assertThat(
1370             TextFormat.printer()
1371                 .escapingNonAscii(false)
1372                 .printToString(TestAllTypes.newBuilder().setOptionalString("a\\bc\"ef\"g").build()))
1373         .isEqualTo("optional_string: \"a\\\\bc\\\"ef\\\"g\"\n");
1374 
1375     // Test escaping roundtrip
1376     TestAllTypes message = TestAllTypes.newBuilder().setOptionalString("a\\bc\\\"ef\"g").build();
1377     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
1378     TextFormat.merge(TextFormat.printer().escapingNonAscii(false).printToString(message), builder);
1379     assertThat(builder.getOptionalString()).isEqualTo(message.getOptionalString());
1380   }
1381 
1382   @Test
testPrintToUnicodeStringWithNewlines()1383   public void testPrintToUnicodeStringWithNewlines() throws Exception {
1384     // No newlines at start and end
1385     assertThat(
1386             TextFormat.printer()
1387                 .escapingNonAscii(false)
1388                 .printToString(
1389                     TestAllTypes.newBuilder()
1390                         .setOptionalString("test newlines\n\nin\nstring")
1391                         .build()))
1392         .isEqualTo("optional_string: \"test newlines\\n\\nin\\nstring\"\n");
1393 
1394     // Newlines at start and end
1395     assertThat(
1396             TextFormat.printer()
1397                 .escapingNonAscii(false)
1398                 .printToString(
1399                     TestAllTypes.newBuilder()
1400                         .setOptionalString("\ntest\nnewlines\n\nin\nstring\n")
1401                         .build()))
1402         .isEqualTo("optional_string: \"\\ntest\\nnewlines\\n\\nin\\nstring\\n\"\n");
1403 
1404     // Strings with 0, 1 and 2 newlines.
1405     assertThat(
1406             TextFormat.printer()
1407                 .escapingNonAscii(false)
1408                 .printToString(TestAllTypes.newBuilder().setOptionalString("").build()))
1409         .isEqualTo("optional_string: \"\"\n");
1410     assertThat(
1411             TextFormat.printer()
1412                 .escapingNonAscii(false)
1413                 .printToString(TestAllTypes.newBuilder().setOptionalString("\n").build()))
1414         .isEqualTo("optional_string: \"\\n\"\n");
1415     assertThat(
1416             TextFormat.printer()
1417                 .escapingNonAscii(false)
1418                 .printToString(TestAllTypes.newBuilder().setOptionalString("\n\n").build()))
1419         .isEqualTo("optional_string: \"\\n\\n\"\n");
1420 
1421     // Test escaping roundtrip
1422     TestAllTypes message =
1423         TestAllTypes.newBuilder().setOptionalString("\ntest\nnewlines\n\nin\nstring\n").build();
1424     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
1425     TextFormat.merge(TextFormat.printer().escapingNonAscii(false).printToString(message), builder);
1426     assertThat(builder.getOptionalString()).isEqualTo(message.getOptionalString());
1427   }
1428 
1429   @Test
testPrintToUnicodeString_unknown()1430   public void testPrintToUnicodeString_unknown() {
1431     assertThat(
1432             TextFormat.printer()
1433                 .escapingNonAscii(false)
1434                 .printToString(
1435                     UnknownFieldSet.newBuilder()
1436                         .addField(
1437                             1,
1438                             UnknownFieldSet.Field.newBuilder()
1439                                 .addLengthDelimited(bytes(0xe3, 0x81, 0x82))
1440                                 .build())
1441                         .build()))
1442         .isEqualTo("1: \"\\343\\201\\202\"\n");
1443   }
1444 
1445   @Test
testParseUnknownExtensions()1446   public void testParseUnknownExtensions() throws Exception {
1447     TestUtil.TestLogHandler logHandler = new TestUtil.TestLogHandler();
1448     Logger logger = Logger.getLogger(TextFormat.class.getName());
1449     logger.addHandler(logHandler);
1450     // Test unknown extension can pass.
1451     assertParseSuccessWithUnknownExtensions("[unknown_extension]: 123");
1452     assertParseSuccessWithUnknownExtensions(
1453         "[unknown_extension]: 123\n" + "[unknown_ext]: inf\n" + "[unknown]: 1.234");
1454     // Test warning messages.
1455     assertThat(logHandler.getStoredLogRecords().get(0).getMessage())
1456         .isEqualTo(
1457             "Input contains unknown fields and/or extensions:\n"
1458                 + "1:2:\tprotobuf_unittest.TestAllTypes.[unknown_extension]");
1459     assertThat(logHandler.getStoredLogRecords().get(1).getMessage())
1460         .isEqualTo(
1461             "Input contains unknown fields and/or extensions:\n"
1462                 + "1:2:\tprotobuf_unittest.TestAllTypes.[unknown_extension]\n"
1463                 + "2:2:\tprotobuf_unittest.TestAllTypes.[unknown_ext]\n"
1464                 + "3:2:\tprotobuf_unittest.TestAllTypes.[unknown]");
1465 
1466     // Test unknown field can not pass.
1467     assertParseErrorWithUnknownExtensions(
1468         "2:1: Input contains unknown fields and/or extensions:\n"
1469             + "1:2:\tprotobuf_unittest.TestAllTypes.[unknown_extension]\n"
1470             + "2:1:\tprotobuf_unittest.TestAllTypes.unknown_field",
1471         "[unknown_extension]: 1\n" + "unknown_field: 12345");
1472     assertParseErrorWithUnknownExtensions(
1473         "3:1: Input contains unknown fields and/or extensions:\n"
1474             + "1:2:\tprotobuf_unittest.TestAllTypes.[unknown_extension1]\n"
1475             + "2:2:\tprotobuf_unittest.TestAllTypes.[unknown_extension2]\n"
1476             + "3:1:\tprotobuf_unittest.TestAllTypes.unknown_field\n"
1477             + "4:2:\tprotobuf_unittest.TestAllTypes.[unknown_extension3]",
1478         "[unknown_extension1]: 1\n"
1479             + "[unknown_extension2]: 2\n"
1480             + "unknown_field: 12345\n"
1481             + "[unknown_extension3]: 3\n");
1482     assertParseErrorWithUnknownExtensions(
1483         "1:1: Input contains unknown fields and/or extensions:\n"
1484             + "1:1:\tprotobuf_unittest.TestAllTypes.unknown_field1\n"
1485             + "2:1:\tprotobuf_unittest.TestAllTypes.unknown_field2\n"
1486             + "3:2:\tprotobuf_unittest.TestAllTypes.[unknown_extension]\n"
1487             + "4:1:\tprotobuf_unittest.TestAllTypes.unknown_field3",
1488         "unknown_field1: 1\n"
1489             + "unknown_field2: 2\n"
1490             + "[unknown_extension]: 12345\n"
1491             + "unknown_field3: 3\n");
1492   }
1493 
1494   @Test
testParseUnknownExtensionWithAnyMessage()1495   public void testParseUnknownExtensionWithAnyMessage() throws Exception {
1496     assertParseSuccessWithUnknownExtensions(
1497         "[unknown_extension]: { "
1498             + "  any_value { "
1499             + "    [type.googleapis.com/protobuf_unittest.OneString] { "
1500             + "      data: 123 "
1501             + "    } "
1502             + " } "
1503             + "}");
1504   }
1505 
1506   // See additional coverage in testOneofOverwriteForbidden and testMapOverwriteForbidden.
1507   @Test
testParseNonRepeatedFields()1508   public void testParseNonRepeatedFields() throws Exception {
1509     assertParseSuccessWithOverwriteForbidden("repeated_int32: 1\nrepeated_int32: 2\n");
1510     assertParseSuccessWithOverwriteForbidden("RepeatedGroup { a: 1 }\nRepeatedGroup { a: 2 }\n");
1511     assertParseSuccessWithOverwriteForbidden(
1512         "repeated_nested_message { bb: 1 }\nrepeated_nested_message { bb: 2 }\n");
1513 
1514     assertParseErrorWithOverwriteForbidden(
1515         "3:15: Non-repeated field "
1516             + "\"protobuf_unittest.TestAllTypes.optional_int32\" "
1517             + "cannot be overwritten.",
1518         "optional_int32: 1\noptional_bool: true\noptional_int32: 1\n");
1519     assertParseErrorWithOverwriteForbidden(
1520         "2:1: Non-repeated field "
1521             + "\"protobuf_unittest.TestAllTypes.optionalgroup\" "
1522             + "cannot be overwritten.",
1523         "OptionalGroup { a: 1 }\nOptionalGroup { }\n");
1524     assertParseErrorWithOverwriteForbidden(
1525         "2:1: Non-repeated field "
1526             + "\"protobuf_unittest.TestAllTypes.optional_nested_message\" "
1527             + "cannot be overwritten.",
1528         "optional_nested_message { }\noptional_nested_message { bb: 3 }\n");
1529     assertParseErrorWithOverwriteForbidden(
1530         "2:14: Non-repeated field "
1531             + "\"protobuf_unittest.TestAllTypes.default_int32\" "
1532             + "cannot be overwritten.",
1533         "default_int32: 41\n"
1534             + // the default value
1535             "default_int32: 41\n");
1536     assertParseErrorWithOverwriteForbidden(
1537         "2:15: Non-repeated field "
1538             + "\"protobuf_unittest.TestAllTypes.default_string\" "
1539             + "cannot be overwritten.",
1540         "default_string: \"zxcv\"\ndefault_string: \"asdf\"\n");
1541   }
1542 
1543   @Test
testParseShortRepeatedFormOfRepeatedFields()1544   public void testParseShortRepeatedFormOfRepeatedFields() throws Exception {
1545     assertParseSuccessWithOverwriteForbidden("repeated_foreign_enum: [FOREIGN_FOO, FOREIGN_BAR]");
1546     assertParseSuccessWithOverwriteForbidden("repeated_int32: [ 1, 2 ]\n");
1547     assertParseSuccessWithOverwriteForbidden("RepeatedGroup [{ a: 1 },{ a: 2 }]\n");
1548     assertParseSuccessWithOverwriteForbidden("repeated_nested_message [{ bb: 1 }, { bb: 2 }]\n");
1549     // See also testMapShortForm.
1550   }
1551 
1552   @Test
testParseShortRepeatedFormOfEmptyRepeatedFields()1553   public void testParseShortRepeatedFormOfEmptyRepeatedFields() throws Exception {
1554     assertParseSuccessWithOverwriteForbidden("repeated_foreign_enum: []");
1555     assertParseSuccessWithOverwriteForbidden("repeated_int32: []\n");
1556     assertParseSuccessWithOverwriteForbidden("RepeatedGroup []\n");
1557     assertParseSuccessWithOverwriteForbidden("repeated_nested_message []\n");
1558     // See also testMapShortFormEmpty.
1559   }
1560 
1561   @Test
testParseShortRepeatedFormWithTrailingComma()1562   public void testParseShortRepeatedFormWithTrailingComma() throws Exception {
1563     assertParseErrorWithOverwriteForbidden(
1564         "1:38: Expected identifier. Found \']\'", "repeated_foreign_enum: [FOREIGN_FOO, ]\n");
1565     assertParseErrorWithOverwriteForbidden(
1566         "1:22: Couldn't parse integer: For input string: \"]\"", "repeated_int32: [ 1, ]\n");
1567     assertParseErrorWithOverwriteForbidden("1:25: Expected \"{\".", "RepeatedGroup [{ a: 1 },]\n");
1568     assertParseErrorWithOverwriteForbidden(
1569         "1:37: Expected \"{\".", "repeated_nested_message [{ bb: 1 }, ]\n");
1570     // See also testMapShortFormTrailingComma.
1571   }
1572 
1573   @Test
testParseShortRepeatedFormOfNonRepeatedFields()1574   public void testParseShortRepeatedFormOfNonRepeatedFields() throws Exception {
1575     assertParseErrorWithOverwriteForbidden(
1576         "1:17: Couldn't parse integer: For input string: \"[\"", "optional_int32: [1]\n");
1577     assertParseErrorWithOverwriteForbidden(
1578         "1:17: Couldn't parse integer: For input string: \"[\"", "optional_int32: []\n");
1579   }
1580 
1581   // =======================================================================
1582   // test delimited
1583 
1584   @Test
testPrintGroupLikeDelimited()1585   public void testPrintGroupLikeDelimited() throws Exception {
1586     TestDelimited message =
1587         TestDelimited.newBuilder()
1588             .setGroupLike(TestDelimited.GroupLike.newBuilder().setA(1).build())
1589             .build();
1590     assertThat(TextFormat.printer().printToString(message)).isEqualTo("GroupLike {\n  a: 1\n}\n");
1591   }
1592 
1593   @Test
testPrintGroupLikeDelimitedExtension()1594   public void testPrintGroupLikeDelimitedExtension() throws Exception {
1595     TestDelimited message =
1596         TestDelimited.newBuilder()
1597             .setExtension(
1598                 UnittestDelimited.groupLikeFileScope,
1599                 GroupLikeFileScope.newBuilder().setA(1).build())
1600             .build();
1601     assertThat(TextFormat.printer().printToString(message))
1602         .isEqualTo("[editions_unittest.grouplikefilescope] {\n  a: 1\n}\n");
1603   }
1604 
1605   @Test
testPrintGroupLikeNotDelimited()1606   public void testPrintGroupLikeNotDelimited() throws Exception {
1607     TestDelimited message =
1608         TestDelimited.newBuilder()
1609             .setLengthprefixed(TestDelimited.LengthPrefixed.newBuilder().setA(1).build())
1610             .build();
1611     assertThat(TextFormat.printer().printToString(message))
1612         .isEqualTo("lengthprefixed {\n  a: 1\n}\n");
1613   }
1614 
1615   @Test
testPrintGroupLikeMismatchedName()1616   public void testPrintGroupLikeMismatchedName() throws Exception {
1617     TestDelimited message =
1618         TestDelimited.newBuilder()
1619             .setNotgrouplike(TestDelimited.GroupLike.newBuilder().setA(1).build())
1620             .build();
1621     assertThat(TextFormat.printer().printToString(message))
1622         .isEqualTo("notgrouplike {\n  a: 1\n}\n");
1623   }
1624 
1625   @Test
testPrintGroupLikeExtensionMismatchedName()1626   public void testPrintGroupLikeExtensionMismatchedName() throws Exception {
1627     TestDelimited message =
1628         TestDelimited.newBuilder()
1629             .setExtension(
1630                 UnittestDelimited.notGroupLikeScope, NotGroupLikeScope.newBuilder().setA(1).build())
1631             .build();
1632     assertThat(TextFormat.printer().printToString(message))
1633         .isEqualTo("[editions_unittest.not_group_like_scope] {\n  a: 1\n}\n");
1634   }
1635 
1636   @Test
testPrintGroupLikeMismatchedScope()1637   public void testPrintGroupLikeMismatchedScope() throws Exception {
1638     TestDelimited message =
1639         TestDelimited.newBuilder()
1640             .setNotgrouplikescope(NotGroupLikeScope.newBuilder().setA(1).build())
1641             .build();
1642     assertThat(TextFormat.printer().printToString(message))
1643         .isEqualTo("notgrouplikescope {\n  a: 1\n}\n");
1644   }
1645 
1646   @Test
testPrintGroupLikeExtensionMismatchedScope()1647   public void testPrintGroupLikeExtensionMismatchedScope() throws Exception {
1648     TestDelimited message =
1649         TestDelimited.newBuilder()
1650             .setExtension(
1651                 UnittestDelimited.grouplike, TestDelimited.GroupLike.newBuilder().setA(1).build())
1652             .build();
1653     assertThat(TextFormat.printer().printToString(message))
1654         .isEqualTo("[editions_unittest.grouplike] {\n  a: 1\n}\n");
1655   }
1656 
1657   @Test
testPrintGroupLikeMismatchedFile()1658   public void testPrintGroupLikeMismatchedFile() throws Exception {
1659     TestDelimited message =
1660         TestDelimited.newBuilder()
1661             .setMessageimport(MessageImport.newBuilder().setA(1).build())
1662             .build();
1663     assertThat(TextFormat.printer().printToString(message))
1664         .isEqualTo("messageimport {\n  a: 1\n}\n");
1665   }
1666 
1667   @Test
testParseDelimitedGroupLikeType()1668   public void testParseDelimitedGroupLikeType() throws Exception {
1669     TestDelimited.Builder message = TestDelimited.newBuilder();
1670     TextFormat.merge("GroupLike { a: 1 }", message);
1671     assertThat(message.build())
1672         .isEqualTo(
1673             TestDelimited.newBuilder()
1674                 .setGroupLike(TestDelimited.GroupLike.newBuilder().setA(1).build())
1675                 .build());
1676   }
1677 
1678   @Test
testParseDelimitedGroupLikeField()1679   public void testParseDelimitedGroupLikeField() throws Exception {
1680     TestDelimited.Builder message = TestDelimited.newBuilder();
1681     TextFormat.merge("grouplike { a: 2 }", message);
1682     assertThat(message.build())
1683         .isEqualTo(
1684             TestDelimited.newBuilder()
1685                 .setGroupLike(TestDelimited.GroupLike.newBuilder().setA(2).build())
1686                 .build());
1687   }
1688 
1689   @Test
testParseDelimitedGroupLikeExtension()1690   public void testParseDelimitedGroupLikeExtension() throws Exception {
1691     TestDelimited.Builder message = TestDelimited.newBuilder();
1692     ExtensionRegistry registry = ExtensionRegistry.newInstance();
1693     registry.add(UnittestDelimited.grouplike);
1694     TextFormat.merge("[editions_unittest.grouplike] { a: 2 }", registry, message);
1695     assertThat(message.build())
1696         .isEqualTo(
1697             TestDelimited.newBuilder()
1698                 .setExtension(
1699                     UnittestDelimited.grouplike,
1700                     TestDelimited.GroupLike.newBuilder().setA(2).build())
1701                 .build());
1702   }
1703 
1704   @Test
testParseDelimitedGroupLikeInvalid()1705   public void testParseDelimitedGroupLikeInvalid() throws Exception {
1706     TestDelimited.Builder message = TestDelimited.newBuilder();
1707     try {
1708       TextFormat.merge("GROUPlike { a: 3 }", message);
1709       assertWithMessage("Expected parse exception.").fail();
1710     } catch (TextFormat.ParseException e) {
1711       assertThat(e)
1712           .hasMessageThat()
1713           .isEqualTo(
1714               "1:1: Input contains unknown fields and/or extensions:\n"
1715                   + "1:1:\teditions_unittest.TestDelimited.GROUPlike");
1716     }
1717   }
1718 
1719   @Test
testParseDelimitedGroupLikeInvalidExtension()1720   public void testParseDelimitedGroupLikeInvalidExtension() throws Exception {
1721     TestDelimited.Builder message = TestDelimited.newBuilder();
1722     ExtensionRegistry registry = ExtensionRegistry.newInstance();
1723     registry.add(UnittestDelimited.grouplike);
1724     try {
1725       TextFormat.merge("[editions_unittest.GroupLike] { a: 2 }", registry, message);
1726       assertWithMessage("Expected parse exception.").fail();
1727     } catch (TextFormat.ParseException e) {
1728       assertThat(e)
1729           .hasMessageThat()
1730           .isEqualTo(
1731               "1:20: Input contains unknown fields and/or extensions:\n"
1732                   + "1:20:\teditions_unittest.TestDelimited.[editions_unittest.GroupLike]");
1733     }
1734   }
1735 
1736   @Test
testParseDelimited()1737   public void testParseDelimited() throws Exception {
1738     TestDelimited.Builder message = TestDelimited.newBuilder();
1739     TextFormat.merge("notgrouplike { b: 3 }", message);
1740     assertThat(message.build())
1741         .isEqualTo(
1742             TestDelimited.newBuilder()
1743                 .setNotgrouplike(TestDelimited.GroupLike.newBuilder().setB(3).build())
1744                 .build());
1745   }
1746 
1747   @Test
testParseDelimitedInvalid()1748   public void testParseDelimitedInvalid() throws Exception {
1749     TestDelimited.Builder message = TestDelimited.newBuilder();
1750     try {
1751       TextFormat.merge("NotGroupLike { a: 3 }", message);
1752       assertWithMessage("Expected parse exception.").fail();
1753     } catch (TextFormat.ParseException e) {
1754       assertThat(e)
1755           .hasMessageThat()
1756           .isEqualTo(
1757               "1:1: Input contains unknown fields and/or extensions:\n"
1758                   + "1:1:\teditions_unittest.TestDelimited.NotGroupLike");
1759     }
1760   }
1761 
1762   @Test
testParseDelimitedInvalidScope()1763   public void testParseDelimitedInvalidScope() throws Exception {
1764     TestDelimited.Builder message = TestDelimited.newBuilder();
1765     try {
1766       TextFormat.merge("NotGroupLikeScope { a: 3 }", message);
1767       assertWithMessage("Expected parse exception.").fail();
1768     } catch (TextFormat.ParseException e) {
1769       assertThat(e)
1770           .hasMessageThat()
1771           .isEqualTo(
1772               "1:1: Input contains unknown fields and/or extensions:\n"
1773                   + "1:1:\teditions_unittest.TestDelimited.NotGroupLikeScope");
1774     }
1775   }
1776 
1777   // =======================================================================
1778   // test oneof
1779 
1780   @Test
testOneofTextFormat()1781   public void testOneofTextFormat() throws Exception {
1782     TestOneof2.Builder builder = TestOneof2.newBuilder();
1783     TestUtil.setOneof(builder);
1784     TestOneof2 message = builder.build();
1785     TestOneof2.Builder dest = TestOneof2.newBuilder();
1786     TextFormat.merge(TextFormat.printer().escapingNonAscii(false).printToString(message), dest);
1787     TestUtil.assertOneofSet(dest.build());
1788   }
1789 
1790   @Test
testOneofOverwriteForbidden()1791   public void testOneofOverwriteForbidden() throws Exception {
1792     String input = "foo_string: \"stringvalue\" foo_int: 123";
1793     TestOneof2.Builder builder = TestOneof2.newBuilder();
1794     try {
1795       PARSER_WITH_OVERWRITE_FORBIDDEN.merge(input, TestUtil.getFullExtensionRegistry(), builder);
1796       assertWithMessage("Expected parse exception.").fail();
1797     } catch (TextFormat.ParseException e) {
1798       assertThat(e)
1799           .hasMessageThat()
1800           .isEqualTo(
1801               "1:34: Field \"protobuf_unittest.TestOneof2.foo_int\""
1802                   + " is specified along with field \"protobuf_unittest.TestOneof2.foo_string\","
1803                   + " another member of oneof \"foo\".");
1804     }
1805   }
1806 
1807   @Test
testOneofOverwriteAllowed()1808   public void testOneofOverwriteAllowed() throws Exception {
1809     String input = "foo_string: \"stringvalue\" foo_int: 123";
1810     TestOneof2.Builder builder = TestOneof2.newBuilder();
1811     DEFAULT_PARSER.merge(input, TestUtil.getFullExtensionRegistry(), builder);
1812     // Only the last value sticks.
1813     TestOneof2 oneof = builder.build();
1814     assertThat(oneof.hasFooString()).isFalse();
1815     assertThat(oneof.hasFooInt()).isTrue();
1816   }
1817 
1818   // =======================================================================
1819   // test map
1820 
1821   @Test
testMapTextFormat()1822   public void testMapTextFormat() throws Exception {
1823     TestMap message =
1824         TestMap.newBuilder()
1825             .putInt32ToStringField(10, "apple")
1826             .putInt32ToStringField(20, "banana")
1827             .putInt32ToStringField(30, "cherry")
1828             .build();
1829     String text = TextFormat.printer().escapingNonAscii(false).printToString(message);
1830     {
1831       TestMap.Builder dest = TestMap.newBuilder();
1832       TextFormat.merge(text, dest);
1833       assertThat(dest.build()).isEqualTo(message);
1834     }
1835     {
1836       TestMap.Builder dest = TestMap.newBuilder();
1837       PARSER_WITH_OVERWRITE_FORBIDDEN.merge(text, dest);
1838       assertThat(dest.build()).isEqualTo(message);
1839     }
1840   }
1841 
1842   @Test
testMapDuplicateKeys()1843   public void testMapDuplicateKeys() throws Exception {
1844     String input =
1845         "int32_to_int32_field: {\n"
1846             + "  key: 1\n"
1847             + "  value: 1\n"
1848             + "}\n"
1849             + "int32_to_int32_field: {\n"
1850             + "  key: -2147483647\n"
1851             + "  value: 5\n"
1852             + "}\n"
1853             + "int32_to_int32_field: {\n"
1854             + "  key: 1\n"
1855             + "  value: -1\n"
1856             + "}\n";
1857     TestMap msg = TextFormat.parse(input, TestMap.class);
1858     int i1 = msg.getInt32ToInt32FieldMap().get(1);
1859     TestMap msg2 = TextFormat.parse(msg.toString(), TestMap.class);
1860     int i2 = msg2.getInt32ToInt32FieldMap().get(1);
1861     assertThat(i1).isEqualTo(i2);
1862   }
1863 
1864   @Test
testMapShortForm()1865   public void testMapShortForm() throws Exception {
1866     String text =
1867         "string_to_int32_field [{ key: 'x' value: 10 }, { key: 'y' value: 20 }]\n"
1868             + "int32_to_message_field "
1869             + "[{ key: 1 value { value: 100 } }, { key: 2 value: { value: 200 } }]\n";
1870     TestMap.Builder dest = TestMap.newBuilder();
1871     PARSER_WITH_OVERWRITE_FORBIDDEN.merge(text, dest);
1872     TestMap message = dest.build();
1873     assertThat(message.getStringToInt32FieldMap()).hasSize(2);
1874     assertThat(message.getInt32ToMessageFieldMap()).hasSize(2);
1875     assertThat(message.getStringToInt32FieldMap().get("x").intValue()).isEqualTo(10);
1876     assertThat(message.getInt32ToMessageFieldMap().get(2).getValue()).isEqualTo(200);
1877   }
1878 
1879   @Test
testMapShortFormEmpty()1880   public void testMapShortFormEmpty() throws Exception {
1881     String text = "string_to_int32_field []\nint32_to_message_field: []\n";
1882     TestMap.Builder dest = TestMap.newBuilder();
1883     PARSER_WITH_OVERWRITE_FORBIDDEN.merge(text, dest);
1884     TestMap message = dest.build();
1885     assertThat(message.getStringToInt32FieldMap()).isEmpty();
1886     assertThat(message.getInt32ToMessageFieldMap()).isEmpty();
1887   }
1888 
1889   @Test
testMapShortFormTrailingComma()1890   public void testMapShortFormTrailingComma() throws Exception {
1891     String text = "string_to_int32_field [{ key: 'x' value: 10 }, ]\n";
1892     TestMap.Builder dest = TestMap.newBuilder();
1893     try {
1894       PARSER_WITH_OVERWRITE_FORBIDDEN.merge(text, dest);
1895       assertWithMessage("Expected parse exception.").fail();
1896     } catch (TextFormat.ParseException e) {
1897       assertThat(e).hasMessageThat().isEqualTo("1:48: Expected \"{\".");
1898     }
1899   }
1900 
1901   @Test
testMapOverwrite()1902   public void testMapOverwrite() throws Exception {
1903     String text =
1904         "int32_to_int32_field { key: 1 value: 10 }\n"
1905             + "int32_to_int32_field { key: 2 value: 20 }\n"
1906             + "int32_to_int32_field { key: 1 value: 30 }\n";
1907 
1908     {
1909       // With default parser, last value set for the key holds.
1910       TestMap.Builder builder = TestMap.newBuilder();
1911       DEFAULT_PARSER.merge(text, builder);
1912       TestMap map = builder.build();
1913       assertThat(map.getInt32ToInt32FieldMap()).hasSize(2);
1914       assertThat(map.getInt32ToInt32FieldMap().get(1).intValue()).isEqualTo(30);
1915     }
1916 
1917     {
1918       // With overwrite forbidden, same behavior.
1919       // TODO: Expect parse exception here.
1920       TestMap.Builder builder = TestMap.newBuilder();
1921       PARSER_WITH_OVERWRITE_FORBIDDEN.merge(text, builder);
1922       TestMap map = builder.build();
1923       assertThat(map.getInt32ToInt32FieldMap()).hasSize(2);
1924       assertThat(map.getInt32ToInt32FieldMap().get(1).intValue()).isEqualTo(30);
1925     }
1926 
1927     {
1928       // With overwrite forbidden and a dynamic message, same behavior.
1929       // TODO: Expect parse exception here.
1930       Message.Builder builder = DynamicMessage.newBuilder(TestMap.getDescriptor());
1931       PARSER_WITH_OVERWRITE_FORBIDDEN.merge(text, builder);
1932       TestMap map =
1933           TestMap.parseFrom(
1934               builder.build().toByteString(), ExtensionRegistryLite.getEmptyRegistry());
1935       assertThat(map.getInt32ToInt32FieldMap()).hasSize(2);
1936       assertThat(map.getInt32ToInt32FieldMap().get(1).intValue()).isEqualTo(30);
1937     }
1938   }
1939 
1940   // =======================================================================
1941   // test location information
1942 
1943   @Test
testParseInfoTreeBuilding()1944   public void testParseInfoTreeBuilding() throws Exception {
1945     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
1946 
1947     Descriptor descriptor = TestAllTypes.getDescriptor();
1948     TextFormatParseInfoTree.Builder treeBuilder = TextFormatParseInfoTree.builder();
1949     // Set to allow unknown fields
1950     TextFormat.Parser parser =
1951         TextFormat.Parser.newBuilder()
1952             .setAllowUnknownFields(true)
1953             .setParseInfoTreeBuilder(treeBuilder)
1954             .build();
1955 
1956     final String stringData =
1957         "optional_int32: 1\n"
1958             + "optional_int64: 2\n"
1959             + "  optional_double: 2.4\n"
1960             + "repeated_int32: 5\n"
1961             + "repeated_int32: 10\n"
1962             + "optional_nested_message <\n"
1963             + "  bb: 78\n"
1964             + ">\n"
1965             + "repeated_nested_message <\n"
1966             + "  bb: 79\n"
1967             + ">\n"
1968             + "repeated_nested_message <\n"
1969             + "  bb: 80\n"
1970             + ">";
1971 
1972     parser.merge(stringData, builder);
1973     TextFormatParseInfoTree tree = treeBuilder.build();
1974 
1975     // Verify that the tree has the correct positions.
1976     assertLocation(tree, descriptor, "optional_int32", 0, 0, 0);
1977     assertLocation(tree, descriptor, "optional_int64", 0, 1, 0);
1978     assertLocation(tree, descriptor, "optional_double", 0, 2, 2);
1979 
1980     assertLocation(tree, descriptor, "repeated_int32", 0, 3, 0);
1981     assertLocation(tree, descriptor, "repeated_int32", 1, 4, 0);
1982 
1983     assertLocation(tree, descriptor, "optional_nested_message", 0, 5, 0);
1984     assertLocation(tree, descriptor, "repeated_nested_message", 0, 8, 0);
1985     assertLocation(tree, descriptor, "repeated_nested_message", 1, 11, 0);
1986 
1987     // Check for fields not set. For an invalid field, the location returned should be -1, -1.
1988     assertLocation(tree, descriptor, "repeated_int64", 0, -1, -1);
1989     assertLocation(tree, descriptor, "repeated_int32", 6, -1, -1);
1990 
1991     // Verify inside the nested message.
1992     FieldDescriptor nestedField = descriptor.findFieldByName("optional_nested_message");
1993 
1994     TextFormatParseInfoTree nestedTree = tree.getNestedTrees(nestedField).get(0);
1995     assertLocation(nestedTree, nestedField.getMessageType(), "bb", 0, 6, 2);
1996 
1997     // Verify inside another nested message.
1998     nestedField = descriptor.findFieldByName("repeated_nested_message");
1999     nestedTree = tree.getNestedTrees(nestedField).get(0);
2000     assertLocation(nestedTree, nestedField.getMessageType(), "bb", 0, 9, 2);
2001 
2002     nestedTree = tree.getNestedTrees(nestedField).get(1);
2003     assertLocation(nestedTree, nestedField.getMessageType(), "bb", 0, 12, 2);
2004 
2005     // Verify a NULL tree for an unknown nested field.
2006     try {
2007       tree.getNestedTree(nestedField, 2);
2008       assertWithMessage("unknown nested field should throw").fail();
2009     } catch (IllegalArgumentException unused) {
2010       // pass
2011     }
2012   }
2013 
2014   @SuppressWarnings("LenientFormatStringValidation")
assertLocation( TextFormatParseInfoTree tree, final Descriptor descriptor, final String fieldName, int index, int line, int column)2015   private void assertLocation(
2016       TextFormatParseInfoTree tree,
2017       final Descriptor descriptor,
2018       final String fieldName,
2019       int index,
2020       int line,
2021       int column) {
2022     List<TextFormatParseLocation> locs = tree.getLocations(descriptor.findFieldByName(fieldName));
2023     if (index < locs.size()) {
2024       TextFormatParseLocation location = locs.get(index);
2025       TextFormatParseLocation expected = TextFormatParseLocation.create(line, column);
2026       assertThat(location).isEqualTo(expected);
2027     } else if (line != -1 && column != -1) {
2028       // Expected 0 args, but got 3.
2029       assertWithMessage(
2030               "Tree/descriptor/fieldname did not contain index %d, line %d column %d expected",
2031               index, line, column)
2032           .fail();
2033     }
2034   }
2035 
2036   @Test
testSortMapFields()2037   public void testSortMapFields() throws Exception {
2038     TestMap message =
2039         TestMap.newBuilder()
2040             .putStringToInt32Field("cherry", 30)
2041             .putStringToInt32Field("banana", 20)
2042             .putStringToInt32Field("apple", 10)
2043             .putInt32ToStringField(30, "cherry")
2044             .putInt32ToStringField(20, "banana")
2045             .putInt32ToStringField(10, "apple")
2046             .build();
2047     String text =
2048         "int32_to_string_field {\n"
2049             + "  key: 10\n"
2050             + "  value: \"apple\"\n"
2051             + "}\n"
2052             + "int32_to_string_field {\n"
2053             + "  key: 20\n"
2054             + "  value: \"banana\"\n"
2055             + "}\n"
2056             + "int32_to_string_field {\n"
2057             + "  key: 30\n"
2058             + "  value: \"cherry\"\n"
2059             + "}\n"
2060             + "string_to_int32_field {\n"
2061             + "  key: \"apple\"\n"
2062             + "  value: 10\n"
2063             + "}\n"
2064             + "string_to_int32_field {\n"
2065             + "  key: \"banana\"\n"
2066             + "  value: 20\n"
2067             + "}\n"
2068             + "string_to_int32_field {\n"
2069             + "  key: \"cherry\"\n"
2070             + "  value: 30\n"
2071             + "}\n";
2072     assertThat(TextFormat.printer().printToString(message)).isEqualTo(text);
2073   }
2074 
2075   @Test
testPreservesFloatingPointNegative0()2076   public void testPreservesFloatingPointNegative0() throws Exception {
2077     proto3_unittest.UnittestProto3.TestAllTypes message =
2078         proto3_unittest.UnittestProto3.TestAllTypes.newBuilder()
2079             .setOptionalFloat(-0.0f)
2080             .setOptionalDouble(-0.0)
2081             .build();
2082     assertThat(TextFormat.printer().printToString(message))
2083         .isEqualTo("optional_float: -0.0\noptional_double: -0.0\n");
2084   }
2085 
makeRecursiveMessage(int depth)2086   private TestRecursiveMessage makeRecursiveMessage(int depth) {
2087     if (depth == 0) {
2088       return TestRecursiveMessage.newBuilder().setI(5).build();
2089     } else {
2090       return TestRecursiveMessage.newBuilder().setA(makeRecursiveMessage(depth - 1)).build();
2091     }
2092   }
2093 
2094   @Test
testDefaultRecursionLimit()2095   public void testDefaultRecursionLimit() throws Exception {
2096     String depth100 = TextFormat.printer().printToString(makeRecursiveMessage(100));
2097     String depth101 = TextFormat.printer().printToString(makeRecursiveMessage(101));
2098     TextFormat.parse(depth100, TestRecursiveMessage.class);
2099     try {
2100       TextFormat.parse(depth101, TestRecursiveMessage.class);
2101       assertWithMessage("Parsing deep message should have failed").fail();
2102     } catch (TextFormat.ParseException e) {
2103       assertThat(e).hasMessageThat().contains("too deep");
2104     }
2105   }
2106 
2107   @Test
testRecursionLimitWithUnknownFields()2108   public void testRecursionLimitWithUnknownFields() throws Exception {
2109     TextFormat.Parser parser =
2110         TextFormat.Parser.newBuilder().setAllowUnknownFields(true).setRecursionLimit(2).build();
2111     TestRecursiveMessage.Builder depth2 = TestRecursiveMessage.newBuilder();
2112     parser.merge("u { u { i: 0 } }", depth2);
2113     try {
2114       TestRecursiveMessage.Builder depth3 = TestRecursiveMessage.newBuilder();
2115       parser.merge("u { u { u { } } }", depth3);
2116       assertWithMessage("Parsing deep message should have failed").fail();
2117     } catch (TextFormat.ParseException e) {
2118       assertThat(e).hasMessageThat().contains("too deep");
2119     }
2120   }
2121 
2122   @Test
testRecursionLimitWithKnownAndUnknownFields()2123   public void testRecursionLimitWithKnownAndUnknownFields() throws Exception {
2124     TextFormat.Parser parser =
2125         TextFormat.Parser.newBuilder().setAllowUnknownFields(true).setRecursionLimit(2).build();
2126     TestRecursiveMessage.Builder depth2 = TestRecursiveMessage.newBuilder();
2127     parser.merge("a { u { i: 0 } }", depth2);
2128     try {
2129       TestRecursiveMessage.Builder depth3 = TestRecursiveMessage.newBuilder();
2130       parser.merge("a { u { u { } } }", depth3);
2131       assertWithMessage("Parsing deep message should have failed").fail();
2132     } catch (TextFormat.ParseException e) {
2133       assertThat(e).hasMessageThat().contains("too deep");
2134     }
2135   }
2136 
2137   @Test
testRecursionLimitWithAny()2138   public void testRecursionLimitWithAny() throws Exception {
2139     TextFormat.Parser parser =
2140         TextFormat.Parser.newBuilder()
2141             .setRecursionLimit(2)
2142             .setTypeRegistry(TypeRegistry.newBuilder().add(TestAllTypes.getDescriptor()).build())
2143             .build();
2144     TestAny.Builder depth2 = TestAny.newBuilder();
2145     parser.merge(
2146         "value { [type.googleapis.com/protobuf_unittest.TestAllTypes] { optional_int32: 1 } }",
2147         depth2);
2148     try {
2149       TestAny.Builder depth3 = TestAny.newBuilder();
2150       parser.merge(
2151           "value { [type.googleapis.com/protobuf_unittest.TestAllTypes] { optional_nested_message {"
2152               + "} } }",
2153           depth3);
2154       assertWithMessage("Parsing deep message should have failed").fail();
2155     } catch (TextFormat.ParseException e) {
2156       assertThat(e).hasMessageThat().contains("too deep");
2157     }
2158   }
2159 
2160   @Test
testRecursionLimitWithTopLevelAny()2161   public void testRecursionLimitWithTopLevelAny() throws Exception {
2162     TextFormat.Parser parser =
2163         TextFormat.Parser.newBuilder()
2164             .setRecursionLimit(2)
2165             .setTypeRegistry(
2166                 TypeRegistry.newBuilder().add(TestRecursiveMessage.getDescriptor()).build())
2167             .build();
2168     Any.Builder depth2 = Any.newBuilder();
2169     parser.merge(
2170         "[type.googleapis.com/protobuf_unittest.TestRecursiveMessage] { a { i: 0 } }", depth2);
2171     try {
2172       Any.Builder depth3 = Any.newBuilder();
2173       parser.merge(
2174           "[type.googleapis.com/protobuf_unittest.TestRecursiveMessage] { a { a { i: 0 } } }",
2175           depth3);
2176       assertWithMessage("Parsing deep message should have failed").fail();
2177     } catch (TextFormat.ParseException e) {
2178       assertThat(e).hasMessageThat().contains("too deep");
2179     }
2180   }
2181 }
2182