Home | History | Annotate | Download | only in protobuf
      1 // Protocol Buffers - Google's data interchange format
      2 // Copyright 2008 Google Inc.  All rights reserved.
      3 // http://code.google.com/p/protobuf/
      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 com.google.protobuf.Descriptors.FieldDescriptor;
     34 import protobuf_unittest.UnittestProto.OneString;
     35 import protobuf_unittest.UnittestProto.TestAllTypes;
     36 import protobuf_unittest.UnittestProto.TestAllExtensions;
     37 import protobuf_unittest.UnittestProto.TestEmptyMessage;
     38 import protobuf_unittest.UnittestProto.TestAllTypes.NestedMessage;
     39 import protobuf_unittest.UnittestMset.TestMessageSet;
     40 import protobuf_unittest.UnittestMset.TestMessageSetExtension1;
     41 import protobuf_unittest.UnittestMset.TestMessageSetExtension2;
     42 
     43 import junit.framework.TestCase;
     44 
     45 import java.io.StringReader;
     46 
     47 /**
     48  * Test case for {@link TextFormat}.
     49  *
     50  * TODO(wenboz): ExtensionTest and rest of text_format_unittest.cc.
     51  *
     52  * @author wenboz (at) google.com (Wenbo Zhu)
     53  */
     54 public class TextFormatTest extends TestCase {
     55 
     56   // A basic string with different escapable characters for testing.
     57   private final static String kEscapeTestString =
     58       "\"A string with ' characters \n and \r newlines and \t tabs and \001 "
     59           + "slashes \\";
     60 
     61   // A representation of the above string with all the characters escaped.
     62   private final static String kEscapeTestStringEscaped =
     63       "\"\\\"A string with \\' characters \\n and \\r newlines "
     64           + "and \\t tabs and \\001 slashes \\\\\"";
     65 
     66   private static String allFieldsSetText = TestUtil.readTextFromFile(
     67     "text_format_unittest_data.txt");
     68   private static String allExtensionsSetText = TestUtil.readTextFromFile(
     69     "text_format_unittest_extensions_data.txt");
     70 
     71   private static String exoticText =
     72     "repeated_int32: -1\n" +
     73     "repeated_int32: -2147483648\n" +
     74     "repeated_int64: -1\n" +
     75     "repeated_int64: -9223372036854775808\n" +
     76     "repeated_uint32: 4294967295\n" +
     77     "repeated_uint32: 2147483648\n" +
     78     "repeated_uint64: 18446744073709551615\n" +
     79     "repeated_uint64: 9223372036854775808\n" +
     80     "repeated_double: 123.0\n" +
     81     "repeated_double: 123.5\n" +
     82     "repeated_double: 0.125\n" +
     83     "repeated_double: .125\n" +
     84     "repeated_double: -.125\n" +
     85     "repeated_double: 1.23E17\n" +
     86     "repeated_double: 1.23E+17\n" +
     87     "repeated_double: -1.23e-17\n" +
     88     "repeated_double: .23e+17\n" +
     89     "repeated_double: -.23E17\n" +
     90     "repeated_double: 1.235E22\n" +
     91     "repeated_double: 1.235E-18\n" +
     92     "repeated_double: 123.456789\n" +
     93     "repeated_double: Infinity\n" +
     94     "repeated_double: -Infinity\n" +
     95     "repeated_double: NaN\n" +
     96     "repeated_string: \"\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\"" +
     97       "\\341\\210\\264\"\n" +
     98     "repeated_bytes: \"\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\"\\376\"\n";
     99 
    100   private static String canonicalExoticText =
    101       exoticText.replace(": .", ": 0.").replace(": -.", ": -0.")   // short-form double
    102       .replace("23e", "23E").replace("E+", "E").replace("0.23E17", "2.3E16");
    103 
    104   private String messageSetText =
    105     "[protobuf_unittest.TestMessageSetExtension1] {\n" +
    106     "  i: 123\n" +
    107     "}\n" +
    108     "[protobuf_unittest.TestMessageSetExtension2] {\n" +
    109     "  str: \"foo\"\n" +
    110     "}\n";
    111 
    112   /** Print TestAllTypes and compare with golden file. */
    113   public void testPrintMessage() throws Exception {
    114     String javaText = TextFormat.printToString(TestUtil.getAllSet());
    115 
    116     // Java likes to add a trailing ".0" to floats and doubles.  C printf
    117     // (with %g format) does not.  Our golden files are used for both
    118     // C++ and Java TextFormat classes, so we need to conform.
    119     javaText = javaText.replace(".0\n", "\n");
    120 
    121     assertEquals(allFieldsSetText, javaText);
    122   }
    123 
    124   /** Print TestAllExtensions and compare with golden file. */
    125   public void testPrintExtensions() throws Exception {
    126     String javaText = TextFormat.printToString(TestUtil.getAllExtensionsSet());
    127 
    128     // Java likes to add a trailing ".0" to floats and doubles.  C printf
    129     // (with %g format) does not.  Our golden files are used for both
    130     // C++ and Java TextFormat classes, so we need to conform.
    131     javaText = javaText.replace(".0\n", "\n");
    132 
    133     assertEquals(allExtensionsSetText, javaText);
    134   }
    135 
    136   public void testPrintUnknownFields() throws Exception {
    137     // Test printing of unknown fields in a message.
    138 
    139     TestEmptyMessage message =
    140       TestEmptyMessage.newBuilder()
    141         .setUnknownFields(
    142           UnknownFieldSet.newBuilder()
    143             .addField(5,
    144               UnknownFieldSet.Field.newBuilder()
    145                 .addVarint(1)
    146                 .addFixed32(2)
    147                 .addFixed64(3)
    148                 .addLengthDelimited(ByteString.copyFromUtf8("4"))
    149                 .addGroup(
    150                   UnknownFieldSet.newBuilder()
    151                     .addField(10,
    152                       UnknownFieldSet.Field.newBuilder()
    153                         .addVarint(5)
    154                         .build())
    155                     .build())
    156                 .build())
    157             .addField(8,
    158               UnknownFieldSet.Field.newBuilder()
    159                 .addVarint(1)
    160                 .addVarint(2)
    161                 .addVarint(3)
    162                 .build())
    163             .addField(15,
    164               UnknownFieldSet.Field.newBuilder()
    165                 .addVarint(0xABCDEF1234567890L)
    166                 .addFixed32(0xABCD1234)
    167                 .addFixed64(0xABCDEF1234567890L)
    168                 .build())
    169             .build())
    170         .build();
    171 
    172     assertEquals(
    173       "5: 1\n" +
    174       "5: 0x00000002\n" +
    175       "5: 0x0000000000000003\n" +
    176       "5: \"4\"\n" +
    177       "5 {\n" +
    178       "  10: 5\n" +
    179       "}\n" +
    180       "8: 1\n" +
    181       "8: 2\n" +
    182       "8: 3\n" +
    183       "15: 12379813812177893520\n" +
    184       "15: 0xabcd1234\n" +
    185       "15: 0xabcdef1234567890\n",
    186       TextFormat.printToString(message));
    187   }
    188 
    189   public void testPrintField() throws Exception {
    190     final FieldDescriptor dataField =
    191       OneString.getDescriptor().findFieldByName("data");
    192     assertEquals(
    193       "data: \"test data\"\n",
    194       TextFormat.printFieldToString(dataField, "test data"));
    195 
    196     final FieldDescriptor optionalField =
    197       TestAllTypes.getDescriptor().findFieldByName("optional_nested_message");
    198     final Object value = NestedMessage.newBuilder().setBb(42).build();
    199 
    200     assertEquals(
    201       "optional_nested_message {\n  bb: 42\n}\n",
    202       TextFormat.printFieldToString(optionalField, value));
    203   }
    204 
    205   /**
    206    * Helper to construct a ByteString from a String containing only 8-bit
    207    * characters.  The characters are converted directly to bytes, *not*
    208    * encoded using UTF-8.
    209    */
    210   private ByteString bytes(String str) throws Exception {
    211     return ByteString.copyFrom(str.getBytes("ISO-8859-1"));
    212   }
    213 
    214   /**
    215    * Helper to construct a ByteString from a bunch of bytes.  The inputs are
    216    * actually ints so that I can use hex notation and not get stupid errors
    217    * about precision.
    218    */
    219   private ByteString bytes(int... bytesAsInts) {
    220     byte[] bytes = new byte[bytesAsInts.length];
    221     for (int i = 0; i < bytesAsInts.length; i++) {
    222       bytes[i] = (byte) bytesAsInts[i];
    223     }
    224     return ByteString.copyFrom(bytes);
    225   }
    226 
    227   public void testPrintExotic() throws Exception {
    228     Message message = TestAllTypes.newBuilder()
    229       // Signed vs. unsigned numbers.
    230       .addRepeatedInt32 (-1)
    231       .addRepeatedUint32(-1)
    232       .addRepeatedInt64 (-1)
    233       .addRepeatedUint64(-1)
    234 
    235       .addRepeatedInt32 (1  << 31)
    236       .addRepeatedUint32(1  << 31)
    237       .addRepeatedInt64 (1l << 63)
    238       .addRepeatedUint64(1l << 63)
    239 
    240       // Floats of various precisions and exponents.
    241       .addRepeatedDouble(123)
    242       .addRepeatedDouble(123.5)
    243       .addRepeatedDouble(0.125)
    244       .addRepeatedDouble(.125)
    245       .addRepeatedDouble(-.125)
    246       .addRepeatedDouble(123e15)
    247       .addRepeatedDouble(123e15)
    248       .addRepeatedDouble(-1.23e-17)
    249       .addRepeatedDouble(.23e17)
    250       .addRepeatedDouble(-23e15)
    251       .addRepeatedDouble(123.5e20)
    252       .addRepeatedDouble(123.5e-20)
    253       .addRepeatedDouble(123.456789)
    254       .addRepeatedDouble(Double.POSITIVE_INFINITY)
    255       .addRepeatedDouble(Double.NEGATIVE_INFINITY)
    256       .addRepeatedDouble(Double.NaN)
    257 
    258       // Strings and bytes that needing escaping.
    259       .addRepeatedString("\0\001\007\b\f\n\r\t\013\\\'\"\u1234")
    260       .addRepeatedBytes(bytes("\0\001\007\b\f\n\r\t\013\\\'\"\u00fe"))
    261       .build();
    262 
    263     assertEquals(canonicalExoticText, message.toString());
    264   }
    265 
    266   public void testPrintMessageSet() throws Exception {
    267     TestMessageSet messageSet =
    268       TestMessageSet.newBuilder()
    269         .setExtension(
    270           TestMessageSetExtension1.messageSetExtension,
    271           TestMessageSetExtension1.newBuilder().setI(123).build())
    272         .setExtension(
    273           TestMessageSetExtension2.messageSetExtension,
    274           TestMessageSetExtension2.newBuilder().setStr("foo").build())
    275         .build();
    276 
    277     assertEquals(messageSetText, messageSet.toString());
    278   }
    279 
    280   // =================================================================
    281 
    282   public void testParse() throws Exception {
    283     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
    284     TextFormat.merge(allFieldsSetText, builder);
    285     TestUtil.assertAllFieldsSet(builder.build());
    286   }
    287 
    288   public void testParseReader() throws Exception {
    289     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
    290     TextFormat.merge(new StringReader(allFieldsSetText), builder);
    291     TestUtil.assertAllFieldsSet(builder.build());
    292   }
    293 
    294   public void testParseExtensions() throws Exception {
    295     TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
    296     TextFormat.merge(allExtensionsSetText,
    297                      TestUtil.getExtensionRegistry(),
    298                      builder);
    299     TestUtil.assertAllExtensionsSet(builder.build());
    300   }
    301 
    302   public void testParseCompatibility() throws Exception {
    303     String original = "repeated_float: inf\n" +
    304                       "repeated_float: -inf\n" +
    305                       "repeated_float: nan\n" +
    306                       "repeated_float: inff\n" +
    307                       "repeated_float: -inff\n" +
    308                       "repeated_float: nanf\n" +
    309                       "repeated_float: 1.0f\n" +
    310                       "repeated_float: infinityf\n" +
    311                       "repeated_float: -Infinityf\n" +
    312                       "repeated_double: infinity\n" +
    313                       "repeated_double: -infinity\n" +
    314                       "repeated_double: nan\n";
    315     String canonical =  "repeated_float: Infinity\n" +
    316                         "repeated_float: -Infinity\n" +
    317                         "repeated_float: NaN\n" +
    318                         "repeated_float: Infinity\n" +
    319                         "repeated_float: -Infinity\n" +
    320                         "repeated_float: NaN\n" +
    321                         "repeated_float: 1.0\n" +
    322                         "repeated_float: Infinity\n" +
    323                         "repeated_float: -Infinity\n" +
    324                         "repeated_double: Infinity\n" +
    325                         "repeated_double: -Infinity\n" +
    326                         "repeated_double: NaN\n";
    327     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
    328     TextFormat.merge(original, builder);
    329     assertEquals(canonical, builder.build().toString());
    330   }
    331 
    332   public void testParseExotic() throws Exception {
    333     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
    334     TextFormat.merge(exoticText, builder);
    335 
    336     // Too lazy to check things individually.  Don't try to debug this
    337     // if testPrintExotic() is failing.
    338     assertEquals(canonicalExoticText, builder.build().toString());
    339   }
    340 
    341   public void testParseMessageSet() throws Exception {
    342     ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance();
    343     extensionRegistry.add(TestMessageSetExtension1.messageSetExtension);
    344     extensionRegistry.add(TestMessageSetExtension2.messageSetExtension);
    345 
    346     TestMessageSet.Builder builder = TestMessageSet.newBuilder();
    347     TextFormat.merge(messageSetText, extensionRegistry, builder);
    348     TestMessageSet messageSet = builder.build();
    349 
    350     assertTrue(messageSet.hasExtension(
    351       TestMessageSetExtension1.messageSetExtension));
    352     assertEquals(123, messageSet.getExtension(
    353       TestMessageSetExtension1.messageSetExtension).getI());
    354     assertTrue(messageSet.hasExtension(
    355       TestMessageSetExtension2.messageSetExtension));
    356     assertEquals("foo", messageSet.getExtension(
    357       TestMessageSetExtension2.messageSetExtension).getStr());
    358   }
    359 
    360   public void testParseNumericEnum() throws Exception {
    361     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
    362     TextFormat.merge("optional_nested_enum: 2", builder);
    363     assertEquals(TestAllTypes.NestedEnum.BAR, builder.getOptionalNestedEnum());
    364   }
    365 
    366   public void testParseAngleBrackets() throws Exception {
    367     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
    368     TextFormat.merge("OptionalGroup: < a: 1 >", builder);
    369     assertTrue(builder.hasOptionalGroup());
    370     assertEquals(1, builder.getOptionalGroup().getA());
    371   }
    372 
    373   public void testParseComment() throws Exception {
    374     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
    375     TextFormat.merge(
    376       "# this is a comment\n" +
    377       "optional_int32: 1  # another comment\n" +
    378       "optional_int64: 2\n" +
    379       "# EOF comment", builder);
    380     assertEquals(1, builder.getOptionalInt32());
    381     assertEquals(2, builder.getOptionalInt64());
    382   }
    383 
    384   private void assertParseError(String error, String text) {
    385     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
    386     try {
    387       TextFormat.merge(text, TestUtil.getExtensionRegistry(), builder);
    388       fail("Expected parse exception.");
    389     } catch (TextFormat.ParseException e) {
    390       assertEquals(error, e.getMessage());
    391     }
    392   }
    393 
    394   public void testParseErrors() throws Exception {
    395     assertParseError(
    396       "1:16: Expected \":\".",
    397       "optional_int32 123");
    398     assertParseError(
    399       "1:23: Expected identifier.",
    400       "optional_nested_enum: ?");
    401     assertParseError(
    402       "1:18: Couldn't parse integer: Number must be positive: -1",
    403       "optional_uint32: -1");
    404     assertParseError(
    405       "1:17: Couldn't parse integer: Number out of range for 32-bit signed " +
    406         "integer: 82301481290849012385230157",
    407       "optional_int32: 82301481290849012385230157");
    408     assertParseError(
    409       "1:16: Expected \"true\" or \"false\".",
    410       "optional_bool: maybe");
    411     assertParseError(
    412       "1:18: Expected string.",
    413       "optional_string: 123");
    414     assertParseError(
    415       "1:18: String missing ending quote.",
    416       "optional_string: \"ueoauaoe");
    417     assertParseError(
    418       "1:18: String missing ending quote.",
    419       "optional_string: \"ueoauaoe\n" +
    420       "optional_int32: 123");
    421     assertParseError(
    422       "1:18: Invalid escape sequence: '\\z'",
    423       "optional_string: \"\\z\"");
    424     assertParseError(
    425       "1:18: String missing ending quote.",
    426       "optional_string: \"ueoauaoe\n" +
    427       "optional_int32: 123");
    428     assertParseError(
    429       "1:2: Extension \"nosuchext\" not found in the ExtensionRegistry.",
    430       "[nosuchext]: 123");
    431     assertParseError(
    432       "1:20: Extension \"protobuf_unittest.optional_int32_extension\" does " +
    433         "not extend message type \"protobuf_unittest.TestAllTypes\".",
    434       "[protobuf_unittest.optional_int32_extension]: 123");
    435     assertParseError(
    436       "1:1: Message type \"protobuf_unittest.TestAllTypes\" has no field " +
    437         "named \"nosuchfield\".",
    438       "nosuchfield: 123");
    439     assertParseError(
    440       "1:21: Expected \">\".",
    441       "OptionalGroup < a: 1");
    442     assertParseError(
    443       "1:23: Enum type \"protobuf_unittest.TestAllTypes.NestedEnum\" has no " +
    444         "value named \"NO_SUCH_VALUE\".",
    445       "optional_nested_enum: NO_SUCH_VALUE");
    446     assertParseError(
    447       "1:23: Enum type \"protobuf_unittest.TestAllTypes.NestedEnum\" has no " +
    448         "value with number 123.",
    449       "optional_nested_enum: 123");
    450 
    451     // Delimiters must match.
    452     assertParseError(
    453       "1:22: Expected identifier.",
    454       "OptionalGroup < a: 1 }");
    455     assertParseError(
    456       "1:22: Expected identifier.",
    457       "OptionalGroup { a: 1 >");
    458   }
    459 
    460   // =================================================================
    461 
    462   public void testEscape() throws Exception {
    463     // Escape sequences.
    464     assertEquals("\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\"",
    465       TextFormat.escapeBytes(bytes("\0\001\007\b\f\n\r\t\013\\\'\"")));
    466     assertEquals("\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\"",
    467       TextFormat.escapeText("\0\001\007\b\f\n\r\t\013\\\'\""));
    468     assertEquals(bytes("\0\001\007\b\f\n\r\t\013\\\'\""),
    469       TextFormat.unescapeBytes("\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\""));
    470     assertEquals("\0\001\007\b\f\n\r\t\013\\\'\"",
    471       TextFormat.unescapeText("\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\""));
    472 
    473     // Unicode handling.
    474     assertEquals("\\341\\210\\264", TextFormat.escapeText("\u1234"));
    475     assertEquals("\\341\\210\\264",
    476                  TextFormat.escapeBytes(bytes(0xe1, 0x88, 0xb4)));
    477     assertEquals("\u1234", TextFormat.unescapeText("\\341\\210\\264"));
    478     assertEquals(bytes(0xe1, 0x88, 0xb4),
    479                  TextFormat.unescapeBytes("\\341\\210\\264"));
    480     assertEquals("\u1234", TextFormat.unescapeText("\\xe1\\x88\\xb4"));
    481     assertEquals(bytes(0xe1, 0x88, 0xb4),
    482                  TextFormat.unescapeBytes("\\xe1\\x88\\xb4"));
    483 
    484     // Errors.
    485     try {
    486       TextFormat.unescapeText("\\x");
    487       fail("Should have thrown an exception.");
    488     } catch (TextFormat.InvalidEscapeSequenceException e) {
    489       // success
    490     }
    491 
    492     try {
    493       TextFormat.unescapeText("\\z");
    494       fail("Should have thrown an exception.");
    495     } catch (TextFormat.InvalidEscapeSequenceException e) {
    496       // success
    497     }
    498 
    499     try {
    500       TextFormat.unescapeText("\\");
    501       fail("Should have thrown an exception.");
    502     } catch (TextFormat.InvalidEscapeSequenceException e) {
    503       // success
    504     }
    505   }
    506 
    507   public void testParseInteger() throws Exception {
    508     assertEquals(          0, TextFormat.parseInt32(          "0"));
    509     assertEquals(          1, TextFormat.parseInt32(          "1"));
    510     assertEquals(         -1, TextFormat.parseInt32(         "-1"));
    511     assertEquals(      12345, TextFormat.parseInt32(      "12345"));
    512     assertEquals(     -12345, TextFormat.parseInt32(     "-12345"));
    513     assertEquals( 2147483647, TextFormat.parseInt32( "2147483647"));
    514     assertEquals(-2147483648, TextFormat.parseInt32("-2147483648"));
    515 
    516     assertEquals(                0, TextFormat.parseUInt32(         "0"));
    517     assertEquals(                1, TextFormat.parseUInt32(         "1"));
    518     assertEquals(            12345, TextFormat.parseUInt32(     "12345"));
    519     assertEquals(       2147483647, TextFormat.parseUInt32("2147483647"));
    520     assertEquals((int) 2147483648L, TextFormat.parseUInt32("2147483648"));
    521     assertEquals((int) 4294967295L, TextFormat.parseUInt32("4294967295"));
    522 
    523     assertEquals(          0L, TextFormat.parseInt64(          "0"));
    524     assertEquals(          1L, TextFormat.parseInt64(          "1"));
    525     assertEquals(         -1L, TextFormat.parseInt64(         "-1"));
    526     assertEquals(      12345L, TextFormat.parseInt64(      "12345"));
    527     assertEquals(     -12345L, TextFormat.parseInt64(     "-12345"));
    528     assertEquals( 2147483647L, TextFormat.parseInt64( "2147483647"));
    529     assertEquals(-2147483648L, TextFormat.parseInt64("-2147483648"));
    530     assertEquals( 4294967295L, TextFormat.parseInt64( "4294967295"));
    531     assertEquals( 4294967296L, TextFormat.parseInt64( "4294967296"));
    532     assertEquals(9223372036854775807L,
    533                  TextFormat.parseInt64("9223372036854775807"));
    534     assertEquals(-9223372036854775808L,
    535                  TextFormat.parseInt64("-9223372036854775808"));
    536 
    537     assertEquals(          0L, TextFormat.parseUInt64(          "0"));
    538     assertEquals(          1L, TextFormat.parseUInt64(          "1"));
    539     assertEquals(      12345L, TextFormat.parseUInt64(      "12345"));
    540     assertEquals( 2147483647L, TextFormat.parseUInt64( "2147483647"));
    541     assertEquals( 4294967295L, TextFormat.parseUInt64( "4294967295"));
    542     assertEquals( 4294967296L, TextFormat.parseUInt64( "4294967296"));
    543     assertEquals(9223372036854775807L,
    544                  TextFormat.parseUInt64("9223372036854775807"));
    545     assertEquals(-9223372036854775808L,
    546                  TextFormat.parseUInt64("9223372036854775808"));
    547     assertEquals(-1L, TextFormat.parseUInt64("18446744073709551615"));
    548 
    549     // Hex
    550     assertEquals(0x1234abcd, TextFormat.parseInt32("0x1234abcd"));
    551     assertEquals(-0x1234abcd, TextFormat.parseInt32("-0x1234abcd"));
    552     assertEquals(-1, TextFormat.parseUInt64("0xffffffffffffffff"));
    553     assertEquals(0x7fffffffffffffffL,
    554                  TextFormat.parseInt64("0x7fffffffffffffff"));
    555 
    556     // Octal
    557     assertEquals(01234567, TextFormat.parseInt32("01234567"));
    558 
    559     // Out-of-range
    560     try {
    561       TextFormat.parseInt32("2147483648");
    562       fail("Should have thrown an exception.");
    563     } catch (NumberFormatException e) {
    564       // success
    565     }
    566 
    567     try {
    568       TextFormat.parseInt32("-2147483649");
    569       fail("Should have thrown an exception.");
    570     } catch (NumberFormatException e) {
    571       // success
    572     }
    573 
    574     try {
    575       TextFormat.parseUInt32("4294967296");
    576       fail("Should have thrown an exception.");
    577     } catch (NumberFormatException e) {
    578       // success
    579     }
    580 
    581     try {
    582       TextFormat.parseUInt32("-1");
    583       fail("Should have thrown an exception.");
    584     } catch (NumberFormatException e) {
    585       // success
    586     }
    587 
    588     try {
    589       TextFormat.parseInt64("9223372036854775808");
    590       fail("Should have thrown an exception.");
    591     } catch (NumberFormatException e) {
    592       // success
    593     }
    594 
    595     try {
    596       TextFormat.parseInt64("-9223372036854775809");
    597       fail("Should have thrown an exception.");
    598     } catch (NumberFormatException e) {
    599       // success
    600     }
    601 
    602     try {
    603       TextFormat.parseUInt64("18446744073709551616");
    604       fail("Should have thrown an exception.");
    605     } catch (NumberFormatException e) {
    606       // success
    607     }
    608 
    609     try {
    610       TextFormat.parseUInt64("-1");
    611       fail("Should have thrown an exception.");
    612     } catch (NumberFormatException e) {
    613       // success
    614     }
    615 
    616     // Not a number.
    617     try {
    618       TextFormat.parseInt32("abcd");
    619       fail("Should have thrown an exception.");
    620     } catch (NumberFormatException e) {
    621       // success
    622     }
    623   }
    624 
    625   public void testParseLongString() throws Exception {
    626     String longText =
    627       "123456789012345678901234567890123456789012345678901234567890" +
    628       "123456789012345678901234567890123456789012345678901234567890" +
    629       "123456789012345678901234567890123456789012345678901234567890" +
    630       "123456789012345678901234567890123456789012345678901234567890" +
    631       "123456789012345678901234567890123456789012345678901234567890" +
    632       "123456789012345678901234567890123456789012345678901234567890" +
    633       "123456789012345678901234567890123456789012345678901234567890" +
    634       "123456789012345678901234567890123456789012345678901234567890" +
    635       "123456789012345678901234567890123456789012345678901234567890" +
    636       "123456789012345678901234567890123456789012345678901234567890" +
    637       "123456789012345678901234567890123456789012345678901234567890" +
    638       "123456789012345678901234567890123456789012345678901234567890" +
    639       "123456789012345678901234567890123456789012345678901234567890" +
    640       "123456789012345678901234567890123456789012345678901234567890" +
    641       "123456789012345678901234567890123456789012345678901234567890" +
    642       "123456789012345678901234567890123456789012345678901234567890" +
    643       "123456789012345678901234567890123456789012345678901234567890" +
    644       "123456789012345678901234567890123456789012345678901234567890" +
    645       "123456789012345678901234567890123456789012345678901234567890" +
    646       "123456789012345678901234567890123456789012345678901234567890";
    647 
    648     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
    649     TextFormat.merge("optional_string: \"" + longText + "\"", builder);
    650     assertEquals(longText, builder.getOptionalString());
    651   }
    652 
    653   public void testParseAdjacentStringLiterals() throws Exception {
    654     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
    655     TextFormat.merge("optional_string: \"foo\" 'corge' \"grault\"", builder);
    656     assertEquals("foocorgegrault", builder.getOptionalString());
    657   }
    658 }
    659