626 lines
16 KiB
Go
626 lines
16 KiB
Go
package babble
|
|
|
|
import (
|
|
"os"
|
|
"testing"
|
|
"time"
|
|
|
|
"dk/internal/database"
|
|
)
|
|
|
|
func setupTestDB(t *testing.T) *database.DB {
|
|
testDB := "test_babble.db"
|
|
t.Cleanup(func() {
|
|
os.Remove(testDB)
|
|
})
|
|
|
|
db, err := database.Open(testDB)
|
|
if err != nil {
|
|
t.Fatalf("Failed to open test database: %v", err)
|
|
}
|
|
|
|
// Create babble table
|
|
createTable := `CREATE TABLE babble (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
posted INTEGER NOT NULL DEFAULT (unixepoch()),
|
|
author TEXT NOT NULL DEFAULT '',
|
|
babble TEXT NOT NULL DEFAULT ''
|
|
)`
|
|
|
|
if err := db.Exec(createTable); err != nil {
|
|
t.Fatalf("Failed to create babble table: %v", err)
|
|
}
|
|
|
|
// Insert test data with specific timestamps for predictable testing
|
|
now := time.Now().Unix()
|
|
testBabble := `INSERT INTO babble (posted, author, babble) VALUES
|
|
(?, 'Alice', 'Hello everyone! Welcome to the game'),
|
|
(?, 'Bob', 'Thanks Alice! @Alice this game is great'),
|
|
(?, 'Charlie', 'Anyone want to team up for the dungeon?'),
|
|
(?, 'Alice', 'I can help @Charlie, let me know'),
|
|
(?, 'David', 'Server lag is really bad right now...'),
|
|
(?, 'Eve', 'Quick question about spell mechanics')`
|
|
|
|
timestamps := []any{
|
|
now - 3600*6, // 6 hours ago
|
|
now - 3600*4, // 4 hours ago
|
|
now - 3600*2, // 2 hours ago
|
|
now - 3600*1, // 1 hour ago
|
|
now - 1800, // 30 minutes ago
|
|
now - 300, // 5 minutes ago
|
|
}
|
|
|
|
if err := db.Exec(testBabble, timestamps...); err != nil {
|
|
t.Fatalf("Failed to insert test babble: %v", err)
|
|
}
|
|
|
|
return db
|
|
}
|
|
|
|
func TestFind(t *testing.T) {
|
|
db := setupTestDB(t)
|
|
defer db.Close()
|
|
|
|
// Test finding existing babble
|
|
babble, err := Find(db, 1)
|
|
if err != nil {
|
|
t.Fatalf("Failed to find babble: %v", err)
|
|
}
|
|
|
|
if babble.ID != 1 {
|
|
t.Errorf("Expected ID 1, got %d", babble.ID)
|
|
}
|
|
if babble.Author != "Alice" {
|
|
t.Errorf("Expected author 'Alice', got '%s'", babble.Author)
|
|
}
|
|
if babble.Babble != "Hello everyone! Welcome to the game" {
|
|
t.Errorf("Expected specific message, got '%s'", babble.Babble)
|
|
}
|
|
if babble.Posted == 0 {
|
|
t.Error("Expected non-zero posted timestamp")
|
|
}
|
|
|
|
// Test finding non-existent babble
|
|
_, err = Find(db, 999)
|
|
if err == nil {
|
|
t.Error("Expected error when finding non-existent babble")
|
|
}
|
|
}
|
|
|
|
func TestAll(t *testing.T) {
|
|
db := setupTestDB(t)
|
|
defer db.Close()
|
|
|
|
babbles, err := All(db)
|
|
if err != nil {
|
|
t.Fatalf("Failed to get all babble: %v", err)
|
|
}
|
|
|
|
if len(babbles) != 6 {
|
|
t.Errorf("Expected 6 babble messages, got %d", len(babbles))
|
|
}
|
|
|
|
// Check ordering (newest first)
|
|
if len(babbles) >= 2 {
|
|
if babbles[0].Posted < babbles[1].Posted {
|
|
t.Error("Expected babble to be ordered by posted time (newest first)")
|
|
}
|
|
}
|
|
|
|
// First message should be the most recent (5 minutes ago)
|
|
if babbles[0].Author != "Eve" {
|
|
t.Errorf("Expected newest message from Eve, got from '%s'", babbles[0].Author)
|
|
}
|
|
}
|
|
|
|
func TestByAuthor(t *testing.T) {
|
|
db := setupTestDB(t)
|
|
defer db.Close()
|
|
|
|
// Test messages by Alice
|
|
aliceMessages, err := ByAuthor(db, "Alice")
|
|
if err != nil {
|
|
t.Fatalf("Failed to get babble by author: %v", err)
|
|
}
|
|
|
|
if len(aliceMessages) != 2 {
|
|
t.Errorf("Expected 2 messages by Alice, got %d", len(aliceMessages))
|
|
}
|
|
|
|
// Verify all messages are by Alice
|
|
for _, message := range aliceMessages {
|
|
if message.Author != "Alice" {
|
|
t.Errorf("Expected author 'Alice', got '%s'", message.Author)
|
|
}
|
|
}
|
|
|
|
// Check ordering (newest first)
|
|
if len(aliceMessages) == 2 {
|
|
if aliceMessages[0].Babble != "I can help @Charlie, let me know" {
|
|
t.Errorf("Expected newest message by Alice first")
|
|
}
|
|
}
|
|
|
|
// Test case insensitive search
|
|
aliceMessagesLower, err := ByAuthor(db, "alice")
|
|
if err != nil {
|
|
t.Fatalf("Failed to get babble by lowercase author: %v", err)
|
|
}
|
|
|
|
if len(aliceMessagesLower) != 2 {
|
|
t.Errorf("Expected case insensitive search to find 2 messages, got %d", len(aliceMessagesLower))
|
|
}
|
|
|
|
// Test author with no messages
|
|
noMessages, err := ByAuthor(db, "NonexistentUser")
|
|
if err != nil {
|
|
t.Fatalf("Failed to query non-existent author: %v", err)
|
|
}
|
|
|
|
if len(noMessages) != 0 {
|
|
t.Errorf("Expected 0 messages by non-existent author, got %d", len(noMessages))
|
|
}
|
|
}
|
|
|
|
func TestRecent(t *testing.T) {
|
|
db := setupTestDB(t)
|
|
defer db.Close()
|
|
|
|
// Test getting 3 most recent messages
|
|
recentMessages, err := Recent(db, 3)
|
|
if err != nil {
|
|
t.Fatalf("Failed to get recent babble: %v", err)
|
|
}
|
|
|
|
if len(recentMessages) != 3 {
|
|
t.Errorf("Expected 3 recent messages, got %d", len(recentMessages))
|
|
}
|
|
|
|
// Check ordering (newest first)
|
|
if len(recentMessages) >= 2 {
|
|
if recentMessages[0].Posted < recentMessages[1].Posted {
|
|
t.Error("Expected recent messages to be ordered newest first")
|
|
}
|
|
}
|
|
|
|
// Test getting more messages than exist
|
|
allRecentMessages, err := Recent(db, 10)
|
|
if err != nil {
|
|
t.Fatalf("Failed to get recent babble with high limit: %v", err)
|
|
}
|
|
|
|
if len(allRecentMessages) != 6 {
|
|
t.Errorf("Expected 6 messages (all available), got %d", len(allRecentMessages))
|
|
}
|
|
}
|
|
|
|
func TestSince(t *testing.T) {
|
|
db := setupTestDB(t)
|
|
defer db.Close()
|
|
|
|
// Test messages since 3 hours ago
|
|
threeHoursAgo := time.Now().Add(-3 * time.Hour).Unix()
|
|
recentMessages, err := Since(db, threeHoursAgo)
|
|
if err != nil {
|
|
t.Fatalf("Failed to get babble since timestamp: %v", err)
|
|
}
|
|
|
|
// Should get messages from 2 hours ago, 1 hour ago, 30 minutes ago, and 5 minutes ago
|
|
expectedCount := 4
|
|
if len(recentMessages) != expectedCount {
|
|
t.Errorf("Expected %d messages since 3 hours ago, got %d", expectedCount, len(recentMessages))
|
|
}
|
|
|
|
// Verify all messages are since the timestamp
|
|
for _, message := range recentMessages {
|
|
if message.Posted < threeHoursAgo {
|
|
t.Errorf("Message with timestamp %d is before the 'since' timestamp %d", message.Posted, threeHoursAgo)
|
|
}
|
|
}
|
|
|
|
// Test with future timestamp (should return no messages)
|
|
futureMessages, err := Since(db, time.Now().Add(time.Hour).Unix())
|
|
if err != nil {
|
|
t.Fatalf("Failed to query future timestamp: %v", err)
|
|
}
|
|
|
|
if len(futureMessages) != 0 {
|
|
t.Errorf("Expected 0 messages since future timestamp, got %d", len(futureMessages))
|
|
}
|
|
}
|
|
|
|
func TestBetween(t *testing.T) {
|
|
db := setupTestDB(t)
|
|
defer db.Close()
|
|
|
|
// Test messages between 5 hours ago and 1 hour ago
|
|
start := time.Now().Add(-5 * time.Hour).Unix()
|
|
end := time.Now().Add(-1 * time.Hour).Unix()
|
|
|
|
betweenMessages, err := Between(db, start, end)
|
|
if err != nil {
|
|
t.Fatalf("Failed to get babble between timestamps: %v", err)
|
|
}
|
|
|
|
// Should get messages from 4 hours ago, 2 hours ago, and 1 hour ago (inclusive end)
|
|
expectedCount := 3
|
|
if len(betweenMessages) != expectedCount {
|
|
t.Errorf("Expected %d messages between timestamps, got %d", expectedCount, len(betweenMessages))
|
|
}
|
|
|
|
// Verify all messages are within the range
|
|
for _, message := range betweenMessages {
|
|
if message.Posted < start || message.Posted > end {
|
|
t.Errorf("Message with timestamp %d is outside range [%d, %d]", message.Posted, start, end)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestSearch(t *testing.T) {
|
|
db := setupTestDB(t)
|
|
defer db.Close()
|
|
|
|
// Test searching for "game"
|
|
gameMessages, err := Search(db, "game")
|
|
if err != nil {
|
|
t.Fatalf("Failed to search babble: %v", err)
|
|
}
|
|
|
|
expectedCount := 2 // Alice's welcome message and Bob's response
|
|
if len(gameMessages) != expectedCount {
|
|
t.Errorf("Expected %d messages containing 'game', got %d", expectedCount, len(gameMessages))
|
|
}
|
|
|
|
// Verify all messages contain the search term
|
|
for _, message := range gameMessages {
|
|
if !message.Contains("game") {
|
|
t.Errorf("Message '%s' does not contain search term 'game'", message.Babble)
|
|
}
|
|
}
|
|
|
|
// Test case insensitive search
|
|
gameMessagesUpper, err := Search(db, "GAME")
|
|
if err != nil {
|
|
t.Fatalf("Failed to search babble with uppercase: %v", err)
|
|
}
|
|
|
|
if len(gameMessagesUpper) != expectedCount {
|
|
t.Error("Expected case insensitive search to find same results")
|
|
}
|
|
|
|
// Test search with no results
|
|
noResults, err := Search(db, "nonexistentterm")
|
|
if err != nil {
|
|
t.Fatalf("Failed to search for non-existent term: %v", err)
|
|
}
|
|
|
|
if len(noResults) != 0 {
|
|
t.Errorf("Expected 0 results for non-existent term, got %d", len(noResults))
|
|
}
|
|
}
|
|
|
|
func TestRecentByAuthor(t *testing.T) {
|
|
db := setupTestDB(t)
|
|
defer db.Close()
|
|
|
|
// Test recent messages by Alice (limit 1)
|
|
aliceRecent, err := RecentByAuthor(db, "Alice", 1)
|
|
if err != nil {
|
|
t.Fatalf("Failed to get recent babble by author: %v", err)
|
|
}
|
|
|
|
if len(aliceRecent) != 1 {
|
|
t.Errorf("Expected 1 recent message by Alice, got %d", len(aliceRecent))
|
|
}
|
|
|
|
if len(aliceRecent) > 0 && aliceRecent[0].Babble != "I can help @Charlie, let me know" {
|
|
t.Error("Expected most recent message by Alice")
|
|
}
|
|
|
|
// Test with higher limit
|
|
aliceAll, err := RecentByAuthor(db, "Alice", 5)
|
|
if err != nil {
|
|
t.Fatalf("Failed to get all recent messages by Alice: %v", err)
|
|
}
|
|
|
|
if len(aliceAll) != 2 {
|
|
t.Errorf("Expected 2 total messages by Alice, got %d", len(aliceAll))
|
|
}
|
|
}
|
|
|
|
func TestBuilder(t *testing.T) {
|
|
db := setupTestDB(t)
|
|
defer db.Close()
|
|
|
|
// Create new babble using builder
|
|
testTime := time.Now()
|
|
babble, err := NewBuilder(db).
|
|
WithAuthor("TestUser").
|
|
WithBabble("Test message from builder").
|
|
WithPostedTime(testTime).
|
|
Create()
|
|
|
|
if err != nil {
|
|
t.Fatalf("Failed to create babble with builder: %v", err)
|
|
}
|
|
|
|
if babble.ID == 0 {
|
|
t.Error("Expected non-zero ID after creation")
|
|
}
|
|
if babble.Author != "TestUser" {
|
|
t.Errorf("Expected author 'TestUser', got '%s'", babble.Author)
|
|
}
|
|
if babble.Babble != "Test message from builder" {
|
|
t.Errorf("Expected specific message, got '%s'", babble.Babble)
|
|
}
|
|
if babble.Posted != testTime.Unix() {
|
|
t.Errorf("Expected posted time %d, got %d", testTime.Unix(), babble.Posted)
|
|
}
|
|
|
|
// Test WithMessage alias
|
|
babble2, err := NewBuilder(db).
|
|
WithAuthor("TestUser2").
|
|
WithMessage("Using WithMessage alias").
|
|
Create()
|
|
|
|
if err != nil {
|
|
t.Fatalf("Failed to create babble with WithMessage: %v", err)
|
|
}
|
|
|
|
if babble2.Babble != "Using WithMessage alias" {
|
|
t.Errorf("WithMessage alias failed, got '%s'", babble2.Babble)
|
|
}
|
|
|
|
// Verify it was saved to database
|
|
foundBabble, err := Find(db, babble.ID)
|
|
if err != nil {
|
|
t.Fatalf("Failed to find created babble: %v", err)
|
|
}
|
|
|
|
if foundBabble.Babble != "Test message from builder" {
|
|
t.Errorf("Created babble not found in database")
|
|
}
|
|
|
|
// Test builder with default timestamp
|
|
defaultBabble, err := NewBuilder(db).
|
|
WithAuthor("DefaultUser").
|
|
WithBabble("Message with default timestamp").
|
|
Create()
|
|
|
|
if err != nil {
|
|
t.Fatalf("Failed to create babble with default timestamp: %v", err)
|
|
}
|
|
|
|
// Should have recent timestamp (within last minute)
|
|
if time.Since(defaultBabble.PostedTime()) > time.Minute {
|
|
t.Error("Expected default timestamp to be recent")
|
|
}
|
|
}
|
|
|
|
func TestSave(t *testing.T) {
|
|
db := setupTestDB(t)
|
|
defer db.Close()
|
|
|
|
babble, err := Find(db, 1)
|
|
if err != nil {
|
|
t.Fatalf("Failed to find babble: %v", err)
|
|
}
|
|
|
|
// Modify babble
|
|
babble.Author = "UpdatedAuthor"
|
|
babble.Babble = "Updated message content"
|
|
babble.Posted = time.Now().Unix()
|
|
|
|
// Save changes
|
|
err = babble.Save()
|
|
if err != nil {
|
|
t.Fatalf("Failed to save babble: %v", err)
|
|
}
|
|
|
|
// Verify changes were saved
|
|
updatedBabble, err := Find(db, 1)
|
|
if err != nil {
|
|
t.Fatalf("Failed to find updated babble: %v", err)
|
|
}
|
|
|
|
if updatedBabble.Author != "UpdatedAuthor" {
|
|
t.Errorf("Expected updated author 'UpdatedAuthor', got '%s'", updatedBabble.Author)
|
|
}
|
|
if updatedBabble.Babble != "Updated message content" {
|
|
t.Errorf("Expected updated message, got '%s'", updatedBabble.Babble)
|
|
}
|
|
}
|
|
|
|
func TestDelete(t *testing.T) {
|
|
db := setupTestDB(t)
|
|
defer db.Close()
|
|
|
|
babble, err := Find(db, 1)
|
|
if err != nil {
|
|
t.Fatalf("Failed to find babble: %v", err)
|
|
}
|
|
|
|
// Delete babble
|
|
err = babble.Delete()
|
|
if err != nil {
|
|
t.Fatalf("Failed to delete babble: %v", err)
|
|
}
|
|
|
|
// Verify babble was deleted
|
|
_, err = Find(db, 1)
|
|
if err == nil {
|
|
t.Error("Expected error when finding deleted babble")
|
|
}
|
|
}
|
|
|
|
func TestUtilityMethods(t *testing.T) {
|
|
db := setupTestDB(t)
|
|
defer db.Close()
|
|
|
|
babble, _ := Find(db, 1)
|
|
|
|
// Test PostedTime
|
|
postedTime := babble.PostedTime()
|
|
if postedTime.IsZero() {
|
|
t.Error("Expected non-zero posted time")
|
|
}
|
|
|
|
// Test SetPostedTime
|
|
newTime := time.Now().Add(-30 * time.Minute)
|
|
babble.SetPostedTime(newTime)
|
|
if babble.Posted != newTime.Unix() {
|
|
t.Errorf("Expected posted timestamp %d, got %d", newTime.Unix(), babble.Posted)
|
|
}
|
|
|
|
// Test IsRecent (should be true for 30 minutes ago)
|
|
if !babble.IsRecent() {
|
|
t.Error("Expected message from 30 minutes ago to be recent")
|
|
}
|
|
|
|
// Test Age
|
|
age := babble.Age()
|
|
if age < 0 {
|
|
t.Error("Expected positive age")
|
|
}
|
|
|
|
// Test IsAuthor
|
|
if !babble.IsAuthor("Alice") {
|
|
t.Error("Expected IsAuthor to return true for correct author")
|
|
}
|
|
if !babble.IsAuthor("alice") { // Test case insensitive
|
|
t.Error("Expected IsAuthor to be case insensitive")
|
|
}
|
|
if babble.IsAuthor("Bob") {
|
|
t.Error("Expected IsAuthor to return false for incorrect author")
|
|
}
|
|
|
|
// Test Preview
|
|
longMessage := "This is a very long chat message that should be truncated when preview is called for display purposes"
|
|
babble.Babble = longMessage
|
|
|
|
preview := babble.Preview(20)
|
|
if len(preview) > 20 {
|
|
t.Errorf("Expected preview length <= 20, got %d", len(preview))
|
|
}
|
|
if preview[len(preview)-3:] != "..." {
|
|
t.Error("Expected preview to end with ellipsis")
|
|
}
|
|
|
|
shortPreview := babble.Preview(200) // Longer than message
|
|
if shortPreview != longMessage {
|
|
t.Error("Expected short message to not be truncated")
|
|
}
|
|
|
|
// Test WordCount
|
|
babble.Babble = "This is a test with five words"
|
|
wordCount := babble.WordCount()
|
|
if wordCount != 7 {
|
|
t.Errorf("Expected 7 words, got %d", wordCount)
|
|
}
|
|
|
|
// Test Length
|
|
expectedLength := len(babble.Babble)
|
|
if babble.Length() != expectedLength {
|
|
t.Errorf("Expected length %d, got %d", expectedLength, babble.Length())
|
|
}
|
|
|
|
// Test Contains
|
|
if !babble.Contains("test") {
|
|
t.Error("Expected message to contain 'test'")
|
|
}
|
|
if !babble.Contains("TEST") { // Case insensitive
|
|
t.Error("Expected Contains to be case insensitive")
|
|
}
|
|
if babble.Contains("nonexistent") {
|
|
t.Error("Expected message not to contain 'nonexistent'")
|
|
}
|
|
|
|
// Test IsEmpty
|
|
babble.Babble = ""
|
|
if !babble.IsEmpty() {
|
|
t.Error("Expected empty message to be empty")
|
|
}
|
|
|
|
babble.Babble = " "
|
|
if !babble.IsEmpty() {
|
|
t.Error("Expected whitespace-only message to be empty")
|
|
}
|
|
|
|
babble.Babble = "Not empty"
|
|
if babble.IsEmpty() {
|
|
t.Error("Expected non-empty message not to be empty")
|
|
}
|
|
|
|
// Test IsLongMessage
|
|
shortMsg := "Short"
|
|
babble.Babble = shortMsg
|
|
if babble.IsLongMessage(100) {
|
|
t.Error("Expected short message not to be long")
|
|
}
|
|
if !babble.IsLongMessage(3) {
|
|
t.Error("Expected message longer than threshold to be long")
|
|
}
|
|
}
|
|
|
|
func TestMentionMethods(t *testing.T) {
|
|
db := setupTestDB(t)
|
|
defer db.Close()
|
|
|
|
// Test GetMentions
|
|
babble, _ := Find(db, 2) // Bob's message: "Thanks Alice! @Alice this game is great"
|
|
mentions := babble.GetMentions()
|
|
|
|
expectedMentions := []string{"Alice"}
|
|
if len(mentions) != len(expectedMentions) {
|
|
t.Errorf("Expected %d mentions, got %d", len(expectedMentions), len(mentions))
|
|
}
|
|
|
|
for i, expected := range expectedMentions {
|
|
if i < len(mentions) && mentions[i] != expected {
|
|
t.Errorf("Expected mention '%s' at position %d, got '%s'", expected, i, mentions[i])
|
|
}
|
|
}
|
|
|
|
// Test HasMention
|
|
if !babble.HasMention("Alice") {
|
|
t.Error("Expected message to mention Alice")
|
|
}
|
|
if !babble.HasMention("alice") { // Case insensitive
|
|
t.Error("Expected HasMention to be case insensitive")
|
|
}
|
|
if babble.HasMention("Bob") {
|
|
t.Error("Expected message not to mention Bob")
|
|
}
|
|
|
|
// Test message with multiple mentions and punctuation
|
|
babble.Babble = "Hey @Alice, @Bob! Can you help @Charlie?"
|
|
mentions = babble.GetMentions()
|
|
expectedMentions = []string{"Alice", "Bob", "Charlie"}
|
|
|
|
if len(mentions) != len(expectedMentions) {
|
|
t.Errorf("Expected %d mentions, got %d: %v", len(expectedMentions), len(mentions), mentions)
|
|
}
|
|
|
|
for _, expected := range expectedMentions {
|
|
if !babble.HasMention(expected) {
|
|
t.Errorf("Expected message to mention %s", expected)
|
|
}
|
|
}
|
|
|
|
// Test message with no mentions
|
|
babble.Babble = "No mentions in this message"
|
|
mentions = babble.GetMentions()
|
|
|
|
if len(mentions) != 0 {
|
|
t.Errorf("Expected 0 mentions, got %d", len(mentions))
|
|
}
|
|
|
|
// Test malformed mentions (should be ignored)
|
|
babble.Babble = "Just @ alone or @"
|
|
mentions = babble.GetMentions()
|
|
|
|
if len(mentions) != 0 {
|
|
t.Errorf("Expected 0 mentions for malformed @, got %d", len(mentions))
|
|
}
|
|
}
|