1 /* 2 * Copyright (C) 2014 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 17 package com.android.inputmethod.latin; 18 19 import static org.junit.Assert.assertEquals; 20 import static org.junit.Assert.assertFalse; 21 import static org.junit.Assert.assertTrue; 22 23 import android.content.ContentResolver; 24 import android.content.Context; 25 import android.database.Cursor; 26 import android.database.MatrixCursor; 27 import android.net.Uri; 28 import android.provider.ContactsContract; 29 import android.provider.ContactsContract.Contacts; 30 import android.test.RenamingDelegatingContext; 31 import android.test.mock.MockContentProvider; 32 import android.test.mock.MockContentResolver; 33 34 import androidx.test.InstrumentationRegistry; 35 import androidx.test.filters.SmallTest; 36 import androidx.test.runner.AndroidJUnit4; 37 38 import com.android.inputmethod.latin.ContactsDictionaryConstants; 39 import com.android.inputmethod.latin.ContactsManager; 40 41 import org.junit.Before; 42 import org.junit.Test; 43 import org.junit.runner.RunWith; 44 45 import java.util.ArrayList; 46 import java.util.HashMap; 47 import java.util.concurrent.TimeUnit; 48 49 /** 50 * Tests for {@link ContactsManager} 51 */ 52 @SmallTest 53 @RunWith(AndroidJUnit4.class) 54 public class ContactsManagerTest { 55 56 private ContactsManager mManager; 57 private FakeContactsContentProvider mFakeContactsContentProvider; 58 private MatrixCursor mMatrixCursor; 59 60 private final static float EPSILON = 0.00001f; 61 62 @Before setUp()63 public void setUp() throws Exception { 64 // Fake content provider 65 mFakeContactsContentProvider = new FakeContactsContentProvider(); 66 mMatrixCursor = new MatrixCursor(ContactsDictionaryConstants.PROJECTION); 67 // Add the fake content provider to fake content resolver. 68 final MockContentResolver contentResolver = new MockContentResolver(); 69 contentResolver.addProvider(ContactsContract.AUTHORITY, mFakeContactsContentProvider); 70 // Add the fake content resolver to a fake context. 71 final ContextWithMockContentResolver context = 72 new ContextWithMockContentResolver(InstrumentationRegistry.getTargetContext()); 73 context.setContentResolver(contentResolver); 74 75 mManager = new ContactsManager(context); 76 } 77 78 @Test testGetValidNames()79 public void testGetValidNames() { 80 final String contactName1 = "firstname last-name"; 81 final String contactName2 = "larry"; 82 mMatrixCursor.addRow(new Object[] { 1, contactName1, 0, 0, 0 }); 83 mMatrixCursor.addRow(new Object[] { 2, null /* null name */, 0, 0, 0 }); 84 mMatrixCursor.addRow(new Object[] { 3, contactName2, 0, 0, 0 }); 85 mMatrixCursor.addRow(new Object[] { 4, "floopy@example.com" /* invalid name */, 0, 0, 0 }); 86 mMatrixCursor.addRow(new Object[] { 5, "news-group" /* invalid name */, 0, 0, 0 }); 87 mFakeContactsContentProvider.addQueryResult(Contacts.CONTENT_URI, mMatrixCursor); 88 89 final ArrayList<String> validNames = mManager.getValidNames(Contacts.CONTENT_URI); 90 assertEquals(2, validNames.size()); 91 assertEquals(contactName1, validNames.get(0)); 92 assertEquals(contactName2, validNames.get(1)); 93 } 94 95 @Test testGetValidNamesAffinity()96 public void testGetValidNamesAffinity() { 97 final long now = System.currentTimeMillis(); 98 final long month_ago = now - TimeUnit.MILLISECONDS.convert(31, TimeUnit.DAYS); 99 for (int i = 0; i < ContactsManager.MAX_CONTACT_NAMES + 10; ++i) { 100 mMatrixCursor.addRow(new Object[] { i, "name" + i, i, now, 1 }); 101 } 102 mFakeContactsContentProvider.addQueryResult(Contacts.CONTENT_URI, mMatrixCursor); 103 104 final ArrayList<String> validNames = mManager.getValidNames(Contacts.CONTENT_URI); 105 assertEquals(ContactsManager.MAX_CONTACT_NAMES, validNames.size()); 106 for (int i = 0; i < 10; ++i) { 107 assertFalse(validNames.contains("name" + i)); 108 } 109 for (int i = 10; i < ContactsManager.MAX_CONTACT_NAMES + 10; ++i) { 110 assertTrue(validNames.contains("name" + i)); 111 } 112 } 113 114 @Test testComputeAffinity()115 public void testComputeAffinity() { 116 final long now = System.currentTimeMillis(); 117 final long month_ago = now - TimeUnit.MILLISECONDS.convert(31, TimeUnit.DAYS); 118 mMatrixCursor.addRow(new Object[] { 1, "name", 1, month_ago, 1 }); 119 mFakeContactsContentProvider.addQueryResult(Contacts.CONTENT_URI, mMatrixCursor); 120 121 Cursor cursor = mFakeContactsContentProvider.query(Contacts.CONTENT_URI, 122 ContactsDictionaryConstants.PROJECTION_ID_ONLY, null, null, null); 123 cursor.moveToFirst(); 124 ContactsManager.RankedContact contact = new ContactsManager.RankedContact(cursor); 125 contact.computeAffinity(1, month_ago); 126 assertEquals(contact.getAffinity(), 1.0f, EPSILON); 127 contact.computeAffinity(2, now); 128 assertEquals(contact.getAffinity(), (2.0f/3.0f + (float)Math.pow(0.5, 3) + 1.0f) / 3, 129 EPSILON); 130 } 131 132 @Test testGetCount()133 public void testGetCount() { 134 mMatrixCursor.addRow(new Object[] { 1, "firstname", 0, 0, 0 }); 135 mMatrixCursor.addRow(new Object[] { 2, null /* null name */, 0, 0, 0 }); 136 mMatrixCursor.addRow(new Object[] { 3, "larry", 0, 0, 0 }); 137 mMatrixCursor.addRow(new Object[] { 4, "floopy@example.com" /* invalid name */, 0, 0, 0 }); 138 mFakeContactsContentProvider.addQueryResult(Contacts.CONTENT_URI, mMatrixCursor); 139 assertEquals(4, mManager.getContactCount()); 140 } 141 142 143 static class ContextWithMockContentResolver extends RenamingDelegatingContext { 144 private ContentResolver contentResolver; 145 setContentResolver(final ContentResolver contentResolver)146 public void setContentResolver(final ContentResolver contentResolver) { 147 this.contentResolver = contentResolver; 148 } 149 ContextWithMockContentResolver(final Context targetContext)150 public ContextWithMockContentResolver(final Context targetContext) { 151 super(targetContext, "test"); 152 } 153 154 @Override getContentResolver()155 public ContentResolver getContentResolver() { 156 return contentResolver; 157 } 158 } 159 160 static class FakeContactsContentProvider extends MockContentProvider { 161 private final HashMap<String, MatrixCursor> mQueryCursorMapForTestExpectations = 162 new HashMap<>(); 163 164 @Override query(final Uri uri, final String[] projection, final String selection, final String[] selectionArgs, final String sortOrder)165 public Cursor query(final Uri uri, final String[] projection, final String selection, 166 final String[] selectionArgs, final String sortOrder) { 167 return mQueryCursorMapForTestExpectations.get(uri.toString()); 168 } 169 reset()170 public void reset() { 171 mQueryCursorMapForTestExpectations.clear(); 172 } 173 addQueryResult(final Uri uri, final MatrixCursor cursor)174 public void addQueryResult(final Uri uri, final MatrixCursor cursor) { 175 mQueryCursorMapForTestExpectations.put(uri.toString(), cursor); 176 } 177 } 178 } 179