1/*
2 * Copyright (C) 2012 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
17package com.android.providers.contacts;
18
19import android.net.Uri;
20import android.os.Bundle;
21import android.provider.ContactsContract.ContactCounts;
22import android.provider.ContactsContract.Contacts;
23import android.provider.ContactsContract.RawContacts;
24import android.test.AndroidTestCase;
25import android.test.MoreAsserts;
26import android.test.suitebuilder.annotation.SmallTest;
27
28import com.android.providers.contacts.util.MockSharedPreferences;
29
30@SmallTest
31public class FastScrollingIndexCacheTest extends AndroidTestCase {
32    private MockSharedPreferences mPrefs;
33    private FastScrollingIndexCache mCache;
34
35    private static final String[] TITLES_0 = new String[] {};
36    private static final String[] TITLES_1 = new String[] {"a"};
37    private static final String[] TITLES_2 = new String[] {"", "b"};
38    private static final String[] TITLES_3 = new String[] {"", "b", "aaa"};
39
40    private static final int[] COUNTS_0 = new int[] {};
41    private static final int[] COUNTS_1 = new int[] {1};
42    private static final int[] COUNTS_2 = new int[] {2, 3};
43    private static final int[] COUNTS_3 = new int[] {0, -1, 2};
44
45    private static final String[] PROJECTION_0 = new String[] {};
46    private static final String[] PROJECTION_1 = new String[] {"c1"};
47    private static final String[] PROJECTION_2 = new String[] {"c3", "c4"};
48
49    private static final Uri URI_A = Contacts.CONTENT_URI;
50    private static final Uri URI_B = RawContacts.CONTENT_URI;
51
52    @Override
53    protected void setUp() throws Exception {
54        super.setUp();
55
56        mPrefs = new MockSharedPreferences();
57        mCache = new FastScrollingIndexCache(mPrefs);
58    }
59
60    private void assertBundle(String[] expectedTitles, int[] expectedCounts, Bundle actual) {
61        assertNotNull(actual);
62        MoreAsserts.assertEquals(expectedTitles,
63                actual.getStringArray(ContactCounts.EXTRA_ADDRESS_BOOK_INDEX_TITLES));
64        MoreAsserts.assertEquals(expectedCounts,
65                actual.getIntArray(ContactCounts.EXTRA_ADDRESS_BOOK_INDEX_COUNTS));
66    }
67
68    /**
69     * Test for {@link FastScrollingIndexCache#buildExtraBundleFromValue} and
70     * {@link FastScrollingIndexCache#buildCacheValue}.
71     */
72    public void testBuildCacheValue() {
73        assertBundle(TITLES_0, COUNTS_0,
74                FastScrollingIndexCache.buildExtraBundleFromValue(
75                        FastScrollingIndexCache.buildCacheValue(TITLES_0, COUNTS_0)));
76        assertBundle(TITLES_1, COUNTS_1,
77                FastScrollingIndexCache.buildExtraBundleFromValue(
78                        FastScrollingIndexCache.buildCacheValue(TITLES_1, COUNTS_1)));
79        assertBundle(TITLES_2, COUNTS_2,
80                FastScrollingIndexCache.buildExtraBundleFromValue(
81                        FastScrollingIndexCache.buildCacheValue(TITLES_2, COUNTS_2)));
82    }
83
84    private static final Bundle putAndGetBundle(FastScrollingIndexCache cache, Uri queryUri,
85            String selection, String[] selectionArgs, String sortOrder, String countExpression,
86            String[] titles, int[] counts) {
87        Bundle bundle = FastScrollingIndexCache.buildExtraBundle(titles, counts);
88        cache.put(queryUri, selection, selectionArgs, sortOrder, countExpression, bundle);
89        return bundle;
90    }
91
92    public void testPutAndGet() {
93        // Initially the cache is empty
94        assertNull(mCache.get(null, null, null, null, null));
95        assertNull(mCache.get(URI_A, "*s*", PROJECTION_0, "*so*", "*ce*"));
96        assertNull(mCache.get(URI_A, "*s*", PROJECTION_1, "*so*", "*ce*"));
97        assertNull(mCache.get(URI_B, "s", PROJECTION_2, "so", "ce"));
98
99        // Put...
100        Bundle b;
101        b = putAndGetBundle(mCache, null, null, null, null, null, TITLES_0, COUNTS_0);
102        assertBundle(TITLES_0, COUNTS_0, b);
103
104        b = putAndGetBundle(mCache, URI_A, "*s*", PROJECTION_0, "*so*", "*ce*", TITLES_1, COUNTS_1);
105        assertBundle(TITLES_1, COUNTS_1, b);
106
107        b = putAndGetBundle(mCache, URI_A, "*s*", PROJECTION_1, "*so*", "*ce*", TITLES_2, COUNTS_2);
108        assertBundle(TITLES_2, COUNTS_2, b);
109
110        b = putAndGetBundle(mCache, URI_B, "s", PROJECTION_2, "so", "ce", TITLES_3, COUNTS_3);
111        assertBundle(TITLES_3, COUNTS_3, b);
112
113        // Get...
114        assertBundle(TITLES_0, COUNTS_0, mCache.get(null, null, null, null, null));
115        assertBundle(TITLES_1, COUNTS_1, mCache.get(URI_A, "*s*", PROJECTION_0, "*so*", "*ce*"));
116        assertBundle(TITLES_2, COUNTS_2, mCache.get(URI_A, "*s*", PROJECTION_1, "*so*", "*ce*"));
117        assertBundle(TITLES_3, COUNTS_3, mCache.get(URI_B, "s", PROJECTION_2, "so", "ce"));
118
119        // Invalidate...
120        mCache.invalidate();
121
122        // Get again... Nothing shoul be cached...
123        assertNull(mCache.get(null, null, null, null, null));
124        assertNull(mCache.get(URI_A, "*s*", PROJECTION_0, "*so*", "*ce*"));
125        assertNull(mCache.get(URI_A, "*s*", PROJECTION_1, "*so*", "*ce*"));
126        assertNull(mCache.get(URI_B, "s", PROJECTION_2, "so", "ce"));
127
128        // Put again...
129        b = putAndGetBundle(mCache, null, null, null, null, null, TITLES_0, COUNTS_0);
130        assertBundle(TITLES_0, COUNTS_0, b);
131
132        b = putAndGetBundle(mCache, URI_A, "*s*", PROJECTION_0, "*so*", "*ce*", TITLES_1, COUNTS_1);
133        assertBundle(TITLES_1, COUNTS_1, b);
134
135        b = putAndGetBundle(mCache, URI_A, "*s*", PROJECTION_1, "*so*", "*ce*", TITLES_2, COUNTS_2);
136        assertBundle(TITLES_2, COUNTS_2, b);
137
138        b = putAndGetBundle(mCache, URI_B, "s", PROJECTION_2, "so", "ce", TITLES_2, COUNTS_2);
139        assertBundle(TITLES_2, COUNTS_2, b);
140
141        // Now, create a new cache instance (with the same shared preferences)
142        // It should restore the cache content from the preferences...
143
144        FastScrollingIndexCache cache2 = new FastScrollingIndexCache(mPrefs);
145        assertBundle(TITLES_0, COUNTS_0, cache2.get(null, null, null, null, null));
146        assertBundle(TITLES_1, COUNTS_1, cache2.get(URI_A, "*s*", PROJECTION_0, "*so*", "*ce*"));
147        assertBundle(TITLES_2, COUNTS_2, cache2.get(URI_A, "*s*", PROJECTION_1, "*so*", "*ce*"));
148        assertBundle(TITLES_2, COUNTS_2, cache2.get(URI_B, "s", PROJECTION_2, "so", "ce"));
149    }
150
151    public void testMalformedPreferences() {
152        mPrefs.edit().putString(FastScrollingIndexCache.PREFERENCE_KEY, "123");
153        // get() shouldn't crash
154        assertNull(mCache.get(null, null, null, null, null));
155    }
156}
157