Unit test catching un-annotated lazies (#4886)

This commit is contained in:
SomeTroglodyte
2021-08-17 12:52:41 +02:00
committed by GitHub
parent 8c97e2c6fc
commit 076128a37e
2 changed files with 113 additions and 1 deletions

View File

@ -0,0 +1,110 @@
package com.unciv.testing
import com.unciv.Constants
import com.unciv.UncivGame
import com.unciv.logic.GameInfo
import com.unciv.logic.GameSaver
import com.unciv.logic.GameStarter
import com.unciv.logic.civilization.PlayerType
import com.unciv.logic.map.MapParameters
import com.unciv.logic.map.MapSize
import com.unciv.logic.map.MapSizeNew
import com.unciv.models.metadata.GameParameters
import com.unciv.models.metadata.GameSettings
import com.unciv.models.metadata.Player
import com.unciv.models.ruleset.RulesetCache
import com.unciv.ui.newgamescreen.GameSetupInfo
import org.junit.Assert
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(GdxTestRunner::class)
class SerializationTests {
private var game = GameInfo()
/** A runtime Class object for [kotlin.SynchronizedLazyImpl] to enable helping Gdx.Json to
* not StackOverflow on them, as a direct compile time retrieval is forbidden */
private val classSynchronizedLazyImpl: Class<*> by lazy {
// I hope you get the irony...
@Suppress("unused") // No, test is not _directly_ used, only reflected on
class TestWithLazy { val test: Int by lazy { 0 } }
val badInstance = TestWithLazy()
val badField = badInstance::class.java.declaredFields[0]
badField.isAccessible = true
badField.get(badInstance)::class.java
}
@Before
fun prepareGame() {
RulesetCache.loadRulesets(noMods = true)
// Create a tiny game with just 1 human player and the barbarians
// Must be 1 human otherwise GameInfo.setTransients crashes on the `if (currentPlayer == "")` line
val param = GameParameters().apply {
numberOfCityStates = 0
players.clear()
players.add(Player("Rome").apply { playerType = PlayerType.Human })
players.add(Player("Greece"))
religionEnabled = true
}
val mapParameters = MapParameters().apply {
mapSize = MapSizeNew(MapSize.Tiny)
seed = 42L
}
val setup = GameSetupInfo(param, mapParameters)
UncivGame.Current = UncivGame("")
UncivGame.Current.settings = GameSettings()
game = GameStarter.startNewGame(setup)
UncivGame.Current.gameInfo = game
// Found a city otherwise too many classes have no instance and are not tested
val civ = game.getCurrentPlayerCivilization()
val unit = civ.getCivUnits().first { it.hasUnique(Constants.settlerUnique) }
val tile = unit.getTile()
unit.civInfo.addCity(tile.position)
if (tile.ruleset.tileImprovements.containsKey("City center"))
tile.improvement = "City center"
unit.destroy()
// Ensure some diplomacy objects are instantiated
val otherCiv = game.getCivilization("Greece")
civ.makeCivilizationsMeet(otherCiv)
}
@Test
fun canSerializeGame() {
val json = try {
GameSaver.json().toJson(game)
} catch (ex: Exception) {
""
}
Assert.assertTrue("This test will only pass when a game can be serialized", json.isNotEmpty())
}
@Test
fun serializedLaziesTest() {
val jsonSerializer = com.badlogic.gdx.utils.Json().apply {
setIgnoreDeprecated(true)
setDeprecated(classSynchronizedLazyImpl, "initializer", true)
setDeprecated(classSynchronizedLazyImpl, "lock", true) // this is the culprit as kotlin initializes it to `this@SynchronizedLazyImpl`
}
val json = try {
jsonSerializer.toJson(game)
} catch (ex: Throwable) {
ex.printStackTrace()
return
}
val pattern = """\{(\w+)\${'$'}delegate:\{class:kotlin.SynchronizedLazyImpl,"""
val matches = Regex(pattern).findAll(json)
matches.forEach {
println("Lazy missing `@delegate:Transient` annotation: " + it.groups[1]!!.value)
}
val result = matches.any()
Assert.assertFalse("This test will only pass when no serializable lazy fields are found", result)
}
}