defmodule SimpleshopTheme.SettingsTest do use SimpleshopTheme.DataCase, async: false alias SimpleshopTheme.Settings alias SimpleshopTheme.Settings.ThemeSettings describe "get_setting/2 and put_setting/3" do test "stores and retrieves string settings" do assert {:ok, _} = Settings.put_setting("site_name", "My Shop") assert Settings.get_setting("site_name") == "My Shop" end test "stores and retrieves json settings" do data = %{"foo" => "bar", "nested" => %{"key" => "value"}} assert {:ok, _} = Settings.put_setting("custom_data", data, "json") assert Settings.get_setting("custom_data") == data end test "stores and retrieves integer settings" do assert {:ok, _} = Settings.put_setting("max_products", 100, "integer") assert Settings.get_setting("max_products") == 100 end test "stores and retrieves boolean settings" do assert {:ok, _} = Settings.put_setting("feature_enabled", true, "boolean") assert Settings.get_setting("feature_enabled") == true end test "returns default when setting doesn't exist" do assert Settings.get_setting("nonexistent", "default") == "default" assert Settings.get_setting("nonexistent") == nil end test "updates existing setting" do assert {:ok, _} = Settings.put_setting("site_name", "Old Name") assert {:ok, _} = Settings.put_setting("site_name", "New Name") assert Settings.get_setting("site_name") == "New Name" end end describe "get_theme_settings/0" do test "returns default theme settings when none exist" do settings = Settings.get_theme_settings() assert %ThemeSettings{} = settings assert settings.mood == "neutral" assert settings.typography == "clean" assert settings.shape == "soft" assert settings.density == "balanced" end test "returns stored theme settings" do {:ok, _} = Settings.update_theme_settings(%{mood: "dark", typography: "modern"}) settings = Settings.get_theme_settings() assert settings.mood == "dark" assert settings.typography == "modern" end end describe "update_theme_settings/1" do test "updates theme settings successfully" do {:ok, settings} = Settings.update_theme_settings(%{mood: "warm", typography: "editorial"}) assert settings.mood == "warm" assert settings.typography == "editorial" end test "regenerates CSS cache when settings change" do alias SimpleshopTheme.Theme.CSSCache # Get initial cached CSS {:ok, initial_css} = CSSCache.get() assert initial_css =~ ".themed {" # Update to a different accent color {:ok, _settings} = Settings.update_theme_settings(%{accent_color: "#ff0000"}) # Cache should now contain new CSS with the red accent color {:ok, updated_css} = CSSCache.get() assert updated_css =~ ".themed {" # Red = hue 0 assert updated_css =~ "--t-accent-h: 0" # Change to blue {:ok, _settings} = Settings.update_theme_settings(%{accent_color: "#0000ff"}) {:ok, blue_css} = CSSCache.get() # Blue = hue 240 assert blue_css =~ "--t-accent-h: 240" # Restore default CSSCache.warm() end test "validates mood values" do {:error, changeset} = Settings.update_theme_settings(%{mood: "invalid"}) assert "is invalid" in errors_on(changeset).mood end test "validates typography values" do {:error, changeset} = Settings.update_theme_settings(%{typography: "invalid"}) assert "is invalid" in errors_on(changeset).typography end test "validates logo size range" do {:error, changeset} = Settings.update_theme_settings(%{logo_size: 10}) assert "must be greater than or equal to 24" in errors_on(changeset).logo_size end test "preserves existing settings when updating subset" do {:ok, _} = Settings.update_theme_settings(%{mood: "warm"}) {:ok, settings} = Settings.update_theme_settings(%{typography: "modern"}) assert settings.mood == "warm" assert settings.typography == "modern" end end describe "apply_preset/1" do test "applies gallery preset successfully" do {:ok, settings} = Settings.apply_preset(:gallery) assert settings.mood == "warm" assert settings.typography == "editorial" assert settings.shape == "soft" assert settings.accent_color == "#e85d04" end test "applies studio preset successfully" do {:ok, settings} = Settings.apply_preset(:studio) assert settings.mood == "neutral" assert settings.typography == "clean" assert settings.accent_color == "#2563eb" end test "returns error for invalid preset" do assert {:error, :preset_not_found} = Settings.apply_preset(:nonexistent) end end describe "put_secret/2 and get_secret/2" do test "encrypts, stores, and retrieves a secret" do assert {:ok, _} = Settings.put_secret("test_key", "super_secret_value") assert Settings.get_secret("test_key") == "super_secret_value" end test "returns default when secret doesn't exist" do assert Settings.get_secret("nonexistent") == nil assert Settings.get_secret("nonexistent", "fallback") == "fallback" end test "upserts existing secret" do assert {:ok, _} = Settings.put_secret("test_key", "first_value") assert {:ok, _} = Settings.put_secret("test_key", "second_value") assert Settings.get_secret("test_key") == "second_value" end test "stores encrypted_value as binary, not plaintext" do {:ok, _} = Settings.put_secret("test_key", "plaintext_here") setting = Repo.get_by(SimpleshopTheme.Settings.Setting, key: "test_key") assert setting.value_type == "encrypted" assert setting.value == "[encrypted]" assert is_binary(setting.encrypted_value) refute setting.encrypted_value == "plaintext_here" end end describe "has_secret?/1" do test "returns false when secret doesn't exist" do refute Settings.has_secret?("nonexistent") end test "returns true when secret exists" do {:ok, _} = Settings.put_secret("test_key", "value") assert Settings.has_secret?("test_key") end end describe "secret_hint/1" do test "returns nil when secret doesn't exist" do assert Settings.secret_hint("nonexistent") == nil end test "returns masked hint for long secrets" do {:ok, _} = Settings.put_secret("test_key", "sk_test_abc123xyz789") hint = Settings.secret_hint("test_key") assert hint =~ "sk_test_" assert hint =~ "•••" assert hint =~ "789" end test "returns masked hint for short secrets" do {:ok, _} = Settings.put_secret("test_key", "short") assert Settings.secret_hint("test_key") == "•••" end end describe "site_live?/0 and set_site_live/1" do test "defaults to false when no setting exists" do refute Settings.site_live?() end test "returns true after setting site live" do assert {:ok, _} = Settings.set_site_live(true) assert Settings.site_live?() end test "returns false after setting site offline" do assert {:ok, _} = Settings.set_site_live(true) assert Settings.site_live?() assert {:ok, _} = Settings.set_site_live(false) refute Settings.site_live?() end end describe "delete_setting/1" do test "deletes an existing setting" do {:ok, _} = Settings.put_setting("to_delete", "value") assert Settings.get_setting("to_delete") == "value" assert {:ok, _} = Settings.delete_setting("to_delete") assert Settings.get_setting("to_delete") == nil end test "returns :ok when setting doesn't exist" do assert :ok = Settings.delete_setting("nonexistent") end end end