Created
December 2, 2018 12:05
-
-
Save tomergoldst/290bf4877271136b234a74cd63690da0 to your computer and use it in GitHub Desktop.
Key-Value store interface and shared preferences implementation example plus memory (mock) implemetnation in Kotlin
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
interface KeyStoreDataSource { | |
fun getString(key: String, defaultValue: String?): String? | |
fun putString(key: String, value: String?) | |
fun getInt(key: String, defaultValue: Int): Int | |
fun putInt(key: String, value: Int) | |
fun getLong(key: String, defaultValue: Long): Long | |
fun putLong(key: String, value: Long) | |
fun getFloat(key: String, defaultValue: Float): Float | |
fun putFloat(key: String, value: Float) | |
fun getBoolean(key: String, defaultValue: Boolean): Boolean | |
fun putBoolean(key: String, value: Boolean) | |
fun getAll(): Map<String, *> | |
fun remove(key: String) | |
fun clear() | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class KeyStoreDataSourceImpl private constructor( | |
context: Context, | |
private val mSharedPrefsName: String | |
) : | |
KeyStoreDataSource { | |
private var mSharedPrefs: SharedPreferences? = null | |
init { | |
loadPreferences(context) | |
} | |
private fun loadPreferences(context: Context) { | |
mSharedPrefs = context.getSharedPreferences(mSharedPrefsName, Context.MODE_PRIVATE) | |
} | |
override fun getString(key: String, defaultValue: String?): String? { | |
return mSharedPrefs!!.getString(key, defaultValue) | |
} | |
override fun putString(key: String, value: String?) { | |
val editor = mSharedPrefs!!.edit() | |
editor.putString(key, value) | |
editor.apply() | |
} | |
override fun getInt(key: String, defaultValue: Int): Int { | |
return mSharedPrefs!!.getInt(key, defaultValue) | |
} | |
override fun putInt(key: String, value: Int) { | |
val editor = mSharedPrefs!!.edit() | |
editor.putInt(key, value) | |
editor.apply() | |
} | |
override fun getLong(key: String, defaultValue: Long): Long { | |
return mSharedPrefs!!.getLong(key, defaultValue) | |
} | |
override fun putLong(key: String, value: Long) { | |
val editor = mSharedPrefs!!.edit() | |
editor.putLong(key, value) | |
editor.apply() | |
} | |
override fun getFloat(key: String, defaultValue: Float): Float { | |
return mSharedPrefs!!.getFloat(key, defaultValue) | |
} | |
override fun putFloat(key: String, value: Float) { | |
val editor = mSharedPrefs!!.edit() | |
editor.putFloat(key, value) | |
editor.apply() | |
} | |
override fun getBoolean(key: String, defaultValue: Boolean): Boolean { | |
return mSharedPrefs!!.getBoolean(key, defaultValue) | |
} | |
override fun putBoolean(key: String, value: Boolean) { | |
val editor = mSharedPrefs!!.edit() | |
editor.putBoolean(key, value) | |
editor.apply() | |
} | |
override fun remove(key: String) { | |
mSharedPrefs!!.edit().remove(key).apply() | |
} | |
override fun clear() { | |
mSharedPrefs!!.edit().clear().apply() | |
} | |
override fun getAll(): Map<String, *> { | |
return mSharedPrefs!!.all | |
} | |
companion object { | |
@Volatile | |
private var INSTANCE: KeyStoreDataSourceImpl? = null | |
fun getInstance(context: Context): KeyStoreDataSourceImpl = | |
INSTANCE ?: synchronized(this) { | |
INSTANCE ?: KeyStoreDataSourceImpl(context, "com.tomergoldst.rooster.sharedprefs") | |
.also { INSTANCE = it } | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class MemoryKeyStore : KeyStoreDataSource { | |
private val store: MutableMap<String, Any?> = hashMapOf() | |
override fun getString(key: String, defaultValue: String?): String? { | |
return store[key] as String? ?: return defaultValue | |
} | |
override fun putString(key: String, value: String?) { | |
store[key] = value | |
} | |
override fun getInt(key: String, defaultValue: Int): Int { | |
return store[key] as Int? ?: return defaultValue | |
} | |
override fun putInt(key: String, value: Int) { | |
store[key] = value | |
} | |
override fun getLong(key: String, defaultValue: Long): Long { | |
return store[key] as Long? ?: return defaultValue | |
} | |
override fun putLong(key: String, value: Long) { | |
store[key] = value | |
} | |
override fun getFloat(key: String, defaultValue: Float): Float { | |
return store[key] as Float? ?: return defaultValue | |
} | |
override fun putFloat(key: String, value: Float) { | |
store[key] = value | |
} | |
override fun getBoolean(key: String, defaultValue: Boolean): Boolean { | |
return store[key] as Boolean? ?: return defaultValue | |
} | |
override fun putBoolean(key: String, value: Boolean) { | |
store[key] = value | |
} | |
override fun remove(key: String) { | |
store.remove(key) | |
} | |
override fun clear() { | |
store.clear() | |
} | |
override fun getAll(): Map<String, *> { | |
return store | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class MockedKeyStoreUnitTest { | |
private val mockKeyStore = MemoryKeyStore() | |
@Test | |
fun whenAddingString_valueExistAtStore() { | |
val key = "color" | |
val expectedValue = "blue" | |
mockKeyStore.putString(key, expectedValue) | |
val actualResult = mockKeyStore.getString(key, null) | |
assertEquals(expectedValue, actualResult) | |
} | |
@Test | |
fun whenGettingStringThatDoesNotExist_gettingDefaultValue() { | |
val key = "color" | |
val defaultValue = "blue" | |
val actualResult = mockKeyStore.getString(key, defaultValue) | |
assertEquals(defaultValue, actualResult) | |
} | |
@Test | |
fun whenGettingStringThatDoesNotExist_gettingDefaultValueOfNull() { | |
val key = "color" | |
val actualResult = mockKeyStore.getString(key, null) | |
assertNull(actualResult) | |
} | |
@Test | |
fun whenAddingString_getAddedString() { | |
val key = "color" | |
val expectedValue = "blue" | |
mockKeyStore.putString(key, expectedValue) | |
val actualResult = mockKeyStore.getString(key, null) | |
assertEquals(expectedValue, actualResult) | |
} | |
@Test | |
fun whenAddingInt_valueExistOnDictionary() { | |
val key = "number" | |
val expectedValue = 5 | |
mockKeyStore.putInt(key, expectedValue) | |
val actualResult = mockKeyStore.getInt(key, 0) | |
assertEquals(expectedValue.toLong(), actualResult.toLong()) | |
} | |
@Test | |
fun whenGettingIntThatDoesNotExist_gettingDefaultValue() { | |
val key = "number" | |
val actualResult = mockKeyStore.getInt(key, 0) | |
assertEquals(0, actualResult.toLong()) | |
} | |
@Test | |
fun whenAddingLong_valueExistOnDictionary() { | |
val key = "number" | |
val expectedValue = 100000L | |
mockKeyStore.putLong(key, expectedValue) | |
val actualResult = mockKeyStore.getLong(key, 0) | |
assertEquals(expectedValue, actualResult) | |
} | |
@Test | |
fun whenGettingLongThatDoesNotExist_gettingDefaultValue() { | |
val key = "number" | |
val actualResult = mockKeyStore.getLong(key, 0) | |
assertEquals(0, actualResult) | |
} | |
@Test | |
fun whenAddingFloat_valueExistOnDictionary() { | |
val key = "fraction" | |
val expectedValue = 4.75f | |
mockKeyStore.putFloat(key, expectedValue) | |
val actualResult = mockKeyStore.getFloat(key, 0f) | |
assertEquals(expectedValue, actualResult, 0f) | |
} | |
@Test | |
fun whenGettingFloatThatDoesNotExist_gettingDefaultValue() { | |
val key = "fraction" | |
val actualResult = mockKeyStore.getFloat(key, 1.5f) | |
assertEquals(1.5f, actualResult, 0f) | |
} | |
@Test | |
fun whenUpdatingString_valueUpdated() { | |
val key = "color" | |
val initialValue = "blue" | |
val updatedValue = "yellow" | |
mockKeyStore.putString(key, initialValue) | |
mockKeyStore.putString(key, updatedValue) | |
val actualResult = mockKeyStore.getString(key, null) | |
assertEquals(updatedValue, actualResult) | |
} | |
@Test | |
fun whenUpdatingLong_valueUpdated() { | |
val key = "big_number" | |
val initialValue = 100000L | |
val updatedValue = 200000L | |
mockKeyStore.putLong(key, initialValue) | |
mockKeyStore.putLong(key, updatedValue) | |
val actualResult = mockKeyStore.getLong(key, 0) | |
assertEquals(updatedValue, actualResult) | |
} | |
@Test | |
fun whenAddingMultipleKeys_numOfKeyOnStoreMatch() { | |
mockKeyStore.putLong("big_number", 1L) | |
mockKeyStore.putString("color", "blue") | |
mockKeyStore.putBoolean("exist", true) | |
val size = mockKeyStore.getAll().size | |
assertEquals(3, size.toLong()) | |
} | |
@Test | |
fun whenClear_storeIsEmpty() { | |
mockKeyStore.putLong("big_number", 3L) | |
mockKeyStore.putString("color", "blue") | |
mockKeyStore.putBoolean("exist", true) | |
mockKeyStore.clear() | |
val size = mockKeyStore.getAll().size | |
assertEquals(0, size.toLong()) | |
} | |
@Test | |
fun whenRemoveKey_keyNotExistOnStore() { | |
val key = "color" | |
val expectedValue = "blue" | |
mockKeyStore.putString(key, expectedValue) | |
val actualResult = mockKeyStore.getString(key, null) | |
assertEquals(expectedValue, actualResult) | |
mockKeyStore.remove(key) | |
assertEquals(null, mockKeyStore.getString(key, null)) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment