ImportTestProvider.java revision 48dd8e86a81d2ab40eb762975c8211c225002bf0
1cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber/*
2cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber * Copyright (C) 2010 The Android Open Source Project
3cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber *
4cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber * Licensed under the Apache License, Version 2.0 (the "License");
5cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber * you may not use this file except in compliance with the License.
6cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber * You may obtain a copy of the License at
7cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber *
8cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber *      http://www.apache.org/licenses/LICENSE-2.0
9cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber *
10cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber * Unless required by applicable law or agreed to in writing, software
11cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber * distributed under the License is distributed on an "AS IS" BASIS,
12cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber * See the License for the specific language governing permissions and
14cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber * limitations under the License.
15cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber */
16cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huberpackage com.android.vcard.tests.testutils;
17cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber
18cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huberimport android.content.ContentProviderOperation;
19cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huberimport android.content.ContentProviderResult;
20cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huberimport android.content.ContentValues;
21cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huberimport android.net.Uri;
22cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huberimport android.provider.ContactsContract.CommonDataKinds.Email;
23cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huberimport android.provider.ContactsContract.CommonDataKinds.Event;
24cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huberimport android.provider.ContactsContract.CommonDataKinds.GroupMembership;
25cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huberimport android.provider.ContactsContract.CommonDataKinds.Im;
26cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huberimport android.provider.ContactsContract.CommonDataKinds.Nickname;
27cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huberimport android.provider.ContactsContract.CommonDataKinds.Note;
28cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huberimport android.provider.ContactsContract.CommonDataKinds.Organization;
29cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huberimport android.provider.ContactsContract.CommonDataKinds.Phone;
30cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huberimport android.provider.ContactsContract.CommonDataKinds.Photo;
31cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huberimport android.provider.ContactsContract.CommonDataKinds.Relation;
32cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huberimport android.provider.ContactsContract.CommonDataKinds.SipAddress;
33cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huberimport android.provider.ContactsContract.CommonDataKinds.StructuredName;
34cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huberimport android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
35cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huberimport android.provider.ContactsContract.CommonDataKinds.Website;
365bc087c573c70c84c6a39946457590b42d392a33Andreas Huberimport android.provider.ContactsContract.Data;
375bc087c573c70c84c6a39946457590b42d392a33Andreas Huberimport android.provider.ContactsContract.RawContacts;
385bc087c573c70c84c6a39946457590b42d392a33Andreas Huberimport android.test.AndroidTestCase;
395bc087c573c70c84c6a39946457590b42d392a33Andreas Huberimport android.test.mock.MockContentProvider;
405bc087c573c70c84c6a39946457590b42d392a33Andreas Huberimport android.text.TextUtils;
41cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber
42cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huberimport junit.framework.TestCase;
43cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber
44cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huberimport java.util.ArrayList;
45cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huberimport java.util.Arrays;
46cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huberimport java.util.Collection;
47cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huberimport java.util.HashMap;
48cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huberimport java.util.HashSet;
49cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huberimport java.util.Map;
50cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huberimport java.util.Map.Entry;
51cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huberimport java.util.Set;
52cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huberimport java.util.SortedMap;
53cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huberimport java.util.TreeMap;
54cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber
55cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huberpublic class ImportTestProvider extends MockContentProvider {
56f933441648ef6a71dee783d733aac17b9508b452Andreas Huber    private static final Set<String> sKnownMimeTypeSet =
57f933441648ef6a71dee783d733aac17b9508b452Andreas Huber        new HashSet<String>(Arrays.asList(StructuredName.CONTENT_ITEM_TYPE,
58f933441648ef6a71dee783d733aac17b9508b452Andreas Huber                Nickname.CONTENT_ITEM_TYPE, Phone.CONTENT_ITEM_TYPE,
59f933441648ef6a71dee783d733aac17b9508b452Andreas Huber                Email.CONTENT_ITEM_TYPE, StructuredPostal.CONTENT_ITEM_TYPE,
60f933441648ef6a71dee783d733aac17b9508b452Andreas Huber                Im.CONTENT_ITEM_TYPE, Organization.CONTENT_ITEM_TYPE,
61f933441648ef6a71dee783d733aac17b9508b452Andreas Huber                Event.CONTENT_ITEM_TYPE, Photo.CONTENT_ITEM_TYPE,
62f933441648ef6a71dee783d733aac17b9508b452Andreas Huber                Note.CONTENT_ITEM_TYPE, Website.CONTENT_ITEM_TYPE,
63f933441648ef6a71dee783d733aac17b9508b452Andreas Huber                Relation.CONTENT_ITEM_TYPE, Event.CONTENT_ITEM_TYPE,
64f933441648ef6a71dee783d733aac17b9508b452Andreas Huber                GroupMembership.CONTENT_ITEM_TYPE, SipAddress.CONTENT_ITEM_TYPE));
65f933441648ef6a71dee783d733aac17b9508b452Andreas Huber
66f933441648ef6a71dee783d733aac17b9508b452Andreas Huber    final Map<String, Collection<ContentValues>> mMimeTypeToExpectedContentValues;
67f933441648ef6a71dee783d733aac17b9508b452Andreas Huber
68f933441648ef6a71dee783d733aac17b9508b452Andreas Huber    public ImportTestProvider(AndroidTestCase androidTestCase) {
695bc087c573c70c84c6a39946457590b42d392a33Andreas Huber        mMimeTypeToExpectedContentValues =
705bc087c573c70c84c6a39946457590b42d392a33Andreas Huber            new HashMap<String, Collection<ContentValues>>();
715bc087c573c70c84c6a39946457590b42d392a33Andreas Huber        for (String acceptanbleMimeType : sKnownMimeTypeSet) {
725bc087c573c70c84c6a39946457590b42d392a33Andreas Huber            // Do not use HashSet since the current implementation changes the content of
735bc087c573c70c84c6a39946457590b42d392a33Andreas Huber            // ContentValues after the insertion, which make the result of hashCode()
745bc087c573c70c84c6a39946457590b42d392a33Andreas Huber            // changes...
75f933441648ef6a71dee783d733aac17b9508b452Andreas Huber            mMimeTypeToExpectedContentValues.put(
76f933441648ef6a71dee783d733aac17b9508b452Andreas Huber                    acceptanbleMimeType, new ArrayList<ContentValues>());
77f933441648ef6a71dee783d733aac17b9508b452Andreas Huber        }
78f933441648ef6a71dee783d733aac17b9508b452Andreas Huber    }
79f933441648ef6a71dee783d733aac17b9508b452Andreas Huber
80f933441648ef6a71dee783d733aac17b9508b452Andreas Huber    public void addExpectedContentValues(ContentValues expectedContentValues) {
81f933441648ef6a71dee783d733aac17b9508b452Andreas Huber        final String mimeType = expectedContentValues.getAsString(Data.MIMETYPE);
82f933441648ef6a71dee783d733aac17b9508b452Andreas Huber        if (!sKnownMimeTypeSet.contains(mimeType)) {
83f933441648ef6a71dee783d733aac17b9508b452Andreas Huber            TestCase.fail(String.format(
84cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber                    "Unknow MimeType %s in the test code. Test code should be broken.",
85cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber                    mimeType));
86cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber        }
87cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber
88cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber        final Collection<ContentValues> contentValuesCollection =
89cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber                mMimeTypeToExpectedContentValues.get(mimeType);
90cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber        contentValuesCollection.add(expectedContentValues);
91cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber    }
92cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber
93cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber    @Override
94cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber    public ContentProviderResult[] applyBatch(
952a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber            ArrayList<ContentProviderOperation> operations) {
96cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber        if (operations == null) {
972a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber            TestCase.fail("There is no operation.");
985bc087c573c70c84c6a39946457590b42d392a33Andreas Huber        }
995bc087c573c70c84c6a39946457590b42d392a33Andreas Huber
1005bc087c573c70c84c6a39946457590b42d392a33Andreas Huber        final int size = operations.size();
1015bc087c573c70c84c6a39946457590b42d392a33Andreas Huber        ContentProviderResult[] fakeResultArray = new ContentProviderResult[size];
1025bc087c573c70c84c6a39946457590b42d392a33Andreas Huber        for (int i = 0; i < size; i++) {
1032a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber            Uri uri = Uri.withAppendedPath(RawContacts.CONTENT_URI, String.valueOf(i));
1042a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber            fakeResultArray[i] = new ContentProviderResult(uri);
105f933441648ef6a71dee783d733aac17b9508b452Andreas Huber        }
106f933441648ef6a71dee783d733aac17b9508b452Andreas Huber
107cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber        for (int i = 0; i < size; i++) {
108f89d780df70b7fbb8465bce4913c46cca019721fAndreas Huber            ContentProviderOperation operation = operations.get(i);
109cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber            ContentValues contentValues = operation.resolveValueBackReferences(
110f89d780df70b7fbb8465bce4913c46cca019721fAndreas Huber                    fakeResultArray, i);
111cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber        }
1122a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber        for (int i = 0; i < size; i++) {
1132a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber            ContentProviderOperation operation = operations.get(i);
1142a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber            ContentValues actualContentValues = operation.resolveValueBackReferences(
115cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber                    fakeResultArray, i);
116cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber            final Uri uri = operation.getUri();
117cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber            if (uri.equals(RawContacts.CONTENT_URI)) {
118cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber                TestCase.assertNull(actualContentValues.get(RawContacts.ACCOUNT_NAME));
119cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber                TestCase.assertNull(actualContentValues.get(RawContacts.ACCOUNT_TYPE));
120cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber            } else if (uri.equals(Data.CONTENT_URI)) {
121cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber                final String mimeType = actualContentValues.getAsString(Data.MIMETYPE);
122cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber                if (!sKnownMimeTypeSet.contains(mimeType)) {
123cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber                    TestCase.fail(String.format(
124cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber                            "Unknown MimeType %s. " +
125cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber                            "(Maybe the MimeType is added after developing this test suite." +
126cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber                            "Please look into %s if you strongly believe the type is regitimate)",
127bff07d0b22a5ee2d9f044f6cb5e4be1532017ab0Andreas Huber                            ImportTestProvider.class.getSimpleName(), mimeType));
128f933441648ef6a71dee783d733aac17b9508b452Andreas Huber                }
1293856b090cd04ba5dd4a59a12430ed724d5995909Steve Block                // Remove data meaningless in this unit tests.
130bff07d0b22a5ee2d9f044f6cb5e4be1532017ab0Andreas Huber                // Specifically, Data.DATA1 - DATA7 are set to null or empty String
131cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber                // regardless of the input, but it may change depending on how
132cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber                // resolver-related code handles it.
133cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber                // Here, we ignore these implementation-dependent specs and
134cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber                // just check whether vCard importer correctly inserts rellevent data.
135cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber                Set<String> keyToBeRemoved = new HashSet<String>();
1365bc087c573c70c84c6a39946457590b42d392a33Andreas Huber                for (Entry<String, Object> entry : actualContentValues.valueSet()) {
13732f3cefa373cd55e63deda36ca9d07c7fe22eaafAndreas Huber                    Object value = entry.getValue();
13832f3cefa373cd55e63deda36ca9d07c7fe22eaafAndreas Huber                    if (value == null || TextUtils.isEmpty(value.toString())) {
1392a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber                        keyToBeRemoved.add(entry.getKey());
140bff07d0b22a5ee2d9f044f6cb5e4be1532017ab0Andreas Huber                    }
1419a442c1b9a051edc6d4ceb0daad2d0a8433e7b0bAndreas Huber                }
1429a442c1b9a051edc6d4ceb0daad2d0a8433e7b0bAndreas Huber                for (String key: keyToBeRemoved) {
1439a442c1b9a051edc6d4ceb0daad2d0a8433e7b0bAndreas Huber                    actualContentValues.remove(key);
1449a442c1b9a051edc6d4ceb0daad2d0a8433e7b0bAndreas Huber                }
1459a442c1b9a051edc6d4ceb0daad2d0a8433e7b0bAndreas Huber                /* for testing
1469a442c1b9a051edc6d4ceb0daad2d0a8433e7b0bAndreas Huber                Log.d("@@@",
1479a442c1b9a051edc6d4ceb0daad2d0a8433e7b0bAndreas Huber                        String.format("MimeType: %s, data: %s",
1489a442c1b9a051edc6d4ceb0daad2d0a8433e7b0bAndreas Huber                                mimeType, actualContentValues.toString())); */
1499a442c1b9a051edc6d4ceb0daad2d0a8433e7b0bAndreas Huber                // Remove RAW_CONTACT_ID entry just for safety, since we do not care
1509a442c1b9a051edc6d4ceb0daad2d0a8433e7b0bAndreas Huber                // how resolver-related code handles the entry in this unit test,
1519a442c1b9a051edc6d4ceb0daad2d0a8433e7b0bAndreas Huber                if (actualContentValues.containsKey(Data.RAW_CONTACT_ID)) {
15222fc52f6f72f39e33c3970d0291de3569118aa5cAndreas Huber                    actualContentValues.remove(Data.RAW_CONTACT_ID);
1539a442c1b9a051edc6d4ceb0daad2d0a8433e7b0bAndreas Huber                }
15422fc52f6f72f39e33c3970d0291de3569118aa5cAndreas Huber                final Collection<ContentValues> contentValuesCollection =
1559a442c1b9a051edc6d4ceb0daad2d0a8433e7b0bAndreas Huber                    mMimeTypeToExpectedContentValues.get(mimeType);
1569a442c1b9a051edc6d4ceb0daad2d0a8433e7b0bAndreas Huber                if (contentValuesCollection.isEmpty()) {
1579a442c1b9a051edc6d4ceb0daad2d0a8433e7b0bAndreas Huber                    TestCase.fail("ContentValues for MimeType " + mimeType
1589a442c1b9a051edc6d4ceb0daad2d0a8433e7b0bAndreas Huber                            + " is not expected at all (" + actualContentValues + ")");
1599a442c1b9a051edc6d4ceb0daad2d0a8433e7b0bAndreas Huber                }
1609a442c1b9a051edc6d4ceb0daad2d0a8433e7b0bAndreas Huber                boolean checked = false;
16122fc52f6f72f39e33c3970d0291de3569118aa5cAndreas Huber                for (ContentValues expectedContentValues : contentValuesCollection) {
1622a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber                    /*for testing
1632a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber                    Log.d("@@@", "expected: "
1642a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber                            + convertToEasilyReadableString(expectedContentValues));
1652a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber                    Log.d("@@@", "actual  : "
166cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber                            + convertToEasilyReadableString(actualContentValues));*/
167cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber                    if (equalsForContentValues(expectedContentValues,
168cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber                            actualContentValues)) {
169cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber                        TestCase.assertTrue(contentValuesCollection.remove(expectedContentValues));
170cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber                        checked = true;
171cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber                        break;
172cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber                    }
173cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber                }
174cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber                if (!checked) {
175cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber                    final StringBuilder builder = new StringBuilder();
176cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber                    builder.append("\n");
177cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber                    builder.append("Unexpected: ");
178cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber                    builder.append(convertToEasilyReadableString(actualContentValues));
179cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber                    builder.append("\n");
180cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber                    builder.append("Expected  : ");
181cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber                    for (ContentValues expectedContentValues : contentValuesCollection) {
182cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber                        builder.append(convertToEasilyReadableString(expectedContentValues));
183cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber                    }
184f933441648ef6a71dee783d733aac17b9508b452Andreas Huber                    TestCase.fail(builder.toString());
185f933441648ef6a71dee783d733aac17b9508b452Andreas Huber                }
186f933441648ef6a71dee783d733aac17b9508b452Andreas Huber            } else {
187f933441648ef6a71dee783d733aac17b9508b452Andreas Huber                TestCase.fail("Unexpected Uri has come: " + uri);
188f933441648ef6a71dee783d733aac17b9508b452Andreas Huber            }
189f933441648ef6a71dee783d733aac17b9508b452Andreas Huber        }  // for (int i = 0; i < size; i++) {
190f933441648ef6a71dee783d733aac17b9508b452Andreas Huber        return fakeResultArray;
191f933441648ef6a71dee783d733aac17b9508b452Andreas Huber    }
192f933441648ef6a71dee783d733aac17b9508b452Andreas Huber
193f933441648ef6a71dee783d733aac17b9508b452Andreas Huber    /**
194f933441648ef6a71dee783d733aac17b9508b452Andreas Huber     * Checks all expected ContentValues are consumed during import.
195f933441648ef6a71dee783d733aac17b9508b452Andreas Huber     */
196f933441648ef6a71dee783d733aac17b9508b452Andreas Huber    public void verify() {
197f933441648ef6a71dee783d733aac17b9508b452Andreas Huber        StringBuilder builder = new StringBuilder();
198f933441648ef6a71dee783d733aac17b9508b452Andreas Huber        for (Collection<ContentValues> contentValuesCollection :
199cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber                mMimeTypeToExpectedContentValues.values()) {
200            for (ContentValues expectedContentValues: contentValuesCollection) {
201                builder.append(convertToEasilyReadableString(expectedContentValues));
202                builder.append("\n");
203            }
204        }
205        if (builder.length() > 0) {
206            final String failMsg =
207                "There is(are) remaining expected ContentValues instance(s): \n"
208                    + builder.toString();
209            TestCase.fail(failMsg);
210        }
211    }
212
213    /**
214     * Utility method to print ContentValues whose content is printed with sorted keys.
215     */
216    private String convertToEasilyReadableString(ContentValues contentValues) {
217        if (contentValues == null) {
218            return "null";
219        }
220        String mimeTypeValue = "";
221        SortedMap<String, String> sortedMap = new TreeMap<String, String>();
222        for (Entry<String, Object> entry : contentValues.valueSet()) {
223            final String key = entry.getKey();
224            final Object value = entry.getValue();
225            final String valueString = (value != null ? value.toString() : null);
226            if (Data.MIMETYPE.equals(key)) {
227                mimeTypeValue = valueString;
228            } else {
229                TestCase.assertNotNull(key);
230                sortedMap.put(key, valueString);
231            }
232        }
233        StringBuilder builder = new StringBuilder();
234        builder.append(Data.MIMETYPE);
235        builder.append('=');
236        builder.append(mimeTypeValue);
237        for (Entry<String, String> entry : sortedMap.entrySet()) {
238            final String key = entry.getKey();
239            final String value = entry.getValue();
240            builder.append(' ');
241            builder.append(key);
242            builder.append("=\"");
243            builder.append(value);
244            builder.append('"');
245        }
246        return builder.toString();
247    }
248
249    private static boolean equalsForContentValues(
250            final ContentValues expected, final ContentValues actual) {
251        if (expected == actual) {
252            return true;
253        } else if (expected == null || actual == null || expected.size() != actual.size()) {
254            return false;
255        }
256
257        for (Entry<String, Object> entry : expected.valueSet()) {
258            final String key = entry.getKey();
259            final Object value = entry.getValue();
260            if (!actual.containsKey(key)) {
261                return false;
262            }
263            // Type mismatch usuall happens as importer doesn't care the type of each value.
264            // For example, variable type might be Integer when importing the type of TEL,
265            // while variable type would be String when importing the type of RELATION.
266            final Object actualValue = actual.get(key);
267            if (value instanceof byte[]) {
268                if (!Arrays.equals((byte[])value, (byte[])actualValue)) {
269                    byte[] e = (byte[])value;
270                    byte[] a = (byte[])actualValue;
271                    return false;
272                }
273            } else if (!value.equals(actualValue) &&
274                    !value.toString().equals(actualValue.toString())) {
275                return false;
276            }
277        }
278        return true;
279    }
280}