1 /* 2 * Copyright (C) 2014 Square, Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package okio; 17 18 import java.io.EOFException; 19 import java.io.IOException; 20 import java.io.InputStream; 21 import java.nio.charset.Charset; 22 import java.util.Arrays; 23 import java.util.List; 24 import org.junit.Before; 25 import org.junit.Test; 26 import org.junit.runner.RunWith; 27 import org.junit.runners.Parameterized; 28 29 import static okio.TestUtil.assertByteArrayEquals; 30 import static okio.TestUtil.assertByteArraysEquals; 31 import static okio.TestUtil.repeat; 32 import static okio.Util.UTF_8; 33 import static org.junit.Assert.assertEquals; 34 import static org.junit.Assert.assertFalse; 35 import static org.junit.Assert.assertTrue; 36 import static org.junit.Assert.fail; 37 38 @RunWith(Parameterized.class) 39 public class BufferedSourceTest { 40 private static final Factory BUFFER_FACTORY = new Factory() { 41 @Override public Pipe pipe() { 42 Buffer buffer = new Buffer(); 43 Pipe result = new Pipe(); 44 result.sink = buffer; 45 result.source = buffer; 46 return result; 47 } 48 49 @Override public String toString() { 50 return "Buffer"; 51 } 52 }; 53 54 private static final Factory REAL_BUFFERED_SOURCE_FACTORY = new Factory() { 55 @Override public Pipe pipe() { 56 Buffer buffer = new Buffer(); 57 Pipe result = new Pipe(); 58 result.sink = buffer; 59 result.source = new RealBufferedSource(buffer); 60 return result; 61 } 62 63 @Override public String toString() { 64 return "RealBufferedSource"; 65 } 66 }; 67 68 private static final Factory ONE_BYTE_AT_A_TIME_FACTORY = new Factory() { 69 @Override public Pipe pipe() { 70 Buffer buffer = new Buffer(); 71 Pipe result = new Pipe(); 72 result.sink = buffer; 73 result.source = new RealBufferedSource(new ForwardingSource(buffer) { 74 @Override public long read(Buffer sink, long byteCount) throws IOException { 75 return super.read(sink, Math.min(byteCount, 1L)); 76 } 77 }); 78 return result; 79 } 80 81 @Override public String toString() { 82 return "OneByteAtATime"; 83 } 84 }; 85 86 private interface Factory { 87 Pipe pipe(); 88 } 89 90 private static class Pipe { 91 BufferedSink sink; 92 BufferedSource source; 93 } 94 95 // ANDROID-BEGIN 96 // @Parameterized.Parameters(name = "{0}") 97 @Parameterized.Parameters 98 // ANDROID-END 99 public static List<Object[]> parameters() { 100 return Arrays.asList( 101 new Object[] { BUFFER_FACTORY }, 102 new Object[] { REAL_BUFFERED_SOURCE_FACTORY }, 103 new Object[] { ONE_BYTE_AT_A_TIME_FACTORY }); 104 } 105 106 // ANDROID-BEGIN 107 // @Parameterized.Parameter 108 private final Factory factory; 109 public BufferedSourceTest(Factory factory) { 110 this.factory = factory; 111 } 112 // ANDROID-END 113 private BufferedSink sink; 114 private BufferedSource source; 115 116 @Before public void setUp() { 117 Pipe pipe = factory.pipe(); 118 sink = pipe.sink; 119 source = pipe.source; 120 } 121 122 @Test public void readBytes() throws Exception { 123 sink.write(new byte[] { (byte) 0xab, (byte) 0xcd }); 124 assertEquals(0xab, source.readByte() & 0xff); 125 assertEquals(0xcd, source.readByte() & 0xff); 126 assertTrue(source.exhausted()); 127 } 128 129 @Test public void readShort() throws Exception { 130 sink.write(new byte[] { 131 (byte) 0xab, (byte) 0xcd, (byte) 0xef, (byte) 0x01 132 }); 133 assertEquals((short) 0xabcd, source.readShort()); 134 assertEquals((short) 0xef01, source.readShort()); 135 assertTrue(source.exhausted()); 136 } 137 138 @Test public void readShortLe() throws Exception { 139 sink.write(new byte[] { 140 (byte) 0xab, (byte) 0xcd, (byte) 0xef, (byte) 0x10 141 }); 142 assertEquals((short) 0xcdab, source.readShortLe()); 143 assertEquals((short) 0x10ef, source.readShortLe()); 144 assertTrue(source.exhausted()); 145 } 146 147 @Test public void readShortSplitAcrossMultipleSegments() throws Exception { 148 sink.writeUtf8(repeat('a', Segment.SIZE - 1)); 149 sink.write(new byte[] { (byte) 0xab, (byte) 0xcd }); 150 source.skip(Segment.SIZE - 1); 151 assertEquals((short) 0xabcd, source.readShort()); 152 assertTrue(source.exhausted()); 153 } 154 155 @Test public void readInt() throws Exception { 156 sink.write(new byte[] { 157 (byte) 0xab, (byte) 0xcd, (byte) 0xef, (byte) 0x01, (byte) 0x87, (byte) 0x65, (byte) 0x43, 158 (byte) 0x21 159 }); 160 assertEquals(0xabcdef01, source.readInt()); 161 assertEquals(0x87654321, source.readInt()); 162 assertTrue(source.exhausted()); 163 } 164 165 @Test public void readIntLe() throws Exception { 166 sink.write(new byte[] { 167 (byte) 0xab, (byte) 0xcd, (byte) 0xef, (byte) 0x10, (byte) 0x87, (byte) 0x65, (byte) 0x43, 168 (byte) 0x21 169 }); 170 assertEquals(0x10efcdab, source.readIntLe()); 171 assertEquals(0x21436587, source.readIntLe()); 172 assertTrue(source.exhausted()); 173 } 174 175 @Test public void readIntSplitAcrossMultipleSegments() throws Exception { 176 sink.writeUtf8(repeat('a', Segment.SIZE - 3)); 177 sink.write(new byte[] { 178 (byte) 0xab, (byte) 0xcd, (byte) 0xef, (byte) 0x01 179 }); 180 source.skip(Segment.SIZE - 3); 181 assertEquals(0xabcdef01, source.readInt()); 182 assertTrue(source.exhausted()); 183 } 184 185 @Test public void readLong() throws Exception { 186 sink.write(new byte[] { 187 (byte) 0xab, (byte) 0xcd, (byte) 0xef, (byte) 0x10, (byte) 0x87, (byte) 0x65, (byte) 0x43, 188 (byte) 0x21, (byte) 0x36, (byte) 0x47, (byte) 0x58, (byte) 0x69, (byte) 0x12, (byte) 0x23, 189 (byte) 0x34, (byte) 0x45 190 }); 191 assertEquals(0xabcdef1087654321L, source.readLong()); 192 assertEquals(0x3647586912233445L, source.readLong()); 193 assertTrue(source.exhausted()); 194 } 195 196 @Test public void readLongLe() throws Exception { 197 sink.write(new byte[] { 198 (byte) 0xab, (byte) 0xcd, (byte) 0xef, (byte) 0x10, (byte) 0x87, (byte) 0x65, (byte) 0x43, 199 (byte) 0x21, (byte) 0x36, (byte) 0x47, (byte) 0x58, (byte) 0x69, (byte) 0x12, (byte) 0x23, 200 (byte) 0x34, (byte) 0x45 201 }); 202 assertEquals(0x2143658710efcdabL, source.readLongLe()); 203 assertEquals(0x4534231269584736L, source.readLongLe()); 204 assertTrue(source.exhausted()); 205 } 206 207 @Test public void readLongSplitAcrossMultipleSegments() throws Exception { 208 sink.writeUtf8(repeat('a', Segment.SIZE - 7)); 209 sink.write(new byte[] { 210 (byte) 0xab, (byte) 0xcd, (byte) 0xef, (byte) 0x01, (byte) 0x87, (byte) 0x65, (byte) 0x43, 211 (byte) 0x21, 212 }); 213 source.skip(Segment.SIZE - 7); 214 assertEquals(0xabcdef0187654321L, source.readLong()); 215 assertTrue(source.exhausted()); 216 } 217 218 @Test public void readAll() throws IOException { 219 source.buffer().writeUtf8("abc"); 220 sink.writeUtf8("def"); 221 222 Buffer sink = new Buffer(); 223 assertEquals(6, source.readAll(sink)); 224 assertEquals("abcdef", sink.readUtf8()); 225 assertTrue(source.exhausted()); 226 } 227 228 @Test public void readAllExhausted() throws IOException { 229 MockSink mockSink = new MockSink(); 230 assertEquals(0, source.readAll(mockSink)); 231 assertTrue(source.exhausted()); 232 mockSink.assertLog(); 233 } 234 235 @Test public void readExhaustedSource() throws Exception { 236 Buffer sink = new Buffer(); 237 sink.writeUtf8(repeat('a', 10)); 238 assertEquals(-1, source.read(sink, 10)); 239 assertEquals(10, sink.size()); 240 assertTrue(source.exhausted()); 241 } 242 243 @Test public void readZeroBytesFromSource() throws Exception { 244 Buffer sink = new Buffer(); 245 sink.writeUtf8(repeat('a', 10)); 246 247 // Either 0 or -1 is reasonable here. For consistency with Android's 248 // ByteArrayInputStream we return 0. 249 assertEquals(-1, source.read(sink, 0)); 250 assertEquals(10, sink.size()); 251 assertTrue(source.exhausted()); 252 } 253 254 @Test public void readFully() throws Exception { 255 sink.writeUtf8(repeat('a', 10000)); 256 Buffer sink = new Buffer(); 257 source.readFully(sink, 9999); 258 assertEquals(repeat('a', 9999), sink.readUtf8()); 259 assertEquals("a", source.readUtf8()); 260 } 261 262 @Test public void readFullyTooShortThrows() throws IOException { 263 sink.writeUtf8("Hi"); 264 Buffer sink = new Buffer(); 265 try { 266 source.readFully(sink, 5); 267 fail(); 268 } catch (EOFException ignored) { 269 } 270 271 // Verify we read all that we could from the source. 272 assertEquals("Hi", sink.readUtf8()); 273 } 274 275 @Test public void readFullyByteArray() throws IOException { 276 Buffer data = new Buffer(); 277 data.writeUtf8("Hello").writeUtf8(repeat('e', Segment.SIZE)); 278 279 byte[] expected = data.clone().readByteArray(); 280 sink.write(data, data.size()); 281 282 byte[] sink = new byte[Segment.SIZE + 5]; 283 source.readFully(sink); 284 assertByteArraysEquals(expected, sink); 285 } 286 287 @Test public void readFullyByteArrayTooShortThrows() throws IOException { 288 sink.writeUtf8("Hello"); 289 290 byte[] sink = new byte[6]; 291 try { 292 source.readFully(sink); 293 fail(); 294 } catch (EOFException ignored) { 295 } 296 297 // Verify we read all that we could from the source. 298 assertByteArraysEquals(new byte[] { 'H', 'e', 'l', 'l', 'o', 0 }, sink); 299 } 300 301 @Test public void readIntoByteArray() throws IOException { 302 sink.writeUtf8("abcd"); 303 304 byte[] sink = new byte[3]; 305 int read = source.read(sink); 306 if (factory == ONE_BYTE_AT_A_TIME_FACTORY) { 307 assertEquals(1, read); 308 byte[] expected = { 'a', 0, 0 }; 309 assertByteArraysEquals(expected, sink); 310 } else { 311 assertEquals(3, read); 312 byte[] expected = { 'a', 'b', 'c' }; 313 assertByteArraysEquals(expected, sink); 314 } 315 } 316 317 @Test public void readIntoByteArrayNotEnough() throws IOException { 318 sink.writeUtf8("abcd"); 319 320 byte[] sink = new byte[5]; 321 int read = source.read(sink); 322 if (factory == ONE_BYTE_AT_A_TIME_FACTORY) { 323 assertEquals(1, read); 324 byte[] expected = { 'a', 0, 0, 0, 0 }; 325 assertByteArraysEquals(expected, sink); 326 } else { 327 assertEquals(4, read); 328 byte[] expected = { 'a', 'b', 'c', 'd', 0 }; 329 assertByteArraysEquals(expected, sink); 330 } 331 } 332 333 @Test public void readIntoByteArrayOffsetAndCount() throws IOException { 334 sink.writeUtf8("abcd"); 335 336 byte[] sink = new byte[7]; 337 int read = source.read(sink, 2, 3); 338 if (factory == ONE_BYTE_AT_A_TIME_FACTORY) { 339 assertEquals(1, read); 340 byte[] expected = { 0, 0, 'a', 0, 0, 0, 0 }; 341 assertByteArraysEquals(expected, sink); 342 } else { 343 assertEquals(3, read); 344 byte[] expected = { 0, 0, 'a', 'b', 'c', 0, 0 }; 345 assertByteArraysEquals(expected, sink); 346 } 347 } 348 349 @Test public void readByteArray() throws IOException { 350 String string = "abcd" + repeat('e', Segment.SIZE); 351 sink.writeUtf8(string); 352 assertByteArraysEquals(string.getBytes(UTF_8), source.readByteArray()); 353 } 354 355 @Test public void readByteArrayPartial() throws IOException { 356 sink.writeUtf8("abcd"); 357 assertEquals("[97, 98, 99]", Arrays.toString(source.readByteArray(3))); 358 assertEquals("d", source.readUtf8(1)); 359 } 360 361 @Test public void readByteString() throws IOException { 362 sink.writeUtf8("abcd").writeUtf8(repeat('e', Segment.SIZE)); 363 assertEquals("abcd" + repeat('e', Segment.SIZE), source.readByteString().utf8()); 364 } 365 366 @Test public void readByteStringPartial() throws IOException { 367 sink.writeUtf8("abcd").writeUtf8(repeat('e', Segment.SIZE)); 368 assertEquals("abc", source.readByteString(3).utf8()); 369 assertEquals("d", source.readUtf8(1)); 370 } 371 372 @Test public void readSpecificCharsetPartial() throws Exception { 373 sink.write( 374 ByteString.decodeHex("0000007600000259000002c80000006c000000e40000007300000259" 375 + "000002cc000000720000006100000070000000740000025900000072")); 376 assertEquals("vls", source.readString(7 * 4, Charset.forName("utf-32"))); 377 } 378 379 @Test public void readSpecificCharset() throws Exception { 380 sink.write( 381 ByteString.decodeHex("0000007600000259000002c80000006c000000e40000007300000259" 382 + "000002cc000000720000006100000070000000740000025900000072")); 383 assertEquals("vlsraptr", source.readString(Charset.forName("utf-32"))); 384 } 385 386 @Test public void readUtf8SpansSegments() throws Exception { 387 sink.writeUtf8(repeat('a', Segment.SIZE * 2)); 388 source.skip(Segment.SIZE - 1); 389 assertEquals("aa", source.readUtf8(2)); 390 } 391 392 @Test public void readUtf8Segment() throws Exception { 393 sink.writeUtf8(repeat('a', Segment.SIZE)); 394 assertEquals(repeat('a', Segment.SIZE), source.readUtf8(Segment.SIZE)); 395 } 396 397 @Test public void readUtf8PartialBuffer() throws Exception { 398 sink.writeUtf8(repeat('a', Segment.SIZE + 20)); 399 assertEquals(repeat('a', Segment.SIZE + 10), source.readUtf8(Segment.SIZE + 10)); 400 } 401 402 @Test public void readUtf8EntireBuffer() throws Exception { 403 sink.writeUtf8(repeat('a', Segment.SIZE * 2)); 404 assertEquals(repeat('a', Segment.SIZE * 2), source.readUtf8()); 405 } 406 407 @Test public void skip() throws Exception { 408 sink.writeUtf8("a"); 409 sink.writeUtf8(repeat('b', Segment.SIZE)); 410 sink.writeUtf8("c"); 411 source.skip(1); 412 assertEquals('b', source.readByte() & 0xff); 413 source.skip(Segment.SIZE - 2); 414 assertEquals('b', source.readByte() & 0xff); 415 source.skip(1); 416 assertTrue(source.exhausted()); 417 } 418 419 @Test public void skipInsufficientData() throws Exception { 420 sink.writeUtf8("a"); 421 422 try { 423 source.skip(2); 424 fail(); 425 } catch (EOFException ignored) { 426 } 427 } 428 429 @Test public void indexOf() throws Exception { 430 // The segment is empty. 431 assertEquals(-1, source.indexOf((byte) 'a')); 432 433 // The segment has one value. 434 sink.writeUtf8("a"); // a 435 assertEquals(0, source.indexOf((byte) 'a')); 436 assertEquals(-1, source.indexOf((byte) 'b')); 437 438 // The segment has lots of data. 439 sink.writeUtf8(repeat('b', Segment.SIZE - 2)); // ab...b 440 assertEquals(0, source.indexOf((byte) 'a')); 441 assertEquals(1, source.indexOf((byte) 'b')); 442 assertEquals(-1, source.indexOf((byte) 'c')); 443 444 // The segment doesn't start at 0, it starts at 2. 445 source.skip(2); // b...b 446 assertEquals(-1, source.indexOf((byte) 'a')); 447 assertEquals(0, source.indexOf((byte) 'b')); 448 assertEquals(-1, source.indexOf((byte) 'c')); 449 450 // The segment is full. 451 sink.writeUtf8("c"); // b...bc 452 assertEquals(-1, source.indexOf((byte) 'a')); 453 assertEquals(0, source.indexOf((byte) 'b')); 454 assertEquals(Segment.SIZE - 3, source.indexOf((byte) 'c')); 455 456 // The segment doesn't start at 2, it starts at 4. 457 source.skip(2); // b...bc 458 assertEquals(-1, source.indexOf((byte) 'a')); 459 assertEquals(0, source.indexOf((byte) 'b')); 460 assertEquals(Segment.SIZE - 5, source.indexOf((byte) 'c')); 461 462 // Two segments. 463 sink.writeUtf8("d"); // b...bcd, d is in the 2nd segment. 464 assertEquals(Segment.SIZE - 4, source.indexOf((byte) 'd')); 465 assertEquals(-1, source.indexOf((byte) 'e')); 466 } 467 468 @Test public void indexOfWithOffset() throws IOException { 469 sink.writeUtf8("a").writeUtf8(repeat('b', Segment.SIZE)).writeUtf8("c"); 470 assertEquals(-1, source.indexOf((byte) 'a', 1)); 471 assertEquals(15, source.indexOf((byte) 'b', 15)); 472 } 473 474 @Test public void indexOfByteString() throws IOException { 475 assertEquals(-1, source.indexOf(ByteString.encodeUtf8("flop"))); 476 477 sink.writeUtf8("flip flop"); 478 assertEquals(5, source.indexOf(ByteString.encodeUtf8("flop"))); 479 source.readUtf8(); // Clear stream. 480 481 // Make sure we backtrack and resume searching after partial match. 482 sink.writeUtf8("hi hi hi hey"); 483 assertEquals(3, source.indexOf(ByteString.encodeUtf8("hi hi hey"))); 484 } 485 486 @Test public void indexOfByteStringWithOffset() throws IOException { 487 assertEquals(-1, source.indexOf(ByteString.encodeUtf8("flop"), 1)); 488 489 sink.writeUtf8("flop flip flop"); 490 assertEquals(10, source.indexOf(ByteString.encodeUtf8("flop"), 1)); 491 source.readUtf8(); // Clear stream 492 493 // Make sure we backtrack and resume searching after partial match. 494 sink.writeUtf8("hi hi hi hi hey"); 495 assertEquals(6, source.indexOf(ByteString.encodeUtf8("hi hi hey"), 1)); 496 } 497 498 @Test public void indexOfByteStringInvalidArgumentsThrows() throws IOException { 499 try { 500 source.indexOf(ByteString.of()); 501 fail(); 502 } catch (IllegalArgumentException e) { 503 assertEquals("bytes is empty", e.getMessage()); 504 } 505 try { 506 source.indexOf(ByteString.encodeUtf8("hi"), -1); 507 fail(); 508 } catch (IllegalArgumentException e) { 509 assertEquals("fromIndex < 0", e.getMessage()); 510 } 511 } 512 513 @Test public void indexOfElement() throws IOException { 514 sink.writeUtf8("a").writeUtf8(repeat('b', Segment.SIZE)).writeUtf8("c"); 515 assertEquals(0, source.indexOfElement(ByteString.encodeUtf8("DEFGaHIJK"))); 516 assertEquals(1, source.indexOfElement(ByteString.encodeUtf8("DEFGHIJKb"))); 517 assertEquals(Segment.SIZE + 1, source.indexOfElement(ByteString.encodeUtf8("cDEFGHIJK"))); 518 assertEquals(1, source.indexOfElement(ByteString.encodeUtf8("DEFbGHIc"))); 519 assertEquals(-1L, source.indexOfElement(ByteString.encodeUtf8("DEFGHIJK"))); 520 assertEquals(-1L, source.indexOfElement(ByteString.encodeUtf8(""))); 521 } 522 523 @Test public void indexOfElementWithOffset() throws IOException { 524 sink.writeUtf8("a").writeUtf8(repeat('b', Segment.SIZE)).writeUtf8("c"); 525 assertEquals(-1, source.indexOfElement(ByteString.encodeUtf8("DEFGaHIJK"), 1)); 526 assertEquals(15, source.indexOfElement(ByteString.encodeUtf8("DEFGHIJKb"), 15)); 527 } 528 529 @Test public void request() throws IOException { 530 sink.writeUtf8("a").writeUtf8(repeat('b', Segment.SIZE)).writeUtf8("c"); 531 assertTrue(source.request(Segment.SIZE + 2)); 532 assertFalse(source.request(Segment.SIZE + 3)); 533 } 534 535 @Test public void require() throws IOException { 536 sink.writeUtf8("a").writeUtf8(repeat('b', Segment.SIZE)).writeUtf8("c"); 537 source.require(Segment.SIZE + 2); 538 try { 539 source.require(Segment.SIZE + 3); 540 fail(); 541 } catch (EOFException expected) { 542 } 543 } 544 545 @Test public void inputStream() throws Exception { 546 sink.writeUtf8("abc"); 547 InputStream in = source.inputStream(); 548 byte[] bytes = { 'z', 'z', 'z' }; 549 int read = in.read(bytes); 550 if (factory == ONE_BYTE_AT_A_TIME_FACTORY) { 551 assertEquals(1, read); 552 assertByteArrayEquals("azz", bytes); 553 554 read = in.read(bytes); 555 assertEquals(1, read); 556 assertByteArrayEquals("bzz", bytes); 557 558 read = in.read(bytes); 559 assertEquals(1, read); 560 assertByteArrayEquals("czz", bytes); 561 } else { 562 assertEquals(3, read); 563 assertByteArrayEquals("abc", bytes); 564 } 565 566 assertEquals(-1, in.read()); 567 } 568 569 @Test public void inputStreamOffsetCount() throws Exception { 570 sink.writeUtf8("abcde"); 571 InputStream in = source.inputStream(); 572 byte[] bytes = { 'z', 'z', 'z', 'z', 'z' }; 573 int read = in.read(bytes, 1, 3); 574 if (factory == ONE_BYTE_AT_A_TIME_FACTORY) { 575 assertEquals(1, read); 576 assertByteArrayEquals("zazzz", bytes); 577 } else { 578 assertEquals(3, read); 579 assertByteArrayEquals("zabcz", bytes); 580 } 581 } 582 583 @Test public void inputStreamSkip() throws Exception { 584 sink.writeUtf8("abcde"); 585 InputStream in = source.inputStream(); 586 assertEquals(4, in.skip(4)); 587 assertEquals('e', in.read()); 588 } 589 590 @Test public void inputStreamCharByChar() throws Exception { 591 sink.writeUtf8("abc"); 592 InputStream in = source.inputStream(); 593 assertEquals('a', in.read()); 594 assertEquals('b', in.read()); 595 assertEquals('c', in.read()); 596 assertEquals(-1, in.read()); 597 } 598 599 @Test public void inputStreamBounds() throws IOException { 600 sink.writeUtf8(repeat('a', 100)); 601 InputStream in = source.inputStream(); 602 try { 603 in.read(new byte[100], 50, 51); 604 fail(); 605 } catch (ArrayIndexOutOfBoundsException expected) { 606 } 607 } 608 609 @Test public void longHexString() throws IOException { 610 assertLongHexString("8000000000000000", 0x8000000000000000L); 611 assertLongHexString("fffffffffffffffe", 0xFFFFFFFFFFFFFFFEL); 612 assertLongHexString("FFFFFFFFFFFFFFFe", 0xFFFFFFFFFFFFFFFEL); 613 assertLongHexString("ffffffffffffffff", 0xffffffffffffffffL); 614 assertLongHexString("FFFFFFFFFFFFFFFF", 0xFFFFFFFFFFFFFFFFL); 615 assertLongHexString("0000000000000000", 0x0); 616 assertLongHexString("0000000000000001", 0x1); 617 assertLongHexString("7999999999999999", 0x7999999999999999L); 618 619 assertLongHexString("FF", 0xFF); 620 assertLongHexString("0000000000000001", 0x1); 621 } 622 623 @Test public void hexStringWithManyLeadingZeros() throws IOException { 624 assertLongHexString("00000000000000001", 0x1); 625 assertLongHexString("0000000000000000ffffffffffffffff", 0xffffffffffffffffL); 626 assertLongHexString("00000000000000007fffffffffffffff", 0x7fffffffffffffffL); 627 assertLongHexString(TestUtil.repeat('0', Segment.SIZE + 1) + "1", 0x1); 628 } 629 630 private void assertLongHexString(String s, long expected) throws IOException { 631 sink.writeUtf8(s); 632 long actual = source.readHexadecimalUnsignedLong(); 633 assertEquals(s + " --> " + expected, expected, actual); 634 } 635 636 @Test public void longHexStringAcrossSegment() throws IOException { 637 sink.writeUtf8(repeat('a', Segment.SIZE - 8)).writeUtf8("FFFFFFFFFFFFFFFF"); 638 source.skip(Segment.SIZE - 8); 639 assertEquals(-1, source.readHexadecimalUnsignedLong()); 640 } 641 642 @Test public void longHexStringTooLongThrows() throws IOException { 643 try { 644 sink.writeUtf8("fffffffffffffffff"); 645 source.readHexadecimalUnsignedLong(); 646 fail(); 647 } catch (NumberFormatException e) { 648 assertEquals("Number too large: fffffffffffffffff", e.getMessage()); 649 } 650 } 651 652 @Test public void longHexStringTooShortThrows() throws IOException { 653 try { 654 sink.writeUtf8(" "); 655 source.readHexadecimalUnsignedLong(); 656 fail(); 657 } catch (NumberFormatException e) { 658 assertEquals("Expected leading [0-9a-fA-F] character but was 0x20", e.getMessage()); 659 } 660 } 661 662 @Test public void longHexEmptySourceThrows() throws IOException { 663 try { 664 sink.writeUtf8(""); 665 source.readHexadecimalUnsignedLong(); 666 fail(); 667 } catch (IllegalStateException | EOFException expected) { 668 } 669 } 670 671 @Test public void longDecimalString() throws IOException { 672 assertLongDecimalString("-9223372036854775808", -9223372036854775808L); 673 assertLongDecimalString("-1", -1L); 674 assertLongDecimalString("0", 0L); 675 assertLongDecimalString("1", 1L); 676 assertLongDecimalString("9223372036854775807", 9223372036854775807L); 677 678 assertLongDecimalString("00000001", 1L); 679 assertLongDecimalString("-000001", -1L); 680 } 681 682 private void assertLongDecimalString(String s, long expected) throws IOException { 683 sink.writeUtf8(s); 684 sink.writeUtf8("zzz"); 685 long actual = source.readDecimalLong(); 686 assertEquals(s + " --> " + expected, expected, actual); 687 assertEquals("zzz", source.readUtf8()); 688 } 689 690 @Test public void longDecimalStringAcrossSegment() throws IOException { 691 sink.writeUtf8(repeat('a', Segment.SIZE - 8)).writeUtf8("1234567890123456"); 692 sink.writeUtf8("zzz"); 693 source.skip(Segment.SIZE - 8); 694 assertEquals(1234567890123456L, source.readDecimalLong()); 695 assertEquals("zzz", source.readUtf8()); 696 } 697 698 @Test public void longDecimalStringTooLongThrows() throws IOException { 699 try { 700 sink.writeUtf8("12345678901234567890"); // Too many digits. 701 source.readDecimalLong(); 702 fail(); 703 } catch (NumberFormatException e) { 704 assertEquals("Number too large: 12345678901234567890", e.getMessage()); 705 } 706 } 707 708 @Test public void longDecimalStringTooHighThrows() throws IOException { 709 try { 710 sink.writeUtf8("9223372036854775808"); // Right size but cannot fit. 711 source.readDecimalLong(); 712 fail(); 713 } catch (NumberFormatException e) { 714 assertEquals("Number too large: 9223372036854775808", e.getMessage()); 715 } 716 } 717 718 @Test public void longDecimalStringTooLowThrows() throws IOException { 719 try { 720 sink.writeUtf8("-9223372036854775809"); // Right size but cannot fit. 721 source.readDecimalLong(); 722 fail(); 723 } catch (NumberFormatException e) { 724 assertEquals("Number too large: -9223372036854775809", e.getMessage()); 725 } 726 } 727 728 @Test public void longDecimalStringTooShortThrows() throws IOException { 729 try { 730 sink.writeUtf8(" "); 731 source.readDecimalLong(); 732 fail(); 733 } catch (NumberFormatException e) { 734 assertEquals("Expected leading [0-9] or '-' character but was 0x20", e.getMessage()); 735 } 736 } 737 738 @Test public void longDecimalEmptyThrows() throws IOException { 739 try { 740 sink.writeUtf8(""); 741 source.readDecimalLong(); 742 fail(); 743 } catch (IllegalStateException | EOFException expected) { 744 } 745 } 746 747 @Test public void codePoints() throws IOException { 748 sink.write(ByteString.decodeHex("7f")); 749 assertEquals(0x7f, source.readUtf8CodePoint()); 750 751 sink.write(ByteString.decodeHex("dfbf")); 752 assertEquals(0x07ff, source.readUtf8CodePoint()); 753 754 sink.write(ByteString.decodeHex("efbfbf")); 755 assertEquals(0xffff, source.readUtf8CodePoint()); 756 757 sink.write(ByteString.decodeHex("f48fbfbf")); 758 assertEquals(0x10ffff, source.readUtf8CodePoint()); 759 } 760 761 @Test public void decimalStringWithManyLeadingZeros() throws IOException { 762 assertLongDecimalString("00000000000000001", 1); 763 assertLongDecimalString("00000000000000009223372036854775807", 9223372036854775807L); 764 assertLongDecimalString("-00000000000000009223372036854775808", -9223372036854775808L); 765 assertLongDecimalString(TestUtil.repeat('0', Segment.SIZE + 1) + "1", 1); 766 } 767 } 768