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