1 /*
2 * Copyright (C) 2025 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 package com.android.documentsui.ui
17
18 import android.content.Context
19 import android.content.res.Resources
20 import android.net.Uri
21 import android.provider.DocumentsContract.Document.MIME_TYPE_DIR
22 import androidx.test.filters.SmallTest
23 import com.android.documentsui.OperationDialogFragment.DIALOG_TYPE_CONVERTED
24 import com.android.documentsui.OperationDialogFragment.DIALOG_TYPE_FAILURE
25 import com.android.documentsui.R
26 import com.android.documentsui.base.DocumentInfo
27 import com.android.documentsui.services.FileOperationService.OPERATION_COMPRESS
28 import com.android.documentsui.services.FileOperationService.OPERATION_COPY
29 import com.android.documentsui.services.FileOperationService.OPERATION_DELETE
30 import com.android.documentsui.services.FileOperationService.OPERATION_EXTRACT
31 import com.android.documentsui.services.FileOperationService.OPERATION_MOVE
32 import com.android.documentsui.services.FileOperationService.OPERATION_UNKNOWN
33 import org.junit.Assert.assertEquals
34 import org.junit.Before
35 import org.junit.Test
36 import org.junit.runner.RunWith
37 import org.junit.runners.Parameterized
38 import org.junit.runners.Suite
39 import org.junit.runners.Suite.SuiteClasses
40 import org.mockito.ArgumentMatchers.anyString
41 import org.mockito.Mock
42 import org.mockito.Mockito.eq
43 import org.mockito.Mockito.`when` as whenever
44 import org.mockito.MockitoAnnotations
45
46 @SmallTest
47 @RunWith(Suite::class)
48 @SuiteClasses(
49 MessageBuilderTest.GenerateDeleteMessage::class,
50 MessageBuilderTest.GenerateListMessage::class
51 )
52 open class MessageBuilderTest() {
53 companion object {
54 const val EXPECTED_MESSAGE = "Delete message"
55 }
56
57 class GenerateDeleteMessage() {
58 private lateinit var messageBuilder: MessageBuilder
59
60 @Mock
61 private lateinit var resources: Resources
62
63 @Mock
64 private lateinit var context: Context
65
66 @Before
setUpnull67 fun setUp() {
68 MockitoAnnotations.openMocks(this)
69 whenever(context.resources).thenReturn(resources)
70 messageBuilder = MessageBuilder(context)
71 }
72
assertDeleteMessagenull73 private fun assertDeleteMessage(docInfo: DocumentInfo, resId: Int) {
74 whenever(
75 resources.getString(
76 eq(resId),
77 eq(docInfo.displayName)
78 )
79 ).thenReturn(EXPECTED_MESSAGE)
80 assertEquals(messageBuilder.generateDeleteMessage(listOf(docInfo)), EXPECTED_MESSAGE)
81 }
82
assertQuantityDeleteMessagenull83 private fun assertQuantityDeleteMessage(docInfos: List<DocumentInfo>, resId: Int) {
84 whenever(
85 resources.getQuantityString(
86 eq(resId),
87 eq(docInfos.size),
88 eq(docInfos.size)
89 )
90 ).thenReturn(EXPECTED_MESSAGE)
91 assertEquals(messageBuilder.generateDeleteMessage(docInfos), EXPECTED_MESSAGE)
92 }
93
94 @Test
testGenerateDeleteMessage_singleFilenull95 fun testGenerateDeleteMessage_singleFile() {
96 assertDeleteMessage(
97 createFile("Test doc"),
98 R.string.delete_filename_confirmation_message
99 )
100 }
101
102 @Test
testGenerateDeleteMessage_singleDirectorynull103 fun testGenerateDeleteMessage_singleDirectory() {
104 assertDeleteMessage(
105 createDirectory("Test doc"),
106 R.string.delete_foldername_confirmation_message
107 )
108 }
109
110 @Test
testGenerateDeleteMessage_multipleFilesnull111 fun testGenerateDeleteMessage_multipleFiles() {
112 assertQuantityDeleteMessage(
113 listOf(createFile("File 1"), createFile("File 2")),
114 R.plurals.delete_files_confirmation_message
115 )
116 }
117
118 @Test
testGenerateDeleteMessage_multipleDirectoriesnull119 fun testGenerateDeleteMessage_multipleDirectories() {
120 assertQuantityDeleteMessage(
121 listOf(
122 createDirectory("Directory 1"),
123 createDirectory("Directory 2")
124 ),
125 R.plurals.delete_folders_confirmation_message
126 )
127 }
128
129 @Test
testGenerateDeleteMessage_mixedFilesAndDirectoriesnull130 fun testGenerateDeleteMessage_mixedFilesAndDirectories() {
131 assertQuantityDeleteMessage(
132 listOf(createFile("File 1"), createDirectory("Directory 1")),
133 R.plurals.delete_items_confirmation_message
134 )
135 }
136 }
137
138 @RunWith(Parameterized::class)
139 class GenerateListMessage() {
140 private lateinit var messageBuilder: MessageBuilder
141
142 @Mock
143 private lateinit var resources: Resources
144
145 @Mock
146 private lateinit var context: Context
147
148 @Before
setUpnull149 fun setUp() {
150 MockitoAnnotations.openMocks(this)
151 whenever(context.resources).thenReturn(resources)
152 messageBuilder = MessageBuilder(context)
153 }
154
155 data class ListMessageData(
156 val dialogType: Int,
157 val opType: Int = OPERATION_UNKNOWN,
158 val resId: Int
159 )
160
161 companion object {
162 @Parameterized.Parameters(name = "{0}")
163 @JvmStatic
parametersnull164 fun parameters() =
165 listOf(
166 ListMessageData(
167 dialogType = DIALOG_TYPE_CONVERTED,
168 resId = R.plurals.copy_converted_warning_content,
169 ),
170 ListMessageData(
171 dialogType = DIALOG_TYPE_FAILURE,
172 opType = OPERATION_COPY,
173 resId = R.plurals.copy_failure_alert_content,
174 ),
175 ListMessageData(
176 dialogType = DIALOG_TYPE_FAILURE,
177 opType = OPERATION_COMPRESS,
178 resId = R.plurals.compress_failure_alert_content,
179 ),
180 ListMessageData(
181 dialogType = DIALOG_TYPE_FAILURE,
182 opType = OPERATION_EXTRACT,
183 resId = R.plurals.extract_failure_alert_content,
184 ),
185 ListMessageData(
186 dialogType = DIALOG_TYPE_FAILURE,
187 opType = OPERATION_DELETE,
188 resId = R.plurals.delete_failure_alert_content,
189 ),
190 ListMessageData(
191 dialogType = DIALOG_TYPE_FAILURE,
192 opType = OPERATION_MOVE,
193 resId = R.plurals.move_failure_alert_content,
194 ),
195 )
196 }
197
198 @Parameterized.Parameter(0)
199 lateinit var testData: ListMessageData
200
201 @Test
202 fun testGenerateListMessage() {
203 whenever(
204 resources.getQuantityString(
205 eq(testData.resId),
206 eq(2),
207 anyString(),
208 )
209 ).thenReturn(EXPECTED_MESSAGE)
210 assertEquals(
211 messageBuilder.generateListMessage(
212 testData.dialogType,
213 testData.opType,
214 listOf(createFile("File 1")),
215 listOf(Uri.parse("content://random-uri")),
216 ),
217 EXPECTED_MESSAGE
218 )
219 }
220 }
221 }
222
createFilenull223 fun createFile(displayName: String): DocumentInfo {
224 val doc = DocumentInfo()
225 doc.displayName = displayName
226 return doc
227 }
228
createDirectorynull229 fun createDirectory(displayName: String): DocumentInfo {
230 val doc = DocumentInfo()
231 doc.displayName = displayName
232 doc.mimeType = MIME_TYPE_DIR
233 return doc
234 }
235