#if POSTGRES using Events.EF.Data.Postgres; #else using Events.EF.Data.MSSQL; #endif using Events.EF.Models; using Events.MVC.Controllers; using Events.MVC.Models; using Events.MVC.Models.Sports; using Events.Tests.UnitTests.Infrastructure; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Options; using Moq; using Sieve.Models; namespace Events.Tests.UnitTests.Controllers; public class SportsControllerShould { [Fact] public async Task ReturnPartialViewWithExpectedViewModelForExistingRow() { await using var ctx = ControllerTestContext.CreateContext(); ctx.Sports.Add(new Sport { Id = 5, Name = "Basketball" }); await ctx.SaveChangesAsync(); var controller = CreateController(ctx, useSieve: false); var result = await controller.Row(5); var partial = Assert.IsType(result); Assert.Equal("_SportRow", partial.ViewName); var model = Assert.IsType(partial.Model); Assert.Equal(5, model.Id); Assert.Equal("Basketball", model.Name); } [Fact] public async Task ReturnNotFoundForMissingRow() { await using var ctx = ControllerTestContext.CreateContext(); var controller = CreateController(ctx, useSieve: false); var result = await controller.Row(404); Assert.IsType(result); } [Fact] public async Task CreateSport() { await using var ctx = ControllerTestContext.CreateContext(); var controller = CreateController(ctx); var result = await controller.Create(new SportViewModel { Name = "Volleyball" }, ControllerTestContext.EmptySieveModel()); var partial = Assert.IsType(result); Assert.Equal("_SportsList", partial.ViewName); Assert.Contains(ctx.Sports, s => s.Name == "Volleyball"); Assert.Contains("was added successfully", controller.Response.Headers[Events.MVC.Constants.HtmxHeaders.Trigger].ToString()); } [Fact] public async Task ReturnPagedSportsWhenIndexIsRequestedUsingMockedPagingOptions() { await using var ctx = ControllerTestContext.CreateContext(); ctx.Sports.AddRange( new Sport { Id = 1, Name = "Athletics" }, new Sport { Id = 2, Name = "Basketball" }, new Sport { Id = 3, Name = "Cycling" }); await ctx.SaveChangesAsync(); var optionsMock = new Mock>(); optionsMock .SetupGet(options => options.Value) .Returns(new PagingSettings { PageSize = 2 }); var controller = new SportsController( ctx, ControllerTestContext.CreateSieveProcessor(), optionsMock.Object) .WithTempData(); var result = await controller.Index(new SieveModel()); var view = Assert.IsType(result); var model = Assert.IsType>(view.Model); Assert.Equal(2, model.Data.Count); Assert.Equal(2, model.PagingInfo.ItemsPerPage); Assert.Equal(3, model.PagingInfo.TotalItemsCount); Assert.Equal(3, model.PagingInfo.FilteredItemsCount); } [Fact] public async Task PopulateModelStateValidationErrorsForMissingName() { await using var ctx = ControllerTestContext.CreateContext(); var controller = CreateController(ctx); var invalidModel = new SportViewModel { Name = string.Empty }; var result = await controller.Create(invalidModel, ControllerTestContext.EmptySieveModel()); Assert.False( controller.ModelState.IsValid, "This assertion intentionally demonstrates an incorrect expectation: unit tests do not run the MVC validation pipeline automatically."); Assert.True( controller.ModelState.ContainsKey(nameof(SportViewModel.Name)), "This assertion intentionally demonstrates an incorrect expectation: without MVC model validation, ModelState should not contain a validation entry for Name."); Assert.Contains( controller.ModelState[nameof(SportViewModel.Name)]!.Errors, error => error.ErrorMessage == "The Name field is required."); var partial = Assert.IsType(result); Assert.Equal("_CreateSportForm", partial.ViewName); } [Fact] public async Task EditSport() { await using var ctx = ControllerTestContext.CreateContext(); ctx.Sports.Add(ControllerTestContext.CreateSport()); await ctx.SaveChangesAsync(); var controller = CreateController(ctx, useSieve: false); var result = await controller.Edit(10, new SportViewModel { Id = 10, Name = "Volleyball" }); var partial = Assert.IsType(result); Assert.Equal("_SportRow", partial.ViewName); Assert.Equal("Volleyball", (await ctx.Sports.SingleAsync()).Name); } [Fact] public async Task DeleteSport() { await using var ctx = ControllerTestContext.CreateContext(); ctx.Sports.Add(ControllerTestContext.CreateSport()); await ctx.SaveChangesAsync(); var controller = CreateController(ctx); var result = await controller.Delete(10, ControllerTestContext.EmptySieveModel()); var partial = Assert.IsType(result); Assert.Equal("_SportsList", partial.ViewName); Assert.Empty(ctx.Sports); Assert.Contains("was deleted successfully", controller.Response.Headers[Events.MVC.Constants.HtmxHeaders.Trigger].ToString()); } [Fact] public async Task ReturnConflictWhenDeletingSportWithRegistrations() { await using var ctx = ControllerTestContext.CreateContext(); ctx.Countries.Add(ControllerTestContext.CreateCountry()); ctx.People.Add(ControllerTestContext.CreatePerson()); ctx.Events.Add(ControllerTestContext.CreateEvent()); ctx.Sports.Add(ControllerTestContext.CreateSport()); ctx.Registrations.Add(new Registration { Id = 1000, EventId = 100, PersonId = 1, SportId = 10 }); await ctx.SaveChangesAsync(); var controller = CreateController(ctx); var result = await controller.Delete(10, ControllerTestContext.EmptySieveModel()); var content = Assert.IsType(result); Assert.Equal(409, controller.Response.StatusCode); Assert.Equal("The sport cannot be deleted because registrations exist.", content.Content); } private static SportsController CreateController(EventsContext ctx, bool useSieve = true) { var controller = new SportsController( ctx, useSieve ? ControllerTestContext.CreateSieveProcessor() : null!, ControllerTestContext.CreatePagingOptions()) .WithTempData(); return controller; } }