Skip to content

Commit

Permalink
test(android): setup native unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
EchoEllet committed Dec 4, 2024
1 parent 66ae598 commit 5df2e0d
Show file tree
Hide file tree
Showing 6 changed files with 251 additions and 5 deletions.
4 changes: 4 additions & 0 deletions quill_native_bridge_android/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

All notable changes to this project will be documented in this file.

## 0.0.1+2

- Setup [native unit tests](https://docs.flutter.dev/testing/testing-plugins#native-unit-tests) to test plugin platform functionality.

## 0.0.1+1

- Fixes a crash that can happen on Android API 28 and earlier when permission is denied. [Related comment with more details](https://github.com/singerdmx/flutter-quill/pull/2403#discussion_r1866055681).
Expand Down
18 changes: 18 additions & 0 deletions quill_native_bridge_android/android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,22 @@ android {
defaultConfig {
minSdk = 21
}

testOptions {
unitTests.all {
useJUnitPlatform()

testLogging {
events "passed", "skipped", "failed", "standardOut", "standardError"
outputs.upToDateWhen { false }
showStandardStreams = true
}
}
}
}

dependencies {
testImplementation("org.jetbrains.kotlin:kotlin-test")
testImplementation("org.mockito:mockito-core:5.14.2")
testImplementation("org.mockito.kotlin:mockito-kotlin:5.4.0")
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package dev.flutterquill.quill_native_bridge

import android.util.Log
import androidx.annotation.VisibleForTesting
import dev.flutterquill.quill_native_bridge.generated.QuillNativeBridgeApi
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.embedding.engine.plugins.activity.ActivityAware
Expand All @@ -12,8 +13,11 @@ class QuillNativeBridgePlugin : FlutterPlugin, ActivityAware {
const val TAG = "QuillNativeBridgePlugin"
}

private var pluginApi: QuillNativeBridgeImpl? = null
private var activityPluginBinding: ActivityPluginBinding? = null
@VisibleForTesting
internal var pluginApi: QuillNativeBridgeImpl? = null

@VisibleForTesting
internal var activityPluginBinding: ActivityPluginBinding? = null

override fun onAttachedToEngine(binding: FlutterPlugin.FlutterPluginBinding) {
val pluginApi = QuillNativeBridgeImpl(binding.applicationContext)
Expand Down Expand Up @@ -55,12 +59,14 @@ class QuillNativeBridgePlugin : FlutterPlugin, ActivityAware {
)
}

private fun setActivityPluginBinding(binding: ActivityPluginBinding, methodName: String) {
@VisibleForTesting
internal fun setActivityPluginBinding(binding: ActivityPluginBinding, methodName: String) {
activityPluginBinding = binding
pluginApi?.setActivityPluginBinding(binding) ?: logApiNotSetError(methodName)
}

private fun disposeActivityPluginBinding(methodName: String) {
@VisibleForTesting
internal fun disposeActivityPluginBinding(methodName: String) {
activityPluginBinding = null
pluginApi?.setActivityPluginBinding(null) ?: logApiNotSetError(methodName)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package dev.flutterquill.quill_native_bridge

import dev.flutterquill.quill_native_bridge.generated.FlutterError
import dev.flutterquill.quill_native_bridge.util.respondFlutterPigeonError
import dev.flutterquill.quill_native_bridge.util.respondFlutterPigeonSuccess
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertIs
import kotlin.test.assertTrue

class FlutterPigeonResponseTest {
@Test
fun `respondFlutterPigeonSuccess invokes with success result correctly`() {
var invoked = false
val messageInput = "Hello, World!"

val callback: (Result<String>) -> Unit = {
invoked = true

assertTrue(it.isSuccess)
assertEquals(messageInput, it.getOrNull())
}

callback.respondFlutterPigeonSuccess(messageInput)

assertTrue(invoked)
}

@Test
fun `respondFlutterPigeonError invokes with error result correctly`() {
var invoked = false
val flutterPigeonError = FlutterError("EXAMPLE_CODE", "Example message", "Example Details")

val callback: (Result<FlutterError>) -> Unit = {
invoked = true

assertTrue(it.isFailure)

val capturedFlutterPigeonError = it.exceptionOrNull()
assertIs<FlutterError>(capturedFlutterPigeonError)

assertEquals(flutterPigeonError.code, capturedFlutterPigeonError.code)
assertEquals(flutterPigeonError.message, capturedFlutterPigeonError.message)
assertEquals(flutterPigeonError.details, capturedFlutterPigeonError.details)
}

callback.respondFlutterPigeonError(
code = flutterPigeonError.code,
message = flutterPigeonError.message,
details = flutterPigeonError.details,
)

assertTrue(invoked)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
package dev.flutterquill.quill_native_bridge

import android.app.Activity
import android.app.Application
import io.flutter.embedding.engine.plugins.FlutterPlugin.FlutterPluginBinding
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding
import io.flutter.plugin.common.BinaryMessenger
import org.mockito.kotlin.any
import org.mockito.kotlin.mock
import org.mockito.kotlin.times
import org.mockito.kotlin.verify
import org.mockito.kotlin.verifyNoMoreInteractions
import kotlin.test.BeforeTest
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertNotNull
import kotlin.test.assertNull

class QuillNativeBridgePluginTest {

private lateinit var mockPluginApi: QuillNativeBridgeImpl
private lateinit var mockApplication: Application
private lateinit var mockActivity: Activity

private lateinit var mockFlutterPluginBinding: FlutterPluginBinding
private lateinit var mockActivityBinding: ActivityPluginBinding
private lateinit var mockBinaryMessenger: BinaryMessenger

private lateinit var plugin: QuillNativeBridgePlugin

@BeforeTest
fun setup() {
mockPluginApi = mock()
mockApplication = mock()
mockActivity = mock()
mockBinaryMessenger = mock()
mockFlutterPluginBinding = mock {
on { applicationContext }.thenReturn(mockApplication)
on { binaryMessenger }.thenReturn(mockBinaryMessenger)
}
mockActivityBinding = mock { on { activity }.thenReturn(mockActivity) }

plugin = QuillNativeBridgePlugin()
}

@Test
fun `The log tag is correct`() {
assertEquals("QuillNativeBridgePlugin", QuillNativeBridgePlugin.TAG)
}

@Test
fun `onAttachedToEngine sets up the plugin API`() {
assertNull(plugin.pluginApi, "The plugin API is null initially")

plugin.onAttachedToEngine(mockFlutterPluginBinding)

verify(mockFlutterPluginBinding).binaryMessenger
verify(mockFlutterPluginBinding).applicationContext
verifyNoMoreInteractions(mockFlutterPluginBinding)

assertNotNull(plugin.pluginApi, "The plugin API should be not null after the attach")
}

@Test
fun `onDetachedFromEngine tears down the plugin API`() {
plugin.onAttachedToEngine(mockFlutterPluginBinding)
plugin.onDetachedFromEngine(mockFlutterPluginBinding)

verify(mockFlutterPluginBinding, times(2)).binaryMessenger
verify(mockFlutterPluginBinding).applicationContext
verifyNoMoreInteractions(mockFlutterPluginBinding)

assertNull(plugin.pluginApi, "The plugin API be null after the detach")
}

@Test
fun `setActivityPluginBinding updates ActivityPluginBinding reference correctly`() {
plugin.pluginApi = mockPluginApi

assertNotNull(plugin.pluginApi, "The plugin API expected to be not null")
assertNull(plugin.activityPluginBinding, "The activity plugin binding is null initially")

val input = mock<ActivityPluginBinding>()

plugin.setActivityPluginBinding(input, "Any")

assertNotNull(plugin.activityPluginBinding)
assertEquals(input, plugin.activityPluginBinding)

verify(mockPluginApi).setActivityPluginBinding(input)
verifyNoMoreInteractions(mockPluginApi)
}

@Test
fun `disposeActivityPluginBinding updates ActivityPluginBinding reference to null`() {
plugin.pluginApi = mockPluginApi

assertNotNull(plugin.pluginApi, "The plugin API expected to be not null")
assertNull(plugin.activityPluginBinding, "The activity plugin binding is null initially")

plugin.setActivityPluginBinding(mock(), "Any")
assertNotNull(plugin.activityPluginBinding)

verify(mockPluginApi).setActivityPluginBinding(any())

plugin.disposeActivityPluginBinding("Any")

assertNull(plugin.activityPluginBinding)

verify(mockPluginApi).setActivityPluginBinding(null)
verifyNoMoreInteractions(mockPluginApi)
}

@Test
fun `onAttachedToActivity updates ActivityPluginBinding reference correctly`() {
plugin.pluginApi = mockPluginApi

val input = mock<ActivityPluginBinding>()

plugin.onAttachedToActivity(input)

assertNotNull(plugin.activityPluginBinding)
assertEquals(input, plugin.activityPluginBinding)
}

@Test
fun `onDetachedFromActivityForConfigChanges updates ActivityPluginBinding reference to null`() {
plugin.activityPluginBinding = mock()

assertNotNull(plugin.activityPluginBinding)

plugin.pluginApi = mockPluginApi

plugin.onDetachedFromActivityForConfigChanges()

assertNull(plugin.activityPluginBinding)
}

@Test
fun `onReattachedToActivityForConfigChanges updates ActivityPluginBinding reference correctly`() {
plugin.pluginApi = mockPluginApi

val input = mock<ActivityPluginBinding>()

plugin.onReattachedToActivityForConfigChanges(input)

assertNotNull(plugin.activityPluginBinding)
assertEquals(input, plugin.activityPluginBinding)
}

@Test
fun `onDetachedFromActivity updates ActivityPluginBinding reference to null`() {
plugin.activityPluginBinding = mock()

assertNotNull(plugin.activityPluginBinding)

plugin.pluginApi = mockPluginApi

plugin.onDetachedFromActivity()

assertNull(plugin.activityPluginBinding)
}
}
2 changes: 1 addition & 1 deletion quill_native_bridge_android/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: quill_native_bridge_android
description: "Android implementation of the quill_native_bridge plugin."
version: 0.0.1+1
version: 0.0.1+2
homepage: https://github.com/FlutterQuill/quill-native-bridge/tree/main/quill_native_bridge_android
repository: https://github.com/FlutterQuill/quill-native-bridge/tree/main/quill_native_bridge_android
issue_tracker: https://github.com/FlutterQuill/quill-native-bridge/issues?q=is%3Aissue+is%3Aopen+label%3A%22platform-android%22
Expand Down

0 comments on commit 5df2e0d

Please sign in to comment.