Skip to content

Commit

Permalink
mod loading test, fix infinite loading
Browse files Browse the repository at this point in the history
  • Loading branch information
Bixilon committed Dec 19, 2023
1 parent ce7d320 commit 41ccca8
Show file tree
Hide file tree
Showing 8 changed files with 139 additions and 6 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*
* Minosoft
* Copyright (C) 2020-2023 Moritz Zwerger
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/

package de.bixilon.minosoft.modding.loader.phase

import de.bixilon.kutil.cast.CastUtil.unsafeCast
import de.bixilon.kutil.latch.SimpleLatch
import de.bixilon.kutil.reflection.ReflectionUtil.forceSet
import de.bixilon.kutil.reflection.ReflectionUtil.getFieldOrNull
import de.bixilon.minosoft.modding.loader.ModLoader
import de.bixilon.minosoft.terminal.RunConfiguration
import org.testng.Assert.assertEquals
import org.testng.annotations.Test
import java.io.File


@Test(groups = ["mods"])
class LoadingPhaseTest {

private fun create(path: String): LoadingPhase {
ModLoader.mods.clear()
val phase = LoadingPhase(path)
phase::class.java.getFieldOrNull("path")!!.forceSet(phase, File("./src/integration-test/resources/mods/$path"))

return phase
}

private val LoadingPhase.latch: SimpleLatch get() = this::class.java.getFieldOrNull("latch")!!.get(this).unsafeCast()

fun setup() {
val phase = create("empty")
assertEquals(phase.state, PhaseStates.WAITING)
assertEquals(phase.latch.count, 1) // not started
}

fun `load but skip loading`() {
val phase = create("empty")
RunConfiguration.IGNORE_MODS = true
phase.load()
RunConfiguration.IGNORE_MODS = false
phase.latch.await()
}

fun `load empty`() {
val phase = create("empty")
phase.load()
assertEquals(phase.state, PhaseStates.COMPLETE)
assertEquals(phase.latch.count, 0)
phase.await()
assertEquals(ModLoader.mods.mods.size, 0)
}

fun `broken mod`() {
val phase = create("broken")
phase.load()
phase.await()
assertEquals(ModLoader.mods.mods.size, 0)
}

fun `nocode mod`() {
val phase = create("nocode")
phase.load()
phase.await()
assertEquals(ModLoader.mods.mods.size, 0)
}

fun `dummy mod`() {
val phase = create("dummy")
phase.load()
phase.await()
assertEquals(ModLoader.mods.mods.size, 1)
val mod = ModLoader.mods["dummy"]!!.main!!
assertEquals(mod::class.java.getFieldOrNull("dummy")!!.get(mod), 1)
assertEquals(mod::class.java.getFieldOrNull("init")!!.get(mod), 1)
assertEquals(mod::class.java.getFieldOrNull("postInit")!!.get(mod), 1)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Intentionally bad formatted
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Minosoft
* Copyright (C) 2020-2023 Moritz Zwerger
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/

package de.bixilon.minosoft.modding.dummy

import de.bixilon.minosoft.modding.loader.mod.ModMain

object DummyMod : ModMain() {
var dummy = 1
var init = 0
var postInit = 0

override fun init() {
init++
}

override fun postInit() {
postInit++
}
}
6 changes: 6 additions & 0 deletions src/integration-test/resources/mods/dummy/dummy/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"name": "dummy",
"version": "1.0",
"main": "de.bixilon.minosoft.modding.dummy.DummyMod"
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"name": "dummy",
"version": "1.0",
"main": "de.bixilon.minosoft.modding.dummy.DummyNotExistant"
}

8 changes: 7 additions & 1 deletion src/main/java/de/bixilon/minosoft/modding/loader/ModList.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* Minosoft
* Copyright (C) 2020-2022 Moritz Zwerger
* Copyright (C) 2020-2023 Moritz Zwerger
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
Expand Down Expand Up @@ -74,6 +74,12 @@ class ModList(
this.virtual += list.virtual
}

@Synchronized
fun clear() {
this.mods.clear()
this.virtual.clear()
}

override fun iterator(): Iterator<MinosoftMod> {
return mods.values.iterator()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import de.bixilon.kutil.observer.DataObserver.Companion.observed
import de.bixilon.minosoft.modding.loader.ModList
import de.bixilon.minosoft.modding.loader.ModLoader
import de.bixilon.minosoft.modding.loader.ModLoadingUtil.construct
import de.bixilon.minosoft.modding.loader.ModLoadingUtil.postInit
import de.bixilon.minosoft.modding.loader.ModLoadingUtil.validate
import de.bixilon.minosoft.modding.loader.error.DuplicateModError
import de.bixilon.minosoft.modding.loader.error.DuplicateProvidedError
Expand All @@ -40,10 +41,6 @@ class LoadingPhase(val name: String) {
var state by observed(PhaseStates.WAITING)
private set

private fun MinosoftMod.postInit() {
main!!.postInit()
}

private fun inject(list: ModList, source: ModSource, latch: AbstractLatch) {
val mod = MinosoftMod(source, this, ParentLatch(4, latch))
Log.log(LogMessageType.MOD_LOADING, LogLevels.VERBOSE) { "Injecting $source" }
Expand Down Expand Up @@ -97,7 +94,7 @@ class LoadingPhase(val name: String) {
if (files.isEmpty() && additionalSources.isEmpty()) {
// no mods to load
state = PhaseStates.COMPLETE
this.latch.dec()
inner.dec(); this.latch.dec()
return
}
val list = ModList()
Expand Down

0 comments on commit 41ccca8

Please sign in to comment.