1 /*
2  * Copyright (C) 2019 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.controls.management
18 
19 import android.app.PendingIntent
20 import android.content.ComponentName
21 import android.service.controls.Control
22 import android.testing.AndroidTestingRunner
23 import androidx.test.filters.SmallTest
24 import com.android.systemui.SysuiTestCase
25 import com.android.systemui.controls.ControlStatus
26 import com.android.systemui.controls.controller.ControlInfo
27 import org.junit.Assert.assertEquals
28 import org.junit.Assert.assertFalse
29 import org.junit.Assert.assertTrue
30 import org.junit.Before
31 import org.junit.Test
32 import org.junit.runner.RunWith
33 import org.mockito.Mock
34 import org.mockito.Mockito.never
35 import org.mockito.Mockito.verify
36 import org.mockito.MockitoAnnotations
37 
38 @SmallTest
39 @RunWith(AndroidTestingRunner::class)
40 class AllModelTest : SysuiTestCase() {
41 
42     companion object {
43         private const val EMPTY_STRING = "Other"
44     }
45 
46     @Mock
47     lateinit var pendingIntent: PendingIntent
48     @Mock
49     lateinit var controlsModelCallback: ControlsModel.ControlsModelCallback
50 
51     val idPrefix = "controlId"
52     val favoritesIndices = listOf(7, 3, 1, 9)
53     val favoritesList = favoritesIndices.map { "controlId$it" }
54     lateinit var controls: List<ControlStatus>
55 
56     lateinit var model: AllModel
57 
58     private fun zoneMap(id: Int): String? {
59         return when (id) {
60             10 -> ""
61             11 -> null
62             else -> ((id + 1) % 3).toString()
63         }
64     }
65 
66     @Before
67     fun setUp() {
68         MockitoAnnotations.initMocks(this)
69 
70         // controlId0 --> zone = 1
71         // controlId1 --> zone = 2, favorite
72         // controlId2 --> zone = 0
73         // controlId3 --> zone = 1, favorite
74         // controlId4 --> zone = 2
75         // controlId5 --> zone = 0
76         // controlId6 --> zone = 1
77         // controlId7 --> zone = 2, favorite
78         // controlId8 --> zone = 0
79         // controlId9 --> zone = 1, favorite
80         // controlId10 --> zone = ""
81         // controlId11 --> zone = null
82         controls = (0..11).map {
83             ControlStatus(
84                     Control.StatelessBuilder("$idPrefix$it", pendingIntent)
85                             .setZone(zoneMap(it))
86                             .build(),
87                     ComponentName("", ""),
88                     it in favoritesIndices
89             )
90         }
91         model = AllModel(controls, favoritesList, EMPTY_STRING, controlsModelCallback)
92     }
93 
94     @Test
95     fun testElements() {
96 
97         // Zones are sorted by order of appearance, with empty at the end with special header.
98         val expected = listOf(
99                 ZoneNameWrapper("1"),
100                 ControlStatusWrapper(controls[0]),
101                 ControlStatusWrapper(controls[3]),
102                 ControlStatusWrapper(controls[6]),
103                 ControlStatusWrapper(controls[9]),
104                 ZoneNameWrapper("2"),
105                 ControlStatusWrapper(controls[1]),
106                 ControlStatusWrapper(controls[4]),
107                 ControlStatusWrapper(controls[7]),
108                 ZoneNameWrapper("0"),
109                 ControlStatusWrapper(controls[2]),
110                 ControlStatusWrapper(controls[5]),
111                 ControlStatusWrapper(controls[8]),
112                 ZoneNameWrapper(EMPTY_STRING),
113                 ControlStatusWrapper(controls[10]),
114                 ControlStatusWrapper(controls[11])
115         )
116         expected.zip(model.elements).forEachIndexed { index, it ->
117             assertEquals("Error in item at index $index", it.first, it.second)
118         }
119     }
120 
121     private fun sameControl(controlInfo: ControlInfo, control: Control): Boolean {
122         return controlInfo.controlId == control.controlId &&
123                 controlInfo.controlTitle == control.title &&
124                 controlInfo.controlSubtitle == control.subtitle &&
125                 controlInfo.deviceType == control.deviceType
126     }
127 
128     @Test
129     fun testAllEmpty_noHeader() {
130         val selected_controls = listOf(controls[10], controls[11])
131         val new_model = AllModel(selected_controls, emptyList(), EMPTY_STRING,
132                 controlsModelCallback)
133         val expected = listOf(
134                 ControlStatusWrapper(controls[10]),
135                 ControlStatusWrapper(controls[11])
136         )
137 
138         expected.zip(new_model.elements).forEachIndexed { index, it ->
139             assertEquals("Error in item at index $index", it.first, it.second)
140         }
141     }
142 
143     @Test
144     fun testFavorites() {
145         val expectedFavorites = favoritesIndices.map(controls::get).map(ControlStatus::control)
146         model.favorites.zip(expectedFavorites).forEach {
147             assertTrue(sameControl(it.first, it.second))
148         }
149     }
150 
151     @Test
152     fun testAddFavorite() {
153         val indexToAdd = 6
154         model.changeFavoriteStatus("$idPrefix$indexToAdd", true)
155 
156         val expectedFavorites = favoritesIndices.map(controls::get).map(ControlStatus::control) +
157                 controls[indexToAdd].control
158 
159         model.favorites.zip(expectedFavorites).forEach {
160             assertTrue(sameControl(it.first, it.second))
161         }
162 
163         verify(controlsModelCallback).onFirstChange()
164     }
165 
166     @Test
167     fun testAddFavorite_changesModelFlag() {
168         val indexToAdd = 6
169         val id = "$idPrefix$indexToAdd"
170         model.changeFavoriteStatus(id, true)
171         assertTrue(
172                 (model.elements.first {
173                     it is ControlStatusWrapper && it.controlStatus.control.controlId == id
174                 } as ControlStatusWrapper)
175                         .controlStatus.favorite
176         )
177 
178         verify(controlsModelCallback).onFirstChange()
179     }
180 
181     @Test
182     fun testAddFavorite_alreadyThere() {
183         val indexToAdd = 7
184         model.changeFavoriteStatus("$idPrefix$indexToAdd", true)
185 
186         val expectedFavorites = favoritesIndices.map(controls::get).map(ControlStatus::control)
187 
188         assertEquals(expectedFavorites.size, model.favorites.size)
189         model.favorites.zip(expectedFavorites).forEach {
190             assertTrue(sameControl(it.first, it.second))
191         }
192 
193         verify(controlsModelCallback, never()).onFirstChange()
194     }
195 
196     @Test
197     fun testRemoveFavorite() {
198         val indexToRemove = 3
199         model.changeFavoriteStatus("$idPrefix$indexToRemove", false)
200 
201         val expectedFavorites = (favoritesIndices.filterNot { it == indexToRemove })
202                 .map(controls::get)
203                 .map(ControlStatus::control)
204 
205         model.favorites.zip(expectedFavorites).forEach {
206             assertTrue(sameControl(it.first, it.second))
207         }
208 
209         verify(controlsModelCallback).onFirstChange()
210     }
211 
212     @Test
213     fun testRemoveFavorite_changesModelFlag() {
214         val indexToRemove = 3
215         val id = "$idPrefix$indexToRemove"
216         model.changeFavoriteStatus(id, false)
217         assertFalse(
218                 (model.elements.first {
219                     it is ControlStatusWrapper && it.controlStatus.control.controlId == id
220                 } as ControlStatusWrapper)
221                         .controlStatus.favorite
222         )
223 
224         verify(controlsModelCallback).onFirstChange()
225     }
226 
227     @Test
228     fun testRemoveFavorite_notThere() {
229         val indexToRemove = 4
230         model.changeFavoriteStatus("$idPrefix$indexToRemove", false)
231 
232         val expectedFavorites = favoritesIndices.map(controls::get).map(ControlStatus::control)
233 
234         model.favorites.zip(expectedFavorites).forEach {
235             assertTrue(sameControl(it.first, it.second))
236         }
237 
238         verify(controlsModelCallback, never()).onFirstChange()
239     }
240 }
241