1 /*
2  * Copyright (C) 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.multiuser.widget.tests.unit.domain
18 
19 import android.content.Context
20 import androidx.room.Room
21 import androidx.test.core.app.ApplicationProvider
22 import androidx.test.ext.junit.runners.AndroidJUnit4
23 import com.android.multiuser.widget.tests.R
24 import com.android.multiuser.widget.data.ActionsRepository
25 import com.android.multiuser.widget.data.UserDao
26 import com.android.multiuser.widget.data.UsersDatabase
27 import com.android.multiuser.widget.data.model.User
28 import com.android.multiuser.widget.domain.LoadUsersUseCase
29 import com.android.multiuser.widget.util.SHOULD_DISPLAY_ADD_USER_BUTTON
30 import com.android.multiuser.widget.viewmodel.ActionViewModel
31 import com.android.multiuser.widget.viewmodel.UserViewModel
32 import java.io.IOException
33 import java.util.concurrent.CountDownLatch
34 import kotlin.test.assertContains
35 import kotlin.test.assertEquals
36 import kotlin.test.assertFalse
37 import kotlinx.coroutines.Dispatchers
38 import kotlinx.coroutines.async
39 import kotlinx.coroutines.cancelAndJoin
40 import kotlinx.coroutines.flow.first
41 import kotlinx.coroutines.runBlocking
42 import org.junit.After
43 import org.junit.Before
44 import org.junit.Test
45 import org.junit.runner.RunWith
46 
47 @RunWith(AndroidJUnit4::class)
48 class LoadUsersUseCaseTest {
49     private lateinit var database: UsersDatabase
50     private lateinit var userDao: UserDao
51     private lateinit var loadUsersUseCase: LoadUsersUseCase
52     private lateinit var actionsRepository: ActionsRepository
53     private val addUserActionViewModel = ActionViewModel (
54         resourceId = R.drawable.person_add,
55         title = "Add user",
56         contentDescription = "Add user",
57     )
58 
59     @Before
setUpnull60     fun setUp() {
61         val context = ApplicationProvider.getApplicationContext<Context>()
62         actionsRepository = ActionsRepository(context)
63         database = Room.inMemoryDatabaseBuilder(context, UsersDatabase::class.java).build()
64         userDao = database.getUserDao()
65         loadUsersUseCase =
66             LoadUsersUseCase(userDao = userDao, actionsRepository = actionsRepository)
67     }
68 
69     @After
70     @Throws(IOException::class)
closeDatabasenull71     fun closeDatabase() {
72         database.close()
73     }
74 
75     @Test
<lambda>null76     fun loadUsersModel_mapsUserToUserViewModel() = runBlocking {
77         val fakeUser1 = User(
78             id = 0,
79             name = "fake_user_name_1",
80             creationTime = 0,
81             iconPath = "fake_icon_path_1",
82             isCurrentUser = true,
83             isAdmin = false,
84         )
85         val fakeUser2 = User(
86             id = 1,
87             name = "fake_user_name_2",
88             creationTime = 1,
89             iconPath = "fake_icon_path_2",
90             isCurrentUser = false,
91             isAdmin = true,
92         )
93         userDao.addUsers(fakeUser1)
94         userDao.addUsers(fakeUser2)
95 
96         val expectedUserViewModel1 = UserViewModel(
97             iconPath = "fake_icon_path_1",
98             id = 0,
99             name = "fake_user_name_1",
100             contentDescription = null,
101             isSelected = true,
102         )
103         val expectedUserViewModel2 = UserViewModel(
104             iconPath = "fake_icon_path_2",
105             id = 1,
106             name = "fake_user_name_2",
107             contentDescription = null,
108             isSelected = false,
109         )
110 
111         val latch = CountDownLatch(1)
112         val job = async(Dispatchers.IO) {
113             val model = loadUsersUseCase().first()
114             assertEquals(model.users.size, 2)
115             assertContains(model.users, expectedUserViewModel1)
116             assertContains(model.users, expectedUserViewModel2)
117             latch.countDown()
118         }
119 
120         latch.await()
121         job.cancelAndJoin()
122     }
123 
124     @Test
<lambda>null125     fun currentUserIsAdminAndAddUserButtonFlagIsSet_viewmodelIncludesAddUserButton() = runBlocking {
126         val fakeUser = User(
127             id = 0,
128             name = "fake_user_name",
129             creationTime = 0,
130             iconPath = "fake_icon_path",
131             isCurrentUser = true,
132             isAdmin = true,
133         )
134         userDao.addUsers(fakeUser)
135         SHOULD_DISPLAY_ADD_USER_BUTTON = true
136 
137         val latch = CountDownLatch(1)
138         val job = async(Dispatchers.IO) {
139             val model = loadUsersUseCase().first()
140             assertEquals(model.actions.size, 1)
141             assertContains(model.actions, addUserActionViewModel)
142             latch.countDown()
143         }
144 
145         latch.await()
146         job.cancelAndJoin()
147     }
148 
149     @Test
currentUserIsAdminAndAddUserButtonFlagIsNotSet_viewmodelDoesNotIncludeAddUserButtonnull150     fun currentUserIsAdminAndAddUserButtonFlagIsNotSet_viewmodelDoesNotIncludeAddUserButton()
151         = runBlocking {
152         val fakeUser = User(
153             id = 0,
154             name = "fake_user_name",
155             creationTime = 0,
156             iconPath = "fake_icon_path",
157             isCurrentUser = true,
158             isAdmin = true,
159         )
160         userDao.addUsers(fakeUser)
161         SHOULD_DISPLAY_ADD_USER_BUTTON = false
162 
163         val latch = CountDownLatch(1)
164         val job = async(Dispatchers.IO) {
165             val model = loadUsersUseCase().first()
166             assertFalse(model.actions.contains(addUserActionViewModel))
167             latch.countDown()
168         }
169 
170         latch.await()
171         job.cancelAndJoin()
172     }
173 
174     @Test
<lambda>null175     fun currentUserIsNotAdmin_viewmodelDoesNotIncludeAddUserButton() = runBlocking {
176         val fakeUser = User(
177             id = 0,
178             name = "fake_user_name",
179             creationTime = 0,
180             iconPath = "fake_icon_path",
181             isCurrentUser = true,
182             isAdmin = false,
183         )
184         userDao.addUsers(fakeUser)
185 
186         val latch = CountDownLatch(1)
187         val job = async(Dispatchers.IO) {
188             val model = loadUsersUseCase().first()
189             assertFalse(model.actions.contains(addUserActionViewModel))
190             latch.countDown()
191         }
192 
193         latch.await()
194         job.cancelAndJoin()
195     }
196 }
197