package canned import ( "context" "testing" "github.com/gochat/gochat/internal/model" ) func TestCannedResponseService_Create(t *testing.T) { provider := setupCannedTestDBProvider(t) accountID, _ := seedTestAccount(provider.DB(), t) svc := NewCannedResponseService(provider) cr := &CannedResponse{ AccountID: accountID, ShortCode: "greeting", Content: "Hello! How can I help you?", } if err := svc.Create(context.Background(), cr); err != nil { t.Fatalf("Create failed: %v", err) } if cr.ID == 0 { t.Fatal("expected ID to be set after Create") } if cr.ShortCode != "greeting" { t.Fatalf("expected ShortCode 'greeting', got '%s'", cr.ShortCode) } if cr.Content != "Hello! How can I help you?" { t.Fatalf("expected Content 'Hello! How can I help you?', got '%s'", cr.Content) } } func TestCannedResponseService_Create_DuplicateShortCode(t *testing.T) { provider := setupCannedTestDBProvider(t) accountID, _ := seedTestAccount(provider.DB(), t) svc := NewCannedResponseService(provider) cr1 := &CannedResponse{ AccountID: accountID, ShortCode: "greeting", Content: "Hello!", } if err := svc.Create(context.Background(), cr1); err != nil { t.Fatalf("first Create failed: %v", err) } // Same short_code within the same account should fail due to uniqueIndex. cr2 := &CannedResponse{ AccountID: accountID, ShortCode: "greeting", Content: "Hi there!", } if err := svc.Create(context.Background(), cr2); err == nil { t.Fatal("expected error on duplicate short_code, got nil") } } func TestCannedResponseService_GetByID(t *testing.T) { provider := setupCannedTestDBProvider(t) accountID, _ := seedTestAccount(provider.DB(), t) svc := NewCannedResponseService(provider) cr := &CannedResponse{ AccountID: accountID, ShortCode: "thanks", Content: "Thank you for contacting us!", } if err := svc.Create(context.Background(), cr); err != nil { t.Fatalf("Create failed: %v", err) } found, err := svc.GetByID(context.Background(), cr.ID) if err != nil { t.Fatalf("GetByID failed: %v", err) } if found.ID != cr.ID { t.Fatalf("expected ID %d, got %d", cr.ID, found.ID) } if found.ShortCode != "thanks" { t.Fatalf("expected ShortCode 'thanks', got '%s'", found.ShortCode) } if found.Content != "Thank you for contacting us!" { t.Fatalf("expected Content 'Thank you for contacting us!', got '%s'", found.Content) } } func TestCannedResponseService_GetByID_NotFound(t *testing.T) { provider := setupCannedTestDBProvider(t) svc := NewCannedResponseService(provider) _, err := svc.GetByID(context.Background(), 9999) if err == nil { t.Fatal("expected error for non-existent ID, got nil") } } func TestCannedResponseService_Update(t *testing.T) { provider := setupCannedTestDBProvider(t) accountID, _ := seedTestAccount(provider.DB(), t) svc := NewCannedResponseService(provider) cr := &CannedResponse{ AccountID: accountID, ShortCode: "bye", Content: "Goodbye!", } if err := svc.Create(context.Background(), cr); err != nil { t.Fatalf("Create failed: %v", err) } updates := map[string]interface{}{ "short_code": "farewell", "content": "Farewell and thank you!", } if err := svc.Update(context.Background(), cr.ID, updates); err != nil { t.Fatalf("Update failed: %v", err) } found, err := svc.GetByID(context.Background(), cr.ID) if err != nil { t.Fatalf("GetByID after Update failed: %v", err) } if found.ShortCode != "farewell" { t.Fatalf("expected ShortCode 'farewell', got '%s'", found.ShortCode) } if found.Content != "Farewell and thank you!" { t.Fatalf("expected Content 'Farewell and thank you!', got '%s'", found.Content) } } func TestCannedResponseService_Delete(t *testing.T) { provider := setupCannedTestDBProvider(t) accountID, _ := seedTestAccount(provider.DB(), t) svc := NewCannedResponseService(provider) cr := &CannedResponse{ AccountID: accountID, ShortCode: "hello", Content: "Hello!", } if err := svc.Create(context.Background(), cr); err != nil { t.Fatalf("Create failed: %v", err) } if err := svc.Delete(context.Background(), cr.ID); err != nil { t.Fatalf("Delete failed: %v", err) } // After soft delete, GetByID should return error. _, err := svc.GetByID(context.Background(), cr.ID) if err == nil { t.Fatal("expected error after Delete, got nil (soft-deleted record should not be found)") } } func TestCannedResponseService_ListByAccount(t *testing.T) { provider := setupCannedTestDBProvider(t) accountID, _ := seedTestAccount(provider.DB(), t) svc := NewCannedResponseService(provider) // Seed multiple canned responses. items := []CannedResponse{ {AccountID: accountID, ShortCode: "alpha", Content: "Alpha content"}, {AccountID: accountID, ShortCode: "beta", Content: "Beta content"}, {AccountID: accountID, ShortCode: "gamma", Content: "Gamma content"}, } for i := range items { if err := svc.Create(context.Background(), &items[i]); err != nil { t.Fatalf("Create #%d failed: %v", i, err) } } // Create a second account with its own canned response — should not appear. db := provider.DB() account2 := &model.Account{Name: "Other Account"} if err := db.Create(account2).Error; err != nil { t.Fatalf("failed to create second account: %v", err) } crOther := &CannedResponse{ AccountID: account2.ID, ShortCode: "other", Content: "Other account content", } if err := svc.Create(context.Background(), crOther); err != nil { t.Fatalf("Create other-account canned response failed: %v", err) } results, err := svc.ListByAccount(context.Background(), accountID) if err != nil { t.Fatalf("ListByAccount failed: %v", err) } if len(results) != 3 { t.Fatalf("expected 3 results, got %d", len(results)) } // Results should be ordered by short_code ASC. if results[0].ShortCode != "alpha" { t.Fatalf("expected first result ShortCode 'alpha', got '%s'", results[0].ShortCode) } if results[1].ShortCode != "beta" { t.Fatalf("expected second result ShortCode 'beta', got '%s'", results[1].ShortCode) } if results[2].ShortCode != "gamma" { t.Fatalf("expected third result ShortCode 'gamma', got '%s'", results[2].ShortCode) } } func TestCannedResponseService_Search(t *testing.T) { provider := setupCannedTestDBProvider(t) accountID, _ := seedTestAccount(provider.DB(), t) svc := NewCannedResponseService(provider) items := []CannedResponse{ {AccountID: accountID, ShortCode: "greet_hi", Content: "Hi there! Welcome."}, {AccountID: accountID, ShortCode: "greet_hello", Content: "Hello! How can we help?"}, {AccountID: accountID, ShortCode: "farewell", Content: "Goodbye and have a great day!"}, } for i := range items { if err := svc.Create(context.Background(), &items[i]); err != nil { t.Fatalf("Create #%d failed: %v", i, err) } } // Search for "greet" — should match short_code on first two items. results, err := svc.Search(context.Background(), accountID, "greet") if err != nil { t.Fatalf("Search failed: %v", err) } // short_code matches should rank before content-only matches. // Both "greet_hi" and "greet_hello" match on short_code. if len(results) < 2 { t.Fatalf("expected at least 2 results for 'greet', got %d", len(results)) } // Verify that short_code match results come first. for i := 0; i < 2; i++ { if results[i].ShortCode != "greet_hi" && results[i].ShortCode != "greet_hello" { t.Fatalf("expected short_code match in top results, got '%s'", results[i].ShortCode) } } // Search for "great" — matches content in "farewell". results2, err := svc.Search(context.Background(), accountID, "great") if err != nil { t.Fatalf("Search for 'great' failed: %v", err) } if len(results2) != 1 { t.Fatalf("expected 1 result for 'great', got %d", len(results2)) } if results2[0].ShortCode != "farewell" { t.Fatalf("expected ShortCode 'farewell', got '%s'", results2[0].ShortCode) } // Empty query should return all (same as ListByAccount). results3, err := svc.Search(context.Background(), accountID, "") if err != nil { t.Fatalf("Search with empty query failed: %v", err) } if len(results3) != 3 { t.Fatalf("expected 3 results for empty query, got %d", len(results3)) } } func TestCannedResponseService_GetByShortCode(t *testing.T) { provider := setupCannedTestDBProvider(t) accountID, _ := seedTestAccount(provider.DB(), t) svc := NewCannedResponseService(provider) cr := &CannedResponse{ AccountID: accountID, ShortCode: "welcome", Content: "Welcome to our service!", } if err := svc.Create(context.Background(), cr); err != nil { t.Fatalf("Create failed: %v", err) } found, err := svc.GetByShortCode(context.Background(), accountID, "welcome") if err != nil { t.Fatalf("GetByShortCode failed: %v", err) } if found.ID != cr.ID { t.Fatalf("expected ID %d, got %d", cr.ID, found.ID) } if found.ShortCode != "welcome" { t.Fatalf("expected ShortCode 'welcome', got '%s'", found.ShortCode) } // Non-existent short_code should return error. _, err = svc.GetByShortCode(context.Background(), accountID, "nonexistent") if err == nil { t.Fatal("expected error for non-existent short_code, got nil") } }