test: add serialization round-trip test (Closes #37)
This commit was merged in pull request #43.
This commit is contained in:
@@ -0,0 +1,172 @@
|
||||
package org.shahondin1624
|
||||
|
||||
import org.shahondin1624.lib.functions.DataLoader
|
||||
import org.shahondin1624.model.attributes.Attribute
|
||||
import org.shahondin1624.model.attributes.AttributeType
|
||||
import org.shahondin1624.model.attributes.Attributes
|
||||
import org.shahondin1624.model.characterdata.CharacterData
|
||||
import org.shahondin1624.model.characterdata.Metatype
|
||||
import org.shahondin1624.model.charactermodel.DamageMonitor
|
||||
import org.shahondin1624.model.charactermodel.ShadowrunCharacter
|
||||
import org.shahondin1624.model.talents.Talent
|
||||
import org.shahondin1624.model.talents.Talents
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class SerializationRoundTripTest {
|
||||
|
||||
/**
|
||||
* Build a character with non-default values in every field,
|
||||
* serialize to JSON, deserialize back, and assert deep equality.
|
||||
*
|
||||
* Note: DamageMonitor.attributes and DamageMonitor.cache are @Transient
|
||||
* and are not serialized. After deserialization, ShadowrunCharacter.init
|
||||
* re-sets the attributes on the DamageMonitor. We therefore keep damage
|
||||
* current values within the range valid for EMPTY_ATTRIBUTES (max 7 for
|
||||
* stun/physical, 0 for overflow) so the DamageMonitor init won't throw.
|
||||
*/
|
||||
@Test
|
||||
fun serializeDeserializePreservesAllFields() {
|
||||
val attributes = Attributes(
|
||||
body = Attribute(AttributeType.Body, 5),
|
||||
agility = Attribute(AttributeType.Agility, 6),
|
||||
reaction = Attribute(AttributeType.Reaction, 4),
|
||||
strength = Attribute(AttributeType.Strength, 7),
|
||||
willpower = Attribute(AttributeType.Willpower, 3),
|
||||
logic = Attribute(AttributeType.Logic, 5),
|
||||
intuition = Attribute(AttributeType.Intuition, 4),
|
||||
charisma = Attribute(AttributeType.Charisma, 6),
|
||||
edge = 3
|
||||
)
|
||||
|
||||
val characterData = CharacterData(
|
||||
concept = "Street Samurai",
|
||||
nuyen = 25000,
|
||||
essence = 3.5f,
|
||||
name = "Jane 'Razor' Smith",
|
||||
metatype = Metatype.Elf,
|
||||
age = 34,
|
||||
gender = "female",
|
||||
streetCred = 5,
|
||||
notoriety = 2,
|
||||
publicAwareness = 1,
|
||||
totalKarma = 100,
|
||||
currentKarma = 42
|
||||
)
|
||||
|
||||
val talents = Talents(
|
||||
talents = listOf(
|
||||
Talent(name = "Firearms", attribute = AttributeType.Agility, value = 6, custom = false),
|
||||
Talent(name = "Blades", attribute = AttributeType.Agility, value = 5, custom = false),
|
||||
Talent(name = "Custom Hack", attribute = AttributeType.Logic, value = 3, custom = true)
|
||||
)
|
||||
)
|
||||
|
||||
// Keep damage within EMPTY_ATTRIBUTES bounds: stun/physical max = 7, overflow max = 0
|
||||
val damageMonitor = DamageMonitor(
|
||||
attributes = attributes,
|
||||
stunCurrent = 3,
|
||||
physicalCurrent = 2,
|
||||
overflowCurrent = 0
|
||||
)
|
||||
|
||||
val original = ShadowrunCharacter(
|
||||
characterData = characterData,
|
||||
attributes = attributes,
|
||||
talents = talents,
|
||||
damageMonitor = damageMonitor
|
||||
)
|
||||
|
||||
// Round-trip
|
||||
val json = DataLoader.serialize(original)
|
||||
val restored = DataLoader.deserialize(json)
|
||||
|
||||
// CharacterData assertions
|
||||
assertEquals(original.characterData.concept, restored.characterData.concept)
|
||||
assertEquals(original.characterData.nuyen, restored.characterData.nuyen)
|
||||
assertEquals(original.characterData.essence, restored.characterData.essence)
|
||||
assertEquals(original.characterData.name, restored.characterData.name)
|
||||
assertEquals(original.characterData.metatype, restored.characterData.metatype)
|
||||
assertEquals(original.characterData.age, restored.characterData.age)
|
||||
assertEquals(original.characterData.gender, restored.characterData.gender)
|
||||
assertEquals(original.characterData.streetCred, restored.characterData.streetCred)
|
||||
assertEquals(original.characterData.notoriety, restored.characterData.notoriety)
|
||||
assertEquals(original.characterData.publicAwareness, restored.characterData.publicAwareness)
|
||||
assertEquals(original.characterData.totalKarma, restored.characterData.totalKarma)
|
||||
assertEquals(original.characterData.currentKarma, restored.characterData.currentKarma)
|
||||
assertEquals(original.characterData.version, restored.characterData.version)
|
||||
|
||||
// Attributes assertions
|
||||
assertEquals(original.attributes.body(), restored.attributes.body())
|
||||
assertEquals(original.attributes.agility(), restored.attributes.agility())
|
||||
assertEquals(original.attributes.reaction(), restored.attributes.reaction())
|
||||
assertEquals(original.attributes.strength(), restored.attributes.strength())
|
||||
assertEquals(original.attributes.willpower(), restored.attributes.willpower())
|
||||
assertEquals(original.attributes.logic(), restored.attributes.logic())
|
||||
assertEquals(original.attributes.intuition(), restored.attributes.intuition())
|
||||
assertEquals(original.attributes.charisma(), restored.attributes.charisma())
|
||||
assertEquals(original.attributes.edge, restored.attributes.edge)
|
||||
assertEquals(original.attributes.version, restored.attributes.version)
|
||||
|
||||
// Talents assertions
|
||||
assertEquals(original.talents.talents.size, restored.talents.talents.size)
|
||||
original.talents.talents.forEachIndexed { i, orig ->
|
||||
val rest = restored.talents.talents[i]
|
||||
assertEquals(orig.name, rest.name, "Talent[$i].name")
|
||||
assertEquals(orig.attribute, rest.attribute, "Talent[$i].attribute")
|
||||
assertEquals(orig.value, rest.value, "Talent[$i].value")
|
||||
assertEquals(orig.custom, rest.custom, "Talent[$i].custom")
|
||||
}
|
||||
assertEquals(original.talents.version, restored.talents.version)
|
||||
|
||||
// DamageMonitor assertions (check serialized fields only; @Transient fields are re-set)
|
||||
assertEquals(original.damageMonitor.stunCurrent(), restored.damageMonitor.stunCurrent())
|
||||
assertEquals(original.damageMonitor.physicalCurrent(), restored.damageMonitor.physicalCurrent())
|
||||
assertEquals(original.damageMonitor.overflowCurrent(), restored.damageMonitor.overflowCurrent())
|
||||
|
||||
// Version
|
||||
assertEquals(original.version, restored.version)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun roundTripWithExampleCharacter() {
|
||||
// EXAMPLE_CHARACTER uses createDamageMonitor which sets damage to max values
|
||||
// that may exceed the EMPTY_ATTRIBUTES limit during deserialization.
|
||||
// Create a copy with safe damage values for the round-trip test.
|
||||
val original = org.shahondin1624.model.EXAMPLE_CHARACTER.copy(
|
||||
damageMonitor = DamageMonitor(
|
||||
attributes = org.shahondin1624.model.EXAMPLE_CHARACTER.attributes,
|
||||
stunCurrent = 0,
|
||||
physicalCurrent = 0,
|
||||
overflowCurrent = 0
|
||||
)
|
||||
)
|
||||
val json = DataLoader.serialize(original)
|
||||
val restored = DataLoader.deserialize(json)
|
||||
|
||||
assertEquals(original.characterData, restored.characterData)
|
||||
assertEquals(original.attributes.edge, restored.attributes.edge)
|
||||
assertEquals(original.talents.talents.size, restored.talents.talents.size)
|
||||
assertEquals(original.version, restored.version)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun serializedJsonContainsAllFields() {
|
||||
val original = org.shahondin1624.model.EXAMPLE_CHARACTER
|
||||
val json = DataLoader.serialize(original)
|
||||
|
||||
// Verify key fields are present in JSON output
|
||||
val checks = listOf(
|
||||
"characterData", "attributes", "talents", "damageMonitor",
|
||||
"name", "metatype", "nuyen", "essence", "edge",
|
||||
"body", "agility", "reaction", "strength",
|
||||
"willpower", "logic", "intuition", "charisma",
|
||||
"stunCurrent", "physicalCurrent", "overflowCurrent",
|
||||
"version"
|
||||
)
|
||||
for (field in checks) {
|
||||
assertTrue(json.contains("\"$field\""), "JSON should contain \"$field\"")
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user