package cache import ( "context" "encoding/json" "testing" "time" ) // mockCacheStore is a mock implementation of Cache for testing type mockCacheStore struct { data map[string][]byte } func (m *mockCacheStore) Get(ctx context.Context, key *CacheKey) ([]byte, error) { keyStr := key.Kind + ":" + key.Code if data, ok := m.data[keyStr]; ok { return data, nil } return nil, nil } func (m *mockCacheStore) Set(ctx context.Context, key *CacheKey, data []byte, ttl time.Duration) error { keyStr := key.Kind + ":" + key.Code m.data[keyStr] = data return nil } func (m *mockCacheStore) Exists(ctx context.Context, key *CacheKey) (bool, error) { keyStr := key.Kind + ":" + key.Code _, ok := m.data[keyStr] return ok, nil } func (m *mockCacheStore) Delete(ctx context.Context, key *CacheKey) error { keyStr := key.Kind + ":" + key.Code delete(m.data, keyStr) return nil } func (m *mockCacheStore) Increment(ctx context.Context, key *CacheKey) (int64, error) { return 0, nil } func (m *mockCacheStore) Decrement(ctx context.Context, key *CacheKey) (int64, error) { return 0, nil } func TestNewPreferences(t *testing.T) { mockStore := &mockCacheStore{data: make(map[string][]byte)} prefs := NewPreferences(mockStore) if prefs == nil { t.Error("expected Preferences to be created") } if prefs.store == nil { t.Error("expected store to be initialized") } } func TestPreferencesGetSavedCities(t *testing.T) { mockStore := &mockCacheStore{data: make(map[string][]byte)} prefs := NewPreferences(mockStore) // Test with no data cities, err := prefs.GetSavedCities(context.Background(), "user1") if err != nil { t.Errorf("expected no error, got %v", err) } if len(cities) != 0 { t.Errorf("expected 0 cities, got %d", len(cities)) } // Test with data - the key is "prefs:saved_city:user1:user1" citiesData, _ := json.Marshal([]PreferenceSavedCity{ {CityCode: "c1", Name: "Moscow"}, {CityCode: "c2", Name: "St. Petersburg"}, }) mockStore.data["prefs:saved_city:user1:user1"] = citiesData cities, err = prefs.GetSavedCities(context.Background(), "user1") if err != nil { t.Errorf("expected no error, got %v", err) } if len(cities) != 2 { t.Errorf("expected 2 cities, got %d", len(cities)) } if cities[0].CityCode != "c1" { t.Errorf("expected first city code 'c1', got '%s'", cities[0].CityCode) } } func TestPreferencesAddSavedCity(t *testing.T) { mockStore := &mockCacheStore{data: make(map[string][]byte)} prefs := NewPreferences(mockStore) // Add first city err := prefs.AddSavedCity(context.Background(), "user1", "c1", "Moscow") if err != nil { t.Errorf("expected no error, got %v", err) } // Add second city err = prefs.AddSavedCity(context.Background(), "user1", "c2", "St. Petersburg") if err != nil { t.Errorf("expected no error, got %v", err) } // Verify cities cities, err := prefs.GetSavedCities(context.Background(), "user1") if err != nil { t.Errorf("expected no error, got %v", err) } if len(cities) != 2 { t.Errorf("expected 2 cities, got %d", len(cities)) } // Update existing city err = prefs.AddSavedCity(context.Background(), "user1", "c1", "Moscow Updated") if err != nil { t.Errorf("expected no error, got %v", err) } cities, err = prefs.GetSavedCities(context.Background(), "user1") if err != nil { t.Errorf("expected no error, got %v", err) } if cities[0].Name != "Moscow Updated" { t.Errorf("expected city name 'Moscow Updated', got '%s'", cities[0].Name) } } func TestPreferencesRemoveSavedCity(t *testing.T) { mockStore := &mockCacheStore{data: make(map[string][]byte)} prefs := NewPreferences(mockStore) // Add cities prefs.AddSavedCity(context.Background(), "user1", "c1", "Moscow") prefs.AddSavedCity(context.Background(), "user1", "c2", "St. Petersburg") // Remove one city err := prefs.RemoveSavedCity(context.Background(), "user1", "c1") if err != nil { t.Errorf("expected no error, got %v", err) } cities, err := prefs.GetSavedCities(context.Background(), "user1") if err != nil { t.Errorf("expected no error, got %v", err) } if len(cities) != 1 { t.Errorf("expected 1 city, got %d", len(cities)) } if cities[0].CityCode != "c2" { t.Errorf("expected city code 'c2', got '%s'", cities[0].CityCode) } // Remove all cities err = prefs.RemoveSavedCity(context.Background(), "user1", "c2") if err != nil { t.Errorf("expected no error, got %v", err) } cities, err = prefs.GetSavedCities(context.Background(), "user1") if err != nil { t.Errorf("expected no error, got %v", err) } if len(cities) != 0 { t.Errorf("expected 0 cities, got %d", len(cities)) } } func TestPreferencesGetSearchHistory(t *testing.T) { mockStore := &mockCacheStore{data: make(map[string][]byte)} prefs := NewPreferences(mockStore) // Test with no data history, err := prefs.GetSearchHistory(context.Background(), "user1") if err != nil { t.Errorf("expected no error, got %v", err) } if len(history) != 0 { t.Errorf("expected 0 history entries, got %d", len(history)) } // Test with data - the key is "prefs:search_history:user1:user1" historyData, _ := json.Marshal([]PreferenceSearchHistory{ {Query: "c1→c2", FromCity: "c1", ToCity: "c2", Date: "2026-08-15", CreatedAt: time.Now().Unix()}, }) mockStore.data["prefs:search_history:user1:user1"] = historyData history, err = prefs.GetSearchHistory(context.Background(), "user1") if err != nil { t.Errorf("expected no error, got %v", err) } if len(history) != 1 { t.Errorf("expected 1 history entry, got %d", len(history)) } if history[0].FromCity != "c1" { t.Errorf("expected from_city 'c1', got '%s'", history[0].FromCity) } } func TestPreferencesAddSearchHistory(t *testing.T) { mockStore := &mockCacheStore{data: make(map[string][]byte)} prefs := NewPreferences(mockStore) // Add search history err := prefs.AddSearchHistory(context.Background(), "user1", "c1", "c2", "2026-08-15") if err != nil { t.Errorf("expected no error, got %v", err) } history, err := prefs.GetSearchHistory(context.Background(), "user1") if err != nil { t.Errorf("expected no error, got %v", err) } if len(history) != 1 { t.Errorf("expected 1 history entry, got %d", len(history)) } if history[0].Query != "c1→c2" { t.Errorf("expected query 'c1→c2', got '%s'", history[0].Query) } } func TestPreferencesRemoveOldSearchHistory(t *testing.T) { mockStore := &mockCacheStore{data: make(map[string][]byte)} prefs := NewPreferences(mockStore) now := time.Now().Unix() // Add history with mixed ages history := []PreferenceSearchHistory{ {Query: "old", FromCity: "c1", ToCity: "c2", Date: "2026-01-01", CreatedAt: now - 100}, {Query: "new", FromCity: "c3", ToCity: "c4", Date: "2026-08-15", CreatedAt: now - 10}, } historyData, _ := json.Marshal(history) mockStore.data["prefs:search_history:user1:user1"] = historyData // Remove old entries (keep only last 50 seconds) err := prefs.RemoveOldSearchHistory(context.Background(), "user1", 50) if err != nil { t.Errorf("expected no error, got %v", err) } history, err = prefs.GetSearchHistory(context.Background(), "user1") if err != nil { t.Errorf("expected no error, got %v", err) } if len(history) != 1 { t.Errorf("expected 1 history entry, got %d", len(history)) } if history[0].Query != "new" { t.Errorf("expected query 'new', got '%s'", history[0].Query) } }