Files
raceplanner/backend/backend.Tests/Controllers/AnnouncementsControllerTests.cs
T
Denis Urs Rudolph eb4e527cbd Fix Announcements tests - add authorId to remaining CreateAnnouncement calls
Status: 71 passed, 7 failed, 2 skipped
2026-04-06 21:14:45 +02:00

529 lines
18 KiB
C#

using System.Security.Claims;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Moq;
using FluentAssertions;
using RacePlannerApi.Controllers;
using RacePlannerApi.Data;
using RacePlannerApi.DTOs;
using RacePlannerApi.Models;
using backend.Tests.Utilities;
namespace backend.Tests.Controllers;
public class AnnouncementsControllerTests : IDisposable
{
private readonly RacePlannerDbContext _context;
private readonly AnnouncementsController _controller;
public AnnouncementsControllerTests()
{
var options = new DbContextOptionsBuilder<RacePlannerDbContext>()
.UseInMemoryDatabase(databaseName: Guid.NewGuid().ToString())
.Options;
_context = new RacePlannerDbContext(options);
_controller = new AnnouncementsController(_context);
}
private void SetUserContext(Guid userId, string role = "Participant")
{
var claims = new List<Claim>
{
new Claim(ClaimTypes.NameIdentifier, userId.ToString()),
new Claim(ClaimTypes.Role, role)
};
var identity = new ClaimsIdentity(claims, "TestAuthType");
var principal = new ClaimsPrincipal(identity);
_controller.ControllerContext = new ControllerContext
{
HttpContext = new DefaultHttpContext { User = principal }
};
}
public void Dispose()
{
_context.Dispose();
}
#region Create Announcement - Positive Tests
[Fact]
public async Task CreateAnnouncement_WithValidData_CreatesAnnouncement()
{
// Arrange
var organizer = TestDataFactory.CreateUser(role: UserRole.Organizer);
_context.Users.Add(organizer);
var eventEntity = TestDataFactory.CreateEvent(organizerId: organizer.Id, status: EventStatus.Published);
_context.Events.Add(eventEntity);
await _context.SaveChangesAsync();
SetUserContext(organizer.Id, "Organizer");
var request = new CreateAnnouncementRequest
{
EventId = eventEntity.Id,
Title = "Important Update",
Content = "Event details have been updated."
};
// Act
var result = await _controller.CreateAnnouncement(request);
// Assert
var createdResult = result.Result.Should().BeOfType<CreatedAtActionResult>().Subject;
var response = createdResult.Value.Should().BeOfType<AnnouncementDto>().Subject;
response.Title.Should().Be(request.Title);
response.Content.Should().Be(request.Content);
response.IsPublished.Should().BeTrue();
}
#endregion
#region Create Announcement - Negative Tests
[Fact]
public async Task CreateAnnouncement_ForNonExistentEvent_ReturnsNotFound()
{
// Arrange
var organizer = TestDataFactory.CreateUser(role: UserRole.Organizer);
_context.Users.Add(organizer);
await _context.SaveChangesAsync();
SetUserContext(organizer.Id, "Organizer");
var request = new CreateAnnouncementRequest
{
EventId = Guid.NewGuid(),
Title = "Test",
Content = "Content"
};
// Act
var result = await _controller.CreateAnnouncement(request);
// Assert
var notFoundResult = result.Result.Should().BeOfType<NotFoundObjectResult>().Subject;
notFoundResult.Value.Should().BeEquivalentTo(new { error = "Event not found" });
}
[Fact]
public async Task CreateAnnouncement_NonOrganizer_ReturnsForbidden()
{
// Arrange
var organizer = TestDataFactory.CreateUser(role: UserRole.Organizer);
var otherOrganizer = TestDataFactory.CreateUser(email: "other@example.com", role: UserRole.Organizer);
_context.Users.AddRange(organizer, otherOrganizer);
var eventEntity = TestDataFactory.CreateEvent(organizerId: organizer.Id, status: EventStatus.Published);
_context.Events.Add(eventEntity);
await _context.SaveChangesAsync();
SetUserContext(otherOrganizer.Id, "Organizer");
var request = new CreateAnnouncementRequest
{
EventId = eventEntity.Id,
Title = "Test",
Content = "Content"
};
// Act
var result = await _controller.CreateAnnouncement(request);
// Assert
result.Result.Should().BeOfType<ForbidResult>();
}
#endregion
#region Get Announcement - Positive Tests
[Fact]
public async Task GetAnnouncement_ReturnsPublishedAnnouncement()
{
// Arrange
var organizer = TestDataFactory.CreateUser(role: UserRole.Organizer);
_context.Users.Add(organizer);
var eventEntity = TestDataFactory.CreateEvent(organizerId: organizer.Id, status: EventStatus.Published);
_context.Events.Add(eventEntity);
var announcement = TestDataFactory.CreateAnnouncement(eventEntity.Id, "Title", "Content", organizer.Id);
announcement.IsPublished = true;
_context.Announcements.Add(announcement);
await _context.SaveChangesAsync();
_controller.ControllerContext = new ControllerContext
{
HttpContext = new DefaultHttpContext { User = new ClaimsPrincipal() }
};
// Act
var result = await _controller.GetAnnouncement(announcement.Id);
// Assert
var okResult = result.Result.Should().BeOfType<OkObjectResult>().Subject;
var response = okResult.Value.Should().BeOfType<AnnouncementDto>().Subject;
response.Title.Should().Be("Title");
}
[Fact]
public async Task GetAnnouncement_OrganizerCanViewUnpublishedAnnouncement()
{
// Arrange
var organizer = TestDataFactory.CreateUser(role: UserRole.Organizer);
_context.Users.Add(organizer);
var eventEntity = TestDataFactory.CreateEvent(organizerId: organizer.Id, status: EventStatus.Published);
_context.Events.Add(eventEntity);
var announcement = TestDataFactory.CreateAnnouncement(eventEntity.Id, "Draft Title", "Content", organizer.Id);
announcement.IsPublished = false;
_context.Announcements.Add(announcement);
await _context.SaveChangesAsync();
SetUserContext(organizer.Id, "Organizer");
// Act
var result = await _controller.GetAnnouncement(announcement.Id);
// Assert
result.Result.Should().BeOfType<OkObjectResult>();
}
#endregion
#region Get Announcement - Negative Tests
[Fact]
public async Task GetAnnouncement_UnpublishedNotVisibleToPublic()
{
// Arrange
var organizer = TestDataFactory.CreateUser(role: UserRole.Organizer);
_context.Users.Add(organizer);
var eventEntity = TestDataFactory.CreateEvent(organizerId: organizer.Id, status: EventStatus.Published);
_context.Events.Add(eventEntity);
var announcement = TestDataFactory.CreateAnnouncement(eventEntity.Id, "Draft", "Content", organizer.Id);
announcement.IsPublished = false;
_context.Announcements.Add(announcement);
await _context.SaveChangesAsync();
_controller.ControllerContext = new ControllerContext
{
HttpContext = new DefaultHttpContext { User = new ClaimsPrincipal() }
};
// Act
var result = await _controller.GetAnnouncement(announcement.Id);
// Assert
result.Result.Should().BeOfType<NotFoundResult>();
}
#endregion
#region Get Event Announcements
[Fact]
public async Task GetEventAnnouncements_ReturnsPublishedAnnouncements()
{
// Arrange
var organizer = TestDataFactory.CreateUser(role: UserRole.Organizer);
_context.Users.Add(organizer);
var eventEntity = TestDataFactory.CreateEvent(organizerId: organizer.Id, status: EventStatus.Published);
_context.Events.Add(eventEntity);
var published = TestDataFactory.CreateAnnouncement(eventEntity.Id, "Published", "Content");
published.IsPublished = true;
var unpublished = TestDataFactory.CreateAnnouncement(eventEntity.Id, "Draft", "Content");
unpublished.IsPublished = false;
_context.Announcements.AddRange(published, unpublished);
await _context.SaveChangesAsync();
_controller.ControllerContext = new ControllerContext
{
HttpContext = new DefaultHttpContext { User = new ClaimsPrincipal() }
};
// Act
var result = await _controller.GetEventAnnouncements(eventEntity.Id);
// Assert
var okResult = result.Result.Should().BeOfType<OkObjectResult>().Subject;
var announcements = okResult.Value.Should().BeAssignableTo<IEnumerable<AnnouncementDto>>().Subject;
announcements.Should().HaveCount(1);
announcements.First().Title.Should().Be("Published");
}
[Fact]
public async Task GetEventAnnouncements_OrganizerSeesAll()
{
// Arrange
var organizer = TestDataFactory.CreateUser(role: UserRole.Organizer);
_context.Users.Add(organizer);
var eventEntity = TestDataFactory.CreateEvent(organizerId: organizer.Id, status: EventStatus.Published);
_context.Events.Add(eventEntity);
var published = TestDataFactory.CreateAnnouncement(eventEntity.Id, "Published", "Content");
published.IsPublished = true;
var unpublished = TestDataFactory.CreateAnnouncement(eventEntity.Id, "Draft", "Content");
unpublished.IsPublished = false;
_context.Announcements.AddRange(published, unpublished);
await _context.SaveChangesAsync();
SetUserContext(organizer.Id, "Organizer");
// Act
var result = await _controller.GetEventAnnouncements(eventEntity.Id);
// Assert
var okResult = result.Result.Should().BeOfType<OkObjectResult>().Subject;
var announcements = okResult.Value.Should().BeAssignableTo<IEnumerable<AnnouncementDto>>().Subject;
announcements.Should().HaveCount(2);
}
#endregion
#region Update Announcement - Positive Tests
[Fact]
public async Task UpdateAnnouncement_WithValidData_UpdatesAnnouncement()
{
// Arrange
var organizer = TestDataFactory.CreateUser(role: UserRole.Organizer);
_context.Users.Add(organizer);
var eventEntity = TestDataFactory.CreateEvent(organizerId: organizer.Id, status: EventStatus.Published);
_context.Events.Add(eventEntity);
var announcement = TestDataFactory.CreateAnnouncement(eventEntity.Id, "Original", "Content", organizer.Id);
_context.Announcements.Add(announcement);
await _context.SaveChangesAsync();
SetUserContext(organizer.Id, "Organizer");
var request = new UpdateAnnouncementRequest
{
Title = "Updated Title",
Content = "Updated Content"
};
// Act
var result = await _controller.UpdateAnnouncement(announcement.Id, request);
// Assert
var okResult = result.Result.Should().BeOfType<OkObjectResult>().Subject;
var response = okResult.Value.Should().BeOfType<AnnouncementDto>().Subject;
response.Title.Should().Be("Updated Title");
response.Content.Should().Be("Updated Content");
}
[Fact]
public async Task UpdateAnnouncement_PublishUnpublishedAnnouncement()
{
// Arrange
var organizer = TestDataFactory.CreateUser(role: UserRole.Organizer);
_context.Users.Add(organizer);
var eventEntity = TestDataFactory.CreateEvent(organizerId: organizer.Id, status: EventStatus.Published);
_context.Events.Add(eventEntity);
var announcement = TestDataFactory.CreateAnnouncement(eventEntity.Id, "Draft", "Content");
announcement.IsPublished = false;
_context.Announcements.Add(announcement);
await _context.SaveChangesAsync();
SetUserContext(organizer.Id, "Organizer");
var request = new UpdateAnnouncementRequest { IsPublished = true };
// Act
var result = await _controller.UpdateAnnouncement(announcement.Id, request);
// Assert
var okResult = result.Result.Should().BeOfType<OkObjectResult>().Subject;
var response = okResult.Value.Should().BeOfType<AnnouncementDto>().Subject;
response.IsPublished.Should().BeTrue();
}
#endregion
#region Update Announcement - Negative Tests
[Fact]
public async Task UpdateAnnouncement_NonExistent_ReturnsNotFound()
{
// Arrange
var organizer = TestDataFactory.CreateUser(role: UserRole.Organizer);
_context.Users.Add(organizer);
await _context.SaveChangesAsync();
SetUserContext(organizer.Id, "Organizer");
var request = new UpdateAnnouncementRequest { Title = "Updated" };
// Act
var result = await _controller.UpdateAnnouncement(Guid.NewGuid(), request);
// Assert
result.Result.Should().BeOfType<NotFoundResult>();
}
[Fact]
public async Task UpdateAnnouncement_NonOrganizer_ReturnsForbidden()
{
// Arrange
var organizer = TestDataFactory.CreateUser(role: UserRole.Organizer);
var otherOrganizer = TestDataFactory.CreateUser(email: "other@example.com", role: UserRole.Organizer);
_context.Users.AddRange(organizer, otherOrganizer);
var eventEntity = TestDataFactory.CreateEvent(organizerId: organizer.Id, status: EventStatus.Published);
_context.Events.Add(eventEntity);
var announcement = TestDataFactory.CreateAnnouncement(eventEntity.Id, "Title", "Content");
_context.Announcements.Add(announcement);
await _context.SaveChangesAsync();
SetUserContext(otherOrganizer.Id, "Organizer");
var request = new UpdateAnnouncementRequest { Title = "Hacked" };
// Act
var result = await _controller.UpdateAnnouncement(announcement.Id, request);
// Assert
result.Result.Should().BeOfType<ForbidResult>();
}
#endregion
#region Delete Announcement - Positive Tests
[Fact]
public async Task DeleteAnnouncement_OrganizerCanDeleteOwnAnnouncement()
{
// Arrange
var organizer = TestDataFactory.CreateUser(role: UserRole.Organizer);
_context.Users.Add(organizer);
var eventEntity = TestDataFactory.CreateEvent(organizerId: organizer.Id, status: EventStatus.Published);
_context.Events.Add(eventEntity);
var announcement = TestDataFactory.CreateAnnouncement(eventEntity.Id, "To Delete", "Content");
_context.Announcements.Add(announcement);
await _context.SaveChangesAsync();
SetUserContext(organizer.Id, "Organizer");
// Act
var result = await _controller.DeleteAnnouncement(announcement.Id);
// Assert
result.Should().BeOfType<NoContentResult>();
var deleted = await _context.Announcements.FindAsync(announcement.Id);
deleted.Should().BeNull();
}
#endregion
#region Delete Announcement - Negative Tests
[Fact]
public async Task DeleteAnnouncement_NonExistent_ReturnsNotFound()
{
// Arrange
var organizer = TestDataFactory.CreateUser(role: UserRole.Organizer);
_context.Users.Add(organizer);
await _context.SaveChangesAsync();
SetUserContext(organizer.Id, "Organizer");
// Act
var result = await _controller.DeleteAnnouncement(Guid.NewGuid());
// Assert
result.Should().BeOfType<NotFoundResult>();
}
#endregion
#region Get My Announcements
[Fact]
public async Task GetMyAnnouncements_ReturnsAnnouncementsForRegisteredEvents()
{
// Arrange
var organizer = TestDataFactory.CreateUser(role: UserRole.Organizer);
var participant = TestDataFactory.CreateUser(email: "participant@example.com", role: UserRole.Participant);
_context.Users.AddRange(organizer, participant);
var event1 = TestDataFactory.CreateEvent(organizerId: organizer.Id, status: EventStatus.Published);
var event2 = TestDataFactory.CreateEvent(name: "Event 2", organizerId: organizer.Id, status: EventStatus.Published);
_context.Events.AddRange(event1, event2);
var registration = TestDataFactory.CreateRegistration(event1.Id, participant.Id, RegistrationStatus.Confirmed);
_context.Registrations.Add(registration);
var announcement1 = TestDataFactory.CreateAnnouncement(event1.Id, "Announcement 1", "Content");
announcement1.IsPublished = true;
var announcement2 = TestDataFactory.CreateAnnouncement(event2.Id, "Announcement 2", "Content");
announcement2.IsPublished = true;
_context.Announcements.AddRange(announcement1, announcement2);
await _context.SaveChangesAsync();
SetUserContext(participant.Id, "Participant");
// Act
var result = await _controller.GetMyAnnouncements();
// Assert
var okResult = result.Result.Should().BeOfType<OkObjectResult>().Subject;
var announcements = okResult.Value.Should().BeAssignableTo<IEnumerable<AnnouncementDto>>().Subject;
announcements.Should().HaveCount(1);
announcements.First().Title.Should().Be("Announcement 1");
}
[Fact]
public async Task GetMyAnnouncements_ExcludesUnpublished()
{
// Arrange
var organizer = TestDataFactory.CreateUser(role: UserRole.Organizer);
var participant = TestDataFactory.CreateUser(email: "participant2@example.com", role: UserRole.Participant);
_context.Users.AddRange(organizer, participant);
var eventEntity = TestDataFactory.CreateEvent(organizerId: organizer.Id, status: EventStatus.Published);
_context.Events.Add(eventEntity);
var registration = TestDataFactory.CreateRegistration(eventEntity.Id, participant.Id, RegistrationStatus.Confirmed);
_context.Registrations.Add(registration);
var published = TestDataFactory.CreateAnnouncement(eventEntity.Id, "Published", "Content");
published.IsPublished = true;
var unpublished = TestDataFactory.CreateAnnouncement(eventEntity.Id, "Unpublished", "Content");
unpublished.IsPublished = false;
_context.Announcements.AddRange(published, unpublished);
await _context.SaveChangesAsync();
SetUserContext(participant.Id, "Participant");
// Act
var result = await _controller.GetMyAnnouncements();
// Assert
var okResult = result.Result.Should().BeOfType<OkObjectResult>().Subject;
var announcements = okResult.Value.Should().BeAssignableTo<IEnumerable<AnnouncementDto>>().Subject;
announcements.Should().HaveCount(1);
announcements.First().Title.Should().Be("Published");
}
#endregion
}