Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion ChatApp/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,6 @@ dependencies {

// App functions
implementation(libs.androidx.appfunctions)
implementation(libs.androidx.appfunctions.service)
ksp(libs.androidx.appfunctions.compiler)

testImplementation(libs.junit)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ class AppFunctionsViewModelTest {
fun toggleFunction_doesNotCrash() =
runTest {
// Use a potentially real ID from the app
Comment thread
keyboardsurfer marked this conversation as resolved.
viewModel.toggleFunction("com.example.chatapp.appfunctions.AppFunctions#searchContacts", true)
viewModel.toggleFunction(com.example.chatapp.appfunctions.AppFunctionsIds.SEARCH_CONTACTS_ID, true)
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,6 @@ class AppFunctionInstrumentationTest {

@Inject lateinit var recipientsRepository: RecipientsRepository

@Inject lateinit var appFunctions: AppFunctions

private val context: Context = ApplicationProvider.getApplicationContext()
private val appFunctionManager: AppFunctionManager =
checkNotNull(AppFunctionManager.getInstance(context))
Expand Down Expand Up @@ -164,10 +162,10 @@ class AppFunctionInstrumentationTest {
.getAppFunctionDataList(
ExecuteAppFunctionResponse.Success.PROPERTY_RETURN_VALUE,
)
?.map { it.deserialize(AppFunctions.ContactSearchResult::class.java) },
?.map { it.deserialize(ContactSearchResult::class.java) },
)
.containsExactly(
AppFunctions.ContactSearchResult(endpointValue = "1", endpointType = "INDIVIDUAL", displayName = "Alice Smith"),
ContactSearchResult(endpointValue = "1", endpointType = "INDIVIDUAL", displayName = "Alice Smith"),
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ package com.example.chatapp.appfunctions
import android.content.Context
import android.net.Uri
import androidx.appfunctions.AppFunctionAppUnknownException
import androidx.appfunctions.AppFunctionContext
import androidx.appfunctions.AppFunctionElementNotFoundException
import androidx.appfunctions.AppFunctionInvalidArgumentException
import androidx.test.core.app.ApplicationProvider
Expand All @@ -38,12 +37,6 @@ import org.junit.runner.RunWith

@RunWith(AndroidJUnit4::class)
class AppFunctionsTest {
private val testContext =
object : AppFunctionContext {
override val context: Context
get() = ApplicationProvider.getApplicationContext()
}

private class MockMessageRepository : MessageRepository {
var shouldFail = false
private val messages = MutableStateFlow<Map<String, List<DisplayMessage>>>(emptyMap())
Expand Down Expand Up @@ -85,19 +78,47 @@ class AppFunctionsTest {

private val callManager = CallManager(recipientsRepository)

private val appFunctions = AppFunctions(messageRepository, recipientsRepository, callManager)
private class TestChatAppFunctionService(
val testContext: Context,
messageRepo: MessageRepository,
recipientsRepo: RecipientsRepository,
callMgr: CallManager,
) : BaseChatAppFunctionService() {
init {
Comment thread
keyboardsurfer marked this conversation as resolved.
Outdated
attachBaseContext(testContext)
this.messageRepository = messageRepo
this.recipientsRepository = recipientsRepo
this.callManager = callMgr
}

override fun onExecuteFunction(
request: androidx.appfunctions.ExecuteAppFunctionRequest,
cancellationSignal: android.os.CancellationSignal,
callback: java.util.function.Consumer<androidx.appfunctions.ExecuteAppFunctionResponse>,
) {
// Not used in direct unit tests
}
}

private val appFunctions =
TestChatAppFunctionService(
ApplicationProvider.getApplicationContext(),
messageRepository,
recipientsRepository,
callManager,
)

@Test(expected = AppFunctionInvalidArgumentException::class)
fun searchContacts_returnsEmptyList() {
runBlocking {
appFunctions.searchContacts(testContext, "nonexistent", "INDIVIDUAL")
appFunctions.searchContacts("nonexistent", "INDIVIDUAL")
}
}

@Test
fun searchContacts_returnsMatches() {
runBlocking {
val contacts = appFunctions.searchContacts(testContext, "Alice", "INDIVIDUAL")
val contacts = appFunctions.searchContacts("Alice", "INDIVIDUAL")
Assert.assertEquals(1, contacts.size)
Assert.assertEquals("Alice Smith", contacts[0].displayName)
}
Expand All @@ -106,7 +127,7 @@ class AppFunctionsTest {
@Test
fun searchContacts_groups_returnsMatches() {
runBlocking {
val contacts = appFunctions.searchContacts(testContext, "Work", "GROUP")
val contacts = appFunctions.searchContacts("Work", "GROUP")
Assert.assertEquals(1, contacts.size)
Assert.assertEquals("Work Friends", contacts[0].displayName)
}
Expand All @@ -115,16 +136,15 @@ class AppFunctionsTest {
@Test
fun searchContacts_emptyQuery_returnsRecent() {
runBlocking {
val contacts = appFunctions.searchContacts(testContext, "", "INDIVIDUAL")
val contacts = appFunctions.searchContacts("", "INDIVIDUAL")
Assert.assertEquals(3, contacts.size)
}
}

@Test
fun searchContacts_anyType_returnsMatches() {
runBlocking {
// "searchAny" branch (when filterType is not INDIVIDUAL or GROUP)
val contacts = appFunctions.searchContacts(testContext, "Alice", "ANY")
val contacts = appFunctions.searchContacts("Alice", "ANY")
Assert.assertEquals(1, contacts.size)
Assert.assertEquals("Alice Smith", contacts[0].displayName)
}
Expand All @@ -133,9 +153,9 @@ class AppFunctionsTest {
@Test
fun send_validMessage_returnsSuccess() {
runTest {
val result = appFunctions.send(testContext, "1", "Hello")
val result = appFunctions.send("1", "Hello")
Assert.assertEquals(
AppFunctions.Result(
Result(
"Message ID",
"Message sent to: Alice Smith.",
),
Expand All @@ -149,13 +169,12 @@ class AppFunctionsTest {
runTest {
val result =
appFunctions.send(
testContext,
"1",
"Hello",
listOf(Uri.parse("content://media/1")),
)
Assert.assertEquals(
AppFunctions.Result(
Result(
"Message ID",
"Message sent to: Alice Smith.",
),
Expand All @@ -167,9 +186,9 @@ class AppFunctionsTest {
@Test
fun send_toGroup_success() {
runTest {
val result = appFunctions.send(testContext, "g1", "Hello")
val result = appFunctions.send("g1", "Hello")
Assert.assertEquals(
AppFunctions.Result(
Result(
"Message ID",
"Message sent to: Work Friends.",
),
Expand All @@ -181,39 +200,37 @@ class AppFunctionsTest {
@Test(expected = AppFunctionInvalidArgumentException::class)
fun send_emptyContent_fails() {
runTest {
appFunctions.send(testContext, "1", "")
appFunctions.send("1", "")
}
}

@Test(expected = AppFunctionElementNotFoundException::class)
fun send_invalidRecipient_fails() {
runTest {
appFunctions.send(testContext, "nonexistent_id", "Hello")
appFunctions.send("nonexistent_id", "Hello")
}
}

@Test(expected = AppFunctionAppUnknownException::class)
fun send_repositoryError_returnsError() {
runTest {
messageRepository.shouldFail = true
appFunctions.send(testContext, "1", "Hello")
appFunctions.send("1", "Hello")
}
}

@Test
fun makeCall_returnsPendingIntent() {
runBlocking {
val pendingIntent = appFunctions.makeCall(testContext, endpointValue = "1")
val pendingIntent = appFunctions.makeCall(endpointValue = "1")
Assert.assertNotNull(pendingIntent)
}
}


@Test(expected = AppFunctionElementNotFoundException::class)
fun makeCall_invalidEndpointValue_fails() {
runBlocking {
appFunctions.makeCall(testContext, endpointValue = "nonexistent_id")
appFunctions.makeCall(endpointValue = "nonexistent_id")
}
}

}
18 changes: 17 additions & 1 deletion ChatApp/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
-->

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:appfn="http://schemas.android.com/apk/androidx.appfunctions">
xmlns:appfn="http://schemas.android.com/apk/androidx.appfunctions"
xmlns:tools="http://schemas.android.com/tools">

<application
android:name=".ChatApplication"
Expand Down Expand Up @@ -49,6 +50,21 @@
android:host="com.example.chatapp" />
</intent-filter>
</activity>
<service
android:name="com.example.chatapp.appfunctions.ChatAppFunctionService"
android:permission="android.permission.BIND_APP_FUNCTION_SERVICE"
android:exported="true"
tools:targetApi="36">
<property
android:name="android.app.appfunctions.schema"
android:value="app_functions_schema.xsd" />
<property
android:name="android.app.appfunctions.v2"
android:value="chat_app_function_service.xml" />
<intent-filter>
<action android:name="android.app.appfunctions.AppFunctionService" />
</intent-filter>
</service>
<property
android:name="android.app.appfunctions.app_metadata"
android:resource="@xml/app_metadata" />
Expand Down

This file was deleted.

Loading