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
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
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);
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 }
|
1 /*
2 * Copyright (c) 2014, 2017, 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.io.IOException;
28 import java.io.UncheckedIOException;
29 import java.nio.ByteBuffer;
30 import java.nio.CharBuffer;
31 import java.nio.charset.StandardCharsets;
32 import java.util.ArrayList;
33 import java.util.List;
34 import java.util.Random;
35
36 import static org.testng.Assert.assertEquals;
37 import static org.testng.Assert.fail;
38 import static jdk.incubator.http.internal.hpack.BuffersTestingKit.*;
39 import static jdk.incubator.http.internal.hpack.TestHelper.newRandom;
40
41 //
42 // Some of the tests below overlap in what they test. This allows to diagnose
43 // bugs quicker and with less pain by simply ruling out common working bits.
44 //
45 public final class BinaryPrimitivesTest {
46
47 private final Random rnd = newRandom();
48
65 public void integerWrite1() {
66 verifyWrite(bytes(0b00011111, 0b10011010, 0b00001010), 1337, 5);
67 }
68
69 @Test
70 public void integerWrite2() {
71 verifyWrite(bytes(0b00001010), 10, 5);
72 }
73
74 @Test
75 public void integerWrite3() {
76 verifyWrite(bytes(0b00101010), 42, 8);
77 }
78
79 //
80 // Since readInteger(x) is the inverse of writeInteger(x), thus:
81 //
82 // for all x: readInteger(writeInteger(x)) == x
83 //
84 @Test
85 public void integerIdentity() throws IOException {
86 final int MAX_VALUE = 1 << 22;
87 int totalCases = 0;
88 int maxFilling = 0;
89 IntegerReader r = new IntegerReader();
90 IntegerWriter w = new IntegerWriter();
91 ByteBuffer buf = ByteBuffer.allocate(8);
92 for (int N = 1; N < 9; N++) {
93 for (int expected = 0; expected <= MAX_VALUE; expected++) {
94 w.reset().configure(expected, N, 1).write(buf);
95 buf.flip();
96 totalCases++;
97 maxFilling = Math.max(maxFilling, buf.remaining());
98 r.reset().configure(N).read(buf);
99 assertEquals(r.get(), expected);
100 buf.clear();
101 }
102 }
103 System.out.printf("totalCases: %,d, maxFilling: %,d, maxValue: %,d%n",
104 totalCases, maxFilling, MAX_VALUE);
105 }
106
107 @Test
108 public void integerReadChunked() {
109 final int NUM_TESTS = 1024;
110 IntegerReader r = new IntegerReader();
111 ByteBuffer bb = ByteBuffer.allocate(8);
112 IntegerWriter w = new IntegerWriter();
113 for (int i = 0; i < NUM_TESTS; i++) {
114 final int N = 1 + rnd.nextInt(8);
115 final int expected = rnd.nextInt(Integer.MAX_VALUE) + 1;
116 w.reset().configure(expected, N, rnd.nextInt()).write(bb);
117 bb.flip();
118
119 forEachSplit(bb,
120 (buffers) -> {
121 Iterable<? extends ByteBuffer> buf = relocateBuffers(injectEmptyBuffers(buffers));
122 r.configure(N);
123 for (ByteBuffer b : buf) {
124 try {
125 r.read(b);
126 } catch (IOException e) {
127 throw new UncheckedIOException(e);
128 }
129 }
130 assertEquals(r.get(), expected);
131 r.reset();
132 });
133 bb.clear();
134 }
135 }
136
137 // FIXME: use maxValue in the test
138
139 @Test
140 // FIXME: tune values for better coverage
141 public void integerWriteChunked() {
142 ByteBuffer bb = ByteBuffer.allocate(6);
143 IntegerWriter w = new IntegerWriter();
144 IntegerReader r = new IntegerReader();
145 for (int i = 0; i < 1024; i++) { // number of tests
146 final int N = 1 + rnd.nextInt(8);
147 final int payload = rnd.nextInt(255);
148 final int expected = rnd.nextInt(Integer.MAX_VALUE) + 1;
149
150 forEachSplit(bb,
151 (buffers) -> {
152 List<ByteBuffer> buf = new ArrayList<>();
153 relocateBuffers(injectEmptyBuffers(buffers)).forEach(buf::add);
154 boolean written = false;
155 w.configure(expected, N, payload); // TODO: test for payload it can be read after written
156 for (ByteBuffer b : buf) {
157 int pos = b.position();
158 written = w.write(b);
159 b.position(pos);
160 }
161 if (!written) {
162 fail("please increase bb size");
163 }
164 try {
165 r.configure(N).read(concat(buf));
166 } catch (IOException e) {
167 throw new UncheckedIOException(e);
168 }
169 // TODO: check payload here
170 assertEquals(r.get(), expected);
171 w.reset();
172 r.reset();
173 bb.clear();
174 });
175 }
176 }
177
178
179 //
180 // Since readString(x) is the inverse of writeString(x), thus:
181 //
182 // for all x: readString(writeString(x)) == x
183 //
184 @Test
185 public void stringIdentity() throws IOException {
186 final int MAX_STRING_LENGTH = 4096;
187 ByteBuffer bytes = ByteBuffer.allocate(MAX_STRING_LENGTH + 6); // it takes 6 bytes to encode string length of Integer.MAX_VALUE
188 CharBuffer chars = CharBuffer.allocate(MAX_STRING_LENGTH);
189 StringReader reader = new StringReader();
190 StringWriter writer = new StringWriter();
191 for (int len = 0; len <= MAX_STRING_LENGTH; len++) {
192 for (int i = 0; i < 64; i++) {
193 // not so much "test in isolation", I know... we're testing .reset() as well
194 bytes.clear();
195 chars.clear();
196
197 byte[] b = new byte[len];
198 rnd.nextBytes(b);
199
200 String expected = new String(b, StandardCharsets.ISO_8859_1); // reference string
201
202 boolean written = writer
203 .configure(CharBuffer.wrap(expected), 0, expected.length(), false)
204 .write(bytes);
205
234 final StringReader reader = new StringReader();
235 final StringWriter writer = new StringWriter();
236 for (int len = 0; len <= MAX_STRING_LENGTH; len++) {
237
238 byte[] b = new byte[len];
239 rnd.nextBytes(b);
240
241 String expected = new String(b, StandardCharsets.ISO_8859_1); // reference string
242
243 forEachSplit(bytes, (buffers) -> {
244 writer.configure(expected, 0, expected.length(), false);
245 boolean written = false;
246 for (ByteBuffer buf : buffers) {
247 int p0 = buf.position();
248 written = writer.write(buf);
249 buf.position(p0);
250 }
251 if (!written) {
252 fail("please increase 'bytes' size");
253 }
254 try {
255 reader.read(concat(buffers), chars);
256 } catch (IOException e) {
257 throw new UncheckedIOException(e);
258 }
259 chars.flip();
260 assertEquals(chars.toString(), expected);
261 reader.reset();
262 writer.reset();
263 chars.clear();
264 bytes.clear();
265 });
266 }
267 }
268
269 @Test
270 public void stringReadChunked() {
271 final int MAX_STRING_LENGTH = 16;
272 final ByteBuffer bytes = ByteBuffer.allocate(MAX_STRING_LENGTH + 6);
273 final CharBuffer chars = CharBuffer.allocate(MAX_STRING_LENGTH);
274 final StringReader reader = new StringReader();
275 final StringWriter writer = new StringWriter();
276 for (int len = 0; len <= MAX_STRING_LENGTH; len++) {
277
278 byte[] b = new byte[len];
279 rnd.nextBytes(b);
280
281 String expected = new String(b, StandardCharsets.ISO_8859_1); // reference string
282
283 boolean written = writer
284 .configure(CharBuffer.wrap(expected), 0, expected.length(), false)
285 .write(bytes);
286 writer.reset();
287
288 if (!written) {
289 fail("please increase 'bytes' size");
290 }
291 bytes.flip();
292
293 forEachSplit(bytes, (buffers) -> {
294 for (ByteBuffer buf : buffers) {
295 int p0 = buf.position();
296 try {
297 reader.read(buf, chars);
298 } catch (IOException e) {
299 throw new UncheckedIOException(e);
300 }
301 buf.position(p0);
302 }
303 chars.flip();
304 assertEquals(chars.toString(), expected);
305 reader.reset();
306 chars.clear();
307 });
308
309 bytes.clear();
310 }
311 }
312
313 // @Test
314 // public void test_Huffman_String_Identity() {
315 // StringWriter writer = new StringWriter();
316 // StringReader reader = new StringReader();
317 // // 256 * 8 gives 2048 bits in case of plain 8 bit coding
318 // // 256 * 30 gives you 7680 bits or 960 bytes in case of almost
319 // // improbable event of 256 30 bits symbols in a row
320 // ByteBuffer binary = ByteBuffer.allocate(960);
334 // reader.read(binary, text);
335 // text.flip();
336 // assertEquals(text.toString(), s);
337 // }
338 // }
339 // }
340
341 // TODO: atomic failures: e.g. readonly/overflow
342
343 private static byte[] bytes(int... data) {
344 byte[] bytes = new byte[data.length];
345 for (int i = 0; i < data.length; i++) {
346 bytes[i] = (byte) data[i];
347 }
348 return bytes;
349 }
350
351 private static void verifyRead(byte[] data, int expected, int N) {
352 ByteBuffer buf = ByteBuffer.wrap(data, 0, data.length);
353 IntegerReader reader = new IntegerReader();
354 try {
355 reader.configure(N).read(buf);
356 } catch (IOException e) {
357 throw new UncheckedIOException(e);
358 }
359 assertEquals(expected, reader.get());
360 }
361
362 private void verifyWrite(byte[] expected, int data, int N) {
363 IntegerWriter w = new IntegerWriter();
364 ByteBuffer buf = ByteBuffer.allocate(2 * expected.length);
365 w.configure(data, N, 1).write(buf);
366 buf.flip();
367 assertEquals(ByteBuffer.wrap(expected), buf);
368 }
369 }
|