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