make DBHelper follow the Java Singleton pattern
It was already behaving like a singleton, but the code was spread around in other classes. DBHelper does not use a private constructor though since the tests prevent it.
This commit is contained in:
		
							parent
							
								
									2fe7faed6e
								
							
						
					
					
						commit
						d8879dd425
					
				| @ -453,8 +453,9 @@ public final class Preferences implements SharedPreferences.OnSharedPreferenceCh | ||||
|      * While it is likely that most places asking for preferences have access to a {@link Context}, | ||||
|      * it is a minor convenience to be able to ask for preferences without. | ||||
|      */ | ||||
|     public static void clearSingletonForTesting() { | ||||
|     public static void setupForTests(Context context) { | ||||
|         instance = null; | ||||
|         setup(context); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|  | ||||
| @ -47,13 +47,20 @@ import org.fdroid.fdroid.data.Schema.RepoTable; | ||||
| import java.util.ArrayList; | ||||
| import java.util.List; | ||||
| 
 | ||||
| /** | ||||
|  * This is basically a singleton used to represent the database at the core | ||||
|  * of all of the {@link android.content.ContentProvider}s used at the core | ||||
|  * of this app.  {@link DBHelper} is not {@code private} so that it can be easily | ||||
|  * used in test subclasses. | ||||
|  */ | ||||
| @SuppressWarnings("LineLength") | ||||
| class DBHelper extends SQLiteOpenHelper { | ||||
| public class DBHelper extends SQLiteOpenHelper { | ||||
| 
 | ||||
|     private static final String TAG = "DBHelper"; | ||||
| 
 | ||||
|     public static final int REPO_XML_ARG_COUNT = 8; | ||||
| 
 | ||||
|     private static DBHelper instance; | ||||
|     private static final String DATABASE_NAME = "fdroid"; | ||||
| 
 | ||||
|     private static final String CREATE_TABLE_PACKAGE = "CREATE TABLE " + PackageTable.NAME | ||||
| @ -214,7 +221,22 @@ class DBHelper extends SQLiteOpenHelper { | ||||
| 
 | ||||
|     DBHelper(Context context) { | ||||
|         super(context, DATABASE_NAME, null, DB_VERSION); | ||||
|         this.context = context; | ||||
|         this.context = context.getApplicationContext(); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Only used for testing. Not quite sure how to mock a singleton variable like this. | ||||
|      */ | ||||
|     public static void clearDbHelperSingleton() { | ||||
|         instance = null; | ||||
|     } | ||||
| 
 | ||||
|     static synchronized DBHelper getInstance(Context context) { | ||||
|         if (instance == null) { | ||||
|             Utils.debugLog(TAG, "First time accessing database, creating new helper"); | ||||
|             instance = new DBHelper(context); | ||||
|         } | ||||
|         return instance; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|  | ||||
| @ -5,16 +5,13 @@ import android.content.ContentProvider; | ||||
| import android.content.ContentProviderOperation; | ||||
| import android.content.ContentProviderResult; | ||||
| import android.content.ContentValues; | ||||
| import android.content.Context; | ||||
| import android.content.OperationApplicationException; | ||||
| import android.content.UriMatcher; | ||||
| import android.database.sqlite.SQLiteDatabase; | ||||
| import android.net.Uri; | ||||
| import android.os.Build; | ||||
| import android.support.annotation.NonNull; | ||||
| 
 | ||||
| import org.fdroid.fdroid.BuildConfig; | ||||
| import org.fdroid.fdroid.Utils; | ||||
| 
 | ||||
| import java.util.ArrayList; | ||||
| import java.util.HashSet; | ||||
| @ -23,15 +20,13 @@ import java.util.Set; | ||||
| 
 | ||||
| public abstract class FDroidProvider extends ContentProvider { | ||||
| 
 | ||||
|     private static final String TAG = "FDroidProvider"; | ||||
|     public static final String TAG = "FDroidProvider"; | ||||
| 
 | ||||
|     static final String AUTHORITY = BuildConfig.APPLICATION_ID + ".data"; | ||||
| 
 | ||||
|     static final int CODE_LIST   = 1; | ||||
|     static final int CODE_LIST = 1; | ||||
|     static final int CODE_SINGLE = 2; | ||||
| 
 | ||||
|     private static DBHelper dbHelper; | ||||
| 
 | ||||
|     private boolean isApplyingBatch; | ||||
| 
 | ||||
|     protected abstract String getTableName(); | ||||
| @ -73,28 +68,13 @@ public abstract class FDroidProvider extends ContentProvider { | ||||
|         return result; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Only used for testing. Not quite sure how to mock a singleton variable like this. | ||||
|      */ | ||||
|     public static void clearDbHelperSingleton() { | ||||
|         dbHelper = null; | ||||
|     } | ||||
| 
 | ||||
|     private static synchronized DBHelper getOrCreateDb(Context context) { | ||||
|         if (dbHelper == null) { | ||||
|             Utils.debugLog(TAG, "First time accessing database, creating new helper"); | ||||
|             dbHelper = new DBHelper(context); | ||||
|         } | ||||
|         return dbHelper; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public boolean onCreate() { | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     protected final synchronized SQLiteDatabase db() { | ||||
|         return getOrCreateDb(getContext().getApplicationContext()).getWritableDatabase(); | ||||
|         return DBHelper.getInstance(getContext()).getWritableDatabase(); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
| @ -154,7 +134,7 @@ public abstract class FDroidProvider extends ContentProvider { | ||||
| 
 | ||||
|             if (!isValid) { | ||||
|                 throw new IllegalArgumentException( | ||||
|                     "Cannot save field '" + key + "' to provider " + getProviderName()); | ||||
|                         "Cannot save field '" + key + "' to provider " + getProviderName()); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @ -2,7 +2,6 @@ package org.fdroid.fdroid; | ||||
| 
 | ||||
| import android.app.Application; | ||||
| import android.content.ContentValues; | ||||
| 
 | ||||
| import org.fdroid.fdroid.data.Apk; | ||||
| import org.fdroid.fdroid.data.ApkProvider; | ||||
| import org.fdroid.fdroid.data.App; | ||||
| @ -12,7 +11,6 @@ import org.fdroid.fdroid.data.AppProvider; | ||||
| import org.fdroid.fdroid.data.FDroidProviderTest; | ||||
| import org.fdroid.fdroid.data.InstalledAppTestUtils; | ||||
| import org.fdroid.fdroid.data.Schema; | ||||
| import org.junit.After; | ||||
| import org.junit.Before; | ||||
| import org.junit.Test; | ||||
| import org.junit.runner.RunWith; | ||||
| @ -21,9 +19,9 @@ import org.robolectric.annotation.Config; | ||||
| 
 | ||||
| import java.util.List; | ||||
| 
 | ||||
| import static org.junit.Assert.assertNull; | ||||
| import static org.junit.Assert.assertArrayEquals; | ||||
| import static org.junit.Assert.assertEquals; | ||||
| import static org.junit.Assert.assertNull; | ||||
| 
 | ||||
| @Config(constants = BuildConfig.class, application = Application.class, sdk = 24) | ||||
| @RunWith(RobolectricTestRunner.class) | ||||
| @ -35,7 +33,7 @@ public class AntiFeaturesTest extends FDroidProviderTest { | ||||
| 
 | ||||
|     @Before | ||||
|     public void setup() { | ||||
|         Preferences.setup(context); | ||||
|         Preferences.setupForTests(context); | ||||
| 
 | ||||
|         ContentValues vulnValues = new ContentValues(1); | ||||
|         vulnValues.put(Schema.ApkTable.Cols.AntiFeatures.ANTI_FEATURES, "KnownVuln,ContainsGreenButtons"); | ||||
| @ -58,11 +56,6 @@ public class AntiFeaturesTest extends FDroidProviderTest { | ||||
|         AppProvider.Helper.recalculatePreferredMetadata(context); | ||||
|     } | ||||
| 
 | ||||
|     @After | ||||
|     public void tearDown() { | ||||
|         Preferences.clearSingletonForTesting(); | ||||
|     } | ||||
| 
 | ||||
|     private static String generateHash(String packageName, int versionCode) { | ||||
|         return packageName + "-" + versionCode; | ||||
|     } | ||||
|  | ||||
| @ -1,7 +1,6 @@ | ||||
| package org.fdroid.fdroid.data; | ||||
| 
 | ||||
| import android.app.Application; | ||||
| 
 | ||||
| import org.fdroid.fdroid.Assert; | ||||
| import org.fdroid.fdroid.BuildConfig; | ||||
| import org.fdroid.fdroid.TestUtils; | ||||
| @ -11,10 +10,10 @@ import org.junit.runner.RunWith; | ||||
| import org.robolectric.RobolectricTestRunner; | ||||
| import org.robolectric.annotation.Config; | ||||
| 
 | ||||
| import static org.junit.Assert.assertTrue; | ||||
| import static org.junit.Assert.assertEquals; | ||||
| import static org.junit.Assert.assertFalse; | ||||
| import static org.junit.Assert.assertNull; | ||||
| import static org.junit.Assert.assertTrue; | ||||
| 
 | ||||
| @Config(constants = BuildConfig.class, application = Application.class, sdk = 24) | ||||
| @RunWith(RobolectricTestRunner.class) | ||||
|  | ||||
| @ -10,7 +10,6 @@ import org.fdroid.fdroid.BuildConfig; | ||||
| import org.fdroid.fdroid.Preferences; | ||||
| import org.fdroid.fdroid.TestUtils; | ||||
| import org.fdroid.fdroid.data.Schema.AppMetadataTable.Cols; | ||||
| import org.junit.After; | ||||
| import org.junit.Before; | ||||
| import org.junit.Test; | ||||
| import org.junit.runner.RunWith; | ||||
| @ -40,12 +39,7 @@ public class AppProviderTest extends FDroidProviderTest { | ||||
|     @Before | ||||
|     public void setup() { | ||||
|         TestUtils.registerContentProvider(AppProvider.getAuthority(), AppProvider.class); | ||||
|         Preferences.setup(context); | ||||
|     } | ||||
| 
 | ||||
|     @After | ||||
|     public void tearDown() { | ||||
|         Preferences.clearSingletonForTesting(); | ||||
|         Preferences.setupForTests(context); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|  | ||||
| @ -1,7 +1,6 @@ | ||||
| package org.fdroid.fdroid.data; | ||||
| 
 | ||||
| import android.content.ContextWrapper; | ||||
| 
 | ||||
| import org.fdroid.fdroid.TestUtils; | ||||
| import org.junit.After; | ||||
| import org.junit.Before; | ||||
| @ -24,7 +23,7 @@ public abstract class FDroidProviderTest { | ||||
|     @After | ||||
|     public final void tearDownBase() { | ||||
|         CategoryProvider.Helper.clearCategoryIdCache(); | ||||
|         FDroidProvider.clearDbHelperSingleton(); | ||||
|         DBHelper.clearDbHelperSingleton(); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  | ||||
| @ -8,7 +8,6 @@ import org.fdroid.fdroid.BuildConfig; | ||||
| import org.fdroid.fdroid.Preferences; | ||||
| import org.fdroid.fdroid.TestUtils; | ||||
| import org.fdroid.fdroid.data.Schema.InstalledAppTable.Cols; | ||||
| import org.junit.After; | ||||
| import org.junit.Before; | ||||
| import org.junit.Test; | ||||
| import org.junit.runner.RunWith; | ||||
| @ -31,12 +30,7 @@ public class InstalledAppProviderTest extends FDroidProviderTest { | ||||
|     @Before | ||||
|     public void setup() { | ||||
|         TestUtils.registerContentProvider(InstalledAppProvider.getAuthority(), InstalledAppProvider.class); | ||||
|         Preferences.setup(context); | ||||
|     } | ||||
| 
 | ||||
|     @After | ||||
|     public void tearDown() { | ||||
|         Preferences.clearSingletonForTesting(); | ||||
|         Preferences.setupForTests(context); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|  | ||||
| @ -2,11 +2,9 @@ package org.fdroid.fdroid.data; | ||||
| 
 | ||||
| import android.app.Application; | ||||
| import android.content.Context; | ||||
| 
 | ||||
| import org.fdroid.fdroid.BuildConfig; | ||||
| import org.fdroid.fdroid.Preferences; | ||||
| import org.fdroid.fdroid.TestUtils; | ||||
| import org.junit.After; | ||||
| import org.junit.Before; | ||||
| import org.junit.Test; | ||||
| import org.junit.runner.RunWith; | ||||
| @ -24,7 +22,7 @@ public class PreferredSignatureTest extends FDroidProviderTest { | ||||
|     @Before | ||||
|     public void setup() { | ||||
|         TestUtils.registerContentProvider(AppProvider.getAuthority(), AppProvider.class); | ||||
|         Preferences.setup(context); | ||||
|         Preferences.setupForTests(context); | ||||
| 
 | ||||
|         // This is what the FDroidApp does when this preference is changed. Need to also do this under testing. | ||||
|         Preferences.get().registerUnstableUpdatesChangeListener(new Preferences.ChangeListener() { | ||||
| @ -35,11 +33,6 @@ public class PreferredSignatureTest extends FDroidProviderTest { | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     @After | ||||
|     public void tearDown() { | ||||
|         Preferences.clearSingletonForTesting(); | ||||
|     } | ||||
| 
 | ||||
|     private Repo createFDroidRepo() { | ||||
|         return RepoProviderTest.insertRepo(context, "https://f-droid.org/fdroid/repo", "", "", ""); | ||||
|     } | ||||
|  | ||||
| @ -39,7 +39,7 @@ public class ProviderUriTests { | ||||
| 
 | ||||
|     @After | ||||
|     public void teardown() { | ||||
|         FDroidProvider.clearDbHelperSingleton(); | ||||
|         DBHelper.clearDbHelperSingleton(); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|  | ||||
| @ -26,7 +26,6 @@ import android.content.ContentValues; | ||||
| import android.content.Context; | ||||
| import android.net.Uri; | ||||
| import android.support.annotation.Nullable; | ||||
| 
 | ||||
| import org.fdroid.fdroid.BuildConfig; | ||||
| import org.fdroid.fdroid.R; | ||||
| import org.fdroid.fdroid.Utils; | ||||
|  | ||||
| @ -5,7 +5,6 @@ import org.fdroid.fdroid.BuildConfig; | ||||
| import org.fdroid.fdroid.Preferences; | ||||
| import org.fdroid.fdroid.TestUtils; | ||||
| import org.fdroid.fdroid.data.Schema.AppMetadataTable.Cols; | ||||
| import org.junit.After; | ||||
| import org.junit.Before; | ||||
| import org.junit.Test; | ||||
| import org.junit.runner.RunWith; | ||||
| @ -24,7 +23,7 @@ public class SuggestedVersionTest extends FDroidProviderTest { | ||||
|     @Before | ||||
|     public void setup() { | ||||
|         TestUtils.registerContentProvider(AppProvider.getAuthority(), AppProvider.class); | ||||
|         Preferences.setup(context); | ||||
|         Preferences.setupForTests(context); | ||||
| 
 | ||||
|         // This is what the FDroidApp does when this preference is changed. Need to also do this under testing. | ||||
|         Preferences.get().registerUnstableUpdatesChangeListener(new Preferences.ChangeListener() { | ||||
| @ -35,11 +34,6 @@ public class SuggestedVersionTest extends FDroidProviderTest { | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     @After | ||||
|     public void tearDown() { | ||||
|         Preferences.clearSingletonForTesting(); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void singleRepoSingleSig() { | ||||
|         App singleApp = TestUtils.insertApp( | ||||
|  | ||||
| @ -4,7 +4,6 @@ package org.fdroid.fdroid.updater; | ||||
| import android.content.ContentValues; | ||||
| import android.support.annotation.NonNull; | ||||
| import android.util.Log; | ||||
| 
 | ||||
| import org.fdroid.fdroid.BuildConfig; | ||||
| import org.fdroid.fdroid.RepoUpdater.UpdateException; | ||||
| import org.fdroid.fdroid.data.Repo; | ||||
|  | ||||
| @ -26,7 +26,6 @@ import org.fdroid.fdroid.data.Repo; | ||||
| import org.fdroid.fdroid.data.RepoProvider; | ||||
| import org.fdroid.fdroid.data.RepoPushRequest; | ||||
| import org.fdroid.fdroid.mock.RepoDetails; | ||||
| import org.junit.After; | ||||
| import org.junit.Before; | ||||
| import org.junit.Test; | ||||
| import org.junit.runner.RunWith; | ||||
| @ -66,12 +65,7 @@ public class IndexV1UpdaterTest extends FDroidProviderTest { | ||||
| 
 | ||||
|     @Before | ||||
|     public void setup() { | ||||
|         Preferences.setup(context); | ||||
|     } | ||||
| 
 | ||||
|     @After | ||||
|     public void tearDown() { | ||||
|         Preferences.clearSingletonForTesting(); | ||||
|         Preferences.setupForTests(context); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|  | ||||
| @ -1,7 +1,6 @@ | ||||
| package org.fdroid.fdroid.updater; | ||||
| 
 | ||||
| import android.content.ContentValues; | ||||
| 
 | ||||
| import org.fdroid.fdroid.BuildConfig; | ||||
| import org.fdroid.fdroid.RepoUpdater; | ||||
| import org.fdroid.fdroid.data.Apk; | ||||
|  | ||||
| @ -17,7 +17,6 @@ import org.fdroid.fdroid.data.FDroidProviderTest; | ||||
| import org.fdroid.fdroid.data.Repo; | ||||
| import org.fdroid.fdroid.data.RepoProvider; | ||||
| import org.fdroid.fdroid.data.Schema; | ||||
| import org.junit.After; | ||||
| import org.junit.Before; | ||||
| 
 | ||||
| import java.io.File; | ||||
| @ -86,12 +85,7 @@ public abstract class MultiRepoUpdaterTest extends FDroidProviderTest { | ||||
|         RepoProvider.Helper.remove(context, 3); | ||||
|         RepoProvider.Helper.remove(context, 4); | ||||
| 
 | ||||
|         Preferences.setup(context); | ||||
|     } | ||||
| 
 | ||||
|     @After | ||||
|     public final void tearDownMultiRepo() { | ||||
|         Preferences.clearSingletonForTesting(); | ||||
|         Preferences.setupForTests(context); | ||||
|     } | ||||
| 
 | ||||
|     protected void assertApp(String packageName, int[] versionCodes) { | ||||
|  | ||||
| @ -4,7 +4,6 @@ package org.fdroid.fdroid.updater; | ||||
| import android.content.ContentValues; | ||||
| import android.support.annotation.StringDef; | ||||
| import android.util.Log; | ||||
| 
 | ||||
| import org.fdroid.fdroid.BuildConfig; | ||||
| import org.fdroid.fdroid.RepoUpdater; | ||||
| import org.fdroid.fdroid.TestUtils; | ||||
|  | ||||
| @ -14,7 +14,7 @@ import org.fdroid.fdroid.R; | ||||
| import org.fdroid.fdroid.data.Apk; | ||||
| import org.fdroid.fdroid.data.App; | ||||
| import org.fdroid.fdroid.data.AppProviderTest; | ||||
| import org.fdroid.fdroid.data.FDroidProvider; | ||||
| import org.fdroid.fdroid.data.DBHelper; | ||||
| import org.fdroid.fdroid.data.FDroidProviderTest; | ||||
| import org.fdroid.fdroid.data.Repo; | ||||
| import org.fdroid.fdroid.data.RepoProviderTest; | ||||
| @ -36,7 +36,7 @@ public class AppDetailsAdapterTest extends FDroidProviderTest { | ||||
|     @Before | ||||
|     public void setup() { | ||||
|         ImageLoader.getInstance().init(ImageLoaderConfiguration.createDefault(context)); | ||||
|         Preferences.setup(context); | ||||
|         Preferences.setupForTests(context); | ||||
| 
 | ||||
|         Repo repo = RepoProviderTest.insertRepo(context, "http://www.example.com/fdroid/repo", "", "", "Test Repo"); | ||||
|         app = AppProviderTest.insertApp(contentResolver, context, "com.example.app", "Test App", | ||||
| @ -46,8 +46,7 @@ public class AppDetailsAdapterTest extends FDroidProviderTest { | ||||
|     @After | ||||
|     public void teardown() { | ||||
|         ImageLoader.getInstance().destroy(); | ||||
|         FDroidProvider.clearDbHelperSingleton(); | ||||
|         Preferences.clearSingletonForTesting(); | ||||
|         DBHelper.clearDbHelperSingleton(); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Hans-Christoph Steiner
						Hans-Christoph Steiner