diff --git a/amethyst/build.gradle b/amethyst/build.gradle index 435213034..c1acc5a08 100644 --- a/amethyst/build.gradle +++ b/amethyst/build.gradle @@ -293,6 +293,7 @@ dependencies { testImplementation libs.junit testImplementation libs.mockk + testImplementation libs.kotlinx.coroutines.test androidTestImplementation platform(libs.androidx.compose.bom) androidTestImplementation libs.androidx.junit diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/MediaCompressor.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/MediaCompressor.kt index 1f4726898..6b7468c59 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/MediaCompressor.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/MediaCompressor.kt @@ -160,7 +160,7 @@ class MediaCompressor { } } - fun from( + private fun from( uri: Uri?, contentType: String?, context: Context, diff --git a/amethyst/src/test/java/com/vitorpamplona/amethyst/ui/components/MediaCompressorTest.kt b/amethyst/src/test/java/com/vitorpamplona/amethyst/ui/components/MediaCompressorTest.kt new file mode 100644 index 000000000..d0ab42afd --- /dev/null +++ b/amethyst/src/test/java/com/vitorpamplona/amethyst/ui/components/MediaCompressorTest.kt @@ -0,0 +1,132 @@ +/** + * Copyright (c) 2024 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.ui.components + +import android.net.Uri +import android.os.Looper +import com.abedelazizshe.lightcompressorlibrary.VideoCompressor +import id.zelory.compressor.Compressor +import io.mockk.MockKAnnotations +import io.mockk.coEvery +import io.mockk.coVerify +import io.mockk.every +import io.mockk.mockk +import io.mockk.mockkStatic +import io.mockk.unmockkAll +import io.mockk.verify +import kotlinx.coroutines.test.runTest +import org.junit.After +import org.junit.Before +import org.junit.Ignore +import org.junit.Test +import java.io.File + +class MediaCompressorTest { + @Before + fun setUp() { + // Mock compressors + mockkStatic(android.content.Context::class) + mockkStatic(VideoCompressor::class) + mockkStatic(Compressor::class) + + // mock out main thread check + mockkStatic(Looper::class) + every { Looper.myLooper() } returns mockk() + every { Looper.getMainLooper() } returns mockk() + MockKAnnotations.init(this) + } + + @After + fun tearDown() { + unmockkAll() + } + + @Test + fun `Compression level uncompressed should not compress media`() = + runTest { + // setup + val mediaQuality = CompressorQuality.UNCOMPRESSED + val uri = mockk() + val contentType = "video" + + // Execution + MediaCompressor().compress( + uri, + contentType, + applicationContext = mockk(), + onReady = { _, _, _ -> }, + onError = { }, + mediaQuality = mediaQuality, + ) + + // Verify + verify(exactly = 0) { VideoCompressor.start(any(), any(), any(), any(), any(), any(), any()) } + } + + @Test + fun `Video media should invoke video compressor`() = + runTest { + // setup + val mediaQuality = CompressorQuality.MEDIUM + val uri = mockk() + val contentType = "video" + + every { VideoCompressor.start(any(), any(), any(), any(), any(), any(), any()) } returns Unit + + // Execution + MediaCompressor().compress( + uri, + contentType, + applicationContext = mockk(), + onReady = { _, _, _ -> }, + onError = { }, + mediaQuality = mediaQuality, + ) + + // Verify + verify(exactly = 1) { VideoCompressor.start(any(), any(), any(), any(), any(), any(), any()) } + } + + @Test + @Ignore("Bug in mockk https://github.com/mockk/mockk/issues/944") + fun `Image media should invoke image compressor`() = + runTest { + // setup + val mediaQuality = CompressorQuality.MEDIUM + val uri = mockk() + val contentType = "image" + + coEvery { Compressor.compress(any(), any(), any(), any()) } returns File("test") + + // Execution + MediaCompressor().compress( + uri, + contentType, + applicationContext = mockk(), + onReady = { _, _, _ -> }, + onError = { }, + mediaQuality = mediaQuality, + ) + + // Verify + coVerify(exactly = 0) { Compressor.compress(any(), any(), any(), any()) } + } +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 1768d5ee9..437eab6e6 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -35,6 +35,7 @@ lightcompressor = "1.3.2" markdown = "077a2cde64" media3 = "1.4.1" mockk = "1.13.12" +kotlinx-coroutines-test = "1.9.0-RC.2" navigationCompose = "2.8.1" okhttp = "5.0.0-alpha.14" runner = "1.6.2" @@ -116,6 +117,7 @@ markdown-commonmark = { group = "com.github.vitorpamplona.compose-richtext", nam markdown-ui = { group = "com.github.vitorpamplona.compose-richtext", name = "richtext-ui", version.ref = "markdown" } markdown-ui-material3 = { group = "com.github.vitorpamplona.compose-richtext", name = "richtext-ui-material3", version.ref = "markdown" } mockk = { group = "io.mockk", name = "mockk", version.ref = "mockk" } +kotlinx-coroutines-test = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-test", version.ref = "kotlinx-coroutines-test"} okhttp = { group = "com.squareup.okhttp3", name = "okhttp", version.ref = "okhttp" } rfc3986-normalizer = { group = "org.czeal", name = "rfc3986", version.ref = "rfc3986" } secp256k1-kmp-jni-android = { group = "fr.acinq.secp256k1", name = "secp256k1-kmp-jni-android", version.ref = "secp256k1KmpJniAndroid" }