• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*******************************************************************************
2  *      Copyright (C) 2012 Google Inc.
3  *      Licensed to The Android Open Source Project.
4  *
5  *      Licensed under the Apache License, Version 2.0 (the "License");
6  *      you may not use this file except in compliance with the License.
7  *      You may obtain a copy of the License at
8  *
9  *           http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *      Unless required by applicable law or agreed to in writing, software
12  *      distributed under the License is distributed on an "AS IS" BASIS,
13  *      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *      See the License for the specific language governing permissions and
15  *      limitations under the License.
16  *******************************************************************************/
17 
18 package com.android.mail.browse;
19 
20 import android.content.ContentProvider;
21 import android.content.ContentValues;
22 import android.content.Context;
23 import android.content.UriMatcher;
24 import android.content.pm.ProviderInfo;
25 import android.database.Cursor;
26 import android.database.MatrixCursor;
27 import android.net.Uri;
28 
29 import com.android.mail.utils.MatrixCursorWithCachedColumns;
30 
31 import java.util.ArrayList;
32 import java.util.HashMap;
33 import java.util.Map.Entry;
34 import java.util.Set;
35 
36 /**
37  * TestProvider is a ContentProvider that can be used to simulate the storage and retrieval of
38  * rows from any ContentProvider, even if that provider does not exist in the caller's package.
39  *
40  * It is specifically designed to enable testing of sync adapters that create
41  * ContentProviderOperations (CPOs) that are then executed using ContentResolver.applyBatch().
42  * Why is this useful? Because we can't instantiate CalendarProvider or ContactsProvider from our
43  * package, as required by MockContentResolver.addProvider()
44  *
45  * Usage:
46  *
47  * ContentResolver.applyBatch(MockProvider.AUTHORITY, batch) will cause the CPOs to be executed,
48  * returning an array of ContentProviderResult; in the case of inserts, the result will include
49  * a Uri that can be used via query(). Note that the CPOs can contain references to any authority.
50  *
51  * query() does not allow non-null selection, selectionArgs, or sortOrder arguments; the
52  * presence of these will result in an UnsupportedOperationException insert() acts as expected,
53  * returning a Uri that can be directly used in a query
54  *
55  * delete() and update() do not allow non-null selection or selectionArgs arguments; the presence
56  * of these will result in an UnsupportedOperationException
57  *
58  * NOTE: MockProvider only simulates direct storage/retrieval of rows; it does not (and can not)
59  * simulate other actions (e.g. creation of ancillary data) that the actual provider might perform
60  *
61  * NOTE: See MockProviderTests for usage examples
62  **/
63 public class TestProvider extends ContentProvider {
64     public static final String AUTHORITY = "com.android.mail.mock.provider";
65 
66     /* package */static final UriMatcher sURIMatcher = new UriMatcher(UriMatcher.NO_MATCH);
67 
68     /* package */static final int TABLE = 100;
69     /* package */static final int RECORD = 101;
70 
71     public static final String ID_COLUMN = "_id";
72 
TestProvider()73     public TestProvider() {
74         super();
75     }
76 
TestProvider(Context context)77     public TestProvider(Context context) {
78         this();
79         ProviderInfo info = new ProviderInfo();
80         info.authority = AUTHORITY;
81         attachInfo(context, info);
82     }
83 
84     // We'll store our values here
85     private HashMap<String, ContentValues> mMockStore = new HashMap<String, ContentValues>();
86     // And we'll generate new id's from here
87     long mMockId = 1;
88 
89     @Override
delete(Uri uri, String selection, String[] selectionArgs)90     public int delete(Uri uri, String selection, String[] selectionArgs) {
91         if (selection != null || selectionArgs != null) {
92             throw new UnsupportedOperationException();
93         }
94         String path = uri.getPath();
95         if (mMockStore.containsKey(path)) {
96             mMockStore.remove(path);
97             return 1;
98         } else {
99             return 0;
100         }
101     }
102 
103     @Override
getType(Uri uri)104     public String getType(Uri uri) {
105         throw new UnsupportedOperationException();
106     }
107 
108     @Override
insert(Uri uri, ContentValues values)109     public Uri insert(Uri uri, ContentValues values) {
110         // Remove the leading slash
111         String table = uri.getPath().substring(1);
112         long id = mMockId++;
113         Uri newUri = new Uri.Builder().scheme("content").authority(AUTHORITY).path(table)
114                 .appendPath(Long.toString(id)).build();
115         // Remember to store the _id
116         values.put(ID_COLUMN, id);
117         mMockStore.put(newUri.getPath(), values);
118         int match = sURIMatcher.match(uri);
119         if (match == UriMatcher.NO_MATCH) {
120             sURIMatcher.addURI(AUTHORITY, table, TABLE);
121             sURIMatcher.addURI(AUTHORITY, table + "/#", RECORD);
122         }
123         return newUri;
124     }
125 
126     @Override
onCreate()127     public boolean onCreate() {
128         return false;
129     }
130 
131     @Override
query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)132     public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
133             String sortOrder) {
134         if (selection != null || selectionArgs != null || sortOrder != null || projection == null) {
135             throw new UnsupportedOperationException();
136         }
137         final int match = sURIMatcher.match(uri);
138         ArrayList<ContentValues> valuesList = new ArrayList<ContentValues>();
139         switch (match) {
140             case TABLE:
141                 Set<Entry<String, ContentValues>> entrySet = mMockStore.entrySet();
142                 String prefix = uri.getPath() + "/";
143                 for (Entry<String, ContentValues> entry : entrySet) {
144                     if (entry.getKey().startsWith(prefix)) {
145                         valuesList.add(entry.getValue());
146                     }
147                 }
148                 break;
149             case RECORD:
150                 ContentValues values = mMockStore.get(uri.getPath());
151                 if (values != null) {
152                     valuesList.add(values);
153                 }
154                 break;
155             default:
156                 throw new IllegalArgumentException("Unknown URI " + uri);
157         }
158         MatrixCursor cursor = new MatrixCursorWithCachedColumns(projection, 1);
159         for (ContentValues cv : valuesList) {
160             Object[] rowValues = new Object[projection.length];
161             int i = 0;
162             for (String column : projection) {
163                 rowValues[i++] = cv.get(column);
164             }
165             cursor.addRow(rowValues);
166         }
167         return cursor;
168     }
169 
170     @Override
update(Uri uri, ContentValues newValues, String selection, String[] selectionArgs)171     public int update(Uri uri, ContentValues newValues, String selection, String[] selectionArgs) {
172         if (selection != null || selectionArgs != null) {
173             throw new UnsupportedOperationException();
174         }
175         final int match = sURIMatcher.match(uri);
176         ArrayList<ContentValues> updateValuesList = new ArrayList<ContentValues>();
177         String path = uri.getPath();
178         switch (match) {
179             case TABLE:
180                 Set<Entry<String, ContentValues>> entrySet = mMockStore.entrySet();
181                 String prefix = path + "/";
182                 for (Entry<String, ContentValues> entry : entrySet) {
183                     if (entry.getKey().startsWith(prefix)) {
184                         updateValuesList.add(entry.getValue());
185                     }
186                 }
187                 break;
188             case RECORD:
189                 ContentValues cv = mMockStore.get(path);
190                 if (cv != null) {
191                     updateValuesList.add(cv);
192                 }
193                 break;
194             default:
195                 throw new IllegalArgumentException("Unknown URI " + uri);
196         }
197         Set<Entry<String, Object>> newValuesSet = newValues.valueSet();
198         for (Entry<String, Object> entry : newValuesSet) {
199             String key = entry.getKey();
200             Object value = entry.getValue();
201             for (ContentValues targetValues : updateValuesList) {
202                 if (value instanceof Integer) {
203                     targetValues.put(key, (Integer) value);
204                 } else if (value instanceof Long) {
205                     targetValues.put(key, (Long) value);
206                 } else if (value instanceof String) {
207                     targetValues.put(key, (String) value);
208                 } else if (value instanceof Boolean) {
209                     targetValues.put(key, (Boolean) value);
210                 } else {
211                     throw new IllegalArgumentException();
212                 }
213             }
214         }
215         for (ContentValues targetValues : updateValuesList) {
216             switch(match) {
217                 case TABLE:
218                     mMockStore.put(path + "/" + targetValues.getAsLong(ID_COLUMN), targetValues);
219                     break;
220                 case RECORD:
221                     mMockStore.put(path, targetValues);
222                     break;
223             }
224         }
225         return updateValuesList.size();
226     }
227 }
228