1 /*
2  * Copyright 2022 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.bluetooth.opp;
18 
19 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
20 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
21 import static android.content.pm.PackageManager.DONT_KILL_APP;
22 
23 import static org.mockito.ArgumentMatchers.anyInt;
24 import static org.mockito.ArgumentMatchers.anyString;
25 import static org.mockito.Mockito.doAnswer;
26 import static org.mockito.Mockito.doReturn;
27 
28 import android.content.ComponentName;
29 import android.content.Context;
30 import android.database.Cursor;
31 
32 import org.mockito.internal.util.MockUtil;
33 
34 import java.util.List;
35 import java.util.Objects;
36 
37 public class BluetoothOppTestUtils {
38 
39     /**
40      * A class containing the data to be return by a cursor. Intended to be use with setUpMockCursor
41      *
42      * @attr columnName is name of column to be used as a parameter in cursor.getColumnIndexOrThrow
43      * @attr mIndex should be returned from cursor.getColumnIndexOrThrow
44      * @attr mValue should be returned from cursor.getInt() or cursor.getString() or
45      *     cursor.getLong()
46      */
47     public static class CursorMockData {
48         public final String mColumnName;
49         public final int mColumnIndex;
50         public final Object mValue;
51 
CursorMockData(String columnName, int index, Object value)52         public CursorMockData(String columnName, int index, Object value) {
53             mColumnName = columnName;
54             mColumnIndex = index;
55             mValue = value;
56         }
57     }
58 
59     /**
60      * Set up a mock single-row Cursor that work for common use cases in the OPP package. It mocks
61      * the database column index and value of the cell in that column of the current row
62      *
63      * <pre>
64      *  cursorMockDataList.add(
65      *     new CursorMockData(BluetoothShare.DIRECTION, 2, BluetoothShare.DIRECTION_INBOUND
66      *     );
67      *     ...
68      *  setUpMockCursor(cursor, cursorMockDataList);
69      *  // This will return 2
70      *  int index = cursor.getColumnIndexOrThrow(BluetoothShare.DIRECTION);
71      *  int direction = cursor.getInt(index); // This will return BluetoothShare.DIRECTION_INBOUND
72      * </pre>
73      *
74      * @param cursor a mock/spy cursor to be setup
75      * @param cursorMockDataList a list representing what cursor will return
76      */
setUpMockCursor(Cursor cursor, List<CursorMockData> cursorMockDataList)77     public static void setUpMockCursor(Cursor cursor, List<CursorMockData> cursorMockDataList) {
78         assert (MockUtil.isMock(cursor));
79 
80         doAnswer(
81                         invocation -> {
82                             String name = invocation.getArgument(0);
83                             return cursorMockDataList.stream()
84                                     .filter(
85                                             mockCursorData ->
86                                                     Objects.equals(
87                                                             mockCursorData.mColumnName, name))
88                                     .findFirst()
89                                     .orElse(new CursorMockData("", -1, null))
90                                     .mColumnIndex;
91                         })
92                 .when(cursor)
93                 .getColumnIndexOrThrow(anyString());
94 
95         doAnswer(
96                         invocation -> {
97                             int index = invocation.getArgument(0);
98                             return cursorMockDataList.stream()
99                                     .filter(mockCursorData -> mockCursorData.mColumnIndex == index)
100                                     .findFirst()
101                                     .orElse(new CursorMockData("", -1, -1))
102                                     .mValue;
103                         })
104                 .when(cursor)
105                 .getInt(anyInt());
106 
107         doAnswer(
108                         invocation -> {
109                             int index = invocation.getArgument(0);
110                             return cursorMockDataList.stream()
111                                     .filter(mockCursorData -> mockCursorData.mColumnIndex == index)
112                                     .findFirst()
113                                     .orElse(new CursorMockData("", -1, -1))
114                                     .mValue;
115                         })
116                 .when(cursor)
117                 .getLong(anyInt());
118 
119         doAnswer(
120                         invocation -> {
121                             int index = invocation.getArgument(0);
122                             return cursorMockDataList.stream()
123                                     .filter(mockCursorData -> mockCursorData.mColumnIndex == index)
124                                     .findFirst()
125                                     .orElse(new CursorMockData("", -1, null))
126                                     .mValue;
127                         })
128                 .when(cursor)
129                 .getString(anyInt());
130 
131         doReturn(true).when(cursor).moveToFirst();
132         doReturn(true).when(cursor).moveToLast();
133         doReturn(true).when(cursor).moveToNext();
134         doReturn(true).when(cursor).moveToPrevious();
135         doReturn(true).when(cursor).moveToPosition(anyInt());
136     }
137 
138     /**
139      * Enable/Disable an activity for testing
140      *
141      * @param activityClass the activity class to enable/disable
142      * @param enable true to enable, false to disable
143      * @param mTargetContext target context
144      */
enableActivity(Class activityClass, boolean enable, Context mTargetContext)145     public static void enableActivity(Class activityClass, boolean enable, Context mTargetContext) {
146         int enabledState =
147                 enable ? COMPONENT_ENABLED_STATE_ENABLED : COMPONENT_ENABLED_STATE_DEFAULT;
148 
149         mTargetContext
150                 .getPackageManager()
151                 .setApplicationEnabledSetting(
152                         mTargetContext.getPackageName(), enabledState, DONT_KILL_APP);
153 
154         ComponentName activityName = new ComponentName(mTargetContext, activityClass);
155         mTargetContext
156                 .getPackageManager()
157                 .setComponentEnabledSetting(activityName, enabledState, DONT_KILL_APP);
158     }
159 }
160