1 /*
2  * Copyright 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.systemui.education.data.repository
18 
19 import android.content.Context
20 import androidx.test.ext.junit.runners.AndroidJUnit4
21 import androidx.test.filters.SmallTest
22 import com.android.systemui.SysuiTestCase
23 import com.android.systemui.SysuiTestableContext
24 import com.android.systemui.contextualeducation.GestureType.BACK
25 import com.android.systemui.coroutines.collectLastValue
26 import com.android.systemui.education.data.model.EduDeviceConnectionTime
27 import com.android.systemui.education.data.model.GestureEduModel
28 import com.android.systemui.education.domain.interactor.mockEduInputManager
29 import com.android.systemui.kosmos.Kosmos
30 import com.android.systemui.kosmos.testDispatcher
31 import com.android.systemui.kosmos.testScope
32 import com.google.common.truth.Truth.assertThat
33 import java.io.File
34 import javax.inject.Provider
35 import kotlinx.coroutines.CoroutineScope
36 import kotlinx.coroutines.test.TestScope
37 import kotlinx.coroutines.test.runTest
38 import org.junit.Before
39 import org.junit.Rule
40 import org.junit.Test
41 import org.junit.rules.TemporaryFolder
42 import org.junit.runner.RunWith
43 
44 @SmallTest
45 @RunWith(AndroidJUnit4::class)
46 class ContextualEducationRepositoryTest : SysuiTestCase() {
47 
48     private lateinit var underTest: UserContextualEducationRepository
49     private val kosmos = Kosmos()
50     private val testScope = kosmos.testScope
<lambda>null51     private val dsScopeProvider: Provider<CoroutineScope> = Provider {
52         TestScope(kosmos.testDispatcher).backgroundScope
53     }
54 
55     private val testUserId = 1111
56     private val secondTestUserId = 1112
57 
58     // For deleting any test files created after the test
59     @get:Rule val tmpFolder: TemporaryFolder = TemporaryFolder.builder().assureDeletion().build()
60 
61     @Before
setUpnull62     fun setUp() {
63         // Create TestContext here because TemporaryFolder.create() is called in @Before. It is
64         // needed before calling TemporaryFolder.newFolder().
65         val testContext = TestContext(context, tmpFolder.newFolder())
66         underTest =
67             UserContextualEducationRepository(
68                 testContext,
69                 dsScopeProvider,
70                 kosmos.mockEduInputManager,
71                 kosmos.testDispatcher
72             )
73         underTest.setUser(testUserId)
74     }
75 
76     @Test
changeRetrievedValueForNewUsernull77     fun changeRetrievedValueForNewUser() =
78         testScope.runTest {
79             // Update data for old user.
80             underTest.updateGestureEduModel(BACK) { it.copy(signalCount = 1) }
81             val model by collectLastValue(underTest.readGestureEduModelFlow(BACK))
82             assertThat(model?.signalCount).isEqualTo(1)
83 
84             // User is changed.
85             underTest.setUser(secondTestUserId)
86             // Assert count is 0 after user is changed.
87             assertThat(model?.signalCount).isEqualTo(0)
88         }
89 
90     @Test
changeUserIdForNewUsernull91     fun changeUserIdForNewUser() =
92         testScope.runTest {
93             val model by collectLastValue(underTest.readGestureEduModelFlow(BACK))
94             assertThat(model?.userId).isEqualTo(testUserId)
95             underTest.setUser(secondTestUserId)
96             assertThat(model?.userId).isEqualTo(secondTestUserId)
97         }
98 
99     @Test
dataChangedOnUpdatenull100     fun dataChangedOnUpdate() =
101         testScope.runTest {
102             val newModel =
103                 GestureEduModel(
104                     signalCount = 2,
105                     educationShownCount = 1,
106                     lastShortcutTriggeredTime = kosmos.fakeEduClock.instant(),
107                     lastEducationTime = kosmos.fakeEduClock.instant(),
108                     usageSessionStartTime = kosmos.fakeEduClock.instant(),
109                     userId = testUserId,
110                     gestureType = BACK
111                 )
112             underTest.updateGestureEduModel(BACK) { newModel }
113             val model by collectLastValue(underTest.readGestureEduModelFlow(BACK))
114             assertThat(model).isEqualTo(newModel)
115         }
116 
117     @Test
eduDeviceConnectionTimeDataChangedOnUpdatenull118     fun eduDeviceConnectionTimeDataChangedOnUpdate() =
119         testScope.runTest {
120             val newModel =
121                 EduDeviceConnectionTime(
122                     keyboardFirstConnectionTime = kosmos.fakeEduClock.instant(),
123                     touchpadFirstConnectionTime = kosmos.fakeEduClock.instant(),
124                 )
125             underTest.updateEduDeviceConnectionTime { newModel }
126             val model by collectLastValue(underTest.readEduDeviceConnectionTime())
127             assertThat(model).isEqualTo(newModel)
128         }
129 
130     /** Test context which allows overriding getFilesDir path */
131     private class TestContext(context: Context, private val folder: File) :
132         SysuiTestableContext(context) {
getFilesDirnull133         override fun getFilesDir(): File {
134             return folder
135         }
136     }
137 }
138