diff --git a/gradle.properties b/gradle.properties index 4c1bbf8..14c9c43 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1 +1 @@ -library_version=1.0.0b1 +library_version=1.0.0b2 \ No newline at end of file diff --git a/src/main/kotlin/dev/thecodewarrior/mirror/member/ConstructorMirror.kt b/src/main/kotlin/dev/thecodewarrior/mirror/member/ConstructorMirror.kt index f70b89f..a464d0c 100644 --- a/src/main/kotlin/dev/thecodewarrior/mirror/member/ConstructorMirror.kt +++ b/src/main/kotlin/dev/thecodewarrior/mirror/member/ConstructorMirror.kt @@ -46,29 +46,17 @@ public class ConstructorMirror internal constructor( } /** - * Create a new instance using this constructor. If performance is of the essence use [callFast], which should be - * near-native speed, but will provide somewhat less helpful exceptions. + * Create a new instance using this constructor. After the one-time cost of creating the + * [MethodHandle][java.lang.invoke.MethodHandle], the access should be near-native speed. */ @Suppress("UNCHECKED_CAST") public fun call(vararg args: Any?): T { - if(args.size != parameters.size) - throw IllegalArgumentException("Incorrect argument count (${args.size}) for constructor `$this`") return raw.wrapper(args as Array) as T } @JvmSynthetic public operator fun invoke(vararg args: Any?): T = call(*args) - /** - * Create a new instance using this constructor. After the one-time cost of creating the - * [MethodHandle][java.lang.invoke.MethodHandle], the access should be near-native speed. This method, while faster - * than [call], will provide somewhat less helpful exceptions. - */ - @Suppress("UNCHECKED_CAST") - public fun callFast(vararg args: Any?): T { - return raw.wrapper(args as Array) as T - } - override fun toString(): String { var str = "" if(access != Modifier.Access.DEFAULT) { diff --git a/src/main/kotlin/dev/thecodewarrior/mirror/member/FieldMirror.kt b/src/main/kotlin/dev/thecodewarrior/mirror/member/FieldMirror.kt index 355e400..7383786 100644 --- a/src/main/kotlin/dev/thecodewarrior/mirror/member/FieldMirror.kt +++ b/src/main/kotlin/dev/thecodewarrior/mirror/member/FieldMirror.kt @@ -125,33 +125,13 @@ public class FieldMirror internal constructor( MethodHandleHelper.wrapperForStaticGetter(java) } - /** - * Get the value of this field in the passed instance. If this is a static field, `null` should be used for the - * instance. If performance is of the essence however, use [getFast], which should be near-native speed, but will - * have somewhat less helpful exceptions. - */ - @Suppress("UNCHECKED_CAST") - public fun get(receiver: Any?): T { - if(isStatic) { - if(receiver != null) - throw IllegalArgumentException("Invalid receiver for static field `${declaringClass.java.simpleName}.$name`. Expected null.") - return raw.staticGetWrapper() as T - } else { - if (receiver == null) - throw NullPointerException("Null receiver for instance field `${declaringClass.java.simpleName}.$name`") - if(!declaringClass.java.isAssignableFrom(receiver.javaClass)) - throw IllegalArgumentException("Invalid receiver type `${receiver.javaClass.simpleName}` for instance field `${declaringClass.java.simpleName}.$name`") - return raw.instanceGetWrapper(receiver) as T - } - } - /** * Get the value of this field in the passed instance. If this is a static field, `null` should be used for the * instance. After the one-time cost of creating the [MethodHandle][java.lang.invoke.MethodHandle], the access should - * be near-native speed. This method, while faster than [get], will provide somewhat less helpful exceptions. + * be near-native speed. */ @Suppress("UNCHECKED_CAST") - public fun getFast(receiver: Any?): T { + public fun get(receiver: Any?): T { if(isStatic) { return raw.staticGetWrapper() as T } else { @@ -168,33 +148,13 @@ public class FieldMirror internal constructor( MethodHandleHelper.wrapperForStaticSetter(java) } - /** - * Set the value of this field in the passed instance. If this is a static field, `null` should be used for the - * instance. If performance is of the essence however, use [setFast], which should be near-native speed, but will - * have somewhat less helpful exceptions. - */ - @Suppress("UNCHECKED_CAST") - public fun set(receiver: Any?, value: Any?) { - if(isStatic) { - if(receiver != null) - throw IllegalArgumentException("Invalid receiver for static field `${declaringClass.java.simpleName}.$name`. Expected null.") - raw.staticSetWrapper(value) - } else { - if (receiver == null) - throw NullPointerException("Null receiver for instance field `${declaringClass.java.simpleName}.$name`") - if(!declaringClass.java.isAssignableFrom(receiver.javaClass)) - throw IllegalArgumentException("Invalid receiver type `${receiver.javaClass.simpleName}` for instance field `${declaringClass.java.simpleName}.$name`") - raw.instanceSetWrapper(receiver, value) - } - } - /** * Set the value of this field in the passed instance. If this is a static field, `null` should be used for the * instance. After the one-time cost of creating the [MethodHandle][java.lang.invoke.MethodHandle], the access - * should be near-native speed. This method, while faster than [set], will provide somewhat less helpful exceptions. + * should be near-native speed. */ @Suppress("UNCHECKED_CAST") - public fun setFast(receiver: Any?, value: Any?) { + public fun set(receiver: Any?, value: Any?) { if(isStatic) { raw.staticSetWrapper(value) } else { diff --git a/src/main/kotlin/dev/thecodewarrior/mirror/member/MemberMirror.kt b/src/main/kotlin/dev/thecodewarrior/mirror/member/MemberMirror.kt index 95d4ce3..8c7b240 100644 --- a/src/main/kotlin/dev/thecodewarrior/mirror/member/MemberMirror.kt +++ b/src/main/kotlin/dev/thecodewarrior/mirror/member/MemberMirror.kt @@ -42,7 +42,7 @@ public abstract class MemberMirror internal constructor( */ public abstract fun withDeclaringClass(enclosing: ClassMirror?): MemberMirror - override fun getAnnotation(annotationClass: Class): T { + override fun getAnnotation(annotationClass: Class): T? { return annotatedElement.getAnnotation(annotationClass) } diff --git a/src/main/kotlin/dev/thecodewarrior/mirror/member/MethodMirror.kt b/src/main/kotlin/dev/thecodewarrior/mirror/member/MethodMirror.kt index ea7fd00..96da16f 100644 --- a/src/main/kotlin/dev/thecodewarrior/mirror/member/MethodMirror.kt +++ b/src/main/kotlin/dev/thecodewarrior/mirror/member/MethodMirror.kt @@ -175,49 +175,23 @@ public class MethodMirror internal constructor( } /** - * Call this method on the passed instance. If this is a static method, `null` should be used for the instance. If - * performance is of the essence use [callFast], which should be near-native speed, but will provide somewhat less - * helpful exceptions. + * Call this method on the passed instance. If this is a static method, `null` should be used for the instance. + * After the one-time cost of creating the [MethodHandle][java.lang.invoke.MethodHandle], the access should be + * near-native speed. */ @Suppress("UNCHECKED_CAST") @Throws(Throwable::class) public fun call(receiver: Any?, vararg args: Any?): T { if(isStatic) { - if(receiver != null) - throw IllegalArgumentException("Invalid receiver for static method `${declaringClass.java.simpleName}.$name`. Expected null.") - if(args.size != parameters.size) - throw IllegalArgumentException("Incorrect argument count (${args.size}) for static method `$this`") - return raw.staticWrapper(args as Array) as T } else { - if(receiver == null) - throw NullPointerException("Null receiver for instance method `${declaringClass.java.simpleName}.$name`") - if(!declaringClass.java.isAssignableFrom(receiver.javaClass)) - throw IllegalArgumentException("Invalid receiver type `${receiver.javaClass.simpleName}` for instance method `${declaringClass.java.simpleName}.$name`") - if(args.size != parameters.size) - throw IllegalArgumentException("Incorrect argument count (${args.size}) for instance method `$this`") - - return raw.instanceWrapper(receiver, args as Array) as T + return raw.instanceWrapper(receiver!!, args as Array) as T } } @JvmSynthetic public operator fun invoke(receiver: Any?, vararg args: Any?): T = call(receiver, *args) - /** - * Call this method on the passed instance. If this is a static method, `null` should be used for the instance. - * After the one-time cost of creating the [MethodHandle][java.lang.invoke.MethodHandle], the access should be - * near-native speed. This method, while faster than [call], will provide somewhat less helpful exceptions. - */ - @Suppress("UNCHECKED_CAST") - public fun callFast(receiver: Any?, vararg args: Any?): T { - if(isStatic) { - return raw.staticWrapper(args as Array) as T - } else { - return raw.instanceWrapper(receiver!!, args as Array) as T - } - } - override fun toString(): String { var str = "" str += modifiers.joinToString("") { "$it " } diff --git a/src/test/kotlin/dev/thecodewarrior/mirror/methodhandles/Constructors.kt b/src/test/kotlin/dev/thecodewarrior/mirror/methodhandles/Constructors.kt index c81204d..bb2e7bb 100644 --- a/src/test/kotlin/dev/thecodewarrior/mirror/methodhandles/Constructors.kt +++ b/src/test/kotlin/dev/thecodewarrior/mirror/methodhandles/Constructors.kt @@ -64,59 +64,4 @@ internal class Constructors: MTest() { Mirror.reflect(X._constructor()).call(0) } } - - @Test - fun `fast calling a constructor should correctly return an instance`() { - val X by sources.add("X", "class X { int field; X() { field = 20; } }") - sources.compile() - val instance = Mirror.reflect(X._constructor()).callFast() - assertEquals(X, instance.javaClass) - assertEquals(20, instance._get("field")) - } - - @Test - fun `fast calling a private constructor should not throw`() { - val X by sources.add("X", "class X { int field; private X() { field = 20; } }") - sources.compile() - assertDoesNotThrow { - Mirror.reflect(X._constructor()).callFast() - } - } - - @Test - fun `fast calling a constructor with arguments should pass them`() { - val X by sources.add("X", "class X { int field; X(int param) { field = param; } }") - sources.compile() - val instance = Mirror.reflect(X._constructor()).callFast(20) - assertEquals(X, instance.javaClass) - assertEquals(20, instance._get("field")) - } - - @Test - fun `fast calling a constructor with arguments and no parameters should not throw`() { - val X by sources.add("X", "class X { X() { } }") - sources.compile() - // for some reason passing arguments to a zero-arg method is fine, but not constructors? - assertThrows { - Mirror.reflect(X._constructor()).callFast(0) - } - } - - @Test - fun `fast calling a constructor with too many arguments should throw`() { - val X by sources.add("X", "class X { X(int a) { } }") - sources.compile() - assertThrows { - Mirror.reflect(X._constructor()).callFast(0, 1) - } - } - - @Test - fun `fast calling a constructor with too few arguments should throw`() { - val X by sources.add("X", "class X { X(int a, int b) { } }") - sources.compile() - assertThrows { - Mirror.reflect(X._constructor()).callFast(0) - } - } } diff --git a/src/test/kotlin/dev/thecodewarrior/mirror/methodhandles/FastCall.kt b/src/test/kotlin/dev/thecodewarrior/mirror/methodhandles/FastCall.kt deleted file mode 100644 index 4d29fb7..0000000 --- a/src/test/kotlin/dev/thecodewarrior/mirror/methodhandles/FastCall.kt +++ /dev/null @@ -1,105 +0,0 @@ -package dev.thecodewarrior.mirror.methodhandles - -import dev.thecodewarrior.mirror.Mirror -import dev.thecodewarrior.mirror.testsupport.MTest -import dev.thecodewarrior.mirror.testsupport.MirrorTestBase -import org.junit.jupiter.api.Assertions.assertEquals -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.assertDoesNotThrow -import org.junit.jupiter.api.assertThrows - -internal class FastCall: MTest() { - @Test - fun `fast calling a void method should correctly invoke it`() { - val X by sources.add("X", "class X { int field = 10; void method() { this.field = 20; } }") - sources.compile() - val instance = X._new() - Mirror.reflect(X._m("method")).callFast(instance) - assertEquals(20, instance._get("field")) - } - - @Test - fun `fast calling a private method should not throw`() { - val X by sources.add("X", "class X { private void method() { } }") - sources.compile() - val instance = X._new() - assertDoesNotThrow { - Mirror.reflect(X._m("method")).callFast(instance) - } - } - - @Test - fun `fast calling a method with arguments should correctly pass them`() { - val X by sources.add("X", "class X { int field = 10; void method(int param) { this.field = param; } }") - sources.compile() - val instance = X._new() - Mirror.reflect(X._m("method")).callFast(instance, 20) - assertEquals(20, instance._get("field")) - } - - @Test - fun `fast calling a method with a return value should correctly return it`() { - val X by sources.add("X", "class X { int method() { return 20; } }") - sources.compile() - val instance = X._new() - assertEquals(20, Mirror.reflect(X._m("method")).call(instance)) - } - - @Test - fun `fast calling a method with a null receiver should throw`() { - val X by sources.add("X", "class X { void method() { } }") - sources.compile() - assertThrows { - Mirror.reflect(X._m("method")).callFast(null) - } - } - - @Test - fun `fast calling a method with the wrong receiver type should throw`() { - val X by sources.add("X", "class X { void method() { } }") - sources.compile() - assertThrows { - Mirror.reflect(X._m("method")).callFast("") - } - } - - @Test - fun `fast calling a method with arguments and no parameters should not throw`() { - val X by sources.add("X", "class X { void method() { } }") - sources.compile() - val instance = X._new() - assertDoesNotThrow { - Mirror.reflect(X._m("method")).callFast(instance, 0) - } - } - - @Test - fun `fast calling a method with too many arguments should throw`() { - val X by sources.add("X", "class X { void method(int a) { } }") - sources.compile() - val instance = X._new() - assertThrows { - Mirror.reflect(X._m("method")).callFast(instance, 0, 1) - } - } - - @Test - fun `fast calling a method with too few arguments should throw`() { - val X by sources.add("X", "class X { void method(int a, int b) { } }") - sources.compile() - val instance = X._new() - assertThrows { - Mirror.reflect(X._m("method")).callFast(instance, 0) - } - } - - @Test - fun `fast calling a method with wrong parameter types should throw`() { - val X by sources.add("X", "class X { void method(int a, float b) { } }") - sources.compile() - val instance = X._new() - assertThrows { - Mirror.reflect(X._m("method")).callFast(instance, 0, "") - } - } -} diff --git a/src/test/kotlin/dev/thecodewarrior/mirror/methodhandles/Fields.kt b/src/test/kotlin/dev/thecodewarrior/mirror/methodhandles/Fields.kt index 46f5097..b8b4059 100644 --- a/src/test/kotlin/dev/thecodewarrior/mirror/methodhandles/Fields.kt +++ b/src/test/kotlin/dev/thecodewarrior/mirror/methodhandles/Fields.kt @@ -3,6 +3,7 @@ package dev.thecodewarrior.mirror.methodhandles import dev.thecodewarrior.mirror.Mirror import dev.thecodewarrior.mirror.testsupport.MTest import dev.thecodewarrior.mirror.testsupport.MirrorTestBase +import dev.thecodewarrior.mirror.testsupport.assertMessage import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertDoesNotThrow @@ -18,13 +19,13 @@ internal class Fields: MTest() { } @Test - fun `getting a static field with a non-null receiver should throw`() { + fun `getting a static field with a non-null receiver should not throw`() { val X by sources.add("X", "class X { static int field = 10; }") sources.compile() val instance = X._new() val field = Mirror.reflect(X._f("field")) - assertThrows { - field.get(instance) + assertDoesNotThrow { + field.get(instance) } } @@ -38,12 +39,12 @@ internal class Fields: MTest() { } @Test - fun `setting a static field with a non-null receiver should throw`() { + fun `setting a static field with a non-null receiver should not throw`() { val X by sources.add("X", "class X { static int field = 10; }") sources.compile() val instance = X._new() val field = Mirror.reflect(X._f("field")) - assertThrows { + assertDoesNotThrow { field.set(instance, 20) } } @@ -72,9 +73,9 @@ internal class Fields: MTest() { val X by sources.add("X", "class X { int field = 10; }") sources.compile() val field = Mirror.reflect(X._f("field")) - assertThrows { + assertThrows { field.get("") - } + }.assertMessage("Cannot cast java.lang.String to gen.X") } @Test @@ -122,119 +123,4 @@ internal class Fields: MTest() { field.set(null, 20) assertEquals(20, X._get("field")) } - - @Test - fun `fast getting a static field with a null receiver should return its value`() { - val X by sources.add("X", "class X { static int field = 10; }") - sources.compile() - val field = Mirror.reflect(X._f("field")) - assertEquals(10, field.getFast(null)) - } - - @Test - fun `fast getting a static field with a non-null receiver should not throw`() { - val X by sources.add("X", "class X { static int field = 10; }") - sources.compile() - val instance = X._new() - val field = Mirror.reflect(X._f("field")) - assertDoesNotThrow { - assertEquals(10, field.getFast(instance)) - } - } - - @Test - fun `fast setting a static field with a null receiver should change its value`() { - val X by sources.add("X", "class X { static int field = 10; }") - sources.compile() - val field = Mirror.reflect(X._f("field")) - field.setFast(null, 20) - assertEquals(20, X._get("field")) - } - - @Test - fun `fast setting a static field with a non-null receiver should not throw`() { - val X by sources.add("X", "class X { static int field = 10; }") - sources.compile() - val instance = X._new() - val field = Mirror.reflect(X._f("field")) - assertDoesNotThrow { - field.setFast(instance, 20) - } - assertEquals(20, instance._get("field")) - } - - @Test - fun `fast getting a field with a nonnull receiver should return its value`() { - val X by sources.add("X", "class X { int field = 10; }") - sources.compile() - val instance = X._new() - val field = Mirror.reflect(X._f("field")) - assertEquals(10, field.getFast(instance)) - } - - @Test - fun `fast getting a field with a null receiver should throw`() { - val X by sources.add("X", "class X { int field = 10; }") - sources.compile() - val field = Mirror.reflect(X._f("field")) - assertThrows { - field.getFast(null) - } - } - - @Test - fun `fast getting a field with the wrong receiver type should throw`() { - val X by sources.add("X", "class X { int field = 10; }") - sources.compile() - val field = Mirror.reflect(X._f("field")) - assertThrows { - field.getFast("") - } - } - - @Test - fun `fast setting a field with a non-null receiver should change its value`() { - val X by sources.add("X", "class X { int field = 10; }") - sources.compile() - val instance = X._new() - val field = Mirror.reflect(X._f("field")) - field.setFast(instance, 20) - assertEquals(20, instance._get("field")) - } - - @Test - fun `fast setting a field with a null receiver should throw`() { - val X by sources.add("X", "class X { int field = 10; }") - sources.compile() - val field = Mirror.reflect(X._f("field")) - assertThrows { - field.setFast(null, 20) - } - } - - @Test - fun `fast getting a private field with should return its value`() { - val X by sources.add("X", "class X { private static int field = 10; }") - sources.compile() - val field = Mirror.reflect(X._f("field")) - assertEquals(10, field.getFast(null)) - } - - @Test - fun `fast setting a private field should change its value`() { - val X by sources.add("X", "class X { private static int field = 10; }") - sources.compile() - val field = Mirror.reflect(X._f("field")) - field.set(null, 20) - assertEquals(20, X._get("field")) - } - - @Test - fun `fast setting a final field should change its value`() { - val X by sources.add("X", "class X { final static int field = 10; }") - sources.compile() - val field = Mirror.reflect(X._f("field")) - field.set(null, 20) - assertEquals(20, X._get("field")) - } } diff --git a/src/test/kotlin/dev/thecodewarrior/mirror/methodhandles/InstanceMethods.kt b/src/test/kotlin/dev/thecodewarrior/mirror/methodhandles/InstanceMethods.kt index d239d24..c2f9425 100644 --- a/src/test/kotlin/dev/thecodewarrior/mirror/methodhandles/InstanceMethods.kt +++ b/src/test/kotlin/dev/thecodewarrior/mirror/methodhandles/InstanceMethods.kt @@ -3,6 +3,7 @@ package dev.thecodewarrior.mirror.methodhandles import dev.thecodewarrior.mirror.Mirror import dev.thecodewarrior.mirror.testsupport.MTest import dev.thecodewarrior.mirror.testsupport.MirrorTestBase +import dev.thecodewarrior.mirror.testsupport.assertMessage import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertDoesNotThrow @@ -59,21 +60,21 @@ internal class InstanceMethods: MTest() { } @Test - fun `calling a method with the wrong receiver type should throw`() { + fun `calling a method with the wrong receiver type should throw a ClassCastException`() { val X by sources.add("X", "class X { void method() { } }") sources.compile() - assertThrows { + assertThrows { Mirror.reflect(X._m("method")).call("") - } + }.assertMessage("Cannot cast java.lang.String to gen.X") } @Test - fun `calling a method with arguments and no parameters should throw`() { + fun `calling a method with arguments and no parameters should not throw`() { val X by sources.add("X", "class X { void method() { } }") sources.compile() val instance = X._new() assertDoesNotThrow { - Mirror.reflect(X._m("method")).callFast(instance, 0) + Mirror.reflect(X._m("method")).call(instance, 0) } } diff --git a/src/test/kotlin/dev/thecodewarrior/mirror/methodhandles/StaticMethods.kt b/src/test/kotlin/dev/thecodewarrior/mirror/methodhandles/StaticMethods.kt index cc58cff..38be686 100644 --- a/src/test/kotlin/dev/thecodewarrior/mirror/methodhandles/StaticMethods.kt +++ b/src/test/kotlin/dev/thecodewarrior/mirror/methodhandles/StaticMethods.kt @@ -47,7 +47,7 @@ internal class StaticMethods: MTest() { val X by sources.add("X", "class X { static void method() { } }") sources.compile() val instance = X._new() - assertThrows { + assertDoesNotThrow { // Core Reflection just ignores the instance Mirror.reflect(X._m("method")).call(instance) } } @@ -56,7 +56,7 @@ internal class StaticMethods: MTest() { fun `calling a static method with the wrong receiver type should throw`() { val X by sources.add("X", "class X { static void method() { } }") sources.compile() - assertThrows { + assertDoesNotThrow { // Core Reflection just ignores the instance Mirror.reflect(X._m("method")).call("") } } @@ -66,7 +66,7 @@ internal class StaticMethods: MTest() { val X by sources.add("X", "class X { static void method() { } }") sources.compile() assertThrows { - Mirror.reflect(X._m("method")).callFast(null, 0) + Mirror.reflect(X._m("method")).call(null, 0) } } diff --git a/src/test/kotlin/dev/thecodewarrior/mirror/testsupport/TestSourceNopException.kt b/src/test/kotlin/dev/thecodewarrior/mirror/testsupport/TestSourceNopException.kt index b8b696f..a9851a6 100644 --- a/src/test/kotlin/dev/thecodewarrior/mirror/testsupport/TestSourceNopException.kt +++ b/src/test/kotlin/dev/thecodewarrior/mirror/testsupport/TestSourceNopException.kt @@ -2,4 +2,7 @@ package dev.thecodewarrior.mirror.testsupport import java.lang.RuntimeException +/** + * An exception used in TestSource generated classes for nop implementations. + */ class TestSourceNopException: RuntimeException() { } \ No newline at end of file diff --git a/src/test/kotlin/dev/thecodewarrior/mirror/testsupport/TestUtilsAssertions.kt b/src/test/kotlin/dev/thecodewarrior/mirror/testsupport/TestUtilsAssertions.kt index 956cd68..34a96d1 100644 --- a/src/test/kotlin/dev/thecodewarrior/mirror/testsupport/TestUtilsAssertions.kt +++ b/src/test/kotlin/dev/thecodewarrior/mirror/testsupport/TestUtilsAssertions.kt @@ -166,6 +166,39 @@ class TestUtilsAssertions { } } + @Test + fun assertNotInstanceOf_withExactType_shouldFail() { + assertThrows { + assertNotInstanceOf(Object1::class.java, Object1()) + } + } + + @Test + fun assertNotInstanceOf_withSubclass_shouldFail() { + class SubObject1: Object1() + assertThrows { + assertNotInstanceOf(Object1::class.java, SubObject1()) + } + } + + @Test + fun assertNotInstanceOf_withImplementor_shouldFail() { + class SubObject1: Interface1 + assertThrows { + assertNotInstanceOf(Interface1::class.java, SubObject1()) + } + } + + @Test + fun assertNotInstanceOf_withUnrelated_shouldSucceed() { + assertNotInstanceOf(Object2::class.java, Object1()) + } + + @Test + fun assertNotInstanceOf_withSuperclass_shouldSucceed() { + class SubObject1: Interface1 + assertNotInstanceOf(SubObject1::class.java, Object1()) + } // ============================================================================================================= @Test diff --git a/src/test/kotlin/dev/thecodewarrior/mirror/testsupport/Utils.kt b/src/test/kotlin/dev/thecodewarrior/mirror/testsupport/Utils.kt index 811ce81..bcdde62 100644 --- a/src/test/kotlin/dev/thecodewarrior/mirror/testsupport/Utils.kt +++ b/src/test/kotlin/dev/thecodewarrior/mirror/testsupport/Utils.kt @@ -80,17 +80,30 @@ fun assertSetEquals(expected: List, actual: List) { ) } - -fun assertInstanceOf(expected: Class<*>, actual: Any?) { +fun assertInstanceOf(expected: Class, actual: Any?): T { if(!expected.isInstance(actual)) throw AssertionFailedError("", expected.canonicalName, actual.toStringWithIdentity() ) + @Suppress("UNCHECKED_CAST") + return actual as T +} + +inline fun assertInstanceOf(actual: Any?): T { + return assertInstanceOf(T::class.java, actual) +} + +fun assertNotInstanceOf(notExpected: Class<*>, actual: Any?) { + if(notExpected.isInstance(actual)) + throw AssertionFailedError("", + "Not " + notExpected.canonicalName, + actual.toStringWithIdentity() + ) } -inline fun assertInstanceOf(actual: Any?) { - assertInstanceOf(T::class.java, actual) +inline fun assertNotInstanceOf(actual: Any?) { + assertNotInstanceOf(T::class.java, actual) } private fun Any?.toStringWithIdentity(): String { diff --git a/src/test/kotlin/dev/thecodewarrior/mirror/type/classmirror/KClassTest.kt b/src/test/kotlin/dev/thecodewarrior/mirror/type/classmirror/KClassTest.kt new file mode 100644 index 0000000..0cbdf9f --- /dev/null +++ b/src/test/kotlin/dev/thecodewarrior/mirror/type/classmirror/KClassTest.kt @@ -0,0 +1,50 @@ +@file:Suppress("ClassName", "PropertyName") + +package dev.thecodewarrior.mirror.type.classmirror + +import dev.thecodewarrior.mirror.Mirror +import dev.thecodewarrior.mirror.member.MethodMirror +import dev.thecodewarrior.mirror.member.Modifier +import dev.thecodewarrior.mirror.testsupport.* +import dev.thecodewarrior.mirror.utils.Untested +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Nested +import org.junit.jupiter.api.Test +import java.lang.reflect.Method +import kotlin.reflect.KMutableProperty +import kotlin.reflect.KMutableProperty1 +import kotlin.reflect.KProperty1 +import kotlin.reflect.full.declaredMembers +import kotlin.reflect.jvm.jvmErasure + +/** + * Currently just tests for certain KClass behavioral assumptions, but I may eventually create a `KClassMirror` type. + */ +@Suppress("LocalVariableName") +internal class KClassTest: MTest() { + + @Test + fun `declaredMemberProperties should include fields as 'KMutableProperty1's`() { + val A by sources.add("A", "@rt(FIELD) @interface A {}") + val X by sources.add("X", "class X { @A int field; }") + sources.compile() + val members = X.kotlin.declaredMembers.toList() + assertEquals(1, members.size) + val property = assertInstanceOf>(members[0]) + assertEquals("field", property.name) + assertEquals(_int, property.returnType.jvmErasure.java) + } + + @Test + fun `declaredMemberProperties should include final fields as 'KProperty1's`() { + val X by sources.add("X", "class X { final int field = 0; }") + sources.compile() + val members = X.kotlin.declaredMembers.toList() + assertEquals(1, members.size) + val property = assertInstanceOf>(members[0]) + assertNotInstanceOf>(property); + assertEquals("field", property.name) + assertEquals(_int, property.returnType.jvmErasure.java) + } + +}