Skip to content

Commit

Permalink
Improve tests for JDK 17
Browse files Browse the repository at this point in the history
  • Loading branch information
theigl committed Feb 21, 2022
1 parent 74355ac commit 181c016
Show file tree
Hide file tree
Showing 11 changed files with 126 additions and 141 deletions.
4 changes: 4 additions & 0 deletions src/com/esotericsoftware/kryo/util/Util.java
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@ public class Util {
primitiveWrappers.put(short.class, Short.class);
}

public static boolean isUnsafeAvailable () {
return unsafe;
}

public static boolean isClassAvailable (String className) {
try {
Class.forName(className);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ void testImmutableSet () {
roundTrip(6, Set.of(1, 2, 3));
}

static class TestClass {
public static class TestClass {
List<Integer> list;
Map<Integer, Integer> map;
Set<Integer> set;
Expand Down
83 changes: 44 additions & 39 deletions test/com/esotericsoftware/kryo/KryoTestCase.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import com.esotericsoftware.kryo.unsafe.UnsafeByteBufferOutput;
import com.esotericsoftware.kryo.unsafe.UnsafeInput;
import com.esotericsoftware.kryo.unsafe.UnsafeOutput;
import com.esotericsoftware.kryo.util.Util;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
Expand Down Expand Up @@ -139,50 +140,54 @@ public Input createInput (byte[] buffer) {
}
});

roundTripWithBufferFactory(length, object1, new BufferFactory() {
public Output createOutput (OutputStream os) {
return new UnsafeOutput(os);
}

public Output createOutput (OutputStream os, int size) {
return new UnsafeOutput(os, size);
}
if (Util.isUnsafeAvailable()) {
roundTripWithBufferFactory(length, object1, new BufferFactory() {
public Output createOutput(OutputStream os) {
return new UnsafeOutput(os);
}

public Output createOutput (int size, int limit) {
return new UnsafeOutput(size, limit);
}
public Output createOutput(OutputStream os, int size) {
return new UnsafeOutput(os, size);
}

public Input createInput (InputStream os, int size) {
return new UnsafeInput(os, size);
}
public Output createOutput(int size, int limit) {
return new UnsafeOutput(size, limit);
}

public Input createInput (byte[] buffer) {
return new UnsafeInput(buffer);
}
});
public Input createInput(InputStream os, int size) {
return new UnsafeInput(os, size);
}

roundTripWithBufferFactory(length, object1, new BufferFactory() {
public Output createOutput (OutputStream os) {
return new UnsafeByteBufferOutput(os);
}

public Output createOutput (OutputStream os, int size) {
return new UnsafeByteBufferOutput(os, size);
}

public Output createOutput (int size, int limit) {
return new UnsafeByteBufferOutput(size, limit);
}

public Input createInput (InputStream os, int size) {
return new UnsafeByteBufferInput(os, size);
}
public Input createInput(byte[] buffer) {
return new UnsafeInput(buffer);
}
});
}

public Input createInput (byte[] buffer) {
ByteBuffer byteBuffer = allocateByteBuffer(buffer);
return new UnsafeByteBufferInput(byteBuffer.asReadOnlyBuffer());
}
});
if (Util.isUnsafeAvailable()) {
roundTripWithBufferFactory(length, object1, new BufferFactory() {
public Output createOutput(OutputStream os) {
return new UnsafeByteBufferOutput(os);
}

public Output createOutput(OutputStream os, int size) {
return new UnsafeByteBufferOutput(os, size);
}

public Output createOutput(int size, int limit) {
return new UnsafeByteBufferOutput(size, limit);
}

public Input createInput(InputStream os, int size) {
return new UnsafeByteBufferInput(os, size);
}

public Input createInput(byte[] buffer) {
ByteBuffer byteBuffer = allocateByteBuffer(buffer);
return new UnsafeByteBufferInput(byteBuffer.asReadOnlyBuffer());
}
});
}

return object2;
}
Expand Down
99 changes: 16 additions & 83 deletions test/com/esotericsoftware/kryo/ReferenceTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@
import com.esotericsoftware.kryo.io.Output;
import com.esotericsoftware.kryo.serializers.MapSerializer;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.TreeMap;

import org.junit.jupiter.api.Test;
Expand Down Expand Up @@ -89,19 +89,13 @@ void testReadingNestedObjectsFirst () {
list.add("2");
list.add("1");
list.add("1");
List subList = list.subList(0, 5);
ArrayListHolder subList = new ArrayListHolder(list);

kryo.setRegistrationRequired(false);
kryo.register(ArrayList.class);
Class<List> subListClass = (Class<List>)subList.getClass();
if (subListClass.getName().equals("java.util.ArrayList$SubList")) {
// This is JDK > = 1.7
kryo.register(subList.getClass(), new ArraySubListSerializer());
} else {
kryo.register(subList.getClass(), new SubListSerializer());
kryo.register(ArrayListHolder.class);

}
roundTrip(23, subList);
roundTrip(15, subList);
}

@Test
Expand All @@ -118,86 +112,25 @@ void testReadInvalidReference() {
fail("Exception was expected");
}

public static class SubListSerializer extends Serializer<List> {
private Field listField, offsetField, sizeField;

public SubListSerializer () {
try {
Class sublistClass = Class.forName("java.util.SubList");
listField = sublistClass.getDeclaredField("l");
offsetField = sublistClass.getDeclaredField("offset");
sizeField = sublistClass.getDeclaredField("size");
listField.setAccessible(true);
offsetField.setAccessible(true);
sizeField.setAccessible(true);
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}

public void write (Kryo kryo, Output output, List list) {
try {
kryo.writeClassAndObject(output, listField.get(list));
int fromIndex = offsetField.getInt(list);
int count = sizeField.getInt(list);
output.writeInt(fromIndex);
output.writeInt(count);
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}

public List read (Kryo kryo, Input input, Class<? extends List> type) {
List list = (List)kryo.readClassAndObject(input);
int fromIndex = input.readInt();
int count = input.readInt();
return list.subList(fromIndex, fromIndex + count);
}
}
public static class ArrayListHolder {
private List<Object> parent;

public static class ArraySubListSerializer extends Serializer<List> {
private Field parentField, offsetField, sizeField;

public ArraySubListSerializer () {
try {
Class sublistClass = Class.forName("java.util.ArrayList$SubList");
parentField = getParentField(sublistClass);
offsetField = sublistClass.getDeclaredField("offset");
sizeField = sublistClass.getDeclaredField("size");
parentField.setAccessible(true);
offsetField.setAccessible(true);
sizeField.setAccessible(true);
} catch (Exception ex) {
throw new RuntimeException(ex);
}
public ArrayListHolder () {
}

private Field getParentField(Class sublistClass) throws NoSuchFieldException {
try {
// java 9+
return sublistClass.getDeclaredField("root");
} catch(NoSuchFieldException e) {
return sublistClass.getDeclaredField("parent");
}
public ArrayListHolder (List<Object> parent) {
this.parent = parent;
}

public void write (Kryo kryo, Output output, List list) {
try {
kryo.writeClassAndObject(output, parentField.get(list));
int offset = offsetField.getInt(list);
int size = sizeField.getInt(list);
output.writeInt(offset);
output.writeInt(size);
} catch (Exception ex) {
throw new RuntimeException(ex);
}
public boolean equals (Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ArrayListHolder that = (ArrayListHolder)o;
return Objects.equals(parent, that.parent);
}

public List read (Kryo kryo, Input input, Class<? extends List> type) {
List list = (List)kryo.readClassAndObject(input);
int offset = input.readInt();
int size = input.readInt();
return list.subList(offset, offset + size);
public int hashCode () {
return Objects.hash(parent);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ void testByteBufferOutputFixed () throws Exception {
}

@Test
@Unsafe
void testUnsafeOutput () throws Exception {
UnsafeOutput output = new UnsafeOutput(OUTPUT_BUFFER_SIZE);
UnsafeInput input = new UnsafeInput(output.getBuffer());
Expand All @@ -117,6 +118,7 @@ void testUnsafeOutput () throws Exception {
}

@Test
@Unsafe
void testUnsafeOutputFixed () throws Exception {
UnsafeOutput output = new UnsafeOutput(OUTPUT_BUFFER_SIZE);
UnsafeInput input = new UnsafeInput(output.getBuffer());
Expand All @@ -127,6 +129,7 @@ void testUnsafeOutputFixed () throws Exception {
}

@Test
@Unsafe
void testUnsafeByteBufferOutput () throws Exception {
UnsafeByteBufferOutput output = new UnsafeByteBufferOutput(OUTPUT_BUFFER_SIZE);
UnsafeByteBufferInput input = new UnsafeByteBufferInput(output.getByteBuffer());
Expand All @@ -135,6 +138,7 @@ void testUnsafeByteBufferOutput () throws Exception {
}

@Test
@Unsafe
void testUnsafeByteBufferOutputFixed () throws Exception {
UnsafeByteBufferOutput output = new UnsafeByteBufferOutput(OUTPUT_BUFFER_SIZE);
UnsafeByteBufferInput input = new UnsafeByteBufferInput(output.getByteBuffer());
Expand Down Expand Up @@ -198,7 +202,7 @@ public void setUp () throws Exception {
Log.WARN();
}

private static class SampleObject implements Externalizable, KryoSerializable {
public static class SampleObject implements Externalizable, KryoSerializable {
private int intValue;
public float floatValue;
protected Short shortValue;
Expand Down
34 changes: 34 additions & 0 deletions test/com/esotericsoftware/kryo/Unsafe.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/* Copyright (c) 2008-2022, Nathan Sweet
* 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
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */

package com.esotericsoftware.kryo;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import org.junit.jupiter.api.condition.EnabledIf;

/** Conditional annotation that runs a test only if Unsafe is available */
@Target(value = {ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@EnabledIf("com.esotericsoftware.kryo.util.Util#isUnsafeAvailable")
public @interface Unsafe {
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import static com.esotericsoftware.kryo.KryoAssert.*;
import static org.junit.jupiter.api.Assertions.*;

import com.esotericsoftware.kryo.Unsafe;
import com.esotericsoftware.kryo.unsafe.UnsafeByteBufferInput;
import com.esotericsoftware.kryo.unsafe.UnsafeByteBufferOutput;
import com.esotericsoftware.kryo.unsafe.UnsafeUtil;
Expand All @@ -33,6 +34,7 @@
import org.junit.jupiter.api.Test;

/** @author Roman Levenstein <romixlev@gmail.com> */
@Unsafe
@SuppressWarnings("restriction")
class UnsafeByteBufferInputOutputTest {

Expand Down
2 changes: 2 additions & 0 deletions test/com/esotericsoftware/kryo/io/UnsafeInputOutputTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import static com.esotericsoftware.kryo.KryoAssert.*;
import static org.junit.jupiter.api.Assertions.*;

import com.esotericsoftware.kryo.Unsafe;
import com.esotericsoftware.kryo.unsafe.UnsafeInput;
import com.esotericsoftware.kryo.unsafe.UnsafeOutput;

Expand All @@ -32,6 +33,7 @@
import org.junit.jupiter.api.Test;

/** @author Nathan Sweet <misc@n4te.com> */
@Unsafe
class UnsafeInputOutputTest {
@Test
void testOutputStream () {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import com.esotericsoftware.kryo.serializers.FieldSerializer.NotNull;
import com.esotericsoftware.kryo.serializers.FieldSerializer.Optional;
import com.esotericsoftware.kryo.serializers.MapSerializer.BindMap;
import com.esotericsoftware.kryo.util.Util;

import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
Expand Down Expand Up @@ -402,7 +403,7 @@ void testDefaultInstantiatorStrategy () {

kryo.register(HasPrivateConstructor.class);
roundTrip(4, test);
assertEquals(20, HasPrivateConstructor.invocations, "Wrong number of constructor invocations");
assertEquals(Util.isUnsafeAvailable() ? 20 : 10, HasPrivateConstructor.invocations, "Wrong number of constructor invocations");
}

/** This test uses StdInstantiatorStrategy and should bypass invocation of no-arg constructor, even if it is provided. **/
Expand Down
Loading

0 comments on commit 181c016

Please sign in to comment.