diff --git a/app/src/main/java/com/swoosh/microblog/data/SiteMetadataCache.kt b/app/src/main/java/com/swoosh/microblog/data/SiteMetadataCache.kt new file mode 100644 index 0000000..c104989 --- /dev/null +++ b/app/src/main/java/com/swoosh/microblog/data/SiteMetadataCache.kt @@ -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" + } +} diff --git a/app/src/test/java/com/swoosh/microblog/data/SiteMetadataCacheTest.kt b/app/src/test/java/com/swoosh/microblog/data/SiteMetadataCacheTest.kt new file mode 100644 index 0000000..359c2e8 --- /dev/null +++ b/app/src/test/java/com/swoosh/microblog/data/SiteMetadataCacheTest.kt @@ -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() + 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")) + } +}