1 /* 2 * Copyright (C) 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 * use this file except in compliance with the License. You may obtain a copy of 6 * 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, WITHOUT 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 * License for the specific language governing permissions and limitations under 14 * the License. 15 */ 16 17 package android.content.cts; 18 19 import static android.content.ContentResolver.QUERY_ARG_SQL_SELECTION; 20 import static android.content.ContentResolver.QUERY_ARG_SQL_SELECTION_ARGS; 21 22 import static org.junit.Assert.assertEquals; 23 import static org.junit.Assert.assertTrue; 24 import static org.mockito.ArgumentMatchers.eq; 25 import static org.mockito.Mockito.mock; 26 import static org.mockito.Mockito.when; 27 28 import android.content.ContentProvider; 29 import android.content.ContentProviderOperation; 30 import android.content.ContentProviderResult; 31 import android.content.ContentValues; 32 import android.database.MatrixCursor; 33 import android.net.Uri; 34 import android.os.Bundle; 35 import android.platform.test.annotations.AppModeSdkSandbox; 36 37 import androidx.test.runner.AndroidJUnit4; 38 39 import org.junit.Before; 40 import org.junit.Test; 41 import org.junit.runner.RunWith; 42 import org.mockito.ArgumentMatchers; 43 44 import java.util.Objects; 45 46 @RunWith(AndroidJUnit4.class) 47 @AppModeSdkSandbox(reason = "Allow test in the SDK sandbox (does not prevent other modes).") 48 public class ContentProviderOperationTest { 49 private static final Uri TEST_URI = Uri.parse("content://com.example"); 50 private static final Uri TEST_URI_RESULT = Uri.parse("content://com.example/12"); 51 private static final String TEST_SELECTION = "foo=?"; 52 private static final String[] TEST_SELECTION_ARGS = new String[] { "bar" }; 53 private static final String TEST_METHOD = "test_method"; 54 private static final String TEST_ARG = "test_arg"; 55 56 private static final ContentValues TEST_VALUES = new ContentValues(); 57 private static final Bundle TEST_EXTRAS = new Bundle(); 58 private static final Bundle TEST_EXTRAS_WITH_SQL = new Bundle(); 59 private static final Bundle TEST_EXTRAS_RESULT = new Bundle(); 60 61 static { 62 TEST_VALUES.put("test_key", "test_value"); 63 64 TEST_EXTRAS.putString("test_key", "test_value"); 65 66 TEST_EXTRAS_WITH_SQL.putAll(TEST_EXTRAS); TEST_EXTRAS_WITH_SQL.putString(QUERY_ARG_SQL_SELECTION, TEST_SELECTION)67 TEST_EXTRAS_WITH_SQL.putString(QUERY_ARG_SQL_SELECTION, TEST_SELECTION); TEST_EXTRAS_WITH_SQL.putStringArray(QUERY_ARG_SQL_SELECTION_ARGS, TEST_SELECTION_ARGS)68 TEST_EXTRAS_WITH_SQL.putStringArray(QUERY_ARG_SQL_SELECTION_ARGS, TEST_SELECTION_ARGS); 69 70 TEST_EXTRAS_RESULT.putString("test_result", "42"); 71 } 72 73 private static final ContentProviderResult[] TEST_RESULTS = new ContentProviderResult[] { 74 new ContentProviderResult(TEST_URI_RESULT), 75 new ContentProviderResult(84), 76 new ContentProviderResult(TEST_EXTRAS_RESULT), 77 new ContentProviderResult(new IllegalArgumentException()), 78 }; 79 80 private ContentProvider provider; 81 82 private ContentProviderOperation op; 83 private ContentProviderResult res; 84 85 @Before setUp()86 public void setUp() throws Exception { 87 provider = mock(ContentProvider.class); 88 } 89 90 @Test testInsert()91 public void testInsert() throws Exception { 92 op = ContentProviderOperation.newInsert(TEST_URI) 93 .withValues(TEST_VALUES) 94 .withExtras(TEST_EXTRAS) 95 .build(); 96 97 assertEquals(TEST_URI, op.getUri()); 98 assertTrue(op.isInsert()); 99 assertTrue(op.isWriteOperation()); 100 101 when(provider.insert(eq(TEST_URI), eq(TEST_VALUES), eqBundle(TEST_EXTRAS))) 102 .thenReturn(TEST_URI_RESULT); 103 res = op.apply(provider, null, 0); 104 assertEquals(TEST_URI_RESULT, res.uri); 105 } 106 107 @Test testUpdate()108 public void testUpdate() throws Exception { 109 op = ContentProviderOperation.newUpdate(TEST_URI) 110 .withSelection(TEST_SELECTION, TEST_SELECTION_ARGS) 111 .withValues(TEST_VALUES) 112 .withExtras(TEST_EXTRAS) 113 .build(); 114 115 assertEquals(TEST_URI, op.getUri()); 116 assertTrue(op.isUpdate()); 117 assertTrue(op.isWriteOperation()); 118 119 when(provider.update(eq(TEST_URI), eq(TEST_VALUES), eqBundle(TEST_EXTRAS_WITH_SQL))) 120 .thenReturn(1); 121 res = op.apply(provider, null, 0); 122 assertEquals(1, (int) res.count); 123 } 124 125 @Test testDelete()126 public void testDelete() throws Exception { 127 op = ContentProviderOperation.newDelete(TEST_URI) 128 .withSelection(TEST_SELECTION, TEST_SELECTION_ARGS) 129 .withExtras(TEST_EXTRAS) 130 .build(); 131 132 assertEquals(TEST_URI, op.getUri()); 133 assertTrue(op.isDelete()); 134 assertTrue(op.isWriteOperation()); 135 136 when(provider.delete(eq(TEST_URI), eqBundle(TEST_EXTRAS_WITH_SQL))) 137 .thenReturn(1); 138 res = op.apply(provider, null, 0); 139 assertEquals(1, (int) res.count); 140 } 141 142 @Test testAssertQuery()143 public void testAssertQuery() throws Exception { 144 op = ContentProviderOperation.newAssertQuery(TEST_URI) 145 .withSelection(TEST_SELECTION, TEST_SELECTION_ARGS) 146 .withExtras(TEST_EXTRAS) 147 .withValues(TEST_VALUES) 148 .build(); 149 150 assertEquals(TEST_URI, op.getUri()); 151 assertTrue(op.isAssertQuery()); 152 assertTrue(op.isReadOperation()); 153 154 final MatrixCursor cursor = new MatrixCursor(new String[] { "test_key" }); 155 cursor.addRow(new Object[] { "test_value" }); 156 157 when(provider.query(eq(TEST_URI), eq(new String[] { "test_key" }), 158 eqBundle(TEST_EXTRAS_WITH_SQL), eq(null))) 159 .thenReturn(cursor); 160 op.apply(provider, null, 0); 161 } 162 163 @Test testCall()164 public void testCall() throws Exception { 165 op = ContentProviderOperation.newCall(TEST_URI, TEST_METHOD, TEST_ARG) 166 .withExtras(TEST_EXTRAS) 167 .build(); 168 169 assertEquals(TEST_URI, op.getUri()); 170 assertTrue(op.isCall()); 171 172 when(provider.call(eq(TEST_URI.getAuthority()), eq(TEST_METHOD), 173 eq(TEST_ARG), eqBundle(TEST_EXTRAS))) 174 .thenReturn(TEST_EXTRAS_RESULT); 175 res = op.apply(provider, null, 0); 176 assertEquals(TEST_EXTRAS_RESULT, res.extras); 177 } 178 179 @Test testBackReferenceSelection()180 public void testBackReferenceSelection() throws Exception { 181 op = ContentProviderOperation.newDelete(TEST_URI) 182 .withSelection(null, new String[] { "a", "b", "c", "d" }) 183 .withSelectionBackReference(0, 0) 184 .withSelectionBackReference(1, 1) 185 .withSelectionBackReference(2, 2, "test_result") 186 .build(); 187 188 final String[] res = op.resolveSelectionArgsBackReferences(TEST_RESULTS, 189 TEST_RESULTS.length); 190 assertEquals("12", res[0]); 191 assertEquals("84", res[1]); 192 assertEquals("42", res[2]); 193 assertEquals("d", res[3]); 194 } 195 196 @Test testBackReferenceValue()197 public void testBackReferenceValue() throws Exception { 198 final ContentValues values = new ContentValues(); 199 values.put("a", "a"); 200 values.put("b", "b"); 201 values.put("c", "c"); 202 values.put("d", "d"); 203 204 op = ContentProviderOperation.newUpdate(TEST_URI) 205 .withValues(values) 206 .withValueBackReference("a", 0) 207 .withValueBackReference("b", 1) 208 .withValueBackReference("c", 2, "test_result") 209 .build(); 210 211 final ContentValues res = op.resolveValueBackReferences(TEST_RESULTS, 212 TEST_RESULTS.length); 213 assertEquals(12L, (long) res.get("a")); 214 assertEquals(84L, (long) res.get("b")); 215 assertEquals("42", res.get("c")); 216 assertEquals("d", res.get("d")); 217 } 218 219 @Test testBackReferenceExtra()220 public void testBackReferenceExtra() throws Exception { 221 final Bundle extras = new Bundle(); 222 extras.putString("a", "a"); 223 extras.putString("b", "b"); 224 extras.putString("c", "c"); 225 extras.putString("d", "d"); 226 227 op = ContentProviderOperation.newCall(TEST_URI, TEST_METHOD, TEST_ARG) 228 .withExtras(extras) 229 .withExtraBackReference("a", 0) 230 .withExtraBackReference("b", 1) 231 .withExtraBackReference("c", 2, "test_result") 232 .build(); 233 234 final Bundle res = op.resolveExtrasBackReferences(TEST_RESULTS, 235 TEST_RESULTS.length); 236 assertEquals(12L, (long) res.get("a")); 237 assertEquals(84L, (long) res.get("b")); 238 assertEquals("42", res.get("c")); 239 assertEquals("d", res.get("d")); 240 } 241 242 @Test testExceptionAllowed()243 public void testExceptionAllowed() throws Exception { 244 op = ContentProviderOperation.newCall(TEST_URI, TEST_METHOD, TEST_ARG) 245 .withExtras(TEST_EXTRAS) 246 .withExceptionAllowed(true) 247 .build(); 248 249 assertTrue(op.isExceptionAllowed()); 250 251 when(provider.call(eq(TEST_URI.getAuthority()), eq(TEST_METHOD), 252 eq(TEST_ARG), eqBundle(TEST_EXTRAS))) 253 .thenThrow(new IllegalArgumentException()); 254 res = op.apply(provider, null, 0); 255 assertTrue((res.exception instanceof IllegalArgumentException)); 256 } 257 258 @Test testLayering()259 public void testLayering() throws Exception { 260 op = ContentProviderOperation.newAssertQuery(TEST_URI) 261 .withSelection(TEST_SELECTION, TEST_SELECTION_ARGS) 262 .withExtras(TEST_EXTRAS) 263 .withExtra("test_key", "other_extra") 264 .withValues(TEST_VALUES) 265 .withValue("test_key", "other_value") 266 .build(); 267 268 assertEquals("other_extra", op.resolveExtrasBackReferences(null, 0).getString("test_key")); 269 assertEquals("other_value", op.resolveValueBackReferences(null, 0).getAsString("test_key")); 270 } 271 eqBundle(Bundle bundle)272 public static Bundle eqBundle(Bundle bundle) { 273 return ArgumentMatchers.argThat((other) -> { 274 // Ideally we'd use something like Bundle.kindofEquals() here, but 275 // it doesn't perform deep equals inside String[] values, so the 276 // best we can do is a simple string equality check 277 return Objects.equals(bundle.toString(), other.toString()); 278 }); 279 } 280 } 281