using MicCheck.Api.Audit; using MicCheck.Api.Common; using MicCheck.Api.Common.Security.Authorization; using MicCheck.Api.Data; using MicCheck.Api.Organizations; using MicCheck.Api.Projects; using MicCheck.Api.Tests.Unit.TestSupport; using Microsoft.AspNetCore.Mvc; using Moq; using NUnit.Framework; namespace MicCheck.Api.Tests.Unit.Projects; [TestFixture] public class ProjectsControllerTests { private Mock _db = null!; private List _projects = null!; private List _permissions = null!; private ProjectsController _controller = null!; private const int OrganizationId = 1; [SetUp] public void SetUp() { _db = new Mock(); _db.SetupDbSet(c => c.Organizations, [ new Organization { Id = OrganizationId, Name = "Test Org", CreatedAt = DateTimeOffset.UtcNow } ]); _projects = []; _db.SetupDbSetWithGeneratedIds(c => c.Projects, _projects); _permissions = []; _db.SetupDbSet(c => c.UserProjectPermissions, _permissions); var webhookQueue = new MicCheck.Api.Webhooks.WebhookQueue(); var auditService = new Mock(); auditService.Setup(a => a.LogAsync( It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) .Returns(Task.CompletedTask); _controller = new ProjectsController(new ProjectService(_db.Object, auditService.Object)); } [Test] public async Task WhenListingProjectsForAnOrganization_ThenTheyAreReturnedInAPage() { await _controller.Create(new CreateProjectRequest("Project A", OrganizationId), CancellationToken.None); await _controller.Create(new CreateProjectRequest("Project B", OrganizationId), CancellationToken.None); var result = await _controller.List(OrganizationId); var ok = result.Result as OkObjectResult; var page = (PaginatedResponse)ok!.Value!; Assert.That(page.Count, Is.EqualTo(2)); Assert.That(page.Results, Has.Count.EqualTo(2)); } [Test] public async Task WhenListingProjectsWithAPageSizeAboveTheMaximum_ThenItIsClampedTo100() { for (var i = 0; i < 3; i++) await _controller.Create(new CreateProjectRequest($"Project {i}", OrganizationId), CancellationToken.None); var result = await _controller.List(OrganizationId, page: 1, pageSize: 1000); var ok = result.Result as OkObjectResult; var page = (PaginatedResponse)ok!.Value!; Assert.That(page.Results, Has.Count.EqualTo(3)); } [Test] public async Task WhenCreatingAProject_ThenACreatedResultWithTheProjectIsReturned() { var result = await _controller.Create(new CreateProjectRequest("My Project", OrganizationId), CancellationToken.None); var created = result.Result as CreatedAtActionResult; Assert.That(created, Is.Not.Null); Assert.That(((ProjectResponse)created!.Value!).Name, Is.EqualTo("My Project")); } [Test] public async Task WhenGettingAProjectByIdThatExists_ThenItIsReturned() { var created = await _controller.Create(new CreateProjectRequest("My Project", OrganizationId), CancellationToken.None); var projectId = ((ProjectResponse)((CreatedAtActionResult)created.Result!).Value!).Id; var result = await _controller.GetById(projectId, CancellationToken.None); var ok = result.Result as OkObjectResult; Assert.That(ok, Is.Not.Null); Assert.That(((ProjectResponse)ok!.Value!).Id, Is.EqualTo(projectId)); } [Test] public async Task WhenGettingAProjectByIdThatDoesNotExist_ThenNotFoundIsReturned() { var result = await _controller.GetById(999, CancellationToken.None); Assert.That(result.Result, Is.InstanceOf()); } [Test] public async Task WhenUpdatingAProjectThatDoesNotExist_ThenNotFoundIsReturned() { var result = await _controller.Update(999, new UpdateProjectRequest("renamed", false), CancellationToken.None); Assert.That(result.Result, Is.InstanceOf()); } [Test] public async Task WhenUpdatingAProject_ThenTheUpdatedProjectIsReturned() { var created = await _controller.Create(new CreateProjectRequest("Old Name", OrganizationId), CancellationToken.None); var projectId = ((ProjectResponse)((CreatedAtActionResult)created.Result!).Value!).Id; var result = await _controller.Update(projectId, new UpdateProjectRequest("New Name", true), CancellationToken.None); var ok = result.Result as OkObjectResult; var response = (ProjectResponse)ok!.Value!; Assert.That(response.Name, Is.EqualTo("New Name")); Assert.That(response.HideDisabledFlags, Is.True); } [Test] public async Task WhenDeletingAProjectThatDoesNotExist_ThenNotFoundIsReturned() { var result = await _controller.Delete(999, CancellationToken.None); Assert.That(result, Is.InstanceOf()); } [Test] public async Task WhenDeletingAProject_ThenNoContentIsReturnedAndItIsRemoved() { var created = await _controller.Create(new CreateProjectRequest("My Project", OrganizationId), CancellationToken.None); var projectId = ((ProjectResponse)((CreatedAtActionResult)created.Result!).Value!).Id; var result = await _controller.Delete(projectId, CancellationToken.None); Assert.That(result, Is.InstanceOf()); Assert.That(_projects.Any(p => p.Id == projectId), Is.False); } [Test] public async Task WhenListingUserPermissionsForAProjectThatDoesNotExist_ThenNotFoundIsReturned() { var result = await _controller.ListUserPermissions(999, CancellationToken.None); Assert.That(result.Result, Is.InstanceOf()); } [Test] public async Task WhenListingUserPermissionsForAProject_ThenTheyAreReturned() { var created = await _controller.Create(new CreateProjectRequest("My Project", OrganizationId), CancellationToken.None); var projectId = ((ProjectResponse)((CreatedAtActionResult)created.Result!).Value!).Id; await _controller.CreateUserPermissions(projectId, new SetUserPermissionsRequest(5, true, ["ViewProject"]), CancellationToken.None); var result = await _controller.ListUserPermissions(projectId, CancellationToken.None); var ok = result.Result as OkObjectResult; var perms = (IReadOnlyList)ok!.Value!; Assert.That(perms, Has.Count.EqualTo(1)); Assert.That(perms[0].UserId, Is.EqualTo(5)); } [Test] public async Task WhenCreatingUserPermissionsForAProjectThatDoesNotExist_ThenNotFoundIsReturned() { var result = await _controller.CreateUserPermissions(999, new SetUserPermissionsRequest(5, true, []), CancellationToken.None); Assert.That(result.Result, Is.InstanceOf()); } [Test] public async Task WhenCreatingUserPermissions_ThenThePermissionsAreParsedAndPersisted() { var created = await _controller.Create(new CreateProjectRequest("My Project", OrganizationId), CancellationToken.None); var projectId = ((ProjectResponse)((CreatedAtActionResult)created.Result!).Value!).Id; var result = await _controller.CreateUserPermissions( projectId, new SetUserPermissionsRequest(5, true, ["ViewProject", "EditFeature"]), CancellationToken.None); var ok = result.Result as OkObjectResult; var response = (UserPermissionResponse)ok!.Value!; Assert.That(response.Permissions, Is.EqualTo(new[] { "ViewProject", "EditFeature" })); } [Test] public async Task WhenUpdatingUserPermissionsForAProjectThatDoesNotExist_ThenNotFoundIsReturned() { var result = await _controller.UpdateUserPermissions(999, 5, new SetUserPermissionsRequest(5, true, []), CancellationToken.None); Assert.That(result.Result, Is.InstanceOf()); } [Test] public async Task WhenUpdatingUserPermissions_ThenTheExistingRecordIsChanged() { var created = await _controller.Create(new CreateProjectRequest("My Project", OrganizationId), CancellationToken.None); var projectId = ((ProjectResponse)((CreatedAtActionResult)created.Result!).Value!).Id; await _controller.CreateUserPermissions(projectId, new SetUserPermissionsRequest(5, false, ["ViewProject"]), CancellationToken.None); var result = await _controller.UpdateUserPermissions(projectId, 5, new SetUserPermissionsRequest(5, true, ["DeleteFeature"]), CancellationToken.None); var ok = result.Result as OkObjectResult; var response = (UserPermissionResponse)ok!.Value!; Assert.That(response.IsAdmin, Is.True); Assert.That(response.Permissions, Is.EqualTo(new[] { "DeleteFeature" })); Assert.That(_permissions, Has.Count.EqualTo(1)); } [Test] public async Task WhenDeletingUserPermissionsForAProjectThatDoesNotExist_ThenNotFoundIsReturned() { var result = await _controller.DeleteUserPermissions(999, 5, CancellationToken.None); Assert.That(result, Is.InstanceOf()); } [Test] public async Task WhenDeletingUserPermissions_ThenTheRecordIsRemoved() { var created = await _controller.Create(new CreateProjectRequest("My Project", OrganizationId), CancellationToken.None); var projectId = ((ProjectResponse)((CreatedAtActionResult)created.Result!).Value!).Id; await _controller.CreateUserPermissions(projectId, new SetUserPermissionsRequest(5, true, ["ViewProject"]), CancellationToken.None); var result = await _controller.DeleteUserPermissions(projectId, 5, CancellationToken.None); Assert.That(result, Is.InstanceOf()); Assert.That(_permissions, Is.Empty); } }