Coverage priorities 1-5: test pure functions, extract interfaces, mock-based handler tests
- Priority 1: Test NewSendEmailTask + NewSendPushTask (5 tests) - Priority 2: Test customHTTPErrorHandler — all 15+ branches (21 tests) - Priority 3: Extract Enqueuer interface + payload builders in worker pkg (5 tests) - Priority 4: Extract ClassifyFile/ComputeRelPath in migrate-encrypt (6 tests) - Priority 5: Define Handler interfaces, refactor to accept them, mock-based tests (14 tests) - Fix .gitignore: /worker instead of worker to stop ignoring internal/worker/ Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
236
internal/repositories/task_template_repo_test.go
Normal file
236
internal/repositories/task_template_repo_test.go
Normal file
@@ -0,0 +1,236 @@
|
||||
package repositories
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/treytartt/honeydue-api/internal/models"
|
||||
"github.com/treytartt/honeydue-api/internal/testutil"
|
||||
)
|
||||
|
||||
func TestTaskTemplateRepository_Create(t *testing.T) {
|
||||
db := testutil.SetupTestDB(t)
|
||||
testutil.SeedLookupData(t, db)
|
||||
repo := NewTaskTemplateRepository(db)
|
||||
|
||||
var cat models.TaskCategory
|
||||
require.NoError(t, db.First(&cat).Error)
|
||||
|
||||
var freq models.TaskFrequency
|
||||
require.NoError(t, db.First(&freq).Error)
|
||||
|
||||
template := &models.TaskTemplate{
|
||||
Title: "Change HVAC Filter",
|
||||
Description: "Replace the HVAC air filter",
|
||||
CategoryID: &cat.ID,
|
||||
FrequencyID: &freq.ID,
|
||||
IsActive: true,
|
||||
Tags: "hvac,filter,maintenance",
|
||||
}
|
||||
err := repo.Create(template)
|
||||
require.NoError(t, err)
|
||||
assert.NotZero(t, template.ID)
|
||||
}
|
||||
|
||||
func TestTaskTemplateRepository_GetAll(t *testing.T) {
|
||||
t.Skip("requires PostgreSQL: SQLite cannot scan jsonb default into json.RawMessage")
|
||||
db := testutil.SetupTestDB(t)
|
||||
testutil.SeedLookupData(t, db)
|
||||
repo := NewTaskTemplateRepository(db)
|
||||
|
||||
// Create active and inactive templates
|
||||
t1 := &models.TaskTemplate{Title: "Active Template", IsActive: true}
|
||||
t2 := &models.TaskTemplate{Title: "Inactive Template", IsActive: false}
|
||||
require.NoError(t, db.Create(t1).Error)
|
||||
require.NoError(t, db.Create(t2).Error)
|
||||
|
||||
templates, err := repo.GetAll()
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, templates, 1) // Only active
|
||||
assert.Equal(t, "Active Template", templates[0].Title)
|
||||
}
|
||||
|
||||
func TestTaskTemplateRepository_GetByCategory(t *testing.T) {
|
||||
t.Skip("requires PostgreSQL: SQLite cannot scan jsonb default into json.RawMessage")
|
||||
db := testutil.SetupTestDB(t)
|
||||
testutil.SeedLookupData(t, db)
|
||||
repo := NewTaskTemplateRepository(db)
|
||||
|
||||
var cat models.TaskCategory
|
||||
require.NoError(t, db.First(&cat).Error)
|
||||
|
||||
t1 := &models.TaskTemplate{Title: "Cat Template", CategoryID: &cat.ID, IsActive: true}
|
||||
t2 := &models.TaskTemplate{Title: "No Cat Template", IsActive: true}
|
||||
require.NoError(t, db.Create(t1).Error)
|
||||
require.NoError(t, db.Create(t2).Error)
|
||||
|
||||
templates, err := repo.GetByCategory(cat.ID)
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, templates, 1)
|
||||
assert.Equal(t, "Cat Template", templates[0].Title)
|
||||
}
|
||||
|
||||
func TestTaskTemplateRepository_Search(t *testing.T) {
|
||||
t.Skip("requires PostgreSQL: SQLite cannot scan jsonb default into json.RawMessage")
|
||||
db := testutil.SetupTestDB(t)
|
||||
repo := NewTaskTemplateRepository(db)
|
||||
|
||||
t1 := &models.TaskTemplate{Title: "Change HVAC Filter", Tags: "hvac,filter", IsActive: true}
|
||||
t2 := &models.TaskTemplate{Title: "Fix Faucet", Tags: "plumbing", IsActive: true}
|
||||
require.NoError(t, db.Create(t1).Error)
|
||||
require.NoError(t, db.Create(t2).Error)
|
||||
|
||||
// Search by title
|
||||
results, err := repo.Search("hvac")
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, results, 1)
|
||||
assert.Equal(t, "Change HVAC Filter", results[0].Title)
|
||||
|
||||
// Search by tag
|
||||
results, err = repo.Search("plumbing")
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, results, 1)
|
||||
assert.Equal(t, "Fix Faucet", results[0].Title)
|
||||
|
||||
// No match
|
||||
results, err = repo.Search("nonexistent")
|
||||
require.NoError(t, err)
|
||||
assert.Empty(t, results)
|
||||
}
|
||||
|
||||
func TestTaskTemplateRepository_GetByID(t *testing.T) {
|
||||
t.Skip("requires PostgreSQL: SQLite cannot scan jsonb default into json.RawMessage")
|
||||
db := testutil.SetupTestDB(t)
|
||||
repo := NewTaskTemplateRepository(db)
|
||||
|
||||
tmpl := &models.TaskTemplate{Title: "Test Template", IsActive: true}
|
||||
require.NoError(t, db.Create(tmpl).Error)
|
||||
|
||||
found, err := repo.GetByID(tmpl.ID)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "Test Template", found.Title)
|
||||
}
|
||||
|
||||
func TestTaskTemplateRepository_GetByID_NotFound(t *testing.T) {
|
||||
db := testutil.SetupTestDB(t)
|
||||
repo := NewTaskTemplateRepository(db)
|
||||
|
||||
_, err := repo.GetByID(9999)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestTaskTemplateRepository_Update(t *testing.T) {
|
||||
db := testutil.SetupTestDB(t)
|
||||
repo := NewTaskTemplateRepository(db)
|
||||
|
||||
tmpl := &models.TaskTemplate{Title: "Original", IsActive: true}
|
||||
require.NoError(t, db.Create(tmpl).Error)
|
||||
|
||||
tmpl.Title = "Updated"
|
||||
err := repo.Update(tmpl)
|
||||
require.NoError(t, err)
|
||||
|
||||
found, err := repo.GetByID(tmpl.ID)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "Updated", found.Title)
|
||||
}
|
||||
|
||||
func TestTaskTemplateRepository_Delete(t *testing.T) {
|
||||
db := testutil.SetupTestDB(t)
|
||||
repo := NewTaskTemplateRepository(db)
|
||||
|
||||
tmpl := &models.TaskTemplate{Title: "To Delete", IsActive: true}
|
||||
require.NoError(t, db.Create(tmpl).Error)
|
||||
|
||||
err := repo.Delete(tmpl.ID)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = repo.GetByID(tmpl.ID)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestTaskTemplateRepository_GetAllIncludingInactive(t *testing.T) {
|
||||
t.Skip("requires PostgreSQL: SQLite cannot scan jsonb default into json.RawMessage")
|
||||
db := testutil.SetupTestDB(t)
|
||||
repo := NewTaskTemplateRepository(db)
|
||||
|
||||
t1 := &models.TaskTemplate{Title: "Active", IsActive: true}
|
||||
t2 := &models.TaskTemplate{Title: "Inactive", IsActive: false}
|
||||
require.NoError(t, db.Create(t1).Error)
|
||||
require.NoError(t, db.Create(t2).Error)
|
||||
|
||||
templates, err := repo.GetAllIncludingInactive()
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, templates, 2) // Both active and inactive
|
||||
}
|
||||
|
||||
func TestTaskTemplateRepository_Count(t *testing.T) {
|
||||
db := testutil.SetupTestDB(t)
|
||||
repo := NewTaskTemplateRepository(db)
|
||||
|
||||
t1 := &models.TaskTemplate{Title: "Active 1", IsActive: true}
|
||||
t2 := &models.TaskTemplate{Title: "Active 2", IsActive: true}
|
||||
require.NoError(t, db.Create(t1).Error)
|
||||
require.NoError(t, db.Create(t2).Error)
|
||||
// Use raw SQL for inactive record to avoid GORM default:true overriding IsActive=false
|
||||
require.NoError(t, db.Exec(
|
||||
"INSERT INTO task_tasktemplate (title, is_active, display_order, created_at, updated_at) VALUES (?, ?, ?, datetime('now'), datetime('now'))",
|
||||
"Inactive", false, 0,
|
||||
).Error)
|
||||
|
||||
count, err := repo.Count()
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, int64(2), count) // Only active
|
||||
}
|
||||
|
||||
func TestTaskTemplateRepository_GetByRegion(t *testing.T) {
|
||||
t.Skip("requires PostgreSQL: SQLite cannot scan jsonb default into json.RawMessage")
|
||||
db := testutil.SetupTestDB(t)
|
||||
repo := NewTaskTemplateRepository(db)
|
||||
|
||||
// Create a climate region
|
||||
region := &models.ClimateRegion{Name: "Hot-Humid", ZoneNumber: 1, IsActive: true}
|
||||
require.NoError(t, db.Create(region).Error)
|
||||
|
||||
// Create template with region association
|
||||
tmpl := &models.TaskTemplate{Title: "Regional Task", IsActive: true}
|
||||
require.NoError(t, db.Create(tmpl).Error)
|
||||
|
||||
// Associate template with region via join table
|
||||
err := db.Exec("INSERT INTO task_tasktemplate_regions (task_template_id, climate_region_id) VALUES (?, ?)", tmpl.ID, region.ID).Error
|
||||
require.NoError(t, err)
|
||||
|
||||
// Create template without region
|
||||
tmpl2 := &models.TaskTemplate{Title: "Non-Regional Task", IsActive: true}
|
||||
require.NoError(t, db.Create(tmpl2).Error)
|
||||
|
||||
templates, err := repo.GetByRegion(region.ID)
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, templates, 1)
|
||||
assert.Equal(t, "Regional Task", templates[0].Title)
|
||||
}
|
||||
|
||||
func TestTaskTemplateRepository_GetGroupedByCategory(t *testing.T) {
|
||||
t.Skip("requires PostgreSQL: SQLite cannot scan jsonb default into json.RawMessage")
|
||||
db := testutil.SetupTestDB(t)
|
||||
testutil.SeedLookupData(t, db)
|
||||
repo := NewTaskTemplateRepository(db)
|
||||
|
||||
var cat models.TaskCategory
|
||||
require.NoError(t, db.First(&cat).Error)
|
||||
|
||||
t1 := &models.TaskTemplate{Title: "Categorized", CategoryID: &cat.ID, IsActive: true}
|
||||
t2 := &models.TaskTemplate{Title: "Uncategorized", IsActive: true}
|
||||
require.NoError(t, db.Create(t1).Error)
|
||||
require.NoError(t, db.Create(t2).Error)
|
||||
|
||||
grouped, err := repo.GetGroupedByCategory()
|
||||
require.NoError(t, err)
|
||||
assert.GreaterOrEqual(t, len(grouped), 2) // At least the category + "Uncategorized"
|
||||
|
||||
// Uncategorized should have the template without category
|
||||
assert.Len(t, grouped["Uncategorized"], 1)
|
||||
assert.Equal(t, "Uncategorized", grouped["Uncategorized"][0].Title)
|
||||
}
|
||||
Reference in New Issue
Block a user