/* * Copyright 2014 Square Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package okio; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Random; import org.junit.Test; import static okio.TestUtil.assertByteArraysEquals; import static okio.TestUtil.assertEquivalent; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; public class ByteStringTest { @Test public void ofCopyRange() { byte[] bytes = "Hello, World!".getBytes(Util.UTF_8); ByteString byteString = ByteString.of(bytes, 2, 9); // Verify that the bytes were copied out. bytes[4] = (byte) 'a'; assertEquals("llo, Worl", byteString.utf8()); } @Test public void getByte() throws Exception { ByteString byteString = ByteString.decodeHex("ab12"); assertEquals(-85, byteString.getByte(0)); assertEquals(18, byteString.getByte(1)); } @Test public void getByteOutOfBounds() throws Exception { ByteString byteString = ByteString.decodeHex("ab12"); try { byteString.getByte(2); fail(); } catch (IndexOutOfBoundsException expected) { } } @Test public void equals() throws Exception { ByteString byteString = ByteString.decodeHex("000102"); assertTrue(byteString.equals(byteString)); assertTrue(byteString.equals(ByteString.decodeHex("000102"))); assertTrue(ByteString.of().equals(ByteString.EMPTY)); assertTrue(ByteString.EMPTY.equals(ByteString.of())); assertFalse(byteString.equals(new Object())); assertFalse(byteString.equals(ByteString.decodeHex("000201"))); } private final String bronzeHorseman = "На берегу пустынных волн"; @Test public void utf8() throws Exception { ByteString byteString = ByteString.encodeUtf8(bronzeHorseman); assertByteArraysEquals(byteString.toByteArray(), bronzeHorseman.getBytes(Util.UTF_8)); assertTrue(byteString.equals(ByteString.of(bronzeHorseman.getBytes(Util.UTF_8)))); assertEquals(byteString.utf8(), bronzeHorseman); } @Test public void md5() { assertEquals("6cd3556deb0da54bca060b4c39479839", ByteString.encodeUtf8("Hello, world!").md5().hex()); assertEquals("c71dc6df4b2e434b8c74fd6dd6ca3f85", ByteString.encodeUtf8("One Two Three").md5().hex()); assertEquals("37b69fb926e239e049d7e43987974b99", ByteString.encodeUtf8(bronzeHorseman).md5().hex()); } @Test public void sha256() { assertEquals("315f5bdb76d078c43b8ac0064e4a0164612b1fce77c869345bfc94c75894edd3", ByteString.encodeUtf8("Hello, world!").sha256().hex()); assertEquals("641e54ba5e49e169408148a25bef8ca8fa4f8aab222fe8ce4b3535a570ddd68e", ByteString.encodeUtf8("One Two Three").sha256().hex()); assertEquals("4d869e1c3d94568a5344235d9e4f187b8d5d78d06c5c622854c669f2f582d33e", ByteString.encodeUtf8(bronzeHorseman).sha256().hex()); } @Test public void testHashCode() throws Exception { ByteString byteString = ByteString.decodeHex("0102"); assertEquals(byteString.hashCode(), byteString.hashCode()); assertEquals(byteString.hashCode(), ByteString.decodeHex("0102").hashCode()); } @Test public void read() throws Exception { InputStream in = new ByteArrayInputStream("abc".getBytes(Util.UTF_8)); assertEquals(ByteString.decodeHex("6162"), ByteString.read(in, 2)); assertEquals(ByteString.decodeHex("63"), ByteString.read(in, 1)); assertEquals(ByteString.of(), ByteString.read(in, 0)); } @Test public void readAndToLowercase() throws Exception { InputStream in = new ByteArrayInputStream("ABC".getBytes(Util.UTF_8)); assertEquals(ByteString.encodeUtf8("ab"), ByteString.read(in, 2).toAsciiLowercase()); assertEquals(ByteString.encodeUtf8("c"), ByteString.read(in, 1).toAsciiLowercase()); assertEquals(ByteString.EMPTY, ByteString.read(in, 0).toAsciiLowercase()); } @Test public void toAsciiLowerCaseNoUppercase() throws Exception { ByteString s = ByteString.encodeUtf8("a1_+"); assertSame(s, s.toAsciiLowercase()); } @Test public void toAsciiAllUppercase() throws Exception { assertEquals(ByteString.encodeUtf8("ab"), ByteString.encodeUtf8("AB").toAsciiLowercase()); } @Test public void toAsciiStartsLowercaseEndsUppercase() throws Exception { assertEquals(ByteString.encodeUtf8("abcd"), ByteString.encodeUtf8("abCD").toAsciiLowercase()); } @Test public void readAndToUppercase() throws Exception { InputStream in = new ByteArrayInputStream("abc".getBytes(Util.UTF_8)); assertEquals(ByteString.encodeUtf8("AB"), ByteString.read(in, 2).toAsciiUppercase()); assertEquals(ByteString.encodeUtf8("C"), ByteString.read(in, 1).toAsciiUppercase()); assertEquals(ByteString.EMPTY, ByteString.read(in, 0).toAsciiUppercase()); } @Test public void toAsciiStartsUppercaseEndsLowercase() throws Exception { assertEquals(ByteString.encodeUtf8("ABCD"), ByteString.encodeUtf8("ABcd").toAsciiUppercase()); } @Test public void substring() throws Exception { ByteString byteString = ByteString.encodeUtf8("Hello, World!"); assertEquals(byteString.substring(0), byteString); assertEquals(byteString.substring(0, 5), ByteString.encodeUtf8("Hello")); assertEquals(byteString.substring(7), ByteString.encodeUtf8("World!")); assertEquals(byteString.substring(6, 6), ByteString.encodeUtf8("")); } @Test public void substringWithInvalidBounds() throws Exception { ByteString byteString = ByteString.encodeUtf8("Hello, World!"); try { byteString.substring(-1); fail(); } catch (IllegalArgumentException expected) { } try { byteString.substring(0, 14); fail(); } catch (IllegalArgumentException expected) { } try { byteString.substring(8, 7); fail(); } catch (IllegalArgumentException expected) { } } @Test public void write() throws Exception { ByteArrayOutputStream out = new ByteArrayOutputStream(); ByteString.decodeHex("616263").write(out); assertByteArraysEquals(new byte[] { 0x61, 0x62, 0x63 }, out.toByteArray()); } @Test public void encodeBase64() { assertEquals("", ByteString.encodeUtf8("").base64()); assertEquals("AA==", ByteString.encodeUtf8("\u0000").base64()); assertEquals("AAA=", ByteString.encodeUtf8("\u0000\u0000").base64()); assertEquals("AAAA", ByteString.encodeUtf8("\u0000\u0000\u0000").base64()); assertEquals("SG93IG1hbnkgbGluZXMgb2YgY29kZSBhcmUgdGhlcmU/ICdib3V0IDIgbWlsbGlvbi4=", ByteString.encodeUtf8("How many lines of code are there? 'bout 2 million.").base64()); } @Test public void encodeBase64Url() { assertEquals("", ByteString.encodeUtf8("").base64Url()); assertEquals("AA==", ByteString.encodeUtf8("\u0000").base64Url()); assertEquals("AAA=", ByteString.encodeUtf8("\u0000\u0000").base64Url()); assertEquals("AAAA", ByteString.encodeUtf8("\u0000\u0000\u0000").base64Url()); assertEquals("SG93IG1hbnkgbGluZXMgb2YgY29kZSBhcmUgdGhlcmU_ICdib3V0IDIgbWlsbGlvbi4=", ByteString.encodeUtf8("How many lines of code are there? 'bout 2 million.").base64Url()); } @Test public void ignoreUnnecessaryPadding() { assertEquals("", ByteString.decodeBase64("====").utf8()); assertEquals("\u0000\u0000\u0000", ByteString.decodeBase64("AAAA====").utf8()); } @Test public void decodeBase64() { assertEquals("", ByteString.decodeBase64("").utf8()); assertEquals(null, ByteString.decodeBase64("/===")); // Can't do anything with 6 bits! assertEquals(ByteString.decodeHex("ff"), ByteString.decodeBase64("//==")); assertEquals(ByteString.decodeHex("ff"), ByteString.decodeBase64("__==")); assertEquals(ByteString.decodeHex("ffff"), ByteString.decodeBase64("///=")); assertEquals(ByteString.decodeHex("ffff"), ByteString.decodeBase64("___=")); assertEquals(ByteString.decodeHex("ffffff"), ByteString.decodeBase64("////")); assertEquals(ByteString.decodeHex("ffffff"), ByteString.decodeBase64("____")); assertEquals(ByteString.decodeHex("ffffffffffff"), ByteString.decodeBase64("////////")); assertEquals(ByteString.decodeHex("ffffffffffff"), ByteString.decodeBase64("________")); assertEquals("What's to be scared about? It's just a little hiccup in the power...", ByteString.decodeBase64("V2hhdCdzIHRvIGJlIHNjYXJlZCBhYm91dD8gSXQncyBqdXN0IGEgbGl0dGxlIGhpY2" + "N1cCBpbiB0aGUgcG93ZXIuLi4=").utf8()); // Uses two encoding styles. Malformed, but supported as a side-effect. assertEquals(ByteString.decodeHex("ffffff"), ByteString.decodeBase64("__//")); } @Test public void decodeBase64WithWhitespace() { assertEquals("\u0000\u0000\u0000", ByteString.decodeBase64(" AA AA ").utf8()); assertEquals("\u0000\u0000\u0000", ByteString.decodeBase64(" AA A\r\nA ").utf8()); assertEquals("\u0000\u0000\u0000", ByteString.decodeBase64("AA AA").utf8()); assertEquals("\u0000\u0000\u0000", ByteString.decodeBase64(" AA AA ").utf8()); assertEquals("\u0000\u0000\u0000", ByteString.decodeBase64(" AA A\r\nA ").utf8()); assertEquals("\u0000\u0000\u0000", ByteString.decodeBase64("A AAA").utf8()); assertEquals("", ByteString.decodeBase64(" ").utf8()); } @Test public void encodeHex() throws Exception { assertEquals("000102", ByteString.of((byte) 0x0, (byte) 0x1, (byte) 0x2).hex()); } @Test public void decodeHex() throws Exception { assertEquals(ByteString.of((byte) 0x0, (byte) 0x1, (byte) 0x2), ByteString.decodeHex("000102")); } @Test public void decodeHexOddNumberOfChars() throws Exception { try { ByteString.decodeHex("aaa"); fail(); } catch (IllegalArgumentException expected) { } } @Test public void decodeHexInvalidChar() throws Exception { try { ByteString.decodeHex("a\u0000"); fail(); } catch (IllegalArgumentException expected) { } } @Test public void toStringOnEmptyByteString() { assertEquals("ByteString[size=0]", ByteString.of().toString()); } @Test public void toStringOnSmallByteStringIncludesContents() { assertEquals("ByteString[size=16 data=a1b2c3d4e5f61a2b3c4d5e6f10203040]", ByteString.decodeHex("a1b2c3d4e5f61a2b3c4d5e6f10203040").toString()); } @Test public void toStringOnLargeByteStringIncludesMd5() { assertEquals("ByteString[size=17 md5=2c9728a2138b2f25e9f89f99bdccf8db]", ByteString.encodeUtf8("12345678901234567").toString()); } @Test public void javaSerializationTestNonEmpty() throws Exception { ByteString byteString = ByteString.encodeUtf8(bronzeHorseman); assertEquivalent(byteString, TestUtil.reserialize(byteString)); } @Test public void javaSerializationTestEmpty() throws Exception { ByteString byteString = ByteString.of(); assertEquivalent(byteString, TestUtil.reserialize(byteString)); } @Test public void compareToSingleBytes() throws Exception { List<ByteString> originalByteStrings = Arrays.asList( ByteString.decodeHex("00"), ByteString.decodeHex("01"), ByteString.decodeHex("7e"), ByteString.decodeHex("7f"), ByteString.decodeHex("80"), ByteString.decodeHex("81"), ByteString.decodeHex("fe"), ByteString.decodeHex("ff")); List<ByteString> sortedByteStrings = new ArrayList<>(originalByteStrings); Collections.shuffle(sortedByteStrings, new Random(0)); Collections.sort(sortedByteStrings); assertEquals(originalByteStrings, sortedByteStrings); } @Test public void compareToMultipleBytes() throws Exception { List<ByteString> originalByteStrings = Arrays.asList( ByteString.decodeHex(""), ByteString.decodeHex("00"), ByteString.decodeHex("0000"), ByteString.decodeHex("000000"), ByteString.decodeHex("00000000"), ByteString.decodeHex("0000000000"), ByteString.decodeHex("0000000001"), ByteString.decodeHex("000001"), ByteString.decodeHex("00007f"), ByteString.decodeHex("0000ff"), ByteString.decodeHex("000100"), ByteString.decodeHex("000101"), ByteString.decodeHex("007f00"), ByteString.decodeHex("00ff00"), ByteString.decodeHex("010000"), ByteString.decodeHex("010001"), ByteString.decodeHex("01007f"), ByteString.decodeHex("0100ff"), ByteString.decodeHex("010100"), ByteString.decodeHex("01010000"), ByteString.decodeHex("0101000000"), ByteString.decodeHex("0101000001"), ByteString.decodeHex("010101"), ByteString.decodeHex("7f0000"), ByteString.decodeHex("7f0000ffff"), ByteString.decodeHex("ffffff")); List<ByteString> sortedByteStrings = new ArrayList<>(originalByteStrings); Collections.shuffle(sortedByteStrings, new Random(0)); Collections.sort(sortedByteStrings); assertEquals(originalByteStrings, sortedByteStrings); } }