1/* 2 * Copyright 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 */ 16package okio; 17 18import java.io.ByteArrayInputStream; 19import java.io.ByteArrayOutputStream; 20import java.io.InputStream; 21import java.util.ArrayList; 22import java.util.Arrays; 23import java.util.Collections; 24import java.util.List; 25import java.util.Random; 26import org.junit.Test; 27 28import static okio.TestUtil.assertByteArraysEquals; 29import static okio.TestUtil.assertEquivalent; 30import static org.junit.Assert.assertEquals; 31import static org.junit.Assert.assertFalse; 32import static org.junit.Assert.assertSame; 33import static org.junit.Assert.assertTrue; 34import static org.junit.Assert.fail; 35 36public class ByteStringTest { 37 @Test public void ofCopyRange() { 38 byte[] bytes = "Hello, World!".getBytes(Util.UTF_8); 39 ByteString byteString = ByteString.of(bytes, 2, 9); 40 // Verify that the bytes were copied out. 41 bytes[4] = (byte) 'a'; 42 assertEquals("llo, Worl", byteString.utf8()); 43 } 44 45 @Test public void getByte() throws Exception { 46 ByteString byteString = ByteString.decodeHex("ab12"); 47 assertEquals(-85, byteString.getByte(0)); 48 assertEquals(18, byteString.getByte(1)); 49 } 50 51 @Test public void getByteOutOfBounds() throws Exception { 52 ByteString byteString = ByteString.decodeHex("ab12"); 53 try { 54 byteString.getByte(2); 55 fail(); 56 } catch (IndexOutOfBoundsException expected) { 57 } 58 } 59 60 @Test public void equals() throws Exception { 61 ByteString byteString = ByteString.decodeHex("000102"); 62 assertTrue(byteString.equals(byteString)); 63 assertTrue(byteString.equals(ByteString.decodeHex("000102"))); 64 assertTrue(ByteString.of().equals(ByteString.EMPTY)); 65 assertTrue(ByteString.EMPTY.equals(ByteString.of())); 66 assertFalse(byteString.equals(new Object())); 67 assertFalse(byteString.equals(ByteString.decodeHex("000201"))); 68 } 69 70 private final String bronzeHorseman = "На берегу пустынных волн"; 71 72 @Test public void utf8() throws Exception { 73 ByteString byteString = ByteString.encodeUtf8(bronzeHorseman); 74 assertByteArraysEquals(byteString.toByteArray(), bronzeHorseman.getBytes(Util.UTF_8)); 75 assertTrue(byteString.equals(ByteString.of(bronzeHorseman.getBytes(Util.UTF_8)))); 76 assertEquals(byteString.utf8(), bronzeHorseman); 77 } 78 79 @Test public void md5() { 80 assertEquals("6cd3556deb0da54bca060b4c39479839", 81 ByteString.encodeUtf8("Hello, world!").md5().hex()); 82 assertEquals("c71dc6df4b2e434b8c74fd6dd6ca3f85", 83 ByteString.encodeUtf8("One Two Three").md5().hex()); 84 assertEquals("37b69fb926e239e049d7e43987974b99", 85 ByteString.encodeUtf8(bronzeHorseman).md5().hex()); 86 } 87 88 @Test public void sha256() { 89 assertEquals("315f5bdb76d078c43b8ac0064e4a0164612b1fce77c869345bfc94c75894edd3", 90 ByteString.encodeUtf8("Hello, world!").sha256().hex()); 91 assertEquals("641e54ba5e49e169408148a25bef8ca8fa4f8aab222fe8ce4b3535a570ddd68e", 92 ByteString.encodeUtf8("One Two Three").sha256().hex()); 93 assertEquals("4d869e1c3d94568a5344235d9e4f187b8d5d78d06c5c622854c669f2f582d33e", 94 ByteString.encodeUtf8(bronzeHorseman).sha256().hex()); 95 } 96 97 @Test public void testHashCode() throws Exception { 98 ByteString byteString = ByteString.decodeHex("0102"); 99 assertEquals(byteString.hashCode(), byteString.hashCode()); 100 assertEquals(byteString.hashCode(), ByteString.decodeHex("0102").hashCode()); 101 } 102 103 @Test public void read() throws Exception { 104 InputStream in = new ByteArrayInputStream("abc".getBytes(Util.UTF_8)); 105 assertEquals(ByteString.decodeHex("6162"), ByteString.read(in, 2)); 106 assertEquals(ByteString.decodeHex("63"), ByteString.read(in, 1)); 107 assertEquals(ByteString.of(), ByteString.read(in, 0)); 108 } 109 110 @Test public void readAndToLowercase() throws Exception { 111 InputStream in = new ByteArrayInputStream("ABC".getBytes(Util.UTF_8)); 112 assertEquals(ByteString.encodeUtf8("ab"), ByteString.read(in, 2).toAsciiLowercase()); 113 assertEquals(ByteString.encodeUtf8("c"), ByteString.read(in, 1).toAsciiLowercase()); 114 assertEquals(ByteString.EMPTY, ByteString.read(in, 0).toAsciiLowercase()); 115 } 116 117 @Test public void toAsciiLowerCaseNoUppercase() throws Exception { 118 ByteString s = ByteString.encodeUtf8("a1_+"); 119 assertSame(s, s.toAsciiLowercase()); 120 } 121 122 @Test public void toAsciiAllUppercase() throws Exception { 123 assertEquals(ByteString.encodeUtf8("ab"), ByteString.encodeUtf8("AB").toAsciiLowercase()); 124 } 125 126 @Test public void toAsciiStartsLowercaseEndsUppercase() throws Exception { 127 assertEquals(ByteString.encodeUtf8("abcd"), ByteString.encodeUtf8("abCD").toAsciiLowercase()); 128 } 129 130 @Test public void readAndToUppercase() throws Exception { 131 InputStream in = new ByteArrayInputStream("abc".getBytes(Util.UTF_8)); 132 assertEquals(ByteString.encodeUtf8("AB"), ByteString.read(in, 2).toAsciiUppercase()); 133 assertEquals(ByteString.encodeUtf8("C"), ByteString.read(in, 1).toAsciiUppercase()); 134 assertEquals(ByteString.EMPTY, ByteString.read(in, 0).toAsciiUppercase()); 135 } 136 137 @Test public void toAsciiStartsUppercaseEndsLowercase() throws Exception { 138 assertEquals(ByteString.encodeUtf8("ABCD"), ByteString.encodeUtf8("ABcd").toAsciiUppercase()); 139 } 140 141 @Test public void substring() throws Exception { 142 ByteString byteString = ByteString.encodeUtf8("Hello, World!"); 143 144 assertEquals(byteString.substring(0), byteString); 145 assertEquals(byteString.substring(0, 5), ByteString.encodeUtf8("Hello")); 146 assertEquals(byteString.substring(7), ByteString.encodeUtf8("World!")); 147 assertEquals(byteString.substring(6, 6), ByteString.encodeUtf8("")); 148 } 149 150 @Test public void substringWithInvalidBounds() throws Exception { 151 ByteString byteString = ByteString.encodeUtf8("Hello, World!"); 152 153 try { 154 byteString.substring(-1); 155 fail(); 156 } catch (IllegalArgumentException expected) { 157 } 158 159 try { 160 byteString.substring(0, 14); 161 fail(); 162 } catch (IllegalArgumentException expected) { 163 } 164 165 try { 166 byteString.substring(8, 7); 167 fail(); 168 } catch (IllegalArgumentException expected) { 169 } 170 } 171 172 @Test public void write() throws Exception { 173 ByteArrayOutputStream out = new ByteArrayOutputStream(); 174 ByteString.decodeHex("616263").write(out); 175 assertByteArraysEquals(new byte[] { 0x61, 0x62, 0x63 }, out.toByteArray()); 176 } 177 178 @Test public void encodeBase64() { 179 assertEquals("", ByteString.encodeUtf8("").base64()); 180 assertEquals("AA==", ByteString.encodeUtf8("\u0000").base64()); 181 assertEquals("AAA=", ByteString.encodeUtf8("\u0000\u0000").base64()); 182 assertEquals("AAAA", ByteString.encodeUtf8("\u0000\u0000\u0000").base64()); 183 assertEquals("SG93IG1hbnkgbGluZXMgb2YgY29kZSBhcmUgdGhlcmU/ICdib3V0IDIgbWlsbGlvbi4=", 184 ByteString.encodeUtf8("How many lines of code are there? 'bout 2 million.").base64()); 185 } 186 187 @Test public void encodeBase64Url() { 188 assertEquals("", ByteString.encodeUtf8("").base64Url()); 189 assertEquals("AA==", ByteString.encodeUtf8("\u0000").base64Url()); 190 assertEquals("AAA=", ByteString.encodeUtf8("\u0000\u0000").base64Url()); 191 assertEquals("AAAA", ByteString.encodeUtf8("\u0000\u0000\u0000").base64Url()); 192 assertEquals("SG93IG1hbnkgbGluZXMgb2YgY29kZSBhcmUgdGhlcmU_ICdib3V0IDIgbWlsbGlvbi4=", 193 ByteString.encodeUtf8("How many lines of code are there? 'bout 2 million.").base64Url()); 194 } 195 196 @Test public void ignoreUnnecessaryPadding() { 197 assertEquals("", ByteString.decodeBase64("====").utf8()); 198 assertEquals("\u0000\u0000\u0000", ByteString.decodeBase64("AAAA====").utf8()); 199 } 200 201 @Test public void decodeBase64() { 202 assertEquals("", ByteString.decodeBase64("").utf8()); 203 assertEquals(null, ByteString.decodeBase64("/===")); // Can't do anything with 6 bits! 204 assertEquals(ByteString.decodeHex("ff"), ByteString.decodeBase64("//==")); 205 assertEquals(ByteString.decodeHex("ff"), ByteString.decodeBase64("__==")); 206 assertEquals(ByteString.decodeHex("ffff"), ByteString.decodeBase64("///=")); 207 assertEquals(ByteString.decodeHex("ffff"), ByteString.decodeBase64("___=")); 208 assertEquals(ByteString.decodeHex("ffffff"), ByteString.decodeBase64("////")); 209 assertEquals(ByteString.decodeHex("ffffff"), ByteString.decodeBase64("____")); 210 assertEquals(ByteString.decodeHex("ffffffffffff"), ByteString.decodeBase64("////////")); 211 assertEquals(ByteString.decodeHex("ffffffffffff"), ByteString.decodeBase64("________")); 212 assertEquals("What's to be scared about? It's just a little hiccup in the power...", 213 ByteString.decodeBase64("V2hhdCdzIHRvIGJlIHNjYXJlZCBhYm91dD8gSXQncyBqdXN0IGEgbGl0dGxlIGhpY2" 214 + "N1cCBpbiB0aGUgcG93ZXIuLi4=").utf8()); 215 // Uses two encoding styles. Malformed, but supported as a side-effect. 216 assertEquals(ByteString.decodeHex("ffffff"), ByteString.decodeBase64("__//")); 217 } 218 219 @Test public void decodeBase64WithWhitespace() { 220 assertEquals("\u0000\u0000\u0000", ByteString.decodeBase64(" AA AA ").utf8()); 221 assertEquals("\u0000\u0000\u0000", ByteString.decodeBase64(" AA A\r\nA ").utf8()); 222 assertEquals("\u0000\u0000\u0000", ByteString.decodeBase64("AA AA").utf8()); 223 assertEquals("\u0000\u0000\u0000", ByteString.decodeBase64(" AA AA ").utf8()); 224 assertEquals("\u0000\u0000\u0000", ByteString.decodeBase64(" AA A\r\nA ").utf8()); 225 assertEquals("\u0000\u0000\u0000", ByteString.decodeBase64("A AAA").utf8()); 226 assertEquals("", ByteString.decodeBase64(" ").utf8()); 227 } 228 229 @Test public void encodeHex() throws Exception { 230 assertEquals("000102", ByteString.of((byte) 0x0, (byte) 0x1, (byte) 0x2).hex()); 231 } 232 233 @Test public void decodeHex() throws Exception { 234 assertEquals(ByteString.of((byte) 0x0, (byte) 0x1, (byte) 0x2), ByteString.decodeHex("000102")); 235 } 236 237 @Test public void decodeHexOddNumberOfChars() throws Exception { 238 try { 239 ByteString.decodeHex("aaa"); 240 fail(); 241 } catch (IllegalArgumentException expected) { 242 } 243 } 244 245 @Test public void decodeHexInvalidChar() throws Exception { 246 try { 247 ByteString.decodeHex("a\u0000"); 248 fail(); 249 } catch (IllegalArgumentException expected) { 250 } 251 } 252 253 @Test public void toStringOnEmptyByteString() { 254 assertEquals("ByteString[size=0]", ByteString.of().toString()); 255 } 256 257 @Test public void toStringOnSmallByteStringIncludesContents() { 258 assertEquals("ByteString[size=16 data=a1b2c3d4e5f61a2b3c4d5e6f10203040]", 259 ByteString.decodeHex("a1b2c3d4e5f61a2b3c4d5e6f10203040").toString()); 260 } 261 262 @Test public void toStringOnLargeByteStringIncludesMd5() { 263 assertEquals("ByteString[size=17 md5=2c9728a2138b2f25e9f89f99bdccf8db]", 264 ByteString.encodeUtf8("12345678901234567").toString()); 265 } 266 267 @Test public void javaSerializationTestNonEmpty() throws Exception { 268 ByteString byteString = ByteString.encodeUtf8(bronzeHorseman); 269 assertEquivalent(byteString, TestUtil.reserialize(byteString)); 270 } 271 272 @Test public void javaSerializationTestEmpty() throws Exception { 273 ByteString byteString = ByteString.of(); 274 assertEquivalent(byteString, TestUtil.reserialize(byteString)); 275 } 276 277 @Test public void compareToSingleBytes() throws Exception { 278 List<ByteString> originalByteStrings = Arrays.asList( 279 ByteString.decodeHex("00"), 280 ByteString.decodeHex("01"), 281 ByteString.decodeHex("7e"), 282 ByteString.decodeHex("7f"), 283 ByteString.decodeHex("80"), 284 ByteString.decodeHex("81"), 285 ByteString.decodeHex("fe"), 286 ByteString.decodeHex("ff")); 287 288 List<ByteString> sortedByteStrings = new ArrayList<>(originalByteStrings); 289 Collections.shuffle(sortedByteStrings, new Random(0)); 290 Collections.sort(sortedByteStrings); 291 292 assertEquals(originalByteStrings, sortedByteStrings); 293 } 294 295 @Test public void compareToMultipleBytes() throws Exception { 296 List<ByteString> originalByteStrings = Arrays.asList( 297 ByteString.decodeHex(""), 298 ByteString.decodeHex("00"), 299 ByteString.decodeHex("0000"), 300 ByteString.decodeHex("000000"), 301 ByteString.decodeHex("00000000"), 302 ByteString.decodeHex("0000000000"), 303 ByteString.decodeHex("0000000001"), 304 ByteString.decodeHex("000001"), 305 ByteString.decodeHex("00007f"), 306 ByteString.decodeHex("0000ff"), 307 ByteString.decodeHex("000100"), 308 ByteString.decodeHex("000101"), 309 ByteString.decodeHex("007f00"), 310 ByteString.decodeHex("00ff00"), 311 ByteString.decodeHex("010000"), 312 ByteString.decodeHex("010001"), 313 ByteString.decodeHex("01007f"), 314 ByteString.decodeHex("0100ff"), 315 ByteString.decodeHex("010100"), 316 ByteString.decodeHex("01010000"), 317 ByteString.decodeHex("0101000000"), 318 ByteString.decodeHex("0101000001"), 319 ByteString.decodeHex("010101"), 320 ByteString.decodeHex("7f0000"), 321 ByteString.decodeHex("7f0000ffff"), 322 ByteString.decodeHex("ffffff")); 323 324 List<ByteString> sortedByteStrings = new ArrayList<>(originalByteStrings); 325 Collections.shuffle(sortedByteStrings, new Random(0)); 326 Collections.sort(sortedByteStrings); 327 328 assertEquals(originalByteStrings, sortedByteStrings); 329 } 330} 331