mirror of
https://github.com/pawelorzech/Swoosh.git
synced 2026-03-31 11:55:47 +00:00
feat: add SiteMetadataCache for per-account site metadata storage
SharedPreferences-based cache for GhostSite metadata keyed by account ID. Supports save/get/getVersion/remove operations with Gson serialization. Includes Robolectric tests for round-trip, overwrite, multi-account isolation, and removal.
This commit is contained in:
parent
6761eae351
commit
492ee1ca11
2 changed files with 203 additions and 0 deletions
|
|
@ -0,0 +1,42 @@
|
|||
package com.swoosh.microblog.data
|
||||
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import com.google.gson.Gson
|
||||
import com.swoosh.microblog.data.model.GhostSite
|
||||
|
||||
class SiteMetadataCache(context: Context) {
|
||||
|
||||
private val prefs: SharedPreferences = context.getSharedPreferences(
|
||||
PREFS_NAME, Context.MODE_PRIVATE
|
||||
)
|
||||
private val gson = Gson()
|
||||
|
||||
fun save(accountId: String, site: GhostSite) {
|
||||
val json = gson.toJson(site)
|
||||
prefs.edit().putString(keyForAccount(accountId), json).apply()
|
||||
}
|
||||
|
||||
fun get(accountId: String): GhostSite? {
|
||||
val json = prefs.getString(keyForAccount(accountId), null) ?: return null
|
||||
return try {
|
||||
gson.fromJson(json, GhostSite::class.java)
|
||||
} catch (e: Exception) {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
fun getVersion(accountId: String): String? {
|
||||
return get(accountId)?.version
|
||||
}
|
||||
|
||||
fun remove(accountId: String) {
|
||||
prefs.edit().remove(keyForAccount(accountId)).apply()
|
||||
}
|
||||
|
||||
private fun keyForAccount(accountId: String): String = "site_$accountId"
|
||||
|
||||
companion object {
|
||||
const val PREFS_NAME = "site_metadata_cache"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,161 @@
|
|||
package com.swoosh.microblog.data
|
||||
|
||||
import android.app.Application
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import com.swoosh.microblog.data.model.GhostSite
|
||||
import org.junit.Assert.*
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.annotation.Config
|
||||
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
@Config(application = Application::class)
|
||||
class SiteMetadataCacheTest {
|
||||
|
||||
private lateinit var cache: SiteMetadataCache
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
val context = ApplicationProvider.getApplicationContext<Application>()
|
||||
cache = SiteMetadataCache(context)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `save and get round trip`() {
|
||||
val site = GhostSite(
|
||||
title = "My Blog",
|
||||
description = "A test blog",
|
||||
logo = "https://example.com/logo.png",
|
||||
icon = "https://example.com/icon.png",
|
||||
accent_color = "#ff1a75",
|
||||
url = "https://example.com/",
|
||||
version = "5.82.0",
|
||||
locale = "en"
|
||||
)
|
||||
|
||||
cache.save("account-1", site)
|
||||
val retrieved = cache.get("account-1")
|
||||
|
||||
assertNotNull(retrieved)
|
||||
assertEquals("My Blog", retrieved!!.title)
|
||||
assertEquals("A test blog", retrieved.description)
|
||||
assertEquals("https://example.com/logo.png", retrieved.logo)
|
||||
assertEquals("https://example.com/icon.png", retrieved.icon)
|
||||
assertEquals("#ff1a75", retrieved.accent_color)
|
||||
assertEquals("https://example.com/", retrieved.url)
|
||||
assertEquals("5.82.0", retrieved.version)
|
||||
assertEquals("en", retrieved.locale)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `get returns null for unknown account`() {
|
||||
val result = cache.get("nonexistent-account")
|
||||
assertNull(result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getVersion returns version string`() {
|
||||
val site = GhostSite(
|
||||
title = "Blog",
|
||||
description = null,
|
||||
logo = null,
|
||||
icon = null,
|
||||
accent_color = null,
|
||||
url = null,
|
||||
version = "5.82.0",
|
||||
locale = null
|
||||
)
|
||||
|
||||
cache.save("account-2", site)
|
||||
assertEquals("5.82.0", cache.getVersion("account-2"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getVersion returns null for unknown account`() {
|
||||
assertNull(cache.getVersion("nonexistent"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `save overwrites existing data`() {
|
||||
val site1 = GhostSite(
|
||||
title = "Old Title",
|
||||
description = null,
|
||||
logo = null,
|
||||
icon = null,
|
||||
accent_color = null,
|
||||
url = null,
|
||||
version = "5.0.0",
|
||||
locale = null
|
||||
)
|
||||
val site2 = GhostSite(
|
||||
title = "New Title",
|
||||
description = "Updated",
|
||||
logo = null,
|
||||
icon = null,
|
||||
accent_color = null,
|
||||
url = null,
|
||||
version = "5.82.0",
|
||||
locale = null
|
||||
)
|
||||
|
||||
cache.save("account-3", site1)
|
||||
cache.save("account-3", site2)
|
||||
val retrieved = cache.get("account-3")
|
||||
|
||||
assertEquals("New Title", retrieved?.title)
|
||||
assertEquals("Updated", retrieved?.description)
|
||||
assertEquals("5.82.0", retrieved?.version)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `different accounts have independent data`() {
|
||||
val site1 = GhostSite(
|
||||
title = "Blog One",
|
||||
description = null,
|
||||
logo = null,
|
||||
icon = null,
|
||||
accent_color = null,
|
||||
url = null,
|
||||
version = "5.0.0",
|
||||
locale = null
|
||||
)
|
||||
val site2 = GhostSite(
|
||||
title = "Blog Two",
|
||||
description = null,
|
||||
logo = null,
|
||||
icon = null,
|
||||
accent_color = null,
|
||||
url = null,
|
||||
version = "4.48.0",
|
||||
locale = null
|
||||
)
|
||||
|
||||
cache.save("account-a", site1)
|
||||
cache.save("account-b", site2)
|
||||
|
||||
assertEquals("Blog One", cache.get("account-a")?.title)
|
||||
assertEquals("Blog Two", cache.get("account-b")?.title)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `remove deletes cached data`() {
|
||||
val site = GhostSite(
|
||||
title = "To Remove",
|
||||
description = null,
|
||||
logo = null,
|
||||
icon = null,
|
||||
accent_color = null,
|
||||
url = null,
|
||||
version = "5.0.0",
|
||||
locale = null
|
||||
)
|
||||
|
||||
cache.save("account-remove", site)
|
||||
assertNotNull(cache.get("account-remove"))
|
||||
|
||||
cache.remove("account-remove")
|
||||
assertNull(cache.get("account-remove"))
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue