1 /* 2 * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 package jdk.incubator.http.internal.hpack; 24 25 import org.testng.annotations.Test; 26 27 import java.nio.ByteBuffer; 28 import java.nio.CharBuffer; 29 import java.nio.charset.StandardCharsets; 30 import java.util.ArrayList; 31 import java.util.List; 32 import java.util.Random; 33 34 import static org.testng.Assert.assertEquals; 35 import static org.testng.Assert.fail; 36 import static jdk.incubator.http.internal.hpack.BuffersTestingKit.*; 37 import static jdk.incubator.http.internal.hpack.TestHelper.newRandom; 38 39 // 40 // Some of the tests below overlap in what they test. This allows to diagnose 41 // bugs quicker and with less pain by simply ruling out common working bits. 42 // 43 public final class BinaryPrimitivesTest { 44 45 private final Random rnd = newRandom(); 46 47 @Test 48 public void integerRead1() { 49 verifyRead(bytes(0b00011111, 0b10011010, 0b00001010), 1337, 5); 50 } 51 52 @Test 53 public void integerRead2() { 54 verifyRead(bytes(0b00001010), 10, 5); 55 } 56 57 @Test 58 public void integerRead3() { 59 verifyRead(bytes(0b00101010), 42, 8); 60 } 61 62 @Test 63 public void integerWrite1() { 64 verifyWrite(bytes(0b00011111, 0b10011010, 0b00001010), 1337, 5); 65 } 66 67 @Test 68 public void integerWrite2() { 69 verifyWrite(bytes(0b00001010), 10, 5); 70 } 71 72 @Test 73 public void integerWrite3() { 74 verifyWrite(bytes(0b00101010), 42, 8); 75 } 76 77 // 78 // Since readInteger(x) is the inverse of writeInteger(x), thus: 79 // 80 // for all x: readInteger(writeInteger(x)) == x 81 // 82 @Test 83 public void integerIdentity() { 84 final int MAX_VALUE = 1 << 22; 85 int totalCases = 0; 86 int maxFilling = 0; 87 IntegerReader r = new IntegerReader(); 88 IntegerWriter w = new IntegerWriter(); 89 ByteBuffer buf = ByteBuffer.allocate(8); 90 for (int N = 1; N < 9; N++) { 91 for (int expected = 0; expected <= MAX_VALUE; expected++) { 92 w.reset().configure(expected, N, 1).write(buf); 93 buf.flip(); 94 totalCases++; 95 maxFilling = Math.max(maxFilling, buf.remaining()); 96 r.reset().configure(N).read(buf); 97 assertEquals(r.get(), expected); 98 buf.clear(); 99 } 100 } 101 System.out.printf("totalCases: %,d, maxFilling: %,d, maxValue: %,d%n", 102 totalCases, maxFilling, MAX_VALUE); 103 } 104 105 @Test 106 public void integerReadChunked() { 107 final int NUM_TESTS = 1024; 108 IntegerReader r = new IntegerReader(); 109 ByteBuffer bb = ByteBuffer.allocate(8); 110 IntegerWriter w = new IntegerWriter(); 111 for (int i = 0; i < NUM_TESTS; i++) { 112 final int N = 1 + rnd.nextInt(8); 113 final int expected = rnd.nextInt(Integer.MAX_VALUE) + 1; 114 w.reset().configure(expected, N, rnd.nextInt()).write(bb); 115 bb.flip(); 116 117 forEachSplit(bb, 118 (buffers) -> { 119 Iterable<? extends ByteBuffer> buf = relocateBuffers(injectEmptyBuffers(buffers)); 120 r.configure(N); 121 for (ByteBuffer b : buf) { 122 r.read(b); 123 } 124 assertEquals(r.get(), expected); 125 r.reset(); 126 }); 127 bb.clear(); 128 } 129 } 130 131 // FIXME: use maxValue in the test 132 133 @Test 134 // FIXME: tune values for better coverage 135 public void integerWriteChunked() { 136 ByteBuffer bb = ByteBuffer.allocate(6); 137 IntegerWriter w = new IntegerWriter(); 138 IntegerReader r = new IntegerReader(); 139 for (int i = 0; i < 1024; i++) { // number of tests 140 final int N = 1 + rnd.nextInt(8); 141 final int payload = rnd.nextInt(255); 142 final int expected = rnd.nextInt(Integer.MAX_VALUE) + 1; 143 144 forEachSplit(bb, 145 (buffers) -> { 146 List<ByteBuffer> buf = new ArrayList<>(); 147 relocateBuffers(injectEmptyBuffers(buffers)).forEach(buf::add); 148 boolean written = false; 149 w.configure(expected, N, payload); // TODO: test for payload it can be read after written 150 for (ByteBuffer b : buf) { 151 int pos = b.position(); 152 written = w.write(b); 153 b.position(pos); 154 } 155 if (!written) { 156 fail("please increase bb size"); 157 } 158 r.configure(N).read(concat(buf)); 159 // TODO: check payload here 160 assertEquals(r.get(), expected); 161 w.reset(); 162 r.reset(); 163 bb.clear(); 164 }); 165 } 166 } 167 168 169 // 170 // Since readString(x) is the inverse of writeString(x), thus: 171 // 172 // for all x: readString(writeString(x)) == x 173 // 174 @Test 175 public void stringIdentity() { 176 final int MAX_STRING_LENGTH = 4096; 177 ByteBuffer bytes = ByteBuffer.allocate(MAX_STRING_LENGTH + 6); // it takes 6 bytes to encode string length of Integer.MAX_VALUE 178 CharBuffer chars = CharBuffer.allocate(MAX_STRING_LENGTH); 179 StringReader reader = new StringReader(); 180 StringWriter writer = new StringWriter(); 181 for (int len = 0; len <= MAX_STRING_LENGTH; len++) { 182 for (int i = 0; i < 64; i++) { 183 // not so much "test in isolation", I know... we're testing .reset() as well 184 bytes.clear(); 185 chars.clear(); 186 187 byte[] b = new byte[len]; 188 rnd.nextBytes(b); 189 190 String expected = new String(b, StandardCharsets.ISO_8859_1); // reference string 191 192 boolean written = writer 193 .configure(CharBuffer.wrap(expected), 0, expected.length(), false) 194 .write(bytes); 195 196 if (!written) { 197 fail("please increase 'bytes' size"); 198 } 199 bytes.flip(); 200 reader.read(bytes, chars); 201 chars.flip(); 202 assertEquals(chars.toString(), expected); 203 reader.reset(); 204 writer.reset(); 205 } 206 } 207 } 208 209 // @Test 210 // public void huffmanStringWriteChunked() { 211 // fail(); 212 // } 213 // 214 // @Test 215 // public void huffmanStringReadChunked() { 216 // fail(); 217 // } 218 219 @Test 220 public void stringWriteChunked() { 221 final int MAX_STRING_LENGTH = 8; 222 final ByteBuffer bytes = ByteBuffer.allocate(MAX_STRING_LENGTH + 6); 223 final CharBuffer chars = CharBuffer.allocate(MAX_STRING_LENGTH); 224 final StringReader reader = new StringReader(); 225 final StringWriter writer = new StringWriter(); 226 for (int len = 0; len <= MAX_STRING_LENGTH; len++) { 227 228 byte[] b = new byte[len]; 229 rnd.nextBytes(b); 230 231 String expected = new String(b, StandardCharsets.ISO_8859_1); // reference string 232 233 forEachSplit(bytes, (buffers) -> { 234 writer.configure(expected, 0, expected.length(), false); 235 boolean written = false; 236 for (ByteBuffer buf : buffers) { 237 int p0 = buf.position(); 238 written = writer.write(buf); 239 buf.position(p0); 240 } 241 if (!written) { 242 fail("please increase 'bytes' size"); 243 } 244 reader.read(concat(buffers), chars); 245 chars.flip(); 246 assertEquals(chars.toString(), expected); 247 reader.reset(); 248 writer.reset(); 249 chars.clear(); 250 bytes.clear(); 251 }); 252 } 253 } 254 255 @Test 256 public void stringReadChunked() { 257 final int MAX_STRING_LENGTH = 16; 258 final ByteBuffer bytes = ByteBuffer.allocate(MAX_STRING_LENGTH + 6); 259 final CharBuffer chars = CharBuffer.allocate(MAX_STRING_LENGTH); 260 final StringReader reader = new StringReader(); 261 final StringWriter writer = new StringWriter(); 262 for (int len = 0; len <= MAX_STRING_LENGTH; len++) { 263 264 byte[] b = new byte[len]; 265 rnd.nextBytes(b); 266 267 String expected = new String(b, StandardCharsets.ISO_8859_1); // reference string 268 269 boolean written = writer 270 .configure(CharBuffer.wrap(expected), 0, expected.length(), false) 271 .write(bytes); 272 writer.reset(); 273 274 if (!written) { 275 fail("please increase 'bytes' size"); 276 } 277 bytes.flip(); 278 279 forEachSplit(bytes, (buffers) -> { 280 for (ByteBuffer buf : buffers) { 281 int p0 = buf.position(); 282 reader.read(buf, chars); 283 buf.position(p0); 284 } 285 chars.flip(); 286 assertEquals(chars.toString(), expected); 287 reader.reset(); 288 chars.clear(); 289 }); 290 291 bytes.clear(); 292 } 293 } 294 295 // @Test 296 // public void test_Huffman_String_Identity() { 297 // StringWriter writer = new StringWriter(); 298 // StringReader reader = new StringReader(); 299 // // 256 * 8 gives 2048 bits in case of plain 8 bit coding 300 // // 256 * 30 gives you 7680 bits or 960 bytes in case of almost 301 // // improbable event of 256 30 bits symbols in a row 302 // ByteBuffer binary = ByteBuffer.allocate(960); 303 // CharBuffer text = CharBuffer.allocate(960 / 5); // 5 = minimum code length 304 // for (int len = 0; len < 128; len++) { 305 // for (int i = 0; i < 256; i++) { 306 // // not so much "test in isolation", I know... 307 // binary.clear(); 308 // 309 // byte[] bytes = new byte[len]; 310 // rnd.nextBytes(bytes); 311 // 312 // String s = new String(bytes, StandardCharsets.ISO_8859_1); 313 // 314 // writer.write(CharBuffer.wrap(s), binary, true); 315 // binary.flip(); 316 // reader.read(binary, text); 317 // text.flip(); 318 // assertEquals(text.toString(), s); 319 // } 320 // } 321 // } 322 323 // TODO: atomic failures: e.g. readonly/overflow 324 325 private static byte[] bytes(int... data) { 326 byte[] bytes = new byte[data.length]; 327 for (int i = 0; i < data.length; i++) { 328 bytes[i] = (byte) data[i]; 329 } 330 return bytes; 331 } 332 333 private static void verifyRead(byte[] data, int expected, int N) { 334 ByteBuffer buf = ByteBuffer.wrap(data, 0, data.length); 335 IntegerReader reader = new IntegerReader(); 336 reader.configure(N).read(buf); 337 assertEquals(expected, reader.get()); 338 } 339 340 private void verifyWrite(byte[] expected, int data, int N) { 341 IntegerWriter w = new IntegerWriter(); 342 ByteBuffer buf = ByteBuffer.allocate(2 * expected.length); 343 w.configure(data, N, 1).write(buf); 344 buf.flip(); 345 assertEquals(ByteBuffer.wrap(expected), buf); 346 } 347 }