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 31package com.google.protobuf; 32 33import com.google.protobuf.Descriptors.FieldDescriptor; 34import com.google.protobuf.TextFormat.Parser.SingularOverwritePolicy; 35import protobuf_unittest.UnittestMset.TestMessageSet; 36import protobuf_unittest.UnittestMset.TestMessageSetExtension1; 37import protobuf_unittest.UnittestMset.TestMessageSetExtension2; 38import protobuf_unittest.UnittestProto.OneString; 39import protobuf_unittest.UnittestProto.TestAllExtensions; 40import protobuf_unittest.UnittestProto.TestAllTypes; 41import protobuf_unittest.UnittestProto.TestAllTypes.NestedMessage; 42import protobuf_unittest.UnittestProto.TestEmptyMessage; 43import protobuf_unittest.UnittestProto.TestOneof2; 44 45import junit.framework.TestCase; 46 47import java.io.StringReader; 48 49/** 50 * Test case for {@link TextFormat}. 51 * 52 * TODO(wenboz): ExtensionTest and rest of text_format_unittest.cc. 53 * 54 * @author wenboz@google.com (Wenbo Zhu) 55 */ 56public class TextFormatTest extends TestCase { 57 58 // A basic string with different escapable characters for testing. 59 private final static String kEscapeTestString = 60 "\"A string with ' characters \n and \r newlines and \t tabs and \001 " 61 + "slashes \\"; 62 63 // A representation of the above string with all the characters escaped. 64 private final static String kEscapeTestStringEscaped = 65 "\\\"A string with \\' characters \\n and \\r newlines " 66 + "and \\t tabs and \\001 slashes \\\\"; 67 68 private static String allFieldsSetText = TestUtil.readTextFromFile( 69 "text_format_unittest_data_oneof_implemented.txt"); 70 private static String allExtensionsSetText = TestUtil.readTextFromFile( 71 "text_format_unittest_extensions_data.txt"); 72 73 private static String exoticText = 74 "repeated_int32: -1\n" + 75 "repeated_int32: -2147483648\n" + 76 "repeated_int64: -1\n" + 77 "repeated_int64: -9223372036854775808\n" + 78 "repeated_uint32: 4294967295\n" + 79 "repeated_uint32: 2147483648\n" + 80 "repeated_uint64: 18446744073709551615\n" + 81 "repeated_uint64: 9223372036854775808\n" + 82 "repeated_double: 123.0\n" + 83 "repeated_double: 123.5\n" + 84 "repeated_double: 0.125\n" + 85 "repeated_double: .125\n" + 86 "repeated_double: -.125\n" + 87 "repeated_double: 1.23E17\n" + 88 "repeated_double: 1.23E+17\n" + 89 "repeated_double: -1.23e-17\n" + 90 "repeated_double: .23e+17\n" + 91 "repeated_double: -.23E17\n" + 92 "repeated_double: 1.235E22\n" + 93 "repeated_double: 1.235E-18\n" + 94 "repeated_double: 123.456789\n" + 95 "repeated_double: Infinity\n" + 96 "repeated_double: -Infinity\n" + 97 "repeated_double: NaN\n" + 98 "repeated_string: \"\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\"" + 99 "\\341\\210\\264\"\n" + 100 "repeated_bytes: \"\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\"\\376\"\n"; 101 102 private static String canonicalExoticText = 103 exoticText.replace(": .", ": 0.").replace(": -.", ": -0.") // short-form double 104 .replace("23e", "23E").replace("E+", "E").replace("0.23E17", "2.3E16"); 105 106 private String messageSetText = 107 "[protobuf_unittest.TestMessageSetExtension1] {\n" + 108 " i: 123\n" + 109 "}\n" + 110 "[protobuf_unittest.TestMessageSetExtension2] {\n" + 111 " str: \"foo\"\n" + 112 "}\n"; 113 114 private String messageSetTextWithRepeatedExtension = 115 "[protobuf_unittest.TestMessageSetExtension1] {\n" + 116 " i: 123\n" + 117 "}\n" + 118 "[protobuf_unittest.TestMessageSetExtension1] {\n" + 119 " i: 456\n" + 120 "}\n"; 121 122 private final TextFormat.Parser parserWithOverwriteForbidden = 123 TextFormat.Parser.newBuilder() 124 .setSingularOverwritePolicy( 125 SingularOverwritePolicy.FORBID_SINGULAR_OVERWRITES) 126 .build(); 127 128 private final TextFormat.Parser defaultParser = 129 TextFormat.Parser.newBuilder().build(); 130 131 /** Print TestAllTypes and compare with golden file. */ 132 public void testPrintMessage() throws Exception { 133 String javaText = TextFormat.printToString(TestUtil.getAllSet()); 134 135 // Java likes to add a trailing ".0" to floats and doubles. C printf 136 // (with %g format) does not. Our golden files are used for both 137 // C++ and Java TextFormat classes, so we need to conform. 138 javaText = javaText.replace(".0\n", "\n"); 139 140 assertEquals(allFieldsSetText, javaText); 141 } 142 143 /** Print TestAllTypes as Builder and compare with golden file. */ 144 public void testPrintMessageBuilder() throws Exception { 145 String javaText = TextFormat.printToString(TestUtil.getAllSetBuilder()); 146 147 // Java likes to add a trailing ".0" to floats and doubles. C printf 148 // (with %g format) does not. Our golden files are used for both 149 // C++ and Java TextFormat classes, so we need to conform. 150 javaText = javaText.replace(".0\n", "\n"); 151 152 assertEquals(allFieldsSetText, javaText); 153 } 154 155 /** Print TestAllExtensions and compare with golden file. */ 156 public void testPrintExtensions() throws Exception { 157 String javaText = TextFormat.printToString(TestUtil.getAllExtensionsSet()); 158 159 // Java likes to add a trailing ".0" to floats and doubles. C printf 160 // (with %g format) does not. Our golden files are used for both 161 // C++ and Java TextFormat classes, so we need to conform. 162 javaText = javaText.replace(".0\n", "\n"); 163 164 assertEquals(allExtensionsSetText, javaText); 165 } 166 167 // Creates an example unknown field set. 168 private UnknownFieldSet makeUnknownFieldSet() { 169 return UnknownFieldSet.newBuilder() 170 .addField(5, 171 UnknownFieldSet.Field.newBuilder() 172 .addVarint(1) 173 .addFixed32(2) 174 .addFixed64(3) 175 .addLengthDelimited(ByteString.copyFromUtf8("4")) 176 .addGroup( 177 UnknownFieldSet.newBuilder() 178 .addField(10, 179 UnknownFieldSet.Field.newBuilder() 180 .addVarint(5) 181 .build()) 182 .build()) 183 .build()) 184 .addField(8, 185 UnknownFieldSet.Field.newBuilder() 186 .addVarint(1) 187 .addVarint(2) 188 .addVarint(3) 189 .build()) 190 .addField(15, 191 UnknownFieldSet.Field.newBuilder() 192 .addVarint(0xABCDEF1234567890L) 193 .addFixed32(0xABCD1234) 194 .addFixed64(0xABCDEF1234567890L) 195 .build()) 196 .build(); 197 } 198 199 public void testPrintUnknownFields() throws Exception { 200 // Test printing of unknown fields in a message. 201 202 TestEmptyMessage message = 203 TestEmptyMessage.newBuilder() 204 .setUnknownFields(makeUnknownFieldSet()) 205 .build(); 206 207 assertEquals( 208 "5: 1\n" + 209 "5: 0x00000002\n" + 210 "5: 0x0000000000000003\n" + 211 "5: \"4\"\n" + 212 "5 {\n" + 213 " 10: 5\n" + 214 "}\n" + 215 "8: 1\n" + 216 "8: 2\n" + 217 "8: 3\n" + 218 "15: 12379813812177893520\n" + 219 "15: 0xabcd1234\n" + 220 "15: 0xabcdef1234567890\n", 221 TextFormat.printToString(message)); 222 } 223 224 public void testPrintField() throws Exception { 225 final FieldDescriptor dataField = 226 OneString.getDescriptor().findFieldByName("data"); 227 assertEquals( 228 "data: \"test data\"\n", 229 TextFormat.printFieldToString(dataField, "test data")); 230 231 final FieldDescriptor optionalField = 232 TestAllTypes.getDescriptor().findFieldByName("optional_nested_message"); 233 final Object value = NestedMessage.newBuilder().setBb(42).build(); 234 235 assertEquals( 236 "optional_nested_message {\n bb: 42\n}\n", 237 TextFormat.printFieldToString(optionalField, value)); 238 } 239 240 /** 241 * Helper to construct a ByteString from a String containing only 8-bit 242 * characters. The characters are converted directly to bytes, *not* 243 * encoded using UTF-8. 244 */ 245 private ByteString bytes(String str) throws Exception { 246 return ByteString.copyFrom(str.getBytes("ISO-8859-1")); 247 } 248 249 /** 250 * Helper to construct a ByteString from a bunch of bytes. The inputs are 251 * actually ints so that I can use hex notation and not get stupid errors 252 * about precision. 253 */ 254 private ByteString bytes(int... bytesAsInts) { 255 byte[] bytes = new byte[bytesAsInts.length]; 256 for (int i = 0; i < bytesAsInts.length; i++) { 257 bytes[i] = (byte) bytesAsInts[i]; 258 } 259 return ByteString.copyFrom(bytes); 260 } 261 262 public void testPrintExotic() throws Exception { 263 Message message = TestAllTypes.newBuilder() 264 // Signed vs. unsigned numbers. 265 .addRepeatedInt32 (-1) 266 .addRepeatedUint32(-1) 267 .addRepeatedInt64 (-1) 268 .addRepeatedUint64(-1) 269 270 .addRepeatedInt32 (1 << 31) 271 .addRepeatedUint32(1 << 31) 272 .addRepeatedInt64 (1L << 63) 273 .addRepeatedUint64(1L << 63) 274 275 // Floats of various precisions and exponents. 276 .addRepeatedDouble(123) 277 .addRepeatedDouble(123.5) 278 .addRepeatedDouble(0.125) 279 .addRepeatedDouble(.125) 280 .addRepeatedDouble(-.125) 281 .addRepeatedDouble(123e15) 282 .addRepeatedDouble(123e15) 283 .addRepeatedDouble(-1.23e-17) 284 .addRepeatedDouble(.23e17) 285 .addRepeatedDouble(-23e15) 286 .addRepeatedDouble(123.5e20) 287 .addRepeatedDouble(123.5e-20) 288 .addRepeatedDouble(123.456789) 289 .addRepeatedDouble(Double.POSITIVE_INFINITY) 290 .addRepeatedDouble(Double.NEGATIVE_INFINITY) 291 .addRepeatedDouble(Double.NaN) 292 293 // Strings and bytes that needing escaping. 294 .addRepeatedString("\0\001\007\b\f\n\r\t\013\\\'\"\u1234") 295 .addRepeatedBytes(bytes("\0\001\007\b\f\n\r\t\013\\\'\"\u00fe")) 296 .build(); 297 298 assertEquals(canonicalExoticText, message.toString()); 299 } 300 301 public void testPrintMessageSet() throws Exception { 302 TestMessageSet messageSet = 303 TestMessageSet.newBuilder() 304 .setExtension( 305 TestMessageSetExtension1.messageSetExtension, 306 TestMessageSetExtension1.newBuilder().setI(123).build()) 307 .setExtension( 308 TestMessageSetExtension2.messageSetExtension, 309 TestMessageSetExtension2.newBuilder().setStr("foo").build()) 310 .build(); 311 312 assertEquals(messageSetText, messageSet.toString()); 313 } 314 315 // ================================================================= 316 317 public void testParse() throws Exception { 318 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 319 TextFormat.merge(allFieldsSetText, builder); 320 TestUtil.assertAllFieldsSet(builder.build()); 321 } 322 323 public void testParseReader() throws Exception { 324 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 325 TextFormat.merge(new StringReader(allFieldsSetText), builder); 326 TestUtil.assertAllFieldsSet(builder.build()); 327 } 328 329 public void testParseExtensions() throws Exception { 330 TestAllExtensions.Builder builder = TestAllExtensions.newBuilder(); 331 TextFormat.merge(allExtensionsSetText, 332 TestUtil.getExtensionRegistry(), 333 builder); 334 TestUtil.assertAllExtensionsSet(builder.build()); 335 } 336 337 public void testParseCompatibility() throws Exception { 338 String original = "repeated_float: inf\n" + 339 "repeated_float: -inf\n" + 340 "repeated_float: nan\n" + 341 "repeated_float: inff\n" + 342 "repeated_float: -inff\n" + 343 "repeated_float: nanf\n" + 344 "repeated_float: 1.0f\n" + 345 "repeated_float: infinityf\n" + 346 "repeated_float: -Infinityf\n" + 347 "repeated_double: infinity\n" + 348 "repeated_double: -infinity\n" + 349 "repeated_double: nan\n"; 350 String canonical = "repeated_float: Infinity\n" + 351 "repeated_float: -Infinity\n" + 352 "repeated_float: NaN\n" + 353 "repeated_float: Infinity\n" + 354 "repeated_float: -Infinity\n" + 355 "repeated_float: NaN\n" + 356 "repeated_float: 1.0\n" + 357 "repeated_float: Infinity\n" + 358 "repeated_float: -Infinity\n" + 359 "repeated_double: Infinity\n" + 360 "repeated_double: -Infinity\n" + 361 "repeated_double: NaN\n"; 362 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 363 TextFormat.merge(original, builder); 364 assertEquals(canonical, builder.build().toString()); 365 } 366 367 public void testParseExotic() throws Exception { 368 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 369 TextFormat.merge(exoticText, builder); 370 371 // Too lazy to check things individually. Don't try to debug this 372 // if testPrintExotic() is failing. 373 assertEquals(canonicalExoticText, builder.build().toString()); 374 } 375 376 public void testParseMessageSet() throws Exception { 377 ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance(); 378 extensionRegistry.add(TestMessageSetExtension1.messageSetExtension); 379 extensionRegistry.add(TestMessageSetExtension2.messageSetExtension); 380 381 TestMessageSet.Builder builder = TestMessageSet.newBuilder(); 382 TextFormat.merge(messageSetText, extensionRegistry, builder); 383 TestMessageSet messageSet = builder.build(); 384 385 assertTrue(messageSet.hasExtension( 386 TestMessageSetExtension1.messageSetExtension)); 387 assertEquals(123, messageSet.getExtension( 388 TestMessageSetExtension1.messageSetExtension).getI()); 389 assertTrue(messageSet.hasExtension( 390 TestMessageSetExtension2.messageSetExtension)); 391 assertEquals("foo", messageSet.getExtension( 392 TestMessageSetExtension2.messageSetExtension).getStr()); 393 394 builder = TestMessageSet.newBuilder(); 395 TextFormat.merge(messageSetTextWithRepeatedExtension, extensionRegistry, 396 builder); 397 messageSet = builder.build(); 398 assertEquals(456, messageSet.getExtension( 399 TestMessageSetExtension1.messageSetExtension).getI()); 400 } 401 402 public void testParseMessageSetWithOverwriteForbidden() throws Exception { 403 ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance(); 404 extensionRegistry.add(TestMessageSetExtension1.messageSetExtension); 405 extensionRegistry.add(TestMessageSetExtension2.messageSetExtension); 406 407 TestMessageSet.Builder builder = TestMessageSet.newBuilder(); 408 parserWithOverwriteForbidden.merge( 409 messageSetText, extensionRegistry, builder); 410 TestMessageSet messageSet = builder.build(); 411 assertEquals(123, messageSet.getExtension( 412 TestMessageSetExtension1.messageSetExtension).getI()); 413 assertEquals("foo", messageSet.getExtension( 414 TestMessageSetExtension2.messageSetExtension).getStr()); 415 416 builder = TestMessageSet.newBuilder(); 417 try { 418 parserWithOverwriteForbidden.merge( 419 messageSetTextWithRepeatedExtension, extensionRegistry, builder); 420 fail("expected parse exception"); 421 } catch (TextFormat.ParseException e) { 422 assertEquals("6:1: Non-repeated field " 423 + "\"protobuf_unittest.TestMessageSetExtension1.message_set_extension\"" 424 + " cannot be overwritten.", 425 e.getMessage()); 426 } 427 } 428 429 public void testParseNumericEnum() throws Exception { 430 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 431 TextFormat.merge("optional_nested_enum: 2", builder); 432 assertEquals(TestAllTypes.NestedEnum.BAR, builder.getOptionalNestedEnum()); 433 } 434 435 public void testParseAngleBrackets() throws Exception { 436 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 437 TextFormat.merge("OptionalGroup: < a: 1 >", builder); 438 assertTrue(builder.hasOptionalGroup()); 439 assertEquals(1, builder.getOptionalGroup().getA()); 440 } 441 442 public void testParseComment() throws Exception { 443 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 444 TextFormat.merge( 445 "# this is a comment\n" + 446 "optional_int32: 1 # another comment\n" + 447 "optional_int64: 2\n" + 448 "# EOF comment", builder); 449 assertEquals(1, builder.getOptionalInt32()); 450 assertEquals(2, builder.getOptionalInt64()); 451 } 452 453 private void assertParseError(String error, String text) { 454 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 455 try { 456 TextFormat.merge(text, TestUtil.getExtensionRegistry(), builder); 457 fail("Expected parse exception."); 458 } catch (TextFormat.ParseException e) { 459 assertEquals(error, e.getMessage()); 460 } 461 } 462 463 private void assertParseErrorWithOverwriteForbidden(String error, 464 String text) { 465 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 466 try { 467 parserWithOverwriteForbidden.merge( 468 text, TestUtil.getExtensionRegistry(), builder); 469 fail("Expected parse exception."); 470 } catch (TextFormat.ParseException e) { 471 assertEquals(error, e.getMessage()); 472 } 473 } 474 475 private TestAllTypes assertParseSuccessWithOverwriteForbidden( 476 String text) throws TextFormat.ParseException { 477 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 478 parserWithOverwriteForbidden.merge( 479 text, TestUtil.getExtensionRegistry(), builder); 480 return builder.build(); 481 } 482 483 public void testParseErrors() throws Exception { 484 assertParseError( 485 "1:16: Expected \":\".", 486 "optional_int32 123"); 487 assertParseError( 488 "1:23: Expected identifier. Found '?'", 489 "optional_nested_enum: ?"); 490 assertParseError( 491 "1:18: Couldn't parse integer: Number must be positive: -1", 492 "optional_uint32: -1"); 493 assertParseError( 494 "1:17: Couldn't parse integer: Number out of range for 32-bit signed " + 495 "integer: 82301481290849012385230157", 496 "optional_int32: 82301481290849012385230157"); 497 assertParseError( 498 "1:16: Expected \"true\" or \"false\".", 499 "optional_bool: maybe"); 500 assertParseError( 501 "1:16: Expected \"true\" or \"false\".", 502 "optional_bool: 2"); 503 assertParseError( 504 "1:18: Expected string.", 505 "optional_string: 123"); 506 assertParseError( 507 "1:18: String missing ending quote.", 508 "optional_string: \"ueoauaoe"); 509 assertParseError( 510 "1:18: String missing ending quote.", 511 "optional_string: \"ueoauaoe\n" + 512 "optional_int32: 123"); 513 assertParseError( 514 "1:18: Invalid escape sequence: '\\z'", 515 "optional_string: \"\\z\""); 516 assertParseError( 517 "1:18: String missing ending quote.", 518 "optional_string: \"ueoauaoe\n" + 519 "optional_int32: 123"); 520 assertParseError( 521 "1:2: Extension \"nosuchext\" not found in the ExtensionRegistry.", 522 "[nosuchext]: 123"); 523 assertParseError( 524 "1:20: Extension \"protobuf_unittest.optional_int32_extension\" does " + 525 "not extend message type \"protobuf_unittest.TestAllTypes\".", 526 "[protobuf_unittest.optional_int32_extension]: 123"); 527 assertParseError( 528 "1:1: Message type \"protobuf_unittest.TestAllTypes\" has no field " + 529 "named \"nosuchfield\".", 530 "nosuchfield: 123"); 531 assertParseError( 532 "1:21: Expected \">\".", 533 "OptionalGroup < a: 1"); 534 assertParseError( 535 "1:23: Enum type \"protobuf_unittest.TestAllTypes.NestedEnum\" has no " + 536 "value named \"NO_SUCH_VALUE\".", 537 "optional_nested_enum: NO_SUCH_VALUE"); 538 assertParseError( 539 "1:23: Enum type \"protobuf_unittest.TestAllTypes.NestedEnum\" has no " + 540 "value with number 123.", 541 "optional_nested_enum: 123"); 542 543 // Delimiters must match. 544 assertParseError( 545 "1:22: Expected identifier. Found '}'", 546 "OptionalGroup < a: 1 }"); 547 assertParseError( 548 "1:22: Expected identifier. Found '>'", 549 "OptionalGroup { a: 1 >"); 550 } 551 552 // ================================================================= 553 554 public void testEscape() throws Exception { 555 // Escape sequences. 556 assertEquals("\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\"", 557 TextFormat.escapeBytes(bytes("\0\001\007\b\f\n\r\t\013\\\'\""))); 558 assertEquals("\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\"", 559 TextFormat.escapeText("\0\001\007\b\f\n\r\t\013\\\'\"")); 560 assertEquals(bytes("\0\001\007\b\f\n\r\t\013\\\'\""), 561 TextFormat.unescapeBytes("\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\"")); 562 assertEquals("\0\001\007\b\f\n\r\t\013\\\'\"", 563 TextFormat.unescapeText("\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\"")); 564 assertEquals(kEscapeTestStringEscaped, 565 TextFormat.escapeText(kEscapeTestString)); 566 assertEquals(kEscapeTestString, 567 TextFormat.unescapeText(kEscapeTestStringEscaped)); 568 569 // Unicode handling. 570 assertEquals("\\341\\210\\264", TextFormat.escapeText("\u1234")); 571 assertEquals("\\341\\210\\264", 572 TextFormat.escapeBytes(bytes(0xe1, 0x88, 0xb4))); 573 assertEquals("\u1234", TextFormat.unescapeText("\\341\\210\\264")); 574 assertEquals(bytes(0xe1, 0x88, 0xb4), 575 TextFormat.unescapeBytes("\\341\\210\\264")); 576 assertEquals("\u1234", TextFormat.unescapeText("\\xe1\\x88\\xb4")); 577 assertEquals(bytes(0xe1, 0x88, 0xb4), 578 TextFormat.unescapeBytes("\\xe1\\x88\\xb4")); 579 580 // Handling of strings with unescaped Unicode characters > 255. 581 final String zh = "\u9999\u6e2f\u4e0a\u6d77\ud84f\udf80\u8c50\u9280\u884c"; 582 ByteString zhByteString = ByteString.copyFromUtf8(zh); 583 assertEquals(zhByteString, TextFormat.unescapeBytes(zh)); 584 585 // Errors. 586 try { 587 TextFormat.unescapeText("\\x"); 588 fail("Should have thrown an exception."); 589 } catch (TextFormat.InvalidEscapeSequenceException e) { 590 // success 591 } 592 593 try { 594 TextFormat.unescapeText("\\z"); 595 fail("Should have thrown an exception."); 596 } catch (TextFormat.InvalidEscapeSequenceException e) { 597 // success 598 } 599 600 try { 601 TextFormat.unescapeText("\\"); 602 fail("Should have thrown an exception."); 603 } catch (TextFormat.InvalidEscapeSequenceException e) { 604 // success 605 } 606 } 607 608 public void testParseInteger() throws Exception { 609 assertEquals( 0, TextFormat.parseInt32( "0")); 610 assertEquals( 1, TextFormat.parseInt32( "1")); 611 assertEquals( -1, TextFormat.parseInt32( "-1")); 612 assertEquals( 12345, TextFormat.parseInt32( "12345")); 613 assertEquals( -12345, TextFormat.parseInt32( "-12345")); 614 assertEquals( 2147483647, TextFormat.parseInt32( "2147483647")); 615 assertEquals(-2147483648, TextFormat.parseInt32("-2147483648")); 616 617 assertEquals( 0, TextFormat.parseUInt32( "0")); 618 assertEquals( 1, TextFormat.parseUInt32( "1")); 619 assertEquals( 12345, TextFormat.parseUInt32( "12345")); 620 assertEquals( 2147483647, TextFormat.parseUInt32("2147483647")); 621 assertEquals((int) 2147483648L, TextFormat.parseUInt32("2147483648")); 622 assertEquals((int) 4294967295L, TextFormat.parseUInt32("4294967295")); 623 624 assertEquals( 0L, TextFormat.parseInt64( "0")); 625 assertEquals( 1L, TextFormat.parseInt64( "1")); 626 assertEquals( -1L, TextFormat.parseInt64( "-1")); 627 assertEquals( 12345L, TextFormat.parseInt64( "12345")); 628 assertEquals( -12345L, TextFormat.parseInt64( "-12345")); 629 assertEquals( 2147483647L, TextFormat.parseInt64( "2147483647")); 630 assertEquals(-2147483648L, TextFormat.parseInt64("-2147483648")); 631 assertEquals( 4294967295L, TextFormat.parseInt64( "4294967295")); 632 assertEquals( 4294967296L, TextFormat.parseInt64( "4294967296")); 633 assertEquals(9223372036854775807L, 634 TextFormat.parseInt64("9223372036854775807")); 635 assertEquals(-9223372036854775808L, 636 TextFormat.parseInt64("-9223372036854775808")); 637 638 assertEquals( 0L, TextFormat.parseUInt64( "0")); 639 assertEquals( 1L, TextFormat.parseUInt64( "1")); 640 assertEquals( 12345L, TextFormat.parseUInt64( "12345")); 641 assertEquals( 2147483647L, TextFormat.parseUInt64( "2147483647")); 642 assertEquals( 4294967295L, TextFormat.parseUInt64( "4294967295")); 643 assertEquals( 4294967296L, TextFormat.parseUInt64( "4294967296")); 644 assertEquals(9223372036854775807L, 645 TextFormat.parseUInt64("9223372036854775807")); 646 assertEquals(-9223372036854775808L, 647 TextFormat.parseUInt64("9223372036854775808")); 648 assertEquals(-1L, TextFormat.parseUInt64("18446744073709551615")); 649 650 // Hex 651 assertEquals(0x1234abcd, TextFormat.parseInt32("0x1234abcd")); 652 assertEquals(-0x1234abcd, TextFormat.parseInt32("-0x1234abcd")); 653 assertEquals(-1, TextFormat.parseUInt64("0xffffffffffffffff")); 654 assertEquals(0x7fffffffffffffffL, 655 TextFormat.parseInt64("0x7fffffffffffffff")); 656 657 // Octal 658 assertEquals(01234567, TextFormat.parseInt32("01234567")); 659 660 // Out-of-range 661 try { 662 TextFormat.parseInt32("2147483648"); 663 fail("Should have thrown an exception."); 664 } catch (NumberFormatException e) { 665 // success 666 } 667 668 try { 669 TextFormat.parseInt32("-2147483649"); 670 fail("Should have thrown an exception."); 671 } catch (NumberFormatException e) { 672 // success 673 } 674 675 try { 676 TextFormat.parseUInt32("4294967296"); 677 fail("Should have thrown an exception."); 678 } catch (NumberFormatException e) { 679 // success 680 } 681 682 try { 683 TextFormat.parseUInt32("-1"); 684 fail("Should have thrown an exception."); 685 } catch (NumberFormatException e) { 686 // success 687 } 688 689 try { 690 TextFormat.parseInt64("9223372036854775808"); 691 fail("Should have thrown an exception."); 692 } catch (NumberFormatException e) { 693 // success 694 } 695 696 try { 697 TextFormat.parseInt64("-9223372036854775809"); 698 fail("Should have thrown an exception."); 699 } catch (NumberFormatException e) { 700 // success 701 } 702 703 try { 704 TextFormat.parseUInt64("18446744073709551616"); 705 fail("Should have thrown an exception."); 706 } catch (NumberFormatException e) { 707 // success 708 } 709 710 try { 711 TextFormat.parseUInt64("-1"); 712 fail("Should have thrown an exception."); 713 } catch (NumberFormatException e) { 714 // success 715 } 716 717 // Not a number. 718 try { 719 TextFormat.parseInt32("abcd"); 720 fail("Should have thrown an exception."); 721 } catch (NumberFormatException e) { 722 // success 723 } 724 } 725 726 public void testParseString() throws Exception { 727 final String zh = "\u9999\u6e2f\u4e0a\u6d77\ud84f\udf80\u8c50\u9280\u884c"; 728 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 729 TextFormat.merge("optional_string: \"" + zh + "\"", builder); 730 assertEquals(zh, builder.getOptionalString()); 731 } 732 733 public void testParseLongString() throws Exception { 734 String longText = 735 "123456789012345678901234567890123456789012345678901234567890" + 736 "123456789012345678901234567890123456789012345678901234567890" + 737 "123456789012345678901234567890123456789012345678901234567890" + 738 "123456789012345678901234567890123456789012345678901234567890" + 739 "123456789012345678901234567890123456789012345678901234567890" + 740 "123456789012345678901234567890123456789012345678901234567890" + 741 "123456789012345678901234567890123456789012345678901234567890" + 742 "123456789012345678901234567890123456789012345678901234567890" + 743 "123456789012345678901234567890123456789012345678901234567890" + 744 "123456789012345678901234567890123456789012345678901234567890" + 745 "123456789012345678901234567890123456789012345678901234567890" + 746 "123456789012345678901234567890123456789012345678901234567890" + 747 "123456789012345678901234567890123456789012345678901234567890" + 748 "123456789012345678901234567890123456789012345678901234567890" + 749 "123456789012345678901234567890123456789012345678901234567890" + 750 "123456789012345678901234567890123456789012345678901234567890" + 751 "123456789012345678901234567890123456789012345678901234567890" + 752 "123456789012345678901234567890123456789012345678901234567890" + 753 "123456789012345678901234567890123456789012345678901234567890" + 754 "123456789012345678901234567890123456789012345678901234567890"; 755 756 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 757 TextFormat.merge("optional_string: \"" + longText + "\"", builder); 758 assertEquals(longText, builder.getOptionalString()); 759 } 760 761 public void testParseBoolean() throws Exception { 762 String goodText = 763 "repeated_bool: t repeated_bool : 0\n" + 764 "repeated_bool :f repeated_bool:1"; 765 String goodTextCanonical = 766 "repeated_bool: true\n" + 767 "repeated_bool: false\n" + 768 "repeated_bool: false\n" + 769 "repeated_bool: true\n"; 770 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 771 TextFormat.merge(goodText, builder); 772 assertEquals(goodTextCanonical, builder.build().toString()); 773 774 try { 775 TestAllTypes.Builder badBuilder = TestAllTypes.newBuilder(); 776 TextFormat.merge("optional_bool:2", badBuilder); 777 fail("Should have thrown an exception."); 778 } catch (TextFormat.ParseException e) { 779 // success 780 } 781 try { 782 TestAllTypes.Builder badBuilder = TestAllTypes.newBuilder(); 783 TextFormat.merge("optional_bool: foo", badBuilder); 784 fail("Should have thrown an exception."); 785 } catch (TextFormat.ParseException e) { 786 // success 787 } 788 } 789 790 public void testParseAdjacentStringLiterals() throws Exception { 791 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 792 TextFormat.merge("optional_string: \"foo\" 'corge' \"grault\"", builder); 793 assertEquals("foocorgegrault", builder.getOptionalString()); 794 } 795 796 public void testPrintFieldValue() throws Exception { 797 assertPrintFieldValue("\"Hello\"", "Hello", "repeated_string"); 798 assertPrintFieldValue("123.0", 123f, "repeated_float"); 799 assertPrintFieldValue("123.0", 123d, "repeated_double"); 800 assertPrintFieldValue("123", 123, "repeated_int32"); 801 assertPrintFieldValue("123", 123L, "repeated_int64"); 802 assertPrintFieldValue("true", true, "repeated_bool"); 803 assertPrintFieldValue("4294967295", 0xFFFFFFFF, "repeated_uint32"); 804 assertPrintFieldValue("18446744073709551615", 0xFFFFFFFFFFFFFFFFL, 805 "repeated_uint64"); 806 assertPrintFieldValue("\"\\001\\002\\003\"", 807 ByteString.copyFrom(new byte[] {1, 2, 3}), "repeated_bytes"); 808 } 809 810 private void assertPrintFieldValue(String expect, Object value, 811 String fieldName) throws Exception { 812 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 813 StringBuilder sb = new StringBuilder(); 814 TextFormat.printFieldValue( 815 TestAllTypes.getDescriptor().findFieldByName(fieldName), 816 value, sb); 817 assertEquals(expect, sb.toString()); 818 } 819 820 public void testShortDebugString() { 821 assertEquals("optional_nested_message { bb: 42 } repeated_int32: 1" 822 + " repeated_uint32: 2", 823 TextFormat.shortDebugString(TestAllTypes.newBuilder() 824 .addRepeatedInt32(1) 825 .addRepeatedUint32(2) 826 .setOptionalNestedMessage( 827 NestedMessage.newBuilder().setBb(42).build()) 828 .build())); 829 } 830 831 public void testShortDebugString_unknown() { 832 assertEquals("5: 1 5: 0x00000002 5: 0x0000000000000003 5: \"4\" 5 { 10: 5 }" 833 + " 8: 1 8: 2 8: 3 15: 12379813812177893520 15: 0xabcd1234 15:" 834 + " 0xabcdef1234567890", 835 TextFormat.shortDebugString(makeUnknownFieldSet())); 836 } 837 838 public void testPrintToUnicodeString() throws Exception { 839 assertEquals( 840 "optional_string: \"abc\u3042efg\"\n" + 841 "optional_bytes: \"\\343\\201\\202\"\n" + 842 "repeated_string: \"\u3093XYZ\"\n", 843 TextFormat.printToUnicodeString(TestAllTypes.newBuilder() 844 .setOptionalString("abc\u3042efg") 845 .setOptionalBytes(bytes(0xe3, 0x81, 0x82)) 846 .addRepeatedString("\u3093XYZ") 847 .build())); 848 849 // Double quotes and backslashes should be escaped 850 assertEquals( 851 "optional_string: \"a\\\\bc\\\"ef\\\"g\"\n", 852 TextFormat.printToUnicodeString(TestAllTypes.newBuilder() 853 .setOptionalString("a\\bc\"ef\"g") 854 .build())); 855 856 // Test escaping roundtrip 857 TestAllTypes message = TestAllTypes.newBuilder() 858 .setOptionalString("a\\bc\\\"ef\"g") 859 .build(); 860 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 861 TextFormat.merge(TextFormat.printToUnicodeString(message), builder); 862 assertEquals(message.getOptionalString(), builder.getOptionalString()); 863 } 864 865 public void testPrintToUnicodeStringWithNewlines() { 866 // No newlines at start and end 867 assertEquals("optional_string: \"test newlines\n\nin\nstring\"\n", 868 TextFormat.printToUnicodeString(TestAllTypes.newBuilder() 869 .setOptionalString("test newlines\n\nin\nstring") 870 .build())); 871 872 // Newlines at start and end 873 assertEquals("optional_string: \"\ntest\nnewlines\n\nin\nstring\n\"\n", 874 TextFormat.printToUnicodeString(TestAllTypes.newBuilder() 875 .setOptionalString("\ntest\nnewlines\n\nin\nstring\n") 876 .build())); 877 878 // Strings with 0, 1 and 2 newlines. 879 assertEquals("optional_string: \"\"\n", 880 TextFormat.printToUnicodeString(TestAllTypes.newBuilder() 881 .setOptionalString("") 882 .build())); 883 assertEquals("optional_string: \"\n\"\n", 884 TextFormat.printToUnicodeString(TestAllTypes.newBuilder() 885 .setOptionalString("\n") 886 .build())); 887 assertEquals("optional_string: \"\n\n\"\n", 888 TextFormat.printToUnicodeString(TestAllTypes.newBuilder() 889 .setOptionalString("\n\n") 890 .build())); 891 } 892 893 public void testPrintToUnicodeString_unknown() { 894 assertEquals( 895 "1: \"\\343\\201\\202\"\n", 896 TextFormat.printToUnicodeString(UnknownFieldSet.newBuilder() 897 .addField(1, 898 UnknownFieldSet.Field.newBuilder() 899 .addLengthDelimited(bytes(0xe3, 0x81, 0x82)).build()) 900 .build())); 901 } 902 903 public void testParseNonRepeatedFields() throws Exception { 904 assertParseSuccessWithOverwriteForbidden( 905 "repeated_int32: 1\n" + 906 "repeated_int32: 2\n"); 907 assertParseSuccessWithOverwriteForbidden( 908 "RepeatedGroup { a: 1 }\n" + 909 "RepeatedGroup { a: 2 }\n"); 910 assertParseSuccessWithOverwriteForbidden( 911 "repeated_nested_message { bb: 1 }\n" + 912 "repeated_nested_message { bb: 2 }\n"); 913 assertParseErrorWithOverwriteForbidden( 914 "3:17: Non-repeated field " + 915 "\"protobuf_unittest.TestAllTypes.optional_int32\" " + 916 "cannot be overwritten.", 917 "optional_int32: 1\n" + 918 "optional_bool: true\n" + 919 "optional_int32: 1\n"); 920 assertParseErrorWithOverwriteForbidden( 921 "2:17: Non-repeated field " + 922 "\"protobuf_unittest.TestAllTypes.optionalgroup\" " + 923 "cannot be overwritten.", 924 "OptionalGroup { a: 1 }\n" + 925 "OptionalGroup { }\n"); 926 assertParseErrorWithOverwriteForbidden( 927 "2:33: Non-repeated field " + 928 "\"protobuf_unittest.TestAllTypes.optional_nested_message\" " + 929 "cannot be overwritten.", 930 "optional_nested_message { }\n" + 931 "optional_nested_message { bb: 3 }\n"); 932 assertParseErrorWithOverwriteForbidden( 933 "2:16: Non-repeated field " + 934 "\"protobuf_unittest.TestAllTypes.default_int32\" " + 935 "cannot be overwritten.", 936 "default_int32: 41\n" + // the default value 937 "default_int32: 41\n"); 938 assertParseErrorWithOverwriteForbidden( 939 "2:17: Non-repeated field " + 940 "\"protobuf_unittest.TestAllTypes.default_string\" " + 941 "cannot be overwritten.", 942 "default_string: \"zxcv\"\n" + 943 "default_string: \"asdf\"\n"); 944 } 945 946 public void testParseShortRepeatedFormOfRepeatedFields() throws Exception { 947 assertParseSuccessWithOverwriteForbidden("repeated_foreign_enum: [FOREIGN_FOO, FOREIGN_BAR]"); 948 assertParseSuccessWithOverwriteForbidden("repeated_int32: [ 1, 2 ]\n"); 949 assertParseSuccessWithOverwriteForbidden("RepeatedGroup [{ a: 1 },{ a: 2 }]\n"); 950 assertParseSuccessWithOverwriteForbidden("repeated_nested_message [{ bb: 1 }, { bb: 2 }]\n"); 951 } 952 953 public void testParseShortRepeatedFormOfNonRepeatedFields() throws Exception { 954 assertParseErrorWithOverwriteForbidden( 955 "1:17: Couldn't parse integer: For input string: \"[\"", 956 "optional_int32: [1]\n"); 957 } 958 959 // ======================================================================= 960 // test oneof 961 962 public void testOneofTextFormat() throws Exception { 963 TestOneof2.Builder builder = TestOneof2.newBuilder(); 964 TestUtil.setOneof(builder); 965 TestOneof2 message = builder.build(); 966 TestOneof2.Builder dest = TestOneof2.newBuilder(); 967 TextFormat.merge(TextFormat.printToUnicodeString(message), dest); 968 TestUtil.assertOneofSet(dest.build()); 969 } 970 971 public void testOneofOverwriteForbidden() throws Exception { 972 String input = "foo_string: \"stringvalue\" foo_int: 123"; 973 TestOneof2.Builder builder = TestOneof2.newBuilder(); 974 try { 975 parserWithOverwriteForbidden.merge( 976 input, TestUtil.getExtensionRegistry(), builder); 977 fail("Expected parse exception."); 978 } catch (TextFormat.ParseException e) { 979 assertEquals("1:36: Field \"protobuf_unittest.TestOneof2.foo_int\"" 980 + " is specified along with field \"protobuf_unittest.TestOneof2.foo_string\"," 981 + " another member of oneof \"foo\".", e.getMessage()); 982 } 983 } 984 985 public void testOneofOverwriteAllowed() throws Exception { 986 String input = "foo_string: \"stringvalue\" foo_int: 123"; 987 TestOneof2.Builder builder = TestOneof2.newBuilder(); 988 defaultParser.merge(input, TestUtil.getExtensionRegistry(), builder); 989 // Only the last value sticks. 990 TestOneof2 oneof = builder.build(); 991 assertFalse(oneof.hasFooString()); 992 assertTrue(oneof.hasFooInt()); 993 } 994} 995