1 // Protocol Buffers - Google's data interchange format 2 // Copyright 2008 Google Inc. All rights reserved. 3 // https://developers.google.com/protocol-buffers/ 4 // 5 // Redistribution and use in source and binary forms, with or without 6 // modification, are permitted provided that the following conditions are 7 // met: 8 // 9 // * Redistributions of source code must retain the above copyright 10 // notice, this list of conditions and the following disclaimer. 11 // * Redistributions in binary form must reproduce the above 12 // copyright notice, this list of conditions and the following disclaimer 13 // in the documentation and/or other materials provided with the 14 // distribution. 15 // * Neither the name of Google Inc. nor the names of its 16 // contributors may be used to endorse or promote products derived from 17 // this software without specific prior written permission. 18 // 19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 31 package com.google.protobuf; 32 33 import static com.google.protobuf.TestUtil.TEST_REQUIRED_INITIALIZED; 34 import static com.google.protobuf.TestUtil.TEST_REQUIRED_UNINITIALIZED; 35 36 import com.google.protobuf.Descriptors.FieldDescriptor; 37 import protobuf_unittest.UnittestOptimizeFor.TestOptimizedForSize; 38 import protobuf_unittest.UnittestProto; 39 import protobuf_unittest.UnittestProto.ForeignMessage; 40 import protobuf_unittest.UnittestProto.TestAllExtensions; 41 import protobuf_unittest.UnittestProto.TestAllTypes; 42 import protobuf_unittest.UnittestProto.TestPackedTypes; 43 import protobuf_unittest.UnittestProto.TestRequired; 44 import protobuf_unittest.UnittestProto.TestRequiredForeign; 45 import protobuf_unittest.UnittestProto.TestUnpackedTypes; 46 import java.util.Map; 47 import junit.framework.TestCase; 48 49 /** 50 * Unit test for {@link AbstractMessage}. 51 * 52 * @author kenton@google.com Kenton Varda 53 */ 54 public class AbstractMessageTest extends TestCase { 55 /** 56 * Extends AbstractMessage and wraps some other message object. The methods of the Message 57 * interface which aren't explicitly implemented by AbstractMessage are forwarded to the wrapped 58 * object. This allows us to test that AbstractMessage's implementations work even if the wrapped 59 * object does not use them. 60 */ 61 private static class AbstractMessageWrapper extends AbstractMessage { 62 private final Message wrappedMessage; 63 AbstractMessageWrapper(Message wrappedMessage)64 public AbstractMessageWrapper(Message wrappedMessage) { 65 this.wrappedMessage = wrappedMessage; 66 } 67 68 @Override getDescriptorForType()69 public Descriptors.Descriptor getDescriptorForType() { 70 return wrappedMessage.getDescriptorForType(); 71 } 72 73 @Override getDefaultInstanceForType()74 public AbstractMessageWrapper getDefaultInstanceForType() { 75 return new AbstractMessageWrapper(wrappedMessage.getDefaultInstanceForType()); 76 } 77 78 @Override getAllFields()79 public Map<Descriptors.FieldDescriptor, Object> getAllFields() { 80 return wrappedMessage.getAllFields(); 81 } 82 83 @Override hasField(Descriptors.FieldDescriptor field)84 public boolean hasField(Descriptors.FieldDescriptor field) { 85 return wrappedMessage.hasField(field); 86 } 87 88 @Override getField(Descriptors.FieldDescriptor field)89 public Object getField(Descriptors.FieldDescriptor field) { 90 return wrappedMessage.getField(field); 91 } 92 93 @Override getRepeatedFieldCount(Descriptors.FieldDescriptor field)94 public int getRepeatedFieldCount(Descriptors.FieldDescriptor field) { 95 return wrappedMessage.getRepeatedFieldCount(field); 96 } 97 98 @Override getRepeatedField(Descriptors.FieldDescriptor field, int index)99 public Object getRepeatedField(Descriptors.FieldDescriptor field, int index) { 100 return wrappedMessage.getRepeatedField(field, index); 101 } 102 103 @Override getUnknownFields()104 public UnknownFieldSet getUnknownFields() { 105 return wrappedMessage.getUnknownFields(); 106 } 107 108 @Override newBuilderForType()109 public Builder newBuilderForType() { 110 return new Builder(wrappedMessage.newBuilderForType()); 111 } 112 113 @Override toBuilder()114 public Builder toBuilder() { 115 return new Builder(wrappedMessage.toBuilder()); 116 } 117 118 static class Builder extends AbstractMessage.Builder<Builder> { 119 private final Message.Builder wrappedBuilder; 120 Builder(Message.Builder wrappedBuilder)121 public Builder(Message.Builder wrappedBuilder) { 122 this.wrappedBuilder = wrappedBuilder; 123 } 124 125 @Override build()126 public AbstractMessageWrapper build() { 127 return new AbstractMessageWrapper(wrappedBuilder.build()); 128 } 129 130 @Override buildPartial()131 public AbstractMessageWrapper buildPartial() { 132 return new AbstractMessageWrapper(wrappedBuilder.buildPartial()); 133 } 134 135 @Override clone()136 public Builder clone() { 137 return new Builder(wrappedBuilder.clone()); 138 } 139 140 @Override isInitialized()141 public boolean isInitialized() { 142 return clone().buildPartial().isInitialized(); 143 } 144 145 @Override getDescriptorForType()146 public Descriptors.Descriptor getDescriptorForType() { 147 return wrappedBuilder.getDescriptorForType(); 148 } 149 150 @Override getDefaultInstanceForType()151 public AbstractMessageWrapper getDefaultInstanceForType() { 152 return new AbstractMessageWrapper(wrappedBuilder.getDefaultInstanceForType()); 153 } 154 155 @Override getAllFields()156 public Map<Descriptors.FieldDescriptor, Object> getAllFields() { 157 return wrappedBuilder.getAllFields(); 158 } 159 160 @Override newBuilderForField(Descriptors.FieldDescriptor field)161 public Builder newBuilderForField(Descriptors.FieldDescriptor field) { 162 return new Builder(wrappedBuilder.newBuilderForField(field)); 163 } 164 165 @Override hasField(Descriptors.FieldDescriptor field)166 public boolean hasField(Descriptors.FieldDescriptor field) { 167 return wrappedBuilder.hasField(field); 168 } 169 170 @Override getField(Descriptors.FieldDescriptor field)171 public Object getField(Descriptors.FieldDescriptor field) { 172 return wrappedBuilder.getField(field); 173 } 174 175 @Override setField(Descriptors.FieldDescriptor field, Object value)176 public Builder setField(Descriptors.FieldDescriptor field, Object value) { 177 wrappedBuilder.setField(field, value); 178 return this; 179 } 180 181 @Override clearField(Descriptors.FieldDescriptor field)182 public Builder clearField(Descriptors.FieldDescriptor field) { 183 wrappedBuilder.clearField(field); 184 return this; 185 } 186 187 @Override getRepeatedFieldCount(Descriptors.FieldDescriptor field)188 public int getRepeatedFieldCount(Descriptors.FieldDescriptor field) { 189 return wrappedBuilder.getRepeatedFieldCount(field); 190 } 191 192 @Override getRepeatedField(Descriptors.FieldDescriptor field, int index)193 public Object getRepeatedField(Descriptors.FieldDescriptor field, int index) { 194 return wrappedBuilder.getRepeatedField(field, index); 195 } 196 197 @Override setRepeatedField(Descriptors.FieldDescriptor field, int index, Object value)198 public Builder setRepeatedField(Descriptors.FieldDescriptor field, int index, Object value) { 199 wrappedBuilder.setRepeatedField(field, index, value); 200 return this; 201 } 202 203 @Override addRepeatedField(Descriptors.FieldDescriptor field, Object value)204 public Builder addRepeatedField(Descriptors.FieldDescriptor field, Object value) { 205 wrappedBuilder.addRepeatedField(field, value); 206 return this; 207 } 208 209 @Override getUnknownFields()210 public UnknownFieldSet getUnknownFields() { 211 return wrappedBuilder.getUnknownFields(); 212 } 213 214 @Override setUnknownFields(UnknownFieldSet unknownFields)215 public Builder setUnknownFields(UnknownFieldSet unknownFields) { 216 wrappedBuilder.setUnknownFields(unknownFields); 217 return this; 218 } 219 220 @Override getFieldBuilder(FieldDescriptor field)221 public Message.Builder getFieldBuilder(FieldDescriptor field) { 222 return wrappedBuilder.getFieldBuilder(field); 223 } 224 } 225 226 @Override getParserForType()227 public Parser<? extends Message> getParserForType() { 228 return wrappedMessage.getParserForType(); 229 } 230 } 231 232 // ================================================================= 233 234 TestUtil.ReflectionTester reflectionTester = 235 new TestUtil.ReflectionTester(TestAllTypes.getDescriptor(), null); 236 237 TestUtil.ReflectionTester extensionsReflectionTester = 238 new TestUtil.ReflectionTester( 239 TestAllExtensions.getDescriptor(), TestUtil.getFullExtensionRegistry()); 240 testClear()241 public void testClear() throws Exception { 242 AbstractMessageWrapper message = 243 new AbstractMessageWrapper.Builder(TestAllTypes.newBuilder(TestUtil.getAllSet())) 244 .clear() 245 .build(); 246 TestUtil.assertClear((TestAllTypes) message.wrappedMessage); 247 } 248 testCopy()249 public void testCopy() throws Exception { 250 AbstractMessageWrapper message = 251 new AbstractMessageWrapper.Builder(TestAllTypes.newBuilder()) 252 .mergeFrom(TestUtil.getAllSet()) 253 .build(); 254 TestUtil.assertAllFieldsSet((TestAllTypes) message.wrappedMessage); 255 } 256 testSerializedSize()257 public void testSerializedSize() throws Exception { 258 TestAllTypes message = TestUtil.getAllSet(); 259 Message abstractMessage = new AbstractMessageWrapper(TestUtil.getAllSet()); 260 261 assertEquals(message.getSerializedSize(), abstractMessage.getSerializedSize()); 262 } 263 testSerialization()264 public void testSerialization() throws Exception { 265 Message abstractMessage = new AbstractMessageWrapper(TestUtil.getAllSet()); 266 267 TestUtil.assertAllFieldsSet(TestAllTypes.parseFrom(abstractMessage.toByteString())); 268 269 assertEquals(TestUtil.getAllSet().toByteString(), abstractMessage.toByteString()); 270 } 271 testParsing()272 public void testParsing() throws Exception { 273 AbstractMessageWrapper.Builder builder = 274 new AbstractMessageWrapper.Builder(TestAllTypes.newBuilder()); 275 AbstractMessageWrapper message = builder.mergeFrom(TestUtil.getAllSet().toByteString()).build(); 276 TestUtil.assertAllFieldsSet((TestAllTypes) message.wrappedMessage); 277 } 278 testParsingUninitialized()279 public void testParsingUninitialized() throws Exception { 280 TestRequiredForeign.Builder builder = TestRequiredForeign.newBuilder(); 281 builder.getOptionalMessageBuilder().setDummy2(10); 282 ByteString bytes = builder.buildPartial().toByteString(); 283 Message.Builder abstractMessageBuilder = 284 new AbstractMessageWrapper.Builder(TestRequiredForeign.newBuilder()); 285 // mergeFrom() should not throw initialization error. 286 abstractMessageBuilder.mergeFrom(bytes).buildPartial(); 287 try { 288 abstractMessageBuilder.mergeFrom(bytes).build(); 289 fail(); 290 } catch (UninitializedMessageException ex) { 291 // pass 292 } 293 294 // test DynamicMessage directly. 295 Message.Builder dynamicMessageBuilder = 296 DynamicMessage.newBuilder(TestRequiredForeign.getDescriptor()); 297 // mergeFrom() should not throw initialization error. 298 dynamicMessageBuilder.mergeFrom(bytes).buildPartial(); 299 try { 300 dynamicMessageBuilder.mergeFrom(bytes).build(); 301 fail(); 302 } catch (UninitializedMessageException ex) { 303 // pass 304 } 305 } 306 testPackedSerialization()307 public void testPackedSerialization() throws Exception { 308 Message abstractMessage = new AbstractMessageWrapper(TestUtil.getPackedSet()); 309 310 TestUtil.assertPackedFieldsSet(TestPackedTypes.parseFrom(abstractMessage.toByteString())); 311 312 assertEquals(TestUtil.getPackedSet().toByteString(), abstractMessage.toByteString()); 313 } 314 testPackedParsing()315 public void testPackedParsing() throws Exception { 316 AbstractMessageWrapper.Builder builder = 317 new AbstractMessageWrapper.Builder(TestPackedTypes.newBuilder()); 318 AbstractMessageWrapper message = 319 builder.mergeFrom(TestUtil.getPackedSet().toByteString()).build(); 320 TestUtil.assertPackedFieldsSet((TestPackedTypes) message.wrappedMessage); 321 } 322 testUnpackedSerialization()323 public void testUnpackedSerialization() throws Exception { 324 Message abstractMessage = new AbstractMessageWrapper(TestUtil.getUnpackedSet()); 325 326 TestUtil.assertUnpackedFieldsSet(TestUnpackedTypes.parseFrom(abstractMessage.toByteString())); 327 328 assertEquals(TestUtil.getUnpackedSet().toByteString(), abstractMessage.toByteString()); 329 } 330 testParsePackedToUnpacked()331 public void testParsePackedToUnpacked() throws Exception { 332 AbstractMessageWrapper.Builder builder = 333 new AbstractMessageWrapper.Builder(TestUnpackedTypes.newBuilder()); 334 AbstractMessageWrapper message = 335 builder.mergeFrom(TestUtil.getPackedSet().toByteString()).build(); 336 TestUtil.assertUnpackedFieldsSet((TestUnpackedTypes) message.wrappedMessage); 337 } 338 testParseUnpackedToPacked()339 public void testParseUnpackedToPacked() throws Exception { 340 AbstractMessageWrapper.Builder builder = 341 new AbstractMessageWrapper.Builder(TestPackedTypes.newBuilder()); 342 AbstractMessageWrapper message = 343 builder.mergeFrom(TestUtil.getUnpackedSet().toByteString()).build(); 344 TestUtil.assertPackedFieldsSet((TestPackedTypes) message.wrappedMessage); 345 } 346 testUnpackedParsing()347 public void testUnpackedParsing() throws Exception { 348 AbstractMessageWrapper.Builder builder = 349 new AbstractMessageWrapper.Builder(TestUnpackedTypes.newBuilder()); 350 AbstractMessageWrapper message = 351 builder.mergeFrom(TestUtil.getUnpackedSet().toByteString()).build(); 352 TestUtil.assertUnpackedFieldsSet((TestUnpackedTypes) message.wrappedMessage); 353 } 354 testOptimizedForSize()355 public void testOptimizedForSize() throws Exception { 356 // We're mostly only checking that this class was compiled successfully. 357 TestOptimizedForSize message = TestOptimizedForSize.newBuilder().setI(1).build(); 358 message = TestOptimizedForSize.parseFrom(message.toByteString()); 359 assertEquals(2, message.getSerializedSize()); 360 } 361 362 // ----------------------------------------------------------------- 363 // Tests for isInitialized(). 364 testIsInitialized()365 public void testIsInitialized() throws Exception { 366 TestRequired.Builder builder = TestRequired.newBuilder(); 367 AbstractMessageWrapper.Builder abstractBuilder = new AbstractMessageWrapper.Builder(builder); 368 369 assertFalse(abstractBuilder.isInitialized()); 370 assertEquals("a, b, c", abstractBuilder.getInitializationErrorString()); 371 builder.setA(1); 372 assertFalse(abstractBuilder.isInitialized()); 373 assertEquals("b, c", abstractBuilder.getInitializationErrorString()); 374 builder.setB(1); 375 assertFalse(abstractBuilder.isInitialized()); 376 assertEquals("c", abstractBuilder.getInitializationErrorString()); 377 builder.setC(1); 378 assertTrue(abstractBuilder.isInitialized()); 379 assertEquals("", abstractBuilder.getInitializationErrorString()); 380 } 381 testForeignIsInitialized()382 public void testForeignIsInitialized() throws Exception { 383 TestRequiredForeign.Builder builder = TestRequiredForeign.newBuilder(); 384 AbstractMessageWrapper.Builder abstractBuilder = new AbstractMessageWrapper.Builder(builder); 385 386 assertTrue(abstractBuilder.isInitialized()); 387 assertEquals("", abstractBuilder.getInitializationErrorString()); 388 389 builder.setOptionalMessage(TEST_REQUIRED_UNINITIALIZED); 390 assertFalse(abstractBuilder.isInitialized()); 391 assertEquals( 392 "optional_message.b, optional_message.c", abstractBuilder.getInitializationErrorString()); 393 394 builder.setOptionalMessage(TEST_REQUIRED_INITIALIZED); 395 assertTrue(abstractBuilder.isInitialized()); 396 assertEquals("", abstractBuilder.getInitializationErrorString()); 397 398 builder.addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED); 399 assertFalse(abstractBuilder.isInitialized()); 400 assertEquals( 401 "repeated_message[0].b, repeated_message[0].c", 402 abstractBuilder.getInitializationErrorString()); 403 404 builder.setRepeatedMessage(0, TEST_REQUIRED_INITIALIZED); 405 assertTrue(abstractBuilder.isInitialized()); 406 assertEquals("", abstractBuilder.getInitializationErrorString()); 407 } 408 409 // ----------------------------------------------------------------- 410 // Tests for mergeFrom 411 412 static final TestAllTypes MERGE_SOURCE = 413 TestAllTypes.newBuilder() 414 .setOptionalInt32(1) 415 .setOptionalString("foo") 416 .setOptionalForeignMessage(ForeignMessage.getDefaultInstance()) 417 .addRepeatedString("bar") 418 .build(); 419 420 static final TestAllTypes MERGE_DEST = 421 TestAllTypes.newBuilder() 422 .setOptionalInt64(2) 423 .setOptionalString("baz") 424 .setOptionalForeignMessage(ForeignMessage.newBuilder().setC(3).build()) 425 .addRepeatedString("qux") 426 .build(); 427 428 static final String MERGE_RESULT_TEXT = 429 "" 430 + "optional_int32: 1\n" 431 + "optional_int64: 2\n" 432 + "optional_string: \"foo\"\n" 433 + "optional_foreign_message {\n" 434 + " c: 3\n" 435 + "}\n" 436 + "repeated_string: \"qux\"\n" 437 + "repeated_string: \"bar\"\n"; 438 testMergeFrom()439 public void testMergeFrom() throws Exception { 440 AbstractMessageWrapper result = 441 new AbstractMessageWrapper.Builder(TestAllTypes.newBuilder(MERGE_DEST)) 442 .mergeFrom(MERGE_SOURCE) 443 .build(); 444 445 assertEquals(MERGE_RESULT_TEXT, result.toString()); 446 } 447 448 // ----------------------------------------------------------------- 449 // Tests for equals and hashCode 450 testEqualsAndHashCode()451 public void testEqualsAndHashCode() throws Exception { 452 TestAllTypes a = TestUtil.getAllSet(); 453 TestAllTypes b = TestAllTypes.newBuilder().build(); 454 TestAllTypes c = TestAllTypes.newBuilder(b).addRepeatedString("x").build(); 455 TestAllTypes d = TestAllTypes.newBuilder(c).addRepeatedString("y").build(); 456 TestAllExtensions e = TestUtil.getAllExtensionsSet(); 457 TestAllExtensions f = 458 TestAllExtensions.newBuilder(e) 459 .addExtension(UnittestProto.repeatedInt32Extension, 999) 460 .build(); 461 462 checkEqualsIsConsistent(a); 463 checkEqualsIsConsistent(b); 464 checkEqualsIsConsistent(c); 465 checkEqualsIsConsistent(d); 466 checkEqualsIsConsistent(e); 467 checkEqualsIsConsistent(f); 468 469 checkNotEqual(a, b); 470 checkNotEqual(a, c); 471 checkNotEqual(a, d); 472 checkNotEqual(a, e); 473 checkNotEqual(a, f); 474 475 checkNotEqual(b, c); 476 checkNotEqual(b, d); 477 checkNotEqual(b, e); 478 checkNotEqual(b, f); 479 480 checkNotEqual(c, d); 481 checkNotEqual(c, e); 482 checkNotEqual(c, f); 483 484 checkNotEqual(d, e); 485 checkNotEqual(d, f); 486 487 checkNotEqual(e, f); 488 489 // Deserializing into the TestEmptyMessage such that every field 490 // is an {@link UnknownFieldSet.Field}. 491 UnittestProto.TestEmptyMessage eUnknownFields = 492 UnittestProto.TestEmptyMessage.parseFrom(e.toByteArray()); 493 UnittestProto.TestEmptyMessage fUnknownFields = 494 UnittestProto.TestEmptyMessage.parseFrom(f.toByteArray()); 495 checkNotEqual(eUnknownFields, fUnknownFields); 496 checkEqualsIsConsistent(eUnknownFields); 497 checkEqualsIsConsistent(fUnknownFields); 498 499 // Subsequent reconstitutions should be identical 500 UnittestProto.TestEmptyMessage eUnknownFields2 = 501 UnittestProto.TestEmptyMessage.parseFrom(e.toByteArray()); 502 checkEqualsIsConsistent(eUnknownFields, eUnknownFields2); 503 } 504 505 /** Asserts that the given proto has symmetric equals and hashCode methods. */ checkEqualsIsConsistent(Message message)506 private void checkEqualsIsConsistent(Message message) { 507 // Object should be equal to itself. 508 assertEquals(message, message); 509 510 // Object should be equal to a dynamic copy of itself. 511 DynamicMessage dynamic = DynamicMessage.newBuilder(message).build(); 512 checkEqualsIsConsistent(message, dynamic); 513 } 514 515 /** Asserts that the given protos are equal and have the same hash code. */ checkEqualsIsConsistent(Message message1, Message message2)516 private void checkEqualsIsConsistent(Message message1, Message message2) { 517 assertEquals(message1, message2); 518 assertEquals(message2, message1); 519 assertEquals(message2.hashCode(), message1.hashCode()); 520 } 521 522 /** 523 * Asserts that the given protos are not equal and have different hash codes. 524 * 525 * <p><b>Note:</b> It's valid for non-equal objects to have the same hash code, so this test is 526 * stricter than it needs to be. However, this should happen relatively rarely. 527 */ checkNotEqual(Message m1, Message m2)528 private void checkNotEqual(Message m1, Message m2) { 529 String equalsError = String.format("%s should not be equal to %s", m1, m2); 530 assertFalse(equalsError, m1.equals(m2)); 531 assertFalse(equalsError, m2.equals(m1)); 532 533 assertFalse( 534 String.format("%s should have a different hash code from %s", m1, m2), 535 m1.hashCode() == m2.hashCode()); 536 } 537 testCheckByteStringIsUtf8OnUtf8()538 public void testCheckByteStringIsUtf8OnUtf8() { 539 ByteString byteString = ByteString.copyFromUtf8("some text"); 540 AbstractMessageLite.checkByteStringIsUtf8(byteString); 541 // No exception thrown. 542 } 543 testCheckByteStringIsUtf8OnNonUtf8()544 public void testCheckByteStringIsUtf8OnNonUtf8() { 545 ByteString byteString = 546 ByteString.copyFrom(new byte[] {(byte) 0x80}); // A lone continuation byte. 547 try { 548 AbstractMessageLite.checkByteStringIsUtf8(byteString); 549 fail("Expected AbstractMessageLite.checkByteStringIsUtf8 to throw IllegalArgumentException"); 550 } catch (IllegalArgumentException exception) { 551 assertEquals("Byte string is not UTF-8.", exception.getMessage()); 552 } 553 } 554 } 555