0

test: NetInputStreamTest, NetOutputStreamTest

This commit is contained in:
2020-05-02 05:18:16 +03:00
parent a293ae021d
commit c67d9f9a6c
6 changed files with 609 additions and 7 deletions

View File

@@ -17,6 +17,7 @@ repositories {
ext {
slf4j_version = '1.7.25'
lombok_version = '1.18.2'
junit_version = '5.5.2'
}
dependencies {
@@ -29,5 +30,14 @@ dependencies {
/* LOMBOK */
annotationProcessor (group: 'org.projectlombok', name: 'lombok', version: lombok_version)
compileOnly (group: 'org.projectlombok', name: 'lombok', version: lombok_version)
/* TESTING */
testImplementation (group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: junit_version)
testRuntimeOnly (group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: junit_version)
testImplementation (group: 'org.junit.jupiter', name: 'junit-jupiter-params', version: junit_version)
testImplementation (group: 'org.apache.commons', name: 'commons-lang3', version: '3.9')
}
test {
useJUnitPlatform()
}

View File

@@ -1,13 +1,11 @@
package mc.protocol.io.coder;
import mc.protocol.io.NetOutputStream;
package mc.protocol.io;
import java.io.ByteArrayOutputStream;
class ByteArrayNetOutputStream extends NetOutputStream {
public class ByteArrayNetOutputStream extends NetOutputStream {
//TODO может заменить на DataOutputStream?
private ByteArrayOutputStream baos = new ByteArrayOutputStream();
private final ByteArrayOutputStream baos = new ByteArrayOutputStream();
@Override
public void writeByte(int value) {
@@ -55,11 +53,11 @@ class ByteArrayNetOutputStream extends NetOutputStream {
writeLong(Double.doubleToLongBits(value));
}
int size() {
public int size() {
return baos.size();
}
byte[] toByteArray() {
public byte[] toByteArray() {
return baos.toByteArray();
}
}

View File

@@ -4,6 +4,7 @@ import lombok.RequiredArgsConstructor;
import mc.protocol.Packet;
import mc.protocol.PacketDirection;
import mc.protocol.State;
import mc.protocol.io.ByteArrayNetOutputStream;
import mc.protocol.io.NetOutputStream;
import java.util.Objects;

View File

@@ -0,0 +1,63 @@
package mc.protocol.io;
import java.nio.ByteBuffer;
class ByteArrayNetInputStream extends NetInputStream {
private final ByteBuffer byteBuffer;
private int index = 0;
public ByteArrayNetInputStream(byte[] buffer) {
byteBuffer = ByteBuffer.wrap(buffer);
}
@Override
public void markReadIndex() {
index = byteBuffer.position();
}
@Override
public void resetReadIndex() {
byteBuffer.position(index);
}
@Override
public int readableBytes() {
return byteBuffer.limit(); //TODO нужно простестировать
}
@Override
public byte readByte() {
return byteBuffer.get();
}
@Override
public int readBytes(byte[] buffer, int offset, int lengtn) {
return readableBytes() - byteBuffer.get(buffer, offset, lengtn).remaining();
}
@Override
public int readShort() {
return byteBuffer.getShort();
}
@Override
public int readInt() {
return byteBuffer.getInt();
}
@Override
public long readLong() {
return byteBuffer.getLong();
}
@Override
public float readFloat() {
return byteBuffer.getFloat();
}
@Override
public double readDouble() {
return byteBuffer.getDouble();
}
}

View File

@@ -0,0 +1,300 @@
package mc.protocol.io;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Random;
import java.util.UUID;
import java.util.stream.Stream;
import static org.junit.jupiter.api.Assertions.*;
class NetInputStreamTest {
private Random random;
private ByteArrayOutputStream baos;
@BeforeEach
void setUp() {
random = new Random(System.currentTimeMillis());
baos = new ByteArrayOutputStream();
}
@ParameterizedTest
@MethodSource("paramsReadBoolean")
void readBoolean(byte sourceByte, boolean expectedValue) {
baos.write(sourceByte);
NetInputStream netInputStream = createNetInputStream(baos.toByteArray());
assertEquals(expectedValue, netInputStream.readBoolean());
}
@Test
void readByte() {
byte b = Integer.valueOf(random.nextInt()).byteValue();
baos.write(b);
assertEquals(b, createNetInputStream(baos.toByteArray()).readByte());
assertEquals(b, createNetInputStream(baos.toByteArray()).read());
baos.reset();
baos.write(128);
assertEquals(-128, createNetInputStream(baos.toByteArray()).readByte());
}
@Test
void readUnsignedByte() {
int value = 128;
baos.write(value);
assertEquals(value, createNetInputStream(baos.toByteArray()).readUnsignedByte());
}
@Test
void readShort() throws IOException {
int value = Integer.valueOf(random.nextInt()).shortValue();
createDataOutputStream().writeShort(value);
assertEquals(value, createNetInputStream(baos.toByteArray()).readShort());
baos.reset();
createDataOutputStream().writeShort(32768);
assertEquals(-32768, createNetInputStream(baos.toByteArray()).readShort());
}
@Test
void readUnsignedShort() throws IOException {
int value = 32768;
createDataOutputStream().writeShort(value);
assertEquals(value, createNetInputStream(baos.toByteArray()).readUnsignedShort());
}
@ParameterizedTest
@MethodSource("paramsReadUnsignedByte")
void readUnsignedByte(byte sourceByte, int expectedValue) {
baos.write(sourceByte);
assertEquals(expectedValue, createNetInputStream(baos.toByteArray()).readUnsignedByte());
}
@ParameterizedTest
@MethodSource("paramsReadString")
void readString(String string) throws IOException {
final byte[] strBytes = string.getBytes(StandardCharsets.UTF_8);
final byte[] bytes = new byte[strBytes.length + 1];
bytes[0] = (byte) string.codePoints().count(); // здесь считается, что размер поместится в один байт
System.arraycopy(strBytes, 0, bytes, 1, strBytes.length);
baos.write(bytes);
assertEquals(string, createNetInputStream(baos.toByteArray()).readString());
}
@Test
void readString_overSize() throws IOException {
String string = "123";
final byte[] strBytes = string.getBytes(StandardCharsets.UTF_8);
final byte[] bytes = new byte[strBytes.length + 1];
final int length = string.length();
bytes[0] = (byte) (length + 1); // здесь считается, что размер поместится в один байт
System.arraycopy(strBytes, 0, bytes, 1, strBytes.length);
baos.write(bytes);
assertThrows(DecoderException.class, () -> createNetInputStream(baos.toByteArray()).readString(length));
}
@Test
void readString_lessZero() throws IOException {
String string = "123";
final byte[] strBytes = string.getBytes(StandardCharsets.UTF_8);
final byte[] bytes = new byte[strBytes.length + 5];
bytes[0] = (byte) 0xFF;
bytes[1] = (byte) 0xFF;
bytes[2] = (byte) 0xFF;
bytes[3] = (byte) 0xFF;
bytes[4] = (byte) 0x0F;
System.arraycopy(strBytes, 0, bytes, 5, strBytes.length);
baos.write(bytes);
assertThrows(DecoderException.class, () -> createNetInputStream(baos.toByteArray()).readString(-1));
}
@ParameterizedTest
@MethodSource("paramsReadVarInt")
void readVarInt(byte[] sourceBytes, int expectedValue) throws IOException {
baos.write(sourceBytes);
assertEquals(expectedValue, createNetInputStream(baos.toByteArray()).readVarInt());
}
@Test
void readVarInt_tooBig() throws IOException {
baos.write(new byte[]{ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0x0F });
assertEquals(-1, createNetInputStream(baos.toByteArray()).readVarInt());
}
@ParameterizedTest
@MethodSource({"paramsReadVarInt", "paramsReadVarLong"})
void readVarLong(byte[] sourceBytes, long expectedValue) throws IOException {
baos.write(sourceBytes);
assertEquals(expectedValue, createNetInputStream(baos.toByteArray()).readVarLong());
}
@Test
void readVarLong_tooBig() throws IOException {
baos.write(new byte[]{ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
(byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
(byte) 0xFF, (byte) 0x0F });
assertEquals(-1, createNetInputStream(baos.toByteArray()).readVarLong());
}
@Test
void readUUID() throws IOException {
final UUID uuid = UUID.randomUUID();
final long mostSignificantBits = uuid.getMostSignificantBits();
final long leastSignificantBits = uuid.getLeastSignificantBits();
baos.write(new byte[]{
(byte) ((mostSignificantBits >>> 56) & 0xFF),
(byte) ((mostSignificantBits >>> 48) & 0xFF),
(byte) ((mostSignificantBits >>> 40) & 0xFF),
(byte) ((mostSignificantBits >>> 32) & 0xFF),
(byte) ((mostSignificantBits >>> 24) & 0xFF),
(byte) ((mostSignificantBits >>> 16) & 0xFF),
(byte) ((mostSignificantBits >>> 8) & 0xFF),
(byte) (mostSignificantBits & 0xFF)
});
baos.write(new byte[]{
(byte) ((leastSignificantBits >>> 56) & 0xFF),
(byte) ((leastSignificantBits >>> 48) & 0xFF),
(byte) ((leastSignificantBits >>> 40) & 0xFF),
(byte) ((leastSignificantBits >>> 32) & 0xFF),
(byte) ((leastSignificantBits >>> 24) & 0xFF),
(byte) ((leastSignificantBits >>> 16) & 0xFF),
(byte) ((leastSignificantBits >>> 8) & 0xFF),
(byte) (leastSignificantBits & 0xFF)
});
assertEquals(uuid, createNetInputStream(baos.toByteArray()).readUUID());
}
@Test
void readBytes() throws IOException {
byte[] bytes = new byte[128];
random.nextBytes(bytes);
baos.write(bytes);
byte[] actualBytes = new byte[128];
createNetInputStream(baos.toByteArray()).readBytes(actualBytes);
assertArrayEquals(bytes, actualBytes);
actualBytes = new byte[128];
int read = createNetInputStream(baos.toByteArray()).read(actualBytes);
assertArrayEquals(bytes, actualBytes);
assertEquals(128, read);
}
@Test
void read_offset() throws IOException {
byte[] bytes = new byte[128];
random.nextBytes(bytes);
baos.write(bytes);
byte[] actualBytes = new byte[128];
int read = createNetInputStream(baos.toByteArray()).read(actualBytes, 3, 11);
assertEquals(11, read);
byte[] buff1 = new byte[11];
System.arraycopy(bytes, 0, buff1, 0, 11);
byte[] buff2 = new byte[11];
System.arraycopy(actualBytes, 3, buff2, 0, 11);
assertArrayEquals(buff1, buff2);
}
private NetInputStream createNetInputStream(byte[] buffer) {
return new ByteArrayNetInputStream(buffer);
}
private DataOutputStream createDataOutputStream() {
return new DataOutputStream(baos);
}
private static Stream<Arguments> paramsReadBoolean() {
return Stream.of(
Arguments.of((byte) 0x00, false),
Arguments.of((byte) 0x01, true)
);
}
private static Stream<Arguments> paramsReadUnsignedByte() {
return Stream.of(
Arguments.of((byte) 30, 30),
Arguments.of((byte) (0xFF & 130), 130)
);
}
private static Stream<Arguments> paramsReadString() {
return Stream.of(
Arguments.of(""),
Arguments.of("Latin"),
Arguments.of("Кириллица"),
Arguments.of("العربية"),
Arguments.of("ﬦﬣﬡ"), // Алфавитные формы представления
Arguments.of("\uD800\uDD07") // Эгейские цифры, [один]
);
}
private static Stream<Arguments> paramsReadVarInt() {
return Stream.of(
Arguments.of(new byte[]{ 0x78 }, 120),
Arguments.of(new byte[]{ (byte) 0xE0, 0x5D }, 12000),
Arguments.of(new byte[]{ (byte) 0xC0, (byte) 0xA9, 0x07 }, 120000),
Arguments.of(new byte[]{ (byte) 0x80, (byte) 0x9C, (byte) 0x9C, (byte) 0x39 }, 120_000_000),
Arguments.of(new byte[]{ (byte) 0x80, (byte) 0x98, (byte) 0x9A, (byte) 0xBC, 0x04 }, 1_200_000_000)
);
}
private static Stream<Arguments> paramsReadVarLong() {
return Stream.of(
Arguments.of(
new byte[]{ (byte) 0x80, (byte) 0xF0, (byte) 0x85, (byte) 0xDA, 0x2C },
12_000_000_000L),
Arguments.of(
new byte[]{ (byte) 0x80, (byte) 0xE0, (byte) 0xBA, (byte) 0x84, (byte) 0xBF, 0x03 },
120_000_000_000L),
Arguments.of(
new byte[]{ (byte) 0x80, (byte) 0x80, (byte) 0xF3, (byte) 0xBD, (byte) 0x9F, (byte) 0xDD,
0x02 },
12_000_000_000_000L),
Arguments.of(
new byte[]{ (byte) 0x80, (byte) 0x80, (byte) 0xEC, (byte) 0xAD, (byte) 0xCC, (byte) 0xEC,
(byte) 0x90, 0x02},
1_200_000_000_000_000L),
Arguments.of(
new byte[]{ (byte) 0x80, (byte) 0x80, (byte) 0xB0, (byte) 0xE8, (byte) 0xD3, (byte) 0xEB,
(byte) 0x94, (byte) 0xD5, 0x01 },
120_000_000_000_000_000L),
Arguments.of(
new byte[]{ (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80,
(byte) 0x80, (byte) 0x80, (byte) 0x80, 0x01 },
Long.MIN_VALUE)
);
}
}

View File

@@ -0,0 +1,230 @@
package mc.protocol.io;
import org.apache.commons.lang3.RandomStringUtils;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Random;
import java.util.UUID;
import java.util.stream.Stream;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
class NetOutputStreamTest {
private static Random random;
@BeforeAll
static void setUp() {
random = new Random(System.currentTimeMillis());
}
@ParameterizedTest
@MethodSource("paramsWriteBoolean")
void writeBoolean(boolean sourceValue, byte expectedByte) {
NetOutputStream netOutputStream = createNetOutputStream();
netOutputStream.writeBoolean(sourceValue);
assertEquals(expectedByte, toByteArray(netOutputStream)[0]);
}
@ParameterizedTest
@MethodSource("paramsWriteByte")
void writeByte(byte sourceValue, byte expectedByte) throws IOException {
NetOutputStream netOutputStream = createNetOutputStream();
netOutputStream.writeByte(sourceValue);
assertEquals(expectedByte, toByteArray(netOutputStream)[0]);
netOutputStream = createNetOutputStream();
netOutputStream.write(sourceValue);
assertEquals(expectedByte, toByteArray(netOutputStream)[0]);
}
@ParameterizedTest
@MethodSource("paramsWriteString")
void writeString(String string) {
NetOutputStream netOutputStream = createNetOutputStream();
netOutputStream.writeString(string);
byte[] bytes = toByteArray(netOutputStream);
int length = bytes[0];
assertEquals(string.codePoints().count(), length);
byte[] dataBytes = new byte[bytes.length - 1];
System.arraycopy(bytes, 1, dataBytes, 0, dataBytes.length);
assertEquals(string, new String(dataBytes, StandardCharsets.UTF_8));
}
@Test
void writeString_overSize() {
String overSizeString = RandomStringUtils.randomAscii(Short.MAX_VALUE + Short.MAX_VALUE);
NetOutputStream netOutputStream = createNetOutputStream();
netOutputStream.writeString(overSizeString);
NetInputStream netInputStream = new ByteArrayNetInputStream(toByteArray(netOutputStream));
String actualString = netInputStream.readString();
String expectedString = overSizeString.substring(0, Short.MAX_VALUE);
assertEquals(expectedString, actualString);
}
@ParameterizedTest
@MethodSource("paramsWriteVarInt")
void writeVarInt(int sourceValue, byte[] expectedBytes) {
NetOutputStream netOutputStream = createNetOutputStream();
netOutputStream.writeVarInt(sourceValue);
assertArrayEquals(expectedBytes, toByteArray(netOutputStream));
}
@ParameterizedTest
@MethodSource({"paramsWriteVarInt", "paramsWriteVarLong"})
void writeVarLong(long sourceValue, byte[] expectedBytes) {
NetOutputStream netOutputStream = createNetOutputStream();
netOutputStream.writeVarLong(sourceValue);
assertArrayEquals(expectedBytes, toByteArray(netOutputStream));
}
@Test
void writeUUID() {
final UUID uuid = UUID.randomUUID();
NetOutputStream netOutputStream = createNetOutputStream();
netOutputStream.writeUUID(uuid);
final long mostSignificantBits = uuid.getMostSignificantBits();
final long leastSignificantBits = uuid.getLeastSignificantBits();
assertArrayEquals(new byte[]{ (byte) ((mostSignificantBits >>> 56) & 0xFF),
(byte) ((mostSignificantBits >>> 48) & 0xFF),
(byte) ((mostSignificantBits >>> 40) & 0xFF),
(byte) ((mostSignificantBits >>> 32) & 0xFF),
(byte) ((mostSignificantBits >>> 24) & 0xFF),
(byte) ((mostSignificantBits >>> 16) & 0xFF),
(byte) ((mostSignificantBits >>> 8) & 0xFF),
(byte) (mostSignificantBits & 0xFF),
(byte) ((leastSignificantBits >>> 56) & 0xFF),
(byte) ((leastSignificantBits >>> 48) & 0xFF),
(byte) ((leastSignificantBits >>> 40) & 0xFF),
(byte) ((leastSignificantBits >>> 32) & 0xFF),
(byte) ((leastSignificantBits >>> 24) & 0xFF),
(byte) ((leastSignificantBits >>> 16) & 0xFF),
(byte) ((leastSignificantBits >>> 8) & 0xFF),
(byte) (leastSignificantBits & 0xFF) },
toByteArray(netOutputStream));
}
@Test
void writeBytes() throws IOException {
byte[] bytes = new byte[128];
random.nextBytes(bytes);
NetOutputStream netOutputStream = createNetOutputStream();
netOutputStream.writeBytes(bytes);
assertArrayEquals(bytes, toByteArray(netOutputStream));
netOutputStream = createNetOutputStream();
netOutputStream.write(bytes);
assertArrayEquals(bytes, toByteArray(netOutputStream));
}
@Test
void write_offset() throws IOException {
byte[] bytes = new byte[128];
random.nextBytes(bytes);
NetOutputStream netOutputStream = createNetOutputStream();
netOutputStream.write(bytes, 3, 11);
byte[] actualBytes = new byte[11];
System.arraycopy(toByteArray(netOutputStream), 0, actualBytes, 0, 11);
byte[] expectedBytes = new byte[11];
System.arraycopy(bytes, 3, expectedBytes, 0, 11);
assertArrayEquals(expectedBytes, actualBytes);
}
private NetOutputStream createNetOutputStream() {
return new ByteArrayNetOutputStream();
}
private byte[] toByteArray(NetOutputStream netOutputStream) {
return ((ByteArrayNetOutputStream) netOutputStream).toByteArray();
}
private static Stream<Arguments> paramsWriteBoolean() {
return Stream.of(
Arguments.of(false, (byte) 0x00),
Arguments.of(true, (byte) 0x01)
);
}
private static Stream<Arguments> paramsWriteByte() {
byte b = Integer.valueOf(random.nextInt()).byteValue();
return Stream.of(
Arguments.of(b, b),
Arguments.of((byte) 128, (byte) -128)
);
}
private static Stream<Arguments> paramsWriteString() {
return Stream.of(
Arguments.of(""),
Arguments.of("Latin"),
Arguments.of("Кириллица"),
Arguments.of("العربية"),
Arguments.of("ﬦﬣﬡ"), // Алфавитные формы представления
Arguments.of("\uD800\uDD07") // Эгейские цифры, [один]
);
}
private static Stream<Arguments> paramsWriteVarInt() {
return Stream.of(
Arguments.of(120, new byte[]{ 0x78 }),
Arguments.of(12000, new byte[]{ (byte) 0xE0, 0x5D }),
Arguments.of(120000, new byte[]{ (byte) 0xC0, (byte) 0xA9, 0x07 }),
Arguments.of(120000000, new byte[]{ (byte) 0x80, (byte) 0x9C, (byte) 0x9C, (byte) 0x39 }),
Arguments.of(1200000000, new byte[]{ (byte) 0x80, (byte) 0x98, (byte) 0x9A, (byte) 0xBC, 0x04 })
);
}
private static Stream<Arguments> paramsWriteVarLong() {
return Stream.of(
Arguments.of(
12_000_000_000L,
new byte[]{ (byte) 0x80, (byte) 0xF0, (byte) 0x85, (byte) 0xDA, 0x2C }),
Arguments.of(
120_000_000_000L,
new byte[]{ (byte) 0x80, (byte) 0xE0, (byte) 0xBA, (byte) 0x84, (byte) 0xBF, 0x03 }),
Arguments.of(
12_000_000_000_000L,
new byte[]{ (byte) 0x80, (byte) 0x80, (byte) 0xF3, (byte) 0xBD, (byte) 0x9F, (byte) 0xDD,
0x02 }),
Arguments.of(
1_200_000_000_000_000L,
new byte[]{ (byte) 0x80, (byte) 0x80, (byte) 0xEC, (byte) 0xAD, (byte) 0xCC, (byte) 0xEC,
(byte) 0x90, 0x02}),
Arguments.of(
120_000_000_000_000_000L,
new byte[]{ (byte) 0x80, (byte) 0x80, (byte) 0xB0, (byte) 0xE8, (byte) 0xD3, (byte) 0xEB,
(byte) 0x94, (byte) 0xD5, 0x01 }),
Arguments.of(
Long.MIN_VALUE,
new byte[]{ (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80,
(byte) 0x80, (byte) 0x80, (byte) 0x80, 0x01 })
);
}
}