"""Tests for marketing_intelligence.storage.campaign_config.""" import json from pathlib import Path from typing import Any from unittest.mock import patch from marketing_intelligence.core.models import CampaignPost from marketing_intelligence.storage import campaign_config as cc def _patch_file(tmp_path: Path) -> Any: return patch.object( cc, "_config_file", return_value=tmp_path / "campaign_config.json" ) # ─────────────────────────── list_posts ──────────────────────────────────── class TestListPosts: def test_returns_empty_when_no_file(self, tmp_path: Path) -> None: with _patch_file(tmp_path): assert cc.list_posts("camp_a") == [] def test_returns_active_posts(self, tmp_path: Path) -> None: data = { "camp_a": [ {"post_id": "v1", "url": "", "is_active": True}, {"post_id": "v2", "url": "", "is_active": False}, ] } (tmp_path / "campaign_config.json").write_text(json.dumps(data)) with _patch_file(tmp_path): posts = cc.list_posts("camp_a") assert len(posts) == 1 assert posts[0].post_id == "v1" def test_defaults_to_active_when_flag_missing(self, tmp_path: Path) -> None: data = {"camp_a": [{"post_id": "v1", "url": ""}]} (tmp_path / "campaign_config.json").write_text(json.dumps(data)) with _patch_file(tmp_path): posts = cc.list_posts("camp_a") assert len(posts) == 1 # ─────────────────────────── add_posts ───────────────────────────────────── class TestAddPosts: def test_adds_new_posts(self, tmp_path: Path) -> None: posts = [CampaignPost(post_id="v1", url="https://tiktok.com/v1")] with _patch_file(tmp_path): added = cc.add_posts("camp_a", posts) assert added == 1 def test_does_not_duplicate(self, tmp_path: Path) -> None: data = {"camp_a": [{"post_id": "v1", "url": "", "is_active": True}]} (tmp_path / "campaign_config.json").write_text(json.dumps(data)) posts = [CampaignPost(post_id="v1", url="")] with _patch_file(tmp_path): added = cc.add_posts("camp_a", posts) assert added == 0 def test_reactivates_inactive_post(self, tmp_path: Path) -> None: data = {"camp_a": [{"post_id": "v1", "url": "", "is_active": False}]} (tmp_path / "campaign_config.json").write_text(json.dumps(data)) posts = [CampaignPost(post_id="v1", url="")] with _patch_file(tmp_path): cc.add_posts("camp_a", posts) result = cc.list_posts("camp_a") assert result[0].is_active is True def test_persists_to_file(self, tmp_path: Path) -> None: posts = [CampaignPost(post_id="v1", url="")] with _patch_file(tmp_path): cc.add_posts("camp_a", posts) saved = json.loads((tmp_path / "campaign_config.json").read_text()) assert len(saved["camp_a"]) == 1 # ─────────────────────────── deactivate_posts ────────────────────────────── class TestDeactivatePosts: def test_deactivates_all_active(self, tmp_path: Path) -> None: data = { "camp_a": [ {"post_id": "v1", "url": "", "is_active": True}, {"post_id": "v2", "url": "", "is_active": True}, ] } (tmp_path / "campaign_config.json").write_text(json.dumps(data)) with _patch_file(tmp_path): count = cc.deactivate_posts("camp_a") assert count == 2 def test_returns_zero_when_already_inactive(self, tmp_path: Path) -> None: data = {"camp_a": [{"post_id": "v1", "url": "", "is_active": False}]} (tmp_path / "campaign_config.json").write_text(json.dumps(data)) with _patch_file(tmp_path): count = cc.deactivate_posts("camp_a") assert count == 0 def test_returns_zero_for_unknown_campaign(self, tmp_path: Path) -> None: with _patch_file(tmp_path): count = cc.deactivate_posts("no_camp") assert count == 0 # ─────────────────────────── list_active_campaign_ids ────────────────────── class TestListActiveCampaignIds: def test_returns_ids_with_active_posts(self, tmp_path: Path) -> None: data = { "camp_a": [{"post_id": "v1", "is_active": True}], "camp_b": [{"post_id": "v2", "is_active": False}], } (tmp_path / "campaign_config.json").write_text(json.dumps(data)) with _patch_file(tmp_path): ids = cc.list_active_campaign_ids() assert ids == ["camp_a"] def test_returns_empty_when_no_file(self, tmp_path: Path) -> None: with _patch_file(tmp_path): assert cc.list_active_campaign_ids() == []