Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test(TypeHandlerLibrary): RuntimeDelegatingTypeHandler test failure #3992

Merged
merged 19 commits into from
Nov 7, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
4fa9bb5
style: checkstyle appeasement
keturn May 24, 2020
e427dc2
style(tests): lambda
keturn May 24, 2020
2a72cec
chore(build): explicit dependency on mockito-core
keturn May 25, 2020
d46902f
chore(test): clean up unparameterized type usage
keturn May 25, 2020
f6ad180
chore(dict): conjugations of deserialize
keturn May 25, 2020
a27b270
chore(ide): don't offer to convert varargs to array
keturn May 25, 2020
80c32bb
Merge remote-tracking branch 'origin/develop' into fix/java11-persists
keturn Sep 4, 2020
16f514f
refactor: TypeHandler moved to subsystems
keturn Mar 26, 2021
bd31a32
Merge remote-tracking branch 'origin/develop' into fix/java11-persists
keturn Mar 26, 2021
caf9721
test: do not warn about unused field on stub class
keturn Mar 26, 2021
e13284f
Merge remote-tracking branch 'origin/develop' into fix/java11-persists
keturn Nov 5, 2021
0676411
build(IntelliJ): no need to replace varargs methods
keturn Nov 5, 2021
e12dcfc
test(TypeHandlerLibrary): spy on THL instance so we may verify intera…
keturn Nov 6, 2021
9c5cbea
test(TypeHandlerLibrary): revert to mocking THL and its sandbox
keturn Nov 6, 2021
c17653f
chore: whitespace
keturn Nov 6, 2021
54f9052
chore(TypeHandlerLibrary): update to junit 5.8 from 5.5, mockito 3.12…
keturn Nov 6, 2021
801d583
test(TypeHandlerLibrary): stub sandbox.getSuTypeIdentifier
keturn Nov 6, 2021
6b0af08
test(TypeHandlerLibrary): comment on what we're mocking
keturn Nov 6, 2021
913a1df
Merge remote-tracking branch 'origin/develop' into fix/java11-persists
keturn Nov 7, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .idea/dictionaries/kevint.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions .idea/inspectionProfiles/Terasology.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 8 additions & 5 deletions subsystems/TypeHandlerLibrary/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,15 @@ dependencies {
testRuntimeOnly("org.slf4j:slf4j-simple:1.7.32") {
because("log output during tests")
}
testImplementation(platform("org.junit:junit-bom:5.8.1")) {
// junit-bom will set version numbers for the other org.junit dependencies.
}
testImplementation("org.junit.jupiter:junit-jupiter-api")
testImplementation("org.junit.jupiter:junit-jupiter-params")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine")
testImplementation("org.mockito:mockito-inline:3.12.4")

testImplementation("org.junit.jupiter:junit-jupiter-api:5.5.2")
testImplementation("org.junit.jupiter:junit-jupiter-params:5.5.2")
testImplementation("org.mockito:mockito-junit-jupiter:3.11.2")

testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.5.2")
testImplementation("org.mockito:mockito-junit-jupiter:3.12.4")
}

tasks.register<Test>("unitTest") {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@

import com.google.common.collect.ImmutableMap;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentMatcher;
import org.reflections.Reflections;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.terasology.persistence.typeHandling.PersistedData;
import org.terasology.persistence.typeHandling.PersistedDataSerializer;
import org.terasology.persistence.typeHandling.TypeHandler;
Expand All @@ -14,7 +16,7 @@
import org.terasology.persistence.typeHandling.inMemory.AbstractPersistedData;
import org.terasology.persistence.typeHandling.inMemory.PersistedMap;
import org.terasology.persistence.typeHandling.inMemory.PersistedString;
import org.terasology.persistence.typeHandling.reflection.ReflectionsSandbox;
import org.terasology.persistence.typeHandling.reflection.SerializationSandbox;
import org.terasology.reflection.TypeInfo;

import java.lang.reflect.Type;
Expand All @@ -30,136 +32,103 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

class RuntimeDelegatingTypeHandlerTest {
private final TypeHandlerLibrary typeHandlerLibrary = mock(TypeHandlerLibrary.class);

private final TypeHandlerContext context =
new TypeHandlerContext(typeHandlerLibrary, new ReflectionsSandbox(new Reflections(getClass().getClassLoader())));

private TypeHandler baseTypeHandler;
private TypeHandler subTypeHandler;
private Class<Sub> subType;
private Type baseType;
private RuntimeDelegatingTypeHandler<Base> runtimeDelegatingTypeHandler;

private static class Base {
int x;
@ExtendWith(MockitoExtension.class)
public class RuntimeDelegatingTypeHandlerTest {
private final TypeHandlerLibrary typeHandlerLibrary;

private final TypeHandler<Base> baseTypeHandler;
private final TypeHandler<Sub> subTypeHandler;
private final Class<Sub> subType = Sub.class;
private final Class<Base> baseType = Base.class;
private final RuntimeDelegatingTypeHandler<Base> runtimeDelegatingTypeHandler;


RuntimeDelegatingTypeHandlerTest(@Mock TypeHandler<Base> baseTypeHandler, @Mock SubHandler subTypeHandler,
@Mock SerializationSandbox sandbox, @Mock TypeHandlerLibrary typeHandlerLibrary) {
this.baseTypeHandler = baseTypeHandler;
this.subTypeHandler = subTypeHandler;
configureMockSerializer(baseTypeHandler);
configureMockSerializer(subTypeHandler);

this.typeHandlerLibrary = typeHandlerLibrary;
// We must mock `getTypeHandler(Type)`, not only `getTypeHandler(Class<>)`
when(typeHandlerLibrary.getTypeHandler((Type) baseType))
.thenReturn(Optional.of(baseTypeHandler));
when(typeHandlerLibrary.getTypeHandler((Type) subType))
.thenReturn(Optional.of(subTypeHandler));

when(sandbox.findSubTypeOf(subType.getName(), baseType))
.thenReturn(Optional.of(subType));
when(sandbox.getSubTypeIdentifier(subType, baseType))
.thenReturn(subType.getName());
TypeHandlerContext context = new TypeHandlerContext(typeHandlerLibrary, sandbox);

runtimeDelegatingTypeHandler = new RuntimeDelegatingTypeHandler<>(
baseTypeHandler, TypeInfo.of(Base.class), context);
}

private static class Sub extends Base {
float y;
}

private void setupHandlers() {
subType = Sub.class;
baseType = TypeInfo.of(Base.class).getType();

abstract class SubHandler extends TypeHandler<Sub> { }

baseTypeHandler = mockTypeHandler();
subTypeHandler = mockTypeHandler(SubHandler.class);

when(typeHandlerLibrary.getTypeHandler(eq(baseType)))
.thenReturn(Optional.of(baseTypeHandler));

when(typeHandlerLibrary.getTypeHandler(eq((Type) subType)))
.thenReturn(Optional.of(subTypeHandler));

runtimeDelegatingTypeHandler = new RuntimeDelegatingTypeHandler<Base>(baseTypeHandler, TypeInfo.of(Base.class), context);
}

private static TypeHandler<?> mockTypeHandler(Class<? extends TypeHandler> subHandlerClass) {
TypeHandler<?> mocked = mock(subHandlerClass);

private static void configureMockSerializer(TypeHandler<?> mocked) {
when(mocked.serialize(any(), any())).thenReturn(new AbstractPersistedData() {
@Override
public boolean isNull() {
return true;
}
});

return mocked;
}

private static TypeHandler<?> mockTypeHandler() {
return mockTypeHandler(TypeHandler.class);
}

@Test
void testSerializeBase() {
PersistedDataSerializer serializer = mock(PersistedDataSerializer.class);
when(serializer.serialize(any(String.class)))
.then(invocation -> new PersistedString((String) invocation.getArguments()[0]));

setupHandlers();

Base base = new Base();
runtimeDelegatingTypeHandler.serialize(base, serializer);

verify(typeHandlerLibrary, never()).getTypeHandler(eq((Type) subType));

verify(baseTypeHandler).serialize(any(), any());
verify(subTypeHandler, never()).serialize(any(), any());

verify(serializer, never()).serialize(
argThat((ArgumentMatcher<Map<String, PersistedData>>) argument -> {
return argument.containsKey(RuntimeDelegatingTypeHandler.TYPE_FIELD);
})
argThat((ArgumentMatcher<Map<String, PersistedData>>) argument -> argument.containsKey(RuntimeDelegatingTypeHandler.TYPE_FIELD))
);
}

@Test
void testSerializeSub() {
PersistedDataSerializer serializer = mock(PersistedDataSerializer.class);
when(serializer.serialize(any(String.class)))
.then(invocation -> new PersistedString((String) invocation.getArguments()[0]));

setupHandlers();
.then(invocation -> new PersistedString((String) invocation.getArguments()[0]));

Base sub = new Sub();
runtimeDelegatingTypeHandler.serialize(sub, serializer);

verify(typeHandlerLibrary, never()).getTypeHandler(eq(baseType));
verify(typeHandlerLibrary).getTypeHandler(eq((Type) subType));

verify(baseTypeHandler, never()).serialize(any(), any());
verify(subTypeHandler).serialize(any(), any());

verify(serializer).serialize(
argThat((ArgumentMatcher<Map<String, PersistedData>>) argument -> {
return argument.get(RuntimeDelegatingTypeHandler.TYPE_FIELD)
.getAsString()
.equals(subType.getName())
&& argument.containsKey(RuntimeDelegatingTypeHandler.VALUE_FIELD);
})
argThat((ArgumentMatcher<Map<String, PersistedData>>) argument -> argument.get(RuntimeDelegatingTypeHandler.TYPE_FIELD)
.getAsString()
.equals(subType.getName())
&& argument.containsKey(RuntimeDelegatingTypeHandler.VALUE_FIELD))
);
}

@Test
void testDeserializeBase() {
setupHandlers();

PersistedData persistedBase = new PersistedMap(ImmutableMap.of());

runtimeDelegatingTypeHandler.deserialize(persistedBase);

verify(typeHandlerLibrary, never()).getTypeHandler(eq((Type) subType));

verify(baseTypeHandler).deserialize(any());
verify(subTypeHandler, never()).deserialize(any());
}

@Test
void testDeserializeSub() {
setupHandlers();

PersistedData persistedSub = new PersistedMap(
ImmutableMap.of(
RuntimeDelegatingTypeHandler.TYPE_FIELD,
new PersistedString(((Class<?>) subType).getName()),
RuntimeDelegatingTypeHandler.VALUE_FIELD,
new PersistedMap(ImmutableMap.of())
)
ImmutableMap.of(
RuntimeDelegatingTypeHandler.TYPE_FIELD,
new PersistedString(subType.getName()),
RuntimeDelegatingTypeHandler.VALUE_FIELD,
new PersistedMap(ImmutableMap.of())
)
);

runtimeDelegatingTypeHandler.deserialize(persistedSub);
Expand All @@ -173,27 +142,33 @@ void testDeserializeSub() {

@Test
void testDeserializeNonSub() {
setupHandlers();

PersistedData persistedData = new PersistedMap(
ImmutableMap.of(
RuntimeDelegatingTypeHandler.TYPE_FIELD,
new PersistedString(Integer.class.getName()),
RuntimeDelegatingTypeHandler.VALUE_FIELD,
new PersistedMap(ImmutableMap.of())
)
ImmutableMap.of(
RuntimeDelegatingTypeHandler.TYPE_FIELD,
new PersistedString(Integer.class.getName()),
RuntimeDelegatingTypeHandler.VALUE_FIELD,
new PersistedMap(ImmutableMap.of())
)
);

Optional<Base> deserialized = runtimeDelegatingTypeHandler.deserialize(persistedData);

assertFalse(deserialized.isPresent());

verify(typeHandlerLibrary, never()).getTypeHandler(eq(baseType));
verify(typeHandlerLibrary, never()).getTypeHandler(eq((Type) subType));
verify(typeHandlerLibrary, never()).getTypeHandler(eq((Type) Integer.class));

verify(subTypeHandler, never()).deserialize(any());
// Serializes using base type handler
verify(baseTypeHandler).deserialize(any());
}

private static class Base {
@SuppressWarnings("unused")
int x;
}

private static class Sub extends Base {
@SuppressWarnings("unused")
float y;
}

private abstract static class SubHandler extends TypeHandler<Sub> { }
}