diff --git a/composeApp/src/commonMain/kotlin/ch/parano/myice/models/Account.kt b/composeApp/src/commonMain/kotlin/ch/parano/myice/models/Account.kt new file mode 100644 index 0000000..73ad8f1 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/ch/parano/myice/models/Account.kt @@ -0,0 +1,9 @@ +package ch.parano.myice.models + +import kotlinx.serialization.Serializable + +@Serializable +data class Account( + val name: String, + val label: String, +) diff --git a/composeApp/src/commonMain/kotlin/ch/parano/myice/models/Convocation.kt b/composeApp/src/commonMain/kotlin/ch/parano/myice/models/Convocation.kt new file mode 100644 index 0000000..026707c --- /dev/null +++ b/composeApp/src/commonMain/kotlin/ch/parano/myice/models/Convocation.kt @@ -0,0 +1,9 @@ +package ch.parano.myice.models + +import kotlinx.serialization.Serializable + +@Serializable +data class Convocation( + val available: List = emptyList(), + val staff: List = emptyList(), +) diff --git a/composeApp/src/commonMain/kotlin/ch/parano/myice/models/Event.kt b/composeApp/src/commonMain/kotlin/ch/parano/myice/models/Event.kt new file mode 100644 index 0000000..c548a48 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/ch/parano/myice/models/Event.kt @@ -0,0 +1,20 @@ +package ch.parano.myice.models + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class Event( + @SerialName("id_event") + @Serializable(with = FlexibleStringSerializer::class) + val idEvent: String = "", + val agegroup: String = "", + val name: String = "", + val title: String = "", + val opponent: String = "", + val place: String = "", + val start: String = "", + val end: String = "", + val color: String? = null, + @SerialName("event") val eventType: String = "", +) diff --git a/composeApp/src/commonMain/kotlin/ch/parano/myice/models/EventDetail.kt b/composeApp/src/commonMain/kotlin/ch/parano/myice/models/EventDetail.kt new file mode 100644 index 0000000..a7be996 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/ch/parano/myice/models/EventDetail.kt @@ -0,0 +1,14 @@ +package ch.parano.myice.models + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class EventDetail( + val title: String = "", + val type: String = "", + val place: String = "", + @SerialName("time_start") val timeStart: String = "", + @SerialName("time_end") val timeEnd: String = "", + val convocation: Convocation = Convocation(), +) diff --git a/composeApp/src/commonMain/kotlin/ch/parano/myice/models/FlexibleStringSerializer.kt b/composeApp/src/commonMain/kotlin/ch/parano/myice/models/FlexibleStringSerializer.kt new file mode 100644 index 0000000..e3084b3 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/ch/parano/myice/models/FlexibleStringSerializer.kt @@ -0,0 +1,26 @@ +package ch.parano.myice.models + +import kotlinx.serialization.KSerializer +import kotlinx.serialization.SerializationException +import kotlinx.serialization.descriptors.PrimitiveKind +import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder +import kotlinx.serialization.json.JsonDecoder +import kotlinx.serialization.json.jsonPrimitive + +object FlexibleStringSerializer : KSerializer { + override val descriptor: SerialDescriptor = + PrimitiveSerialDescriptor("FlexibleString", PrimitiveKind.STRING) + + override fun serialize(encoder: Encoder, value: String) { + encoder.encodeString(value) + } + + override fun deserialize(decoder: Decoder): String { + val jsonDecoder = decoder as? JsonDecoder + ?: throw SerializationException("FlexibleStringSerializer expects JsonDecoder") + return jsonDecoder.decodeJsonElement().jsonPrimitive.content + } +} diff --git a/composeApp/src/commonMain/kotlin/ch/parano/myice/models/Player.kt b/composeApp/src/commonMain/kotlin/ch/parano/myice/models/Player.kt new file mode 100644 index 0000000..4ad53e6 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/ch/parano/myice/models/Player.kt @@ -0,0 +1,12 @@ +package ch.parano.myice.models + +import kotlinx.serialization.Serializable + +@Serializable +data class Player( + val position: String? = null, + @Serializable(with = FlexibleStringSerializer::class) val number: String? = null, + val fname: String, + val lname: String, + val dob: String, +) diff --git a/composeApp/src/commonMain/kotlin/ch/parano/myice/models/Staff.kt b/composeApp/src/commonMain/kotlin/ch/parano/myice/models/Staff.kt new file mode 100644 index 0000000..8ca1d6b --- /dev/null +++ b/composeApp/src/commonMain/kotlin/ch/parano/myice/models/Staff.kt @@ -0,0 +1,10 @@ +package ch.parano.myice.models + +import kotlinx.serialization.Serializable + +@Serializable +data class Staff( + val role: String, + val fname: String, + val lname: String, +) diff --git a/composeApp/src/commonMain/kotlin/ch/parano/myice/models/UserInfo.kt b/composeApp/src/commonMain/kotlin/ch/parano/myice/models/UserInfo.kt new file mode 100644 index 0000000..286252e --- /dev/null +++ b/composeApp/src/commonMain/kotlin/ch/parano/myice/models/UserInfo.kt @@ -0,0 +1,8 @@ +package ch.parano.myice.models + +import kotlinx.serialization.Serializable + +@Serializable +data class UserInfo( + val email: String = "", +) diff --git a/composeApp/src/commonTest/kotlin/ch/parano/myice/models/ModelSerializationTest.kt b/composeApp/src/commonTest/kotlin/ch/parano/myice/models/ModelSerializationTest.kt new file mode 100644 index 0000000..73093c1 --- /dev/null +++ b/composeApp/src/commonTest/kotlin/ch/parano/myice/models/ModelSerializationTest.kt @@ -0,0 +1,183 @@ +package ch.parano.myice.models + +import kotlinx.serialization.json.Json +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertNull + +class ModelSerializationTest { + + private val json = Json { ignoreUnknownKeys = true } + + @Test + fun testAccountDeserialization() { + val input = """{"name":"default","label":"Default"}""" + val account = json.decodeFromString(input) + assertEquals("default", account.name) + assertEquals("Default", account.label) + } + + @Test + fun testEventDeserialization() { + val input = """ + { + "id_event": 761040, + "agegroup": "U13 (Elite)", + "name": "U13 Elite - HC Ajoie", + "title": "U13 (Elite)\nGame\nRaiffeisen Arena", + "opponent": "HC Ajoie", + "place": "Raiffeisen Arena, Porrentruy", + "start": "2024-11-10T14:00:00", + "end": "2024-11-10T16:15:00", + "color": "#e4222e", + "event": "Jeu" + } + """.trimIndent() + val event = json.decodeFromString(input) + assertEquals("761040", event.idEvent) + assertEquals("U13 (Elite)", event.agegroup) + assertEquals("U13 Elite - HC Ajoie", event.name) + assertEquals("HC Ajoie", event.opponent) + assertEquals("#e4222e", event.color) + assertEquals("Jeu", event.eventType) + } + + @Test + fun testEventDeserializationWithNullFields() { + val input = """ + { + "id_event": "12345", + "agegroup": "U15", + "name": "", + "title": "Practice", + "opponent": "", + "place": "Les Vernets", + "start": "2024-11-10T14:00:00", + "end": "2024-11-10T15:30:00" + } + """.trimIndent() + val event = json.decodeFromString(input) + assertEquals("12345", event.idEvent) + assertEquals("", event.name) + assertEquals("", event.opponent) + assertNull(event.color) + assertEquals("", event.eventType) + } + + @Test + fun testPlayerWithIntNumber() { + val input = """ + {"position":"Gardien","number":1,"fname":"Jean","lname":"Dupont","dob":"2012-03-15"} + """.trimIndent() + val player = json.decodeFromString(input) + assertEquals("Gardien", player.position) + assertEquals("1", player.number) + assertEquals("Jean", player.fname) + } + + @Test + fun testPlayerWithStringNumber() { + val input = """ + {"position":"Attaquant","number":"27","fname":"Pierre","lname":"Martin","dob":"2012-05-20"} + """.trimIndent() + val player = json.decodeFromString(input) + assertEquals("27", player.number) + } + + @Test + fun testPlayerWithNullNumber() { + val input = """ + {"position":null,"number":null,"fname":"Paul","lname":"Durand","dob":"2012-01-10"} + """.trimIndent() + val player = json.decodeFromString(input) + assertNull(player.position) + assertNull(player.number) + } + + @Test + fun testStaffDeserialization() { + val input = """ + {"role":"Coach","fname":"Jean","lname":"Dupont"} + """.trimIndent() + val staff = json.decodeFromString(input) + assertEquals("Coach", staff.role) + assertEquals("Jean", staff.fname) + assertEquals("Dupont", staff.lname) + } + + @Test + fun testConvocationDeserialization() { + val input = """ + { + "available": [ + {"position":"Gardien","number":1,"fname":"Jean","lname":"Dupont","dob":"2012-03-15"} + ], + "staff": [ + {"role":"Coach","fname":"Marc","lname":"Blanc"} + ] + } + """.trimIndent() + val convocation = json.decodeFromString(input) + assertEquals(1, convocation.available.size) + assertEquals("1", convocation.available[0].number) + assertEquals(1, convocation.staff.size) + assertEquals("Coach", convocation.staff[0].role) + } + + @Test + fun testConvocationWithEmptyArrays() { + val input = """{"available":[],"staff":[]}""" + val convocation = json.decodeFromString(input) + assertEquals(0, convocation.available.size) + assertEquals(0, convocation.staff.size) + } + + @Test + fun testEventDetailDeserialization() { + val input = """ + { + "title": "U13 (Elite) - Saison HC Ajoie", + "type": "games", + "place": "Raiffeisen Arena, Porrentruy", + "time_start": "2024-11-10T14:00:00", + "time_end": "2024-11-10T16:15:00", + "is_away": "1", + "convocation": { + "available": [], + "staff": [] + } + } + """.trimIndent() + val detail = json.decodeFromString(input) + assertEquals("U13 (Elite) - Saison HC Ajoie", detail.title) + assertEquals("games", detail.type) + assertEquals("2024-11-10T14:00:00", detail.timeStart) + assertEquals(0, detail.convocation.available.size) + } + + @Test + fun testUserInfoDeserialization() { + val input = """{"email":"rene@luria.ch","sub":"abc123"}""" + val userInfo = json.decodeFromString(input) + assertEquals("rene@luria.ch", userInfo.email) + } + + @Test + fun testEventRoundTripSerialization() { + val event = Event( + idEvent = "761040", + agegroup = "U13 (Elite)", + name = "U13 Elite - HC Ajoie", + title = "U13 (Elite)\nGame\nArena", + opponent = "HC Ajoie", + place = "Arena", + start = "2024-11-10T14:00:00", + end = "2024-11-10T16:15:00", + color = "#e4222e", + eventType = "Jeu", + ) + val jsonString = json.encodeToString(Event.serializer(), event) + val decoded = json.decodeFromString(jsonString) + assertEquals(event, decoded) + } +}