Merge pull request #43 from InsanusMokrassar/0.18.1

0.18.1
This commit is contained in:
InsanusMokrassar 2019-12-02 13:22:53 +06:00 committed by GitHub
commit ba145d3ff8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 253 additions and 46 deletions

View File

@ -20,6 +20,18 @@
* `Game` now is not serializable and have no additional trash, related to serialization
* `TelegramFile` was removed
### 0.18.1 Libraries update
* Update libraries:
* `kotlin`: 1.3.41 -> 1.3.61
* `kotlin coroutines`: 1.2.2 -> 1.3.2
* `kotlin serialization`: 0.11.1 -> 0.14.0
* `joda time`: 2.10.3 -> 2.10.5
* `ktor`: 1.2.3 -> 1.2.6
* `BotAction` now will be deserialized in a little bit other way
* `BotActionSerializer` now is internal
* Most part of serializers now are objects (instead of classes as was previously)
## 0.17.0 July 29, 2019 API Update
Libraries updates:

View File

@ -1,4 +1,4 @@
project.version = "0.18.0"
project.version = "0.18.1"
project.group = "com.github.insanusmokrassar"
buildscript {
@ -39,6 +39,8 @@ dependencies {
api "io.ktor:ktor-server:$ktor_version"
api "io.ktor:ktor-server-host-common:$ktor_version"
testImplementation "org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version"
}
compileKotlin {

View File

@ -1,9 +1,9 @@
kotlin.code.style=official
kotlin_version=1.3.41
kotlin_coroutines_version=1.2.2
kotlin_serialisation_runtime_version=0.11.1
joda_time_version=2.10.3
ktor_version=1.2.3
kotlin_version=1.3.61
kotlin_coroutines_version=1.3.2
kotlin_serialisation_runtime_version=0.14.0
joda_time_version=2.10.5
ktor_version=1.2.6
gradle_bintray_plugin_version=1.8.4

View File

@ -1,6 +1,6 @@
#Thu Feb 21 12:05:40 HKT 2019
#Fri Nov 29 12:11:00 HKT 2019
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.2.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-6.0.1-all.zip

View File

@ -1,18 +1 @@
/*
* This settings file was generated by the Gradle 'init' task.
*
* The settings file is used to specify which projects to include in your build.
* In a single project build this file can be empty or even removed.
*
* Detailed information about configuring a multi-project build in Gradle can be found
* in the user guide at https://docs.gradle.org/3.4.1/userguide/multi_project_builds.html
*/
/*
// To declare projects as part of a multi-project build use the 'include' method
include 'shared'
include 'api'
include 'services:webservice'
*/
rootProject.name = 'TelegramBotAPI'

View File

@ -37,7 +37,7 @@ data class Username(
fun String.toUsername(): Username = Username(this)
@Serializer(ChatIdentifier::class)
internal class ChatIdentifierSerializer: KSerializer<ChatIdentifier> {
internal object ChatIdentifierSerializer : KSerializer<ChatIdentifier> {
override fun deserialize(decoder: Decoder): ChatIdentifier {
val id = decoder.decodeString()
return id.toLongOrNull() ?.let {
@ -51,7 +51,7 @@ internal class ChatIdentifierSerializer: KSerializer<ChatIdentifier> {
override fun serialize(encoder: Encoder, obj: ChatIdentifier) {
when (obj) {
is ChatId -> encoder.encodeString(obj.chatId.toString())
is ChatId -> encoder.encodeLong(obj.chatId)
is Username -> encoder.encodeString(obj.username)
}
}

View File

@ -27,10 +27,9 @@ typealias Markdown = MarkdownParseMode
typealias HTML = HTMLParseMode
@Serializer(ParseMode::class)
internal class ParseModeSerializerObject: KSerializer<ParseMode> {
internal object ParseModeSerializerObject : KSerializer<ParseMode> {
override fun deserialize(decoder: Decoder): ParseMode {
val mode = decoder.decodeString()
return when (mode) {
return when (decoder.decodeString()) {
MarkdownParseMode.parseModeName -> MarkdownParseMode
HTMLParseMode.parseModeName -> HTMLParseMode
else -> throw IllegalArgumentException("Unknown parse mode")

View File

@ -5,7 +5,10 @@ import org.joda.time.DateTime
import java.util.concurrent.TimeUnit
@Serializable(TelegramDateSerializer::class)
class TelegramDate(
data class TelegramDate(
/**
* Contains UNIX time (seconds)
*/
private val date: Long
) {
constructor(dateTime: DateTime) : this(
@ -21,7 +24,7 @@ class TelegramDate(
fun DateTime.toTelegramDate(): TelegramDate = TelegramDate(this)
@Serializer(TelegramDate::class)
internal class TelegramDateSerializer: KSerializer<TelegramDate> {
internal object TelegramDateSerializer : KSerializer<TelegramDate> {
override fun serialize(encoder: Encoder, obj: TelegramDate) {
encoder.encodeLong(
TimeUnit.MILLISECONDS.toSeconds(obj.asDate.millis)

View File

@ -2,31 +2,29 @@ package com.github.insanusmokrassar.TelegramBotAPI.types.actions
import kotlinx.serialization.*
private val actions = listOf(
TypingAction,
UploadPhotoAction,
RecordVideoAction,
UploadVideoAction,
RecordAudioAction,
UploadAudioAction,
UploadDocumentAction,
FindLocationAction
)
@Serializable(BotActionSerializer::class)
sealed class BotAction {
abstract val actionName: String
}
@Serializer(BotAction::class)
class BotActionSerializer: KSerializer<BotAction> {
internal object BotActionSerializer: KSerializer<BotAction> {
override fun serialize(encoder: Encoder, obj: BotAction) {
encoder.encodeString(obj.actionName)
}
override fun deserialize(decoder: Decoder): BotAction {
val actionName = decoder.decodeString()
return actions.firstOrNull { it.actionName == actionName } ?: throw IllegalStateException("Unknown action type: $actionName")
return when (val actionName = decoder.decodeString()) {
TypingAction.actionName -> TypingAction
UploadPhotoAction.actionName -> UploadPhotoAction
RecordVideoAction.actionName -> RecordVideoAction
UploadVideoAction.actionName -> UploadVideoAction
RecordAudioAction.actionName -> RecordAudioAction
UploadAudioAction.actionName -> UploadAudioAction
UploadDocumentAction.actionName -> UploadDocumentAction
FindLocationAction.actionName -> FindLocationAction
else -> throw IllegalStateException("Unknown action type: $actionName")
}
}
}

View File

@ -0,0 +1,60 @@
package com.github.insanusmokrassar.TelegramBotAPI.types
import com.github.insanusmokrassar.TelegramBotAPI.types.actions.*
import kotlinx.serialization.ImplicitReflectionSerializer
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
import kotlin.test.Test
import kotlin.test.assertEquals
@ImplicitReflectionSerializer
class BotActionTests {
@Serializable
data class Example(
val botAction: BotAction
)
private fun checkBotAction(example: Example, sourceAction: BotAction) {
assertEquals(
sourceAction.actionName,
when (example.botAction) {
TypingAction -> example.botAction.actionName
UploadPhotoAction -> example.botAction.actionName
RecordVideoAction -> example.botAction.actionName
UploadVideoAction -> example.botAction.actionName
RecordAudioAction -> example.botAction.actionName
UploadAudioAction -> example.botAction.actionName
UploadDocumentAction -> example.botAction.actionName
FindLocationAction -> example.botAction.actionName
}
)
}
private fun checkBotActionSerializeDeserialize(example: Example) {
val stringified = Json.plain.stringify(Example.serializer(), example)
assertEquals("{\"botAction\":\"${example.botAction.actionName}\"}", stringified)
val deserialized = Json.plain.parse(Example.serializer(), stringified)
assertEquals(example, deserialized)
checkBotAction(deserialized, example.botAction)
}
@Test
fun `BotAction correctly serialized and deserialized`() {
fun BotAction.example() = Example(this)
listOf(
TypingAction.example(),
UploadPhotoAction.example(),
RecordVideoAction.example(),
UploadVideoAction.example(),
RecordAudioAction.example(),
UploadAudioAction.example(),
UploadDocumentAction.example(),
FindLocationAction.example()
).forEach {
checkBotActionSerializeDeserialize(it)
}
}
}

View File

@ -0,0 +1,79 @@
package com.github.insanusmokrassar.TelegramBotAPI.types
import kotlinx.serialization.ImplicitReflectionSerializer
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
import kotlin.test.*
@ImplicitReflectionSerializer
private const val chatIdentifierChatId: Identifier = 123L
@ImplicitReflectionSerializer
private const val chatIdentifierLink = "tg://user?id=$chatIdentifierChatId"
@ImplicitReflectionSerializer
private const val testUsername = "@Example"
@ImplicitReflectionSerializer
class ChatIdentifierTests {
@Test
fun `Cast from Int to ChatId is working correctly`() {
val chatId = chatIdentifierChatId.toInt().toChatId()
assertEquals(chatIdentifierChatId, chatId.chatId)
}
@Test
fun `Cast from Byte to ChatId is working correctly`() {
val chatId = chatIdentifierChatId.toByte().toChatId()
assertEquals(chatIdentifierChatId, chatId.chatId)
}
@Test
fun `Cast from Identifier to ChatId is working correctly`() {
val chatId = chatIdentifierChatId.toChatId()
assertEquals(chatIdentifierChatId, chatId.chatId)
}
@Test
fun `Creating link from ChatId is correct`() {
val chatId = chatIdentifierChatId.toChatId()
assertEquals(chatIdentifierLink, chatId.link)
}
@Test
fun `Cast from String to Username is working correctly`() {
assertEquals(testUsername, testUsername.toUsername().username)
assertFails("Username creating must fail when trying to create from string which is not starting from @ symbol") {
testUsername.replace("@", "").toUsername().username
}
}
@Test
fun `Deserializing from String must work correctly`() {
@Serializable
data class Example(
val identifier: ChatIdentifier
)
Example(chatIdentifierChatId.toChatId()).let { withChatId ->
val stringified = Json.plain.stringify(Example.serializer(), withChatId)
assertEquals(stringified, "{\"identifier\":$chatIdentifierChatId}")
val deserialized = Json.plain.parse(Example.serializer(), stringified)
assertEquals(withChatId, deserialized)
}
Example(testUsername.toUsername()).let { withUsername ->
val stringified = Json.plain.stringify(Example.serializer(), withUsername)
assertEquals(stringified, "{\"identifier\":\"$testUsername\"}")
val deserialized = Json.plain.parse(Example.serializer(), stringified)
assertEquals(withUsername, deserialized)
}
// Replace @ by empty string, because from time to time we can retrieve from Telegram system
// username without starting @ symbol
Example(testUsername.toUsername()).let { withUsername ->
val stringified = Json.plain.stringify(Example.serializer(), withUsername).replace("@", "")
assertEquals("{\"identifier\":\"${testUsername.replace("@", "")}\"}", stringified)
val deserialized = Json.plain.parse(Example.serializer(), stringified)
assertEquals(withUsername, deserialized)
}
}
}

View File

@ -0,0 +1,38 @@
package com.github.insanusmokrassar.TelegramBotAPI.types
import com.github.insanusmokrassar.TelegramBotAPI.types.ParseMode.*
import kotlinx.serialization.ImplicitReflectionSerializer
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
import kotlin.test.Test
import kotlin.test.assertEquals
@ImplicitReflectionSerializer
class ParseModeTests {
@Serializable
data class Example(
val mode: ParseMode
)
@Test
fun `Markdown parse mode correctly serializing and deserializing`() {
val example = Example(Markdown)
val stringified = Json.plain.stringify(Example.serializer(), example)
assertEquals("{\"mode\":\"Markdown\"}", stringified)
val deserialized = Json.plain.parse(Example.serializer(), stringified)
assertEquals(example, deserialized)
}
@Test
fun `HTML parse mode correctly serializing and deserializing`() {
val example = Example(HTML)
val stringified = Json.plain.stringify(Example.serializer(), example)
assertEquals("{\"mode\":\"HTML\"}", stringified)
val deserialized = Json.plain.parse(Example.serializer(), stringified)
assertEquals(example, deserialized)
}
}

View File

@ -0,0 +1,33 @@
package com.github.insanusmokrassar.TelegramBotAPI.types
import kotlinx.serialization.ImplicitReflectionSerializer
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
import org.joda.time.DateTime
import java.util.concurrent.TimeUnit
import kotlin.test.Test
import kotlin.test.assertEquals
private val dateTimeMillis = System.currentTimeMillis()
private val dateTimeUnix = TimeUnit.MILLISECONDS.toSeconds(dateTimeMillis)
private val dateTime = DateTime(TimeUnit.SECONDS.toMillis(dateTimeUnix))
@ImplicitReflectionSerializer
class TelegramDateTests {
@Serializable
data class Example(
val dateTime: TelegramDate
)
@Test
fun `Serializtion of TelegramDate is working correctly`() {
val example = Example(TelegramDate(dateTimeUnix))
val stringified = Json.plain.stringify(Example.serializer(), example)
assertEquals("{\"dateTime\":$dateTimeUnix}", stringified)
val deserialized = Json.plain.parse(Example.serializer(), stringified)
assertEquals(example, deserialized)
assertEquals(dateTime, deserialized.dateTime.asDate)
}
}