test_sticker_cache.py
1 """Tests for gateway/sticker_cache.py — sticker description cache.""" 2 3 import json 4 import time 5 from unittest.mock import patch 6 7 from gateway.sticker_cache import ( 8 _load_cache, 9 _save_cache, 10 get_cached_description, 11 cache_sticker_description, 12 build_sticker_injection, 13 build_animated_sticker_injection, 14 STICKER_VISION_PROMPT, 15 ) 16 17 18 class TestLoadSaveCache: 19 def test_load_missing_file(self, tmp_path): 20 with patch("gateway.sticker_cache.CACHE_PATH", tmp_path / "nope.json"): 21 assert _load_cache() == {} 22 23 def test_load_corrupt_file(self, tmp_path): 24 bad_file = tmp_path / "bad.json" 25 bad_file.write_text("not json{{{") 26 with patch("gateway.sticker_cache.CACHE_PATH", bad_file): 27 assert _load_cache() == {} 28 29 def test_save_and_load_roundtrip(self, tmp_path): 30 cache_file = tmp_path / "cache.json" 31 data = {"abc123": {"description": "A cat", "emoji": "", "set_name": "", "cached_at": 1.0}} 32 with patch("gateway.sticker_cache.CACHE_PATH", cache_file): 33 _save_cache(data) 34 loaded = _load_cache() 35 assert loaded == data 36 37 def test_save_creates_parent_dirs(self, tmp_path): 38 cache_file = tmp_path / "sub" / "dir" / "cache.json" 39 with patch("gateway.sticker_cache.CACHE_PATH", cache_file): 40 _save_cache({"key": "value"}) 41 assert cache_file.exists() 42 43 44 class TestCacheSticker: 45 def test_cache_and_retrieve(self, tmp_path): 46 cache_file = tmp_path / "cache.json" 47 with patch("gateway.sticker_cache.CACHE_PATH", cache_file): 48 cache_sticker_description("uid_1", "A happy dog", emoji="🐕", set_name="Dogs") 49 result = get_cached_description("uid_1") 50 51 assert result is not None 52 assert result["description"] == "A happy dog" 53 assert result["emoji"] == "🐕" 54 assert result["set_name"] == "Dogs" 55 assert "cached_at" in result 56 57 def test_missing_sticker_returns_none(self, tmp_path): 58 cache_file = tmp_path / "cache.json" 59 with patch("gateway.sticker_cache.CACHE_PATH", cache_file): 60 result = get_cached_description("nonexistent") 61 assert result is None 62 63 def test_overwrite_existing(self, tmp_path): 64 cache_file = tmp_path / "cache.json" 65 with patch("gateway.sticker_cache.CACHE_PATH", cache_file): 66 cache_sticker_description("uid_1", "Old description") 67 cache_sticker_description("uid_1", "New description") 68 result = get_cached_description("uid_1") 69 70 assert result["description"] == "New description" 71 72 def test_multiple_stickers(self, tmp_path): 73 cache_file = tmp_path / "cache.json" 74 with patch("gateway.sticker_cache.CACHE_PATH", cache_file): 75 cache_sticker_description("uid_1", "Cat") 76 cache_sticker_description("uid_2", "Dog") 77 r1 = get_cached_description("uid_1") 78 r2 = get_cached_description("uid_2") 79 80 assert r1["description"] == "Cat" 81 assert r2["description"] == "Dog" 82 83 84 class TestBuildStickerInjection: 85 def test_exact_format_no_context(self): 86 result = build_sticker_injection("A cat waving") 87 assert result == '[The user sent a sticker~ It shows: "A cat waving" (=^.w.^=)]' 88 89 def test_exact_format_emoji_only(self): 90 result = build_sticker_injection("A cat", emoji="😀") 91 assert result == '[The user sent a sticker 😀~ It shows: "A cat" (=^.w.^=)]' 92 93 def test_exact_format_emoji_and_set_name(self): 94 result = build_sticker_injection("A cat", emoji="😀", set_name="MyPack") 95 assert result == '[The user sent a sticker 😀 from "MyPack"~ It shows: "A cat" (=^.w.^=)]' 96 97 def test_set_name_without_emoji_ignored(self): 98 """set_name alone (no emoji) produces no context — only emoji+set_name triggers 'from' clause.""" 99 result = build_sticker_injection("A cat", set_name="MyPack") 100 assert result == '[The user sent a sticker~ It shows: "A cat" (=^.w.^=)]' 101 assert "MyPack" not in result 102 103 def test_description_with_quotes(self): 104 result = build_sticker_injection('A "happy" dog') 105 assert '"A \\"happy\\" dog"' not in result # no escaping happens 106 assert 'A "happy" dog' in result 107 108 def test_empty_description(self): 109 result = build_sticker_injection("") 110 assert result == '[The user sent a sticker~ It shows: "" (=^.w.^=)]' 111 112 113 class TestBuildAnimatedStickerInjection: 114 def test_exact_format_with_emoji(self): 115 result = build_animated_sticker_injection(emoji="🎉") 116 assert result == ( 117 "[The user sent an animated sticker 🎉~ " 118 "I can't see animated ones yet, but the emoji suggests: 🎉]" 119 ) 120 121 def test_exact_format_without_emoji(self): 122 result = build_animated_sticker_injection() 123 assert result == "[The user sent an animated sticker~ I can't see animated ones yet]" 124 125 def test_empty_emoji_same_as_no_emoji(self): 126 result = build_animated_sticker_injection(emoji="") 127 assert result == build_animated_sticker_injection()