package repos import ( "context" "gralias/models" "testing" "time" "github.com/jmoiron/sqlx" "github.com/stretchr/testify/assert" _ "github.com/mattn/go-sqlite3" ) func setupTestDB(t *testing.T) (*sqlx.DB, func()) { db, err := sqlx.Connect("sqlite3", ":memory:") assert.NoError(t, err) // Enable foreign key constraints for SQLite _, err = db.Exec("PRAGMA foreign_keys = ON;") assert.NoError(t, err) schema := ` CREATE TABLE IF NOT EXISTS rooms ( id TEXT PRIMARY KEY, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, creator_name TEXT NOT NULL, team_turn TEXT NOT NULL DEFAULT '', this_turn_limit INTEGER NOT NULL DEFAULT 0, opened_this_turn INTEGER NOT NULL DEFAULT 0, blue_counter INTEGER NOT NULL DEFAULT 0, red_counter INTEGER NOT NULL DEFAULT 0, red_turn BOOLEAN NOT NULL DEFAULT FALSE, mime_done BOOLEAN NOT NULL DEFAULT FALSE, is_running BOOLEAN NOT NULL DEFAULT FALSE, is_over BOOLEAN NOT NULL DEFAULT FALSE, team_won TEXT NOT NULL DEFAULT '', room_link TEXT NOT NULL DEFAULT '' ); CREATE TABLE IF NOT EXISTS players ( id INTEGER PRIMARY KEY AUTOINCREMENT, room_id TEXT, username TEXT NOT NULL UNIQUE, team TEXT NOT NULL DEFAULT '', role TEXT NOT NULL DEFAULT '', is_bot BOOLEAN NOT NULL DEFAULT FALSE, FOREIGN KEY (room_id) REFERENCES rooms(id) ON DELETE CASCADE ); CREATE TABLE IF NOT EXISTS word_cards ( id INTEGER PRIMARY KEY AUTOINCREMENT, room_id TEXT NOT NULL, word TEXT NOT NULL, color TEXT NOT NULL DEFAULT '', revealed BOOLEAN NOT NULL DEFAULT FALSE, mime_view BOOLEAN NOT NULL DEFAULT FALSE, FOREIGN KEY (room_id) REFERENCES rooms(id) ON DELETE CASCADE ); CREATE TABLE IF NOT EXISTS card_marks ( id INTEGER PRIMARY KEY AUTOINCREMENT, card_id INTEGER NOT NULL, username TEXT NOT NULL, active BOOLEAN NOT NULL DEFAULT TRUE, FOREIGN KEY (card_id) REFERENCES word_cards(id) ON DELETE CASCADE ); CREATE TABLE IF NOT EXISTS actions ( id INTEGER PRIMARY KEY AUTOINCREMENT, room_id TEXT NOT NULL, actor TEXT NOT NULL, actor_color TEXT NOT NULL DEFAULT '', action_type TEXT NOT NULL, word TEXT NOT NULL DEFAULT '', word_color TEXT NOT NULL DEFAULT '', number_associated TEXT NOT NULL DEFAULT '', created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (room_id) REFERENCES rooms(id) ON DELETE CASCADE ); CREATE TABLE IF NOT EXISTS settings ( id INTEGER PRIMARY KEY AUTOINCREMENT, room_id TEXT NOT NULL, language TEXT NOT NULL DEFAULT 'en', room_pass TEXT NOT NULL DEFAULT '', turn_time INTEGER NOT NULL DEFAULT 60, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (room_id) REFERENCES rooms(id) ON DELETE CASCADE ); CREATE TABLE IF NOT EXISTS sessions( id INTEGER PRIMARY KEY AUTOINCREMENT, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, lifetime INTEGER NOT NULL DEFAULT 3600, token_key TEXT NOT NULL DEFAULT '' UNIQUE, username TEXT NOT NULL, FOREIGN KEY (username) REFERENCES players(username) ON DELETE CASCADE ); ` _, err = db.Exec(schema) assert.NoError(t, err) return db, func() { db.Close() } } func TestRoomsRepo_CreateRoom(t *testing.T) { db, teardown := setupTestDB(t) defer teardown() repo := &RepoProvider{DB: db} room := &models.Room{ ID: "test_room_1", CreatedAt: time.Now(), CreatorName: "test_creator", TeamTurn: "blue", ThisTurnLimit: 5, OpenedThisTurn: 0, BlueCounter: 0, RedCounter: 0, RedTurn: false, MimeDone: false, IsRunning: false, IsOver: false, TeamWon: "", RoomLink: "", Settings: models.GameSettings{ Language: "en", RoundTime: 60, RoomPass: "", }, } err := repo.RoomCreate(context.Background(), room) assert.NoError(t, err) // Verify the room was created var retrievedRoom models.Room err = db.Get(&retrievedRoom, "SELECT * FROM rooms WHERE id = ?", room.ID) assert.NoError(t, err) assert.Equal(t, room.ID, retrievedRoom.ID) assert.Equal(t, room.CreatorName, retrievedRoom.CreatorName) var retrievedSettings models.GameSettings err = db.Get(&retrievedSettings, "SELECT id, language, room_pass, turn_time FROM settings WHERE room_id = ?", room.ID) assert.NoError(t, err) assert.Equal(t, room.Settings.Language, retrievedSettings.Language) assert.Equal(t, room.Settings.RoundTime, retrievedSettings.RoundTime) assert.Equal(t, room.Settings.RoomPass, retrievedSettings.RoomPass) } func TestRoomsRepo_GetRoomByID(t *testing.T) { db, teardown := setupTestDB(t) defer teardown() repo := &RepoProvider{DB: db} room := &models.Room{ ID: "test_room_2", CreatedAt: time.Now(), CreatorName: "test_creator_2", TeamTurn: "red", ThisTurnLimit: 5, OpenedThisTurn: 0, BlueCounter: 0, RedCounter: 0, RedTurn: true, MimeDone: false, IsRunning: false, IsOver: false, TeamWon: "", RoomLink: "", Settings: models.GameSettings{ Language: "en", RoundTime: 60, RoomPass: "", }, } // Insert a room directly into the database for testing GetRoomByID _, err := db.Exec(`INSERT INTO rooms (id, created_at, creator_name, team_turn, this_turn_limit, opened_this_turn, blue_counter, red_counter, red_turn, mime_done, is_running, is_over, team_won, room_link) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, room.ID, room.CreatedAt, room.CreatorName, room.TeamTurn, room.ThisTurnLimit, room.OpenedThisTurn, room.BlueCounter, room.RedCounter, room.RedTurn, room.MimeDone, room.IsRunning, room.IsOver, room.TeamWon, room.RoomLink) assert.NoError(t, err) _, err = db.Exec(`INSERT INTO settings (room_id, language, room_pass, turn_time) VALUES (?, ?, ?, ?)`, room.ID, room.Settings.Language, room.Settings.RoomPass, room.Settings.RoundTime) assert.NoError(t, err) retrievedRoom, err := repo.RoomGetByID(context.Background(), room.ID) assert.NoError(t, err) assert.NotNil(t, retrievedRoom) assert.Equal(t, room.ID, retrievedRoom.ID) assert.Equal(t, room.CreatorName, retrievedRoom.CreatorName) assert.Equal(t, room.Settings.Language, retrievedRoom.Settings.Language) } func TestRoomsRepo_ListRooms(t *testing.T) { db, teardown := setupTestDB(t) defer teardown() repo := &RepoProvider{DB: db} room1 := &models.Room{ ID: "list_room_1", CreatedAt: time.Now(), CreatorName: "list_creator_1", TeamTurn: "blue", ThisTurnLimit: 5, OpenedThisTurn: 0, BlueCounter: 0, RedCounter: 0, RedTurn: false, MimeDone: false, IsRunning: false, IsOver: false, TeamWon: "", RoomLink: "", Settings: models.GameSettings{ Language: "en", RoundTime: 60, RoomPass: "", }, } room2 := &models.Room{ ID: "list_room_2", CreatedAt: time.Now(), CreatorName: "list_creator_2", TeamTurn: "red", ThisTurnLimit: 5, OpenedThisTurn: 0, BlueCounter: 0, RedCounter: 0, RedTurn: true, MimeDone: false, IsRunning: false, IsOver: false, TeamWon: "", RoomLink: "", Settings: models.GameSettings{ Language: "en", RoundTime: 60, RoomPass: "", }, } _, err := db.Exec(`INSERT INTO rooms (id, created_at, creator_name, team_turn, this_turn_limit, opened_this_turn, blue_counter, red_counter, red_turn, mime_done, is_running, is_over, team_won, room_link) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, room1.ID, room1.CreatedAt, room1.CreatorName, room1.TeamTurn, room1.ThisTurnLimit, room1.OpenedThisTurn, room1.BlueCounter, room1.RedCounter, room1.RedTurn, room1.MimeDone, room1.IsRunning, room1.IsOver, room1.TeamWon, room1.RoomLink) assert.NoError(t, err) _, err = db.Exec(`INSERT INTO settings (room_id, language, room_pass, turn_time) VALUES (?, ?, ?, ?)`, room1.ID, room1.Settings.Language, room1.Settings.RoomPass, room1.Settings.RoundTime) assert.NoError(t, err) _, err = db.Exec(`INSERT INTO rooms (id, created_at, creator_name, team_turn, this_turn_limit, opened_this_turn, blue_counter, red_counter, red_turn, mime_done, is_running, is_over, team_won, room_link) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, room2.ID, room2.CreatedAt, room2.CreatorName, room2.TeamTurn, room2.ThisTurnLimit, room2.OpenedThisTurn, room2.BlueCounter, room2.RedCounter, room2.RedTurn, room2.MimeDone, room2.IsRunning, room2.IsOver, room2.TeamWon, room2.RoomLink) assert.NoError(t, err) _, err = db.Exec(`INSERT INTO settings (room_id, language, room_pass, turn_time) VALUES (?, ?, ?, ?)`, room2.ID, room2.Settings.Language, room2.Settings.RoomPass, room2.Settings.RoundTime) assert.NoError(t, err) rooms, err := repo.RoomList(context.Background()) assert.NoError(t, err) assert.Len(t, rooms, 2) } func TestRoomsRepo_DeleteRoomByID(t *testing.T) { db, teardown := setupTestDB(t) defer teardown() repo := &RepoProvider{DB: db} room := &models.Room{ ID: "delete_room_1", CreatedAt: time.Now(), CreatorName: "delete_creator_1", TeamTurn: "blue", ThisTurnLimit: 5, OpenedThisTurn: 0, BlueCounter: 0, RedCounter: 0, RedTurn: false, MimeDone: false, IsRunning: false, IsOver: false, TeamWon: "", RoomLink: "", Settings: models.GameSettings{ Language: "en", RoundTime: 60, RoomPass: "", }, } _, err := db.Exec(`INSERT INTO rooms (id, created_at, creator_name, team_turn, this_turn_limit, opened_this_turn, blue_counter, red_counter, red_turn, mime_done, is_running, is_over, team_won, room_link) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, room.ID, room.CreatedAt, room.CreatorName, room.TeamTurn, room.ThisTurnLimit, room.OpenedThisTurn, room.BlueCounter, room.RedCounter, room.RedTurn, room.MimeDone, room.IsRunning, room.IsOver, room.TeamWon, room.RoomLink) assert.NoError(t, err) _, err = db.Exec(`INSERT INTO settings (room_id, language, room_pass, turn_time) VALUES (?, ?, ?, ?)`, room.ID, room.Settings.Language, room.Settings.RoomPass, room.Settings.RoundTime) assert.NoError(t, err) // Insert a word card for the room wordCard := &models.WordCard{ RoomID: room.ID, Word: "test_word", Color: models.WordColorBlue, Revealed: false, Mime: false, } _, err = db.Exec(`INSERT INTO word_cards (room_id, word, color, revealed, mime_view) VALUES (?, ?, ?, ?, ?)`, wordCard.RoomID, wordCard.Word, wordCard.Color, wordCard.Revealed, wordCard.Mime) assert.NoError(t, err) err = repo.RoomDeleteByID(context.Background(), room.ID) assert.NoError(t, err) var count int err = db.Get(&count, "SELECT COUNT(*) FROM rooms WHERE id = ?", room.ID) assert.NoError(t, err) assert.Equal(t, 0, count) err = db.Get(&count, "SELECT COUNT(*) FROM settings WHERE room_id = ?", room.ID) assert.NoError(t, err) assert.Equal(t, 0, count) err = db.Get(&count, "SELECT COUNT(*) FROM word_cards WHERE room_id = ?", room.ID) assert.NoError(t, err) assert.Equal(t, 0, count) } func TestRoomsRepo_UpdateRoom(t *testing.T) { db, teardown := setupTestDB(t) defer teardown() repo := &RepoProvider{DB: db} room := &models.Room{ ID: "update_room_1", CreatedAt: time.Now(), CreatorName: "update_creator_1", TeamTurn: "blue", ThisTurnLimit: 5, OpenedThisTurn: 0, BlueCounter: 0, RedCounter: 0, RedTurn: false, MimeDone: false, IsRunning: false, IsOver: false, TeamWon: "", RoomLink: "", Settings: models.GameSettings{ Language: "en", RoundTime: 60, RoomPass: "", }, } _, err := db.Exec(`INSERT INTO rooms (id, created_at, creator_name, team_turn, this_turn_limit, opened_this_turn, blue_counter, red_counter, red_turn, mime_done, is_running, is_over, team_won, room_link) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, room.ID, room.CreatedAt, room.CreatorName, room.TeamTurn, room.ThisTurnLimit, room.OpenedThisTurn, room.BlueCounter, room.RedCounter, room.RedTurn, room.MimeDone, room.IsRunning, room.IsOver, room.TeamWon, room.RoomLink) assert.NoError(t, err) _, err = db.Exec(`INSERT INTO settings (room_id, language, room_pass, turn_time) VALUES (?, ?, ?, ?)`, room.ID, room.Settings.Language, room.Settings.RoomPass, room.Settings.RoundTime) assert.NoError(t, err) room.TeamTurn = "red" room.BlueCounter = 10 room.Settings.RoundTime = 120 err = repo.RoomUpdate(context.Background(), room) assert.NoError(t, err) var updatedRoom models.Room err = db.Get(&updatedRoom, "SELECT * FROM rooms WHERE id = ?", room.ID) assert.NoError(t, err) assert.Equal(t, models.UserTeam("red"), updatedRoom.TeamTurn) assert.Equal(t, uint8(10), updatedRoom.BlueCounter) var updatedSettings models.GameSettings err = db.Get(&updatedSettings, "SELECT * FROM settings WHERE room_id = ?", room.ID) assert.NoError(t, err) assert.Equal(t, uint32(120), updatedSettings.RoundTime) }