@@ -19,18 +19,21 @@ package com.google.firebase.ai.type
19
19
import android.Manifest
20
20
import android.content.Context
21
21
import android.content.pm.PackageManager
22
+ import android.os.Build
22
23
import com.google.firebase.ai.common.PermissionMissingException
23
24
import io.ktor.client.plugins.websocket.ClientWebSocketSession
24
25
import kotlin.coroutines.CoroutineContext
25
26
import kotlinx.coroutines.ExperimentalCoroutinesApi
26
27
import kotlinx.coroutines.test.UnconfinedTestDispatcher
27
28
import kotlinx.coroutines.test.runTest
29
+ import org.junit.After
28
30
import org.junit.Assert.assertEquals
29
31
import org.junit.Assert.assertThrows
30
32
import org.junit.Before
31
33
import org.junit.Test
32
34
import org.junit.runner.RunWith
33
35
import org.mockito.Mock
36
+ import org.mockito.MockedStatic
34
37
import org.mockito.Mockito.mockStatic
35
38
import org.mockito.Mockito.`when`
36
39
import org.mockito.junit.MockitoJUnitRunner
@@ -44,25 +47,39 @@ class LiveSessionTest {
44
47
@Mock private lateinit var mockSession: ClientWebSocketSession
45
48
@Mock private lateinit var mockAudioHelper: AudioHelper
46
49
50
+ private lateinit var mockedBuildVersion: MockedStatic <Build .VERSION >
47
51
private lateinit var testDispatcher: CoroutineContext
48
52
private lateinit var liveSession: LiveSession
49
53
50
54
@Before
51
55
fun setUp () {
52
56
testDispatcher = UnconfinedTestDispatcher ()
53
57
`when `(mockContext.packageManager).thenReturn(mockPackageManager)
58
+ mockedBuildVersion = mockStatic(Build .VERSION ::class .java)
54
59
55
60
// Mock AudioHelper.build() to return our mockAudioHelper
56
61
// Need to use mockStatic for static methods
57
- mockStatic(AudioHelper ::class .java).use { mockedAudioHelper ->
58
- mockedAudioHelper.`when `<AudioHelper > { AudioHelper .build() }.thenReturn(mockAudioHelper)
62
+ // Note: It's generally better to manage static mocks with try-with-resources or @ExtendWith if
63
+ // the runner supports it well, but for this structure, @Before/@After is common.
64
+ // AudioHelper static mock is managed with try-with-resources where it's used for instance
65
+ // creation.
66
+ mockStatic(AudioHelper ::class .java).use { mockedAudioHelperStatic ->
67
+ mockedAudioHelperStatic
68
+ .`when `<AudioHelper > { AudioHelper .build() }
69
+ .thenReturn(mockAudioHelper)
59
70
liveSession = LiveSession (mockContext, mockSession, testDispatcher, null )
60
71
}
61
72
}
62
73
74
+ @After
75
+ fun tearDown () {
76
+ mockedBuildVersion.close()
77
+ }
78
+
63
79
@Test
64
- fun `startAudioConversation with RECORD_AUDIO permission proceeds normally` () = runTest {
80
+ fun `startAudioConversation on API M+ with permission proceeds normally` () = runTest {
65
81
// Arrange
82
+ mockedBuildVersion.`when ` { Build .VERSION .SDK_INT }.thenReturn(Build .VERSION_CODES .M )
66
83
`when `(mockContext.checkSelfPermission(Manifest .permission.RECORD_AUDIO ))
67
84
.thenReturn(PackageManager .PERMISSION_GRANTED )
68
85
@@ -72,9 +89,10 @@ class LiveSessionTest {
72
89
}
73
90
74
91
@Test
75
- fun `startAudioConversation without RECORD_AUDIO permission throws PermissionMissingException` () =
92
+ fun `startAudioConversation on API M+ without permission throws PermissionMissingException` () =
76
93
runTest {
77
94
// Arrange
95
+ mockedBuildVersion.`when ` { Build .VERSION .SDK_INT }.thenReturn(Build .VERSION_CODES .M )
78
96
`when `(mockContext.checkSelfPermission(Manifest .permission.RECORD_AUDIO ))
79
97
.thenReturn(PackageManager .PERMISSION_DENIED )
80
98
@@ -85,4 +103,28 @@ class LiveSessionTest {
85
103
}
86
104
assertEquals(" Missing RECORD_AUDIO" , exception.message)
87
105
}
106
+
107
+ @Test
108
+ fun `startAudioConversation on API Pre-M with denied permission proceeds normally` () = runTest {
109
+ // Arrange
110
+ mockedBuildVersion.`when ` { Build .VERSION .SDK_INT }.thenReturn(Build .VERSION_CODES .LOLLIPOP )
111
+ `when `(mockContext.checkSelfPermission(Manifest .permission.RECORD_AUDIO ))
112
+ .thenReturn(PackageManager .PERMISSION_DENIED ) // This shouldn't be checked
113
+
114
+ // Act & Assert
115
+ // No exception should be thrown
116
+ liveSession.startAudioConversation()
117
+ }
118
+
119
+ @Test
120
+ fun `startAudioConversation on API Pre-M with granted permission proceeds normally` () = runTest {
121
+ // Arrange
122
+ mockedBuildVersion.`when ` { Build .VERSION .SDK_INT }.thenReturn(Build .VERSION_CODES .LOLLIPOP )
123
+ `when `(mockContext.checkSelfPermission(Manifest .permission.RECORD_AUDIO ))
124
+ .thenReturn(PackageManager .PERMISSION_GRANTED ) // This shouldn't be checked
125
+
126
+ // Act & Assert
127
+ // No exception should be thrown
128
+ liveSession.startAudioConversation()
129
+ }
88
130
}
0 commit comments