package services import ( "context" "testing" "github.com/google/uuid" "go.uber.org/zap" "gorm.io/driver/sqlite" "gorm.io/gorm" "veza-backend-api/internal/models" ) func TestNewEnhancedNotificationService(t *testing.T) { db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{}) if err != nil { t.Fatalf("Failed to open database: %v", err) } // Auto-migrate if err := db.AutoMigrate(&models.Notification{}); err != nil { t.Fatalf("Failed to migrate: %v", err) } logger := zap.NewNop() service := NewEnhancedNotificationService(db, logger) if service == nil { t.Error("NewEnhancedNotificationService() returned nil") } if service.db == nil { t.Error("NewEnhancedNotificationService() returned service with nil db") } if service.logger == nil { t.Error("NewEnhancedNotificationService() returned service with nil logger") } } func TestEnhancedNotificationService_CreateNotification(t *testing.T) { db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{}) if err != nil { t.Fatalf("Failed to open database: %v", err) } if err := db.AutoMigrate(&models.Notification{}); err != nil { t.Fatalf("Failed to migrate: %v", err) } service := NewEnhancedNotificationService(db, zap.NewNop()) ctx := context.Background() userID := uuid.New() notification, err := service.CreateNotification( ctx, userID, "test_type", "Test Title", "Test Content", "https://example.com", ) if err != nil { t.Fatalf("CreateNotification() error = %v", err) } if notification == nil { t.Error("CreateNotification() returned nil notification") } if notification.ID == uuid.Nil { t.Error("CreateNotification() returned notification with nil ID") } if notification.UserID != userID { t.Errorf("CreateNotification() user_id = %v, want %v", notification.UserID, userID) } if notification.Type != "test_type" { t.Errorf("CreateNotification() type = %v, want test_type", notification.Type) } if notification.Read != false { t.Error("CreateNotification() read should be false") } } func TestEnhancedNotificationService_GetNotifications(t *testing.T) { db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{}) if err != nil { t.Fatalf("Failed to open database: %v", err) } if err := db.AutoMigrate(&models.Notification{}); err != nil { t.Fatalf("Failed to migrate: %v", err) } service := NewEnhancedNotificationService(db, zap.NewNop()) ctx := context.Background() userID := uuid.New() // Create test notifications for i := 0; i < 5; i++ { _, err := service.CreateNotification( ctx, userID, "test_type", "Test Title", "Test Content", "", ) if err != nil { t.Fatalf("Failed to create test notification: %v", err) } } params := NotificationParams{ UserID: userID, UnreadOnly: false, Page: 1, Limit: 10, } result, err := service.GetNotifications(ctx, params) if err != nil { t.Fatalf("GetNotifications() error = %v", err) } if result == nil { t.Error("GetNotifications() returned nil result") } if result.Total != 5 { t.Errorf("GetNotifications() total = %d, want 5", result.Total) } if len(result.Notifications) != 5 { t.Errorf("GetNotifications() returned %d notifications, want 5", len(result.Notifications)) } if result.UnreadCount != 5 { t.Errorf("GetNotifications() unread_count = %d, want 5", result.UnreadCount) } } func TestEnhancedNotificationService_MarkAsRead(t *testing.T) { db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{}) if err != nil { t.Fatalf("Failed to open database: %v", err) } if err := db.AutoMigrate(&models.Notification{}); err != nil { t.Fatalf("Failed to migrate: %v", err) } service := NewEnhancedNotificationService(db, zap.NewNop()) ctx := context.Background() userID := uuid.New() // Create a notification notification, err := service.CreateNotification( ctx, userID, "test_type", "Test Title", "Test Content", "", ) if err != nil { t.Fatalf("Failed to create notification: %v", err) } // Mark as read err = service.MarkAsRead(ctx, userID, notification.ID) if err != nil { t.Fatalf("MarkAsRead() error = %v", err) } // Verify it's marked as read readNotification, err := service.GetNotificationByID(ctx, userID, notification.ID) if err != nil { t.Fatalf("GetNotificationByID() error = %v", err) } if !readNotification.Read { t.Error("MarkAsRead() notification is not marked as read") } if readNotification.ReadAt == nil { t.Error("MarkAsRead() read_at is nil") } } func TestEnhancedNotificationService_DeleteNotification(t *testing.T) { db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{}) if err != nil { t.Fatalf("Failed to open database: %v", err) } if err := db.AutoMigrate(&models.Notification{}); err != nil { t.Fatalf("Failed to migrate: %v", err) } service := NewEnhancedNotificationService(db, zap.NewNop()) ctx := context.Background() userID := uuid.New() // Create a notification notification, err := service.CreateNotification( ctx, userID, "test_type", "Test Title", "Test Content", "", ) if err != nil { t.Fatalf("Failed to create notification: %v", err) } // Delete the notification err = service.DeleteNotification(ctx, userID, notification.ID) if err != nil { t.Fatalf("DeleteNotification() error = %v", err) } // Verify it's deleted _, err = service.GetNotificationByID(ctx, userID, notification.ID) if err == nil { t.Error("DeleteNotification() notification still exists") } } func TestEnhancedNotificationService_GetUnreadCount(t *testing.T) { db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{}) if err != nil { t.Fatalf("Failed to open database: %v", err) } if err := db.AutoMigrate(&models.Notification{}); err != nil { t.Fatalf("Failed to migrate: %v", err) } service := NewEnhancedNotificationService(db, zap.NewNop()) ctx := context.Background() userID := uuid.New() // Create unread notifications for i := 0; i < 3; i++ { _, err := service.CreateNotification( ctx, userID, "test_type", "Test Title", "Test Content", "", ) if err != nil { t.Fatalf("Failed to create notification: %v", err) } } count, err := service.GetUnreadCount(ctx, userID) if err != nil { t.Fatalf("GetUnreadCount() error = %v", err) } if count != 3 { t.Errorf("GetUnreadCount() = %d, want 3", count) } } func TestNotificationParams_Defaults(t *testing.T) { params := NotificationParams{} // Test that defaults are applied in GetNotifications method if params.Page < 1 { params.Page = 1 } if params.Limit < 1 { params.Limit = 20 } if params.Limit > 100 { params.Limit = 100 } if params.Page != 1 { t.Errorf("Expected default page 1, got %d", params.Page) } if params.Limit != 20 { t.Errorf("Expected default limit 20, got %d", params.Limit) } } // Note: Full integration tests would require: // 1. A real database with notifications table // 2. Test data (notifications with various types, read/unread status) // 3. Verification of pagination, filtering, and deletion // // Example integration test structure: // func TestEnhancedNotificationService_Integration(t *testing.T) { // // Setup test database // db := setupTestDB(t) // defer cleanupTestDB(t, db) // // // Create test data // userID := uuid.New() // createTestNotifications(t, db, userID, 25) // 25 notifications // // service := NewEnhancedNotificationService(db, zap.NewNop()) // // ctx := context.Background() // params := NotificationParams{ // UserID: userID, // Page: 1, // Limit: 10, // } // // result, err := service.GetNotifications(ctx, params) // if err != nil { // t.Fatalf("GetNotifications() error = %v", err) // } // // if result.Total != 25 { // t.Errorf("GetNotifications() total = %d, want 25", result.Total) // } // // if len(result.Notifications) != 10 { // t.Errorf("GetNotifications() returned %d notifications, want 10", len(result.Notifications)) // } // }