package org.fdroid.fdroid.data; import android.app.Application; import android.content.ContentValues; import android.database.Cursor; import android.net.Uri; import org.fdroid.fdroid.BuildConfig; import org.fdroid.fdroid.data.Schema.InstalledAppTable.Cols; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricGradleTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import org.robolectric.shadows.ShadowContentResolver; import static org.fdroid.fdroid.Assert.assertIsInstalledVersionInDb; import static org.fdroid.fdroid.Assert.assertResultCount; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import java.util.Map; // TODO: Use sdk=24 when Robolectric supports this @Config(constants = BuildConfig.class, application = Application.class, sdk = 23) @RunWith(RobolectricGradleTestRunner.class) public class InstalledAppProviderTest extends FDroidProviderTest { @Before public void setup() { ShadowContentResolver.registerProvider(InstalledAppProvider.getAuthority(), new InstalledAppProvider()); } @Test public void insertSingleApp() { Map<String, Long> foundBefore = InstalledAppProvider.Helper.all(RuntimeEnvironment.application); assertEquals(foundBefore.size(), 0); ContentValues values = new ContentValues(); values.put(Cols.PACKAGE_NAME, "org.example.test-app"); values.put(Cols.APPLICATION_LABEL, "Test App"); values.put(Cols.VERSION_CODE, 1021); values.put(Cols.VERSION_NAME, "Longhorn"); values.put(Cols.HASH, "has of test app"); values.put(Cols.HASH_TYPE, "fake hash type"); values.put(Cols.LAST_UPDATE_TIME, 100000000L); values.put(Cols.SIGNATURE, "000111222333444555666777888999aaabbbcccdddeeefff"); contentResolver.insert(InstalledAppProvider.getContentUri(), values); Map<String, Long> foundAfter = InstalledAppProvider.Helper.all(RuntimeEnvironment.application); assertEquals(1, foundAfter.size()); assertEquals(100000000L, foundAfter.get("org.example.test-app").longValue()); Cursor cursor = contentResolver.query(InstalledAppProvider.getAppUri("org.example.test-app"), Cols.ALL, null, null, null); assertEquals(cursor.getCount(), 1); cursor.moveToFirst(); assertEquals("org.example.test-app", cursor.getString(cursor.getColumnIndex(Cols.PACKAGE_NAME))); assertEquals("Test App", cursor.getString(cursor.getColumnIndex(Cols.APPLICATION_LABEL))); assertEquals(1021, cursor.getInt(cursor.getColumnIndex(Cols.VERSION_CODE))); assertEquals("Longhorn", cursor.getString(cursor.getColumnIndex(Cols.VERSION_NAME))); assertEquals("has of test app", cursor.getString(cursor.getColumnIndex(Cols.HASH))); assertEquals("fake hash type", cursor.getString(cursor.getColumnIndex(Cols.HASH_TYPE))); assertEquals(100000000L, cursor.getLong(cursor.getColumnIndex(Cols.LAST_UPDATE_TIME))); assertEquals("000111222333444555666777888999aaabbbcccdddeeefff", cursor.getString(cursor.getColumnIndex(Cols.SIGNATURE))); cursor.close(); } @Test public void testInsert() { assertResultCount(contentResolver, 0, InstalledAppProvider.getContentUri()); insertInstalledApp("com.example.com1", 1, "v1"); insertInstalledApp("com.example.com2", 2, "v2"); insertInstalledApp("com.example.com3", 3, "v3"); assertResultCount(contentResolver, 3, InstalledAppProvider.getContentUri()); assertIsInstalledVersionInDb(contentResolver, "com.example.com1", 1, "v1"); assertIsInstalledVersionInDb(contentResolver, "com.example.com2", 2, "v2"); assertIsInstalledVersionInDb(contentResolver, "com.example.com3", 3, "v3"); } @Test public void testUpdate() { insertInstalledApp("com.example.app1", 10, "1.0"); insertInstalledApp("com.example.app2", 10, "1.0"); assertResultCount(contentResolver, 2, InstalledAppProvider.getContentUri()); assertIsInstalledVersionInDb(contentResolver, "com.example.app2", 10, "1.0"); contentResolver.insert( InstalledAppProvider.getContentUri(), createContentValues("com.example.app2", 11, "1.1") ); assertResultCount(contentResolver, 2, InstalledAppProvider.getContentUri()); assertIsInstalledVersionInDb(contentResolver, "com.example.app2", 11, "1.1"); } /** * We expect this to happen, because we should be using insert() instead as it will * do an insert/replace query. */ @Test(expected = UnsupportedOperationException.class) public void testUpdateFails() { contentResolver.update( InstalledAppProvider.getAppUri("com.example.app2"), createContentValues(11, "1.1"), null, null ); } @Test public void testLastUpdateTime() { String packageName = "com.example.app"; insertInstalledApp(packageName, 10, "1.0"); assertResultCount(contentResolver, 1, InstalledAppProvider.getContentUri()); assertIsInstalledVersionInDb(contentResolver, packageName, 10, "1.0"); Uri uri = InstalledAppProvider.getAppUri(packageName); String[] projection = { Cols.PACKAGE_NAME, Cols.LAST_UPDATE_TIME, }; Cursor cursor = contentResolver.query(uri, projection, null, null, null); assertNotNull(cursor); assertEquals("App \"" + packageName + "\" not installed", 1, cursor.getCount()); cursor.moveToFirst(); assertEquals(packageName, cursor.getString(cursor.getColumnIndex(Cols.PACKAGE_NAME))); long lastUpdateTime = cursor.getLong(cursor.getColumnIndex(Cols.LAST_UPDATE_TIME)); assertTrue(lastUpdateTime > 0); assertTrue(lastUpdateTime < System.currentTimeMillis()); cursor.close(); insertInstalledApp(packageName, 11, "1.1"); cursor = contentResolver.query(uri, projection, null, null, null); assertNotNull(cursor); assertEquals("App \"" + packageName + "\" not installed", 1, cursor.getCount()); cursor.moveToFirst(); assertTrue(lastUpdateTime < cursor.getLong(cursor.getColumnIndex(Cols.LAST_UPDATE_TIME))); cursor.close(); } @Test public void testDelete() { insertInstalledApp("com.example.app1", 10, "1.0"); insertInstalledApp("com.example.app2", 10, "1.0"); assertResultCount(contentResolver, 2, InstalledAppProvider.getContentUri()); contentResolver.delete(InstalledAppProvider.getAppUri("com.example.app1"), null, null); assertResultCount(contentResolver, 1, InstalledAppProvider.getContentUri()); assertIsInstalledVersionInDb(contentResolver, "com.example.app2", 10, "1.0"); } private ContentValues createContentValues(int versionCode, String versionNumber) { return createContentValues(null, versionCode, versionNumber); } private ContentValues createContentValues(String appId, int versionCode, String versionNumber) { ContentValues values = new ContentValues(3); if (appId != null) { values.put(Cols.PACKAGE_NAME, appId); } values.put(Cols.APPLICATION_LABEL, "Mock app: " + appId); values.put(Cols.VERSION_CODE, versionCode); values.put(Cols.VERSION_NAME, versionNumber); values.put(Cols.SIGNATURE, ""); values.put(Cols.LAST_UPDATE_TIME, System.currentTimeMillis()); values.put(Cols.HASH_TYPE, "sha256"); values.put(Cols.HASH, "cafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafe"); return values; } private void insertInstalledApp(String appId, int versionCode, String versionNumber) { ContentValues values = createContentValues(appId, versionCode, versionNumber); contentResolver.insert(InstalledAppProvider.getContentUri(), values); } } // https://github.com/robolectric/robolectric/wiki/2.4-to-3.0-Upgrade-Guide