diff --git a/config/detekt/detekt.yml b/config/detekt/detekt.yml index 0a67d2e8c85..d2e419e4e24 100644 --- a/config/detekt/detekt.yml +++ b/config/detekt/detekt.yml @@ -115,6 +115,8 @@ complexity: LongMethod: active: true threshold: 60 + # Generated code cannot be restructured to satisfy this rule: the next re-vendor would undo it. + excludes: [ '**/io/getstream/chat/android/network/**' ] ignoreAnnotated: [ 'ParameterizedRobolectricTestRunner.Parameters' ] LongParameterList: active: true diff --git a/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api/RetrofitCdnApi.kt b/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api/RetrofitCdnApi.kt index 0c903e2119d..04bfad90dc5 100644 --- a/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api/RetrofitCdnApi.kt +++ b/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api/RetrofitCdnApi.kt @@ -16,9 +16,9 @@ package io.getstream.chat.android.client.api -import io.getstream.chat.android.client.api.models.UploadFileResponse import io.getstream.chat.android.client.call.RetrofitCall import io.getstream.chat.android.client.utils.ProgressCallback +import io.getstream.chat.android.network.models.FileUploadResponse import io.getstream.chat.android.network.models.Response import okhttp3.MultipartBody import retrofit2.http.DELETE @@ -38,7 +38,7 @@ internal interface RetrofitCdnApi { @Path("id") channelId: String, @Part file: MultipartBody.Part, @Tag progressCallback: ProgressCallback?, - ): RetrofitCall + ): RetrofitCall @Multipart @POST("/channels/{type}/{id}/file") @@ -47,7 +47,7 @@ internal interface RetrofitCdnApi { @Path("id") channelId: String, @Part file: MultipartBody.Part, @Tag progressCallback: ProgressCallback?, - ): RetrofitCall + ): RetrofitCall @DELETE("/channels/{type}/{id}/file") fun deleteFile( @@ -68,7 +68,7 @@ internal interface RetrofitCdnApi { fun uploadFile( @Part file: MultipartBody.Part, @Tag progressCallback: ProgressCallback?, - ): RetrofitCall + ): RetrofitCall @DELETE("/uploads/file") fun deleteFile( @@ -80,7 +80,7 @@ internal interface RetrofitCdnApi { fun uploadImage( @Part file: MultipartBody.Part, @Tag progressCallback: ProgressCallback?, - ): RetrofitCall + ): RetrofitCall @DELETE("/uploads/image") fun deleteImage( diff --git a/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/MoshiChatApi.kt b/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/MoshiChatApi.kt index ffb411991a2..5f29fc2d259 100644 --- a/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/MoshiChatApi.kt +++ b/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/MoshiChatApi.kt @@ -70,7 +70,6 @@ import io.getstream.chat.android.client.api2.model.requests.UpdateMessageRequest import io.getstream.chat.android.client.api2.model.requests.UpsertPushPreferencesRequest import io.getstream.chat.android.client.api2.model.response.ChannelResponse import io.getstream.chat.android.client.api2.model.response.PushPreferencesResponse -import io.getstream.chat.android.client.api2.model.response.TranslateMessageRequest import io.getstream.chat.android.client.api2.model.response.getUserChannelPreference import io.getstream.chat.android.client.api2.model.response.getUserPreference import io.getstream.chat.android.client.call.RetrofitCall @@ -164,6 +163,7 @@ import io.getstream.chat.android.network.models.SearchUserGroupsResponse import io.getstream.chat.android.network.models.SendEventRequest import io.getstream.chat.android.network.models.SendReactionRequest import io.getstream.chat.android.network.models.SortParamRequest +import io.getstream.chat.android.network.models.TranslateMessageRequest import io.getstream.chat.android.network.models.UnblockUsersRequest import io.getstream.chat.android.network.models.UpdateChannelPartialRequest import io.getstream.chat.android.network.models.UpdateMemberPartialRequest @@ -1438,7 +1438,7 @@ constructor( override fun translate(messageId: String, language: String): Call { return messageApi.translate( messageId = messageId, - request = TranslateMessageRequest(language), + request = TranslateMessageRequest(TranslateMessageRequest.Language.fromString(language)), ).mapDomain { response -> response.message.toDomain() } diff --git a/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/endpoint/MessageApi.kt b/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/endpoint/MessageApi.kt index f77f84a14fa..e91d5f6f8f8 100644 --- a/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/endpoint/MessageApi.kt +++ b/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/endpoint/MessageApi.kt @@ -27,13 +27,13 @@ import io.getstream.chat.android.client.api2.model.response.QueryDraftMessagesRe import io.getstream.chat.android.client.api2.model.response.QueryReactionsResponse import io.getstream.chat.android.client.api2.model.response.ReactionResponse import io.getstream.chat.android.client.api2.model.response.ReactionsResponse -import io.getstream.chat.android.client.api2.model.response.TranslateMessageRequest import io.getstream.chat.android.client.call.RetrofitCall import io.getstream.chat.android.network.models.MessageActionRequest import io.getstream.chat.android.network.models.QueryDraftsRequest import io.getstream.chat.android.network.models.QueryReactionsRequest import io.getstream.chat.android.network.models.Response import io.getstream.chat.android.network.models.SendReactionRequest +import io.getstream.chat.android.network.models.TranslateMessageRequest import io.getstream.chat.android.network.models.UpdateMessagePartialRequest import retrofit2.http.Body import retrofit2.http.DELETE diff --git a/stream-chat-android-client/src/test/java/io/getstream/chat/android/client/api2/mapping/UploadFileResponseMappingTest.kt b/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/mapping/FileUploadResponseMapping.kt similarity index 52% rename from stream-chat-android-client/src/test/java/io/getstream/chat/android/client/api2/mapping/UploadFileResponseMappingTest.kt rename to stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/mapping/FileUploadResponseMapping.kt index ebca592e91e..d48d1ca6f4d 100644 --- a/stream-chat-android-client/src/test/java/io/getstream/chat/android/client/api2/mapping/UploadFileResponseMappingTest.kt +++ b/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/mapping/FileUploadResponseMapping.kt @@ -16,20 +16,22 @@ package io.getstream.chat.android.client.api2.mapping -import io.getstream.chat.android.client.Mother import io.getstream.chat.android.models.UploadedFile -import org.amshove.kluent.shouldBeEqualTo -import org.junit.jupiter.api.Test +import io.getstream.chat.android.network.models.FileUploadResponse +import io.getstream.result.Error +import io.getstream.result.Result -internal class UploadFileResponseMappingTest { - - @Test - fun `UploadFileResponse is correctly mapped to UploadedFile`() { - val dto = Mother.randomUploadFileResponse() - val expected = UploadedFile( - file = dto.file, - thumbUrl = dto.thumb_url, +/** + * The upload endpoints omit `file` when the asset URL is empty, which leaves nothing to attach, so + * that is reported as a failure rather than an upload with a blank URL. + */ +internal fun FileUploadResponse.toUploadedFile(): Result = + when (val uploadedFileUrl = file) { + null -> Result.Failure(Error.GenericError(message = "Missing file URL in the upload response")) + else -> Result.Success( + UploadedFile( + file = uploadedFileUrl, + thumbUrl = thumbUrl, + ), ) - dto.toUploadedFile() shouldBeEqualTo expected } -} diff --git a/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/mapping/UploadFileResponseMapping.kt b/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/mapping/UploadFileResponseMapping.kt deleted file mode 100644 index d8a6639b628..00000000000 --- a/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/mapping/UploadFileResponseMapping.kt +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2014-2026 Stream.io Inc. All rights reserved. - * - * Licensed under the Stream License; - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://github.com/GetStream/stream-chat-android/blob/main/LICENSE - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.getstream.chat.android.client.api2.mapping - -import io.getstream.chat.android.client.api.models.UploadFileResponse -import io.getstream.chat.android.models.UploadedFile - -internal fun UploadFileResponse.toUploadedFile() = - UploadedFile( - file = this.file, - thumbUrl = this.thumb_url, - ) diff --git a/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/model/response/TranslateMessageRequest.kt b/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/model/response/TranslateMessageRequest.kt deleted file mode 100644 index dc1eae65b68..00000000000 --- a/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/model/response/TranslateMessageRequest.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2014-2026 Stream.io Inc. All rights reserved. - * - * Licensed under the Stream License; - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://github.com/GetStream/stream-chat-android/blob/main/LICENSE - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.getstream.chat.android.client.api2.model.response - -import com.squareup.moshi.JsonClass - -@JsonClass(generateAdapter = true) -internal data class TranslateMessageRequest( - val language: String, -) diff --git a/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/parser2/MoshiChatParser.kt b/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/parser2/MoshiChatParser.kt index f037b5cb971..222d467ce10 100644 --- a/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/parser2/MoshiChatParser.kt +++ b/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/parser2/MoshiChatParser.kt @@ -60,6 +60,7 @@ import io.getstream.chat.android.client.socket.ErrorResponse import io.getstream.chat.android.client.socket.SocketErrorMessage import io.getstream.chat.android.network.infrastructure.Serializer import io.getstream.chat.android.network.models.CreatePollRequest +import io.getstream.chat.android.network.models.TranslateMessageRequest import io.getstream.chat.android.network.models.UpdatePollRequest import retrofit2.Retrofit import retrofit2.converter.moshi.MoshiConverterFactory @@ -107,6 +108,10 @@ internal class MoshiChatParser( UpdatePollRequest.VotingVisibility::class.java, UpdatePollRequest.VotingVisibility.VotingVisibilityAdapter(), ) + .add( + TranslateMessageRequest.Language::class.java, + TranslateMessageRequest.Language.LanguageAdapter(), + ) .build() } diff --git a/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/uploader/StreamFileUploader.kt b/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/uploader/StreamFileUploader.kt index ce624c2f2aa..b49493528a7 100644 --- a/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/uploader/StreamFileUploader.kt +++ b/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/uploader/StreamFileUploader.kt @@ -17,12 +17,13 @@ package io.getstream.chat.android.client.uploader import io.getstream.chat.android.client.api.RetrofitCdnApi -import io.getstream.chat.android.client.api.models.UploadFileResponse import io.getstream.chat.android.client.api2.mapping.toUploadedFile import io.getstream.chat.android.client.extensions.getMediaType import io.getstream.chat.android.client.utils.ProgressCallback import io.getstream.chat.android.models.UploadedFile +import io.getstream.chat.android.network.models.FileUploadResponse import io.getstream.result.Result +import io.getstream.result.flatMap import okhttp3.MultipartBody import okhttp3.RequestBody.Companion.asRequestBody import java.io.File @@ -44,7 +45,7 @@ internal class StreamFileUploader( channelId = channelId, file = file.asBodyPart(), progressCallback = callback, - ).execute().map(UploadFileResponse::toUploadedFile) + ).execute().flatMap(FileUploadResponse::toUploadedFile) override fun sendFile( channelType: String, @@ -56,7 +57,7 @@ internal class StreamFileUploader( channelId = channelId, file = file.asBodyPart(), progressCallback = null, - ).execute().map(UploadFileResponse::toUploadedFile) + ).execute().flatMap(FileUploadResponse::toUploadedFile) override fun sendImage( channelType: String, @@ -69,7 +70,7 @@ internal class StreamFileUploader( channelId = channelId, file = file.asBodyPart(), progressCallback = callback, - ).execute().map(UploadFileResponse::toUploadedFile) + ).execute().flatMap(FileUploadResponse::toUploadedFile) override fun sendImage( channelType: String, @@ -81,7 +82,7 @@ internal class StreamFileUploader( channelId = channelId, file = file.asBodyPart(), progressCallback = null, - ).execute().map(UploadFileResponse::toUploadedFile) + ).execute().flatMap(FileUploadResponse::toUploadedFile) override fun deleteFile( channelType: String, @@ -111,7 +112,7 @@ internal class StreamFileUploader( ): Result = retrofitCdnApi.uploadFile( file = file.asBodyPart(), progressCallback = progressCallback, - ).execute().map(UploadFileResponse::toUploadedFile) + ).execute().flatMap(FileUploadResponse::toUploadedFile) override fun deleteFile( url: String, @@ -124,7 +125,7 @@ internal class StreamFileUploader( ): Result = retrofitCdnApi.uploadImage( file = file.asBodyPart(), progressCallback = progressCallback, - ).execute().map(UploadFileResponse::toUploadedFile) + ).execute().flatMap(FileUploadResponse::toUploadedFile) override fun deleteImage( url: String, diff --git a/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api/models/UploadFileResponse.kt b/stream-chat-android-client/src/main/java/io/getstream/chat/android/network/models/FileUploadResponse.kt similarity index 55% rename from stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api/models/UploadFileResponse.kt rename to stream-chat-android-client/src/main/java/io/getstream/chat/android/network/models/FileUploadResponse.kt index 4593e8cf0a4..bb975ff2943 100644 --- a/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api/models/UploadFileResponse.kt +++ b/stream-chat-android-client/src/main/java/io/getstream/chat/android/network/models/FileUploadResponse.kt @@ -14,12 +14,28 @@ * limitations under the License. */ -package io.getstream.chat.android.client.api.models +@file:Suppress( + "ArrayInDataClass", + "EnumEntryName", + "RemoveRedundantQualifierName", + "UnusedImport", +) + +package io.getstream.chat.android.network.models + +import com.squareup.moshi.Json + +/** + * + */ +@com.squareup.moshi.JsonClass(generateAdapter = true) +internal data class FileUploadResponse( + @Json(name = "duration") + internal val duration: String, -import com.squareup.moshi.JsonClass + @Json(name = "file") + internal val file: String? = null, -@JsonClass(generateAdapter = true) -internal data class UploadFileResponse( - val file: String, - val thumb_url: String?, + @Json(name = "thumb_url") + internal val thumbUrl: String? = null, ) diff --git a/stream-chat-android-client/src/main/java/io/getstream/chat/android/network/models/TranslateMessageRequest.kt b/stream-chat-android-client/src/main/java/io/getstream/chat/android/network/models/TranslateMessageRequest.kt new file mode 100644 index 00000000000..6d70127241e --- /dev/null +++ b/stream-chat-android-client/src/main/java/io/getstream/chat/android/network/models/TranslateMessageRequest.kt @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2014-2026 Stream.io Inc. All rights reserved. + * + * Licensed under the Stream License; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://github.com/GetStream/stream-chat-android/blob/main/LICENSE + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@file:Suppress( + "ArrayInDataClass", + "EnumEntryName", + "RemoveRedundantQualifierName", + "UnusedImport", +) + +package io.getstream.chat.android.network.models + +import com.squareup.moshi.FromJson +import com.squareup.moshi.Json +import com.squareup.moshi.JsonAdapter +import com.squareup.moshi.JsonReader +import com.squareup.moshi.JsonWriter +import com.squareup.moshi.ToJson + +/** + * + */ +@com.squareup.moshi.JsonClass(generateAdapter = true) +internal data class TranslateMessageRequest( + @Json(name = "language") + internal val language: Language, +) { + + /** + * Language Enum + */ + internal sealed class Language(internal val value: String) { + override fun toString(): String = value + + internal companion object { + internal fun fromString(s: String): Language = when (s) { + "af" -> Af + "am" -> Am + "ar" -> Ar + "az" -> Az + "bg" -> Bg + "bn" -> Bn + "bs" -> Bs + "cs" -> Cs + "da" -> Da + "de" -> De + "el" -> El + "en" -> En + "es" -> Es + "es-MX" -> EsMX + "et" -> Et + "fa" -> Fa + "fa-AF" -> FaAF + "fi" -> Fi + "fr" -> Fr + "fr-CA" -> FrCA + "ha" -> Ha + "he" -> He + "hi" -> Hi + "hr" -> Hr + "ht" -> Ht + "hu" -> Hu + "id" -> Id + "it" -> It + "ja" -> Ja + "ka" -> Ka + "ko" -> Ko + "lt" -> Lt + "lv" -> Lv + "ms" -> Ms + "nl" -> Nl + "no" -> No + "pl" -> Pl + "ps" -> Ps + "pt" -> Pt + "ro" -> Ro + "ru" -> Ru + "sk" -> Sk + "sl" -> Sl + "so" -> So + "sq" -> Sq + "sr" -> Sr + "sv" -> Sv + "sw" -> Sw + "ta" -> Ta + "th" -> Th + "tl" -> Tl + "tr" -> Tr + "uk" -> Uk + "ur" -> Ur + "vi" -> Vi + "zh" -> Zh + "zh-TW" -> ZhTW + else -> Unknown(s) + } + } + internal object Af : Language("af") + internal object Am : Language("am") + internal object Ar : Language("ar") + internal object Az : Language("az") + internal object Bg : Language("bg") + internal object Bn : Language("bn") + internal object Bs : Language("bs") + internal object Cs : Language("cs") + internal object Da : Language("da") + internal object De : Language("de") + internal object El : Language("el") + internal object En : Language("en") + internal object Es : Language("es") + internal object EsMX : Language("es-MX") + internal object Et : Language("et") + internal object Fa : Language("fa") + internal object FaAF : Language("fa-AF") + internal object Fi : Language("fi") + internal object Fr : Language("fr") + internal object FrCA : Language("fr-CA") + internal object Ha : Language("ha") + internal object He : Language("he") + internal object Hi : Language("hi") + internal object Hr : Language("hr") + internal object Ht : Language("ht") + internal object Hu : Language("hu") + internal object Id : Language("id") + internal object It : Language("it") + internal object Ja : Language("ja") + internal object Ka : Language("ka") + internal object Ko : Language("ko") + internal object Lt : Language("lt") + internal object Lv : Language("lv") + internal object Ms : Language("ms") + internal object Nl : Language("nl") + internal object No : Language("no") + internal object Pl : Language("pl") + internal object Ps : Language("ps") + internal object Pt : Language("pt") + internal object Ro : Language("ro") + internal object Ru : Language("ru") + internal object Sk : Language("sk") + internal object Sl : Language("sl") + internal object So : Language("so") + internal object Sq : Language("sq") + internal object Sr : Language("sr") + internal object Sv : Language("sv") + internal object Sw : Language("sw") + internal object Ta : Language("ta") + internal object Th : Language("th") + internal object Tl : Language("tl") + internal object Tr : Language("tr") + internal object Uk : Language("uk") + internal object Ur : Language("ur") + internal object Vi : Language("vi") + internal object Zh : Language("zh") + internal object ZhTW : Language("zh-TW") + internal data class Unknown(val unknownValue: String) : Language(unknownValue) + + internal class LanguageAdapter : JsonAdapter() { + @FromJson + override fun fromJson(reader: JsonReader): Language? { + val s = reader.nextString() ?: return null + return Language.fromString(s) + } + + @ToJson + override fun toJson(writer: JsonWriter, value: Language?) { + writer.value(value?.value) + } + } + } +} diff --git a/stream-chat-android-client/src/test/java/io/getstream/chat/android/client/Mother.kt b/stream-chat-android-client/src/test/java/io/getstream/chat/android/client/Mother.kt index 10ec4e593a1..a29560fe136 100644 --- a/stream-chat-android-client/src/test/java/io/getstream/chat/android/client/Mother.kt +++ b/stream-chat-android-client/src/test/java/io/getstream/chat/android/client/Mother.kt @@ -23,7 +23,6 @@ import io.getstream.chat.android.client.api.models.QueryThreadsRequest import io.getstream.chat.android.client.api.models.QueryUsersRequest import io.getstream.chat.android.client.api.models.SendActionRequest import io.getstream.chat.android.client.api.models.UpdatePollRequest -import io.getstream.chat.android.client.api.models.UploadFileResponse import io.getstream.chat.android.client.api2.model.dto.AttachmentDto import io.getstream.chat.android.client.api2.model.dto.ChannelInfoDto import io.getstream.chat.android.client.api2.model.dto.ConfigDto @@ -97,6 +96,7 @@ import io.getstream.chat.android.network.models.AppResponseFields import io.getstream.chat.android.network.models.BlockUsersResponse import io.getstream.chat.android.network.models.DeviceResponse import io.getstream.chat.android.network.models.FileUploadConfig +import io.getstream.chat.android.network.models.FileUploadResponse import io.getstream.chat.android.network.models.GetApplicationResponse import io.getstream.chat.android.network.models.UnblockUsersResponse import io.getstream.chat.android.network.models.UnreadCountsChannel @@ -1288,12 +1288,13 @@ internal object Mother { next = next, ) - fun randomUploadFileResponse( - file: String = randomString(), + fun randomFileUploadResponse( + file: String? = randomString(), thumbUrl: String? = randomString(), - ): UploadFileResponse = UploadFileResponse( + ): FileUploadResponse = FileUploadResponse( + duration = randomString(), file = file, - thumb_url = thumbUrl, + thumbUrl = thumbUrl, ) fun randomErrorDto( diff --git a/stream-chat-android-client/src/test/java/io/getstream/chat/android/client/api2/MoshiChatApiTest.kt b/stream-chat-android-client/src/test/java/io/getstream/chat/android/client/api2/MoshiChatApiTest.kt index aacee4f8a2d..e797f95df1a 100644 --- a/stream-chat-android-client/src/test/java/io/getstream/chat/android/client/api2/MoshiChatApiTest.kt +++ b/stream-chat-android-client/src/test/java/io/getstream/chat/android/client/api2/MoshiChatApiTest.kt @@ -87,7 +87,6 @@ import io.getstream.chat.android.client.api2.model.response.SyncHistoryResponse import io.getstream.chat.android.client.api2.model.response.ThreadInfoResponse import io.getstream.chat.android.client.api2.model.response.ThreadResponse import io.getstream.chat.android.client.api2.model.response.TokenResponse -import io.getstream.chat.android.client.api2.model.response.TranslateMessageRequest import io.getstream.chat.android.client.api2.model.response.UpdateUsersResponse import io.getstream.chat.android.client.api2.model.response.UsersResponse import io.getstream.chat.android.client.call.RetrofitCall @@ -167,6 +166,7 @@ import io.getstream.chat.android.network.models.SearchRolesResponse import io.getstream.chat.android.network.models.SearchUserGroupsResponse import io.getstream.chat.android.network.models.SendEventRequest import io.getstream.chat.android.network.models.SortParamRequest +import io.getstream.chat.android.network.models.TranslateMessageRequest import io.getstream.chat.android.network.models.UnblockUsersRequest import io.getstream.chat.android.network.models.UnblockUsersResponse import io.getstream.chat.android.network.models.UpdateChannelPartialRequest @@ -1871,7 +1871,7 @@ internal class MoshiChatApiTest { val language = randomString() val result = sut.translate(messageId, language).await() // then - val expectedBody = TranslateMessageRequest(language) + val expectedBody = TranslateMessageRequest(TranslateMessageRequest.Language.fromString(language)) result `should be instance of` expected verify(api, times(1)).translate(messageId, expectedBody) } diff --git a/stream-chat-android-client/src/test/java/io/getstream/chat/android/client/api2/mapping/FileUploadResponseMappingTest.kt b/stream-chat-android-client/src/test/java/io/getstream/chat/android/client/api2/mapping/FileUploadResponseMappingTest.kt new file mode 100644 index 00000000000..6e4b30d5fe0 --- /dev/null +++ b/stream-chat-android-client/src/test/java/io/getstream/chat/android/client/api2/mapping/FileUploadResponseMappingTest.kt @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2014-2026 Stream.io Inc. All rights reserved. + * + * Licensed under the Stream License; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://github.com/GetStream/stream-chat-android/blob/main/LICENSE + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.getstream.chat.android.client.api2.mapping + +import io.getstream.chat.android.client.Mother +import io.getstream.chat.android.models.UploadedFile +import io.getstream.result.Result +import org.amshove.kluent.shouldBeEqualTo +import org.amshove.kluent.shouldBeInstanceOf +import org.junit.jupiter.api.Test + +internal class FileUploadResponseMappingTest { + + @Test + fun `FileUploadResponse is correctly mapped to UploadedFile`() { + val dto = Mother.randomFileUploadResponse() + + val result = dto.toUploadedFile() + + result shouldBeEqualTo Result.Success( + UploadedFile( + file = dto.file!!, + thumbUrl = dto.thumbUrl, + ), + ) + } + + @Test + fun `FileUploadResponse without a thumbnail is mapped with a null thumbUrl`() { + val dto = Mother.randomFileUploadResponse(thumbUrl = null) + + val result = dto.toUploadedFile() + + result shouldBeEqualTo Result.Success(UploadedFile(file = dto.file!!, thumbUrl = null)) + } + + @Test + fun `FileUploadResponse without a file URL fails instead of yielding a blank upload`() { + val dto = Mother.randomFileUploadResponse(file = null) + + val result = dto.toUploadedFile() + + result shouldBeInstanceOf Result.Failure::class + } +} diff --git a/stream-chat-android-client/src/test/java/io/getstream/chat/android/client/parser2/TranslateMessageRequestAdapterTest.kt b/stream-chat-android-client/src/test/java/io/getstream/chat/android/client/parser2/TranslateMessageRequestAdapterTest.kt new file mode 100644 index 00000000000..92f17dd2cf7 --- /dev/null +++ b/stream-chat-android-client/src/test/java/io/getstream/chat/android/client/parser2/TranslateMessageRequestAdapterTest.kt @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2014-2026 Stream.io Inc. All rights reserved. + * + * Licensed under the Stream License; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://github.com/GetStream/stream-chat-android/blob/main/LICENSE + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.getstream.chat.android.client.parser2 + +import io.getstream.chat.android.network.models.TranslateMessageRequest +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.Test +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.MethodSource + +internal class TranslateMessageRequestAdapterTest { + private val parser = ParserFactory.createMoshiChatParser() + + @Test + fun `Serialize TranslateMessageRequest with a language the models do not know`() { + val language = TranslateMessageRequest.Language.fromString("xx") + + val json = parser.toJson(TranslateMessageRequest(language)) + + Assertions.assertEquals("""{"language":"xx"}""", json) + } + + @ParameterizedTest + @MethodSource("languages") + fun `Serialize TranslateMessageRequest for every language the API accepts`(code: String) { + val json = parser.toJson(TranslateMessageRequest(TranslateMessageRequest.Language.fromString(code))) + + Assertions.assertEquals("""{"language":"$code"}""", json) + } + + companion object { + @JvmStatic + fun languages(): List = listOf( + "af", "am", "ar", "az", "bg", "bn", "bs", "cs", "da", "de", "el", "en", "es", "es-MX", "et", "fa", + "fa-AF", "fi", "fr", "fr-CA", "ha", "he", "hi", "hr", "ht", "hu", "id", "it", "ja", "ka", "ko", + "lt", "lv", "ms", "nl", "no", "pl", "ps", "pt", "ro", "ru", "sk", "sl", "so", "sq", "sr", "sv", + "sw", "ta", "th", "tl", "tr", "uk", "ur", "vi", "zh", "zh-TW", + ) + } +} diff --git a/stream-chat-android-client/src/test/java/io/getstream/chat/android/client/uploader/StreamFileUploaderTest.kt b/stream-chat-android-client/src/test/java/io/getstream/chat/android/client/uploader/StreamFileUploaderTest.kt index 6e4af1a000a..c99c7de8cd0 100644 --- a/stream-chat-android-client/src/test/java/io/getstream/chat/android/client/uploader/StreamFileUploaderTest.kt +++ b/stream-chat-android-client/src/test/java/io/getstream/chat/android/client/uploader/StreamFileUploaderTest.kt @@ -18,13 +18,13 @@ package io.getstream.chat.android.client.uploader import android.webkit.MimeTypeMap import androidx.test.ext.junit.runners.AndroidJUnit4 -import io.getstream.chat.android.client.Mother.randomUploadFileResponse +import io.getstream.chat.android.client.Mother.randomFileUploadResponse import io.getstream.chat.android.client.api.RetrofitCdnApi -import io.getstream.chat.android.client.api.models.UploadFileResponse import io.getstream.chat.android.client.utils.ProgressCallback import io.getstream.chat.android.client.utils.RetroError import io.getstream.chat.android.client.utils.RetroSuccess import io.getstream.chat.android.models.UploadedFile +import io.getstream.chat.android.network.models.FileUploadResponse import io.getstream.chat.android.network.models.Response import io.getstream.chat.android.randomFile import io.getstream.chat.android.randomString @@ -77,7 +77,7 @@ internal class StreamFileUploaderTest { @Test fun `Should send file to api when sending file without progress callback`() { whenever(retrofitCdnApi.sendFile(any(), any(), any(), anyOrNull())).thenReturn( - RetroSuccess(UploadFileResponse(file = "file", thumb_url = "thumb_url")).toRetrofitCall(), + RetroSuccess(FileUploadResponse(duration = "1ms", file = "file", thumbUrl = "thumb_url")).toRetrofitCall(), ) streamFileUploader.sendFile(channelType, channelId, userId, File("")) @@ -96,7 +96,7 @@ internal class StreamFileUploaderTest { val thumbUrl = "thumb_url" whenever(retrofitCdnApi.sendFile(any(), any(), any(), anyOrNull())).thenReturn( - RetroSuccess(UploadFileResponse(file = file, thumb_url = thumbUrl)).toRetrofitCall(), + RetroSuccess(FileUploadResponse(duration = "1ms", file = file, thumbUrl = thumbUrl)).toRetrofitCall(), ) val result = streamFileUploader.sendFile(channelType, channelId, userId, File("")) @@ -107,7 +107,7 @@ internal class StreamFileUploaderTest { @Test fun `Should return result containing error when sending file without progress callback failed`() { whenever(retrofitCdnApi.sendFile(any(), any(), any(), anyOrNull())).thenReturn( - RetroError(500).toRetrofitCall(), + RetroError(500).toRetrofitCall(), ) val result = streamFileUploader.sendFile(channelType, channelId, userId, File("")) @@ -118,7 +118,7 @@ internal class StreamFileUploaderTest { @Test fun `Should send file to api when sending file with progress callback`() { whenever(retrofitCdnApi.sendFile(any(), any(), any(), anyOrNull())).thenReturn( - RetroSuccess(UploadFileResponse(file = "file", thumb_url = "thumb_url")).toRetrofitCall(), + RetroSuccess(FileUploadResponse(duration = "1ms", file = "file", thumbUrl = "thumb_url")).toRetrofitCall(), ) streamFileUploader.sendFile( @@ -140,7 +140,7 @@ internal class StreamFileUploaderTest { @Test fun `Should send image to api when sending image without progress callback`() { whenever(retrofitCdnApi.sendImage(any(), any(), any(), anyOrNull())).thenReturn( - RetroSuccess(UploadFileResponse(file = "file", thumb_url = "thumb_url")).toRetrofitCall(), + RetroSuccess(FileUploadResponse(duration = "1ms", file = "file", thumbUrl = "thumb_url")).toRetrofitCall(), ) streamFileUploader.sendImage(channelType, channelId, userId, File("")) @@ -159,7 +159,7 @@ internal class StreamFileUploaderTest { val thumbUrl: String? = null whenever(retrofitCdnApi.sendImage(any(), any(), any(), anyOrNull())).thenReturn( - RetroSuccess(UploadFileResponse(file = file, thumb_url = thumbUrl)).toRetrofitCall(), + RetroSuccess(FileUploadResponse(duration = "1ms", file = file, thumbUrl = thumbUrl)).toRetrofitCall(), ) val result = streamFileUploader.sendImage(channelType, channelId, userId, File("")) @@ -170,7 +170,7 @@ internal class StreamFileUploaderTest { @Test fun `Should return containing error when sending image without progress callback failed`() { whenever(retrofitCdnApi.sendImage(any(), any(), any(), anyOrNull())).thenReturn( - RetroError(500).toRetrofitCall(), + RetroError(500).toRetrofitCall(), ) val result = streamFileUploader.sendImage(channelType, channelId, userId, File("")) @@ -181,7 +181,7 @@ internal class StreamFileUploaderTest { @Test fun `Should send image to api when sending image with progress callback`() { whenever(retrofitCdnApi.sendImage(any(), any(), any(), anyOrNull())).thenReturn( - RetroSuccess(UploadFileResponse(file = "file", thumb_url = "thumb_url")).toRetrofitCall(), + RetroSuccess(FileUploadResponse(duration = "1ms", file = "file", thumbUrl = "thumb_url")).toRetrofitCall(), ) streamFileUploader.sendImage( @@ -233,7 +233,7 @@ internal class StreamFileUploaderTest { @Test fun `Should upload file to api with progress callback`() { val file = randomFile() - val response = randomUploadFileResponse() + val response = randomFileUploadResponse() whenever( retrofitCdnApi.uploadFile( file = any(), @@ -246,13 +246,13 @@ internal class StreamFileUploaderTest { assertTrue(result is Result.Success) val uploadedFile = result.getOrThrow() assertEquals(response.file, uploadedFile.file) - assertEquals(response.thumb_url, uploadedFile.thumbUrl) + assertEquals(response.thumbUrl, uploadedFile.thumbUrl) } @Test fun `Should upload file to api with no progress callback`() { val file = randomFile() - val response = randomUploadFileResponse() + val response = randomFileUploadResponse() whenever( retrofitCdnApi.uploadFile( file = any(), @@ -265,13 +265,13 @@ internal class StreamFileUploaderTest { assertTrue(result is Result.Success) val uploadedFile = result.getOrThrow() assertEquals(response.file, uploadedFile.file) - assertEquals(response.thumb_url, uploadedFile.thumbUrl) + assertEquals(response.thumbUrl, uploadedFile.thumbUrl) } @Test fun `Should upload image to api with progress callback`() { val file = randomFile() - val response = randomUploadFileResponse() + val response = randomFileUploadResponse() whenever( retrofitCdnApi.uploadImage( file = any(), @@ -284,13 +284,13 @@ internal class StreamFileUploaderTest { assertTrue(result is Result.Success) val uploadedFile = result.getOrThrow() assertEquals(response.file, uploadedFile.file) - assertEquals(response.thumb_url, uploadedFile.thumbUrl) + assertEquals(response.thumbUrl, uploadedFile.thumbUrl) } @Test fun `Should upload image to api with no progress callback`() { val file = randomFile() - val response = randomUploadFileResponse() + val response = randomFileUploadResponse() whenever( retrofitCdnApi.uploadImage( file = any(), @@ -303,7 +303,7 @@ internal class StreamFileUploaderTest { assertTrue(result is Result.Success) val uploadedFile = result.getOrThrow() assertEquals(response.file, uploadedFile.file) - assertEquals(response.thumb_url, uploadedFile.thumbUrl) + assertEquals(response.thumbUrl, uploadedFile.thumbUrl) } @Test