[O] Recursive test

This commit is contained in:
Azalea
2026-08-04 21:08:13 +00:00
parent 13c28bd619
commit 48441188c6
+82 -29
View File
@@ -1,6 +1,7 @@
package test
import com.fasterxml.jackson.databind.JsonNode
import com.fasterxml.jackson.databind.ObjectMapper
import ext.JACKSON
import icu.samnyan.aqua.net.games.chu3.Chu3DataExport
import icu.samnyan.aqua.net.games.mai2.Maimai2DataExport
@@ -14,9 +15,11 @@ import icu.samnyan.aqua.sega.ongeki.model.UserData as OngekiUserData
import icu.samnyan.aqua.sega.ongeki.model.UserPlaylog as OngekiUserPlaylog
import icu.samnyan.aqua.sega.util.BASIC_MAPPER
import icu.samnyan.aqua.sega.util.STRING_MAPPER
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertFalse
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.Test
import tools.jackson.databind.json.JsonMapper
import tools.jackson.module.kotlin.KotlinModule
class ReproduceIssueTest {
@@ -25,16 +28,28 @@ class ReproduceIssueTest {
?: error("Test resource $path not found")
}
private fun checkFieldNamesMatch(baselineNode: JsonNode, currentNode: JsonNode, path: String) {
val baselineKeys = baselineNode.fieldNames().asSequence().toSet()
val currentKeys = currentNode.fieldNames().asSequence().toSet()
private fun checkFieldNamesMatchRecursive(baselineNode: JsonNode, currentNode: JsonNode, path: String = "$") {
if (baselineNode.isObject && currentNode.isObject) {
val baselineKeys = baselineNode.fieldNames().asSequence().toSet()
val currentKeys = currentNode.fieldNames().asSequence().toSet()
val missingKeys = baselineKeys - currentKeys
assertTrue(missingKeys.isEmpty(), "Missing keys at $path: $missingKeys. Current keys: $currentKeys")
val missingKeys = baselineKeys - currentKeys
assertTrue(missingKeys.isEmpty(), "Missing keys at path '$path': $missingKeys. Current keys present: $currentKeys")
for (key in baselineKeys) {
checkFieldNamesMatchRecursive(baselineNode.get(key), currentNode.get(key), "$path.$key")
}
} else if (baselineNode.isArray && currentNode.isArray) {
for (i in 0 until baselineNode.size()) {
if (i < currentNode.size()) {
checkFieldNamesMatchRecursive(baselineNode.get(i), currentNode.get(i), "$path[$i]")
}
}
}
}
@Test
fun testMai2UserPlaylogAllFieldNamesMatchBaseline() {
fun testObjectMapperWithoutKotlinModule() {
val mai2Playlog = Mai2UserPlaylog().apply {
musicId = 11479
level = 2
@@ -56,15 +71,34 @@ class ReproduceIssueTest {
isNewFree = true
}
val currentTree = JACKSON.readTree(JACKSON.writeValueAsString(mai2Playlog))
val baselineTree = JACKSON.readTree(loadResourceJson("/json/mai2_playlog_jackson.json"))
val mai2Map = Mai2UserMap().apply {
mapId = 1
distance = 100
isLock = false
isClear = true
isComplete = true
}
checkFieldNamesMatch(baselineTree, currentTree, "Mai2UserPlaylog")
assertEquals(baselineTree.fieldNames().asSequence().toSet(), currentTree.fieldNames().asSequence().toSet())
val mai2Export = Maimai2DataExport().apply {
userData = Mai2UserDetail().apply { userName = "TestUser" }
userPlaylogList = listOf(mai2Playlog)
userMapList = listOf(mai2Map)
}
// Standard Jackson 2 ObjectMapper() without KotlinModule strips 'is' getters:
val plainObjectMapper = ObjectMapper()
val plainJson = plainObjectMapper.writeValueAsString(mai2Export)
val plainTree = plainObjectMapper.readTree(plainJson)
val plainPlaylogNode = plainTree.at("/userPlaylogList/0")
assertTrue(plainPlaylogNode.has("clear"), "Plain ObjectMapper has 'clear' instead of 'isClear'")
assertTrue(plainPlaylogNode.has("fullCombo"), "Plain ObjectMapper has 'fullCombo' instead of 'isFullCombo'")
assertTrue(plainPlaylogNode.has("allPerfect"), "Plain ObjectMapper has 'allPerfect' instead of 'isAllPerfect'")
assertFalse(plainPlaylogNode.has("isClear"), "Plain ObjectMapper is missing 'isClear'")
}
@Test
fun testMai2ExportEntityFieldNamesMatchBaseline() {
fun testMai2ExportEntityFieldNamesMatchBaselineRecursively() {
val mai2Playlog = Mai2UserPlaylog().apply {
musicId = 11479
level = 2
@@ -103,16 +137,11 @@ class ReproduceIssueTest {
val currentTree = JACKSON.readTree(JACKSON.writeValueAsString(mai2Export))
val baselineTree = JACKSON.readTree(loadResourceJson("/json/mai2_export_web.json"))
checkFieldNamesMatch(baselineTree.at("/userData"), currentTree.at("/userData"), "/userData")
checkFieldNamesMatch(baselineTree.at("/userExtend"), currentTree.at("/userExtend"), "/userExtend")
checkFieldNamesMatch(baselineTree.at("/userOption"), currentTree.at("/userOption"), "/userOption")
checkFieldNamesMatch(baselineTree.at("/userUdemae"), currentTree.at("/userUdemae"), "/userUdemae")
checkFieldNamesMatch(baselineTree.at("/userMapList/0"), currentTree.at("/userMapList/0"), "/userMapList/0")
checkFieldNamesMatch(baselineTree.at("/userPlaylogList/0"), currentTree.at("/userPlaylogList/0"), "/userPlaylogList/0")
checkFieldNamesMatchRecursive(baselineTree, currentTree)
}
@Test
fun testChu3ExportEntityFieldNamesMatchBaseline() {
fun testChu3ExportEntityFieldNamesMatchBaselineRecursively() {
val chu3Playlog = Chu3UserPlaylog().apply {
musicId = 100
level = 1
@@ -130,13 +159,11 @@ class ReproduceIssueTest {
val currentTree = JACKSON.readTree(JACKSON.writeValueAsString(chu3Export))
val baselineTree = JACKSON.readTree(loadResourceJson("/json/chu3_export_web.json"))
checkFieldNamesMatch(baselineTree.at("/userData"), currentTree.at("/userData"), "/userData")
checkFieldNamesMatch(baselineTree.at("/userGameOption"), currentTree.at("/userGameOption"), "/userGameOption")
checkFieldNamesMatch(baselineTree.at("/userPlaylogList/0"), currentTree.at("/userPlaylogList/0"), "/userPlaylogList/0")
checkFieldNamesMatchRecursive(baselineTree, currentTree)
}
@Test
fun testOngekiExportEntityFieldNamesMatchBaseline() {
fun testOngekiExportEntityFieldNamesMatchBaselineRecursively() {
val ongekiPlaylog = OngekiUserPlaylog().apply {
musicId = 200
level = 1
@@ -154,13 +181,11 @@ class ReproduceIssueTest {
val currentTree = JACKSON.readTree(JACKSON.writeValueAsString(ongekiExport))
val baselineTree = JACKSON.readTree(loadResourceJson("/json/ongeki_export_web.json"))
checkFieldNamesMatch(baselineTree.at("/userData"), currentTree.at("/userData"), "/userData")
checkFieldNamesMatch(baselineTree.at("/userOption"), currentTree.at("/userOption"), "/userOption")
checkFieldNamesMatch(baselineTree.at("/userPlaylogList/0"), currentTree.at("/userPlaylogList/0"), "/userPlaylogList/0")
checkFieldNamesMatchRecursive(baselineTree, currentTree)
}
@Test
fun testGameFacingMaimai2PlaylogFieldNamesMatchBaseline() {
fun testGameFacingMaimai2PlaylogFieldNamesMatchBaselineRecursively() {
val mai2Playlog = Mai2UserPlaylog().apply {
musicId = 11479
level = 2
@@ -184,10 +209,38 @@ class ReproduceIssueTest {
val currentBasicTree = BASIC_MAPPER.readTree(BASIC_MAPPER.writeValueAsString(mai2Playlog))
val baselineBasicTree = BASIC_MAPPER.readTree(loadResourceJson("/json/mai2_playlog_basic.json"))
checkFieldNamesMatch(baselineBasicTree, currentBasicTree, "Mai2UserPlaylog (BASIC_MAPPER)")
checkFieldNamesMatchRecursive(baselineBasicTree, currentBasicTree, "Mai2UserPlaylog (BASIC_MAPPER)")
val currentStringTree = STRING_MAPPER.readTree(STRING_MAPPER.writeValueAsString(mai2Playlog))
val baselineStringTree = STRING_MAPPER.readTree(loadResourceJson("/json/mai2_playlog_string.json"))
checkFieldNamesMatch(baselineStringTree, currentStringTree, "Mai2UserPlaylog (STRING_MAPPER)")
checkFieldNamesMatchRecursive(baselineStringTree, currentStringTree, "Mai2UserPlaylog (STRING_MAPPER)")
}
@Test
fun testJackson3JsonMapperWithKotlinModule() {
val mai2Playlog = Mai2UserPlaylog().apply {
musicId = 11479
level = 2
achievement = 1000000
deluxscore = 2000
isClear = true
}
val mai2Export = Maimai2DataExport().apply {
userData = Mai2UserDetail().apply { userName = "TestUser" }
userPlaylogList = listOf(mai2Playlog)
}
val j3Mapper = JsonMapper.builder()
.addModule(KotlinModule.Builder().build())
.build()
val j3Json = j3Mapper.writeValueAsString(mai2Export)
val j3Tree = j3Mapper.readTree(j3Json)
val j3PlaylogNode = j3Tree.at("/userPlaylogList/0")
assertTrue(j3PlaylogNode.has("isClear"), "Jackson 3 JsonMapper with KotlinModule must have 'isClear'")
assertTrue(j3PlaylogNode.has("isFullCombo"), "Jackson 3 JsonMapper with KotlinModule must have 'isFullCombo'")
assertTrue(j3PlaylogNode.has("isAllPerfect"), "Jackson 3 JsonMapper with KotlinModule must have 'isAllPerfect'")
}
}