using System.Text; using AutoFixture; using Govor.API.Controllers; using Govor.Application.Interfaces.Infrastructure.Extensions; using Govor.Application.Interfaces.Medias; using Govor.Contracts.Requests; using Govor.Domain.Models.Messages; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using Moq; namespace Govor.API.Tests.IntegrationTests.Controllers; [TestFixture] public class MediaControllerTests { private Fixture _fixture; private Mock _currentUserMock; private Mock> _loggerMock; private Mock _mockMedia; private Mock _mockAccesser; private MediaController _controller; private Guid _userId = Guid.NewGuid(); [SetUp] public void SetUp() { _fixture = new Fixture(); _fixture.Behaviors.OfType().ToList().ForEach(b => _fixture.Behaviors.Remove(b)); _fixture.Behaviors.Add(new OmitOnRecursionBehavior()); _currentUserMock = new Mock(); _loggerMock = new Mock>(); _mockAccesser = new Mock(); _mockMedia = new Mock(); _currentUserMock.Setup(f => f.GetCurrentUserId()).Returns(_userId); _controller = new MediaController( _loggerMock.Object, _mockMedia.Object, _mockAccesser.Object, _currentUserMock.Object); } // Tests for Upload action [Test] public async Task Upload_ValidRequest_ReturnsOkResult() { // Arrange var content = "fake file content"; var fileName = "testfile.txt"; var fileBytes = System.Text.Encoding.UTF8.GetBytes(content); var stream = new MemoryStream(fileBytes); var formFileMock = new Mock(); formFileMock.Setup(f => f.Length).Returns(fileBytes.Length); formFileMock.Setup(f => f.FileName).Returns(fileName); formFileMock.Setup(f => f.OpenReadStream()).Returns(stream); formFileMock.Setup(f => f.CopyToAsync(It.IsAny(), default)) .Returns((target, _) => stream.CopyToAsync(target)); var uploadRequest = _fixture.Build() .With(r => r.FromFile, formFileMock.Object) .With(r => r.Type, MediaType.Image) .With(r => r.MimeType, "image/png") .With(r => r.EncryptedKey, "secret") .Create(); var uploadResult = _fixture.Create(); _mockMedia.Setup(f => f.UploadMediaAsync(It.IsAny())) .ReturnsAsync(uploadResult); // Act var result = await _controller.Upload(uploadRequest); // Assert Assert.That(result, Is.InstanceOf()); var okResult = result as OkObjectResult; var value = okResult?.Value as MediaUploadResult; Assert.That(value, Is.Not.Null); Assert.That(value!.Url, Is.EqualTo(uploadResult.Url)); Assert.That(value.MediaId, Is.EqualTo(uploadResult.MediaId)); } [Test] public async Task Upload_InvalidModelState_ReturnsBadRequest() { // Arrange _controller.ModelState.AddModelError("Error", "Invalid model state"); var content = "fake file content"; var fileName = "testfile.txt"; var fileBytes = System.Text.Encoding.UTF8.GetBytes(content); var stream = new MemoryStream(fileBytes); var formFileMock = new Mock(); formFileMock.Setup(f => f.Length).Returns(fileBytes.Length); formFileMock.Setup(f => f.FileName).Returns(fileName); formFileMock.Setup(f => f.OpenReadStream()).Returns(stream); formFileMock.Setup(f => f.CopyToAsync(It.IsAny(), default)) .Returns((target, _) => stream.CopyToAsync(target)); var uploadRequest = _fixture.Build() .With(r => r.FromFile, formFileMock.Object) .With(r => r.Type, MediaType.Image) .With(r => r.MimeType, "image/png") .With(r => r.EncryptedKey, "secret") .Create(); // Act var result = await _controller.Upload(uploadRequest); // Assert Assert.That(result, Is.InstanceOf()); } [Test] public async Task Upload_NoFileUploaded_ReturnsBadRequest() { // Arrange var uploadRequest = _fixture.Build() .With(r => r.FromFile, (IFormFile)null) .Create(); // Act var result = await _controller.Upload(uploadRequest); // Assert Assert.That(result, Is.InstanceOf()); var badRequestResult = result as BadRequestObjectResult; Assert.That(badRequestResult?.Value, Is.EqualTo("No file uploaded")); } [Test] public async Task Upload_EmptyFile_ReturnsBadRequest() { // Arrange var formFileMock = new Mock(); formFileMock.Setup(f => f.Length).Returns(0); var uploadRequest = _fixture.Build() .With(r => r.FromFile, formFileMock.Object) .Create(); // Act var result = await _controller.Upload(uploadRequest); // Assert Assert.That(result, Is.InstanceOf()); var badRequestResult = result as BadRequestObjectResult; Assert.That(badRequestResult?.Value, Is.EqualTo("No file uploaded")); } [Test] public async Task Upload_FileTooLarge_ReturnsBadRequest() { // Arrange var formFileMock = new Mock(); formFileMock.Setup(f => f.Length).Returns(20_000_001); // Just over 20MB var uploadRequest = _fixture.Build() .With(r => r.FromFile, formFileMock.Object) .Create(); // Act var result = await _controller.Upload(uploadRequest); // Assert Assert.That(result, Is.InstanceOf()); var badRequestResult = result as BadRequestObjectResult; Assert.That(badRequestResult?.Value, Is.EqualTo("File is too large")); } [Test] public async Task Upload_MissingMimeType_ReturnsBadRequest() { // Arrange var formFileMock = new Mock(); formFileMock.Setup(f => f.Length).Returns(1000); formFileMock.Setup(f => f.FileName).Returns("testfile.txt"); var uploadRequest = _fixture.Build() .With(r => r.FromFile, formFileMock.Object) .With(r => r.MimeType, string.Empty) .Create(); // Act var result = await _controller.Upload(uploadRequest); // Assert Assert.That(result, Is.InstanceOf()); var badRequestResult = result as BadRequestObjectResult; Assert.That(badRequestResult?.Value, Is.EqualTo("Missing MIME type")); } [Test] public async Task Upload_UnauthorizedAccess_ReturnsUnauthorized() { // Arrange var formFileMock = new Mock(); formFileMock.Setup(f => f.Length).Returns(1000); formFileMock.Setup(f => f.FileName).Returns("testfile.txt"); formFileMock.Setup(f => f.OpenReadStream()).Returns(new MemoryStream(new byte[1000])); var uploadRequest = _fixture.Build() .With(r => r.FromFile, formFileMock.Object) .With(r => r.MimeType, "text/plain") .Create(); _mockMedia.Setup(f => f.UploadMediaAsync(It.IsAny())) .ThrowsAsync(new UnauthorizedAccessException("Access denied")); // Act var result = await _controller.Upload(uploadRequest); // Assert Assert.That(result, Is.InstanceOf()); var forbidResult = result as ForbidResult; Assert.That(forbidResult.AuthenticationSchemes.First(), Is.EqualTo("Access denied")); } [Test] public async Task Upload_InvalidOperation_ReturnsBadRequest() { // Arrange var formFileMock = new Mock(); formFileMock.Setup(f => f.Length).Returns(1000); formFileMock.Setup(f => f.FileName).Returns("testfile.txt"); formFileMock.Setup(f => f.OpenReadStream()).Returns(new MemoryStream(new byte[1000])); var uploadRequest = _fixture.Build() .With(r => r.FromFile, formFileMock.Object) .With(r => r.MimeType, "text/plain") .Create(); _mockMedia.Setup(f => f.UploadMediaAsync(It.IsAny())) .ThrowsAsync(new InvalidOperationException("Invalid operation")); // Act var result = await _controller.Upload(uploadRequest); // Assert Assert.That(result, Is.InstanceOf()); var badRequestResult = result as BadRequestObjectResult; Assert.That(badRequestResult?.Value, Is.EqualTo("Invalid operation")); } [Test] public async Task Upload_GeneralException_ReturnsInternalServerError() { // Arrange var formFileMock = new Mock(); formFileMock.Setup(f => f.Length).Returns(1000); formFileMock.Setup(f => f.FileName).Returns("testfile.txt"); formFileMock.Setup(f => f.OpenReadStream()).Returns(new MemoryStream(new byte[1000])); var uploadRequest = _fixture.Build() .With(r => r.FromFile, formFileMock.Object) .With(r => r.MimeType, "text/plain") .Create(); _mockMedia.Setup(f => f.UploadMediaAsync(It.IsAny())) .ThrowsAsync(new Exception("Something went wrong")); // Act var result = await _controller.Upload(uploadRequest); // Assert Assert.That(result, Is.InstanceOf()); var objectResult = result as ObjectResult; Assert.That(objectResult.StatusCode, Is.EqualTo(500)); } // Tests for Download action [Test] public async Task Download_HasAccessAndMediaExists_ReturnsFile() { // Arrange var mediaId = Guid.NewGuid(); var media = _fixture.Build() .With(m => m.Data, Encoding.UTF8.GetBytes("fake file content")) .With(m => m.MimeType, "application/octet-stream") // Ensure MimeType is set .With(m => m.FileName, "testfile.txt") .Create(); _mockAccesser.Setup(f => f.HasAccessAsync(mediaId, _userId)).ReturnsAsync(true); _mockMedia.Setup(f => f.GetMediaByIdAsync(mediaId)).ReturnsAsync(media); // Act var result = await _controller.Download(mediaId); // Assert Assert.That(result, Is.InstanceOf()); var fileResult = result as FileContentResult; Assert.That(fileResult?.FileContents, Is.EqualTo(media.Data)); Assert.That(fileResult?.ContentType, Is.EqualTo(media.MimeType)); // Changed MineType to MimeType Assert.That(fileResult?.FileDownloadName, Is.EqualTo(Path.GetFileName(media.FileName))); } [Test] public async Task Download_NoAccess_ReturnsForbid() { // Arrange var mediaId = Guid.NewGuid(); _mockAccesser.Setup(f => f.HasAccessAsync(mediaId, _userId)).ReturnsAsync(false); // Act var result = await _controller.Download(mediaId); // Assert Assert.That(result, Is.InstanceOf()); } [Test] public async Task Download_MediaNotFound_ReturnsNotFound() { // Arrange var mediaId = Guid.NewGuid(); _mockAccesser.Setup(f => f.HasAccessAsync(mediaId, _userId)).ReturnsAsync(true); _mockMedia.Setup(f => f.GetMediaByIdAsync(mediaId)) .ThrowsAsync(new KeyNotFoundException("Media not found")); // Act var result = await _controller.Download(mediaId); // Assert Assert.That(result, Is.InstanceOf()); var notFoundResult = result as NotFoundObjectResult; Assert.That(notFoundResult?.Value, Is.EqualTo("Media not found")); } [Test] public async Task Download_GeneralException_ReturnsInternalServerError() { // Arrange var mediaId = Guid.NewGuid(); _mockAccesser.Setup(f => f.HasAccessAsync(mediaId, _userId)).ReturnsAsync(true); _mockMedia.Setup(f => f.GetMediaByIdAsync(mediaId)) .ThrowsAsync(new Exception("Something went wrong")); // Act var result = await _controller.Download(mediaId); // Assert Assert.That(result, Is.InstanceOf()); var objectResult = result as ObjectResult; Assert.That(objectResult.StatusCode, Is.EqualTo(500)); } [TearDown] public void TearDown() { _controller.Dispose(); } }