diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 6ce612d..ab31d45 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -134,7 +134,7 @@ sonar { property("sonar.projectName", "gameyfin") property("sonar.host.url", "https://sonarcloud.io") property("sonar.coverage.jacoco.xmlReportPaths", "build/reports/jacoco/test/jacocoTestReport.xml") - property("sonar.coverage.exclusions", "**/*Config.kt") + property("sonar.coverage.exclusions", "**/*Config.kt,**/org/gameyfin/db/h2/**") } } diff --git a/app/src/main/bundles/prod.bundle b/app/src/main/bundles/prod.bundle index cd5894a..fa09a70 100644 Binary files a/app/src/main/bundles/prod.bundle and b/app/src/main/bundles/prod.bundle differ diff --git a/app/src/test/kotlin/org/gameyfin/app/core/serialization/ArrayDeserializerTest.kt b/app/src/test/kotlin/org/gameyfin/app/core/serialization/ArrayDeserializerTest.kt new file mode 100644 index 0000000..a373ae5 --- /dev/null +++ b/app/src/test/kotlin/org/gameyfin/app/core/serialization/ArrayDeserializerTest.kt @@ -0,0 +1,106 @@ +package org.gameyfin.app.core.serialization + +import io.mockk.every +import io.mockk.mockk +import io.mockk.unmockkAll +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import tools.jackson.core.JsonParser +import tools.jackson.core.ObjectReadContext +import tools.jackson.databind.DeserializationContext +import tools.jackson.databind.JsonNode +import java.io.Serializable +import kotlin.test.assertEquals +import kotlin.test.assertTrue + +class ArrayDeserializerTest { + + private lateinit var deserializer: ArrayDeserializer + private lateinit var jsonParser: JsonParser + private lateinit var deserializationContext: DeserializationContext + private lateinit var objectReadContext: ObjectReadContext + + @BeforeEach + fun setup() { + deserializer = ArrayDeserializer() + jsonParser = mockk() + deserializationContext = mockk() + objectReadContext = mockk() + } + + @AfterEach + fun tearDown() { + unmockkAll() + } + + @Test + fun `deserialize should convert JSON array to String array`() { + val textNode1 = mockk() + val textNode2 = mockk() + val textNode3 = mockk() + every { textNode1.asString() } returns "item1" + every { textNode2.asString() } returns "item2" + every { textNode3.asString() } returns "item3" + + val arrayNode = mockk() + every { arrayNode.isArray } returns true + every { arrayNode.iterator() } returns mutableListOf(textNode1, textNode2, textNode3).iterator() + every { jsonParser.objectReadContext() } returns objectReadContext + every { objectReadContext.readTree(jsonParser) } returns arrayNode + + val result = deserializer.deserialize(jsonParser, deserializationContext) + + assertTrue(result is Array<*>) + assertEquals(3, result.size) + assertEquals("item1", result[0]) + assertEquals("item2", result[1]) + assertEquals("item3", result[2]) + } + + @Test + fun `deserialize should convert empty JSON array to empty String array`() { + val arrayNode = mockk() + every { arrayNode.isArray } returns true + every { arrayNode.iterator() } returns mutableListOf().iterator() + every { jsonParser.objectReadContext() } returns objectReadContext + every { objectReadContext.readTree(jsonParser) } returns arrayNode + + val result = deserializer.deserialize(jsonParser, deserializationContext) + + assertTrue(result is Array<*>) + assertEquals(0, result.size) + } + + @Test + fun `deserialize should handle non-array JSON node`() { + val textNode = mockk() + val serializable = "test string" as Serializable + every { textNode.isArray } returns false + every { jsonParser.objectReadContext() } returns objectReadContext + every { objectReadContext.readTree(jsonParser) } returns textNode + every { deserializationContext.readTreeAsValue(textNode, Serializable::class.java) } returns serializable + + val result = deserializer.deserialize(jsonParser, deserializationContext) + + assertEquals(serializable, result) + } + + @Test + fun `deserialize should handle array with single element`() { + val textNode = mockk() + every { textNode.asString() } returns "single" + + val arrayNode = mockk() + every { arrayNode.isArray } returns true + every { arrayNode.iterator() } returns mutableListOf(textNode).iterator() + every { jsonParser.objectReadContext() } returns objectReadContext + every { objectReadContext.readTree(jsonParser) } returns arrayNode + + val result = deserializer.deserialize(jsonParser, deserializationContext) + + assertTrue(result is Array<*>) + assertEquals(1, result.size) + assertEquals("single", result[0]) + } +} diff --git a/app/src/test/kotlin/org/gameyfin/app/core/serialization/DisplayableSerializerTest.kt b/app/src/test/kotlin/org/gameyfin/app/core/serialization/DisplayableSerializerTest.kt new file mode 100644 index 0000000..d63f65d --- /dev/null +++ b/app/src/test/kotlin/org/gameyfin/app/core/serialization/DisplayableSerializerTest.kt @@ -0,0 +1,157 @@ +package org.gameyfin.app.core.serialization + +import io.mockk.mockk +import io.mockk.unmockkAll +import io.mockk.verify +import org.gameyfin.pluginapi.gamemetadata.GameFeature +import org.gameyfin.pluginapi.gamemetadata.Genre +import org.gameyfin.pluginapi.gamemetadata.PlayerPerspective +import org.gameyfin.pluginapi.gamemetadata.Theme +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import tools.jackson.core.JsonGenerator +import tools.jackson.databind.SerializationContext + +class DisplayableSerializerTest { + + private lateinit var serializer: DisplayableSerializer + private lateinit var jsonGenerator: JsonGenerator + private lateinit var serializationContext: SerializationContext + + @BeforeEach + fun setup() { + serializer = DisplayableSerializer() + jsonGenerator = mockk(relaxed = true) + serializationContext = mockk() + } + + @AfterEach + fun tearDown() { + unmockkAll() + } + + @Test + fun `serialize should write displayName for valid theme`() { + val theme = Theme.SCIENCE_FICTION + + serializer.serialize(theme, jsonGenerator, serializationContext) + + verify(exactly = 1) { jsonGenerator.writeString("Science Fiction") } + } + + @Test + fun `serialize should handle null value`() { + serializer.serialize(null, jsonGenerator, serializationContext) + + verify(exactly = 0) { jsonGenerator.writeString(any()) } + } + + @Test + fun `serialize should write displayName for valid genre`() { + val genre = Genre.ROLE_PLAYING + + serializer.serialize(genre, jsonGenerator, serializationContext) + + verify(exactly = 1) { jsonGenerator.writeString("Role-Playing") } + } + + @Test + fun `serialize should write displayName for valid game feature`() { + val feature = GameFeature.MULTIPLAYER + + serializer.serialize(feature, jsonGenerator, serializationContext) + + verify(exactly = 1) { jsonGenerator.writeString("Multiplayer") } + } + + @Test + fun `serialize should write displayName for valid player perspective`() { + val perspective = PlayerPerspective.FIRST_PERSON + + serializer.serialize(perspective, jsonGenerator, serializationContext) + + verify(exactly = 1) { jsonGenerator.writeString("First-Person") } + } + + @Test + fun `serialize should handle theme with hyphens`() { + val theme = Theme.NON_FICTION + + serializer.serialize(theme, jsonGenerator, serializationContext) + + verify(exactly = 1) { jsonGenerator.writeString("Non-Fiction") } + } + + @Test + fun `serialize should handle genre with ampersand`() { + val genre = Genre.CARD_AND_BOARD_GAME + + serializer.serialize(genre, jsonGenerator, serializationContext) + + verify(exactly = 1) { jsonGenerator.writeString("Card & Board Game") } + } + + @Test + fun `serialize should handle genre with slash and apostrophe`() { + val genre = Genre.HACK_AND_SLASH_BEAT_EM_UP + + serializer.serialize(genre, jsonGenerator, serializationContext) + + verify(exactly = 1) { jsonGenerator.writeString("Hack and Slash/Beat 'em up") } + } + + @Test + fun `serialize should handle feature with hyphen`() { + val feature = GameFeature.CROSS_PLATFORM + + serializer.serialize(feature, jsonGenerator, serializationContext) + + verify(exactly = 1) { jsonGenerator.writeString("Cross-Platform") } + } + + @Test + fun `serialize should handle perspective with slash`() { + val perspective = PlayerPerspective.BIRD_VIEW_ISOMETRIC + + serializer.serialize(perspective, jsonGenerator, serializationContext) + + verify(exactly = 1) { jsonGenerator.writeString("Bird View/Isometric") } + } + + @Test + fun `serialize should handle all theme values correctly`() { + Theme.entries.forEach { theme -> + serializer.serialize(theme, jsonGenerator, serializationContext) + + verify(exactly = 1) { jsonGenerator.writeString(theme.displayName) } + } + } + + @Test + fun `serialize should handle all genre values correctly`() { + Genre.entries.forEach { genre -> + serializer.serialize(genre, jsonGenerator, serializationContext) + + verify(atLeast = 1) { jsonGenerator.writeString(genre.displayName) } + } + } + + @Test + fun `serialize should handle all game feature values correctly`() { + GameFeature.entries.forEach { feature -> + serializer.serialize(feature, jsonGenerator, serializationContext) + + verify(atLeast = 1) { jsonGenerator.writeString(feature.displayName) } + } + } + + @Test + fun `serialize should handle all player perspective values correctly`() { + PlayerPerspective.entries.forEach { perspective -> + serializer.serialize(perspective, jsonGenerator, serializationContext) + + verify(atLeast = 1) { jsonGenerator.writeString(perspective.displayName) } + } + } +} diff --git a/app/src/test/kotlin/org/gameyfin/app/core/serialization/GameFeatureDeserializerTest.kt b/app/src/test/kotlin/org/gameyfin/app/core/serialization/GameFeatureDeserializerTest.kt new file mode 100644 index 0000000..e3d5986 --- /dev/null +++ b/app/src/test/kotlin/org/gameyfin/app/core/serialization/GameFeatureDeserializerTest.kt @@ -0,0 +1,196 @@ +package org.gameyfin.app.core.serialization + +import io.mockk.every +import io.mockk.mockk +import io.mockk.unmockkAll +import org.gameyfin.pluginapi.gamemetadata.GameFeature +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import tools.jackson.core.JsonParser +import tools.jackson.databind.DeserializationContext +import kotlin.test.assertEquals +import kotlin.test.assertNull + +class GameFeatureDeserializerTest { + + private lateinit var deserializer: GameFeatureDeserializer + private lateinit var jsonParser: JsonParser + private lateinit var deserializationContext: DeserializationContext + + @BeforeEach + fun setup() { + deserializer = GameFeatureDeserializer() + jsonParser = mockk() + deserializationContext = mockk() + } + + @AfterEach + fun tearDown() { + unmockkAll() + } + + @Test + fun `deserialize should return correct feature for valid displayName`() { + every { jsonParser.string } returns "Singleplayer" + + val result = deserializer.deserialize(jsonParser, deserializationContext) + + assertEquals(GameFeature.SINGLEPLAYER, result) + } + + @Test + fun `deserialize should return null for unknown displayName`() { + every { jsonParser.string } returns "Unknown Feature" + + val result = deserializer.deserialize(jsonParser, deserializationContext) + + assertNull(result) + } + + @Test + fun `deserialize should return null for empty string`() { + every { jsonParser.string } returns "" + + val result = deserializer.deserialize(jsonParser, deserializationContext) + + assertNull(result) + } + + @Test + fun `deserialize should return null for null string`() { + every { jsonParser.string } returns null + + val result = deserializer.deserialize(jsonParser, deserializationContext) + + assertNull(result) + } + + @Test + fun `deserialize should be case-sensitive`() { + every { jsonParser.string } returns "multiplayer" + + val result = deserializer.deserialize(jsonParser, deserializationContext) + + assertNull(result) + } + + @Test + fun `deserialize should handle Multiplayer feature`() { + every { jsonParser.string } returns "Multiplayer" + + val result = deserializer.deserialize(jsonParser, deserializationContext) + + assertEquals(GameFeature.MULTIPLAYER, result) + } + + @Test + fun `deserialize should handle Co-op feature`() { + every { jsonParser.string } returns "Co-op" + + val result = deserializer.deserialize(jsonParser, deserializationContext) + + assertEquals(GameFeature.CO_OP, result) + } + + @Test + fun `deserialize should handle Cross-Platform feature`() { + every { jsonParser.string } returns "Cross-Platform" + + val result = deserializer.deserialize(jsonParser, deserializationContext) + + assertEquals(GameFeature.CROSS_PLATFORM, result) + } + + @Test + fun `deserialize should handle VR feature`() { + every { jsonParser.string } returns "VR" + + val result = deserializer.deserialize(jsonParser, deserializationContext) + + assertEquals(GameFeature.VR, result) + } + + @Test + fun `deserialize should handle AR feature`() { + every { jsonParser.string } returns "AR" + + val result = deserializer.deserialize(jsonParser, deserializationContext) + + assertEquals(GameFeature.AR, result) + } + + @Test + fun `deserialize should handle Cloud Saves feature`() { + every { jsonParser.string } returns "Cloud Saves" + + val result = deserializer.deserialize(jsonParser, deserializationContext) + + assertEquals(GameFeature.CLOUD_SAVES, result) + } + + @Test + fun `deserialize should handle Controller Support feature`() { + every { jsonParser.string } returns "Controller Support" + + val result = deserializer.deserialize(jsonParser, deserializationContext) + + assertEquals(GameFeature.CONTROLLER_SUPPORT, result) + } + + @Test + fun `deserialize should handle Local Multiplayer feature`() { + every { jsonParser.string } returns "Local Multiplayer" + + val result = deserializer.deserialize(jsonParser, deserializationContext) + + assertEquals(GameFeature.LOCAL_MULTIPLAYER, result) + } + + @Test + fun `deserialize should handle Online Co-op feature`() { + every { jsonParser.string } returns "Online Co-op" + + val result = deserializer.deserialize(jsonParser, deserializationContext) + + assertEquals(GameFeature.ONLINE_CO_OP, result) + } + + @Test + fun `deserialize should handle Online PvP feature`() { + every { jsonParser.string } returns "Online PvP" + + val result = deserializer.deserialize(jsonParser, deserializationContext) + + assertEquals(GameFeature.ONLINE_PVP, result) + } + + @Test + fun `deserialize should handle Crossplay feature`() { + every { jsonParser.string } returns "Crossplay" + + val result = deserializer.deserialize(jsonParser, deserializationContext) + + assertEquals(GameFeature.CROSSPLAY, result) + } + + @Test + fun `deserialize should handle Splitscreen feature`() { + every { jsonParser.string } returns "Splitscreen" + + val result = deserializer.deserialize(jsonParser, deserializationContext) + + assertEquals(GameFeature.SPLITSCREEN, result) + } + + @Test + fun `deserialize should handle all valid feature displayNames correctly`() { + GameFeature.entries.forEach { feature -> + every { jsonParser.string } returns feature.displayName + + val result = deserializer.deserialize(jsonParser, deserializationContext) + + assertEquals(feature, result, "Failed to deserialize ${feature.displayName}") + } + } +} diff --git a/app/src/test/kotlin/org/gameyfin/app/core/serialization/GenreDeserializerTest.kt b/app/src/test/kotlin/org/gameyfin/app/core/serialization/GenreDeserializerTest.kt new file mode 100644 index 0000000..6a0723d --- /dev/null +++ b/app/src/test/kotlin/org/gameyfin/app/core/serialization/GenreDeserializerTest.kt @@ -0,0 +1,178 @@ +package org.gameyfin.app.core.serialization + +import io.mockk.every +import io.mockk.mockk +import io.mockk.unmockkAll +import org.gameyfin.pluginapi.gamemetadata.Genre +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import tools.jackson.core.JsonParser +import tools.jackson.databind.DeserializationContext +import kotlin.test.assertEquals +import kotlin.test.assertNull + +class GenreDeserializerTest { + + private lateinit var deserializer: GenreDeserializer + private lateinit var jsonParser: JsonParser + private lateinit var deserializationContext: DeserializationContext + + @BeforeEach + fun setup() { + deserializer = GenreDeserializer() + jsonParser = mockk() + deserializationContext = mockk() + } + + @AfterEach + fun tearDown() { + unmockkAll() + } + + @Test + fun `deserialize should return correct genre for valid displayName`() { + every { jsonParser.string } returns "Action" + + val result = deserializer.deserialize(jsonParser, deserializationContext) + + assertEquals(Genre.ACTION, result) + } + + @Test + fun `deserialize should return null for unknown displayName`() { + every { jsonParser.string } returns "Unknown Genre" + + val result = deserializer.deserialize(jsonParser, deserializationContext) + + assertNull(result) + } + + @Test + fun `deserialize should return null for empty string`() { + every { jsonParser.string } returns "" + + val result = deserializer.deserialize(jsonParser, deserializationContext) + + assertNull(result) + } + + @Test + fun `deserialize should return null for null string`() { + every { jsonParser.string } returns null + + val result = deserializer.deserialize(jsonParser, deserializationContext) + + assertNull(result) + } + + @Test + fun `deserialize should be case-sensitive`() { + every { jsonParser.string } returns "action" + + val result = deserializer.deserialize(jsonParser, deserializationContext) + + assertNull(result) + } + + @Test + fun `deserialize should handle Visual Novel genre`() { + every { jsonParser.string } returns "Visual Novel" + + val result = deserializer.deserialize(jsonParser, deserializationContext) + + assertEquals(Genre.VISUAL_NOVEL, result) + } + + @Test + fun `deserialize should handle Card & Board Game genre`() { + every { jsonParser.string } returns "Card & Board Game" + + val result = deserializer.deserialize(jsonParser, deserializationContext) + + assertEquals(Genre.CARD_AND_BOARD_GAME, result) + } + + @Test + fun `deserialize should handle Point-and-Click genre`() { + every { jsonParser.string } returns "Point-and-Click" + + val result = deserializer.deserialize(jsonParser, deserializationContext) + + assertEquals(Genre.POINT_AND_CLICK, result) + } + + @Test + fun `deserialize should handle Real-Time Strategy genre`() { + every { jsonParser.string } returns "Real-Time Strategy" + + val result = deserializer.deserialize(jsonParser, deserializationContext) + + assertEquals(Genre.REAL_TIME_STRATEGY, result) + } + + @Test + fun `deserialize should handle Turn-Based Strategy genre`() { + every { jsonParser.string } returns "Turn-Based Strategy" + + val result = deserializer.deserialize(jsonParser, deserializationContext) + + assertEquals(Genre.TURN_BASED_STRATEGY, result) + } + + @Test + fun `deserialize should handle Hack and Slash Beat em up genre`() { + every { jsonParser.string } returns "Hack and Slash/Beat 'em up" + + val result = deserializer.deserialize(jsonParser, deserializationContext) + + assertEquals(Genre.HACK_AND_SLASH_BEAT_EM_UP, result) + } + + @Test + fun `deserialize should handle Quiz Trivia genre`() { + every { jsonParser.string } returns "Quiz/Trivia" + + val result = deserializer.deserialize(jsonParser, deserializationContext) + + assertEquals(Genre.QUIZ_TRIVIA, result) + } + + @Test + fun `deserialize should handle Role-Playing genre`() { + every { jsonParser.string } returns "Role-Playing" + + val result = deserializer.deserialize(jsonParser, deserializationContext) + + assertEquals(Genre.ROLE_PLAYING, result) + } + + @Test + fun `deserialize should handle MOBA genre`() { + every { jsonParser.string } returns "MOBA" + + val result = deserializer.deserialize(jsonParser, deserializationContext) + + assertEquals(Genre.MOBA, result) + } + + @Test + fun `deserialize should handle MMO genre`() { + every { jsonParser.string } returns "MMO" + + val result = deserializer.deserialize(jsonParser, deserializationContext) + + assertEquals(Genre.MMO, result) + } + + @Test + fun `deserialize should handle all valid genre displayNames correctly`() { + Genre.entries.forEach { genre -> + every { jsonParser.string } returns genre.displayName + + val result = deserializer.deserialize(jsonParser, deserializationContext) + + assertEquals(genre, result, "Failed to deserialize ${genre.displayName}") + } + } +} diff --git a/app/src/test/kotlin/org/gameyfin/app/core/serialization/PlayerPerspectiveDeserializerTest.kt b/app/src/test/kotlin/org/gameyfin/app/core/serialization/PlayerPerspectiveDeserializerTest.kt new file mode 100644 index 0000000..f706b72 --- /dev/null +++ b/app/src/test/kotlin/org/gameyfin/app/core/serialization/PlayerPerspectiveDeserializerTest.kt @@ -0,0 +1,151 @@ +package org.gameyfin.app.core.serialization + +import io.mockk.every +import io.mockk.mockk +import io.mockk.unmockkAll +import org.gameyfin.pluginapi.gamemetadata.PlayerPerspective +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import tools.jackson.core.JsonParser +import tools.jackson.databind.DeserializationContext +import kotlin.test.assertEquals +import kotlin.test.assertNull + +class PlayerPerspectiveDeserializerTest { + + private lateinit var deserializer: PlayerPerspectiveDeserializer + private lateinit var jsonParser: JsonParser + private lateinit var deserializationContext: DeserializationContext + + @BeforeEach + fun setup() { + deserializer = PlayerPerspectiveDeserializer() + jsonParser = mockk() + deserializationContext = mockk() + } + + @AfterEach + fun tearDown() { + unmockkAll() + } + + @Test + fun `deserialize should return correct perspective for valid displayName`() { + every { jsonParser.string } returns "First-Person" + + val result = deserializer.deserialize(jsonParser, deserializationContext) + + assertEquals(PlayerPerspective.FIRST_PERSON, result) + } + + @Test + fun `deserialize should return null for unknown displayName`() { + every { jsonParser.string } returns "Unknown Perspective" + + val result = deserializer.deserialize(jsonParser, deserializationContext) + + assertNull(result) + } + + @Test + fun `deserialize should return null for empty string`() { + every { jsonParser.string } returns "" + + val result = deserializer.deserialize(jsonParser, deserializationContext) + + assertNull(result) + } + + @Test + fun `deserialize should return null for null string`() { + every { jsonParser.string } returns null + + val result = deserializer.deserialize(jsonParser, deserializationContext) + + assertNull(result) + } + + @Test + fun `deserialize should be case-sensitive`() { + every { jsonParser.string } returns "first-person" + + val result = deserializer.deserialize(jsonParser, deserializationContext) + + assertNull(result) + } + + @Test + fun `deserialize should handle Third-Person perspective`() { + every { jsonParser.string } returns "Third-Person" + + val result = deserializer.deserialize(jsonParser, deserializationContext) + + assertEquals(PlayerPerspective.THIRD_PERSON, result) + } + + @Test + fun `deserialize should handle Bird View Isometric perspective`() { + every { jsonParser.string } returns "Bird View/Isometric" + + val result = deserializer.deserialize(jsonParser, deserializationContext) + + assertEquals(PlayerPerspective.BIRD_VIEW_ISOMETRIC, result) + } + + @Test + fun `deserialize should handle Side View perspective`() { + every { jsonParser.string } returns "Side View" + + val result = deserializer.deserialize(jsonParser, deserializationContext) + + assertEquals(PlayerPerspective.SIDE_VIEW, result) + } + + @Test + fun `deserialize should handle Text perspective`() { + every { jsonParser.string } returns "Text" + + val result = deserializer.deserialize(jsonParser, deserializationContext) + + assertEquals(PlayerPerspective.TEXT, result) + } + + @Test + fun `deserialize should handle Auditory perspective`() { + every { jsonParser.string } returns "Auditory" + + val result = deserializer.deserialize(jsonParser, deserializationContext) + + assertEquals(PlayerPerspective.AUDITORY, result) + } + + @Test + fun `deserialize should handle Virtual Reality perspective`() { + every { jsonParser.string } returns "Virtual Reality" + + val result = deserializer.deserialize(jsonParser, deserializationContext) + + assertEquals(PlayerPerspective.VIRTUAL_REALITY, result) + } + + @Test + fun `deserialize should handle Unknown perspective`() { + every { jsonParser.string } returns "Unknown" + + val result = deserializer.deserialize(jsonParser, deserializationContext) + + assertEquals(PlayerPerspective.UNKNOWN, result) + } + + @Test + fun `deserialize should handle all valid perspective displayNames correctly`() { + PlayerPerspective.entries.forEach { perspective -> + every { jsonParser.string } returns perspective.displayName + + val result = deserializer.deserialize(jsonParser, deserializationContext) + + assertEquals(perspective, result, "Failed to deserialize ${perspective.displayName}") + } + } +} diff --git a/app/src/test/kotlin/org/gameyfin/app/core/serialization/ThemeDeserializerTest.kt b/app/src/test/kotlin/org/gameyfin/app/core/serialization/ThemeDeserializerTest.kt new file mode 100644 index 0000000..99ba63c --- /dev/null +++ b/app/src/test/kotlin/org/gameyfin/app/core/serialization/ThemeDeserializerTest.kt @@ -0,0 +1,151 @@ +package org.gameyfin.app.core.serialization + +import io.mockk.every +import io.mockk.mockk +import io.mockk.unmockkAll +import org.gameyfin.pluginapi.gamemetadata.Theme +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import tools.jackson.core.JsonParser +import tools.jackson.databind.DeserializationContext +import kotlin.test.assertEquals +import kotlin.test.assertNull + +class ThemeDeserializerTest { + + private lateinit var deserializer: ThemeDeserializer + private lateinit var jsonParser: JsonParser + private lateinit var deserializationContext: DeserializationContext + + @BeforeEach + fun setup() { + deserializer = ThemeDeserializer() + jsonParser = mockk() + deserializationContext = mockk() + } + + @AfterEach + fun tearDown() { + unmockkAll() + } + + @Test + fun `deserialize should return correct theme for valid displayName`() { + every { jsonParser.string } returns "Action" + + val result = deserializer.deserialize(jsonParser, deserializationContext) + + assertEquals(Theme.ACTION, result) + } + + @Test + fun `deserialize should return null for unknown displayName`() { + every { jsonParser.string } returns "Unknown Theme" + + val result = deserializer.deserialize(jsonParser, deserializationContext) + + assertNull(result) + } + + @Test + fun `deserialize should return null for empty string`() { + every { jsonParser.string } returns "" + + val result = deserializer.deserialize(jsonParser, deserializationContext) + + assertNull(result) + } + + @Test + fun `deserialize should return null for null string`() { + every { jsonParser.string } returns null + + val result = deserializer.deserialize(jsonParser, deserializationContext) + + assertNull(result) + } + + @Test + fun `deserialize should be case-sensitive`() { + every { jsonParser.string } returns "action" + + val result = deserializer.deserialize(jsonParser, deserializationContext) + + assertNull(result) + } + + @Test + fun `deserialize should handle Science Fiction theme`() { + every { jsonParser.string } returns "Science Fiction" + + val result = deserializer.deserialize(jsonParser, deserializationContext) + + assertEquals(Theme.SCIENCE_FICTION, result) + } + + @Test + fun `deserialize should handle Non-Fiction theme`() { + every { jsonParser.string } returns "Non-Fiction" + + val result = deserializer.deserialize(jsonParser, deserializationContext) + + assertEquals(Theme.NON_FICTION, result) + } + + @Test + fun `deserialize should handle 4X theme`() { + every { jsonParser.string } returns "4X" + + val result = deserializer.deserialize(jsonParser, deserializationContext) + + assertEquals(Theme.FOUR_X, result) + } + + @Test + fun `deserialize should handle Open World theme`() { + every { jsonParser.string } returns "Open World" + + val result = deserializer.deserialize(jsonParser, deserializationContext) + + assertEquals(Theme.OPEN_WORLD, result) + } + + @Test + fun `deserialize should handle Horror theme`() { + every { jsonParser.string } returns "Horror" + + val result = deserializer.deserialize(jsonParser, deserializationContext) + + assertEquals(Theme.HORROR, result) + } + + @Test + fun `deserialize should handle Fantasy theme`() { + every { jsonParser.string } returns "Fantasy" + + val result = deserializer.deserialize(jsonParser, deserializationContext) + + assertEquals(Theme.FANTASY, result) + } + + @Test + fun `deserialize should handle Survival theme`() { + every { jsonParser.string } returns "Survival" + + val result = deserializer.deserialize(jsonParser, deserializationContext) + + assertEquals(Theme.SURVIVAL, result) + } + + @Test + fun `deserialize should handle all valid theme displayNames correctly`() { + Theme.entries.forEach { theme -> + every { jsonParser.string } returns theme.displayName + + val result = deserializer.deserialize(jsonParser, deserializationContext) + + assertEquals(theme, result, "Failed to deserialize ${theme.displayName}") + } + } +}