add some unit tests for RecipientLoader

This commit is contained in:
Vincent Breitmoser 2017-10-05 00:02:17 +02:00
parent fca4630177
commit c2171b5161
2 changed files with 161 additions and 15 deletions

View file

@ -85,6 +85,7 @@ public class RecipientLoader extends AsyncTaskLoader<List<Recipient>> {
private final Uri contactUri; private final Uri contactUri;
private final Uri lookupKeyUri; private final Uri lookupKeyUri;
private final String cryptoProvider; private final String cryptoProvider;
private final ContentResolver contentResolver;
private List<Recipient> cachedRecipients; private List<Recipient> cachedRecipients;
private ForceLoadContentObserver observerContact, observerKey; private ForceLoadContentObserver observerContact, observerKey;
@ -97,6 +98,8 @@ public class RecipientLoader extends AsyncTaskLoader<List<Recipient>> {
this.addresses = null; this.addresses = null;
this.contactUri = null; this.contactUri = null;
this.cryptoProvider = cryptoProvider; this.cryptoProvider = cryptoProvider;
contentResolver = context.getContentResolver();
} }
public RecipientLoader(Context context, String cryptoProvider, Address... addresses) { public RecipientLoader(Context context, String cryptoProvider, Address... addresses) {
@ -106,6 +109,8 @@ public class RecipientLoader extends AsyncTaskLoader<List<Recipient>> {
this.contactUri = null; this.contactUri = null;
this.cryptoProvider = cryptoProvider; this.cryptoProvider = cryptoProvider;
this.lookupKeyUri = null; this.lookupKeyUri = null;
contentResolver = context.getContentResolver();
} }
public RecipientLoader(Context context, String cryptoProvider, Uri contactUri, boolean isLookupKey) { public RecipientLoader(Context context, String cryptoProvider, Uri contactUri, boolean isLookupKey) {
@ -115,6 +120,8 @@ public class RecipientLoader extends AsyncTaskLoader<List<Recipient>> {
this.contactUri = isLookupKey ? null : contactUri; this.contactUri = isLookupKey ? null : contactUri;
this.lookupKeyUri = isLookupKey ? contactUri : null; this.lookupKeyUri = isLookupKey ? contactUri : null;
this.cryptoProvider = cryptoProvider; this.cryptoProvider = cryptoProvider;
contentResolver = context.getContentResolver();
} }
@Override @Override
@ -154,7 +161,7 @@ public class RecipientLoader extends AsyncTaskLoader<List<Recipient>> {
Cursor cursor; Cursor cursor;
try { try {
Uri queryUri = Uri.parse("content://" + cryptoProvider + ".provider.exported/autocrypt_status"); Uri queryUri = Uri.parse("content://" + cryptoProvider + ".provider.exported/autocrypt_status");
cursor = getContext().getContentResolver().query(queryUri, PROJECTION_CRYPTO_ADDRESSES, null, cursor = contentResolver.query(queryUri, PROJECTION_CRYPTO_ADDRESSES, null,
new String[] { "%" + query + "%" }, null); new String[] { "%" + query + "%" }, null);
if (cursor == null) { if (cursor == null) {
@ -195,7 +202,7 @@ public class RecipientLoader extends AsyncTaskLoader<List<Recipient>> {
private void fillContactDataFromEmailContentUri(Uri contactUri, List<Recipient> recipients, private void fillContactDataFromEmailContentUri(Uri contactUri, List<Recipient> recipients,
Map<String, Recipient> recipientMap) { Map<String, Recipient> recipientMap) {
Cursor cursor = getContext().getContentResolver().query(contactUri, PROJECTION, null, null, null); Cursor cursor = contentResolver.query(contactUri, PROJECTION, null, null, null);
if (cursor == null) { if (cursor == null) {
return; return;
@ -207,14 +214,14 @@ public class RecipientLoader extends AsyncTaskLoader<List<Recipient>> {
private void fillContactDataFromLookupKey(Uri lookupKeyUri, List<Recipient> recipients, private void fillContactDataFromLookupKey(Uri lookupKeyUri, List<Recipient> recipients,
Map<String, Recipient> recipientMap) { Map<String, Recipient> recipientMap) {
// We could use the contact id from the URI directly, but getting it from the lookup key is safer // We could use the contact id from the URI directly, but getting it from the lookup key is safer
Uri contactContentUri = Contacts.lookupContact(getContext().getContentResolver(), lookupKeyUri); Uri contactContentUri = Contacts.lookupContact(contentResolver, lookupKeyUri);
if (contactContentUri == null) { if (contactContentUri == null) {
return; return;
} }
String contactIdStr = getContactIdFromContactUri(contactContentUri); String contactIdStr = getContactIdFromContactUri(contactContentUri);
Cursor cursor = getContext().getContentResolver().query( Cursor cursor = contentResolver.query(
ContactsContract.CommonDataKinds.Email.CONTENT_URI, ContactsContract.CommonDataKinds.Email.CONTENT_URI,
PROJECTION, ContactsContract.CommonDataKinds.Email.CONTACT_ID + "=?", PROJECTION, ContactsContract.CommonDataKinds.Email.CONTACT_ID + "=?",
new String[] { contactIdStr }, null); new String[] { contactIdStr }, null);
@ -236,7 +243,7 @@ public class RecipientLoader extends AsyncTaskLoader<List<Recipient>> {
Uri queryUriForNickname = ContactsContract.Data.CONTENT_URI; Uri queryUriForNickname = ContactsContract.Data.CONTENT_URI;
return getContext().getContentResolver().query(queryUriForNickname, return contentResolver.query(queryUriForNickname,
PROJECTION_NICKNAME, PROJECTION_NICKNAME,
ContactsContract.CommonDataKinds.Nickname.NAME + " LIKE ? AND " + ContactsContract.CommonDataKinds.Nickname.NAME + " LIKE ? AND " +
Data.MIMETYPE + " = ?", Data.MIMETYPE + " = ?",
@ -261,7 +268,7 @@ public class RecipientLoader extends AsyncTaskLoader<List<Recipient>> {
private void registerContentObserver() { private void registerContentObserver() {
if (observerContact != null) { if (observerContact != null) {
observerContact = new ForceLoadContentObserver(); observerContact = new ForceLoadContentObserver();
getContext().getContentResolver().registerContentObserver(Email.CONTENT_URI, false, observerContact); contentResolver.registerContentObserver(Email.CONTENT_URI, false, observerContact);
} }
} }
@ -271,8 +278,6 @@ public class RecipientLoader extends AsyncTaskLoader<List<Recipient>> {
boolean hasContact = false; boolean hasContact = false;
final ContentResolver contentResolver = getContext().getContentResolver();
Uri queryUri = Email.CONTENT_URI; Uri queryUri = Email.CONTENT_URI;
Cursor nicknameCursor = getNicknameCursor(nickname); Cursor nicknameCursor = getNicknameCursor(nickname);
@ -303,8 +308,6 @@ public class RecipientLoader extends AsyncTaskLoader<List<Recipient>> {
private boolean fillContactDataFromNameAndEmail(String query, List<Recipient> recipients, private boolean fillContactDataFromNameAndEmail(String query, List<Recipient> recipients,
Map<String, Recipient> recipientMap) { Map<String, Recipient> recipientMap) {
ContentResolver contentResolver = getContext().getContentResolver();
query = "%" + query + "%"; query = "%" + query + "%";
Uri queryUri = Email.CONTENT_URI; Uri queryUri = Email.CONTENT_URI;
@ -391,8 +394,7 @@ public class RecipientLoader extends AsyncTaskLoader<List<Recipient>> {
Cursor cursor; Cursor cursor;
Uri queryUri = Uri.parse("content://" + cryptoProvider + ".provider.exported/autocrypt_status"); Uri queryUri = Uri.parse("content://" + cryptoProvider + ".provider.exported/autocrypt_status");
try { try {
cursor = getContext().getContentResolver().query(queryUri, PROJECTION_CRYPTO_STATUS, null, cursor = contentResolver.query(queryUri, PROJECTION_CRYPTO_STATUS, null, recipientAddresses, null);
recipientAddresses, null);
} catch (SecurityException e) { } catch (SecurityException e) {
// TODO escalate error to crypto status? // TODO escalate error to crypto status?
return; return;
@ -436,7 +438,7 @@ public class RecipientLoader extends AsyncTaskLoader<List<Recipient>> {
if (observerKey != null) { if (observerKey != null) {
observerKey = new ForceLoadContentObserver(); observerKey = new ForceLoadContentObserver();
getContext().getContentResolver().registerContentObserver(queryUri, false, observerKey); contentResolver.registerContentObserver(queryUri, false, observerKey);
} }
} }
@ -472,10 +474,10 @@ public class RecipientLoader extends AsyncTaskLoader<List<Recipient>> {
super.onAbandon(); super.onAbandon();
if (observerKey != null) { if (observerKey != null) {
getContext().getContentResolver().unregisterContentObserver(observerKey); contentResolver.unregisterContentObserver(observerKey);
} }
if (observerContact != null) { if (observerContact != null) {
getContext().getContentResolver().unregisterContentObserver(observerContact); contentResolver.unregisterContentObserver(observerContact);
} }
} }
} }

View file

@ -0,0 +1,144 @@
package com.fsck.k9.activity.compose;
import java.util.List;
import android.content.ContentResolver;
import android.content.Context;
import android.database.MatrixCursor;
import android.net.Uri;
import com.fsck.k9.K9RobolectricTestRunner;
import com.fsck.k9.mail.Address;
import com.fsck.k9.view.RecipientSelectView.Recipient;
import com.fsck.k9.view.RecipientSelectView.RecipientCryptoStatus;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
import static org.mockito.AdditionalMatchers.aryEq;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@SuppressWarnings("WeakerAccess")
@RunWith(K9RobolectricTestRunner.class)
public class RecipientLoaderTest {
static final String CRYPTO_PROVIDER = "cryptoProvider";
static final String[] PROJECTION_CRYPTO_ADDRESSES = { "address", "uid_address" };
static final String[] PROJECTION_CRYPTO_STATUS = { "address", "uid_key_status", "autocrypt_key_status" };
static final Address CONTACT_ADDRESS_1 = Address.parse("Contact Name <address@example.org>")[0];
static final Address CONTACT_ADDRESS_2 = Address.parse("Other Contact Name <address_two@example.org>")[0];
static final String QUERYSTRING = "querystring";
Context context;
ContentResolver contentResolver;
@Before
public void setUp() throws Exception {
context = mock(Context.class);
contentResolver = mock(ContentResolver.class);
when(context.getContentResolver()).thenReturn(contentResolver);
}
@Test
public void queryCryptoProvider() throws Exception {
RecipientLoader recipientLoader = new RecipientLoader(context, CRYPTO_PROVIDER, QUERYSTRING);
setupQueryCryptoProvider("%" + QUERYSTRING + "%", CONTACT_ADDRESS_1, CONTACT_ADDRESS_2);
List<Recipient> recipients = recipientLoader.loadInBackground();
assertEquals(2, recipients.size());
assertEquals(CONTACT_ADDRESS_1, recipients.get(0).address);
assertEquals(CONTACT_ADDRESS_2, recipients.get(1).address);
assertEquals(RecipientCryptoStatus.UNAVAILABLE, recipients.get(0).getCryptoStatus());
}
@Test
public void queryCryptoStatus_unavailable() throws Exception {
RecipientLoader recipientLoader = new RecipientLoader(context, CRYPTO_PROVIDER, CONTACT_ADDRESS_1);
setupCryptoProviderStatus(CONTACT_ADDRESS_1, "0", "0");
List<Recipient> recipients = recipientLoader.loadInBackground();
assertEquals(1, recipients.size());
Recipient recipient = recipients.get(0);
assertEquals(CONTACT_ADDRESS_1, recipient.address);
assertEquals(RecipientCryptoStatus.UNAVAILABLE, recipient.getCryptoStatus());
}
@Test
public void queryCryptoStatus_autocrypt_untrusted() throws Exception {
RecipientLoader recipientLoader = new RecipientLoader(context, CRYPTO_PROVIDER, CONTACT_ADDRESS_1);
setupCryptoProviderStatus(CONTACT_ADDRESS_1, "0", "1");
List<Recipient> recipients = recipientLoader.loadInBackground();
assertEquals(1, recipients.size());
Recipient recipient = recipients.get(0);
assertEquals(CONTACT_ADDRESS_1, recipient.address);
assertEquals(RecipientCryptoStatus.AVAILABLE_UNTRUSTED, recipient.getCryptoStatus());
}
@Test
public void queryCryptoStatus_autocrypt_trusted() throws Exception {
RecipientLoader recipientLoader = new RecipientLoader(context, CRYPTO_PROVIDER, CONTACT_ADDRESS_1);
setupCryptoProviderStatus(CONTACT_ADDRESS_1, "0", "2");
List<Recipient> recipients = recipientLoader.loadInBackground();
assertEquals(1, recipients.size());
Recipient recipient = recipients.get(0);
assertEquals(CONTACT_ADDRESS_1, recipient.address);
assertEquals(RecipientCryptoStatus.AVAILABLE_TRUSTED, recipient.getCryptoStatus());
}
@Test
public void queryCryptoStatus_withHigherUidStatus() throws Exception {
RecipientLoader recipientLoader = new RecipientLoader(context, CRYPTO_PROVIDER, CONTACT_ADDRESS_1);
setupCryptoProviderStatus(CONTACT_ADDRESS_1, "2", "1");
List<Recipient> recipients = recipientLoader.loadInBackground();
assertEquals(1, recipients.size());
Recipient recipient = recipients.get(0);
assertEquals(CONTACT_ADDRESS_1, recipient.address);
assertEquals(RecipientCryptoStatus.AVAILABLE_TRUSTED, recipient.getCryptoStatus());
}
private void setupQueryCryptoProvider(String queriedAddress, Address... contactAddresses) {
MatrixCursor cursor = new MatrixCursor(PROJECTION_CRYPTO_ADDRESSES);
for (Address contactAddress : contactAddresses) {
cursor.addRow(new String[] { queriedAddress, contactAddress.toString() });
}
when(contentResolver
.query(eq(Uri.parse("content://" + CRYPTO_PROVIDER + ".provider.exported/autocrypt_status")),
aryEq(PROJECTION_CRYPTO_ADDRESSES), any(String.class),
aryEq(new String[] { queriedAddress }),
any(String.class))).thenReturn(cursor);
}
private void setupCryptoProviderStatus(Address address, String uidStatus, String autocryptStatus) {
MatrixCursor cursorCryptoStatus = new MatrixCursor(PROJECTION_CRYPTO_STATUS);
cursorCryptoStatus.addRow(new String[] { address.getAddress(), uidStatus, autocryptStatus });
when(contentResolver
.query(eq(Uri.parse("content://" + CRYPTO_PROVIDER + ".provider.exported/autocrypt_status")),
aryEq(PROJECTION_CRYPTO_STATUS), any(String.class),
aryEq(new String[] { address.getAddress() }),
any(String.class))).thenReturn(cursorCryptoStatus);
}
}