From 99d39be9ac7414d29df5be37a7be42203fdd97b6 Mon Sep 17 00:00:00 2001 From: Leon Hoppe Date: Mon, 23 Dec 2024 18:12:21 +0100 Subject: [PATCH] Created user endpoint tests and documentation --- HopFrame.sln.DotSettings.user | 12 + docs/api/endpoints/user.md | 316 +++++++++++ docs/models.md | 10 + .../Controllers/UserControllerTests.cs | 514 ++++++++++++++++++ 4 files changed, 852 insertions(+) create mode 100644 docs/api/endpoints/user.md create mode 100644 tests/HopFrame.Tests.Api/Controllers/UserControllerTests.cs diff --git a/HopFrame.sln.DotSettings.user b/HopFrame.sln.DotSettings.user index 01d3df3..e5935b1 100644 --- a/HopFrame.sln.DotSettings.user +++ b/HopFrame.sln.DotSettings.user @@ -70,6 +70,18 @@ + + + + + + + + + + + + diff --git a/docs/api/endpoints/user.md b/docs/api/endpoints/user.md new file mode 100644 index 0000000..6acf085 --- /dev/null +++ b/docs/api/endpoints/user.md @@ -0,0 +1,316 @@ +# User Endpoints + +## Used Models +- [User](../../models.md#user) +- [UserCreator](../../models.md#usercreator) +- [Permission](../../models.md#permission) + +## API Endpoint: GetUsers + +**Endpoint:** `GET /api/v1/users` + +**Description:** Retrieves a list of users. + +**Authorization Required:** Yes + +**Required Permission:** `hopframe.admin.users.read` + +**Parameters:** None + +**Response:** + +- **200 OK:** Returns a list of users. + ```json + [ + { + "Id": "guid", + "Username": "string", + "Email": "string", + "CreatedAt": "2023-12-23T00:00:00Z", + "Permissions": [ + { + "Id": 1, + "PermissionName": "string", + "GrantedAt": "2023-12-23T00:00:00Z" + } + ] + } + ] + ``` + +- **401 Unauthorized:** User is not authorized to access this endpoint. + + +## API Endpoint: GetUser + +**Endpoint:** `GET /api/v1/users/{userId}` + +**Description:** Retrieves a user by their ID. + +**Authorization Required:** Yes + +**Required Permission:** `hopframe.admin.users.read` + +**Parameters:** +- **userId:** `string` (Path) - The ID of the user to retrieve. + +**Response:** + +- **200 OK:** Returns the user details. + ```json + { + "Id": "guid", + "Username": "string", + "Email": "string", + "CreatedAt": "2023-12-23T00:00:00Z", + "Permissions": [ + { + "Id": 1, + "PermissionName": "string", + "GrantedAt": "2023-12-23T00:00:00Z" + } + ] + } + ``` + +- **400 Bad Request:** Invalid user ID format. + +- **401 Unauthorized:** User is not authorized to access this endpoint. + +- **404 Not Found:** User does not exist. + + +## API Endpoint: GetUserByUsername + +**Endpoint:** `GET /api/v1/users/username/{username}` + +**Description:** Retrieves a user by their username. + +**Authorization Required:** Yes + +**Required Permission:** `hopframe.admin.users.read` + +**Parameters:** +- **username:** `string` (Path) - The username of the user to retrieve. + +**Response:** + +- **200 OK:** Returns the user details. + ```json + { + "Id": "guid", + "Username": "string", + "Email": "string", + "CreatedAt": "2023-12-23T00:00:00Z", + "Permissions": [ + { + "Id": 1, + "PermissionName": "string", + "GrantedAt": "2023-12-23T00:00:00Z" + } + ] + } + ``` + +- **401 Unauthorized:** User is not authorized to access this endpoint. + +- **404 Not Found:** User does not exist. + + +## API Endpoint: GetUserByEmail + +**Endpoint:** `GET /api/v1/users/email/{email}` + +**Description:** Retrieves a user by their email address. + +**Authorization Required:** Yes + +**Required Permission:** `hopframe.admin.users.read` + +**Parameters:** +- **email:** `string` (Path) - The email address of the user to retrieve. + +**Response:** + +- **200 OK:** Returns the user details. + ```json + { + "Id": "guid", + "Username": "string", + "Email": "string", + "CreatedAt": "2023-12-23T00:00:00Z", + "Permissions": [ + { + "Id": 1, + "PermissionName": "string", + "GrantedAt": "2023-12-23T00:00:00Z" + } + ] + } + ``` + +- **401 Unauthorized:** User is not authorized to access this endpoint. + +- **404 Not Found:** User does not exist. + + +## API Endpoint: CreateUser + +**Endpoint:** `POST /api/v1/users` + +**Description:** Creates a new user. + +**Authorization Required:** Yes + +**Required Permission:** `hopframe.admin.users.create` + +**Parameters:** +- **UserCreator:** (Body) - The user creation details. + ```json + { + "Username": "string", + "Email": "string", + "Password": "string", + "Permissions": [ + "permission1", + "permission2" + ] + } + ``` + +**Response:** + +- **200 OK:** Returns the created user. + ```json + { + "Id": "guid", + "Username": "string", + "Email": "string", + "CreatedAt": "2023-12-23T00:00:00Z", + "Permissions": [ + { + "Id": 1, + "PermissionName": "string", + "GrantedAt": "2023-12-23T00:00:00Z" + } + ] + } + ``` + +- **401 Unauthorized:** User is not authorized to access this endpoint. + +- **409 Conflict:** The user already exists. + + +## API Endpoint: UpdateUser + +**Endpoint:** `PUT /api/v1/users/{userId}` + +**Description:** Updates an existing user by their ID. + +**Authorization Required:** Yes + +**Required Permission:** `hopframe.admin.users.update` + +**Parameters:** +- **userId:** `string` (Path) - The ID of the user to update. +- **User:** (Body) - The user details to update. + ```json + { + "Id": "guid", + "Username": "string", + "Email": "string", + "CreatedAt": "2023-12-23T00:00:00Z", + "Permissions": [ + { + "Id": 1, + "PermissionName": "string", + "GrantedAt": "2023-12-23T00:00:00Z" + } + ] + } + ``` + +**Response:** + +- **200 OK:** Returns the updated user. + ```json + { + "Id": "guid", + "Username": "string", + "Email": "string", + "CreatedAt": "2023-12-23T00:00:00Z", + "Permissions": [ + { + "Id": 1, + "PermissionName": "string", + "GrantedAt": "2023-12-23T00:00:00Z" + } + ] + } + ``` + +- **400 Bad Request:** Invalid user ID format. + +- **401 Unauthorized:** User is not authorized to access this endpoint. + +- **404 Not Found:** User does not exist. + +- **409 Conflict:** Cannot edit user with different user ID. + + +## API Endpoint: DeleteUser + +**Endpoint:** `DELETE /api/v1/users/{userId}` + +**Description:** Deletes a user by their ID. + +**Authorization Required:** Yes + +**Required Permission:** `hopframe.admin.users.delete` + +**Parameters:** +- **userId:** `string` (Path) - The ID of the user to delete. + +**Response:** + +- **200 OK:** User successfully deleted. + +- **400 Bad Request:** Invalid user ID format. + +- **401 Unauthorized:** User is not authorized to access this endpoint. + +- **404 Not Found:** User does not exist. + + +## API Endpoint: ChangePassword + +**Endpoint:** `PUT /api/v1/users/{userId}/password` + +**Description:** Updates the password for a user by their ID. + +**Authorization Required:** Yes + +**Required Permission:** `hopframe.admin.users.update` (if the userId is not the id of the requesting user) + +**Parameters:** +- **userId:** `string` (Path) - The ID of the user whose password is being changed. +- **UserPasswordChange:** (Body) - The password change details (note, if you change someone else's password the old password doesn't need to be correct). + ```json + { + "oldPassword": "string", + "newPassword": "string" + } + ``` + +**Response:** + +- **200 OK:** Password successfully updated. + +- **400 Bad Request:** Invalid user ID format. + +- **401 Unauthorized:** User is not authorized to access this endpoint. + +- **404 Not Found:** User does not exist. + +- **409 Conflict:** Old password is incorrect. diff --git a/docs/models.md b/docs/models.md index 7f61e86..91fefd8 100644 --- a/docs/models.md +++ b/docs/models.md @@ -67,6 +67,16 @@ public class UserRegister { } ``` +## UserCreator +```csharp +public class UserCreator { + public string Username { get; set; } + public string Email { get; set; } + public string Password { get; set; } + public virtual List Permissions { get; set; } +} +``` + ## IPermissionOwner ```csharp public interface IPermissionOwner; diff --git a/tests/HopFrame.Tests.Api/Controllers/UserControllerTests.cs b/tests/HopFrame.Tests.Api/Controllers/UserControllerTests.cs new file mode 100644 index 0000000..29b0837 --- /dev/null +++ b/tests/HopFrame.Tests.Api/Controllers/UserControllerTests.cs @@ -0,0 +1,514 @@ +using System.Net; +using HopFrame.Api.Controller; +using HopFrame.Api.Logic; +using HopFrame.Api.Models; +using HopFrame.Database.Models; +using HopFrame.Database.Repositories; +using HopFrame.Security.Authorization; +using HopFrame.Security.Claims; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Options; +using Moq; + +namespace HopFrame.Tests.Api.Controllers; + +public class UserControllerTests { + private (Mock, Mock>, Mock, Mock, UserController) SetupEnvironment() { + var mockLogic = new Mock(); + var mockPermissions = new Mock>(); + var mockPerms = new Mock(); + var mockContext = new Mock(); + + var options = new AdminPermissionOptions(); + + mockPermissions.Setup(o => o.Value).Returns(options); + mockPerms.Setup(p => p.HasPermission(It.IsAny(), It.IsAny())).ReturnsAsync(true); + mockContext + .Setup(c => c.User) + .Returns(new User { Id = Guid.NewGuid(), Username = "user" }); + + var controller = + new UserController(mockPermissions.Object, mockPerms.Object, mockContext.Object, mockLogic.Object); + + return (mockLogic, mockPermissions, mockPerms, mockContext, controller); + } + + [Fact] + public async Task GetUsers_ShouldReturnUnauthorized_WhenUserIsNotAuthorized() { + // Arrange + var (mockLogic, mockPermissions, mockPerms, mockContext, controller) = SetupEnvironment(); + mockPerms.Setup(p => p.HasPermission(It.IsAny(), It.IsAny())).ReturnsAsync(false); + + // Act + var result = await controller.GetUsers(); + + // Assert + Assert.IsType(result.Result); + } + + [Fact] + public async Task GetUsers_ShouldReturnUsers_WhenUserIsAuthorized() { + // Arrange + var (mockLogic, mockPermissions, mockPerms, mockContext, controller) = SetupEnvironment(); + var users = new List { new User { Username = "testuser" } }; + mockLogic.Setup(l => l.GetUsers()).ReturnsAsync(LogicResult>.Ok(users)); + + // Act + var result = await controller.GetUsers(); + + // Assert + var okResult = Assert.IsType(result.Result); + var returnedUsers = Assert.IsAssignableFrom>(okResult.Value); + Assert.Single(returnedUsers); + Assert.Equal("testuser", returnedUsers.First().Username); + } + + [Fact] + public async Task GetUsers_Logic_ShouldReturnOk() { + // Arrange + var (mockLogic, mockPermissions, mockPerms, mockContext, controller) = SetupEnvironment(); + var users = new List { new User { Username = "testuser" } }; + mockLogic.Setup(l => l.GetUsers()).ReturnsAsync(LogicResult>.Ok(users)); + + // Act + var result = await controller.GetUsers(); + + // Assert + var okResult = Assert.IsType(result.Result); + var returnedUsers = Assert.IsAssignableFrom>(okResult.Value); + Assert.Single(returnedUsers); + Assert.Equal("testuser", returnedUsers.First().Username); + } + + [Fact] + public async Task GetUsers_Logic_ShouldReturnNotFound() { + // Arrange + var (mockLogic, mockPermissions, mockPerms, mockContext, controller) = SetupEnvironment(); + mockLogic.Setup(l => l.GetUsers()).ReturnsAsync(LogicResult>.NotFound("No users found")); + + // Act + var result = await controller.GetUsers(); + + // Assert + var notFoundResult = Assert.IsType(result.Result); + Assert.Equal((int)HttpStatusCode.NotFound, notFoundResult.StatusCode); + Assert.Equal("No users found", notFoundResult.Value); + } + + [Fact] + public async Task GetUser_Logic_ShouldReturnOk() { + // Arrange + var (mockLogic, mockPermissions, mockPerms, mockContext, controller) = SetupEnvironment(); + var user = new User { Username = "testuser" }; + mockLogic.Setup(l => l.GetUser(It.IsAny())).ReturnsAsync(LogicResult.Ok(user)); + + // Act + var result = await controller.GetUser("valid-user-id"); + + // Assert + var okResult = Assert.IsType(result.Result); + var returnedUser = Assert.IsType(okResult.Value); + Assert.Equal("testuser", returnedUser.Username); + } + + [Fact] + public async Task GetUser_Logic_ShouldReturnBadRequest() { + // Arrange + var (mockLogic, mockPermissions, mockPerms, mockContext, controller) = SetupEnvironment(); + mockLogic.Setup(l => l.GetUser(It.IsAny())) + .ReturnsAsync(LogicResult.BadRequest("Invalid user id")); + + // Act + var result = await controller.GetUser("invalid-user-id"); + + // Assert + var badRequestResult = Assert.IsType(result.Result); + Assert.Equal((int)HttpStatusCode.BadRequest, badRequestResult.StatusCode); + Assert.Equal("Invalid user id", badRequestResult.Value); + } + + [Fact] + public async Task GetUser_Logic_ShouldReturnUnauthorized() { + // Arrange + var (mockLogic, mockPermissions, mockPerms, mockContext, controller) = SetupEnvironment(); + mockPerms.Setup(p => p.HasPermission(It.IsAny(), It.IsAny())).ReturnsAsync(false); + + // Act + var result = await controller.GetUser("valid-user-id"); + + // Assert + Assert.IsType(result.Result); + } + + [Fact] + public async Task GetUser_Logic_ShouldReturnNotFound() { + // Arrange + var (mockLogic, mockPermissions, mockPerms, mockContext, controller) = SetupEnvironment(); + mockLogic.Setup(l => l.GetUser(It.IsAny())).ReturnsAsync(LogicResult.NotFound("User not found")); + + // Act + var result = await controller.GetUser("invalid-user-id"); + + // Assert + var notFoundResult = Assert.IsType(result.Result); + Assert.Equal((int)HttpStatusCode.NotFound, notFoundResult.StatusCode); + Assert.Equal("User not found", notFoundResult.Value); + } + + [Fact] + public async Task GetUserByUsername_Logic_ShouldReturnOk() { + // Arrange + var (mockLogic, mockPermissions, mockPerms, mockContext, controller) = SetupEnvironment(); + var user = new User { Username = "testuser" }; + mockLogic.Setup(l => l.GetUserByUsername(It.IsAny())).ReturnsAsync(LogicResult.Ok(user)); + + // Act + var result = await controller.GetUserByUsername("valid-username"); + + // Assert + var okResult = Assert.IsType(result.Result); + var returnedUser = Assert.IsType(okResult.Value); + Assert.Equal("testuser", returnedUser.Username); + } + + [Fact] + public async Task GetUserByUsername_Logic_ShouldReturnNotFound() { + // Arrange + var (mockLogic, mockPermissions, mockPerms, mockContext, controller) = SetupEnvironment(); + mockLogic.Setup(l => l.GetUserByUsername(It.IsAny())) + .ReturnsAsync(LogicResult.NotFound("User not found")); + + // Act + var result = await controller.GetUserByUsername("invalid-username"); + + // Assert + var notFoundResult = Assert.IsType(result.Result); + Assert.Equal((int)HttpStatusCode.NotFound, notFoundResult.StatusCode); + Assert.Equal("User not found", notFoundResult.Value); + } + + [Fact] + public async Task GetUserByEmail_Logic_ShouldReturnOk() { + // Arrange + var (mockLogic, mockPermissions, mockPerms, mockContext, controller) = SetupEnvironment(); + var user = new User { Username = "testuser" }; + mockLogic.Setup(l => l.GetUserByEmail(It.IsAny())).ReturnsAsync(LogicResult.Ok(user)); + + // Act + var result = await controller.GetUserByEmail("valid-email@example.com"); + + // Assert + var okResult = Assert.IsType(result.Result); + var returnedUser = Assert.IsType(okResult.Value); + Assert.Equal("testuser", returnedUser.Username); + } + + [Fact] + public async Task GetUserByEmail_Logic_ShouldReturnNotFound() { + // Arrange + var (mockLogic, mockPermissions, mockPerms, mockContext, controller) = SetupEnvironment(); + mockLogic.Setup(l => l.GetUserByEmail(It.IsAny())) + .ReturnsAsync(LogicResult.NotFound("User not found")); + + // Act + var result = await controller.GetUserByEmail("invalid-email@example.com"); + + // Assert + var notFoundResult = Assert.IsType(result.Result); + Assert.Equal((int)HttpStatusCode.NotFound, notFoundResult.StatusCode); + Assert.Equal("User not found", notFoundResult.Value); + } + + [Fact] + public async Task CreateUser_Logic_ShouldReturnOk() { + // Arrange + var (mockLogic, mockPermissions, mockPerms, mockContext, controller) = SetupEnvironment(); + var newUser = new User { Username = "newuser" }; + mockLogic.Setup(l => l.CreateUser(It.IsAny())).ReturnsAsync(LogicResult.Ok(newUser)); + + // Act + var result = await controller.CreateUser(new UserCreator + { Username = "newuser", Email = "newuser@example.com", Password = "password" }); + + // Assert + var okResult = Assert.IsType(result.Result); + var createdUser = Assert.IsType(okResult.Value); + Assert.Equal("newuser", createdUser.Username); + } + + [Fact] + public async Task CreateUser_Logic_ShouldReturnConflict() { + // Arrange + var (mockLogic, mockPermissions, mockPerms, mockContext, controller) = SetupEnvironment(); + mockLogic.Setup(l => l.CreateUser(It.IsAny())) + .ReturnsAsync(LogicResult.Conflict("User already exists")); + + // Act + var result = await controller.CreateUser(new UserCreator + { Username = "existinguser", Email = "existinguser@example.com", Password = "password" }); + + // Assert + var conflictResult = Assert.IsType(result.Result); + Assert.Equal((int)HttpStatusCode.Conflict, conflictResult.StatusCode); + Assert.Equal("User already exists", conflictResult.Value); + } + + [Fact] + public async Task UpdateUser_Logic_ShouldReturnOk() { + // Arrange + var (mockLogic, mockPermissions, mockPerms, mockContext, controller) = SetupEnvironment(); + var updatedUser = new User { Username = "updateduser" }; + mockLogic.Setup(l => l.UpdateUser(It.IsAny(), It.IsAny())) + .ReturnsAsync(LogicResult.Ok(updatedUser)); + + // Act + var result = + await controller.UpdateUser("valid-user-id", new User { Id = Guid.NewGuid(), Username = "updateduser" }); + + // Assert + var okResult = Assert.IsType(result.Result); + var returnedUser = Assert.IsType(okResult.Value); + Assert.Equal("updateduser", returnedUser.Username); + } + + [Fact] + public async Task UpdateUser_Logic_ShouldReturnBadRequest() { + // Arrange + var (mockLogic, mockPermissions, mockPerms, mockContext, controller) = SetupEnvironment(); + mockLogic.Setup(l => l.UpdateUser(It.IsAny(), It.IsAny())) + .ReturnsAsync(LogicResult.BadRequest("Invalid user id")); + + // Act + var result = await controller.UpdateUser("invalid-user-id", + new User { Id = Guid.NewGuid(), Username = "updateduser" }); + + // Assert + var badRequestResult = Assert.IsType(result.Result); + Assert.Equal((int)HttpStatusCode.BadRequest, badRequestResult.StatusCode); + Assert.Equal("Invalid user id", badRequestResult.Value); + } + + [Fact] + public async Task UpdateUser_Logic_ShouldReturnNotFound() { + // Arrange + var (mockLogic, mockPermissions, mockPerms, mockContext, controller) = SetupEnvironment(); + mockLogic.Setup(l => l.UpdateUser(It.IsAny(), It.IsAny())) + .ReturnsAsync(LogicResult.NotFound("User not found")); + + // Act + var result = await controller.UpdateUser("nonexistent-user-id", + new User { Id = Guid.NewGuid(), Username = "nonexistentuser" }); + + // Assert + var notFoundResult = Assert.IsType(result.Result); + Assert.Equal((int)HttpStatusCode.NotFound, notFoundResult.StatusCode); + Assert.Equal("User not found", notFoundResult.Value); + } + + [Fact] + public async Task UpdateUser_Logic_ShouldReturnConflict() { + // Arrange + var (mockLogic, mockPermissions, mockPerms, mockContext, controller) = SetupEnvironment(); + mockLogic.Setup(l => l.UpdateUser(It.IsAny(), It.IsAny())) + .ReturnsAsync(LogicResult.Conflict("Conflict in user update")); + + // Act + var result = await controller.UpdateUser("conflict-user-id", + new User { Id = Guid.NewGuid(), Username = "conflictuser" }); + + // Assert + var conflictResult = Assert.IsType(result.Result); + Assert.Equal((int)HttpStatusCode.Conflict, conflictResult.StatusCode); + Assert.Equal("Conflict in user update", conflictResult.Value); + } + + [Fact] + public async Task DeleteUser_Logic_ShouldReturnOk() { + // Arrange + var (mockLogic, mockPermissions, mockPerms, mockContext, controller) = SetupEnvironment(); + mockLogic.Setup(l => l.DeleteUser(It.IsAny())).ReturnsAsync(LogicResult.Ok()); + + // Act + var result = await controller.DeleteUser("valid-user-id"); + + // Assert + var okResult = Assert.IsType(result); + } + + [Fact] + public async Task DeleteUser_Logic_ShouldReturnNotFound() { + // Arrange + var (mockLogic, mockPermissions, mockPerms, mockContext, controller) = SetupEnvironment(); + mockLogic.Setup(l => l.DeleteUser(It.IsAny())).ReturnsAsync(LogicResult.NotFound("User not found")); + + // Act + var result = await controller.DeleteUser("invalid-user-id"); + + // Assert + var notFoundResult = Assert.IsType(result); + Assert.Equal((int)HttpStatusCode.NotFound, notFoundResult.StatusCode); + Assert.Equal("User not found", notFoundResult.Value); + } + + [Fact] + public async Task DeleteUser_Logic_ShouldReturnBadRequest() { + // Arrange + var (mockLogic, mockPermissions, mockPerms, mockContext, controller) = SetupEnvironment(); + mockLogic.Setup(l => l.DeleteUser(It.IsAny())).ReturnsAsync(LogicResult.BadRequest("Invalid user id")); + + // Act + var result = await controller.DeleteUser("invalid-user-id"); + + // Assert + var badRequestResult = Assert.IsType(result); + Assert.Equal((int)HttpStatusCode.BadRequest, badRequestResult.StatusCode); + Assert.Equal("Invalid user id", badRequestResult.Value); + } + + [Fact] + public async Task ChangePassword_Logic_ShouldReturnOk() { + // Arrange + var (mockLogic, mockPermissions, mockPerms, mockContext, controller) = SetupEnvironment(); + mockLogic.Setup(l => l.UpdatePassword(It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(LogicResult.Ok()); + + // Act + var result = await controller.ChangePassword("valid-user-id", + new UserPasswordChange { OldPassword = "oldPassword", NewPassword = "newPassword" }); + + // Assert + var okResult = Assert.IsType(result); + } + + [Fact] + public async Task ChangePassword_Logic_ShouldReturnBadRequest() { + // Arrange + var (mockLogic, mockPermissions, mockPerms, mockContext, controller) = SetupEnvironment(); + mockLogic.Setup(l => l.UpdatePassword(It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(LogicResult.BadRequest("Invalid user id")); + + // Act + var result = await controller.ChangePassword("invalid-user-id", + new UserPasswordChange { OldPassword = "oldPassword", NewPassword = "newPassword" }); + + // Assert + var badRequestResult = Assert.IsType(result); + Assert.Equal((int)HttpStatusCode.BadRequest, badRequestResult.StatusCode); + Assert.Equal("Invalid user id", badRequestResult.Value); + } + + [Fact] + public async Task ChangePassword_Logic_ShouldReturnNotFound() { + // Arrange + var (mockLogic, mockPermissions, mockPerms, mockContext, controller) = SetupEnvironment(); + mockLogic.Setup(l => l.UpdatePassword(It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(LogicResult.NotFound("User not found")); + + // Act + var result = await controller.ChangePassword("nonexistent-user-id", + new UserPasswordChange { OldPassword = "oldPassword", NewPassword = "newPassword" }); + + // Assert + var notFoundResult = Assert.IsType(result); + Assert.Equal((int)HttpStatusCode.NotFound, notFoundResult.StatusCode); + Assert.Equal("User not found", notFoundResult.Value); + } + + [Fact] + public async Task ChangePassword_Logic_ShouldReturnConflict() { + // Arrange + var (mockLogic, mockPermissions, mockPerms, mockContext, controller) = SetupEnvironment(); + mockLogic.Setup(l => l.UpdatePassword(It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(LogicResult.Conflict("Old password is not correct")); + + // Act + var result = await controller.ChangePassword("conflict-user-id", + new UserPasswordChange { OldPassword = "wrongOldPassword", NewPassword = "newPassword" }); + + // Assert + var conflictResult = Assert.IsType(result); + Assert.Equal((int)HttpStatusCode.Conflict, conflictResult.StatusCode); + Assert.Equal("Old password is not correct", conflictResult.Value); + } + + [Fact] + public async Task GetUserByUsername_Logic_ShouldReturnUnauthorized() { + // Arrange + var (mockLogic, mockPermissions, mockPerms, mockContext, controller) = SetupEnvironment(); + mockPerms.Setup(p => p.HasPermission(It.IsAny(), It.IsAny())).ReturnsAsync(false); + + // Act + var result = await controller.GetUserByUsername("valid-username"); + + // Assert + Assert.IsType(result.Result); + } + + [Fact] + public async Task GetUserByEmail_Logic_ShouldReturnUnauthorized() { + // Arrange + var (mockLogic, mockPermissions, mockPerms, mockContext, controller) = SetupEnvironment(); + mockPerms.Setup(p => p.HasPermission(It.IsAny(), It.IsAny())).ReturnsAsync(false); + + // Act + var result = await controller.GetUserByEmail("valid-email@example.com"); + + // Assert + Assert.IsType(result.Result); + } + + [Fact] + public async Task CreateUser_Logic_ShouldReturnUnauthorized() { + // Arrange + var (mockLogic, mockPermissions, mockPerms, mockContext, controller) = SetupEnvironment(); + mockPerms.Setup(p => p.HasPermission(It.IsAny(), It.IsAny())).ReturnsAsync(false); + + // Act + var result = await controller.CreateUser(new UserCreator + { Username = "newuser", Email = "newuser@example.com", Password = "password" }); + + // Assert + Assert.IsType(result.Result); + } + + [Fact] + public async Task UpdateUser_Logic_ShouldReturnUnauthorized() { + // Arrange + var (mockLogic, mockPermissions, mockPerms, mockContext, controller) = SetupEnvironment(); + mockPerms.Setup(p => p.HasPermission(It.IsAny(), It.IsAny())).ReturnsAsync(false); + + // Act + var result = + await controller.UpdateUser("valid-user-id", new User { Id = Guid.NewGuid(), Username = "updateduser" }); + + // Assert + Assert.IsType(result.Result); + } + + [Fact] + public async Task DeleteUser_Logic_ShouldReturnUnauthorized() { + // Arrange + var (mockLogic, mockPermissions, mockPerms, mockContext, controller) = SetupEnvironment(); + mockPerms.Setup(p => p.HasPermission(It.IsAny(), It.IsAny())).ReturnsAsync(false); + + // Act + var result = await controller.DeleteUser("valid-user-id"); + + // Assert + Assert.IsType(result); + } + + [Fact] + public async Task ChangePassword_Logic_ShouldReturnUnauthorized() { + // Arrange + var (mockLogic, mockPermissions, mockPerms, mockContext, controller) = SetupEnvironment(); + mockPerms.Setup(p => p.HasPermission(It.IsAny(), It.IsAny())).ReturnsAsync(false); + + // Act + var result = await controller.ChangePassword("valid-user-id", + new UserPasswordChange { OldPassword = "oldPassword", NewPassword = "newPassword" }); + + // Assert + Assert.IsType(result); + } +} \ No newline at end of file