package store import ( "database/sql" "path/filepath" "testing" _ "github.com/mattn/go-sqlite3" ) func setupTestStoreWithShopping(t *testing.T) *Store { t.Helper() tempDir := t.TempDir() dbPath := filepath.Join(tempDir, "test.db") db, err := sql.Open("sqlite3", dbPath) if err != nil { t.Fatalf("Failed to open test database: %v", err) } db.SetMaxOpenConns(1) store := &Store{db: db} schema := ` CREATE TABLE IF NOT EXISTS user_shopping_items ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, store TEXT NOT NULL, checked INTEGER DEFAULT 0, created_at DATETIME DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE IF NOT EXISTS shopping_item_checks ( source TEXT NOT NULL, item_id TEXT NOT NULL, checked INTEGER DEFAULT 0, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (source, item_id) ); ` if _, err := db.Exec(schema); err != nil { t.Fatalf("Failed to create schema: %v", err) } return store } func TestUserShoppingItems_CRUD(t *testing.T) { store := setupTestStoreWithShopping(t) defer func() { _ = store.Close() }() // Save items if err := store.SaveUserShoppingItem("Milk", "Costco"); err != nil { t.Fatalf("Failed to save item: %v", err) } if err := store.SaveUserShoppingItem("Bread", "Safeway"); err != nil { t.Fatalf("Failed to save second item: %v", err) } // Get items items, err := store.GetUserShoppingItems() if err != nil { t.Fatalf("Failed to get items: %v", err) } if len(items) != 2 { t.Errorf("Expected 2 items, got %d", len(items)) } // Verify item data var milkItem UserShoppingItem for _, item := range items { if item.Name == "Milk" { milkItem = item break } } if milkItem.Name != "Milk" { t.Error("Could not find Milk item") } if milkItem.Store != "Costco" { t.Errorf("Expected store 'Costco', got '%s'", milkItem.Store) } if milkItem.Checked { t.Error("New item should not be checked") } // Toggle item if err := store.ToggleUserShoppingItem(milkItem.ID, true); err != nil { t.Fatalf("Failed to toggle item: %v", err) } items, _ = store.GetUserShoppingItems() for _, item := range items { if item.ID == milkItem.ID && !item.Checked { t.Error("Item should be checked after toggle") } } // Delete item if err := store.DeleteUserShoppingItem(milkItem.ID); err != nil { t.Fatalf("Failed to delete item: %v", err) } items, _ = store.GetUserShoppingItems() if len(items) != 1 { t.Errorf("Expected 1 item after delete, got %d", len(items)) } } func TestShoppingItemChecks_ExternalSources(t *testing.T) { store := setupTestStoreWithShopping(t) defer func() { _ = store.Close() }() // Set checked for trello item if err := store.SetShoppingItemChecked("trello", "card-123", true); err != nil { t.Fatalf("Failed to set trello checked: %v", err) } // Set checked for plantoeat item if err := store.SetShoppingItemChecked("plantoeat", "pte-456", true); err != nil { t.Fatalf("Failed to set plantoeat checked: %v", err) } // Get trello checks trelloChecks, err := store.GetShoppingItemChecks("trello") if err != nil { t.Fatalf("Failed to get trello checks: %v", err) } if !trelloChecks["card-123"] { t.Error("Expected trello card to be checked") } // Get plantoeat checks pteChecks, err := store.GetShoppingItemChecks("plantoeat") if err != nil { t.Fatalf("Failed to get plantoeat checks: %v", err) } if !pteChecks["pte-456"] { t.Error("Expected plantoeat item to be checked") } // Uncheck trello item if err := store.SetShoppingItemChecked("trello", "card-123", false); err != nil { t.Fatalf("Failed to uncheck trello item: %v", err) } trelloChecks, _ = store.GetShoppingItemChecks("trello") if trelloChecks["card-123"] { t.Error("Trello item should be unchecked after update") } }