2019-03-25 23:05:51 +01:00
|
|
|
/* Copyright (c) 2008-2018, Nathan Sweet
|
2016-03-07 01:06:43 +01:00
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following
|
|
|
|
* conditions are met:
|
|
|
|
*
|
|
|
|
* - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
|
|
|
* - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
|
|
|
|
* disclaimer in the documentation and/or other materials provided with the distribution.
|
|
|
|
* - Neither the name of Esoteric Software nor the names of its contributors may be used to endorse or promote products derived
|
|
|
|
* from this software without specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
|
|
|
|
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
|
|
* SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
2019-03-25 23:05:51 +01:00
|
|
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
|
2014-08-20 23:44:59 +02:00
|
|
|
|
2020-08-12 23:38:56 +02:00
|
|
|
package dorkboxTest.network.kryo;
|
2019-03-25 23:05:51 +01:00
|
|
|
|
|
|
|
import static com.esotericsoftware.minlog.Log.WARN;
|
|
|
|
import static com.esotericsoftware.minlog.Log.warn;
|
|
|
|
import static org.junit.Assert.assertEquals;
|
|
|
|
import static org.junit.Assert.assertNull;
|
2016-03-06 23:50:36 +01:00
|
|
|
|
2014-08-20 23:44:59 +02:00
|
|
|
import java.io.ByteArrayInputStream;
|
|
|
|
import java.io.ByteArrayOutputStream;
|
|
|
|
import java.io.InputStream;
|
|
|
|
import java.io.OutputStream;
|
|
|
|
import java.lang.reflect.Array;
|
2019-03-25 23:05:51 +01:00
|
|
|
import java.nio.ByteBuffer;
|
2014-08-20 23:44:59 +02:00
|
|
|
import java.util.ArrayList;
|
|
|
|
|
2019-03-25 23:05:51 +01:00
|
|
|
import org.junit.Before;
|
2016-03-06 23:50:36 +01:00
|
|
|
|
2019-03-25 23:05:51 +01:00
|
|
|
import com.esotericsoftware.kryo.Kryo;
|
|
|
|
import com.esotericsoftware.kryo.Serializer;
|
|
|
|
import com.esotericsoftware.kryo.io.ByteBufferInput;
|
|
|
|
import com.esotericsoftware.kryo.io.ByteBufferOutput;
|
|
|
|
import com.esotericsoftware.kryo.io.Input;
|
|
|
|
import com.esotericsoftware.kryo.io.Output;
|
|
|
|
import com.esotericsoftware.kryo.unsafe.UnsafeByteBufferInput;
|
|
|
|
import com.esotericsoftware.kryo.unsafe.UnsafeByteBufferOutput;
|
|
|
|
import com.esotericsoftware.kryo.unsafe.UnsafeInput;
|
|
|
|
import com.esotericsoftware.kryo.unsafe.UnsafeOutput;
|
|
|
|
|
|
|
|
/** Convenience methods for round tripping objects.
|
|
|
|
* @author Nathan Sweet */
|
|
|
|
abstract public class KryoTestCase {
|
|
|
|
// When true, roundTrip will only do a single write/read to make debugging easier (breaks some tests).
|
|
|
|
static private final boolean debug = false;
|
2014-08-20 23:44:59 +02:00
|
|
|
|
|
|
|
protected Kryo kryo;
|
|
|
|
protected Output output;
|
|
|
|
protected Input input;
|
|
|
|
protected Object object1, object2;
|
|
|
|
protected boolean supportsCopy;
|
|
|
|
|
2019-03-25 23:05:51 +01:00
|
|
|
static interface BufferFactory {
|
|
|
|
public Output createOutput(OutputStream os);
|
2014-08-20 23:44:59 +02:00
|
|
|
|
2019-03-25 23:05:51 +01:00
|
|
|
public Output createOutput(OutputStream os, int size);
|
2014-08-20 23:44:59 +02:00
|
|
|
|
2019-03-25 23:05:51 +01:00
|
|
|
public Output createOutput(int size, int limit);
|
2014-08-20 23:44:59 +02:00
|
|
|
|
2019-03-25 23:05:51 +01:00
|
|
|
public Input createInput(InputStream os, int size);
|
2014-08-20 23:44:59 +02:00
|
|
|
|
2019-03-25 23:05:51 +01:00
|
|
|
public Input createInput(byte[] buffer);
|
2014-08-20 23:44:59 +02:00
|
|
|
}
|
|
|
|
|
2019-03-25 23:05:51 +01:00
|
|
|
@Before
|
|
|
|
public void setUp () throws Exception {
|
|
|
|
if (debug && WARN) warn("*** DEBUG TEST ***");
|
2014-08-20 23:44:59 +02:00
|
|
|
|
|
|
|
kryo = new Kryo();
|
|
|
|
}
|
|
|
|
|
2019-03-25 23:05:51 +01:00
|
|
|
/** @param length Pass Integer.MIN_VALUE to disable checking the length. */
|
|
|
|
public <T> T roundTrip (int length, T object1) {
|
|
|
|
T object2 = roundTripWithBufferFactory(length, object1, new BufferFactory() {
|
2020-08-12 23:38:56 +02:00
|
|
|
@Override
|
|
|
|
public Output createOutput (OutputStream os) {
|
2019-03-25 23:05:51 +01:00
|
|
|
return new Output(os);
|
2014-08-20 23:44:59 +02:00
|
|
|
}
|
|
|
|
|
2020-08-12 23:38:56 +02:00
|
|
|
@Override
|
|
|
|
public Output createOutput (OutputStream os, int size) {
|
2019-03-25 23:05:51 +01:00
|
|
|
return new Output(os, size);
|
2014-08-20 23:44:59 +02:00
|
|
|
}
|
|
|
|
|
2020-08-12 23:38:56 +02:00
|
|
|
@Override
|
|
|
|
public Output createOutput (int size, int limit) {
|
2019-03-25 23:05:51 +01:00
|
|
|
return new Output(size, limit);
|
2014-08-20 23:44:59 +02:00
|
|
|
}
|
|
|
|
|
2020-08-12 23:38:56 +02:00
|
|
|
@Override
|
|
|
|
public Input createInput (InputStream os, int size) {
|
2019-03-25 23:05:51 +01:00
|
|
|
return new Input(os, size);
|
2014-08-20 23:44:59 +02:00
|
|
|
}
|
|
|
|
|
2020-08-12 23:38:56 +02:00
|
|
|
@Override
|
|
|
|
public Input createInput (byte[] buffer) {
|
2019-03-25 23:05:51 +01:00
|
|
|
return new Input(buffer);
|
2014-08-20 23:44:59 +02:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2019-03-25 23:05:51 +01:00
|
|
|
if (debug) return object2;
|
2014-08-20 23:44:59 +02:00
|
|
|
|
2019-03-25 23:05:51 +01:00
|
|
|
roundTripWithBufferFactory(length, object1, new BufferFactory() {
|
2020-08-12 23:38:56 +02:00
|
|
|
@Override
|
|
|
|
public Output createOutput (OutputStream os) {
|
2014-08-20 23:44:59 +02:00
|
|
|
return new ByteBufferOutput(os);
|
|
|
|
}
|
|
|
|
|
2020-08-12 23:38:56 +02:00
|
|
|
@Override
|
|
|
|
public Output createOutput (OutputStream os, int size) {
|
2014-08-20 23:44:59 +02:00
|
|
|
return new ByteBufferOutput(os, size);
|
|
|
|
}
|
|
|
|
|
2020-08-12 23:38:56 +02:00
|
|
|
@Override
|
|
|
|
public Output createOutput (int size, int limit) {
|
2014-08-20 23:44:59 +02:00
|
|
|
return new ByteBufferOutput(size, limit);
|
|
|
|
}
|
|
|
|
|
2020-08-12 23:38:56 +02:00
|
|
|
@Override
|
|
|
|
public Input createInput (InputStream os, int size) {
|
2014-08-20 23:44:59 +02:00
|
|
|
return new ByteBufferInput(os, size);
|
|
|
|
}
|
|
|
|
|
2020-08-12 23:38:56 +02:00
|
|
|
@Override
|
|
|
|
public Input createInput (byte[] buffer) {
|
2019-03-25 23:05:51 +01:00
|
|
|
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(buffer.length);
|
|
|
|
byteBuffer.put(buffer).flip();
|
|
|
|
return new ByteBufferInput(byteBuffer);
|
2014-08-20 23:44:59 +02:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2019-03-25 23:05:51 +01:00
|
|
|
roundTripWithBufferFactory(length, object1, new BufferFactory() {
|
2020-08-12 23:38:56 +02:00
|
|
|
@Override
|
|
|
|
public Output createOutput (OutputStream os) {
|
2019-03-25 23:05:51 +01:00
|
|
|
return new UnsafeOutput(os);
|
2014-08-20 23:44:59 +02:00
|
|
|
}
|
|
|
|
|
2020-08-12 23:38:56 +02:00
|
|
|
@Override
|
|
|
|
public Output createOutput (OutputStream os, int size) {
|
2019-03-25 23:05:51 +01:00
|
|
|
return new UnsafeOutput(os, size);
|
2014-08-20 23:44:59 +02:00
|
|
|
}
|
|
|
|
|
2020-08-12 23:38:56 +02:00
|
|
|
@Override
|
|
|
|
public Output createOutput (int size, int limit) {
|
2019-03-25 23:05:51 +01:00
|
|
|
return new UnsafeOutput(size, limit);
|
2014-08-20 23:44:59 +02:00
|
|
|
}
|
|
|
|
|
2020-08-12 23:38:56 +02:00
|
|
|
@Override
|
|
|
|
public Input createInput (InputStream os, int size) {
|
2019-03-25 23:05:51 +01:00
|
|
|
return new UnsafeInput(os, size);
|
2014-08-20 23:44:59 +02:00
|
|
|
}
|
|
|
|
|
2020-08-12 23:38:56 +02:00
|
|
|
@Override
|
|
|
|
public Input createInput (byte[] buffer) {
|
2019-03-25 23:05:51 +01:00
|
|
|
return new UnsafeInput(buffer);
|
2014-08-20 23:44:59 +02:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2019-03-25 23:05:51 +01:00
|
|
|
roundTripWithBufferFactory(length, object1, new BufferFactory() {
|
2020-08-12 23:38:56 +02:00
|
|
|
@Override
|
|
|
|
public Output createOutput (OutputStream os) {
|
2019-03-25 23:05:51 +01:00
|
|
|
return new UnsafeByteBufferOutput(os);
|
2014-08-20 23:44:59 +02:00
|
|
|
}
|
|
|
|
|
2020-08-12 23:38:56 +02:00
|
|
|
@Override
|
|
|
|
public Output createOutput (OutputStream os, int size) {
|
2019-03-25 23:05:51 +01:00
|
|
|
return new UnsafeByteBufferOutput(os, size);
|
2014-08-20 23:44:59 +02:00
|
|
|
}
|
|
|
|
|
2020-08-12 23:38:56 +02:00
|
|
|
@Override
|
|
|
|
public Output createOutput (int size, int limit) {
|
2019-03-25 23:05:51 +01:00
|
|
|
return new UnsafeByteBufferOutput(size, limit);
|
2014-08-20 23:44:59 +02:00
|
|
|
}
|
|
|
|
|
2020-08-12 23:38:56 +02:00
|
|
|
@Override
|
|
|
|
public Input createInput (InputStream os, int size) {
|
2019-03-25 23:05:51 +01:00
|
|
|
return new UnsafeByteBufferInput(os, size);
|
2014-08-20 23:44:59 +02:00
|
|
|
}
|
|
|
|
|
2020-08-12 23:38:56 +02:00
|
|
|
@Override
|
|
|
|
public Input createInput (byte[] buffer) {
|
2019-03-25 23:05:51 +01:00
|
|
|
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(buffer.length);
|
|
|
|
byteBuffer.put(buffer).flip();
|
|
|
|
return new UnsafeByteBufferInput(byteBuffer);
|
2014-08-20 23:44:59 +02:00
|
|
|
}
|
|
|
|
});
|
2019-03-25 23:05:51 +01:00
|
|
|
|
|
|
|
return object2;
|
2014-08-20 23:44:59 +02:00
|
|
|
}
|
|
|
|
|
2019-03-25 23:05:51 +01:00
|
|
|
/** @param length Pass Integer.MIN_VALUE to disable checking the length. */
|
|
|
|
public <T> T roundTripWithBufferFactory (int length, T object1, BufferFactory sf) {
|
|
|
|
boolean checkLength = length != Integer.MIN_VALUE;
|
|
|
|
|
2014-08-20 23:44:59 +02:00
|
|
|
this.object1 = object1;
|
|
|
|
|
|
|
|
// Test output to stream, large buffer.
|
|
|
|
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
|
|
|
|
output = sf.createOutput(outStream, 4096);
|
|
|
|
kryo.writeClassAndObject(output, object1);
|
|
|
|
output.flush();
|
|
|
|
|
2019-03-25 23:05:51 +01:00
|
|
|
if (debug) System.out.println();
|
|
|
|
|
2014-08-20 23:44:59 +02:00
|
|
|
// Test input from stream, large buffer.
|
2019-03-25 23:05:51 +01:00
|
|
|
byte[] out = outStream.toByteArray();
|
|
|
|
input = sf.createInput(new ByteArrayInputStream(outStream.toByteArray()), 4096);
|
2014-08-20 23:44:59 +02:00
|
|
|
object2 = kryo.readClassAndObject(input);
|
2019-03-25 23:05:51 +01:00
|
|
|
doAssertEquals(object1, object2);
|
|
|
|
if (checkLength) {
|
|
|
|
assertEquals("Incorrect number of bytes read.", length, input.total());
|
|
|
|
assertEquals("Incorrect number of bytes written.", length, output.total());
|
|
|
|
}
|
|
|
|
|
|
|
|
if (debug) return (T)object2;
|
2014-08-20 23:44:59 +02:00
|
|
|
|
|
|
|
// Test output to stream, small buffer.
|
|
|
|
outStream = new ByteArrayOutputStream();
|
|
|
|
output = sf.createOutput(outStream, 10);
|
|
|
|
kryo.writeClassAndObject(output, object1);
|
|
|
|
output.flush();
|
|
|
|
|
|
|
|
// Test input from stream, small buffer.
|
2019-03-25 23:05:51 +01:00
|
|
|
input = sf.createInput(new ByteArrayInputStream(outStream.toByteArray()), 10);
|
2014-08-20 23:44:59 +02:00
|
|
|
object2 = kryo.readClassAndObject(input);
|
2019-03-25 23:05:51 +01:00
|
|
|
doAssertEquals(object1, object2);
|
|
|
|
if (checkLength) assertEquals("Incorrect number of bytes read.", length, input.total());
|
2014-08-20 23:44:59 +02:00
|
|
|
|
|
|
|
if (object1 != null) {
|
|
|
|
// Test null with serializer.
|
2019-03-25 23:05:51 +01:00
|
|
|
Serializer serializer = kryo.getRegistration(object1.getClass()).getSerializer();
|
|
|
|
output.reset();
|
2014-08-20 23:44:59 +02:00
|
|
|
outStream.reset();
|
|
|
|
kryo.writeObjectOrNull(output, null, serializer);
|
|
|
|
output.flush();
|
|
|
|
|
|
|
|
// Test null from byte array with and without serializer.
|
2019-03-25 23:05:51 +01:00
|
|
|
input = sf.createInput(new ByteArrayInputStream(outStream.toByteArray()), 10);
|
|
|
|
assertNull(kryo.readObjectOrNull(input, object1.getClass(), serializer));
|
|
|
|
|
|
|
|
input = sf.createInput(new ByteArrayInputStream(outStream.toByteArray()), 10);
|
|
|
|
assertNull(kryo.readObjectOrNull(input, object1.getClass()));
|
2014-08-20 23:44:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Test output to byte array.
|
|
|
|
output = sf.createOutput(length * 2, -1);
|
|
|
|
kryo.writeClassAndObject(output, object1);
|
|
|
|
output.flush();
|
|
|
|
|
|
|
|
// Test input from byte array.
|
|
|
|
input = sf.createInput(output.toBytes());
|
|
|
|
object2 = kryo.readClassAndObject(input);
|
2019-03-25 23:05:51 +01:00
|
|
|
doAssertEquals(object1, object2);
|
|
|
|
if (checkLength) {
|
|
|
|
assertEquals("Incorrect length.", length, output.total());
|
|
|
|
assertEquals("Incorrect number of bytes read.", length, input.total());
|
|
|
|
}
|
|
|
|
input.reset();
|
2014-08-20 23:44:59 +02:00
|
|
|
|
|
|
|
if (supportsCopy) {
|
|
|
|
// Test copy.
|
|
|
|
T copy = kryo.copy(object1);
|
2019-03-25 23:05:51 +01:00
|
|
|
doAssertEquals(object1, copy);
|
2014-08-20 23:44:59 +02:00
|
|
|
copy = kryo.copyShallow(object1);
|
2019-03-25 23:05:51 +01:00
|
|
|
doAssertEquals(object1, copy);
|
2014-08-20 23:44:59 +02:00
|
|
|
}
|
|
|
|
|
2019-03-25 23:05:51 +01:00
|
|
|
return (T)object2;
|
2014-08-20 23:44:59 +02:00
|
|
|
}
|
|
|
|
|
2019-03-25 23:05:51 +01:00
|
|
|
protected void doAssertEquals (Object object1, Object object2) {
|
|
|
|
assertEquals(arrayToList(object1), arrayToList(object2));
|
2014-08-20 23:44:59 +02:00
|
|
|
}
|
|
|
|
|
2019-03-25 23:05:51 +01:00
|
|
|
static public Object arrayToList (Object array) {
|
|
|
|
if (array == null || !array.getClass().isArray()) return array;
|
2014-08-20 23:44:59 +02:00
|
|
|
ArrayList list = new ArrayList(Array.getLength(array));
|
2019-03-25 23:05:51 +01:00
|
|
|
for (int i = 0, n = Array.getLength(array); i < n; i++)
|
|
|
|
list.add(arrayToList(Array.get(array, i)));
|
2014-08-20 23:44:59 +02:00
|
|
|
return list;
|
|
|
|
}
|
|
|
|
|
2019-03-25 23:05:51 +01:00
|
|
|
static public ArrayList list (Object... items) {
|
2014-08-20 23:44:59 +02:00
|
|
|
ArrayList list = new ArrayList();
|
2019-03-25 23:05:51 +01:00
|
|
|
for (Object item : items)
|
|
|
|
list.add(item);
|
2014-08-20 23:44:59 +02:00
|
|
|
return list;
|
|
|
|
}
|
|
|
|
}
|