Started implementing ApkProvider tests.

Refactored a couple of common things from AppProviderTest to either
FDroidProviderTest (baseclass) or TestUtils (static methods) where
relevant.
This commit is contained in:
Peter Serwylo 2014-02-18 02:52:02 +11:00
parent 43f8ea0814
commit 85f3232de0
7 changed files with 258 additions and 63 deletions

View File

@ -366,6 +366,11 @@ public class ApkProvider extends FDroidProvider {
String[] apkDetails = apkKeys.split(",");
String[] args = new String[apkDetails.length * 2];
StringBuilder sb = new StringBuilder();
if (apkDetails.length > MAX_APKS_TO_QUERY) {
throw new IllegalArgumentException(
"Cannot query more than " + MAX_APKS_TO_QUERY + ". " +
"You tried to query " + apkDetails.length);
}
for (int i = 0; i < apkDetails.length; i ++) {
String[] parts = apkDetails[i].split(":");
String id = parts[0];

View File

@ -0,0 +1,131 @@
package org.fdroid.fdroid;
import android.content.ContentValues;
import android.database.Cursor;
import org.fdroid.fdroid.data.Apk;
import org.fdroid.fdroid.data.ApkProvider;
import org.fdroid.fdroid.data.AppProvider;
import org.fdroid.fdroid.mock.MockApk;
import java.util.ArrayList;
import java.util.List;
public class ApkProviderTest extends FDroidProviderTest<ApkProvider> {
public ApkProviderTest() {
super(ApkProvider.class, ApkProvider.getAuthority());
}
protected String[] getMinimalProjection() {
return new String[] {
ApkProvider.DataColumns.APK_ID,
ApkProvider.DataColumns.VERSION_CODE,
ApkProvider.DataColumns.NAME
};
}
public void testUris() {
assertInvalidUri(ApkProvider.getAuthority());
assertInvalidUri(AppProvider.getContentUri());
List<Apk> apks = new ArrayList<Apk>(3);
for (int i = 0; i < 10; i ++) {
apks.add(new MockApk("com.example." + i, i));
}
assertValidUri(ApkProvider.getContentUri());
assertValidUri(ApkProvider.getAppUri("org.fdroid.fdroid"));
assertValidUri(ApkProvider.getContentUri(new MockApk("org.fdroid.fdroid", 100)));
assertValidUri(ApkProvider.getContentUri());
assertValidUri(ApkProvider.getContentUri(apks));
assertValidUri(ApkProvider.getContentUri("org.fdroid.fdroid", 100));
assertValidUri(ApkProvider.getRepoUri(1000));
List<Apk> manyApks = new ArrayList<Apk>(ApkProvider.MAX_APKS_TO_QUERY - 5);
for (int i = 0; i < ApkProvider.MAX_APKS_TO_QUERY - 1; i ++) {
manyApks.add(new MockApk("com.example." + i, i));
}
assertValidUri(ApkProvider.getContentUri(manyApks));
manyApks.add(new MockApk("org.fdroid.fdroid.1", 1));
manyApks.add(new MockApk("org.fdroid.fdroid.2", 2));
try {
// Technically, it is a valid URI, because it doesn't
// throw an UnsupportedOperationException. However it
// is still not okay (we run out of bindable parameters
// in the sqlite query.
assertValidUri(ApkProvider.getContentUri(manyApks));
fail();
} catch (IllegalArgumentException e) {
// This is the expected error behaviour.
} catch (Exception e) {
fail();
}
}
public void testQuery() {
Cursor cursor = queryAllApks();
assertNotNull(cursor);
}
private void insertApks(int count) {
for (int i = 0; i < count; i ++) {
insertApk("com.example.test." + i, i);
}
}
public void testInsert() {
// Start with an empty database...
Cursor cursor = queryAllApks();
assertNotNull(cursor);
assertEquals(0, cursor.getCount());
// Insert a new record...
insertApk("org.fdroid.fdroid", 13);
cursor = queryAllApks();
assertNotNull(cursor);
assertEquals(1, cursor.getCount());
// We intentionally throw an IllegalArgumentException if you haven't
// yet called cursor.move*()...
try {
new Apk(cursor);
fail();
} catch (IllegalArgumentException e) {
// Success!
} catch (Exception e) {
fail();
}
// And now we should be able to recover these values from the apk
// value object (because the queryAllApks() helper asks for VERSION_CODE and
// APK_ID.
cursor.moveToFirst();
Apk apk = new Apk(cursor);
assertEquals("org.fdroid.fdroid", apk.id);
assertEquals(13, apk.vercode);
}
public void testIgnore() {
for (int i = 0; i < 10; i ++) {
insertApk("org.fdroid.fdroid", i);
}
}
private Cursor queryAllApks() {
return getMockContentResolver().query(ApkProvider.getContentUri(), getMinimalProjection(), null, null, null);
}
private void insertApk(String id, int versionCode) {
insertApk(id, versionCode, new ContentValues());
}
private void insertApk(String id, int versionCode,
ContentValues additionalValues) {
TestUtils.insertApk(getMockContentResolver(), id, versionCode, additionalValues);
}
}

View File

@ -3,7 +3,6 @@ package org.fdroid.fdroid;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import junit.framework.AssertionFailedError;
import mock.MockCategoryResources;
import mock.MockInstallablePackageManager;
import org.fdroid.fdroid.data.ApkProvider;
@ -11,7 +10,6 @@ import org.fdroid.fdroid.data.App;
import org.fdroid.fdroid.data.AppProvider;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class AppProviderTest extends FDroidProviderTest<AppProvider> {
@ -24,7 +22,6 @@ public class AppProviderTest extends FDroidProviderTest<AppProvider> {
public void setUp() throws Exception {
super.setUp();
getSwappableContext().setResources(new MockCategoryResources());
getSwappableContext().setContentResolver(getMockContentResolver());
}
protected String[] getMinimalProjection() {
@ -75,20 +72,14 @@ public class AppProviderTest extends FDroidProviderTest<AppProvider> {
insertApps(100);
assertAppCount(100, AppProvider.getContentUri());
assertAppCount(0, AppProvider.getInstalledUri());
assertResultCount(100, AppProvider.getContentUri());
assertResultCount(0, AppProvider.getInstalledUri());
for (int i = 10; i < 20; i ++) {
pm.install("com.example.test." + i, i, "v1");
}
assertAppCount(10, AppProvider.getInstalledUri());
}
private void assertAppCount(int expectedCount, Uri uri) {
Cursor cursor = getMockContentResolver().query(uri, getMinimalProjection(), null, null, null);
assertNotNull(cursor);
assertEquals(expectedCount, cursor.getCount());
assertResultCount(10, AppProvider.getInstalledUri());
}
public void testInsert() {
@ -142,7 +133,7 @@ public class AppProviderTest extends FDroidProviderTest<AppProvider> {
"Mineral",
"Vegetable"
};
assertContainsOnly(categories, expected);
TestUtils.assertContainsOnly(categories, expected);
}
public void testCategoriesMultiple() {
@ -160,7 +151,7 @@ public class AppProviderTest extends FDroidProviderTest<AppProvider> {
"Mineral",
"Vegetable"
};
assertContainsOnly(categories, expected);
TestUtils.assertContainsOnly(categories, expected);
insertAppWithCategory("com.example.game", "Game",
"Running,Shooting,Jumping,Bleh,Sneh,Pleh,Blah,Test category," +
@ -188,7 +179,7 @@ public class AppProviderTest extends FDroidProviderTest<AppProvider> {
"With apostrophe's"
};
assertContainsOnly(categoriesLonger, expectedLonger);
TestUtils.assertContainsOnly(categoriesLonger, expectedLonger);
}
private void insertApp(String id, String name) {
@ -207,52 +198,4 @@ public class AppProviderTest extends FDroidProviderTest<AppProvider> {
TestUtils.insertApp(getMockContentResolver(), id, name, additionalValues);
}
private <T extends Comparable> void assertContainsOnly(List<T> actualList, T[] expectedContains) {
List<T> containsList = new ArrayList<T>(expectedContains.length);
Collections.addAll(containsList, expectedContains);
assertContainsOnly(actualList, containsList);
}
private <T> String listToString(List<T> list) {
String string = "[";
for (int i = 0; i < list.size(); i ++) {
if (i > 0) {
string += ", ";
}
string += list.get(i);
}
string += "]";
return string;
}
private <T extends Comparable> void assertContainsOnly(List<T> actualList, List<T> expectedContains) {
if (actualList.size() != expectedContains.size()) {
String message =
"List sizes don't match.\n" +
"Expected: " +
listToString(expectedContains) + "\n" +
"Actual: " +
listToString(actualList);
throw new AssertionFailedError(message);
}
for (T required : expectedContains) {
boolean containsRequired = false;
for (T itemInList : actualList) {
if (required.equals(itemInList)) {
containsRequired = true;
break;
}
}
if (!containsRequired) {
String message =
"List doesn't contain \"" + required + "\".\n" +
"Expected: " +
listToString(expectedContains) + "\n" +
"Actual: " +
listToString(actualList);
throw new AssertionFailedError(message);
}
}
}
}

View File

@ -24,6 +24,13 @@ public abstract class FDroidProviderTest<T extends FDroidProvider> extends Provi
public void setUp() throws Exception {
super.setUp();
Utils.setupInstalledApkCache(new MockInstalledApkCache());
// The *Provider.Helper.* functions tend to take a Context as their
// first parameter. This context is used to connect to the relevant
// content provider. Thus, we need a context that is able to connect
// to the mock content resolver, in order to reach the provider
// under test.
getSwappableContext().setContentResolver(getMockContentResolver());
}
@TargetApi(Build.VERSION_CODES.ECLAIR)
@ -74,4 +81,9 @@ public abstract class FDroidProviderTest<T extends FDroidProvider> extends Provi
*/
protected abstract String[] getMinimalProjection();
protected void assertResultCount(int expectedCount, Uri uri) {
Cursor cursor = getMockContentResolver().query(uri, getMinimalProjection(), null, null, null);
assertNotNull(cursor);
assertEquals(expectedCount, cursor.getCount());
}
}

View File

@ -2,10 +2,65 @@ package org.fdroid.fdroid;
import android.content.*;
import android.net.Uri;
import android.test.mock.MockContentResolver;
import junit.framework.AssertionFailedError;
import org.fdroid.fdroid.data.ApkProvider;
import org.fdroid.fdroid.data.AppProvider;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class TestUtils {
public static <T extends Comparable> void assertContainsOnly(List<T> actualList, T[] expectedContains) {
List<T> containsList = new ArrayList<T>(expectedContains.length);
Collections.addAll(containsList, expectedContains);
assertContainsOnly(actualList, containsList);
}
public static <T> String listToString(List<T> list) {
String string = "[";
for (int i = 0; i < list.size(); i ++) {
if (i > 0) {
string += ", ";
}
string += list.get(i);
}
string += "]";
return string;
}
public static <T extends Comparable> void assertContainsOnly(List<T> actualList, List<T> expectedContains) {
if (actualList.size() != expectedContains.size()) {
String message =
"List sizes don't match.\n" +
"Expected: " +
listToString(expectedContains) + "\n" +
"Actual: " +
listToString(actualList);
throw new AssertionFailedError(message);
}
for (T required : expectedContains) {
boolean containsRequired = false;
for (T itemInList : actualList) {
if (required.equals(itemInList)) {
containsRequired = true;
break;
}
}
if (!containsRequired) {
String message =
"List doesn't contain \"" + required + "\".\n" +
"Expected: " +
listToString(expectedContains) + "\n" +
"Actual: " +
listToString(actualList);
throw new AssertionFailedError(message);
}
}
}
public static void insertApp(ContentResolver resolver, String id, String name, ContentValues additionalValues) {
ContentValues values = new ContentValues();
@ -27,4 +82,25 @@ public class TestUtils {
resolver.insert(uri, values);
}
public static void insertApk(ContentResolver resolver, String id, int versionCode, ContentValues additionalValues) {
ContentValues values = new ContentValues();
values.put(ApkProvider.DataColumns.APK_ID, id);
values.put(ApkProvider.DataColumns.VERSION_CODE, versionCode);
// Required fields (NOT NULL in the database).
values.put(ApkProvider.DataColumns.REPO_ID, 1);
values.put(ApkProvider.DataColumns.VERSION, "The good one");
values.put(ApkProvider.DataColumns.HASH, "11111111aaaaaaaa");
values.put(ApkProvider.DataColumns.NAME, "Test Apk");
values.put(ApkProvider.DataColumns.SIZE, 10000);
values.put(ApkProvider.DataColumns.IS_COMPATIBLE, 1);
values.putAll(additionalValues);
Uri uri = ApkProvider.getContentUri();
resolver.insert(uri, values);
}
}

View File

@ -0,0 +1,12 @@
package org.fdroid.fdroid.mock;
import org.fdroid.fdroid.data.Apk;
public class MockApk extends Apk {
public MockApk(String id, int versionCode) {
this.id = id;
this.vercode = versionCode;
}
}

View File

@ -0,0 +1,16 @@
package org.fdroid.fdroid.mock;
import org.fdroid.fdroid.data.App;
public class MockApp extends App {
public MockApp(String id) {
this(id, "App " + id);
}
public MockApp(String id, String name) {
this.id = id;
this.name = name;
}
}