Skip to content

Commit

Permalink
tests
Browse files Browse the repository at this point in the history
  • Loading branch information
jpenilla committed Nov 15, 2023
1 parent 0dd7c70 commit 2687017
Show file tree
Hide file tree
Showing 4 changed files with 143 additions and 44 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -139,15 +139,29 @@ final class ReflectionProxyInvocationHandler<I> implements InvocationHandler {
}

private void scanInterface(final ReflectionRemapper reflectionRemapper) {
Class<?> prevProxy = null;
Class<?> prevProxied = null;

for (final Class<?> cls : Util.topDownInterfaceHierarchy(this.interfaceClass)) {
final Class<?> proxied = Util.findProxiedClass(cls, reflectionRemapper::remapClassName);

if (prevProxied != null && !prevProxied.isAssignableFrom(proxied)) {
throw new IllegalArgumentException(
"Reflection proxy interface " + cls.getName() + " proxies " + proxied.getName() + ", and extends from reflection proxy interface "
+ prevProxy.getName() + " which proxies " + prevProxied.getName() + ", but the proxied types are not compatible."
);
}

this.scanInterface(
cls,
proxied,
reflectionRemapper::remapClassOrArrayName,
fieldName -> reflectionRemapper.remapFieldName(proxied, fieldName),
(methodName, parameters) -> reflectionRemapper.remapMethodName(proxied, methodName, parameters)
);

prevProxied = proxied;
prevProxy = cls;
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
/*
* reflection-remapper
*
* Copyright (c) 2021-2023 Jason Penilla
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package xyz.jpenilla.reflectionremapper;

import java.nio.file.Path;
import org.junit.jupiter.api.Test;
import xyz.jpenilla.reflectionremapper.proxy.ReflectionProxyFactory;
import xyz.jpenilla.reflectionremapper.proxy.annotation.FieldGetter;
import xyz.jpenilla.reflectionremapper.proxy.annotation.Proxies;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;

class ReflectionProxyInheritanceTest {
private ReflectionProxyFactory factory() {
return ReflectionProxyFactory.create(
ReflectionRemapper.noop(),
this.getClass().getClassLoader()
);
}

@Proxies(String.class)
interface StringProxy {}

@Proxies(Path.class)
interface InvalidPathProxy extends StringProxy {}

@Test
void testInvalidHierarchy() {
// Path does not extend String
assertThrows(IllegalArgumentException.class, () -> this.factory().reflectionProxy(InvalidPathProxy.class));
}

static class Level {
final int number = 50;

String name() {
return this.level();
}

String level() {
return Level.class.getName();
}
}

static class ServerLevel extends Level {
final int number1 = 55;

@Override
String name() {
return this.serverLevel();
}

String serverLevel() {
return ServerLevel.class.getName();
}
}

@Proxies(Level.class)
interface LevelProxy {
String name(Level instance);

@FieldGetter("number")
int number(Level instance);

default String test0() {
return "LP 0";
}

default String test1() {
return "LP 1";
}
}

@Proxies(ServerLevel.class)
interface ServerLevelProxy extends LevelProxy {
@FieldGetter("number1")
int number1(ServerLevel level);

@Override
default String test1() {
return "S" + LevelProxy.super.test1();
}

default String test2() {
return "SLP 2";
}
}

@Test
void testValidHierarchy() {
final LevelProxy levelProxy = this.factory().reflectionProxy(LevelProxy.class);
final ServerLevelProxy serverLevelProxy = this.factory().reflectionProxy(ServerLevelProxy.class);

final ServerLevel sl = new ServerLevel();
final Level l = new Level();

assertEquals(levelProxy.name(l), serverLevelProxy.name(l));
assertEquals(levelProxy.name(sl), serverLevelProxy.name(sl));
assertEquals(levelProxy.number(sl), 50);
assertEquals(levelProxy.number(sl), serverLevelProxy.number(sl));
assertEquals(serverLevelProxy.number1(sl), 55);

// test default methods on proxy interfaces
assertEquals(levelProxy.test0(), serverLevelProxy.test0());
assertEquals("S" + levelProxy.test1(), serverLevelProxy.test1());
assertEquals("SLP 2", serverLevelProxy.test2());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;

class ReflectionRemapperTest {
class ReflectionProxyTest {
private ReflectionProxyFactory factory() {
return ReflectionProxyFactory.create(
ReflectionRemapper.noop(),
Expand Down Expand Up @@ -89,13 +89,13 @@ void testSynthetics() {
assertEquals("nothing5", proxy.get(() -> "nothing", 5).get());
}

@Proxies(className = "xyz.jpenilla.reflectionremapper.ReflectionRemapperTest$PrivateClass")
@Proxies(className = "xyz.jpenilla.reflectionremapper.ReflectionProxyTest$PrivateClass")
interface PrivateClassProxy {
String secret(Object instance);

String useSecretClass(
Object instance,
@Type(className = "xyz.jpenilla.reflectionremapper.ReflectionRemapperTest$AnotherPrivateClass") Object anotherPrivateClass
@Type(className = "xyz.jpenilla.reflectionremapper.ReflectionProxyTest$AnotherPrivateClass") Object anotherPrivateClass
);

@MethodName("useSecretClass")
Expand Down Expand Up @@ -153,7 +153,7 @@ private static int staticMethod() {
}
}

@Proxies(className = "xyz.jpenilla.reflectionremapper.ReflectionRemapperTest$AnotherPrivateClass")
@Proxies(className = "xyz.jpenilla.reflectionremapper.ReflectionProxyTest$AnotherPrivateClass")
interface AnotherPrivateClassProxy {
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,6 @@
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.redstone.NeighborUpdater;
import org.bukkit.command.CommandSender;
import org.bukkit.craftbukkit.v1_20_R2.entity.CraftPlayer;
import org.bukkit.entity.Player;
Expand All @@ -39,7 +37,6 @@
import org.checkerframework.framework.qual.DefaultQualifier;
import xyz.jpenilla.reflectionremapper.ReflectionRemapper;
import xyz.jpenilla.reflectionremapper.proxy.ReflectionProxyFactory;
import xyz.jpenilla.reflectionremapper.proxy.annotation.FieldGetter;
import xyz.jpenilla.reflectionremapper.proxy.annotation.Proxies;

@DefaultQualifier(NonNull.class)
Expand Down Expand Up @@ -71,23 +68,12 @@ private void executeCreateEndPlatform(final CommandContext<CommandSender> ctx) {

private void executeStrikeLightning(final CommandContext<CommandSender> ctx) {
final ServerPlayer serverPlayer = ((CraftPlayer) ctx.getSender()).getHandle();

System.out.println(Reflection.SERVER_LEVEL.neighborUpdater(serverPlayer.level()));
System.out.println(Reflection.LEVEL.neighborUpdater(serverPlayer.level()));

Reflection.SERVER_LEVEL.test1();
Reflection.SERVER_LEVEL.test2();
Reflection.LEVEL.test1();
Reflection.SERVER_LEVEL.test0();
Reflection.LEVEL.test0();

final BlockPos lightningTarget = Reflection.SERVER_LEVEL.findLightningTargetAround((ServerLevel) serverPlayer.level(), serverPlayer.blockPosition());
((Player) ctx.getSender()).getWorld().strikeLightning(MCUtil.toLocation(serverPlayer.level(), lightningTarget));
}

public static final class Reflection {
public static final ServerLevelProxy SERVER_LEVEL;
public static final LevelProxy LEVEL;
public static final ServerPlayerProxy SERVER_PLAYER;

static {
Expand All @@ -98,38 +84,13 @@ public static final class Reflection {

// proxy instances are safe to hold onto
SERVER_LEVEL = reflectionProxyFactory.reflectionProxy(ServerLevelProxy.class);
LEVEL = reflectionProxyFactory.reflectionProxy(LevelProxy.class);
SERVER_PLAYER = reflectionProxyFactory.reflectionProxy(ServerPlayerProxy.class);
}
}

@Proxies(Level.class)
private interface LevelProxy {
@FieldGetter("neighborUpdater")
NeighborUpdater neighborUpdater(Level instance);

default void test0() {
System.out.println("LP 0");
}

default void test1() {
System.out.println("LP 1");
}
}

@Proxies(ServerLevel.class)
private interface ServerLevelProxy extends LevelProxy {
private interface ServerLevelProxy {
BlockPos findLightningTargetAround(ServerLevel instance, BlockPos pos);

@Override
default void test1() {
LevelProxy.super.test1();
System.out.println("SLP 1");
}

default void test2() {
System.out.println("SLP 2");
}
}

@Proxies(ServerPlayer.class)
Expand Down

0 comments on commit 2687017

Please sign in to comment.