/*
* Copyright 2014 Red Hat, Inc.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Apache License v2.0 which accompanies this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* The Apache License v2.0 is available at
* http://www.opensource.org/licenses/apache2.0.php
*
* You may elect to redistribute this code under either of these licenses.
*/
package io.vertx.test.core;
import io.vertx.core.Handler;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.parsetools.RecordParser;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import static io.vertx.test.core.TestUtils.assertNullPointerException;
import static org.junit.Assert.assertEquals;
/**
* @author <a href="http://tfox.org">Tim Fox</a>
* @author <a href="mailto:larsdtimm@gmail.com">Lars Timm</a>
*/
public class RecordParserTest {
@Test
public void testIllegalArguments() throws Exception {
assertNullPointerException(() -> RecordParser.newDelimited((Buffer) null, handler -> {}));
assertNullPointerException(() -> RecordParser.newDelimited((String) null, handler -> {}));
RecordParser parser = RecordParser.newDelimited("", handler -> {});
assertNullPointerException(() -> parser.setOutput(null));
assertNullPointerException(() -> parser.delimitedMode((Buffer) null));
assertNullPointerException(() -> parser.delimitedMode((String) null));
}
@Test
/*
Test parsing with delimiters
*/
public void testDelimited() {
delimited(Buffer.buffer().appendByte((byte)'\n'));
delimited(Buffer.buffer().appendByte((byte) '\r').appendByte((byte) '\n'));
delimited(Buffer.buffer(new byte[]{0, 3, 2, 5, 6, 4, 6}));
}
@Test
/*
Test parsing with fixed size records
*/
public void testFixed() {
int lines = 50;
Buffer[] expected = new Buffer[lines];
//We create lines of length zero to <lines> and shuffle them
List<Buffer> lineList = generateLines(lines, false, (byte) 0);
expected = lineList.toArray(expected);
int totLength = lines * (lines - 1) / 2; // The sum of 0...(lines - 1)
Buffer inp = Buffer.buffer(totLength);
for (int i = 0; i < lines; i++) {
inp.appendBuffer(expected[i]);
}
//We then try every combination of chunk size up to twice the input string length
for (int i = 1; i < inp.length() * 2; i++) {
doTestFixed(inp, new Integer[]{i}, expected);
}
//Then we try a sequence of random chunk sizes
List<Integer> chunkSizes = generateChunkSizes(lines);
//Repeat a few times
for (int i = 0; i < 10; i++) {
Collections.shuffle(chunkSizes);
doTestFixed(inp, chunkSizes.toArray(new Integer[]{}), expected);
}
}
@Test
/*
Test mixture of fixed and delimited
*/
public void testMixed() {
final int lines = 8;
final List<Object> types = new ArrayList<Object>();
class MyHandler implements Handler<Buffer> {
RecordParser parser = RecordParser.newFixed(10, this);
int pos;
public void handle(Buffer buff) {
if (pos < lines) {
Object type = types.get(pos);
if (type instanceof byte[]) {
byte[] bytes = (byte[]) type;
parser.delimitedMode(Buffer.buffer(bytes));
} else {
int length = (Integer) type;
parser.fixedSizeMode(length);
}
}
}
}
MyHandler out = new MyHandler();
Buffer[] expected = new Buffer[lines];
Buffer input = Buffer.buffer(100);
expected[0] = TestUtils.randomBuffer(10);
input.appendBuffer(expected[0]);
types.add(expected[0].length());
expected[1] = TestUtils.randomBuffer(100);
input.appendBuffer(expected[1]);
types.add(expected[1].length());
byte[] delim = new byte[]{23, -120, 100, 3};
expected[2] = TestUtils.randomBuffer(50, true, delim[0]);
input.appendBuffer(expected[2]);
types.add(delim);
input.appendBuffer(Buffer.buffer(delim));
expected[3] = TestUtils.randomBuffer(1000);
input.appendBuffer(expected[3]);
types.add(expected[3].length());
expected[4] = TestUtils.randomBuffer(230, true, delim[0]);
input.appendBuffer(expected[4]);
types.add(delim);
input.appendBuffer(Buffer.buffer(delim));
delim = new byte[]{17};
expected[5] = TestUtils.randomBuffer(341, true, delim[0]);
input.appendBuffer(expected[5]);
types.add(delim);
input.appendBuffer(Buffer.buffer(delim));
delim = new byte[]{54, -32, 0};
expected[6] = TestUtils.randomBuffer(1234, true, delim[0]);
input.appendBuffer(expected[6]);
types.add(delim);
input.appendBuffer(Buffer.buffer(delim));
expected[7] = TestUtils.randomBuffer(100);
input.appendBuffer(expected[7]);
types.add(expected[7].length());
feedChunks(input, out.parser, new Integer[]{50, 10, 3});
}
/*
We create some input dataHandler which contains <lines> lines of lengths in randm order between 0 and lines
And then passes them into the RecordParser in chunk sizes from 0 to twice the total input buffer size
*/
private void delimited(Buffer delim) {
int lines = 50;
Buffer[] expected = new Buffer[lines];
//We create lines of length zero to <lines> and shuffle them
List<Buffer> lineList = generateLines(lines, true, delim.getByte(0));
expected = lineList.toArray(expected);
int totLength = lines * (lines - 1) / 2; // The sum of 0...(lines - 1)
Buffer inp = Buffer.buffer(totLength + lines * delim.length());
for (int i = 0; i < lines; i++) {
inp.appendBuffer(expected[i]);
inp.appendBuffer(delim);
}
//We then try every combination of chunk size up to twice the input string length
for (int i = 1; i < inp.length() * 2; i++) {
doTestDelimited(inp, delim, new Integer[]{i}, expected);
}
//Then we try a sequence of random chunk sizes
List<Integer> chunkSizes = generateChunkSizes(lines);
//Repeat a few times
for (int i = 0; i < 10; i++) {
Collections.shuffle(chunkSizes);
doTestDelimited(inp, delim, chunkSizes.toArray(new Integer[]{}), expected);
}
}
private void doTestDelimited(final Buffer input, Buffer delim, Integer[] chunkSizes, final Buffer... expected) {
final Buffer[] results = new Buffer[expected.length];
Handler<Buffer> out = new Handler<Buffer>() {
int pos;
public void handle(Buffer buff) {
results[pos++] = buff;
}
};
RecordParser parser = RecordParser.newDelimited(delim, out);
feedChunks(input, parser, chunkSizes);
checkResults(expected, results);
}
private void doTestFixed(final Buffer input, Integer[] chunkSizes, final Buffer... expected) {
final Buffer[] results = new Buffer[expected.length];
class MyHandler implements Handler<Buffer> {
int pos;
RecordParser parser = RecordParser.newFixed(expected[0].length(), this);
public void handle(Buffer buff) {
results[pos++] = buff;
if (pos < expected.length) {
parser.fixedSizeMode(expected[pos].length());
}
}
}
MyHandler out = new MyHandler();
feedChunks(input, out.parser, chunkSizes);
checkResults(expected, results);
}
private void feedChunks(Buffer input, RecordParser parser, Integer[] chunkSizes) {
int pos = 0;
int chunkPos = 0;
while (pos < input.length()) {
int chunkSize = chunkSizes[chunkPos++];
if (chunkPos == chunkSizes.length) chunkPos = 0;
int end = pos + chunkSize;
end = end <= input.length() ? end : input.length();
Buffer sub = input.getBuffer(pos, end);
parser.handle(sub);
pos += chunkSize;
}
}
private void checkResults(Buffer[] expected, Buffer[] results) {
for (int i = 0; i < expected.length; i++) {
assertEquals("Expected:" + expected[i] + " length:" + expected[i].length() +
" Actual:" + results[i] + " length:" + results[i].length(), expected[i], results[i]);
}
}
private List<Buffer> generateLines(int lines, boolean delim, byte delimByte) {
//We create lines of length one to <lines> and shuffle them
List<Buffer> lineList = new ArrayList<Buffer>();
for (int i = 0; i < lines; i++) {
lineList.add(TestUtils.randomBuffer(i + 1, delim, delimByte));
}
Collections.shuffle(lineList);
return lineList;
}
private List<Integer> generateChunkSizes(int lines) {
//Then we try a sequence of random chunk sizes
List<Integer> chunkSizes = new ArrayList<Integer>();
for (int i = 1; i < lines / 5; i++) {
chunkSizes.add(i);
}
return chunkSizes;
}
@Test
/*
* test issue-209
*/
public void testSpreadDelimiter() {
doTestDelimited(Buffer.buffer("start-a-b-c-dddabc"), Buffer.buffer("abc"),
new Integer[] { 18 }, Buffer.buffer("start-a-b-c-ddd"));
doTestDelimited(Buffer.buffer("start-abc-dddabc"), Buffer.buffer("abc"),
new Integer[] { 18 }, Buffer.buffer("start-"), Buffer.buffer("-ddd"));
doTestDelimited(Buffer.buffer("start-ab-c-dddabc"), Buffer.buffer("abc"),
new Integer[] { 18 }, Buffer.buffer("start-ab-c-ddd"));
}
}