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