• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 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 package com.android.vcard.tests.testutils;
17 
18 import android.content.ContentProviderOperation;
19 import android.content.ContentProviderResult;
20 import android.content.ContentValues;
21 import android.net.Uri;
22 import android.provider.ContactsContract.Data;
23 import android.provider.ContactsContract.RawContacts;
24 import android.test.mock.MockContentProvider;
25 import android.text.TextUtils;
26 
27 import junit.framework.TestCase;
28 
29 import java.util.ArrayList;
30 import java.util.Arrays;
31 import java.util.Collection;
32 import java.util.HashMap;
33 import java.util.HashSet;
34 import java.util.Map;
35 import java.util.Map.Entry;
36 import java.util.Set;
37 import java.util.SortedMap;
38 import java.util.TreeMap;
39 
40 public class ImportTestProvider extends MockContentProvider {
41     private final Map<String, Collection<ContentValues>>
42             mMimeTypeToExpectedContentValues = new HashMap<String, Collection<ContentValues>>();
43 
addExpectedContentValues(ContentValues expectedContentValues)44     public void addExpectedContentValues(ContentValues expectedContentValues) {
45         final String mimeType = expectedContentValues.getAsString(Data.MIMETYPE);
46 
47         final Collection<ContentValues> contentValuesCollection;
48         if (mMimeTypeToExpectedContentValues.containsKey(mimeType)) {
49              contentValuesCollection = mMimeTypeToExpectedContentValues.get(mimeType);
50         } else {
51             contentValuesCollection = new ArrayList<ContentValues>();
52             mMimeTypeToExpectedContentValues.put(mimeType, contentValuesCollection);
53         }
54 
55         contentValuesCollection.add(expectedContentValues);
56     }
57 
58     @Override
applyBatch( ArrayList<ContentProviderOperation> operations)59     public ContentProviderResult[] applyBatch(
60             ArrayList<ContentProviderOperation> operations) {
61         if (operations == null) {
62             TestCase.fail("There is no operation.");
63         }
64 
65         final int size = operations.size();
66         ContentProviderResult[] fakeResultArray = new ContentProviderResult[size];
67         for (int i = 0; i < size; i++) {
68             Uri uri = Uri.withAppendedPath(RawContacts.CONTENT_URI, String.valueOf(i));
69             fakeResultArray[i] = new ContentProviderResult(uri);
70         }
71 
72         for (int i = 0; i < size; i++) {
73             ContentProviderOperation operation = operations.get(i);
74             ContentValues contentValues = operation.resolveValueBackReferences(
75                     fakeResultArray, i);
76         }
77         for (int i = 0; i < size; i++) {
78             ContentProviderOperation operation = operations.get(i);
79             ContentValues actualContentValues = operation.resolveValueBackReferences(
80                     fakeResultArray, i);
81             final Uri uri = operation.getUri();
82             if (uri.equals(RawContacts.CONTENT_URI)) {
83                 TestCase.assertNull(actualContentValues.get(RawContacts.ACCOUNT_NAME));
84                 TestCase.assertNull(actualContentValues.get(RawContacts.ACCOUNT_TYPE));
85             } else if (uri.equals(Data.CONTENT_URI)) {
86                 final String mimeType = actualContentValues.getAsString(Data.MIMETYPE);
87                 if (!mMimeTypeToExpectedContentValues.containsKey(mimeType)) {
88                     TestCase.fail("Unregistered MimeType " + mimeType);
89                 }
90                 // Remove data meaningless in this unit tests.
91                 // Specifically, Data.DATA1 - DATA7 are set to null or empty String
92                 // regardless of the input, but it may change depending on how
93                 // resolver-related code handles it.
94                 // Here, we ignore these implementation-dependent specs and
95                 // just check whether vCard importer correctly inserts rellevent data.
96                 Set<String> keyToBeRemoved = new HashSet<String>();
97                 for (Entry<String, Object> entry : actualContentValues.valueSet()) {
98                     Object value = entry.getValue();
99                     if (value == null || TextUtils.isEmpty(value.toString())) {
100                         keyToBeRemoved.add(entry.getKey());
101                     }
102                 }
103                 for (String key: keyToBeRemoved) {
104                     actualContentValues.remove(key);
105                 }
106                 /* for testing
107                 Log.d("@@@",
108                         String.format("MimeType: %s, data: %s",
109                                 mimeType, actualContentValues.toString())); */
110                 // Remove RAW_CONTACT_ID entry just for safety, since we do not care
111                 // how resolver-related code handles the entry in this unit test,
112                 if (actualContentValues.containsKey(Data.RAW_CONTACT_ID)) {
113                     actualContentValues.remove(Data.RAW_CONTACT_ID);
114                 }
115                 final Collection<ContentValues> contentValuesCollection =
116                     mMimeTypeToExpectedContentValues.get(mimeType);
117                 if (contentValuesCollection.isEmpty()) {
118                     TestCase.fail("ContentValues for MimeType " + mimeType
119                             + " is not expected at all (" + actualContentValues + ")");
120                 }
121                 boolean checked = false;
122                 for (ContentValues expectedContentValues : contentValuesCollection) {
123                     /*for testing
124                     Log.d("@@@", "expected: "
125                             + convertToEasilyReadableString(expectedContentValues));
126                     Log.d("@@@", "actual  : "
127                             + convertToEasilyReadableString(actualContentValues));*/
128                     if (equalsForContentValues(expectedContentValues,
129                             actualContentValues)) {
130                         TestCase.assertTrue(contentValuesCollection.remove(expectedContentValues));
131                         checked = true;
132                         break;
133                     }
134                 }
135                 if (!checked) {
136                     final StringBuilder builder = new StringBuilder();
137                     builder.append("\n");
138                     builder.append("Unexpected: ");
139                     builder.append(convertToEasilyReadableString(actualContentValues));
140                     builder.append("\n");
141                     builder.append("Expected  : ");
142                     for (ContentValues expectedContentValues : contentValuesCollection) {
143                         builder.append(convertToEasilyReadableString(expectedContentValues));
144                     }
145                     TestCase.fail(builder.toString());
146                 }
147             } else {
148                 TestCase.fail("Unexpected Uri has come: " + uri);
149             }
150         }  // for (int i = 0; i < size; i++) {
151         return fakeResultArray;
152     }
153 
154     /**
155      * Checks all expected ContentValues are consumed during import.
156      */
verify()157     public void verify() {
158         StringBuilder builder = new StringBuilder();
159         for (Collection<ContentValues> contentValuesCollection :
160                 mMimeTypeToExpectedContentValues.values()) {
161             for (ContentValues expectedContentValues: contentValuesCollection) {
162                 builder.append(convertToEasilyReadableString(expectedContentValues));
163                 builder.append("\n");
164             }
165         }
166         if (builder.length() > 0) {
167             final String failMsg =
168                 "There is(are) remaining expected ContentValues instance(s): \n"
169                     + builder.toString();
170             TestCase.fail(failMsg);
171         }
172     }
173 
174     /**
175      * Utility method to print ContentValues whose content is printed with sorted keys.
176      */
convertToEasilyReadableString(ContentValues contentValues)177     private String convertToEasilyReadableString(ContentValues contentValues) {
178         if (contentValues == null) {
179             return "null";
180         }
181         String mimeTypeValue = "";
182         SortedMap<String, String> sortedMap = new TreeMap<String, String>();
183         for (Entry<String, Object> entry : contentValues.valueSet()) {
184             final String key = entry.getKey();
185             final Object value = entry.getValue();
186             final String valueString = (value != null ? value.toString() : null);
187             if (Data.MIMETYPE.equals(key)) {
188                 mimeTypeValue = valueString;
189             } else {
190                 TestCase.assertNotNull(key);
191                 sortedMap.put(key, valueString);
192             }
193         }
194         StringBuilder builder = new StringBuilder();
195         builder.append(Data.MIMETYPE);
196         builder.append('=');
197         builder.append(mimeTypeValue);
198         for (Entry<String, String> entry : sortedMap.entrySet()) {
199             final String key = entry.getKey();
200             final String value = entry.getValue();
201             builder.append(' ');
202             builder.append(key);
203             builder.append("=\"");
204             builder.append(value);
205             builder.append('"');
206         }
207         return builder.toString();
208     }
209 
equalsForContentValues( final ContentValues expected, final ContentValues actual)210     private static boolean equalsForContentValues(
211             final ContentValues expected, final ContentValues actual) {
212         if (expected == actual) {
213             return true;
214         } else if (expected == null || actual == null || expected.size() != actual.size()) {
215             return false;
216         }
217 
218         for (Entry<String, Object> entry : expected.valueSet()) {
219             final String key = entry.getKey();
220             final Object value = entry.getValue();
221             if (!actual.containsKey(key)) {
222                 return false;
223             }
224             // Type mismatch usuall happens as importer doesn't care the type of each value.
225             // For example, variable type might be Integer when importing the type of TEL,
226             // while variable type would be String when importing the type of RELATION.
227             final Object actualValue = actual.get(key);
228             if (value instanceof byte[]) {
229                 if (!Arrays.equals((byte[])value, (byte[])actualValue)) {
230                     byte[] e = (byte[])value;
231                     byte[] a = (byte[])actualValue;
232                     return false;
233                 }
234             } else if (!value.equals(actualValue) &&
235                     !value.toString().equals(actualValue.toString())) {
236                 return false;
237             }
238         }
239         return true;
240     }
241 }