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