test: Add sack util test

This commit is contained in:
Linnea Gräf
2024-11-13 13:40:50 +01:00
parent db87e52938
commit d267913e20
13 changed files with 408 additions and 252 deletions

View File

@@ -7,6 +7,8 @@
*/ */
import com.google.devtools.ksp.gradle.KspTaskJvm import com.google.devtools.ksp.gradle.KspTaskJvm
import com.google.gson.Gson
import com.google.gson.JsonObject
import moe.nea.licenseextractificator.LicenseDiscoveryTask import moe.nea.licenseextractificator.LicenseDiscoveryTask
import moe.nea.mcautotranslations.gradle.CollectTranslations import moe.nea.mcautotranslations.gradle.CollectTranslations
import net.fabricmc.loom.LoomGradleExtension import net.fabricmc.loom.LoomGradleExtension
@@ -219,7 +221,8 @@ val configuredSourceSet = createIsolatedSourceSet("configured",
val sodiumSourceSet = createIsolatedSourceSet("sodium") val sodiumSourceSet = createIsolatedSourceSet("sodium")
val citResewnSourceSet = createIsolatedSourceSet("citresewn", isEnabled = false) // TODO: Wait for update val citResewnSourceSet = createIsolatedSourceSet("citresewn", isEnabled = false) // TODO: Wait for update
val yaclSourceSet = createIsolatedSourceSet("yacl") val yaclSourceSet = createIsolatedSourceSet("yacl")
val explosiveEnhancementSourceSet = createIsolatedSourceSet("explosiveEnhancement", isEnabled = false) // TODO: wait for their port val explosiveEnhancementSourceSet =
createIsolatedSourceSet("explosiveEnhancement", isEnabled = false) // TODO: wait for their port
val wildfireGenderSourceSet = createIsolatedSourceSet("wildfireGender", isEnabled = false) // TODO: wait on their port val wildfireGenderSourceSet = createIsolatedSourceSet("wildfireGender", isEnabled = false) // TODO: wait on their port
val modmenuSourceSet = createIsolatedSourceSet("modmenu") val modmenuSourceSet = createIsolatedSourceSet("modmenu")
val reiSourceSet = createIsolatedSourceSet("rei") val reiSourceSet = createIsolatedSourceSet("rei")
@@ -344,7 +347,35 @@ mcAutoTranslations {
translationFunctionResolved.set("moe.nea.firmament.util.trResolved") translationFunctionResolved.set("moe.nea.firmament.util.trResolved")
} }
val downloadTestRepo by tasks.registering(RepoDownload::class) {
this.hash.set(project.property("firmament.compiletimerepohash") as String)
}
val updateTestRepo by tasks.registering {
outputs.upToDateWhen { false }
doLast {
val propertiesFile = rootProject.file("gradle.properties")
val json =
Gson().fromJson(uri("https://api.github.com/repos/NotEnoughUpdates/NotEnoughUpdates-REPO/branches/master")
.toURL().readText(), JsonObject::class.java)
val latestSha = json["commit"].asJsonObject["sha"].asString
var text = propertiesFile.readText()
text = text.replace("firmament\\.compiletimerepohash=[^\n]*".toRegex(),
"firmament.compiletimerepohash=$latestSha")
propertiesFile.writeText(text)
}
}
tasks.test { tasks.test {
val wd =file("build/testWorkDir")
workingDir(wd)
dependsOn(downloadTestRepo)
doFirst {
wd.mkdirs()
wd.resolve("config").deleteRecursively()
systemProperty("firmament.testrepo", downloadTestRepo.flatMap { it.outputDirectory.asFile }.map { it.absolutePath }.get())
}
useJUnitPlatform() useJUnitPlatform()
} }

View File

@@ -0,0 +1,41 @@
import java.net.URI
import java.util.zip.ZipInputStream
import org.gradle.api.DefaultTask
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.provider.Property
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.OutputDirectory
import org.gradle.api.tasks.TaskAction
abstract class RepoDownload : DefaultTask() {
@get:Input
abstract val hash: Property<String>
@get:OutputDirectory
abstract val outputDirectory: DirectoryProperty
init {
outputDirectory.convention(project.layout.buildDirectory.dir("extracted-test-repo"))
}
@TaskAction
fun performDownload() {
val outputDir = outputDirectory.asFile.get().absoluteFile
outputDir.mkdirs()
URI("https://github.com/notEnoughUpdates/notEnoughUpdates-rEPO/archive/${hash.get()}.zip").toURL().openStream()
.let(::ZipInputStream)
.use { zipInput ->
while (true) {
val entry = zipInput.nextEntry ?: break
val destination = outputDir.resolve(
entry.name.substringAfter('/')).absoluteFile
require(outputDir in generateSequence(destination) { it.parentFile })
if (entry.isDirectory) continue
destination.parentFile.mkdirs()
destination.outputStream().use { output ->
zipInput.copyTo(output)
}
}
}
}
}

View File

@@ -1,4 +1,4 @@
# SPDX-FileCopyrightText: 2023 Linnea Gr<EFBFBD>f <nea@nea.moe> # SPDX-FileCopyrightText: 2023 Linnea Gräf <nea@nea.moe>
# #
# SPDX-License-Identifier: CC0-1.0 # SPDX-License-Identifier: CC0-1.0
# suppress inspection "UnusedProperty" for whole file # suppress inspection "UnusedProperty" for whole file
@@ -9,3 +9,4 @@ loom.platform=fabric
archives_base_name=Firmament archives_base_name=Firmament
maven_group=moe.nea.firmament maven_group=moe.nea.firmament
firmament.compiletimerepohash=a6116d945491d7c57c93d43f51250f93d62d8434

View File

@@ -20,6 +20,7 @@ import moe.nea.firmament.util.TimeMark
import moe.nea.firmament.util.WarpUtil import moe.nea.firmament.util.WarpUtil
import moe.nea.firmament.util.render.RenderInWorldContext import moe.nea.firmament.util.render.RenderInWorldContext
import moe.nea.firmament.util.skyBlockId import moe.nea.firmament.util.skyBlockId
import moe.nea.firmament.util.skyblock.SkyBlockItems
object AncestralSpadeSolver : SubscriptionOwner { object AncestralSpadeSolver : SubscriptionOwner {
var lastDing = TimeMark.farPast() var lastDing = TimeMark.farPast()
@@ -29,13 +30,12 @@ object AncestralSpadeSolver : SubscriptionOwner {
var nextGuess: Vec3d? = null var nextGuess: Vec3d? = null
private set private set
val ancestralSpadeId = SkyblockId("ANCESTRAL_SPADE")
private var lastTeleportAttempt = TimeMark.farPast() private var lastTeleportAttempt = TimeMark.farPast()
fun isEnabled() = fun isEnabled() =
DianaWaypoints.TConfig.ancestralSpadeSolver DianaWaypoints.TConfig.ancestralSpadeSolver
&& SBData.skyblockLocation == SkyBlockIsland.HUB && SBData.skyblockLocation == SkyBlockIsland.HUB
&& MC.player?.inventory?.containsAny { it.skyBlockId == ancestralSpadeId } == true // TODO: add a reactive property here && MC.player?.inventory?.containsAny { it.skyBlockId == SkyBlockItems.ANCESTRAL_SPADE } == true // TODO: add a reactive property here
@Subscribe @Subscribe
fun onKeyBind(event: WorldKeyboardEvent) { fun onKeyBind(event: WorldKeyboardEvent) {

View File

@@ -1,5 +1,3 @@
package moe.nea.firmament.repo package moe.nea.firmament.repo
import com.mojang.serialization.Dynamic import com.mojang.serialization.Dynamic
@@ -30,13 +28,15 @@ import moe.nea.firmament.Firmament
import moe.nea.firmament.gui.config.HudMeta import moe.nea.firmament.gui.config.HudMeta
import moe.nea.firmament.gui.config.HudPosition import moe.nea.firmament.gui.config.HudPosition
import moe.nea.firmament.gui.hud.MoulConfigHud import moe.nea.firmament.gui.hud.MoulConfigHud
import moe.nea.firmament.repo.RepoManager.initialize
import moe.nea.firmament.util.LegacyTagParser import moe.nea.firmament.util.LegacyTagParser
import moe.nea.firmament.util.MC import moe.nea.firmament.util.MC
import moe.nea.firmament.util.SkyblockId import moe.nea.firmament.util.SkyblockId
import moe.nea.firmament.util.TestUtil
import moe.nea.firmament.util.mc.appendLore import moe.nea.firmament.util.mc.appendLore
import moe.nea.firmament.util.mc.modifyLore
import moe.nea.firmament.util.mc.setCustomName import moe.nea.firmament.util.mc.setCustomName
import moe.nea.firmament.util.mc.setSkullOwner import moe.nea.firmament.util.mc.setSkullOwner
import moe.nea.firmament.util.mc.modifyLore
import moe.nea.firmament.util.skyblockId import moe.nea.firmament.util.skyblockId
object ItemCache : IReloadable { object ItemCache : IReloadable {
@@ -130,9 +130,8 @@ object ItemCache : IReloadable {
return Text.literal(string).styled { this.style } return Text.literal(string).styled { this.style }
} }
fun NEUItem.getIdentifier() = skyblockId.identifier
var job: Job? = null var job: Job? = null
object ReloadProgressHud : MoulConfigHud( object ReloadProgressHud : MoulConfigHud(
"repo_reload", HudMeta(HudPosition(0.0, 0.0, 1F), Text.literal("Repo Reload"), 180, 18)) { "repo_reload", HudMeta(HudPosition(0.0, 0.0, 1F), Text.literal("Repo Reload"), 180, 18)) {
@@ -165,7 +164,7 @@ object ItemCache : IReloadable {
} }
cache.clear() cache.clear()
isFlawless = true isFlawless = true
if (TestUtil.isInTest) return
job = Firmament.coroutineScope.launch { job = Firmament.coroutineScope.launch {
val items = repository.items?.items val items = repository.items?.items
if (items == null) { if (items == null) {
@@ -203,6 +202,13 @@ object ItemCache : IReloadable {
itemStack.setSkullOwner(uuid, texture) itemStack.setSkullOwner(uuid, texture)
return itemStack return itemStack
} }
init {
if (TestUtil.isInTest) {
initialize()
}
}
} }

View File

@@ -1,4 +1,3 @@
package moe.nea.firmament.repo package moe.nea.firmament.repo
import io.github.moulberry.repo.IReloadable import io.github.moulberry.repo.IReloadable
@@ -95,4 +94,8 @@ object ItemNameLookup : IReloadable {
return bestMatch return bestMatch
} }
init {
RepoManager.initialize()
}
} }

View File

@@ -5,6 +5,7 @@ import io.github.moulberry.repo.NEURepositoryException
import io.github.moulberry.repo.data.NEUItem import io.github.moulberry.repo.data.NEUItem
import io.github.moulberry.repo.data.NEURecipe import io.github.moulberry.repo.data.NEURecipe
import io.github.moulberry.repo.data.Rarity import io.github.moulberry.repo.data.Rarity
import java.nio.file.Path
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import net.minecraft.client.MinecraftClient import net.minecraft.client.MinecraftClient
@@ -14,9 +15,11 @@ import moe.nea.firmament.Firmament
import moe.nea.firmament.Firmament.logger import moe.nea.firmament.Firmament.logger
import moe.nea.firmament.events.ReloadRegistrationEvent import moe.nea.firmament.events.ReloadRegistrationEvent
import moe.nea.firmament.gui.config.ManagedConfig import moe.nea.firmament.gui.config.ManagedConfig
import moe.nea.firmament.util.ErrorUtil
import moe.nea.firmament.util.MC import moe.nea.firmament.util.MC
import moe.nea.firmament.util.MinecraftDispatcher import moe.nea.firmament.util.MinecraftDispatcher
import moe.nea.firmament.util.SkyblockId import moe.nea.firmament.util.SkyblockId
import moe.nea.firmament.util.TestUtil
import moe.nea.firmament.util.tr import moe.nea.firmament.util.tr
object RepoManager { object RepoManager {
@@ -49,12 +52,17 @@ object RepoManager {
var recentlyFailedToUpdateItemList = false var recentlyFailedToUpdateItemList = false
val neuRepo: NEURepository = NEURepository.of(RepoDownloadManager.repoSavedLocation).apply { val essenceRecipeProvider = EssenceRecipeProvider()
val recipeCache = BetterRepoRecipeCache(essenceRecipeProvider)
fun makeNEURepository(path: Path): NEURepository {
return NEURepository.of(path).apply {
registerReloadListener(ItemCache) registerReloadListener(ItemCache)
registerReloadListener(ExpLadders) registerReloadListener(ExpLadders)
registerReloadListener(ItemNameLookup) registerReloadListener(ItemNameLookup)
ReloadRegistrationEvent.publish(ReloadRegistrationEvent(this)) ReloadRegistrationEvent.publish(ReloadRegistrationEvent(this))
registerReloadListener { registerReloadListener {
if (TestUtil.isInTest) return@registerReloadListener
Firmament.coroutineScope.launch(MinecraftDispatcher) { Firmament.coroutineScope.launch(MinecraftDispatcher) {
if (!trySendClientboundUpdateRecipesPacket()) { if (!trySendClientboundUpdateRecipesPacket()) {
logger.warn("Failed to issue a ClientboundUpdateRecipesPacket (to reload REI). This may lead to an outdated item list.") logger.warn("Failed to issue a ClientboundUpdateRecipesPacket (to reload REI). This may lead to an outdated item list.")
@@ -62,15 +70,13 @@ object RepoManager {
} }
} }
} }
registerReloadListener(essenceRecipeProvider)
registerReloadListener(recipeCache)
}
} }
val essenceRecipeProvider = EssenceRecipeProvider() lateinit var neuRepo: NEURepository
val recipeCache = BetterRepoRecipeCache(essenceRecipeProvider) private set
init {
neuRepo.registerReloadListener(essenceRecipeProvider)
neuRepo.registerReloadListener(recipeCache)
}
fun getAllRecipes() = neuRepo.items.items.values.asSequence().flatMap { it.recipes } fun getAllRecipes() = neuRepo.items.items.values.asSequence().flatMap { it.recipes }
@@ -106,6 +112,11 @@ object RepoManager {
} }
} }
fun reloadForTest(from: Path) {
neuRepo = makeNEURepository(from)
reload()
}
fun reload() { fun reload() {
try { try {
ItemCache.ReloadProgressHud.reportProgress("Reloading from Disk", ItemCache.ReloadProgressHud.reportProgress("Reloading from Disk",
@@ -114,16 +125,24 @@ object RepoManager {
ItemCache.ReloadProgressHud.isEnabled = true ItemCache.ReloadProgressHud.isEnabled = true
neuRepo.reload() neuRepo.reload()
} catch (exc: NEURepositoryException) { } catch (exc: NEURepositoryException) {
ErrorUtil.softError("Failed to reload repository", exc)
MC.sendChat( MC.sendChat(
tr("firmament.repo.reloadfail", tr("firmament.repo.reloadfail",
"Failed to reload repository. This will result in some mod features not working.") "Failed to reload repository. This will result in some mod features not working.")
) )
ItemCache.ReloadProgressHud.isEnabled = false ItemCache.ReloadProgressHud.isEnabled = false
exc.printStackTrace()
} }
} }
private var wasInitialized = false
fun initialize() { fun initialize() {
if (wasInitialized) return
wasInitialized = true
System.getProperty("firmament.testrepo")?.let { compTimeRepo ->
reloadForTest(Path.of(compTimeRepo))
return
}
neuRepo = makeNEURepository(RepoDownloadManager.repoSavedLocation)
if (Config.autoUpdate) { if (Config.autoUpdate) {
launchAsyncUpdate() launchAsyncUpdate()
} else { } else {
@@ -131,6 +150,12 @@ object RepoManager {
} }
} }
init {
if (TestUtil.isInTest) {
initialize()
}
}
fun getPotentialStubPetData(skyblockId: SkyblockId): PetData? { fun getPotentialStubPetData(skyblockId: SkyblockId): PetData? {
val parts = skyblockId.neuItem.split(";") val parts = skyblockId.neuItem.split(";")
if (parts.size != 2) { if (parts.size != 2) {

View File

@@ -10,7 +10,7 @@ import moe.nea.firmament.Firmament
@Suppress("NOTHING_TO_INLINE") // Suppressed since i want the logger to not pick up the ErrorUtil stack-frame @Suppress("NOTHING_TO_INLINE") // Suppressed since i want the logger to not pick up the ErrorUtil stack-frame
object ErrorUtil { object ErrorUtil {
var aggressiveErrors = run { var aggressiveErrors = run {
Thread.currentThread().stackTrace.any { it.className.startsWith("org.junit.") } || Firmament.DEBUG TestUtil.isInTest || Firmament.DEBUG
|| ErrorUtil::class.java.desiredAssertionStatus() || ErrorUtil::class.java.desiredAssertionStatus()
} }

View File

@@ -102,7 +102,7 @@ object MC {
inline val handledScreen: HandledScreen<*>? get() = instance.currentScreen as? HandledScreen<*> inline val handledScreen: HandledScreen<*>? get() = instance.currentScreen as? HandledScreen<*>
inline val window get() = instance.window inline val window get() = instance.window
inline val currentRegistries: RegistryWrapper.WrapperLookup? get() = world?.registryManager inline val currentRegistries: RegistryWrapper.WrapperLookup? get() = world?.registryManager
val defaultRegistries: RegistryWrapper.WrapperLookup = BuiltinRegistries.createWrapperLookup() val defaultRegistries: RegistryWrapper.WrapperLookup by lazy { BuiltinRegistries.createWrapperLookup() }
inline val currentOrDefaultRegistries get() = currentRegistries ?: defaultRegistries inline val currentOrDefaultRegistries get() = currentRegistries ?: defaultRegistries
val defaultItems: RegistryWrapper.Impl<Item> = defaultRegistries.getOrThrow(RegistryKeys.ITEM) val defaultItems: RegistryWrapper.Impl<Item> = defaultRegistries.getOrThrow(RegistryKeys.ITEM)
var lastWorld: World? = null var lastWorld: World? = null

View File

@@ -0,0 +1,5 @@
package moe.nea.firmament.util
object TestUtil {
val isInTest = Thread.currentThread().stackTrace.any { it.className.startsWith("org.junit.") }
}

View File

@@ -60,8 +60,13 @@ object SackUtil {
@Subscribe @Subscribe
fun updateFromChat(event: ProcessChatEvent) { fun updateFromChat(event: ProcessChatEvent) {
if (!event.unformattedString.startsWith("[Sacks]")) return if (!event.unformattedString.startsWith("[Sacks]")) return
getUpdatesFromMessage(event.text)
}
fun getUpdatesFromMessage(text: Text): List<SackUpdate> {
val update = ChatUpdate() val update = ChatUpdate()
event.text.siblings.forEach(update::updateFromHoverText) text.siblings.forEach(update::updateFromHoverText)
return update.updates
} }
data class SackUpdate( data class SackUpdate(

View File

@@ -0,0 +1,10 @@
package moe.nea.firmament.util.skyblock
import moe.nea.firmament.util.SkyblockId
object SkyBlockItems {
val ROTTEN_FLESH = SkyblockId("ROTTEN_FLESH")
val ENCHANTED_DIAMOND = SkyblockId("ENCHANTED_DIAMOND")
val DIAMOND = SkyblockId("DIAMOND")
val ANCESTRAL_SPADE = SkyblockId("ANCESTRAL_SPADE")
}

View File

@@ -0,0 +1,29 @@
package moe.nea.firmament.test.util.skyblock
import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.Test
import moe.nea.firmament.test.testutil.ItemResources
import moe.nea.firmament.util.skyblock.SackUtil
import moe.nea.firmament.util.skyblock.SkyBlockItems
class SackUtilTest {
@Test
fun testOneRottenFlesh() {
Assertions.assertEquals(
listOf(
SackUtil.SackUpdate(SkyBlockItems.ROTTEN_FLESH, "Rotten Flesh", 1)
),
SackUtil.getUpdatesFromMessage(ItemResources.loadText("sacks/gain-rotten-flesh"))
)
}
@Test
fun testAFewRegularItems() {
Assertions.assertEquals(
listOf(
SackUtil.SackUpdate(SkyBlockItems.ROTTEN_FLESH, "Rotten Flesh", 1)
),
SackUtil.getUpdatesFromMessage(ItemResources.loadText("sacks/gain-and-lose-regular"))
)
}
}