diff --git a/src/functionalTest/java/codechicken/multipart/test/ProxyLoggerFunctionalTest.java b/src/functionalTest/java/codechicken/multipart/test/ProxyLoggerFunctionalTest.java new file mode 100644 index 0000000..53f54e3 --- /dev/null +++ b/src/functionalTest/java/codechicken/multipart/test/ProxyLoggerFunctionalTest.java @@ -0,0 +1,37 @@ +package codechicken.multipart.test; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertSame; + +import org.junit.jupiter.api.Test; + +import codechicken.microblock.handler.MicroblockProxy; +import codechicken.multipart.handler.MultipartProxy; + +/** + * Both proxies publish a logger during preInit, and code across both packages logs through them. A plain JVM test only + * ever sees the uninitialised null, so this is the one place the real instances are observable. + */ +class ProxyLoggerFunctionalTest { + + @Test + void bothProxiesPublishALoggerDuringPreInit() { + assertNotNull(MultipartProxy.logger(), "MultipartProxy.logger is set in preInit"); + assertNotNull(MicroblockProxy.logger(), "MicroblockProxy.logger is set in preInit"); + } + + /** + * The package objects are pure aliases: each returns the very instance its proxy holds, adding nothing. That is + * what makes them safe to remove in favour of naming the proxy directly. + */ + @Test + void thePackageObjectAliasesAreTheProxyLoggersThemselves() throws Exception { + assertSame(MultipartProxy.logger(), invokeLogger("codechicken.multipart.package")); + assertSame(MicroblockProxy.logger(), invokeLogger("codechicken.microblock.package")); + } + + /** Reflective because {@code package} is a Java keyword and cannot appear as a type name in Java source. */ + private static Object invokeLogger(String name) throws Exception { + return Class.forName(name).getDeclaredMethod("logger").invoke(null); + } +} diff --git a/src/test/java/codechicken/multipart/PackageObjectCharacterizationTest.java b/src/test/java/codechicken/multipart/PackageObjectCharacterizationTest.java new file mode 100644 index 0000000..5c967e6 --- /dev/null +++ b/src/test/java/codechicken/multipart/PackageObjectCharacterizationTest.java @@ -0,0 +1,55 @@ +package codechicken.multipart; + +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; + +import org.apache.logging.log4j.Logger; +import org.junit.jupiter.api.Test; + +/** + * Both package objects hold one member, a {@code logger} alias for their proxy's logger. + *

+ * Everything here goes through reflection because {@code package} is a Java keyword: + * {@code codechicken.multipart.package} cannot be written as a type name in Java source at all. That is not a style + * choice, it is the reason these two classes have no Java form. + */ +class PackageObjectCharacterizationTest { + + @Test + void bothPackageObjectsExposeAStaticLoggerAccessor() throws Exception { + for (String name : new String[] { "codechicken.multipart.package", "codechicken.microblock.package" }) { + Method logger = Class.forName(name).getDeclaredMethod("logger"); + + assertSame(Logger.class, logger.getReturnType(), name); + assertTrue(Modifier.isPublic(logger.getModifiers()), name); + assertTrue(Modifier.isStatic(logger.getModifiers()), name); + } + } + + @Test + void bothCarryACompanionSingleton() throws Exception { + for (String name : new String[] { "codechicken.multipart.package$", "codechicken.microblock.package$" }) { + Class companion = Class.forName(name); + + assertSame(companion, companion.getField("MODULE$").getType(), name); + } + } + + /** + * The alias reads the proxy's var rather than holding anything, so before preInit has run it reports null instead + * of failing. The Forge server suite asserts the other half, that after preInit it is the very same instance. + */ + @Test + void theAliasReportsWhateverTheProxyHoldsAndIsNullBeforePreInit() throws Exception { + assertNull(invokeLogger("codechicken.multipart.package")); + assertNull(invokeLogger("codechicken.microblock.package")); + } + + private static Object invokeLogger(String name) throws Exception { + return Class.forName(name).getDeclaredMethod("logger").invoke(null); + } +}