From 128ae0f2028153c278f2e580be054cdc3be17b69 Mon Sep 17 00:00:00 2001 From: grimsi <9295182+grimsi@users.noreply.github.com> Date: Thu, 5 Feb 2026 12:32:38 +0100 Subject: [PATCH] Add tests for (De-)serializers Exclude H2 package from Sonar coverage reporting --- app/build.gradle.kts | 2 +- app/src/main/bundles/prod.bundle | Bin 1970352 -> 1970352 bytes .../serialization/ArrayDeserializerTest.kt | 106 ++++++++++ .../DisplayableSerializerTest.kt | 157 ++++++++++++++ .../GameFeatureDeserializerTest.kt | 196 ++++++++++++++++++ .../serialization/GenreDeserializerTest.kt | 178 ++++++++++++++++ .../PlayerPerspectiveDeserializerTest.kt | 151 ++++++++++++++ .../serialization/ThemeDeserializerTest.kt | 151 ++++++++++++++ 8 files changed, 940 insertions(+), 1 deletion(-) create mode 100644 app/src/test/kotlin/org/gameyfin/app/core/serialization/ArrayDeserializerTest.kt create mode 100644 app/src/test/kotlin/org/gameyfin/app/core/serialization/DisplayableSerializerTest.kt create mode 100644 app/src/test/kotlin/org/gameyfin/app/core/serialization/GameFeatureDeserializerTest.kt create mode 100644 app/src/test/kotlin/org/gameyfin/app/core/serialization/GenreDeserializerTest.kt create mode 100644 app/src/test/kotlin/org/gameyfin/app/core/serialization/PlayerPerspectiveDeserializerTest.kt create mode 100644 app/src/test/kotlin/org/gameyfin/app/core/serialization/ThemeDeserializerTest.kt 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 cd5894ad3995e828fd5a53a316f5b7506cec5c1b..fa09a709fc1d4eaa4f3bccff1ced188370c7ec36 100644 GIT binary patch delta 1441 zcmYLIU2IfU5a#aQIrnz&-QU*!*q+lDaw$z|LoB3%D0L%fCDE1wfrTmhymoW-WUP}h@ClAWi`os1R6e*Q> z*UtEqdE`U;g)DvKEI44($4Un8P@)>~pi5U^P9TFBNUGBBNj2;e?m10=$69~=E?*0;H$BJ zAg@mi*IJ@}n}S*@`(_626z99(F{az#KucuY5tXWgv6XZvq@_@+O;4ud-%)&ZDSLPt z<7R&xy;QxSSk@s5=MNOFJWT?0P{AOGYSngy4bq&tM7cTET!S&P1&SqBOO}jq=y&y(beQ;-5T$_g+BDX$wZEq zs?M9q-sRK-FaM~H(JNRO3*_rr*E@FHNg+xRWr!yb<%kMIC87%PB%&HoqmDcL@>x>s zIL{};#X;l_1{Lbi*L-|o0M#|d&u9;iB#;}TBBfd;_+6s(Q^2!fbPzGwb(NnWC3>_9 z=dN!cPnYci5m!AAcpY7#!XHcOH`V+f-=Z(=(^>u$C10N9X|hh9uOW+kjqJ|z3Uaaq z@?xH^BL88YuO-_u$2aQaIlh_fy@Fjc&)dmAG0*pq{db;kLwjAJ ziS1-ZEumEsA+d@4y&=&__S=xyLbg1t%Vkek=&rf2;cIPE*J~U8x-E86eglYC$o7NL zxecbiks1GJ!T!t)zrr#6Cyw!dcZ}|{uIVFPGv}0R_zfi{|H~5N&lGG&M08N!GZCX> zd1l{EPjnMM>Y2S$zR}(9oBHp4Gk;~&?EhxL=AvQ;)h&*h{Qj89yA?Big1DLEy|~f& QF>d&}gwVINFCo@F29*V~PXGV_ delta 1441 zcmYLIU2IfU5a#aQIrnz&-M_Z>$Mzgv;8L2>hS-t{qSTFlg#=s5Qu&iKF(lw3C1|T_ zgCM#KktVtA@1_+SEU2%OevOZeFb)Pw+ui6M|i)EHxoq`^|VtuyEBmWMBM=bM>t zX3jZxWVnB1xZi(yW7sZV;=1mV<>}A-meBI_`>DZ{HJAzwro!h_c3)d4NULw#?6oWL zL(c58TZm}dZ?6myu{~oyMfTJ~UM>F=5S0@dyOvUJXY5ssLQ~h0f&9sX3iZNadl-t8 zO1xude9AoXf&E;TK5`Zuu<2tBgSRPBje5|nD=;UJ!7L=zvq@N|b&piS1m?(Rs^AJ) z-RI6U_GznzPj%IgR%xJS1dNk6Gz)=@PqK3L*D~nP@*C>mZ(2jGUIkk{62Ykhb*2^e zy5wQJQI18JuR7Y`{-bT)D-oa$z6c+EPQ`OmFskLw{tlxSF+G1k4GHL$BN67x1NGpm z@qZw%PYu^vq3%w@QYyPJ3%?ZSJMS^3+u%SeWZV%|s*|xbbSR{yP^(=}rsEeWzOIZt z_!8r0e;mC`y{=f+AqwXY6s|l&0(4Np5QrMpeuWLuoVrB0Io4e4FLASS)&D&^lqtsL zq$4U+-ILDOlZ#Yi1gYdhXSZIvcitJ)L*rTjDS*VYNvdXWcO9e}yu1dvCoVjB?M-(8 z8THaz?me36SX0(TlprDq58)%Ch!`S{NT{Z4QnZr}t#i`D3;ghEGOb(Voww45zBif3 z@iNtQJ=wRKdf??B)iHVni(`R&HS2oEjyt7@GDJDzF+>HT5>bVyMm&zFLDZ__4!`sj zDR!RaQ{mzuawmgIb?6+QSR6ogkMq;o!y^ggrl=@Yt&{v7QTi$1*)TeYnC!mFPmmHl zT7`4hH;|{x_JD}1-ut|cu2A8RCH0$X{*Q07@c)#b%<(74UYg@6Dsu9CJz3;yWlx@0 zl9Mfv-{kpP@*m{+2C}X5e2Y$==V`LP7VP>3-a-C}1^yb@e;4?6v?sTSSIC?ZI%-*> zo1!}`v4iZGCA3N+B({>jHzc~qeistk$X0}Px$F%K-8C0B{8HQ0_1T91!4|tIzX8N% zvIAgrZi1XCX*fIWZj?sPEHGQOO=A3p7zp2FJe^Fxm*@Eqih)(Kz zI%0Gz&+Oafi5}v|JhOMHZ*=$jrv9>T=C6vH{og3qTvY6&x@9qwKM*r{H)5tw5I1wY U8#g+);)btF2z^WY65{#)0h_G0CjbBd 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}") + } + } +}