1 // Protocol Buffers - Google's data interchange format 2 // Copyright 2008 Google Inc. All rights reserved. 3 // https://developers.google.com/protocol-buffers/ 4 // 5 // Redistribution and use in source and binary forms, with or without 6 // modification, are permitted provided that the following conditions are 7 // met: 8 // 9 // * Redistributions of source code must retain the above copyright 10 // notice, this list of conditions and the following disclaimer. 11 // * Redistributions in binary form must reproduce the above 12 // copyright notice, this list of conditions and the following disclaimer 13 // in the documentation and/or other materials provided with the 14 // distribution. 15 // * Neither the name of Google Inc. nor the names of its 16 // contributors may be used to endorse or promote products derived from 17 // this software without specific prior written permission. 18 // 19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 31 package com.google.protobuf; 32 33 import static com.google.protobuf.TestUtil.TEST_REQUIRED_INITIALIZED; 34 import static com.google.protobuf.TestUtil.TEST_REQUIRED_UNINITIALIZED; 35 36 import com.google.protobuf.DescriptorProtos.DescriptorProto; 37 import com.google.protobuf.DescriptorProtos.FieldDescriptorProto; 38 import com.google.protobuf.DescriptorProtos.FileDescriptorProto; 39 import com.google.protobuf.Descriptors.Descriptor; 40 import com.google.protobuf.Descriptors.FieldDescriptor; 41 import com.google.protobuf.Descriptors.FileDescriptor; 42 import com.google.protobuf.TextFormat.Parser.SingularOverwritePolicy; 43 import com.google.protobuf.testing.proto.TestProto3Optional; 44 import com.google.protobuf.testing.proto.TestProto3Optional.NestedEnum; 45 import any_test.AnyTestProto.TestAny; 46 import map_test.MapTestProto.TestMap; 47 import protobuf_unittest.UnittestMset.TestMessageSetExtension1; 48 import protobuf_unittest.UnittestMset.TestMessageSetExtension2; 49 import protobuf_unittest.UnittestProto.OneString; 50 import protobuf_unittest.UnittestProto.TestAllExtensions; 51 import protobuf_unittest.UnittestProto.TestAllTypes; 52 import protobuf_unittest.UnittestProto.TestAllTypes.NestedMessage; 53 import protobuf_unittest.UnittestProto.TestEmptyMessage; 54 import protobuf_unittest.UnittestProto.TestOneof2; 55 import protobuf_unittest.UnittestProto.TestRequired; 56 import proto2_wireformat_unittest.UnittestMsetWireFormat.TestMessageSet; 57 import java.io.StringReader; 58 import java.util.Arrays; 59 import java.util.List; 60 import java.util.logging.Logger; 61 import junit.framework.TestCase; 62 63 /** 64 * Test case for {@link TextFormat}. 65 * 66 * <p>TODO(wenboz): ExtensionTest and rest of text_format_unittest.cc. 67 * 68 * @author wenboz@google.com (Wenbo Zhu) 69 */ 70 public class TextFormatTest extends TestCase { 71 72 // A basic string with different escapable characters for testing. 73 private static final String ESCAPE_TEST_STRING = 74 "\"A string with ' characters \n and \r newlines and \t tabs and \001 slashes \\"; 75 76 // A representation of the above string with all the characters escaped. 77 private static final String ESCAPE_TEST_STRING_ESCAPED = 78 "\\\"A string with \\' characters \\n and \\r newlines " 79 + "and \\t tabs and \\001 slashes \\\\"; 80 81 private static String allFieldsSetText = 82 TestUtil.readTextFromFile("text_format_unittest_data_oneof_implemented.txt"); 83 private static String allExtensionsSetText = 84 TestUtil.readTextFromFile("text_format_unittest_extensions_data.txt"); 85 86 private static String exoticText = 87 "" 88 + "repeated_int32: -1\n" 89 + "repeated_int32: -2147483648\n" 90 + "repeated_int64: -1,\n" 91 + "repeated_int64: -9223372036854775808\n" 92 + "repeated_uint32: 4294967295\n" 93 + "repeated_uint32: 2147483648\n" 94 + "repeated_uint64: 18446744073709551615\n" 95 + "repeated_uint64: 9223372036854775808\n" 96 + "repeated_double: 123.0\n" 97 + "repeated_double: 123.5\n" 98 + "repeated_double: 0.125\n" 99 + "repeated_double: .125\n" 100 + "repeated_double: -.125\n" 101 + "repeated_double: 1.23E17\n" 102 + "repeated_double: 1.23E+17\n" 103 + "repeated_double: -1.23e-17\n" 104 + "repeated_double: .23e+17\n" 105 + "repeated_double: -.23E17\n" 106 + "repeated_double: 1.235E22\n" 107 + "repeated_double: 1.235E-18\n" 108 + "repeated_double: 123.456789\n" 109 + "repeated_double: Infinity\n" 110 + "repeated_double: -Infinity\n" 111 + "repeated_double: NaN\n" 112 + "repeated_string: \"\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\"" 113 + "\\341\\210\\264\"\n" 114 + "repeated_bytes: \"\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\"\\376\"\n"; 115 116 private static String canonicalExoticText = 117 exoticText 118 .replace(": .", ": 0.") 119 .replace(": -.", ": -0.") // short-form double 120 .replace("23e", "23E") 121 .replace("E+", "E") 122 .replace("0.23E17", "2.3E16") 123 .replace(",", ""); 124 125 private String messageSetText = 126 "" 127 + "[protobuf_unittest.TestMessageSetExtension1] {\n" 128 + " i: 123\n" 129 + "}\n" 130 + "[protobuf_unittest.TestMessageSetExtension2] {\n" 131 + " str: \"foo\"\n" 132 + "}\n"; 133 134 private String messageSetTextWithRepeatedExtension = 135 "" 136 + "[protobuf_unittest.TestMessageSetExtension1] {\n" 137 + " i: 123\n" 138 + "}\n" 139 + "[protobuf_unittest.TestMessageSetExtension1] {\n" 140 + " i: 456\n" 141 + "}\n"; 142 143 private final TextFormat.Parser parserAllowingUnknownFields = 144 TextFormat.Parser.newBuilder().setAllowUnknownFields(true).build(); 145 146 private final TextFormat.Parser parserAllowingUnknownExtensions = 147 TextFormat.Parser.newBuilder().setAllowUnknownExtensions(true).build(); 148 149 private final TextFormat.Parser parserWithOverwriteForbidden = 150 TextFormat.Parser.newBuilder() 151 .setSingularOverwritePolicy(SingularOverwritePolicy.FORBID_SINGULAR_OVERWRITES) 152 .build(); 153 154 private final TextFormat.Parser defaultParser = TextFormat.Parser.newBuilder().build(); 155 156 /** Print TestAllTypes and compare with golden file. */ testPrintMessage()157 public void testPrintMessage() throws Exception { 158 String javaText = TextFormat.printer().printToString(TestUtil.getAllSet()); 159 160 // Java likes to add a trailing ".0" to floats and doubles. C printf 161 // (with %g format) does not. Our golden files are used for both 162 // C++ and Java TextFormat classes, so we need to conform. 163 javaText = javaText.replace(".0\n", "\n"); 164 165 assertEquals(allFieldsSetText, javaText); 166 } 167 168 /** Print TestAllTypes as Builder and compare with golden file. */ testPrintMessageBuilder()169 public void testPrintMessageBuilder() throws Exception { 170 String javaText = TextFormat.printer().printToString(TestUtil.getAllSetBuilder()); 171 172 // Java likes to add a trailing ".0" to floats and doubles. C printf 173 // (with %g format) does not. Our golden files are used for both 174 // C++ and Java TextFormat classes, so we need to conform. 175 javaText = javaText.replace(".0\n", "\n"); 176 177 assertEquals(allFieldsSetText, javaText); 178 } 179 180 /** Print TestAllExtensions and compare with golden file. */ testPrintExtensions()181 public void testPrintExtensions() throws Exception { 182 String javaText = TextFormat.printer().printToString(TestUtil.getAllExtensionsSet()); 183 184 // Java likes to add a trailing ".0" to floats and doubles. C printf 185 // (with %g format) does not. Our golden files are used for both 186 // C++ and Java TextFormat classes, so we need to conform. 187 javaText = javaText.replace(".0\n", "\n"); 188 189 assertEquals(allExtensionsSetText, javaText); 190 } 191 192 // Creates an example unknown field set. makeUnknownFieldSet()193 private UnknownFieldSet makeUnknownFieldSet() { 194 195 return UnknownFieldSet.newBuilder() 196 .addField( 197 5, 198 UnknownFieldSet.Field.newBuilder() 199 .addVarint(1) 200 .addFixed32(2) 201 .addFixed64(3) 202 .addLengthDelimited(ByteString.copyFromUtf8("4")) 203 .addLengthDelimited( 204 UnknownFieldSet.newBuilder() 205 .addField(12, UnknownFieldSet.Field.newBuilder().addVarint(6).build()) 206 .build() 207 .toByteString()) 208 .addGroup( 209 UnknownFieldSet.newBuilder() 210 .addField(10, UnknownFieldSet.Field.newBuilder().addVarint(5).build()) 211 .build()) 212 .build()) 213 .addField( 214 8, UnknownFieldSet.Field.newBuilder().addVarint(1).addVarint(2).addVarint(3).build()) 215 .addField( 216 15, 217 UnknownFieldSet.Field.newBuilder() 218 .addVarint(0xABCDEF1234567890L) 219 .addFixed32(0xABCD1234) 220 .addFixed64(0xABCDEF1234567890L) 221 .build()) 222 .build(); 223 } 224 testPrintUnknownFields()225 public void testPrintUnknownFields() throws Exception { 226 // Test printing of unknown fields in a message. 227 228 TestEmptyMessage message = 229 TestEmptyMessage.newBuilder().setUnknownFields(makeUnknownFieldSet()).build(); 230 231 assertEquals( 232 "5: 1\n" 233 + "5: 0x00000002\n" 234 + "5: 0x0000000000000003\n" 235 + "5: \"4\"\n" 236 + "5: {\n" 237 + " 12: 6\n" 238 + "}\n" 239 + "5 {\n" 240 + " 10: 5\n" 241 + "}\n" 242 + "8: 1\n" 243 + "8: 2\n" 244 + "8: 3\n" 245 + "15: 12379813812177893520\n" 246 + "15: 0xabcd1234\n" 247 + "15: 0xabcdef1234567890\n", 248 TextFormat.printer().printToString(message)); 249 } 250 testPrintField()251 public void testPrintField() throws Exception { 252 final FieldDescriptor dataField = OneString.getDescriptor().findFieldByName("data"); 253 assertEquals( 254 "data: \"test data\"\n", TextFormat.printer().printFieldToString(dataField, "test data")); 255 256 final FieldDescriptor optionalField = 257 TestAllTypes.getDescriptor().findFieldByName("optional_nested_message"); 258 final Object value = NestedMessage.newBuilder().setBb(42).build(); 259 260 assertEquals( 261 "optional_nested_message {\n bb: 42\n}\n", 262 TextFormat.printer().printFieldToString(optionalField, value)); 263 } 264 265 /** 266 * Helper to construct a ByteString from a String containing only 8-bit characters. The characters 267 * are converted directly to bytes, *not* encoded using UTF-8. 268 */ bytes(String str)269 private ByteString bytes(String str) { 270 return ByteString.copyFrom(str.getBytes(Internal.ISO_8859_1)); 271 } 272 273 /** 274 * Helper to construct a ByteString from a bunch of bytes. The inputs are actually ints so that I 275 * can use hex notation and not get stupid errors about precision. 276 */ bytes(int... bytesAsInts)277 private ByteString bytes(int... bytesAsInts) { 278 byte[] bytes = new byte[bytesAsInts.length]; 279 for (int i = 0; i < bytesAsInts.length; i++) { 280 bytes[i] = (byte) bytesAsInts[i]; 281 } 282 return ByteString.copyFrom(bytes); 283 } 284 testPrintExotic()285 public void testPrintExotic() throws Exception { 286 Message message = 287 TestAllTypes.newBuilder() 288 // Signed vs. unsigned numbers. 289 .addRepeatedInt32(-1) 290 .addRepeatedUint32(-1) 291 .addRepeatedInt64(-1) 292 .addRepeatedUint64(-1) 293 .addRepeatedInt32(1 << 31) 294 .addRepeatedUint32(1 << 31) 295 .addRepeatedInt64(1L << 63) 296 .addRepeatedUint64(1L << 63) 297 298 // Floats of various precisions and exponents. 299 .addRepeatedDouble(123) 300 .addRepeatedDouble(123.5) 301 .addRepeatedDouble(0.125) 302 .addRepeatedDouble(.125) 303 .addRepeatedDouble(-.125) 304 .addRepeatedDouble(123e15) 305 .addRepeatedDouble(123e15) 306 .addRepeatedDouble(-1.23e-17) 307 .addRepeatedDouble(.23e17) 308 .addRepeatedDouble(-23e15) 309 .addRepeatedDouble(123.5e20) 310 .addRepeatedDouble(123.5e-20) 311 .addRepeatedDouble(123.456789) 312 .addRepeatedDouble(Double.POSITIVE_INFINITY) 313 .addRepeatedDouble(Double.NEGATIVE_INFINITY) 314 .addRepeatedDouble(Double.NaN) 315 316 // Strings and bytes that needing escaping. 317 .addRepeatedString("\0\001\007\b\f\n\r\t\013\\\'\"\u1234") 318 .addRepeatedBytes(bytes("\0\001\007\b\f\n\r\t\013\\\'\"\u00fe")) 319 .build(); 320 321 assertEquals(canonicalExoticText, message.toString()); 322 } 323 testRoundtripProto3Optional()324 public void testRoundtripProto3Optional() throws Exception { 325 Message message = 326 TestProto3Optional.newBuilder() 327 .setOptionalInt32(1) 328 .setOptionalInt64(2) 329 .setOptionalNestedEnum(NestedEnum.BAZ) 330 .build(); 331 TestProto3Optional.Builder message2 = TestProto3Optional.newBuilder(); 332 TextFormat.merge(message.toString(), message2); 333 334 assertTrue(message2.hasOptionalInt32()); 335 assertTrue(message2.hasOptionalInt64()); 336 assertTrue(message2.hasOptionalNestedEnum()); 337 assertEquals(1, message2.getOptionalInt32()); 338 assertEquals(2, message2.getOptionalInt64()); 339 assertEquals(NestedEnum.BAZ, message2.getOptionalNestedEnum()); 340 } 341 testPrintMessageSet()342 public void testPrintMessageSet() throws Exception { 343 TestMessageSet messageSet = 344 TestMessageSet.newBuilder() 345 .setExtension( 346 TestMessageSetExtension1.messageSetExtension, 347 TestMessageSetExtension1.newBuilder().setI(123).build()) 348 .setExtension( 349 TestMessageSetExtension2.messageSetExtension, 350 TestMessageSetExtension2.newBuilder().setStr("foo").build()) 351 .build(); 352 353 assertEquals(messageSetText, messageSet.toString()); 354 } 355 356 // ================================================================= 357 testMerge()358 public void testMerge() throws Exception { 359 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 360 TextFormat.merge(allFieldsSetText, builder); 361 TestUtil.assertAllFieldsSet(builder.build()); 362 } 363 testParse()364 public void testParse() throws Exception { 365 TestUtil.assertAllFieldsSet(TextFormat.parse(allFieldsSetText, TestAllTypes.class)); 366 } 367 testMergeInitialized()368 public void testMergeInitialized() throws Exception { 369 TestRequired.Builder builder = TestRequired.newBuilder(); 370 TextFormat.merge(TEST_REQUIRED_INITIALIZED.toString(), builder); 371 assertEquals(TEST_REQUIRED_INITIALIZED.toString(), builder.buildPartial().toString()); 372 assertTrue(builder.isInitialized()); 373 } 374 testParseInitialized()375 public void testParseInitialized() throws Exception { 376 TestRequired parsed = 377 TextFormat.parse(TEST_REQUIRED_INITIALIZED.toString(), TestRequired.class); 378 assertEquals(TEST_REQUIRED_INITIALIZED.toString(), parsed.toString()); 379 assertTrue(parsed.isInitialized()); 380 } 381 testMergeUninitialized()382 public void testMergeUninitialized() throws Exception { 383 TestRequired.Builder builder = TestRequired.newBuilder(); 384 TextFormat.merge(TEST_REQUIRED_UNINITIALIZED.toString(), builder); 385 assertEquals(TEST_REQUIRED_UNINITIALIZED.toString(), builder.buildPartial().toString()); 386 assertFalse(builder.isInitialized()); 387 } 388 testParseUninitialized()389 public void testParseUninitialized() throws Exception { 390 try { 391 TextFormat.parse(TEST_REQUIRED_UNINITIALIZED.toString(), TestRequired.class); 392 fail("Expected UninitializedMessageException."); 393 } catch (UninitializedMessageException e) { 394 assertEquals("Message missing required fields: b, c", e.getMessage()); 395 } 396 } 397 testMergeReader()398 public void testMergeReader() throws Exception { 399 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 400 TextFormat.merge(new StringReader(allFieldsSetText), builder); 401 TestUtil.assertAllFieldsSet(builder.build()); 402 } 403 testMergeExtensions()404 public void testMergeExtensions() throws Exception { 405 TestAllExtensions.Builder builder = TestAllExtensions.newBuilder(); 406 TextFormat.merge(allExtensionsSetText, TestUtil.getFullExtensionRegistry(), builder); 407 TestUtil.assertAllExtensionsSet(builder.build()); 408 } 409 testParseExtensions()410 public void testParseExtensions() throws Exception { 411 TestUtil.assertAllExtensionsSet( 412 TextFormat.parse( 413 allExtensionsSetText, TestUtil.getFullExtensionRegistry(), TestAllExtensions.class)); 414 } 415 testMergeAndParseCompatibility()416 public void testMergeAndParseCompatibility() throws Exception { 417 String original = 418 "repeated_float: inf\n" 419 + "repeated_float: -inf\n" 420 + "repeated_float: nan\n" 421 + "repeated_float: inff\n" 422 + "repeated_float: -inff\n" 423 + "repeated_float: nanf\n" 424 + "repeated_float: 1.0f\n" 425 + "repeated_float: infinityf\n" 426 + "repeated_float: -Infinityf\n" 427 + "repeated_double: infinity\n" 428 + "repeated_double: -infinity\n" 429 + "repeated_double: nan\n"; 430 String canonical = 431 "repeated_float: Infinity\n" 432 + "repeated_float: -Infinity\n" 433 + "repeated_float: NaN\n" 434 + "repeated_float: Infinity\n" 435 + "repeated_float: -Infinity\n" 436 + "repeated_float: NaN\n" 437 + "repeated_float: 1.0\n" 438 + "repeated_float: Infinity\n" 439 + "repeated_float: -Infinity\n" 440 + "repeated_double: Infinity\n" 441 + "repeated_double: -Infinity\n" 442 + "repeated_double: NaN\n"; 443 444 // Test merge(). 445 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 446 TextFormat.merge(original, builder); 447 assertEquals(canonical, builder.build().toString()); 448 449 // Test parse(). 450 assertEquals(canonical, TextFormat.parse(original, TestAllTypes.class).toString()); 451 } 452 testMergeAndParseExotic()453 public void testMergeAndParseExotic() throws Exception { 454 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 455 TextFormat.merge(exoticText, builder); 456 457 // Too lazy to check things individually. Don't try to debug this 458 // if testPrintExotic() is failing. 459 assertEquals(canonicalExoticText, builder.build().toString()); 460 assertEquals(canonicalExoticText, TextFormat.parse(exoticText, TestAllTypes.class).toString()); 461 } 462 testMergeMessageSet()463 public void testMergeMessageSet() throws Exception { 464 ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance(); 465 extensionRegistry.add(TestMessageSetExtension1.messageSetExtension); 466 extensionRegistry.add(TestMessageSetExtension2.messageSetExtension); 467 468 TestMessageSet.Builder builder = TestMessageSet.newBuilder(); 469 TextFormat.merge(messageSetText, extensionRegistry, builder); 470 TestMessageSet messageSet = builder.build(); 471 472 assertTrue(messageSet.hasExtension(TestMessageSetExtension1.messageSetExtension)); 473 assertEquals(123, messageSet.getExtension(TestMessageSetExtension1.messageSetExtension).getI()); 474 assertTrue(messageSet.hasExtension(TestMessageSetExtension2.messageSetExtension)); 475 assertEquals( 476 "foo", messageSet.getExtension(TestMessageSetExtension2.messageSetExtension).getStr()); 477 478 builder = TestMessageSet.newBuilder(); 479 TextFormat.merge(messageSetTextWithRepeatedExtension, extensionRegistry, builder); 480 messageSet = builder.build(); 481 assertEquals(456, messageSet.getExtension(TestMessageSetExtension1.messageSetExtension).getI()); 482 } 483 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 parserWithOverwriteForbidden.merge(messageSetText, extensionRegistry, builder); 491 TestMessageSet messageSet = builder.build(); 492 assertEquals(123, messageSet.getExtension(TestMessageSetExtension1.messageSetExtension).getI()); 493 assertEquals( 494 "foo", messageSet.getExtension(TestMessageSetExtension2.messageSetExtension).getStr()); 495 496 builder = TestMessageSet.newBuilder(); 497 try { 498 parserWithOverwriteForbidden.merge( 499 messageSetTextWithRepeatedExtension, extensionRegistry, builder); 500 fail("expected parse exception"); 501 } catch (TextFormat.ParseException e) { 502 assertEquals( 503 "4:44: Non-repeated field " 504 + "\"protobuf_unittest.TestMessageSetExtension1.message_set_extension\"" 505 + " cannot be overwritten.", 506 e.getMessage()); 507 } 508 } 509 testMergeNumericEnum()510 public void testMergeNumericEnum() throws Exception { 511 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 512 TextFormat.merge("optional_nested_enum: 2", builder); 513 assertEquals(TestAllTypes.NestedEnum.BAR, builder.getOptionalNestedEnum()); 514 } 515 testMergeAngleBrackets()516 public void testMergeAngleBrackets() throws Exception { 517 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 518 TextFormat.merge("OptionalGroup: < a: 1 >", builder); 519 assertTrue(builder.hasOptionalGroup()); 520 assertEquals(1, builder.getOptionalGroup().getA()); 521 } 522 testMergeComment()523 public void testMergeComment() throws Exception { 524 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 525 TextFormat.merge( 526 "# this is a comment\n" 527 + "optional_int32: 1 # another comment\n" 528 + "optional_int64: 2\n" 529 + "# EOF comment", 530 builder); 531 assertEquals(1, builder.getOptionalInt32()); 532 assertEquals(2, builder.getOptionalInt64()); 533 } 534 testPrintAny_customBuiltTypeRegistry()535 public void testPrintAny_customBuiltTypeRegistry() throws Exception { 536 TestAny testAny = 537 TestAny.newBuilder() 538 .setValue( 539 Any.newBuilder() 540 .setTypeUrl("type.googleapis.com/" + TestAllTypes.getDescriptor().getFullName()) 541 .setValue( 542 TestAllTypes.newBuilder().setOptionalInt32(12345).build().toByteString()) 543 .build()) 544 .build(); 545 String actual = 546 TextFormat.printer() 547 .usingTypeRegistry(TypeRegistry.newBuilder().add(TestAllTypes.getDescriptor()).build()) 548 .printToString(testAny); 549 String expected = 550 "value {\n" 551 + " [type.googleapis.com/protobuf_unittest.TestAllTypes] {\n" 552 + " optional_int32: 12345\n" 553 + " }\n" 554 + "}\n"; 555 assertEquals(expected, actual); 556 } 557 createDescriptorForAny(FieldDescriptorProto... fields)558 private static Descriptor createDescriptorForAny(FieldDescriptorProto... fields) 559 throws Exception { 560 FileDescriptor fileDescriptor = 561 FileDescriptor.buildFrom( 562 FileDescriptorProto.newBuilder() 563 .setName("any.proto") 564 .setPackage("google.protobuf") 565 .setSyntax("proto3") 566 .addMessageType( 567 DescriptorProto.newBuilder() 568 .setName("Any") 569 .addAllField(Arrays.asList(fields))) 570 .build(), 571 new FileDescriptor[0]); 572 return fileDescriptor.getMessageTypes().get(0); 573 } 574 testPrintAny_anyWithDynamicMessage()575 public void testPrintAny_anyWithDynamicMessage() throws Exception { 576 Descriptor descriptor = 577 createDescriptorForAny( 578 FieldDescriptorProto.newBuilder() 579 .setName("type_url") 580 .setNumber(1) 581 .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL) 582 .setType(FieldDescriptorProto.Type.TYPE_STRING) 583 .build(), 584 FieldDescriptorProto.newBuilder() 585 .setName("value") 586 .setNumber(2) 587 .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL) 588 .setType(FieldDescriptorProto.Type.TYPE_BYTES) 589 .build()); 590 DynamicMessage testAny = 591 DynamicMessage.newBuilder(descriptor) 592 .setField( 593 descriptor.findFieldByNumber(1), 594 "type.googleapis.com/" + TestAllTypes.getDescriptor().getFullName()) 595 .setField( 596 descriptor.findFieldByNumber(2), 597 TestAllTypes.newBuilder().setOptionalInt32(12345).build().toByteString()) 598 .build(); 599 String actual = 600 TextFormat.printer() 601 .usingTypeRegistry(TypeRegistry.newBuilder().add(TestAllTypes.getDescriptor()).build()) 602 .printToString(testAny); 603 String expected = 604 "[type.googleapis.com/protobuf_unittest.TestAllTypes] {\n" 605 + " optional_int32: 12345\n" 606 + "}\n"; 607 assertEquals(expected, actual); 608 } 609 testPrintAny_anyFromWithNoValueField()610 public void testPrintAny_anyFromWithNoValueField() throws Exception { 611 Descriptor descriptor = 612 createDescriptorForAny( 613 FieldDescriptorProto.newBuilder() 614 .setName("type_url") 615 .setNumber(1) 616 .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL) 617 .setType(FieldDescriptorProto.Type.TYPE_STRING) 618 .build()); 619 DynamicMessage testAny = 620 DynamicMessage.newBuilder(descriptor) 621 .setField( 622 descriptor.findFieldByNumber(1), 623 "type.googleapis.com/" + TestAllTypes.getDescriptor().getFullName()) 624 .build(); 625 String actual = 626 TextFormat.printer() 627 .usingTypeRegistry(TypeRegistry.newBuilder().add(TestAllTypes.getDescriptor()).build()) 628 .printToString(testAny); 629 String expected = "type_url: \"type.googleapis.com/protobuf_unittest.TestAllTypes\"\n"; 630 assertEquals(expected, actual); 631 } 632 testPrintAny_anyFromWithNoTypeUrlField()633 public void testPrintAny_anyFromWithNoTypeUrlField() throws Exception { 634 Descriptor descriptor = 635 createDescriptorForAny( 636 FieldDescriptorProto.newBuilder() 637 .setName("value") 638 .setNumber(2) 639 .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL) 640 .setType(FieldDescriptorProto.Type.TYPE_BYTES) 641 .build()); 642 DynamicMessage testAny = 643 DynamicMessage.newBuilder(descriptor) 644 .setField( 645 descriptor.findFieldByNumber(2), 646 TestAllTypes.newBuilder().setOptionalInt32(12345).build().toByteString()) 647 .build(); 648 String actual = 649 TextFormat.printer() 650 .usingTypeRegistry(TypeRegistry.newBuilder().add(TestAllTypes.getDescriptor()).build()) 651 .printToString(testAny); 652 String expected = "value: \"\\b\\271`\"\n"; 653 assertEquals(expected, actual); 654 } 655 testPrintAny_anyWithInvalidFieldType()656 public void testPrintAny_anyWithInvalidFieldType() throws Exception { 657 Descriptor descriptor = 658 createDescriptorForAny( 659 FieldDescriptorProto.newBuilder() 660 .setName("type_url") 661 .setNumber(1) 662 .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL) 663 .setType(FieldDescriptorProto.Type.TYPE_STRING) 664 .build(), 665 FieldDescriptorProto.newBuilder() 666 .setName("value") 667 .setNumber(2) 668 .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL) 669 .setType(FieldDescriptorProto.Type.TYPE_STRING) 670 .build()); 671 DynamicMessage testAny = 672 DynamicMessage.newBuilder(descriptor) 673 .setField( 674 descriptor.findFieldByNumber(1), 675 "type.googleapis.com/" + TestAllTypes.getDescriptor().getFullName()) 676 .setField(descriptor.findFieldByNumber(2), "test") 677 .build(); 678 String actual = 679 TextFormat.printer() 680 .usingTypeRegistry(TypeRegistry.newBuilder().add(TestAllTypes.getDescriptor()).build()) 681 .printToString(testAny); 682 String expected = 683 "type_url: \"type.googleapis.com/protobuf_unittest.TestAllTypes\"\n" + "value: \"test\"\n"; 684 assertEquals(expected, actual); 685 } 686 687 testMergeAny_customBuiltTypeRegistry()688 public void testMergeAny_customBuiltTypeRegistry() throws Exception { 689 TestAny.Builder builder = TestAny.newBuilder(); 690 TextFormat.Parser.newBuilder() 691 .setTypeRegistry(TypeRegistry.newBuilder().add(TestAllTypes.getDescriptor()).build()) 692 .build() 693 .merge( 694 "value: {\n" 695 + "[type.googleapis.com/protobuf_unittest.TestAllTypes] {\n" 696 + "optional_int32: 12345\n" 697 + "optional_nested_message {\n" 698 + " bb: 123\n" 699 + "}\n" 700 + "}\n" 701 + "}", 702 builder); 703 assertEquals( 704 TestAny.newBuilder() 705 .setValue( 706 Any.newBuilder() 707 .setTypeUrl("type.googleapis.com/" + TestAllTypes.getDescriptor().getFullName()) 708 .setValue( 709 TestAllTypes.newBuilder() 710 .setOptionalInt32(12345) 711 .setOptionalNestedMessage( 712 TestAllTypes.NestedMessage.newBuilder().setBb(123)) 713 .build() 714 .toByteString()) 715 .build()) 716 .build(), 717 builder.build()); 718 } 719 720 assertParseError(String error, String text)721 private void assertParseError(String error, String text) { 722 // Test merge(). 723 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 724 try { 725 TextFormat.merge(text, TestUtil.getFullExtensionRegistry(), builder); 726 fail("Expected parse exception."); 727 } catch (TextFormat.ParseException e) { 728 assertEquals(error, e.getMessage()); 729 } 730 731 // Test parse(). 732 try { 733 TextFormat.parse(text, TestUtil.getFullExtensionRegistry(), TestAllTypes.class); 734 fail("Expected parse exception."); 735 } catch (TextFormat.ParseException e) { 736 assertEquals(error, e.getMessage()); 737 } 738 } 739 assertParseErrorWithUnknownFields(String error, String text)740 private void assertParseErrorWithUnknownFields(String error, String text) { 741 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 742 try { 743 parserAllowingUnknownFields.merge(text, TestUtil.getFullExtensionRegistry(), builder); 744 fail("Expected parse exception."); 745 } catch (TextFormat.ParseException e) { 746 assertEquals(error, e.getMessage()); 747 } 748 } 749 assertParseSuccessWithUnknownFields(String text)750 private TestAllTypes assertParseSuccessWithUnknownFields(String text) 751 throws TextFormat.ParseException { 752 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 753 parserAllowingUnknownFields.merge(text, TestUtil.getFullExtensionRegistry(), builder); 754 return builder.build(); 755 } 756 assertParseErrorWithUnknownExtensions(String error, String text)757 private void assertParseErrorWithUnknownExtensions(String error, String text) { 758 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 759 try { 760 parserAllowingUnknownExtensions.merge(text, builder); 761 fail("Expected parse exception."); 762 } catch (TextFormat.ParseException e) { 763 assertEquals(error, e.getMessage()); 764 } 765 } 766 assertParseSuccessWithUnknownExtensions(String text)767 private TestAllTypes assertParseSuccessWithUnknownExtensions(String text) 768 throws TextFormat.ParseException { 769 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 770 parserAllowingUnknownExtensions.merge(text, builder); 771 return builder.build(); 772 } 773 assertParseErrorWithOverwriteForbidden(String error, String text)774 private void assertParseErrorWithOverwriteForbidden(String error, String text) { 775 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 776 try { 777 parserWithOverwriteForbidden.merge(text, TestUtil.getFullExtensionRegistry(), builder); 778 fail("Expected parse exception."); 779 } catch (TextFormat.ParseException e) { 780 assertEquals(error, e.getMessage()); 781 } 782 } 783 assertParseSuccessWithOverwriteForbidden(String text)784 private TestAllTypes assertParseSuccessWithOverwriteForbidden(String text) 785 throws TextFormat.ParseException { 786 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 787 parserWithOverwriteForbidden.merge(text, TestUtil.getFullExtensionRegistry(), builder); 788 return builder.build(); 789 } 790 testParseErrors()791 public void testParseErrors() throws Exception { 792 assertParseError("1:16: Expected \":\".", "optional_int32 123"); 793 assertParseError("1:23: Expected identifier. Found '?'", "optional_nested_enum: ?"); 794 assertParseError( 795 "1:18: Couldn't parse integer: Number must be positive: -1", "optional_uint32: -1"); 796 assertParseError( 797 "1:17: Couldn't parse integer: Number out of range for 32-bit signed " 798 + "integer: 82301481290849012385230157", 799 "optional_int32: 82301481290849012385230157"); 800 assertParseError( 801 "1:16: Expected \"true\" or \"false\". Found \"maybe\".", "optional_bool: maybe"); 802 assertParseError("1:16: Expected \"true\" or \"false\". Found \"2\".", "optional_bool: 2"); 803 assertParseError("1:18: Expected string.", "optional_string: 123"); 804 assertParseError("1:18: String missing ending quote.", "optional_string: \"ueoauaoe"); 805 assertParseError( 806 "1:18: String missing ending quote.", "optional_string: \"ueoauaoe\noptional_int32: 123"); 807 assertParseError("1:18: Invalid escape sequence: '\\z'", "optional_string: \"\\z\""); 808 assertParseError( 809 "1:18: String missing ending quote.", "optional_string: \"ueoauaoe\noptional_int32: 123"); 810 assertParseError( 811 "1:2: Input contains unknown fields and/or extensions:\n" 812 + "1:2:\tprotobuf_unittest.TestAllTypes.[nosuchext]", 813 "[nosuchext]: 123"); 814 assertParseError( 815 "1:20: Extension \"protobuf_unittest.optional_int32_extension\" does " 816 + "not extend message type \"protobuf_unittest.TestAllTypes\".", 817 "[protobuf_unittest.optional_int32_extension]: 123"); 818 assertParseError( 819 "1:1: Input contains unknown fields and/or extensions:\n" 820 + "1:1:\tprotobuf_unittest.TestAllTypes.nosuchfield", 821 "nosuchfield: 123"); 822 assertParseError("1:21: Expected \">\".", "OptionalGroup < a: 1"); 823 assertParseError( 824 "1:23: Enum type \"protobuf_unittest.TestAllTypes.NestedEnum\" has no " 825 + "value named \"NO_SUCH_VALUE\".", 826 "optional_nested_enum: NO_SUCH_VALUE"); 827 assertParseError( 828 "1:23: Enum type \"protobuf_unittest.TestAllTypes.NestedEnum\" has no " 829 + "value with number 123.", 830 "optional_nested_enum: 123"); 831 832 // Delimiters must match. 833 assertParseError("1:22: Expected identifier. Found '}'", "OptionalGroup < a: 1 }"); 834 assertParseError("1:22: Expected identifier. Found '>'", "OptionalGroup { a: 1 >"); 835 } 836 837 // ================================================================= 838 testEscape()839 public void testEscape() throws Exception { 840 // Escape sequences. 841 assertEquals( 842 "\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\"\\177", 843 TextFormat.escapeBytes(bytes("\0\001\007\b\f\n\r\t\013\\\'\"\177"))); 844 assertEquals( 845 "\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\"\\177", 846 TextFormat.escapeText("\0\001\007\b\f\n\r\t\013\\\'\"\177")); 847 assertEquals( 848 bytes("\0\001\007\b\f\n\r\t\013\\\'\""), 849 TextFormat.unescapeBytes("\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\"")); 850 assertEquals( 851 "\0\001\007\b\f\n\r\t\013\\\'\"", 852 TextFormat.unescapeText("\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\"")); 853 assertEquals(ESCAPE_TEST_STRING_ESCAPED, TextFormat.escapeText(ESCAPE_TEST_STRING)); 854 assertEquals(ESCAPE_TEST_STRING, TextFormat.unescapeText(ESCAPE_TEST_STRING_ESCAPED)); 855 856 // Invariant 857 assertEquals("hello", TextFormat.escapeBytes(bytes("hello"))); 858 assertEquals("hello", TextFormat.escapeText("hello")); 859 assertEquals(bytes("hello"), TextFormat.unescapeBytes("hello")); 860 assertEquals("hello", TextFormat.unescapeText("hello")); 861 862 // Unicode handling. 863 assertEquals("\\341\\210\\264", TextFormat.escapeText("\u1234")); 864 assertEquals("\\341\\210\\264", TextFormat.escapeBytes(bytes(0xe1, 0x88, 0xb4))); 865 assertEquals("\u1234", TextFormat.unescapeText("\\341\\210\\264")); 866 assertEquals(bytes(0xe1, 0x88, 0xb4), TextFormat.unescapeBytes("\\341\\210\\264")); 867 assertEquals("\u1234", TextFormat.unescapeText("\\xe1\\x88\\xb4")); 868 assertEquals(bytes(0xe1, 0x88, 0xb4), TextFormat.unescapeBytes("\\xe1\\x88\\xb4")); 869 870 // Handling of strings with unescaped Unicode characters > 255. 871 final String zh = "\u9999\u6e2f\u4e0a\u6d77\ud84f\udf80\u8c50\u9280\u884c"; 872 ByteString zhByteString = ByteString.copyFromUtf8(zh); 873 assertEquals(zhByteString, TextFormat.unescapeBytes(zh)); 874 875 // Errors. 876 try { 877 TextFormat.unescapeText("\\x"); 878 fail("Should have thrown an exception."); 879 } catch (TextFormat.InvalidEscapeSequenceException e) { 880 // success 881 } 882 883 try { 884 TextFormat.unescapeText("\\z"); 885 fail("Should have thrown an exception."); 886 } catch (TextFormat.InvalidEscapeSequenceException e) { 887 // success 888 } 889 890 try { 891 TextFormat.unescapeText("\\"); 892 fail("Should have thrown an exception."); 893 } catch (TextFormat.InvalidEscapeSequenceException e) { 894 // success 895 } 896 } 897 testParseInteger()898 public void testParseInteger() throws Exception { 899 assertEquals(0, TextFormat.parseInt32("0")); 900 assertEquals(1, TextFormat.parseInt32("1")); 901 assertEquals(-1, TextFormat.parseInt32("-1")); 902 assertEquals(12345, TextFormat.parseInt32("12345")); 903 assertEquals(-12345, TextFormat.parseInt32("-12345")); 904 assertEquals(2147483647, TextFormat.parseInt32("2147483647")); 905 assertEquals(-2147483648, TextFormat.parseInt32("-2147483648")); 906 907 assertEquals(0, TextFormat.parseUInt32("0")); 908 assertEquals(1, TextFormat.parseUInt32("1")); 909 assertEquals(12345, TextFormat.parseUInt32("12345")); 910 assertEquals(2147483647, TextFormat.parseUInt32("2147483647")); 911 assertEquals((int) 2147483648L, TextFormat.parseUInt32("2147483648")); 912 assertEquals((int) 4294967295L, TextFormat.parseUInt32("4294967295")); 913 914 assertEquals(0L, TextFormat.parseInt64("0")); 915 assertEquals(1L, TextFormat.parseInt64("1")); 916 assertEquals(-1L, TextFormat.parseInt64("-1")); 917 assertEquals(12345L, TextFormat.parseInt64("12345")); 918 assertEquals(-12345L, TextFormat.parseInt64("-12345")); 919 assertEquals(2147483647L, TextFormat.parseInt64("2147483647")); 920 assertEquals(-2147483648L, TextFormat.parseInt64("-2147483648")); 921 assertEquals(4294967295L, TextFormat.parseInt64("4294967295")); 922 assertEquals(4294967296L, TextFormat.parseInt64("4294967296")); 923 assertEquals(9223372036854775807L, TextFormat.parseInt64("9223372036854775807")); 924 assertEquals(-9223372036854775808L, TextFormat.parseInt64("-9223372036854775808")); 925 926 assertEquals(0L, TextFormat.parseUInt64("0")); 927 assertEquals(1L, TextFormat.parseUInt64("1")); 928 assertEquals(12345L, TextFormat.parseUInt64("12345")); 929 assertEquals(2147483647L, TextFormat.parseUInt64("2147483647")); 930 assertEquals(4294967295L, TextFormat.parseUInt64("4294967295")); 931 assertEquals(4294967296L, TextFormat.parseUInt64("4294967296")); 932 assertEquals(9223372036854775807L, TextFormat.parseUInt64("9223372036854775807")); 933 assertEquals(-9223372036854775808L, TextFormat.parseUInt64("9223372036854775808")); 934 assertEquals(-1L, TextFormat.parseUInt64("18446744073709551615")); 935 936 // Hex 937 assertEquals(0x1234abcd, TextFormat.parseInt32("0x1234abcd")); 938 assertEquals(-0x1234abcd, TextFormat.parseInt32("-0x1234abcd")); 939 assertEquals(-1, TextFormat.parseUInt64("0xffffffffffffffff")); 940 assertEquals(0x7fffffffffffffffL, TextFormat.parseInt64("0x7fffffffffffffff")); 941 942 // Octal 943 assertEquals(01234567, TextFormat.parseInt32("01234567")); 944 945 // Out-of-range 946 try { 947 TextFormat.parseInt32("2147483648"); 948 fail("Should have thrown an exception."); 949 } catch (NumberFormatException e) { 950 // success 951 } 952 953 try { 954 TextFormat.parseInt32("-2147483649"); 955 fail("Should have thrown an exception."); 956 } catch (NumberFormatException e) { 957 // success 958 } 959 960 try { 961 TextFormat.parseUInt32("4294967296"); 962 fail("Should have thrown an exception."); 963 } catch (NumberFormatException e) { 964 // success 965 } 966 967 try { 968 TextFormat.parseUInt32("-1"); 969 fail("Should have thrown an exception."); 970 } catch (NumberFormatException e) { 971 // success 972 } 973 974 try { 975 TextFormat.parseInt64("9223372036854775808"); 976 fail("Should have thrown an exception."); 977 } catch (NumberFormatException e) { 978 // success 979 } 980 981 try { 982 TextFormat.parseInt64("-9223372036854775809"); 983 fail("Should have thrown an exception."); 984 } catch (NumberFormatException e) { 985 // success 986 } 987 988 try { 989 TextFormat.parseUInt64("18446744073709551616"); 990 fail("Should have thrown an exception."); 991 } catch (NumberFormatException e) { 992 // success 993 } 994 995 try { 996 TextFormat.parseUInt64("-1"); 997 fail("Should have thrown an exception."); 998 } catch (NumberFormatException e) { 999 // success 1000 } 1001 1002 // Not a number. 1003 try { 1004 TextFormat.parseInt32("abcd"); 1005 fail("Should have thrown an exception."); 1006 } catch (NumberFormatException e) { 1007 // success 1008 } 1009 } 1010 testParseString()1011 public void testParseString() throws Exception { 1012 final String zh = "\u9999\u6e2f\u4e0a\u6d77\ud84f\udf80\u8c50\u9280\u884c"; 1013 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 1014 TextFormat.merge("optional_string: \"" + zh + "\"", builder); 1015 assertEquals(zh, builder.getOptionalString()); 1016 } 1017 testParseLongString()1018 public void testParseLongString() throws Exception { 1019 String longText = 1020 "123456789012345678901234567890123456789012345678901234567890" 1021 + "123456789012345678901234567890123456789012345678901234567890" 1022 + "123456789012345678901234567890123456789012345678901234567890" 1023 + "123456789012345678901234567890123456789012345678901234567890" 1024 + "123456789012345678901234567890123456789012345678901234567890" 1025 + "123456789012345678901234567890123456789012345678901234567890" 1026 + "123456789012345678901234567890123456789012345678901234567890" 1027 + "123456789012345678901234567890123456789012345678901234567890" 1028 + "123456789012345678901234567890123456789012345678901234567890" 1029 + "123456789012345678901234567890123456789012345678901234567890" 1030 + "123456789012345678901234567890123456789012345678901234567890" 1031 + "123456789012345678901234567890123456789012345678901234567890" 1032 + "123456789012345678901234567890123456789012345678901234567890" 1033 + "123456789012345678901234567890123456789012345678901234567890" 1034 + "123456789012345678901234567890123456789012345678901234567890" 1035 + "123456789012345678901234567890123456789012345678901234567890" 1036 + "123456789012345678901234567890123456789012345678901234567890" 1037 + "123456789012345678901234567890123456789012345678901234567890" 1038 + "123456789012345678901234567890123456789012345678901234567890" 1039 + "123456789012345678901234567890123456789012345678901234567890"; 1040 1041 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 1042 TextFormat.merge("optional_string: \"" + longText + "\"", builder); 1043 assertEquals(longText, builder.getOptionalString()); 1044 } 1045 testParseBoolean()1046 public void testParseBoolean() throws Exception { 1047 String goodText = 1048 "repeated_bool: t repeated_bool : 0\n" 1049 + "repeated_bool :f repeated_bool:1\n" 1050 + "repeated_bool: False repeated_bool: True"; 1051 String goodTextCanonical = 1052 "repeated_bool: true\n" 1053 + "repeated_bool: false\n" 1054 + "repeated_bool: false\n" 1055 + "repeated_bool: true\n" 1056 + "repeated_bool: false\n" 1057 + "repeated_bool: true\n"; 1058 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 1059 TextFormat.merge(goodText, builder); 1060 assertEquals(goodTextCanonical, builder.build().toString()); 1061 1062 try { 1063 TestAllTypes.Builder badBuilder = TestAllTypes.newBuilder(); 1064 TextFormat.merge("optional_bool:2", badBuilder); 1065 fail("Should have thrown an exception."); 1066 } catch (TextFormat.ParseException e) { 1067 // success 1068 } 1069 try { 1070 TestAllTypes.Builder badBuilder = TestAllTypes.newBuilder(); 1071 TextFormat.merge("optional_bool: foo", badBuilder); 1072 fail("Should have thrown an exception."); 1073 } catch (TextFormat.ParseException e) { 1074 // success 1075 } 1076 } 1077 testParseAdjacentStringLiterals()1078 public void testParseAdjacentStringLiterals() throws Exception { 1079 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 1080 TextFormat.merge("optional_string: \"foo\" 'corge' \"grault\"", builder); 1081 assertEquals("foocorgegrault", builder.getOptionalString()); 1082 } 1083 testPrintFieldValue()1084 public void testPrintFieldValue() throws Exception { 1085 assertPrintFieldValue("\"Hello\"", "Hello", "repeated_string"); 1086 assertPrintFieldValue("123.0", 123f, "repeated_float"); 1087 assertPrintFieldValue("123.0", 123d, "repeated_double"); 1088 assertPrintFieldValue("123", 123, "repeated_int32"); 1089 assertPrintFieldValue("123", 123L, "repeated_int64"); 1090 assertPrintFieldValue("true", true, "repeated_bool"); 1091 assertPrintFieldValue("4294967295", 0xFFFFFFFF, "repeated_uint32"); 1092 assertPrintFieldValue("18446744073709551615", 0xFFFFFFFFFFFFFFFFL, "repeated_uint64"); 1093 assertPrintFieldValue( 1094 "\"\\001\\002\\003\"", ByteString.copyFrom(new byte[] {1, 2, 3}), "repeated_bytes"); 1095 } 1096 assertPrintFieldValue(String expect, Object value, String fieldName)1097 private void assertPrintFieldValue(String expect, Object value, String fieldName) 1098 throws Exception { 1099 StringBuilder sb = new StringBuilder(); 1100 TextFormat.printer() 1101 .printFieldValue(TestAllTypes.getDescriptor().findFieldByName(fieldName), value, sb); 1102 assertEquals(expect, sb.toString()); 1103 } 1104 testShortDebugString()1105 public void testShortDebugString() { 1106 assertEquals( 1107 "optional_nested_message { bb: 42 } repeated_int32: 1 repeated_uint32: 2", 1108 TextFormat.shortDebugString( 1109 TestAllTypes.newBuilder() 1110 .addRepeatedInt32(1) 1111 .addRepeatedUint32(2) 1112 .setOptionalNestedMessage(NestedMessage.newBuilder().setBb(42).build()) 1113 .build())); 1114 } 1115 testShortDebugString_field()1116 public void testShortDebugString_field() { 1117 final FieldDescriptor dataField = OneString.getDescriptor().findFieldByName("data"); 1118 assertEquals( 1119 "data: \"test data\"", 1120 TextFormat.printer().shortDebugString(dataField, "test data")); 1121 1122 final FieldDescriptor optionalField = 1123 TestAllTypes.getDescriptor().findFieldByName("optional_nested_message"); 1124 final Object value = NestedMessage.newBuilder().setBb(42).build(); 1125 1126 assertEquals( 1127 "optional_nested_message { bb: 42 }", 1128 TextFormat.printer().shortDebugString(optionalField, value)); 1129 } 1130 testShortDebugString_unknown()1131 public void testShortDebugString_unknown() { 1132 assertEquals( 1133 "5: 1 5: 0x00000002 5: 0x0000000000000003 5: \"4\" 5: { 12: 6 } 5 { 10: 5 }" 1134 + " 8: 1 8: 2 8: 3 15: 12379813812177893520 15: 0xabcd1234 15:" 1135 + " 0xabcdef1234567890", 1136 TextFormat.printer().shortDebugString(makeUnknownFieldSet())); 1137 } 1138 testPrintToUnicodeString()1139 public void testPrintToUnicodeString() throws Exception { 1140 assertEquals( 1141 "optional_string: \"abc\u3042efg\"\n" 1142 + "optional_bytes: \"\\343\\201\\202\"\n" 1143 + "repeated_string: \"\u3093XYZ\"\n", 1144 TextFormat.printer() 1145 .escapingNonAscii(false) 1146 .printToString( 1147 TestAllTypes.newBuilder() 1148 .setOptionalString("abc\u3042efg") 1149 .setOptionalBytes(bytes(0xe3, 0x81, 0x82)) 1150 .addRepeatedString("\u3093XYZ") 1151 .build())); 1152 1153 // Double quotes and backslashes should be escaped 1154 assertEquals( 1155 "optional_string: \"a\\\\bc\\\"ef\\\"g\"\n", 1156 TextFormat.printer() 1157 .escapingNonAscii(false) 1158 .printToString(TestAllTypes.newBuilder().setOptionalString("a\\bc\"ef\"g").build())); 1159 1160 // Test escaping roundtrip 1161 TestAllTypes message = TestAllTypes.newBuilder().setOptionalString("a\\bc\\\"ef\"g").build(); 1162 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 1163 TextFormat.merge(TextFormat.printer().escapingNonAscii(false).printToString(message), builder); 1164 assertEquals(message.getOptionalString(), builder.getOptionalString()); 1165 } 1166 testPrintToUnicodeStringWithNewlines()1167 public void testPrintToUnicodeStringWithNewlines() throws Exception { 1168 // No newlines at start and end 1169 assertEquals( 1170 "optional_string: \"test newlines\\n\\nin\\nstring\"\n", 1171 TextFormat.printer() 1172 .escapingNonAscii(false) 1173 .printToString( 1174 TestAllTypes.newBuilder() 1175 .setOptionalString("test newlines\n\nin\nstring") 1176 .build())); 1177 1178 // Newlines at start and end 1179 assertEquals( 1180 "optional_string: \"\\ntest\\nnewlines\\n\\nin\\nstring\\n\"\n", 1181 TextFormat.printer() 1182 .escapingNonAscii(false) 1183 .printToString( 1184 TestAllTypes.newBuilder() 1185 .setOptionalString("\ntest\nnewlines\n\nin\nstring\n") 1186 .build())); 1187 1188 // Strings with 0, 1 and 2 newlines. 1189 assertEquals( 1190 "optional_string: \"\"\n", 1191 TextFormat.printer() 1192 .escapingNonAscii(false) 1193 .printToString(TestAllTypes.newBuilder().setOptionalString("").build())); 1194 assertEquals( 1195 "optional_string: \"\\n\"\n", 1196 TextFormat.printer() 1197 .escapingNonAscii(false) 1198 .printToString(TestAllTypes.newBuilder().setOptionalString("\n").build())); 1199 assertEquals( 1200 "optional_string: \"\\n\\n\"\n", 1201 TextFormat.printer() 1202 .escapingNonAscii(false) 1203 .printToString(TestAllTypes.newBuilder().setOptionalString("\n\n").build())); 1204 1205 // Test escaping roundtrip 1206 TestAllTypes message = 1207 TestAllTypes.newBuilder().setOptionalString("\ntest\nnewlines\n\nin\nstring\n").build(); 1208 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 1209 TextFormat.merge(TextFormat.printer().escapingNonAscii(false).printToString(message), builder); 1210 assertEquals(message.getOptionalString(), builder.getOptionalString()); 1211 } 1212 testPrintToUnicodeString_unknown()1213 public void testPrintToUnicodeString_unknown() { 1214 assertEquals( 1215 "1: \"\\343\\201\\202\"\n", 1216 TextFormat.printer() 1217 .escapingNonAscii(false) 1218 .printToString( 1219 UnknownFieldSet.newBuilder() 1220 .addField( 1221 1, 1222 UnknownFieldSet.Field.newBuilder() 1223 .addLengthDelimited(bytes(0xe3, 0x81, 0x82)) 1224 .build()) 1225 .build())); 1226 } 1227 1228 testParseUnknownExtensions()1229 public void testParseUnknownExtensions() throws Exception { 1230 TestUtil.TestLogHandler logHandler = new TestUtil.TestLogHandler(); 1231 Logger logger = Logger.getLogger(TextFormat.class.getName()); 1232 logger.addHandler(logHandler); 1233 // Test unknown extension can pass. 1234 assertParseSuccessWithUnknownExtensions("[unknown_extension]: 123"); 1235 assertParseSuccessWithUnknownExtensions( 1236 "[unknown_extension]: 123\n" + "[unknown_ext]: inf\n" + "[unknown]: 1.234"); 1237 // Test warning messages. 1238 assertEquals( 1239 "Input contains unknown fields and/or extensions:\n" 1240 + "1:2:\tprotobuf_unittest.TestAllTypes.[unknown_extension]", 1241 logHandler.getStoredLogRecords().get(0).getMessage()); 1242 assertEquals( 1243 "Input contains unknown fields and/or extensions:\n" 1244 + "1:2:\tprotobuf_unittest.TestAllTypes.[unknown_extension]\n" 1245 + "2:2:\tprotobuf_unittest.TestAllTypes.[unknown_ext]\n" 1246 + "3:2:\tprotobuf_unittest.TestAllTypes.[unknown]", 1247 logHandler.getStoredLogRecords().get(1).getMessage()); 1248 1249 // Test unknown field can not pass. 1250 assertParseErrorWithUnknownExtensions( 1251 "2:1: Input contains unknown fields and/or extensions:\n" 1252 + "1:2:\tprotobuf_unittest.TestAllTypes.[unknown_extension]\n" 1253 + "2:1:\tprotobuf_unittest.TestAllTypes.unknown_field", 1254 "[unknown_extension]: 1\n" + "unknown_field: 12345"); 1255 assertParseErrorWithUnknownExtensions( 1256 "3:1: Input contains unknown fields and/or extensions:\n" 1257 + "1:2:\tprotobuf_unittest.TestAllTypes.[unknown_extension1]\n" 1258 + "2:2:\tprotobuf_unittest.TestAllTypes.[unknown_extension2]\n" 1259 + "3:1:\tprotobuf_unittest.TestAllTypes.unknown_field\n" 1260 + "4:2:\tprotobuf_unittest.TestAllTypes.[unknown_extension3]", 1261 "[unknown_extension1]: 1\n" 1262 + "[unknown_extension2]: 2\n" 1263 + "unknown_field: 12345\n" 1264 + "[unknown_extension3]: 3\n"); 1265 assertParseErrorWithUnknownExtensions( 1266 "1:1: Input contains unknown fields and/or extensions:\n" 1267 + "1:1:\tprotobuf_unittest.TestAllTypes.unknown_field1\n" 1268 + "2:1:\tprotobuf_unittest.TestAllTypes.unknown_field2\n" 1269 + "3:2:\tprotobuf_unittest.TestAllTypes.[unknown_extension]\n" 1270 + "4:1:\tprotobuf_unittest.TestAllTypes.unknown_field3", 1271 "unknown_field1: 1\n" 1272 + "unknown_field2: 2\n" 1273 + "[unknown_extension]: 12345\n" 1274 + "unknown_field3: 3\n"); 1275 } 1276 1277 // See additional coverage in testOneofOverwriteForbidden and testMapOverwriteForbidden. testParseNonRepeatedFields()1278 public void testParseNonRepeatedFields() throws Exception { 1279 assertParseSuccessWithOverwriteForbidden("repeated_int32: 1\nrepeated_int32: 2\n"); 1280 assertParseSuccessWithOverwriteForbidden("RepeatedGroup { a: 1 }\nRepeatedGroup { a: 2 }\n"); 1281 assertParseSuccessWithOverwriteForbidden( 1282 "repeated_nested_message { bb: 1 }\nrepeated_nested_message { bb: 2 }\n"); 1283 1284 assertParseErrorWithOverwriteForbidden( 1285 "3:15: Non-repeated field " 1286 + "\"protobuf_unittest.TestAllTypes.optional_int32\" " 1287 + "cannot be overwritten.", 1288 "optional_int32: 1\noptional_bool: true\noptional_int32: 1\n"); 1289 assertParseErrorWithOverwriteForbidden( 1290 "2:1: Non-repeated field " 1291 + "\"protobuf_unittest.TestAllTypes.optionalgroup\" " 1292 + "cannot be overwritten.", 1293 "OptionalGroup { a: 1 }\nOptionalGroup { }\n"); 1294 assertParseErrorWithOverwriteForbidden( 1295 "2:1: Non-repeated field " 1296 + "\"protobuf_unittest.TestAllTypes.optional_nested_message\" " 1297 + "cannot be overwritten.", 1298 "optional_nested_message { }\noptional_nested_message { bb: 3 }\n"); 1299 assertParseErrorWithOverwriteForbidden( 1300 "2:14: Non-repeated field " 1301 + "\"protobuf_unittest.TestAllTypes.default_int32\" " 1302 + "cannot be overwritten.", 1303 "default_int32: 41\n" 1304 + // the default value 1305 "default_int32: 41\n"); 1306 assertParseErrorWithOverwriteForbidden( 1307 "2:15: Non-repeated field " 1308 + "\"protobuf_unittest.TestAllTypes.default_string\" " 1309 + "cannot be overwritten.", 1310 "default_string: \"zxcv\"\ndefault_string: \"asdf\"\n"); 1311 } 1312 testParseShortRepeatedFormOfRepeatedFields()1313 public void testParseShortRepeatedFormOfRepeatedFields() throws Exception { 1314 assertParseSuccessWithOverwriteForbidden("repeated_foreign_enum: [FOREIGN_FOO, FOREIGN_BAR]"); 1315 assertParseSuccessWithOverwriteForbidden("repeated_int32: [ 1, 2 ]\n"); 1316 assertParseSuccessWithOverwriteForbidden("RepeatedGroup [{ a: 1 },{ a: 2 }]\n"); 1317 assertParseSuccessWithOverwriteForbidden("repeated_nested_message [{ bb: 1 }, { bb: 2 }]\n"); 1318 // See also testMapShortForm. 1319 } 1320 testParseShortRepeatedFormOfEmptyRepeatedFields()1321 public void testParseShortRepeatedFormOfEmptyRepeatedFields() throws Exception { 1322 assertParseSuccessWithOverwriteForbidden("repeated_foreign_enum: []"); 1323 assertParseSuccessWithOverwriteForbidden("repeated_int32: []\n"); 1324 assertParseSuccessWithOverwriteForbidden("RepeatedGroup []\n"); 1325 assertParseSuccessWithOverwriteForbidden("repeated_nested_message []\n"); 1326 // See also testMapShortFormEmpty. 1327 } 1328 testParseShortRepeatedFormWithTrailingComma()1329 public void testParseShortRepeatedFormWithTrailingComma() throws Exception { 1330 assertParseErrorWithOverwriteForbidden( 1331 "1:38: Expected identifier. Found \']\'", "repeated_foreign_enum: [FOREIGN_FOO, ]\n"); 1332 assertParseErrorWithOverwriteForbidden( 1333 "1:22: Couldn't parse integer: For input string: \"]\"", "repeated_int32: [ 1, ]\n"); 1334 assertParseErrorWithOverwriteForbidden("1:25: Expected \"{\".", "RepeatedGroup [{ a: 1 },]\n"); 1335 assertParseErrorWithOverwriteForbidden( 1336 "1:37: Expected \"{\".", "repeated_nested_message [{ bb: 1 }, ]\n"); 1337 // See also testMapShortFormTrailingComma. 1338 } 1339 testParseShortRepeatedFormOfNonRepeatedFields()1340 public void testParseShortRepeatedFormOfNonRepeatedFields() throws Exception { 1341 assertParseErrorWithOverwriteForbidden( 1342 "1:17: Couldn't parse integer: For input string: \"[\"", "optional_int32: [1]\n"); 1343 assertParseErrorWithOverwriteForbidden( 1344 "1:17: Couldn't parse integer: For input string: \"[\"", "optional_int32: []\n"); 1345 } 1346 1347 // ======================================================================= 1348 // test oneof 1349 testOneofTextFormat()1350 public void testOneofTextFormat() throws Exception { 1351 TestOneof2.Builder builder = TestOneof2.newBuilder(); 1352 TestUtil.setOneof(builder); 1353 TestOneof2 message = builder.build(); 1354 TestOneof2.Builder dest = TestOneof2.newBuilder(); 1355 TextFormat.merge(TextFormat.printer().escapingNonAscii(false).printToString(message), dest); 1356 TestUtil.assertOneofSet(dest.build()); 1357 } 1358 testOneofOverwriteForbidden()1359 public void testOneofOverwriteForbidden() throws Exception { 1360 String input = "foo_string: \"stringvalue\" foo_int: 123"; 1361 TestOneof2.Builder builder = TestOneof2.newBuilder(); 1362 try { 1363 parserWithOverwriteForbidden.merge(input, TestUtil.getFullExtensionRegistry(), builder); 1364 fail("Expected parse exception."); 1365 } catch (TextFormat.ParseException e) { 1366 assertEquals( 1367 "1:34: Field \"protobuf_unittest.TestOneof2.foo_int\"" 1368 + " is specified along with field \"protobuf_unittest.TestOneof2.foo_string\"," 1369 + " another member of oneof \"foo\".", 1370 e.getMessage()); 1371 } 1372 } 1373 testOneofOverwriteAllowed()1374 public void testOneofOverwriteAllowed() throws Exception { 1375 String input = "foo_string: \"stringvalue\" foo_int: 123"; 1376 TestOneof2.Builder builder = TestOneof2.newBuilder(); 1377 defaultParser.merge(input, TestUtil.getFullExtensionRegistry(), builder); 1378 // Only the last value sticks. 1379 TestOneof2 oneof = builder.build(); 1380 assertFalse(oneof.hasFooString()); 1381 assertTrue(oneof.hasFooInt()); 1382 } 1383 1384 // ======================================================================= 1385 // test map 1386 testMapTextFormat()1387 public void testMapTextFormat() throws Exception { 1388 TestMap message = 1389 TestMap.newBuilder() 1390 .putInt32ToStringField(10, "apple") 1391 .putInt32ToStringField(20, "banana") 1392 .putInt32ToStringField(30, "cherry") 1393 .build(); 1394 String text = TextFormat.printer().escapingNonAscii(false).printToString(message); 1395 { 1396 TestMap.Builder dest = TestMap.newBuilder(); 1397 TextFormat.merge(text, dest); 1398 assertEquals(message, dest.build()); 1399 } 1400 { 1401 TestMap.Builder dest = TestMap.newBuilder(); 1402 parserWithOverwriteForbidden.merge(text, dest); 1403 assertEquals(message, dest.build()); 1404 } 1405 } 1406 testMapDuplicateKeys()1407 public void testMapDuplicateKeys() throws Exception { 1408 String input = 1409 "int32_to_int32_field: {\n" 1410 + " key: 1\n" 1411 + " value: 1\n" 1412 + "}\n" 1413 + "int32_to_int32_field: {\n" 1414 + " key: -2147483647\n" 1415 + " value: 5\n" 1416 + "}\n" 1417 + "int32_to_int32_field: {\n" 1418 + " key: 1\n" 1419 + " value: -1\n" 1420 + "}\n"; 1421 TestMap msg = TextFormat.parse(input, TestMap.class); 1422 int i1 = msg.getInt32ToInt32Field().get(1); 1423 TestMap msg2 = TextFormat.parse(msg.toString(), TestMap.class); 1424 int i2 = msg2.getInt32ToInt32Field().get(1); 1425 assertEquals(i1, i2); 1426 } 1427 testMapShortForm()1428 public void testMapShortForm() throws Exception { 1429 String text = 1430 "string_to_int32_field [{ key: 'x' value: 10 }, { key: 'y' value: 20 }]\n" 1431 + "int32_to_message_field " 1432 + "[{ key: 1 value { value: 100 } }, { key: 2 value: { value: 200 } }]\n"; 1433 TestMap.Builder dest = TestMap.newBuilder(); 1434 parserWithOverwriteForbidden.merge(text, dest); 1435 TestMap message = dest.build(); 1436 assertEquals(2, message.getStringToInt32Field().size()); 1437 assertEquals(2, message.getInt32ToMessageField().size()); 1438 assertEquals(10, message.getStringToInt32Field().get("x").intValue()); 1439 assertEquals(200, message.getInt32ToMessageField().get(2).getValue()); 1440 } 1441 testMapShortFormEmpty()1442 public void testMapShortFormEmpty() throws Exception { 1443 String text = "string_to_int32_field []\nint32_to_message_field: []\n"; 1444 TestMap.Builder dest = TestMap.newBuilder(); 1445 parserWithOverwriteForbidden.merge(text, dest); 1446 TestMap message = dest.build(); 1447 assertEquals(0, message.getStringToInt32Field().size()); 1448 assertEquals(0, message.getInt32ToMessageField().size()); 1449 } 1450 testMapShortFormTrailingComma()1451 public void testMapShortFormTrailingComma() throws Exception { 1452 String text = "string_to_int32_field [{ key: 'x' value: 10 }, ]\n"; 1453 TestMap.Builder dest = TestMap.newBuilder(); 1454 try { 1455 parserWithOverwriteForbidden.merge(text, dest); 1456 fail("Expected parse exception."); 1457 } catch (TextFormat.ParseException e) { 1458 assertEquals("1:48: Expected \"{\".", e.getMessage()); 1459 } 1460 } 1461 testMapOverwrite()1462 public void testMapOverwrite() throws Exception { 1463 String text = 1464 "int32_to_int32_field { key: 1 value: 10 }\n" 1465 + "int32_to_int32_field { key: 2 value: 20 }\n" 1466 + "int32_to_int32_field { key: 1 value: 30 }\n"; 1467 1468 { 1469 // With default parser, last value set for the key holds. 1470 TestMap.Builder builder = TestMap.newBuilder(); 1471 defaultParser.merge(text, builder); 1472 TestMap map = builder.build(); 1473 assertEquals(2, map.getInt32ToInt32Field().size()); 1474 assertEquals(30, map.getInt32ToInt32Field().get(1).intValue()); 1475 } 1476 1477 { 1478 // With overwrite forbidden, same behavior. 1479 // TODO(b/29122459): Expect parse exception here. 1480 TestMap.Builder builder = TestMap.newBuilder(); 1481 defaultParser.merge(text, builder); 1482 TestMap map = builder.build(); 1483 assertEquals(2, map.getInt32ToInt32Field().size()); 1484 assertEquals(30, map.getInt32ToInt32Field().get(1).intValue()); 1485 } 1486 } 1487 1488 // ======================================================================= 1489 // test location information 1490 testParseInfoTreeBuilding()1491 public void testParseInfoTreeBuilding() throws Exception { 1492 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 1493 1494 Descriptor descriptor = TestAllTypes.getDescriptor(); 1495 TextFormatParseInfoTree.Builder treeBuilder = TextFormatParseInfoTree.builder(); 1496 // Set to allow unknown fields 1497 TextFormat.Parser parser = 1498 TextFormat.Parser.newBuilder() 1499 .setAllowUnknownFields(true) 1500 .setParseInfoTreeBuilder(treeBuilder) 1501 .build(); 1502 1503 final String stringData = 1504 "optional_int32: 1\n" 1505 + "optional_int64: 2\n" 1506 + " optional_double: 2.4\n" 1507 + "repeated_int32: 5\n" 1508 + "repeated_int32: 10\n" 1509 + "optional_nested_message <\n" 1510 + " bb: 78\n" 1511 + ">\n" 1512 + "repeated_nested_message <\n" 1513 + " bb: 79\n" 1514 + ">\n" 1515 + "repeated_nested_message <\n" 1516 + " bb: 80\n" 1517 + ">"; 1518 1519 parser.merge(stringData, builder); 1520 TextFormatParseInfoTree tree = treeBuilder.build(); 1521 1522 // Verify that the tree has the correct positions. 1523 assertLocation(tree, descriptor, "optional_int32", 0, 0, 0); 1524 assertLocation(tree, descriptor, "optional_int64", 0, 1, 0); 1525 assertLocation(tree, descriptor, "optional_double", 0, 2, 2); 1526 1527 assertLocation(tree, descriptor, "repeated_int32", 0, 3, 0); 1528 assertLocation(tree, descriptor, "repeated_int32", 1, 4, 0); 1529 1530 assertLocation(tree, descriptor, "optional_nested_message", 0, 5, 0); 1531 assertLocation(tree, descriptor, "repeated_nested_message", 0, 8, 0); 1532 assertLocation(tree, descriptor, "repeated_nested_message", 1, 11, 0); 1533 1534 // Check for fields not set. For an invalid field, the location returned should be -1, -1. 1535 assertLocation(tree, descriptor, "repeated_int64", 0, -1, -1); 1536 assertLocation(tree, descriptor, "repeated_int32", 6, -1, -1); 1537 1538 // Verify inside the nested message. 1539 FieldDescriptor nestedField = descriptor.findFieldByName("optional_nested_message"); 1540 1541 TextFormatParseInfoTree nestedTree = tree.getNestedTrees(nestedField).get(0); 1542 assertLocation(nestedTree, nestedField.getMessageType(), "bb", 0, 6, 2); 1543 1544 // Verify inside another nested message. 1545 nestedField = descriptor.findFieldByName("repeated_nested_message"); 1546 nestedTree = tree.getNestedTrees(nestedField).get(0); 1547 assertLocation(nestedTree, nestedField.getMessageType(), "bb", 0, 9, 2); 1548 1549 nestedTree = tree.getNestedTrees(nestedField).get(1); 1550 assertLocation(nestedTree, nestedField.getMessageType(), "bb", 0, 12, 2); 1551 1552 // Verify a NULL tree for an unknown nested field. 1553 try { 1554 tree.getNestedTree(nestedField, 2); 1555 fail("unknown nested field should throw"); 1556 } catch (IllegalArgumentException unused) { 1557 // pass 1558 } 1559 } 1560 assertLocation( TextFormatParseInfoTree tree, final Descriptor descriptor, final String fieldName, int index, int line, int column)1561 private void assertLocation( 1562 TextFormatParseInfoTree tree, 1563 final Descriptor descriptor, 1564 final String fieldName, 1565 int index, 1566 int line, 1567 int column) { 1568 List<TextFormatParseLocation> locs = tree.getLocations(descriptor.findFieldByName(fieldName)); 1569 if (index < locs.size()) { 1570 TextFormatParseLocation location = locs.get(index); 1571 TextFormatParseLocation expected = TextFormatParseLocation.create(line, column); 1572 assertEquals(expected, location); 1573 } else if (line != -1 && column != -1) { 1574 fail( 1575 String.format( 1576 "Tree/descriptor/fieldname did not contain index %d, line %d column %d expected", 1577 index, line, column)); 1578 } 1579 } 1580 testSortMapFields()1581 public void testSortMapFields() throws Exception { 1582 TestMap message = 1583 TestMap.newBuilder() 1584 .putStringToInt32Field("cherry", 30) 1585 .putStringToInt32Field("banana", 20) 1586 .putStringToInt32Field("apple", 10) 1587 .putInt32ToStringField(30, "cherry") 1588 .putInt32ToStringField(20, "banana") 1589 .putInt32ToStringField(10, "apple") 1590 .build(); 1591 String text = 1592 "int32_to_string_field {\n" 1593 + " key: 10\n" 1594 + " value: \"apple\"\n" 1595 + "}\n" 1596 + "int32_to_string_field {\n" 1597 + " key: 20\n" 1598 + " value: \"banana\"\n" 1599 + "}\n" 1600 + "int32_to_string_field {\n" 1601 + " key: 30\n" 1602 + " value: \"cherry\"\n" 1603 + "}\n" 1604 + "string_to_int32_field {\n" 1605 + " key: \"apple\"\n" 1606 + " value: 10\n" 1607 + "}\n" 1608 + "string_to_int32_field {\n" 1609 + " key: \"banana\"\n" 1610 + " value: 20\n" 1611 + "}\n" 1612 + "string_to_int32_field {\n" 1613 + " key: \"cherry\"\n" 1614 + " value: 30\n" 1615 + "}\n"; 1616 assertEquals(text, TextFormat.printer().printToString(message)); 1617 } 1618 } 1619