Skip to content

Instantly share code, notes, and snippets.

@tomergoldst
Created December 2, 2018 12:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tomergoldst/290bf4877271136b234a74cd63690da0 to your computer and use it in GitHub Desktop.
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
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()
}
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 }
}
}
}
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
}
}
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