From cfd87473b9a493eb737ca6ed62e37ff35d87eb67 Mon Sep 17 00:00:00 2001 From: Jacques Smuts Date: Fri, 11 Nov 2022 11:55:42 +0200 Subject: [PATCH 1/3] Added Moko Resources - Added SharedResources.kt with some samples for how to use Moko --- build.gradle.kts | 2 + gradle/libs.versions.toml | 6 +++ ui/common/build.gradle.kts | 13 ++++- .../common/sharedres/SharedResources.kt | 46 ++++++++++++++++++ .../commonMain/resources/MR/base/strings.xml | 4 ++ .../commonMain/resources/MR/colors/colors.xml | 14 ++++++ .../MR/images/mastodon_logo@1.5x.png | Bin 0 -> 3117 bytes .../resources/MR/images/mastodon_logo@1x.png | Bin 0 -> 1971 bytes .../resources/MR/images/mastodon_logo@2x.png | Bin 0 -> 3847 bytes .../resources/MR/images/mastodon_logo@3x.png | Bin 0 -> 6201 bytes .../resources/MR/images/mastodon_logo@4x.png | Bin 0 -> 7696 bytes .../commonMain/resources/MR/ru/strings.xml | 4 ++ 12 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 ui/common/src/commonMain/kotlin/social/androiddev/common/sharedres/SharedResources.kt create mode 100644 ui/common/src/commonMain/resources/MR/base/strings.xml create mode 100644 ui/common/src/commonMain/resources/MR/colors/colors.xml create mode 100644 ui/common/src/commonMain/resources/MR/images/mastodon_logo@1.5x.png create mode 100644 ui/common/src/commonMain/resources/MR/images/mastodon_logo@1x.png create mode 100644 ui/common/src/commonMain/resources/MR/images/mastodon_logo@2x.png create mode 100644 ui/common/src/commonMain/resources/MR/images/mastodon_logo@3x.png create mode 100644 ui/common/src/commonMain/resources/MR/images/mastodon_logo@4x.png create mode 100644 ui/common/src/commonMain/resources/MR/ru/strings.xml diff --git a/build.gradle.kts b/build.gradle.kts index ff2121f1..803258cd 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -7,6 +7,7 @@ buildscript { repositories { google() mavenCentral() + gradlePluginPortal() } dependencies { @@ -15,6 +16,7 @@ buildscript { classpath(libs.com.android.tools.build.gradle) classpath(libs.org.jetbrains.kotlin.serialization) classpath(libs.com.squareup.sqldelight.gradle.plugin) + classpath(libs.dev.icerock.moko.resources.generator) } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b87eaa54..d2f54552 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -13,6 +13,7 @@ androidx-appcompat = "1.5.1" androidx-activity = "1.6.1" androidx-compose-foundation = "1.2.1" com-arkivanov-decompose = "1.0.0-alpha-05" +dev-icerock-moko-resources = "0.20.1" [libraries] @@ -22,6 +23,7 @@ org-jetbrains-kotlin-gradle-plugin = { module = "org.jetbrains.kotlin:kotlin-gra com-android-tools-build-gradle = { module = "com.android.tools.build:gradle", version.ref = "com-android-tools-build" } org-jetbrains-kotlin-serialization = { module = "org.jetbrains.kotlin:kotlin-serialization", version.ref = "org-jetbrains-kotlin" } com-squareup-sqldelight-gradle-plugin = { module = "com.squareup.sqldelight:gradle-plugin", version.ref = "com-squareup-sqldelight" } +dev-icerock-moko-resources-generator = { module = "dev.icerock.moko:resources-generator", version.ref = "dev-icerock-moko-resources"} # libraries io-ktor-client-core = { module = "io.ktor:ktor-client-core", version.ref = "io-ktor" } @@ -37,6 +39,10 @@ org-jetbrains-kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kot com-google-truth = { module = "com.google.truth:truth", version.ref = "com-google-truth" } +dev-icerock-moko-resources-common = { module = "dev.icerock.moko:resources", version.ref = "dev-icerock-moko-resources"} +dev-icerock-moko-resources-jvm = { module = "dev.icerock.moko:resources-compose", version.ref = "dev-icerock-moko-resources"} +dev-icerock-moko-resources-test = { module = "dev.icerock.moko:resources-test", version.ref = "dev-icerock-moko-resources"} + com-squareup-sqldelight-android-driver = { module = "com.squareup.sqldelight:android-driver", version.ref = "com-squareup-sqldelight" } com-squareup-sqldelight-native-driver = { module = "com.squareup.sqldelight:native-driver", version.ref = "com-squareup-sqldelight" } com-squareup-sqldelight-sqlite-driver = { module = "com.squareup.sqldelight:sqlite-driver", version.ref = "com-squareup-sqldelight" } diff --git a/ui/common/build.gradle.kts b/ui/common/build.gradle.kts index bf4c66db..d2df6ef8 100644 --- a/ui/common/build.gradle.kts +++ b/ui/common/build.gradle.kts @@ -2,9 +2,9 @@ plugins { id("kotlin-multiplatform") id("org.jetbrains.compose") id("com.android.library") + id("dev.icerock.mobile.multiplatform-resources") } - val targetSDKVersion: Int by rootProject.extra val minSDKVersion: Int by rootProject.extra val compileSDKVersion: Int by rootProject.extra @@ -44,6 +44,7 @@ kotlin { implementation(compose.material) implementation(libs.com.arkivanov.decompose) implementation(libs.com.arkivanov.decompose.extensions.compose.jetbrains) + implementation(libs.dev.icerock.moko.resources.common) } } @@ -51,12 +52,14 @@ kotlin { dependencies { // Workaround for https://github.com/JetBrains/compose-jb/issues/2340 implementation(libs.androidx.compose.foundation) + implementation(libs.dev.icerock.moko.resources.jvm) } } named("desktopMain") { dependencies { implementation(compose.desktop.common) + implementation(libs.dev.icerock.moko.resources.jvm) } } } @@ -65,3 +68,11 @@ kotlin { kotlinOptions.jvmTarget = "11" } } + +multiplatformResources { + multiplatformResourcesPackage = "social.androiddev.common" // required +// multiplatformResourcesClassName = "SharedRes" // optional, default MR +// multiplatformResourcesVisibility = dev.icerock.gradle.MRVisibility.Public // optional, default Public +// iosBaseLocalizationRegion = "en" // optional, default "en" +// multiplatformResourcesSourceSet = "commonMain" // optional, default "commonMain" +} \ No newline at end of file diff --git a/ui/common/src/commonMain/kotlin/social/androiddev/common/sharedres/SharedResources.kt b/ui/common/src/commonMain/kotlin/social/androiddev/common/sharedres/SharedResources.kt new file mode 100644 index 00000000..745486b0 --- /dev/null +++ b/ui/common/src/commonMain/kotlin/social/androiddev/common/sharedres/SharedResources.kt @@ -0,0 +1,46 @@ +package social.androiddev.common.sharedres + +import dev.icerock.moko.graphics.Color +import dev.icerock.moko.resources.ImageResource +import dev.icerock.moko.resources.desc.Resource +import dev.icerock.moko.resources.desc.StringDesc +import dev.icerock.moko.resources.getImageByFileName +import social.androiddev.common.MR + +object SharedResources { + + /** + * A String that can be localised. + * On Android, call `toString(context)`, on iOS, call `localized()` + * + * @see https://github.com/icerockdev/moko-resources#example-1---simple-localization-string + */ + fun getLocalisedHello(): StringDesc { + + return StringDesc.Resource(MR.strings.my_string) + } + + /** + * Get an image resource by the file name, and falls back to mastodon logo if it fails + * + * @see https://github.com/icerockdev/moko-resources#example-7---pass-image + */ + fun getImageByFileName(name: String): ImageResource { + val fallbackImage = MR.images.mastodon_logo + return MR.images.getImageByFileName(name) ?: fallbackImage + } + + /** + * Android: val color: Color = MR.colors.valueColor.getColor(context = this) + * + * iOS:val color: UIColor = MR.colors.valueColor.getColor(UIScreen.main.traitCollection.userInterfaceStyle) + * + * @see https://github.com/icerockdev/moko-resources#example-9---pass-colors + */ + fun getValueColor(): Color { + return MR.colors.valueColor.color + } + + + +} \ No newline at end of file diff --git a/ui/common/src/commonMain/resources/MR/base/strings.xml b/ui/common/src/commonMain/resources/MR/base/strings.xml new file mode 100644 index 00000000..74d2165c --- /dev/null +++ b/ui/common/src/commonMain/resources/MR/base/strings.xml @@ -0,0 +1,4 @@ + + + My default localization string + \ No newline at end of file diff --git a/ui/common/src/commonMain/resources/MR/colors/colors.xml b/ui/common/src/commonMain/resources/MR/colors/colors.xml new file mode 100644 index 00000000..cc914249 --- /dev/null +++ b/ui/common/src/commonMain/resources/MR/colors/colors.xml @@ -0,0 +1,14 @@ + + + + #B02743FF + @color/valueColor + + 0xB92743FF + 7CCFEEFF + + + @color/valueColor + @color/referenceColor + + \ No newline at end of file diff --git a/ui/common/src/commonMain/resources/MR/images/mastodon_logo@1.5x.png b/ui/common/src/commonMain/resources/MR/images/mastodon_logo@1.5x.png new file mode 100644 index 0000000000000000000000000000000000000000..b6fe79b19887b0abc5da9415c552799ed73134e7 GIT binary patch literal 3117 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 Hu0mjf^`HNv literal 0 HcmV?d00001 diff --git a/ui/common/src/commonMain/resources/MR/images/mastodon_logo@1x.png b/ui/common/src/commonMain/resources/MR/images/mastodon_logo@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..d5651c721fbc2f4671ea82f7e47290505fe1c11c GIT binary patch literal 1971 zcmV;k2Tb^hP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D2S`aoK~!i%)tXss zR8<(qzoAp6Q>K&_T6RP!pnwq+mx#)P#uyWgEDstJVvO4hf+mVY<%I`*FcC4tDB=>A zC=e4DOc4{sja3WCVgaE_DW!Wm)9FlSI^+L;xp#W!&bfDPCv6%3$&Wkt^e*Q+-*>)q z?m2kGrRHv^9f?CR7!NAI3@`y)0mgxeU^EyD{9qLDf)St(M07ep7q|%8z`vjgoYu?E zgCGbUTRl68qocAKfQqvM<=}oWAKUH)gO|{tMJ%)` z!vnaGA#pp{2F9=~PxJ{`4^J?}Qc`(f4tNgaQ{}09!DDFPv_?-m(cSb7SPYm!@=eTU zOF%U|!9LRO0aTv9Zv>3}0aZS0Dzi}z_c7D008HhYQqO<^lX2JxmTCnyDlG8G_<&dL zo>?MuDt%H_?h`LeZwdEFU3;&5cPc0+nxoR*!^Y~DcZ6|Y0QVJ1)mWbt;=WenzSFp` zDJpH2`xN5Xu?`;C#1pdtci^xY%+d;Mbko#gdHA|9ax;#8uSW_{F)D$q-iLqcyJGUg znQqzmTZ_b5sB8WtzpPkLCbv#2mLl9ogQz4f;dSS6-!K1!<@H~iB^q}ezvAF47_f{d zW&@b6o&_9jGsG7zKqcP1Z;}K?s``GqKB{S#EeG4-iMZCLJW6X9Rz!fc;GBj8T%BUy>PN0FVPF2 zU^F3b?Q2Dxx5?gfVL5c62Sx;CO?9IjI3L!op%ILG9=qWw8q3c8b6vL_X^hB^XS?O) zU5&C2_nXD*=TG!&8P7osqY;Jy^n~UOmFVVxFFp2|CRquq8qsP8(Xv)GhvS-|Rxynp zy%^Qc`c($QjZEbvqgFiHUd?oAeO70rPnr??Rz>3pIjk_OzB48l6q%*BFDd6bIGawF z-_keil-{g1QavYu1fFCPw}>SS7po$%B>I4UViKOBjUQHdJdR^QN`?WfqYHc8NtHZU zcXgHQUW;-UHFD*F!H|7j>{=S-E}SrI2H4jnXAiJLCI8PJV5UeI1~5bwU2O0)1Rmh( zM&Ga*Fa#dpgf8U)CiJWmaW`USWzJu_voVd254B4us(MAv9=HHf9-sk(<^c|J-<}Mn zQPa>PQ4Cs{%Gm?0Ak~T4Au@-<9L4u?a5AGB8!jm)53sK1@I8<+fRho&FNmR2P99+V zxATW)04$*aT-H;Ht#=WVG&B5mRZR^BtfWVqmRq0S73CyDDZceM>a5KSQ%=H1%>f*^ z?wR2@ew6TA*!+heI%F+A-g}(CU$ctOtiada>QE_EF-)jWyez8MBQ%@eZ$ z+i`dR*iNhSL_dL5Fo0iVX;TRh|=Z6?aHQ))f{8rGT zl|p6%xO|=ZLmr7y!4_WwzF>h_W&?N;N4IWHz7$aJ$E? z=&hmf7`LDHgLU9Z@F}1%N}00|7qy-O8?=J#dLMB2WGc84Tn)I3GYN2+rW7zYa-+g{ z4`Z1FCOad?9S%swUfJK^4A{eSw6?2+Vm5%k7XYreq{{&DH_^2po=IHh3c z*#R;-i$V+)dhD_)%>Z4WgX&8^9mTz2ZobU{jPuJPl>zKjTR^tyHN$Tj;IjNJEXYNA z-^*FHH{-!C;IImCH$IzaEce!!{y0bBRF~;{hiZy`s~3pqE8>kg!68vYNJ2LZi7 z7!DkD`8US6)AJZc9HcmqF}#igjv?=XGiWTMuM9}84WRUl!Hp2c?{vUv1Px(-nF;uR zD!7NsYuK`^Fgr8j`z)vj?Btv_90Qzx1yT8o&n|Zo`46Mgrgb1?&~5+#002ovPDHLk FV1nanf!Y87 literal 0 HcmV?d00001 diff --git a/ui/common/src/commonMain/resources/MR/images/mastodon_logo@2x.png b/ui/common/src/commonMain/resources/MR/images/mastodon_logo@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..b6af9e9ff451cbf755fc866a4d200cb90cda1543 GIT binary patch literal 3847 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 + + Моя строка локализации по умолчанию + \ No newline at end of file From 42ae08010a9a584f52fe74a8a9f1e60eda5969ac Mon Sep 17 00:00:00 2001 From: Jacques Smuts Date: Fri, 11 Nov 2022 12:50:33 +0200 Subject: [PATCH 2/3] Added Moko Resources Test - Added SharedResourcesTest.kt --- ui/common/build.gradle.kts | 9 +++++ .../common/sharedres/SharedResourcesTest.kt | 38 +++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 ui/common/src/commonTest/kotlin/social/androiddev/common/sharedres/SharedResourcesTest.kt diff --git a/ui/common/build.gradle.kts b/ui/common/build.gradle.kts index d2df6ef8..e71070ad 100644 --- a/ui/common/build.gradle.kts +++ b/ui/common/build.gradle.kts @@ -62,6 +62,15 @@ kotlin { implementation(libs.dev.icerock.moko.resources.jvm) } } + + //Testing + named("commonTest") { + dependencies { + implementation(kotlin("test")) + implementation(libs.org.jetbrains.kotlin.test.common) + implementation(libs.org.jetbrains.kotlin.test.annotations.common) + } + } } tasks.withType { diff --git a/ui/common/src/commonTest/kotlin/social/androiddev/common/sharedres/SharedResourcesTest.kt b/ui/common/src/commonTest/kotlin/social/androiddev/common/sharedres/SharedResourcesTest.kt new file mode 100644 index 00000000..eb6bedba --- /dev/null +++ b/ui/common/src/commonTest/kotlin/social/androiddev/common/sharedres/SharedResourcesTest.kt @@ -0,0 +1,38 @@ +package social.androiddev.common.sharedres + +import dev.icerock.moko.graphics.Color +import kotlin.test.assertEquals +import kotlin.test.Test + +/** + * These tests aren't ideal, but they show that there's some file access going on + */ +class SharedResourcesTest { + + @Test + fun `getLocalisedHello returns a stringresource with unknown content`() { + + // This test only confirms that the resource is there. To get the content, it must run on androidTest, desktopTest + assertEquals( + "ResourceStringDesc(stringRes=StringResource(resourceId=2132017188))", + SharedResources.getLocalisedHello().toString() + ) + + } + + @Test + fun `getting empty image still returns a fallback image`() { + assertEquals( + "dev.icerock.moko.resources.ImageResource@821330f", + SharedResources.getImageByFileName("").toString() + ) + } + + @Test + fun `getValueColor returns a specific Color class`() { + assertEquals( + Color(red=176, green=39, blue=67, alpha=255), + SharedResources.getValueColor() + ) + } +} \ No newline at end of file From 4b083fd287dbac17c04c818e2ba178ce220464a7 Mon Sep 17 00:00:00 2001 From: Jacques Smuts Date: Fri, 11 Nov 2022 13:35:50 +0200 Subject: [PATCH 3/3] Added Moko Resources Test - Fixed MastodonApiTests.kt and made it use .json files as resources. --- data/network/build.gradle.kts | 8 ++ .../common/network/MastodonApiImpl.kt | 3 + .../files}/response_account_required.json | 0 .../files}/response_context_required.json | 0 .../response_conversation_required.json | 0 .../files}/response_instance_invalid.json | 0 .../files}/response_instance_valid.json | 0 .../response_notification_required.json | 0 .../files}/response_status_required.json | 0 .../common/network/MastodonApiTests.kt | 75 ++++++++++--------- 10 files changed, 51 insertions(+), 35 deletions(-) rename data/network/src/commonTest/resources/{ => MR/files}/response_account_required.json (100%) rename data/network/src/commonTest/resources/{ => MR/files}/response_context_required.json (100%) rename data/network/src/commonTest/resources/{ => MR/files}/response_conversation_required.json (100%) rename data/network/src/commonTest/resources/{ => MR/files}/response_instance_invalid.json (100%) rename data/network/src/commonTest/resources/{ => MR/files}/response_instance_valid.json (100%) rename data/network/src/commonTest/resources/{ => MR/files}/response_notification_required.json (100%) rename data/network/src/commonTest/resources/{ => MR/files}/response_status_required.json (100%) rename data/network/src/{commonTest => desktopTest}/kotlin/social/androiddev/common/network/MastodonApiTests.kt (51%) diff --git a/data/network/build.gradle.kts b/data/network/build.gradle.kts index ba3b38a8..d4ca07b6 100644 --- a/data/network/build.gradle.kts +++ b/data/network/build.gradle.kts @@ -2,6 +2,7 @@ plugins { id("kotlin-multiplatform") id("com.android.library") kotlin("plugin.serialization") + id("dev.icerock.mobile.multiplatform-resources") } val targetSDKVersion: Int by rootProject.extra @@ -46,6 +47,7 @@ kotlin { implementation(libs.io.ktor.serialization.kotlinx.json) implementation(libs.io.ktor.client.content.negotiation) implementation(libs.org.jetbrains.kotlinx.serialization.json) + implementation(libs.dev.icerock.moko.resources.common) } } @@ -105,7 +107,13 @@ kotlin { implementation(libs.io.ktor.client.mock) implementation(libs.org.jetbrains.kotlin.test.common) implementation(libs.org.jetbrains.kotlin.test.annotations.common) + implementation(libs.dev.icerock.moko.resources.test) } } } } + +multiplatformResources { + multiplatformResourcesPackage = "social.androiddev.common.network" // required + multiplatformResourcesSourceSet = "commonTest" // optional, default "commonMain" +} \ No newline at end of file diff --git a/data/network/src/commonMain/kotlin/social/androiddev/common/network/MastodonApiImpl.kt b/data/network/src/commonMain/kotlin/social/androiddev/common/network/MastodonApiImpl.kt index 90015b5f..5d163833 100644 --- a/data/network/src/commonMain/kotlin/social/androiddev/common/network/MastodonApiImpl.kt +++ b/data/network/src/commonMain/kotlin/social/androiddev/common/network/MastodonApiImpl.kt @@ -4,6 +4,7 @@ import io.ktor.client.HttpClient import io.ktor.client.call.body import io.ktor.client.plugins.ResponseException import io.ktor.client.request.get +import io.ktor.serialization.* import kotlinx.serialization.SerializationException import social.androiddev.common.network.model.Instance @@ -24,6 +25,8 @@ class MastodonApiImpl( Result.failure(exception = exception) } catch (exception: ResponseException) { Result.failure(exception = exception) + } catch (exception: JsonConvertException) { + Result.failure(exception = exception) } } } diff --git a/data/network/src/commonTest/resources/response_account_required.json b/data/network/src/commonTest/resources/MR/files/response_account_required.json similarity index 100% rename from data/network/src/commonTest/resources/response_account_required.json rename to data/network/src/commonTest/resources/MR/files/response_account_required.json diff --git a/data/network/src/commonTest/resources/response_context_required.json b/data/network/src/commonTest/resources/MR/files/response_context_required.json similarity index 100% rename from data/network/src/commonTest/resources/response_context_required.json rename to data/network/src/commonTest/resources/MR/files/response_context_required.json diff --git a/data/network/src/commonTest/resources/response_conversation_required.json b/data/network/src/commonTest/resources/MR/files/response_conversation_required.json similarity index 100% rename from data/network/src/commonTest/resources/response_conversation_required.json rename to data/network/src/commonTest/resources/MR/files/response_conversation_required.json diff --git a/data/network/src/commonTest/resources/response_instance_invalid.json b/data/network/src/commonTest/resources/MR/files/response_instance_invalid.json similarity index 100% rename from data/network/src/commonTest/resources/response_instance_invalid.json rename to data/network/src/commonTest/resources/MR/files/response_instance_invalid.json diff --git a/data/network/src/commonTest/resources/response_instance_valid.json b/data/network/src/commonTest/resources/MR/files/response_instance_valid.json similarity index 100% rename from data/network/src/commonTest/resources/response_instance_valid.json rename to data/network/src/commonTest/resources/MR/files/response_instance_valid.json diff --git a/data/network/src/commonTest/resources/response_notification_required.json b/data/network/src/commonTest/resources/MR/files/response_notification_required.json similarity index 100% rename from data/network/src/commonTest/resources/response_notification_required.json rename to data/network/src/commonTest/resources/MR/files/response_notification_required.json diff --git a/data/network/src/commonTest/resources/response_status_required.json b/data/network/src/commonTest/resources/MR/files/response_status_required.json similarity index 100% rename from data/network/src/commonTest/resources/response_status_required.json rename to data/network/src/commonTest/resources/MR/files/response_status_required.json diff --git a/data/network/src/commonTest/kotlin/social/androiddev/common/network/MastodonApiTests.kt b/data/network/src/desktopTest/kotlin/social/androiddev/common/network/MastodonApiTests.kt similarity index 51% rename from data/network/src/commonTest/kotlin/social/androiddev/common/network/MastodonApiTests.kt rename to data/network/src/desktopTest/kotlin/social/androiddev/common/network/MastodonApiTests.kt index ceb23bfb..67702c71 100644 --- a/data/network/src/commonTest/kotlin/social/androiddev/common/network/MastodonApiTests.kt +++ b/data/network/src/desktopTest/kotlin/social/androiddev/common/network/MastodonApiTests.kt @@ -10,58 +10,63 @@ import io.ktor.http.HttpStatusCode import io.ktor.http.headersOf import io.ktor.serialization.kotlinx.json.json import io.ktor.utils.io.ByteReadChannel -import kotlin.test.Ignore +import kotlinx.coroutines.runBlocking +import kotlinx.serialization.json.Json +import org.junit.Test import kotlin.test.assertFalse import kotlin.test.assertNotNull import kotlin.test.assertNull import kotlin.test.assertTrue -import kotlinx.coroutines.runBlocking -import kotlinx.serialization.json.Json -import kotlin.test.Test +/** + * I was unable to read a .json file from commonTest, and so API tests must be done from + * desktopTest, androidTest, and/or iosTest. + */ class MastodonApiTests { - // TODO: fix loading json from resources - // @Test - fun `Instance request should fail with invalid response`() = runBlocking { - // given - // val content: String = javaClass.classLoader.getResource("response_instance_invalid.json").readText() - val content: String = "" - val mastodonApi = MastodonApiImpl( - httpClient = createMockClient( - statusCode = HttpStatusCode.Unauthorized, content = ByteReadChannel(text = content) + + @Test + fun `Instance request should fail with invalid response`() { + runBlocking { + + // given + val content = MR.files.response_account_required.readText() + val mastodonApi = MastodonApiImpl( + httpClient = createMockClient( + statusCode = HttpStatusCode.Unauthorized, + content = ByteReadChannel(text = content) + ) ) - ) - // when - val result = mastodonApi.getInstance("") + // when + val result = mastodonApi.getInstance("") - // then - assertFalse(actual = result.isSuccess) - assertNull(actual = result.getOrNull()?.uri) + // then + assertFalse(actual = result.isSuccess) + assertNull(actual = result.getOrNull()?.uri) + } } - // TODO: fix loading json from resources - //@Test - fun `Instance request should succeed with required field response`() = runBlocking { - // given - // val content: String = javaClass.classLoader.getResource("response_instance_valid.json").readText() - val content: String = "" + @Test + fun `Instance request should succeed with required field response`() { + runBlocking { - val mastodonApi = MastodonApiImpl( - httpClient = createMockClient( - statusCode = HttpStatusCode.Unauthorized, content = ByteReadChannel(text = content) + // given + val content = MR.files.response_instance_valid.readText() + val mastodonApi = MastodonApiImpl( + httpClient = createMockClient( + statusCode = HttpStatusCode.Unauthorized, content = ByteReadChannel(text = content) + ) ) - ) - // when - val result = mastodonApi.getInstance("") + // when + val result = mastodonApi.getInstance("") - // then - assertTrue(actual = result.isSuccess) - assertNotNull(actual = result.getOrNull()?.uri) + // then + assertTrue(actual = result.isSuccess) + assertNotNull(actual = result.getOrNull()?.uri) + } } - private fun createMockClient( statusCode: HttpStatusCode = HttpStatusCode.OK, content: ByteReadChannel ): HttpClient {