package service import ( "context" "testing" "time" "github.com/user-management-system/internal/domain" ) // ============================================================================= // Stats Service Internal Tests // ============================================================================= // mockStatsUserRepoInternal mocks user repository for stats tests type mockStatsUserRepoInternal struct { totalUsers int64 activeUsers int64 inactiveUsers int64 lockedUsers int64 disabledUsers int64 newUsersToday int64 } func (m *mockStatsUserRepoInternal) List(ctx context.Context, offset, limit int) ([]*domain.User, int64, error) { return nil, m.totalUsers, nil } func (m *mockStatsUserRepoInternal) ListByStatus(ctx context.Context, status domain.UserStatus, offset, limit int) ([]*domain.User, int64, error) { switch status { case domain.UserStatusActive: return nil, m.activeUsers, nil case domain.UserStatusInactive: return nil, m.inactiveUsers, nil case domain.UserStatusLocked: return nil, m.lockedUsers, nil case domain.UserStatusDisabled: return nil, m.disabledUsers, nil } return nil, 0, nil } func (m *mockStatsUserRepoInternal) ListCreatedAfter(ctx context.Context, since time.Time, offset, limit int) ([]*domain.User, int64, error) { return nil, m.newUsersToday, nil } // mockStatsLoginLogRepoInternal mocks login log repository for stats tests type mockStatsLoginLogRepoInternal struct { successCount int64 failedCount int64 weekCount int64 } func (m *mockStatsLoginLogRepoInternal) CountByResultSince(ctx context.Context, success bool, since time.Time) (int64, error) { if success { return m.successCount, nil } return m.failedCount, nil } func TestStatsService_GetDashboardStats_Internal(t *testing.T) { userRepo := &mockStatsUserRepoInternal{ totalUsers: 100, activeUsers: 80, inactiveUsers: 10, lockedUsers: 5, disabledUsers: 5, newUsersToday: 3, } loginLogRepo := &mockStatsLoginLogRepoInternal{ successCount: 50, failedCount: 5, weekCount: 200, } svc := NewStatsService(userRepo, loginLogRepo) ctx := context.Background() stats, err := svc.GetDashboardStats(ctx) if err != nil { t.Fatalf("GetDashboardStats failed: %v", err) } if stats.Users.TotalUsers != 100 { t.Errorf("Expected TotalUsers=100, got %d", stats.Users.TotalUsers) } if stats.Logins.LoginsTodaySuccess != 50 { t.Errorf("Expected LoginsTodaySuccess=50, got %d", stats.Logins.LoginsTodaySuccess) } if stats.Logins.LoginsTodayFailed != 5 { t.Errorf("Expected LoginsTodayFailed=5, got %d", stats.Logins.LoginsTodayFailed) } } func TestStatsService_GetDashboardStats_NilLoginLogRepo(t *testing.T) { userRepo := &mockStatsUserRepoInternal{ totalUsers: 50, activeUsers: 40, inactiveUsers: 5, lockedUsers: 3, disabledUsers: 2, newUsersToday: 2, } svc := NewStatsService(userRepo, nil) ctx := context.Background() stats, err := svc.GetDashboardStats(ctx) if err != nil { t.Fatalf("GetDashboardStats failed: %v", err) } if stats.Users.TotalUsers != 50 { t.Errorf("Expected TotalUsers=50, got %d", stats.Users.TotalUsers) } // Login stats should be 0 when loginLogRepo is nil if stats.Logins.LoginsTodaySuccess != 0 { t.Errorf("Expected LoginsTodaySuccess=0, got %d", stats.Logins.LoginsTodaySuccess) } } func TestDaysAgo(t *testing.T) { result := daysAgo(0) if result.After(time.Now()) { t.Error("daysAgo(0) should not be in the future") } result = daysAgo(7) if result.After(time.Now()) { t.Error("daysAgo(7) should not be in the future") } }