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