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
17package com.android.email.activity;
18
19import com.android.email.activity.ContactStatusLoader.Result;
20
21import android.content.Context;
22import android.content.pm.ProviderInfo;
23import android.database.Cursor;
24import android.database.MatrixCursor;
25import android.graphics.Bitmap;
26import android.net.Uri;
27import android.provider.ContactsContract;
28import android.provider.ContactsContract.StatusUpdates;
29import android.test.ProviderTestCase2;
30import android.test.mock.MockContentProvider;
31
32import java.io.ByteArrayOutputStream;
33import java.util.ArrayList;
34import java.util.Queue;
35import java.util.concurrent.LinkedBlockingQueue;
36
37import junit.framework.Assert;
38
39/**
40 * Test for {@link ContactStatusLoader}
41 *
42 * Unfortunately this doesn't check {@link ContactStatusLoader.Result#mLookupUri}, because we don't
43 * (shouldn't) know how {@link android.provider.ContactsContract.Data#getContactLookupUri} is
44 * implemented.
45 */
46public class ContactStatusLoaderTest
47        extends ProviderTestCase2<ContactStatusLoaderTest.MockContactProvider> {
48    private static final String EMAIL = "a@b.c";
49
50    private MockContactProvider mProvider;
51
52    public ContactStatusLoaderTest() {
53        super(MockContactProvider.class, ContactsContract.AUTHORITY);
54    }
55
56    @Override
57    protected void setUp() throws Exception {
58        super.setUp();
59        mProvider = getProvider();
60    }
61
62    // Contact doesn't exist
63    public void testContactNotFound() {
64        // Insert empty cursor
65        mProvider.mCursors.offer(
66                new MatrixCursor(ContactStatusLoader.PROJECTION_PHOTO_ID_PRESENCE));
67
68        // Load!
69        ContactStatusLoader l = new ContactStatusLoader(getMockContext(), EMAIL);
70        Result r = l.loadInBackground();
71
72        // Check input to the provider
73        assertEquals(1, mProvider.mUris.size());
74        assertEquals("content://com.android.contacts/data/emails/lookup/a%40b.c",
75                mProvider.mUris.get(0));
76
77        // Check result
78        assertNull(r.mPhoto);
79        assertEquals(ContactStatusLoader.PRESENCE_UNKNOWN_RESOURCE_ID, r.mPresenceResId);
80    }
81
82    // Contact doesn't exist -- provider returns null for the first query
83    public void testNull() {
84        // No cursor prepared. (Mock provider will return null)
85
86        // Load!
87        ContactStatusLoader l = new ContactStatusLoader(getMockContext(), EMAIL);
88        Result r = l.loadInBackground();
89
90        // Check result
91        assertNull(r.mPhoto);
92        assertEquals(ContactStatusLoader.PRESENCE_UNKNOWN_RESOURCE_ID, r.mPresenceResId);
93    }
94
95    // Contact exists, but no photo
96    public void testNoPhoto() {
97        // Result for the first query (the one for photo-id)
98        MatrixCursor cursor1 = new MatrixCursor(ContactStatusLoader.PROJECTION_PHOTO_ID_PRESENCE);
99        cursor1.addRow(new Object[]{12345, StatusUpdates.AWAY});
100        mProvider.mCursors.offer(cursor1);
101
102        // Empty cursor for the second query
103        mProvider.mCursors.offer(new MatrixCursor(ContactStatusLoader.PHOTO_PROJECTION));
104
105        // Load!
106        ContactStatusLoader l = new ContactStatusLoader(getMockContext(), EMAIL);
107        Result r = l.loadInBackground();
108
109        // Check input to the provider
110        // We should have had at least two queries from loadInBackground.
111        // There can be extra queries from getContactLookupUri(), but this test shouldn't know
112        // the details, so use ">= 2".
113        assertTrue(mProvider.mUris.size() >= 2);
114        assertEquals("content://com.android.contacts/data/emails/lookup/a%40b.c",
115                mProvider.mUris.get(0));
116        assertEquals("content://com.android.contacts/data/12345",
117                mProvider.mUris.get(1));
118
119        // Check result
120        assertNull(r.mPhoto); // no photo
121        assertEquals(android.R.drawable.presence_away, r.mPresenceResId);
122    }
123
124    // Contact exists, but no photo (provider returns null for the second query)
125    public void testNull2() {
126        // Result for the first query (the one for photo-id)
127        MatrixCursor cursor1 = new MatrixCursor(ContactStatusLoader.PROJECTION_PHOTO_ID_PRESENCE);
128        cursor1.addRow(new Object[]{12345, StatusUpdates.AWAY});
129        mProvider.mCursors.offer(cursor1);
130
131        // No cursor for the second query
132
133        // Load!
134        ContactStatusLoader l = new ContactStatusLoader(getMockContext(), EMAIL);
135        Result r = l.loadInBackground();
136
137        // Check result
138        assertNull(r.mPhoto); // no photo
139        assertEquals(android.R.drawable.presence_away, r.mPresenceResId);
140    }
141
142    // Contact exists, with a photo
143    public void testWithPhoto() {
144        // Result for the first query (the one for photo-id)
145        MatrixCursor cursor1 = new MatrixCursor(ContactStatusLoader.PROJECTION_PHOTO_ID_PRESENCE);
146        cursor1.addRow(new Object[]{12345, StatusUpdates.AWAY});
147        mProvider.mCursors.offer(cursor1);
148
149        // Prepare for the second query.
150        MatrixCursor cursor2 = new PhotoCursor(createJpegData(10, 20));
151        mProvider.mCursors.offer(cursor2);
152
153        // Load!
154        ContactStatusLoader l = new ContactStatusLoader(getMockContext(), EMAIL);
155        Result r = l.loadInBackground();
156
157        // Check result
158        assertNotNull(r.mPhoto);
159        assertEquals(10, r.mPhoto.getWidth());
160        assertEquals(android.R.drawable.presence_away, r.mPresenceResId);
161    }
162
163    private static byte[] createJpegData(int width, int height) {
164        Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
165        ByteArrayOutputStream out = new ByteArrayOutputStream();
166        bitmap.compress(Bitmap.CompressFormat.JPEG, 50, out);
167        return out.toByteArray();
168    }
169
170    // MatrixCursor doesn't support getBlob, so use this...
171    private static class PhotoCursor extends MatrixCursor {
172        private final byte[] mBlob;
173
174        public PhotoCursor(byte[] blob) {
175            super(ContactStatusLoader.PHOTO_PROJECTION);
176            mBlob = blob;
177            addRow(new Object[] {null}); // Add dummy row
178        }
179
180        @Override
181        public byte[] getBlob(int column) {
182            Assert.assertEquals(0, column);
183            return mBlob;
184        }
185    }
186
187    public static class MockContactProvider extends MockContentProvider {
188        public ArrayList<String> mUris = new ArrayList<String>();
189
190        public final Queue<Cursor> mCursors = new LinkedBlockingQueue<Cursor>();
191
192        @Override
193        public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
194                String sortOrder) {
195            mUris.add(uri.toString());
196            return mCursors.poll();
197        }
198
199        @Override
200        public void attachInfo(Context context, ProviderInfo info) {
201        }
202    }
203}
204