diff options
| author | Sho Sakuma <me@m1sk9.dev> | 2026-02-26 00:17:21 +0900 |
|---|---|---|
| committer | Sho Sakuma <me@m1sk9.dev> | 2026-02-26 00:17:21 +0900 |
| commit | 70c785eee4c61601ba7fffa17cc8b992b4793491 (patch) | |
| tree | 2bb41b90c19cfd3cfbe638f9f8fbd420ab96aa86 /engine | |
| parent | 365d9ede9d0abaae2bad03231b6bc5243013fc92 (diff) | |
| download | LunaticChat-70c785eee4c61601ba7fffa17cc8b992b4793491.tar.gz LunaticChat-70c785eee4c61601ba7fffa17cc8b992b4793491.tar.bz2 LunaticChat-70c785eee4c61601ba7fffa17cc8b992b4793491.zip | |
test: expand test coverage across all modules
- Add 23 new test files covering exceptions, data classes, permissions,
setting handlers, commands, and cross-server relay
- Change command execute methods from private to internal visibility
to enable unit testing (16 command files)
- Engine coverage: 65.5% → 92.4%
- Platform-paper coverage: 16.8% → 40.0%
- Platform-velocity coverage: 62.4% → 76.8%
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Diffstat (limited to 'engine')
4 files changed, 728 insertions, 0 deletions
diff --git a/engine/src/test/kotlin/dev/m1sk9/lunaticChat/engine/chat/channel/ChannelDataClassesTest.kt b/engine/src/test/kotlin/dev/m1sk9/lunaticChat/engine/chat/channel/ChannelDataClassesTest.kt new file mode 100644 index 0000000..4684432 --- /dev/null +++ b/engine/src/test/kotlin/dev/m1sk9/lunaticChat/engine/chat/channel/ChannelDataClassesTest.kt @@ -0,0 +1,200 @@ +package dev.m1sk9.lunaticChat.engine.chat.channel + +import kotlinx.serialization.json.Json +import java.util.UUID +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertNotEquals +import kotlin.test.assertTrue + +class ChannelDataClassesTest { + private val json = Json { ignoreUnknownKeys = true } + private val testOwnerId = UUID.fromString("00000001-0000-0000-0000-000000000000") + private val testPlayerId = UUID.fromString("00000002-0000-0000-0000-000000000000") + + // --- ChannelRole --- + + @Test + fun `ChannelRole should have 3 entries`() { + assertEquals(3, ChannelRole.entries.size) + } + + @Test + fun `ChannelRole entries should be OWNER, MODERATOR, MEMBER`() { + val expected = setOf("OWNER", "MODERATOR", "MEMBER") + val actual = ChannelRole.entries.map { it.name }.toSet() + assertEquals(expected, actual) + } + + @Test + fun `ChannelRole serialization round-trip should preserve value`() { + ChannelRole.entries.forEach { role -> + val serialized = json.encodeToString(ChannelRole.serializer(), role) + val deserialized = json.decodeFromString(ChannelRole.serializer(), serialized) + assertEquals(role, deserialized) + } + } + + // --- ChannelMember --- + + @Test + fun `ChannelMember should have default joinedAt`() { + val before = System.currentTimeMillis() + val member = ChannelMember(channelId = "ch-1", playerId = testPlayerId, role = ChannelRole.MEMBER) + val after = System.currentTimeMillis() + + assertTrue(member.joinedAt in before..after) + } + + @Test + fun `ChannelMember serialization round-trip should preserve all fields`() { + val original = + ChannelMember( + channelId = "ch-1", + playerId = testPlayerId, + role = ChannelRole.MODERATOR, + joinedAt = 12345L, + ) + + val serialized = json.encodeToString(ChannelMember.serializer(), original) + val deserialized = json.decodeFromString(ChannelMember.serializer(), serialized) + + assertEquals(original.channelId, deserialized.channelId) + assertEquals(original.playerId, deserialized.playerId) + assertEquals(original.role, deserialized.role) + assertEquals(original.joinedAt, deserialized.joinedAt) + } + + @Test + fun `ChannelMember copy should allow role change`() { + val original = ChannelMember(channelId = "ch-1", playerId = testPlayerId, role = ChannelRole.MEMBER) + val promoted = original.copy(role = ChannelRole.MODERATOR) + + assertEquals(ChannelRole.MODERATOR, promoted.role) + assertEquals(original.channelId, promoted.channelId) + assertEquals(original.playerId, promoted.playerId) + assertEquals(original.joinedAt, promoted.joinedAt) + } + + // --- ChannelData --- + + @Test + fun `ChannelData default values should be correct`() { + val data = ChannelData() + assertEquals(1, data.version) + assertTrue(data.channels.isEmpty()) + assertTrue(data.members.isEmpty()) + assertTrue(data.activeChannels.isEmpty()) + } + + @Test + fun `ChannelData serialization round-trip should preserve all fields`() { + val channel = Channel(id = "ch-1", name = "Test Channel", ownerId = testOwnerId, createdAt = 1000L) + val member = ChannelMember(channelId = "ch-1", playerId = testPlayerId, role = ChannelRole.MEMBER, joinedAt = 2000L) + val original = + ChannelData( + version = 1, + channels = mapOf("ch-1" to channel), + members = mapOf("ch-1" to listOf(member)), + activeChannels = mapOf("player1" to "ch-1"), + ) + + val serialized = json.encodeToString(ChannelData.serializer(), original) + val deserialized = json.decodeFromString(ChannelData.serializer(), serialized) + + assertEquals(original.version, deserialized.version) + assertEquals(original.channels.size, deserialized.channels.size) + assertEquals(original.members.size, deserialized.members.size) + assertEquals(original.activeChannels, deserialized.activeChannels) + } + + // --- ChannelContext --- + + @Test + fun `ChannelContext should store all fields`() { + val channel = Channel(id = "ch-1", name = "Test", ownerId = testOwnerId) + val member = ChannelMember(channelId = "ch-1", playerId = testPlayerId, role = ChannelRole.MEMBER) + val context = ChannelContext(channelId = "ch-1", channel = channel, members = listOf(member)) + + assertEquals("ch-1", context.channelId) + assertEquals(channel, context.channel) + assertEquals(1, context.members.size) + assertEquals(testPlayerId, context.members[0].playerId) + } + + @Test + fun `ChannelContext copy should create independent instance`() { + val channel = Channel(id = "ch-1", name = "Test", ownerId = testOwnerId) + val original = ChannelContext(channelId = "ch-1", channel = channel, members = emptyList()) + val copied = original.copy(channelId = "ch-2") + + assertEquals("ch-2", copied.channelId) + assertNotEquals(original.channelId, copied.channelId) + } + + // --- ChannelMessageLogEntry --- + + @Test + fun `ChannelMessageLogEntry create should convert UUID to string`() { + val entry = + ChannelMessageLogEntry.create( + playerId = testPlayerId, + playerName = "TestPlayer", + channelId = "ch-1", + message = "Hello world", + ) + + assertEquals(testPlayerId.toString(), entry.playerId) + assertEquals("TestPlayer", entry.playerName) + assertEquals("ch-1", entry.channelId) + assertEquals("Hello world", entry.message) + } + + @Test + fun `ChannelMessageLogEntry create should set non-empty timestamp`() { + val entry = + ChannelMessageLogEntry.create( + playerId = testPlayerId, + playerName = "TestPlayer", + channelId = "ch-1", + message = "Hello", + ) + + assertTrue(entry.timestamp.isNotEmpty()) + } + + @Test + fun `ChannelMessageLogEntry serialization round-trip should preserve all fields`() { + val original = + ChannelMessageLogEntry( + timestamp = "2024-01-01T00:00:00Z", + playerId = testPlayerId.toString(), + playerName = "TestPlayer", + channelId = "ch-1", + message = "Test message", + ) + + val serialized = json.encodeToString(ChannelMessageLogEntry.serializer(), original) + val deserialized = json.decodeFromString(ChannelMessageLogEntry.serializer(), serialized) + + assertEquals(original.timestamp, deserialized.timestamp) + assertEquals(original.playerId, deserialized.playerId) + assertEquals(original.playerName, deserialized.playerName) + assertEquals(original.channelId, deserialized.channelId) + assertEquals(original.message, deserialized.message) + } + + @Test + fun `ChannelMessageLogEntry create timestamp should be ISO-8601 format`() { + val entry = + ChannelMessageLogEntry.create( + playerId = testPlayerId, + playerName = "TestPlayer", + channelId = "ch-1", + message = "Hello", + ) + + // ISO-8601 timestamps contain 'T' separator + assertTrue(entry.timestamp.contains("T"), "Timestamp should be ISO-8601 format: ${entry.timestamp}") + } +} diff --git a/engine/src/test/kotlin/dev/m1sk9/lunaticChat/engine/exception/ChannelExceptionTest.kt b/engine/src/test/kotlin/dev/m1sk9/lunaticChat/engine/exception/ChannelExceptionTest.kt new file mode 100644 index 0000000..955c96b --- /dev/null +++ b/engine/src/test/kotlin/dev/m1sk9/lunaticChat/engine/exception/ChannelExceptionTest.kt @@ -0,0 +1,279 @@ +package dev.m1sk9.lunaticChat.engine.exception + +import dev.m1sk9.lunaticChat.engine.permission.LunaticChatPermissionNode +import java.util.UUID +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertIs +import kotlin.test.assertNull +import kotlin.test.assertTrue + +class ChannelExceptionTest { + private val testPlayerId = UUID.fromString("00000001-0000-0000-0000-000000000000") + private val testChannelId = "test-channel" + + // --- ChannelAlreadyActiveException --- + + @Test + fun `ChannelAlreadyActiveException should contain playerId and channelId in message`() { + val ex = ChannelAlreadyActiveException(testPlayerId, testChannelId) + assertTrue(ex.message!!.contains(testPlayerId.toString())) + assertTrue(ex.message!!.contains(testChannelId)) + assertEquals(testPlayerId, ex.playerId) + assertEquals(testChannelId, ex.channelId) + } + + // --- ChannelCannotInviteSelfException --- + + @Test + fun `ChannelCannotInviteSelfException should contain playerId in message`() { + val ex = ChannelCannotInviteSelfException(testPlayerId) + assertTrue(ex.message!!.contains(testPlayerId.toString())) + } + + // --- ChannelLimitExceededException --- + + @Test + fun `ChannelLimitExceededException should contain limit in message`() { + val ex = ChannelLimitExceededException(10) + assertTrue(ex.message!!.contains("10")) + assertEquals(10, ex.limit) + } + + // --- ChannelMemberAlreadyException --- + + @Test + fun `ChannelMemberAlreadyException should contain playerId and channelId in message`() { + val ex = ChannelMemberAlreadyException(testPlayerId, testChannelId) + assertTrue(ex.message!!.contains(testPlayerId.toString())) + assertTrue(ex.message!!.contains(testChannelId)) + assertEquals(testChannelId, ex.channelId) + } + + // --- ChannelMemberLimitExceededException --- + + @Test + fun `ChannelMemberLimitExceededException should contain channelId and limit in message`() { + val ex = ChannelMemberLimitExceededException(testChannelId, 50) + assertTrue(ex.message!!.contains(testChannelId)) + assertTrue(ex.message!!.contains("50")) + assertEquals(testChannelId, ex.channelId) + assertEquals(50, ex.limit) + } + + // --- ChannelMemberNotFoundException --- + + @Test + fun `ChannelMemberNotFoundException should contain channelId in message`() { + val ex = ChannelMemberNotFoundException(testChannelId) + assertTrue(ex.message!!.contains(testChannelId)) + } + + // --- ChannelNoOwnerPermissionException --- + + @Test + fun `ChannelNoOwnerPermissionException should contain ownerId in message`() { + val ex = ChannelNoOwnerPermissionException(testPlayerId) + assertTrue(ex.message!!.contains(testPlayerId.toString())) + } + + // --- ChannelNotFoundException --- + + @Test + fun `ChannelNotFoundException should contain channelId in message`() { + val ex = ChannelNotFoundException(testChannelId) + assertTrue(ex.message!!.contains(testChannelId)) + } + + // --- ChannelNotMemberException --- + + @Test + fun `ChannelNotMemberException should contain playerId and channelId in message`() { + val ex = ChannelNotMemberException(testPlayerId, testChannelId) + assertTrue(ex.message!!.contains(testPlayerId.toString())) + assertTrue(ex.message!!.contains(testChannelId)) + } + + // --- ChannelPlayerAlreadyBannedException --- + + @Test + fun `ChannelPlayerAlreadyBannedException should contain playerId and channelId in message`() { + val ex = ChannelPlayerAlreadyBannedException(testPlayerId, testChannelId) + assertTrue(ex.message!!.contains(testPlayerId.toString())) + assertTrue(ex.message!!.contains(testChannelId)) + assertEquals(testPlayerId, ex.playerId) + assertEquals(testChannelId, ex.channelId) + } + + // --- ChannelPlayerBannedException --- + + @Test + fun `ChannelPlayerBannedException should contain playerId and channelId in message`() { + val ex = ChannelPlayerBannedException(testPlayerId, testChannelId) + assertTrue(ex.message!!.contains(testPlayerId.toString())) + assertTrue(ex.message!!.contains(testChannelId)) + assertEquals(testChannelId, ex.channelId) + } + + // --- ChannelPlayerBypassBanException --- + + @Test + fun `ChannelPlayerBypassBanException should contain playerId in message and store channelId`() { + val ex = ChannelPlayerBypassBanException(testPlayerId, testChannelId) + assertTrue(ex.message!!.contains(testPlayerId.toString())) + assertEquals(testChannelId, ex.channelId) + } + + // --- ChannelPlayerBypassKickException --- + + @Test + fun `ChannelPlayerBypassKickException should contain playerId in message and store channelId`() { + val ex = ChannelPlayerBypassKickException(testPlayerId, testChannelId) + assertTrue(ex.message!!.contains(testPlayerId.toString())) + assertEquals(testChannelId, ex.channelId) + } + + // --- ChannelPlayerMembershipLimitExceededException --- + + @Test + fun `ChannelPlayerMembershipLimitExceededException should contain playerId and limit in message`() { + val ex = ChannelPlayerMembershipLimitExceededException(testPlayerId, 5) + assertTrue(ex.message!!.contains(testPlayerId.toString())) + assertTrue(ex.message!!.contains("5")) + assertEquals(testPlayerId, ex.playerId) + assertEquals(5, ex.limit) + } + + // --- ChannelPlayerNotBannedException --- + + @Test + fun `ChannelPlayerNotBannedException should contain playerId and channelId in message`() { + val ex = ChannelPlayerNotBannedException(testPlayerId, testChannelId) + assertTrue(ex.message!!.contains(testPlayerId.toString())) + assertTrue(ex.message!!.contains(testChannelId)) + assertEquals(testChannelId, ex.channelId) + } + + // --- ChannelPrivateRequiresInvitationException --- + + @Test + fun `ChannelPrivateRequiresInvitationException should contain playerId and channelId in message`() { + val ex = ChannelPrivateRequiresInvitationException(testPlayerId, testChannelId) + assertTrue(ex.message!!.contains(testPlayerId.toString())) + assertTrue(ex.message!!.contains(testChannelId)) + assertEquals(testPlayerId, ex.playerId) + assertEquals(testChannelId, ex.channelId) + } + + // --- ChannelRuntimeException --- + + @Test + fun `ChannelRuntimeException should preserve message`() { + val ex = ChannelRuntimeException("runtime error") + assertEquals("runtime error", ex.message) + assertNull(ex.cause) + } + + @Test + fun `ChannelRuntimeException should preserve cause`() { + val cause = RuntimeException("root cause") + val ex = ChannelRuntimeException("runtime error", cause) + assertEquals("runtime error", ex.message) + assertEquals(cause, ex.cause) + } + + // --- ChannelStorageLoadException --- + + @Test + fun `ChannelStorageLoadException should preserve message`() { + val ex = ChannelStorageLoadException("load error") + assertEquals("load error", ex.message) + assertNull(ex.cause) + } + + @Test + fun `ChannelStorageLoadException should preserve cause`() { + val cause = RuntimeException("io error") + val ex = ChannelStorageLoadException("load error", cause) + assertEquals("load error", ex.message) + assertEquals(cause, ex.cause) + } + + // --- ChannelStorageSaveException --- + + @Test + fun `ChannelStorageSaveException should preserve message`() { + val ex = ChannelStorageSaveException("save error") + assertEquals("save error", ex.message) + assertNull(ex.cause) + } + + @Test + fun `ChannelStorageSaveException should preserve cause`() { + val cause = RuntimeException("io error") + val ex = ChannelStorageSaveException("save error", cause) + assertEquals("save error", ex.message) + assertEquals(cause, ex.cause) + } + + // --- ChatModeStorageException --- + + @Test + fun `ChatModeStorageException should preserve message`() { + val ex = ChatModeStorageException("chatmode error") + assertEquals("chatmode error", ex.message) + assertNull(ex.cause) + } + + @Test + fun `ChatModeStorageException should preserve cause`() { + val cause = RuntimeException("io error") + val ex = ChatModeStorageException("chatmode error", cause) + assertEquals("chatmode error", ex.message) + assertEquals(cause, ex.cause) + } + + // --- RequirePermissionException --- + + @Test + fun `RequirePermissionException should join permission nodes in message`() { + val permissions = listOf(LunaticChatPermissionNode.Lc, LunaticChatPermissionNode.Tell) + val ex = RequirePermissionException(permissions) + assertTrue(ex.message!!.contains("lunaticchat.command.lc")) + assertTrue(ex.message!!.contains("lunaticchat.command.tell")) + } + + @Test + fun `RequirePermissionException with single permission should contain that node`() { + val permissions = listOf(LunaticChatPermissionNode.Spy) + val ex = RequirePermissionException(permissions) + assertTrue(ex.message!!.contains("lunaticchat.spy")) + } + + // --- All exceptions are instances of Exception --- + + @Test + fun `all exceptions should be instances of Exception`() { + assertIs<Exception>(ChannelAlreadyActiveException(testPlayerId, testChannelId)) + assertIs<Exception>(ChannelCannotInviteSelfException(testPlayerId)) + assertIs<Exception>(ChannelLimitExceededException(10)) + assertIs<Exception>(ChannelMemberAlreadyException(testPlayerId, testChannelId)) + assertIs<Exception>(ChannelMemberLimitExceededException(testChannelId, 50)) + assertIs<Exception>(ChannelMemberNotFoundException(testChannelId)) + assertIs<Exception>(ChannelNoOwnerPermissionException(testPlayerId)) + assertIs<Exception>(ChannelNotFoundException(testChannelId)) + assertIs<Exception>(ChannelNotMemberException(testPlayerId, testChannelId)) + assertIs<Exception>(ChannelPlayerAlreadyBannedException(testPlayerId, testChannelId)) + assertIs<Exception>(ChannelPlayerBannedException(testPlayerId, testChannelId)) + assertIs<Exception>(ChannelPlayerBypassBanException(testPlayerId, testChannelId)) + assertIs<Exception>(ChannelPlayerBypassKickException(testPlayerId, testChannelId)) + assertIs<Exception>(ChannelPlayerMembershipLimitExceededException(testPlayerId, 5)) + assertIs<Exception>(ChannelPlayerNotBannedException(testPlayerId, testChannelId)) + assertIs<Exception>(ChannelPrivateRequiresInvitationException(testPlayerId, testChannelId)) + assertIs<Exception>(ChannelRuntimeException("test")) + assertIs<Exception>(ChannelStorageLoadException("test")) + assertIs<Exception>(ChannelStorageSaveException("test")) + assertIs<Exception>(ChatModeStorageException("test")) + assertIs<Exception>(RequirePermissionException(listOf(LunaticChatPermissionNode.Lc))) + } +} diff --git a/engine/src/test/kotlin/dev/m1sk9/lunaticChat/engine/permission/LunaticChatPermissionNodeTest.kt b/engine/src/test/kotlin/dev/m1sk9/lunaticChat/engine/permission/LunaticChatPermissionNodeTest.kt new file mode 100644 index 0000000..c9838f2 --- /dev/null +++ b/engine/src/test/kotlin/dev/m1sk9/lunaticChat/engine/permission/LunaticChatPermissionNodeTest.kt @@ -0,0 +1,82 @@ +package dev.m1sk9.lunaticChat.engine.permission + +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertTrue + +class LunaticChatPermissionNodeTest { + private val allNodes = + listOf( + LunaticChatPermissionNode.Lc, + LunaticChatPermissionNode.Tell, + LunaticChatPermissionNode.Reply, + LunaticChatPermissionNode.Settings, + LunaticChatPermissionNode.Status, + LunaticChatPermissionNode.Channel, + LunaticChatPermissionNode.ChannelCreate, + LunaticChatPermissionNode.ChannelList, + LunaticChatPermissionNode.ChannelJoin, + LunaticChatPermissionNode.ChannelLeave, + LunaticChatPermissionNode.ChannelSwitch, + LunaticChatPermissionNode.ChannelStatus, + LunaticChatPermissionNode.ChannelInfo, + LunaticChatPermissionNode.ChannelDelete, + LunaticChatPermissionNode.ChannelInvite, + LunaticChatPermissionNode.ChannelKick, + LunaticChatPermissionNode.ChannelBan, + LunaticChatPermissionNode.ChannelUnban, + LunaticChatPermissionNode.ChannelMod, + LunaticChatPermissionNode.ChannelOwnership, + LunaticChatPermissionNode.ChatMode, + LunaticChatPermissionNode.ChatModeToggle, + LunaticChatPermissionNode.VelocityStatus, + LunaticChatPermissionNode.Spy, + LunaticChatPermissionNode.NoticeUpdate, + LunaticChatPermissionNode.ChannelBypass, + ) + + @Test + fun `all permission nodes should have lunaticchat prefix`() { + allNodes.forEach { node -> + assertTrue( + node.permissionNode.startsWith("lunaticchat."), + "Expected '${node.permissionNode}' to start with 'lunaticchat.'", + ) + } + } + + @Test + fun `should have 26 permission nodes`() { + assertEquals(26, allNodes.size) + } + + @Test + fun `spot check specific permission node values`() { + assertEquals("lunaticchat.command.lc", LunaticChatPermissionNode.Lc.permissionNode) + assertEquals("lunaticchat.command.tell", LunaticChatPermissionNode.Tell.permissionNode) + assertEquals("lunaticchat.command.reply", LunaticChatPermissionNode.Reply.permissionNode) + assertEquals("lunaticchat.command.lc.settings", LunaticChatPermissionNode.Settings.permissionNode) + assertEquals("lunaticchat.command.lc.channel.create", LunaticChatPermissionNode.ChannelCreate.permissionNode) + assertEquals("lunaticchat.command.lc.chatmode.toggle", LunaticChatPermissionNode.ChatModeToggle.permissionNode) + assertEquals("lunaticchat.command.lcv.status", LunaticChatPermissionNode.VelocityStatus.permissionNode) + assertEquals("lunaticchat.spy", LunaticChatPermissionNode.Spy.permissionNode) + assertEquals("lunaticchat.noticeupdate", LunaticChatPermissionNode.NoticeUpdate.permissionNode) + assertEquals("lunaticchat.channelbypass", LunaticChatPermissionNode.ChannelBypass.permissionNode) + } + + @Test + fun `all permission node strings should be non-empty`() { + allNodes.forEach { node -> + assertTrue( + node.permissionNode.isNotEmpty(), + "Permission node should not be empty", + ) + } + } + + @Test + fun `all permission node strings should be unique`() { + val nodeStrings = allNodes.map { it.permissionNode } + assertEquals(nodeStrings.size, nodeStrings.toSet().size, "All permission nodes should be unique") + } +} diff --git a/engine/src/test/kotlin/dev/m1sk9/lunaticChat/engine/settings/SettingsDataClassesTest.kt b/engine/src/test/kotlin/dev/m1sk9/lunaticChat/engine/settings/SettingsDataClassesTest.kt new file mode 100644 index 0000000..8743af9 --- /dev/null +++ b/engine/src/test/kotlin/dev/m1sk9/lunaticChat/engine/settings/SettingsDataClassesTest.kt @@ -0,0 +1,167 @@ +package dev.m1sk9.lunaticChat.engine.settings + +import dev.m1sk9.lunaticChat.engine.chat.ChatMode +import dev.m1sk9.lunaticChat.engine.chat.ChatModeData +import dev.m1sk9.lunaticChat.engine.converter.CacheData +import kotlinx.serialization.json.Json +import java.util.UUID +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertFalse +import kotlin.test.assertTrue + +class SettingsDataClassesTest { + private val json = Json { ignoreUnknownKeys = true } + private val testUUID = UUID.fromString("00000001-0000-0000-0000-000000000000") + private val testUUID2 = UUID.fromString("00000002-0000-0000-0000-000000000000") + + // --- PlayerChatSettings --- + + @Test + fun `PlayerChatSettings default values should all be true`() { + val settings = PlayerChatSettings(uuid = testUUID) + assertTrue(settings.japaneseConversionEnabled) + assertTrue(settings.directMessageNotificationEnabled) + assertTrue(settings.channelMessageNotificationEnabled) + } + + @Test + fun `PlayerChatSettings serialization round-trip should preserve all fields`() { + val original = + PlayerChatSettings( + uuid = testUUID, + japaneseConversionEnabled = false, + directMessageNotificationEnabled = true, + channelMessageNotificationEnabled = false, + ) + + val serialized = json.encodeToString(PlayerChatSettings.serializer(), original) + val deserialized = json.decodeFromString(PlayerChatSettings.serializer(), serialized) + + assertEquals(original.uuid, deserialized.uuid) + assertEquals(original.japaneseConversionEnabled, deserialized.japaneseConversionEnabled) + assertEquals(original.directMessageNotificationEnabled, deserialized.directMessageNotificationEnabled) + assertEquals(original.channelMessageNotificationEnabled, deserialized.channelMessageNotificationEnabled) + } + + @Test + fun `PlayerChatSettings copy should allow flag toggle`() { + val original = PlayerChatSettings(uuid = testUUID) + val modified = original.copy(japaneseConversionEnabled = false) + + assertFalse(modified.japaneseConversionEnabled) + assertTrue(modified.directMessageNotificationEnabled) + assertTrue(modified.channelMessageNotificationEnabled) + assertEquals(original.uuid, modified.uuid) + } + + @Test + fun `PlayerChatSettings copy should allow toggling all flags`() { + val original = PlayerChatSettings(uuid = testUUID) + val modified = + original.copy( + japaneseConversionEnabled = false, + directMessageNotificationEnabled = false, + channelMessageNotificationEnabled = false, + ) + + assertFalse(modified.japaneseConversionEnabled) + assertFalse(modified.directMessageNotificationEnabled) + assertFalse(modified.channelMessageNotificationEnabled) + } + + // --- PlayerSettingsData --- + + @Test + fun `PlayerSettingsData default values should be correct`() { + val data = PlayerSettingsData() + assertEquals(1, data.version) + assertTrue(data.japaneseConversion.isEmpty()) + assertTrue(data.directMessageNotification.isEmpty()) + assertTrue(data.channelMessageNotification.isEmpty()) + } + + @Test + fun `PlayerSettingsData serialization round-trip should preserve UUID keys`() { + val original = + PlayerSettingsData( + version = 1, + japaneseConversion = mapOf(testUUID to true, testUUID2 to false), + directMessageNotification = mapOf(testUUID to false), + channelMessageNotification = mapOf(testUUID2 to true), + ) + + val serialized = json.encodeToString(PlayerSettingsData.serializer(), original) + val deserialized = json.decodeFromString(PlayerSettingsData.serializer(), serialized) + + assertEquals(original.version, deserialized.version) + assertEquals(original.japaneseConversion, deserialized.japaneseConversion) + assertEquals(original.directMessageNotification, deserialized.directMessageNotification) + assertEquals(original.channelMessageNotification, deserialized.channelMessageNotification) + } + + @Test + fun `PlayerSettingsData serialized UUID keys should be string format`() { + val data = PlayerSettingsData(japaneseConversion = mapOf(testUUID to true)) + val serialized = json.encodeToString(PlayerSettingsData.serializer(), data) + assertTrue(serialized.contains(testUUID.toString())) + } + + // --- CacheData --- + + @Test + fun `CacheData should store version and entries`() { + val data = CacheData(version = "1.0", entries = mapOf("hello" to "こんにちは")) + assertEquals("1.0", data.version) + assertEquals("こんにちは", data.entries["hello"]) + } + + @Test + fun `CacheData serialization round-trip should preserve all fields`() { + val original = + CacheData( + version = "2.0", + entries = mapOf("hello" to "こんにちは", "world" to "世界"), + ) + + val serialized = json.encodeToString(CacheData.serializer(), original) + val deserialized = json.decodeFromString(CacheData.serializer(), serialized) + + assertEquals(original.version, deserialized.version) + assertEquals(original.entries, deserialized.entries) + } + + // --- ChatModeData --- + + @Test + fun `ChatModeData default should have empty modes map`() { + val data = ChatModeData() + assertTrue(data.modes.isEmpty()) + } + + @Test + fun `ChatModeData serialization round-trip should preserve UUID-keyed map`() { + val original = + ChatModeData( + modes = + mapOf( + testUUID to ChatMode.CHANNEL, + testUUID2 to ChatMode.GLOBAL, + ), + ) + + val serialized = json.encodeToString(ChatModeData.serializer(), original) + val deserialized = json.decodeFromString(ChatModeData.serializer(), serialized) + + assertEquals(original.modes.size, deserialized.modes.size) + assertEquals(ChatMode.CHANNEL, deserialized.modes[testUUID]) + assertEquals(ChatMode.GLOBAL, deserialized.modes[testUUID2]) + } + + @Test + fun `ChatModeData serialized should contain UUID strings`() { + val data = ChatModeData(modes = mapOf(testUUID to ChatMode.GLOBAL)) + val serialized = json.encodeToString(ChatModeData.serializer(), data) + assertTrue(serialized.contains(testUUID.toString())) + } +} |
