Files
lemma/server/internal/db/scanner_test.go

299 lines
7.1 KiB
Go

package db_test
import (
"database/sql"
"testing"
"time"
"lemma/internal/db"
)
func TestScannerQueryRow(t *testing.T) {
mockSecrets := &mockSecretsService{}
testDB, err := db.NewTestDB(mockSecrets)
if err != nil {
t.Fatalf("Failed to create test database: %v", err)
}
defer testDB.Close()
// Create a test table
_, err = testDB.TestDB().Exec(`
CREATE TABLE users (
id INTEGER PRIMARY KEY,
email TEXT NOT NULL,
created_at TIMESTAMP NOT NULL,
active BOOLEAN NOT NULL
)
`)
if err != nil {
t.Fatalf("Failed to create test table: %v", err)
}
type User struct {
ID int
Email string
CreatedAt time.Time
Active bool
}
// Insert test data
now := time.Now().UTC().Truncate(time.Second)
_, err = testDB.TestDB().Exec(
"INSERT INTO users (id, email, created_at, active) VALUES (?, ?, ?, ?)",
1, "test@example.com", now, true,
)
if err != nil {
t.Fatalf("Failed to insert test data: %v", err)
}
// Test query row success
t.Run("QueryRow success", func(t *testing.T) {
scanner := db.NewScanner(testDB.TestDB(), db.DBTypeSQLite)
q := db.NewQuery(db.DBTypeSQLite)
q.Select("id", "email", "created_at", "active").
From("users").
Where("id = ").
Placeholder(1)
var user User
err := scanner.QueryRow(&user, q)
if err != nil {
t.Errorf("Expected no error, got %v", err)
}
if user.ID != 1 {
t.Errorf("Expected ID 1, got %d", user.ID)
}
if user.Email != "test@example.com" {
t.Errorf("Expected Email test@example.com, got %s", user.Email)
}
if !user.CreatedAt.Equal(now) {
t.Errorf("Expected CreatedAt %v, got %v", now, user.CreatedAt)
}
if !user.Active {
t.Errorf("Expected Active true, got %v", user.Active)
}
})
// Test query row no results
t.Run("QueryRow no results", func(t *testing.T) {
scanner := db.NewScanner(testDB.TestDB(), db.DBTypeSQLite)
q := db.NewQuery(db.DBTypeSQLite)
q.Select("id", "email", "created_at", "active").
From("users").
Where("id = ").
Placeholder(999)
var user User
err := scanner.QueryRow(&user, q)
if err != sql.ErrNoRows {
t.Errorf("Expected ErrNoRows, got %v", err)
}
})
// Test scanning a single value
t.Run("QueryRow single value", func(t *testing.T) {
scanner := db.NewScanner(testDB.TestDB(), db.DBTypeSQLite)
q := db.NewQuery(db.DBTypeSQLite)
q.Select("COUNT(*)").From("users")
var count int
err := scanner.QueryRow(&count, q)
if err != nil {
t.Errorf("Expected no error, got %v", err)
}
if count != 1 {
t.Errorf("Expected count 1, got %d", count)
}
})
}
func TestScannerQuery(t *testing.T) {
mockSecrets := &mockSecretsService{}
testDB, err := db.NewTestDB(mockSecrets)
if err != nil {
t.Fatalf("Failed to create test database: %v", err)
}
defer testDB.Close()
// Create a test table
_, err = testDB.TestDB().Exec(`
CREATE TABLE users (
id INTEGER PRIMARY KEY,
email TEXT NOT NULL,
created_at TIMESTAMP NOT NULL,
active BOOLEAN NOT NULL
)
`)
if err != nil {
t.Fatalf("Failed to create test table: %v", err)
}
type User struct {
ID int
Email string
CreatedAt time.Time
Active bool
}
// Insert test data
now := time.Now().UTC().Truncate(time.Second)
testUsers := []User{
{ID: 1, Email: "user1@example.com", CreatedAt: now, Active: true},
{ID: 2, Email: "user2@example.com", CreatedAt: now, Active: false},
{ID: 3, Email: "user3@example.com", CreatedAt: now, Active: true},
}
for _, user := range testUsers {
_, err = testDB.TestDB().Exec(
"INSERT INTO users (id, email, created_at, active) VALUES (?, ?, ?, ?)",
user.ID, user.Email, user.CreatedAt, user.Active,
)
if err != nil {
t.Fatalf("Failed to insert test data: %v", err)
}
}
// Test query multiple rows
t.Run("Query multiple rows", func(t *testing.T) {
scanner := db.NewScanner(testDB.TestDB(), db.DBTypeSQLite)
q := db.NewQuery(db.DBTypeSQLite)
q.Select("id", "email", "created_at", "active").
From("users").
OrderBy("id ASC")
var users []User
err := scanner.Query(&users, q)
if err != nil {
t.Errorf("Expected no error, got %v", err)
}
if len(users) != len(testUsers) {
t.Errorf("Expected %d users, got %d", len(testUsers), len(users))
}
for i, u := range users {
if u.ID != testUsers[i].ID {
t.Errorf("Expected user[%d].ID %d, got %d", i, testUsers[i].ID, u.ID)
}
if u.Email != testUsers[i].Email {
t.Errorf("Expected user[%d].Email %s, got %s", i, testUsers[i].Email, u.Email)
}
if !u.CreatedAt.Equal(testUsers[i].CreatedAt) {
t.Errorf("Expected user[%d].CreatedAt %v, got %v", i, testUsers[i].CreatedAt, u.CreatedAt)
}
if u.Active != testUsers[i].Active {
t.Errorf("Expected user[%d].Active %v, got %v", i, testUsers[i].Active, u.Active)
}
}
})
// Test query with filter
t.Run("Query with filter", func(t *testing.T) {
scanner := db.NewScanner(testDB.TestDB(), db.DBTypeSQLite)
q := db.NewQuery(db.DBTypeSQLite)
q.Select("id", "email", "created_at", "active").
From("users").
Where("active = ").
Placeholder(true).
OrderBy("id ASC")
var users []User
err := scanner.Query(&users, q)
if err != nil {
t.Errorf("Expected no error, got %v", err)
}
if len(users) != 2 {
t.Errorf("Expected 2 users, got %d", len(users))
}
for _, u := range users {
if !u.Active {
t.Errorf("Expected only active users, got inactive user: %+v", u)
}
}
})
// Test query empty result
t.Run("Query empty result", func(t *testing.T) {
scanner := db.NewScanner(testDB.TestDB(), db.DBTypeSQLite)
q := db.NewQuery(db.DBTypeSQLite)
q.Select("id", "email", "created_at", "active").
From("users").
Where("id > ").
Placeholder(100)
var users []User
err := scanner.Query(&users, q)
if err != nil {
t.Errorf("Expected no error, got %v", err)
}
if len(users) != 0 {
t.Errorf("Expected 0 users, got %d", len(users))
}
})
}
func TestScanErrors(t *testing.T) {
mockSecrets := &mockSecretsService{}
testDB, err := db.NewTestDB(mockSecrets)
if err != nil {
t.Fatalf("Failed to create test database: %v", err)
}
defer testDB.Close()
scanner := db.NewScanner(testDB.TestDB(), db.DBTypeSQLite)
q := db.NewQuery(db.DBTypeSQLite)
q.Select("1")
// Test non-pointer
t.Run("QueryRow non-pointer", func(t *testing.T) {
var user struct{}
err := scanner.QueryRow(user, q) // Passing non-pointer
if err == nil {
t.Error("Expected error for non-pointer, got nil")
}
})
// Test pointer to non-slice for Query
t.Run("Query pointer to non-slice", func(t *testing.T) {
var user struct{}
err := scanner.Query(&user, q) // Passing pointer to struct, not slice
if err == nil {
t.Error("Expected error for non-slice pointer, got nil")
}
})
// Test non-pointer for Query
t.Run("Query non-pointer", func(t *testing.T) {
var users []struct{}
err := scanner.Query(users, q) // Passing non-pointer
if err == nil {
t.Error("Expected error for non-pointer, got nil")
}
})
}
// Mock secrets service for testing
type mockSecretsService struct{}
func (m *mockSecretsService) Encrypt(plaintext string) (string, error) {
return plaintext, nil
}
func (m *mockSecretsService) Decrypt(ciphertext string) (string, error) {
return ciphertext, nil
}