mirror of
https://github.com/2006-Scape/apollo.git
synced 2026-07-04 16:49:11 +00:00
Support npc and object definitions in plugin tests
This commit is contained in:
+74
-21
@@ -5,6 +5,8 @@ import io.mockk.slot
|
||||
import io.mockk.spyk
|
||||
import io.mockk.staticMockk
|
||||
import org.apollo.cache.def.ItemDefinition
|
||||
import org.apollo.cache.def.NpcDefinition
|
||||
import org.apollo.cache.def.ObjectDefinition
|
||||
import org.apollo.game.message.handler.MessageHandlerChainSet
|
||||
import org.apollo.game.model.World
|
||||
import org.apollo.game.model.entity.Npc
|
||||
@@ -15,14 +17,25 @@ import org.apollo.game.plugin.PluginMetaData
|
||||
import org.apollo.game.plugin.testing.fakes.FakePluginContextFactory
|
||||
import org.apollo.game.plugin.testing.junit.api.ActionCapture
|
||||
import org.apollo.game.plugin.testing.junit.api.annotations.ItemDefinitions
|
||||
import org.apollo.game.plugin.testing.junit.api.annotations.NpcDefinitions
|
||||
import org.apollo.game.plugin.testing.junit.api.annotations.ObjectDefinitions
|
||||
import org.apollo.game.plugin.testing.junit.mocking.StubPrototype
|
||||
import org.junit.jupiter.api.extension.*
|
||||
import java.util.*
|
||||
import org.junit.jupiter.api.extension.AfterAllCallback
|
||||
import org.junit.jupiter.api.extension.AfterEachCallback
|
||||
import org.junit.jupiter.api.extension.AfterTestExecutionCallback
|
||||
import org.junit.jupiter.api.extension.BeforeAllCallback
|
||||
import org.junit.jupiter.api.extension.BeforeEachCallback
|
||||
import org.junit.jupiter.api.extension.ExtensionContext
|
||||
import org.junit.jupiter.api.extension.ParameterContext
|
||||
import org.junit.jupiter.api.extension.ParameterResolver
|
||||
import java.util.ArrayList
|
||||
import kotlin.reflect.KFunction
|
||||
import kotlin.reflect.KMutableProperty
|
||||
import kotlin.reflect.full.companionObject
|
||||
import kotlin.reflect.full.createType
|
||||
import kotlin.reflect.full.declaredMemberFunctions
|
||||
import kotlin.reflect.full.declaredMemberProperties
|
||||
import kotlin.reflect.full.findAnnotation
|
||||
import kotlin.reflect.jvm.isAccessible
|
||||
import kotlin.reflect.jvm.jvmErasure
|
||||
|
||||
internal val supportedTestDoubleTypes = setOf(
|
||||
@@ -67,6 +80,25 @@ class ApolloTestingExtension :
|
||||
val stubHandlers = MessageHandlerChainSet()
|
||||
val stubWorld = spyk(World())
|
||||
|
||||
context.testClass // This _must_ come before plugin environment initialisation
|
||||
.map { it.kotlin.companionObject }
|
||||
.ifPresent { companion ->
|
||||
val companionInstance = companion.objectInstance!!
|
||||
val testClassMethods = companion.declaredMemberFunctions
|
||||
|
||||
createTestDefinitions<ItemDefinition, ItemDefinitions>(
|
||||
testClassMethods, companionInstance, ItemDefinition::getId, ItemDefinition::lookup
|
||||
)
|
||||
|
||||
createTestDefinitions<NpcDefinition, NpcDefinitions>(
|
||||
testClassMethods, companionInstance, NpcDefinition::getId, NpcDefinition::lookup
|
||||
)
|
||||
|
||||
createTestDefinitions<ObjectDefinition, ObjectDefinitions>(
|
||||
testClassMethods, companionInstance, ObjectDefinition::getId, ObjectDefinition::lookup
|
||||
)
|
||||
}
|
||||
|
||||
val pluginEnvironment = KotlinPluginEnvironment(stubWorld)
|
||||
pluginEnvironment.setContext(FakePluginContextFactory.create(stubHandlers))
|
||||
pluginEnvironment.load(ArrayList<PluginMetaData>())
|
||||
@@ -77,22 +109,8 @@ class ApolloTestingExtension :
|
||||
}
|
||||
|
||||
override fun beforeEach(context: ExtensionContext) {
|
||||
val testClass = context.requiredTestClass.kotlin
|
||||
val testClassInstance = context.requiredTestInstance
|
||||
val testClassProps = testClass.declaredMemberProperties
|
||||
val testClassMethods = context.testClass.map { it.kotlin.declaredMemberFunctions }.orElse(emptyList())
|
||||
val testClassItemDefs = testClassMethods.asSequence()
|
||||
.mapNotNull { it.findAnnotation<ItemDefinitions>()?.let { anno -> it to anno } }
|
||||
.flatMap { (it.first.call(context.requiredTestInstance as Any) as Collection<ItemDefinition>).asSequence() }
|
||||
.map { it.id to it }
|
||||
.toMap()
|
||||
|
||||
if (testClassItemDefs.isNotEmpty()) {
|
||||
val itemIdSlot = slot<Int>()
|
||||
|
||||
staticMockk<ItemDefinition>().mock()
|
||||
every { ItemDefinition.lookup(capture(itemIdSlot)) } answers { testClassItemDefs[itemIdSlot.captured] }
|
||||
}
|
||||
val testClassProps = context.requiredTestClass.kotlin.declaredMemberProperties
|
||||
|
||||
val store = context.getStore(namespace)
|
||||
val state = store.get(ApolloTestState::class) as ApolloTestState
|
||||
@@ -101,10 +119,10 @@ class ApolloTestingExtension :
|
||||
.mapNotNull { it as? KMutableProperty<*> }
|
||||
.filter { supportedTestDoubleTypes.contains(it.returnType) }
|
||||
|
||||
propertyStubSites.forEach {
|
||||
it.setter.call(
|
||||
propertyStubSites.forEach { property ->
|
||||
property.setter.call(
|
||||
testClassInstance,
|
||||
state.createStub(StubPrototype(it.returnType.jvmErasure, it.annotations))
|
||||
state.createStub(StubPrototype(property.returnType.jvmErasure, property.annotations))
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -124,4 +142,39 @@ class ApolloTestingExtension :
|
||||
|
||||
return testState.createStub(StubPrototype(paramType, param.annotations.toList()))
|
||||
}
|
||||
|
||||
/**
|
||||
* Mocks the definition class of type [D] for any function with the attached annotation [A].
|
||||
*
|
||||
* @param testClassMethods All of the methods in the class being tested.
|
||||
* @param idMapper The map function that returns an id given a definition [D].
|
||||
* @param lookup The lookup function that returns an instance of [D] given a definition id.
|
||||
*/
|
||||
private inline fun <reified D : Any, reified A : Annotation> createTestDefinitions(
|
||||
testClassMethods: Collection<KFunction<*>>,
|
||||
companionObjectInstance: Any?,
|
||||
crossinline idMapper: (D) -> Int,
|
||||
crossinline lookup: (Int) -> D
|
||||
) {
|
||||
val testDefinitions = testClassMethods.asSequence()
|
||||
.filter { method -> method.annotations.any { it is A } }
|
||||
.flatMap { method ->
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
method as? KFunction<Collection<D>> ?: throw RuntimeException("${method.name} is annotated with " +
|
||||
"${A::class.simpleName} but does not return Collection<${D::class.simpleName}."
|
||||
)
|
||||
|
||||
method.isAccessible = true // lets us call methods in private companion objects
|
||||
method.call(companionObjectInstance).asSequence()
|
||||
}
|
||||
.associateBy(idMapper)
|
||||
|
||||
if (testDefinitions.isNotEmpty()) {
|
||||
val idSlot = slot<Int>()
|
||||
|
||||
staticMockk<D>().mock()
|
||||
every { lookup(capture(idSlot)) } answers { testDefinitions[idSlot.captured]!! }
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+33
-1
@@ -1,5 +1,37 @@
|
||||
package org.apollo.game.plugin.testing.junit.api.annotations
|
||||
|
||||
/**
|
||||
* Specifies that the the ItemDefinitions returned by the annotated function should be inserted into the definition
|
||||
* table.
|
||||
*
|
||||
* The annotated function **must**:
|
||||
* - Be inside a **companion object** inside an apollo test class (a regular object will not work).
|
||||
* - Return a `Collection<ItemDefinition>`.
|
||||
*/
|
||||
@Target(AnnotationTarget.FUNCTION)
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
annotation class ItemDefinitions
|
||||
annotation class ItemDefinitions
|
||||
|
||||
/**
|
||||
* Specifies that the the NpcDefinitions returned by the annotated function should be inserted into the definition
|
||||
* table.
|
||||
*
|
||||
* The annotated function **must**:
|
||||
* - Be inside a **companion object** inside an apollo test class (a regular object will not work).
|
||||
* - Return a `Collection<NpcDefinition>`.
|
||||
*/
|
||||
@Target(AnnotationTarget.FUNCTION)
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
annotation class NpcDefinitions
|
||||
|
||||
/**
|
||||
* Specifies that the the ObjectDefinitions returned by the annotated function should be inserted into the definition
|
||||
* table.
|
||||
*
|
||||
* The annotated function **must**:
|
||||
* - Be inside a **companion object** inside an apollo test class (a regular object will not work).
|
||||
* - Return a `Collection<ObjectDefinition>`.
|
||||
*/
|
||||
@Target(AnnotationTarget.FUNCTION)
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
annotation class ObjectDefinitions
|
||||
Reference in New Issue
Block a user