Skip to content

Commit

Permalink
Merge branch 'prerel-1.4.0' into 'main'
Browse files Browse the repository at this point in the history
Prerel 1.4.0

See merge request personal/wedding-share!18
  • Loading branch information
Chris Collins committed Dec 19, 2024
2 parents c4df091 + 57bae97 commit 13fe2ec
Show file tree
Hide file tree
Showing 31 changed files with 981 additions and 239 deletions.
23 changes: 23 additions & 0 deletions WeddingShare.UnitTests/Helpers/JsonResponseHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
namespace WeddingShare.UnitTests.Helpers
{
internal class JsonResponseHelper
{
public static T GetPropertyValue<T>(object? obj, string propertyName, T defaultValue)
{
if (obj != null)
{
try
{
var val = obj?.GetType()?.GetProperty(propertyName)?.GetValue(obj, null);
if (val != null)
{
return (T)val;
}
}
catch { }
}

return defaultValue;
}
}
}
72 changes: 72 additions & 0 deletions WeddingShare.UnitTests/Helpers/MockData.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Primitives;
using WeddingShare.Enums;
using WeddingShare.Models.Database;

namespace WeddingShare.UnitTests.Helpers
{
internal class MockData
{
public static DefaultHttpContext MockHttpContext(Dictionary<string, StringValues>? form = null, IFormFileCollection? files = null)
{
var ctx = new DefaultHttpContext()
{
Session = new MockSession()
};

ctx.Request.Form = new FormCollection(form, files);

return ctx;
}

public static List<GalleryItemModel> MockGalleryItems(int count = 10, int? galleryId = null, GalleryItemState state = GalleryItemState.All)
{
var result = new List<GalleryItemModel>();

for (var i = 0; i < count; i++)
{
result.Add(MockGalleryItem(galleryId, state));
}

return result;
}

public static GalleryItemModel MockGalleryItem(int? galleryId = null, GalleryItemState state = GalleryItemState.All)
{
var rand = new Random();

return new GalleryItemModel()
{
Id = rand.Next(),
GalleryId = galleryId != null ? (int)galleryId : rand.Next(),
Title = $"{Guid.NewGuid()}.{MockFileExtension()}",
UploadedBy = rand.Next(2) % 2 == 0 ? Guid.NewGuid().ToString() : null,
State = state == GalleryItemState.All ? (GalleryItemState)rand.Next(2) : state,
};
}

public static string MockFileExtension()
{
var rand = new Random();

string extension;
switch (rand.Next(4))
{
case 0:
extension = "jpg";
break;
case 1:
extension = "jpeg";
break;
case 2:
extension = "png";
break;
default:
extension = "ffff";
break;
}

return rand.Next(2) % 2 == 0 ? extension.ToUpper() : extension.ToLower();
}
}
}
275 changes: 275 additions & 0 deletions WeddingShare.UnitTests/Tests/Controllers/GalleryControllerTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,275 @@
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Primitives;
using System.Net;
using System.Text.Json;
using WeddingShare.Controllers;
using WeddingShare.Enums;
using WeddingShare.Helpers;
using WeddingShare.Helpers.Database;
using WeddingShare.Models;
using WeddingShare.Models.Database;
using WeddingShare.UnitTests.Helpers;

namespace WeddingShare.UnitTests.Tests.Helpers
{
public class GalleryControllerTests
{
private readonly IWebHostEnvironment _env = Substitute.For<IWebHostEnvironment>();
private readonly IConfigHelper _config = Substitute.For<IConfigHelper>();
private readonly ISecretKeyHelper _secretKey = Substitute.For<ISecretKeyHelper>();
private readonly IDatabaseHelper _database = Substitute.For<IDatabaseHelper>();
private readonly IFileHelper _file = Substitute.For<IFileHelper>();
private readonly IDeviceDetector _deviceDetector = Substitute.For<IDeviceDetector>();
private readonly IImageHelper _image = Substitute.For<IImageHelper>();
private readonly ILogger<GalleryController> _logger = Substitute.For<ILogger<GalleryController>>();
private readonly IStringLocalizer<GalleryController> _localizer = Substitute.For<IStringLocalizer<GalleryController>>();

public GalleryControllerTests()
{
}

[SetUp]
public void Setup()
{
_env.WebRootPath.Returns("/app/wwwroot");

_database.GetGallery("default").Returns(Task.FromResult<GalleryModel?>(new GalleryModel()
{
Id = 1,
Name = "default",
SecretKey = "password",
ApprovedItems = 32,
PendingItems = 50,
TotalItems = 72
}));
_database.GetGallery("missing").Returns(Task.FromResult<GalleryModel?>(null));
_database.AddGallery(Arg.Any<GalleryModel>()).Returns(Task.FromResult<GalleryModel?>(new GalleryModel()
{
Id = 101,
Name = "missing",
SecretKey = "123456",
ApprovedItems = 0,
PendingItems = 0,
TotalItems = 0
}));
_database.AddGalleryItem(Arg.Any<GalleryItemModel>()).Returns(Task.FromResult<GalleryItemModel?>(MockData.MockGalleryItem()));

_database.GetAllGalleryItems(Arg.Any<int>(), GalleryItemState.All).Returns(Task.FromResult(MockData.MockGalleryItems(10, 1, GalleryItemState.All)));
_database.GetAllGalleryItems(Arg.Any<int>(), GalleryItemState.Pending).Returns(Task.FromResult(MockData.MockGalleryItems(10, 1, GalleryItemState.Pending)));
_database.GetAllGalleryItems(Arg.Any<int>(), GalleryItemState.Approved).Returns(Task.FromResult(MockData.MockGalleryItems(10, 1, GalleryItemState.Approved)));

_secretKey.GetGallerySecretKey(Arg.Any<string>()).Returns("password");
_secretKey.GetGallerySecretKey("missing").Returns("123456");

_config.GetOrDefault("Settings", "Allowed_File_Types", Arg.Any<string>()).Returns(".jpg,.jpeg,.png");
_config.GetOrDefault("Settings", "Default_Gallery_View", Arg.Any<int>()).Returns((int)ViewMode.Default);
_config.GetOrDefault("Settings", "Require_Review", Arg.Any<bool>()).Returns(true);
_config.GetOrDefault("Settings", "Max_File_Size_Mb", Arg.Any<int>()).Returns(10);

_localizer[Arg.Any<string>()].Returns(new LocalizedString("UnitTest", "UnitTest"));
}

[TestCase(DeviceType.Desktop, "default", "password", ViewMode.Default, GalleryOrder.None)]
[TestCase(DeviceType.Mobile, "blaa", "123456", ViewMode.Presentation, GalleryOrder.UploadedAsc)]
[TestCase(DeviceType.Tablet, "missing", "123456", ViewMode.Slideshow, GalleryOrder.NameAsc)]
public async Task GalleryController_Index(DeviceType deviceType, string id, string? key, ViewMode? mode, GalleryOrder order)
{
_deviceDetector.ParseDeviceType(Arg.Any<string>()).Returns(deviceType);
_config.GetOrDefault("Settings", "Single_Gallery_Mode", Arg.Any<bool>()).Returns(false);

var controller = new GalleryController(_env, _config, _database, _file, _secretKey, _deviceDetector, _image, _logger, _localizer);
controller.ControllerContext.HttpContext = MockData.MockHttpContext();

ViewResult actual = (ViewResult)await controller.Index(id, key, mode, order);
Assert.That(actual, Is.TypeOf<ViewResult>());
Assert.That(actual?.Model, Is.Not.Null);

PhotoGallery model = (PhotoGallery)actual.Model;
Assert.That(model?.GalleryId, Is.EqualTo(id));
Assert.That(model.GalleryPath, Is.EqualTo($"/uploads/{id}"));
Assert.That(model.ThumbnailsPath, Is.EqualTo($"/thumbnails"));
Assert.That(model.ViewMode, Is.EqualTo(mode));
Assert.That(model?.FileUploader?.GalleryId, Is.EqualTo(id));
Assert.That(model?.FileUploader?.SecretKey, Is.EqualTo(key));
Assert.That(model?.FileUploader?.UploadUrl, Is.EqualTo("/Gallery/UploadImage"));
}

[TestCase(DeviceType.Desktop, ViewMode.Default, GalleryOrder.None)]
[TestCase(DeviceType.Mobile, ViewMode.Presentation, GalleryOrder.UploadedAsc)]
[TestCase(DeviceType.Tablet, ViewMode.Slideshow, GalleryOrder.NameAsc)]
public async Task GalleryController_Index_SingleGalleryMode(DeviceType deviceType, ViewMode? mode, GalleryOrder order)
{
_deviceDetector.ParseDeviceType(Arg.Any<string>()).Returns(deviceType);
_config.GetOrDefault("Settings", "Single_Gallery_Mode", Arg.Any<bool>()).Returns(true);

var controller = new GalleryController(_env, _config, _database, _file, _secretKey, _deviceDetector, _image, _logger, _localizer);
controller.ControllerContext.HttpContext = MockData.MockHttpContext();

ViewResult actual = (ViewResult)await controller.Index("default", "password", mode, order);
Assert.That(actual, Is.TypeOf<ViewResult>());
Assert.That(actual?.Model, Is.Not.Null);

PhotoGallery model = (PhotoGallery)actual.Model;
Assert.That(model?.GalleryId, Is.EqualTo("default"));
Assert.That(model.GalleryPath, Is.EqualTo($"/uploads/default"));
Assert.That(model.ThumbnailsPath, Is.EqualTo($"/thumbnails"));
Assert.That(model.ViewMode, Is.EqualTo(mode));
Assert.That(model?.FileUploader?.GalleryId, Is.EqualTo("default"));
Assert.That(model?.FileUploader?.SecretKey, Is.EqualTo("password"));
Assert.That(model?.FileUploader?.UploadUrl, Is.EqualTo("/Gallery/UploadImage"));
}

[TestCase(true, 1, null)]
[TestCase(true, 3, "Bob")]
[TestCase(false, 1, "")]
[TestCase(false, 3, "Unit Testing")]
public async Task GalleryController_UploadImage(bool requiresReview, int fileCount, string? uploadedBy)
{
_config.GetOrDefault("Settings", "Require_Review", Arg.Any<bool>()).Returns(requiresReview);

var files = new FormFileCollection();
for (var i = 0; i < fileCount; i++)
{
files.Add(new FormFile(null, 0, 0, "TestFile_001", $"{Guid.NewGuid()}.jpg"));
}

var controller = new GalleryController(_env, _config, _database, _file, _secretKey, _deviceDetector, _image, _logger, _localizer);
controller.ControllerContext.HttpContext = MockData.MockHttpContext(
form: new Dictionary<string, StringValues>
{
{ "Id", "default" },
{ "SecretKey", "password" },
{ "UploadedBy", uploadedBy }
},
files: files);

JsonResult actual = (JsonResult)await controller.UploadImage();
Assert.That(actual, Is.TypeOf<JsonResult>());
Assert.That(actual?.Value, Is.Not.Null);
Assert.That(JsonResponseHelper.GetPropertyValue(actual.Value, "success", false), Is.True);
Assert.That(JsonResponseHelper.GetPropertyValue(actual.Value, "uploaded", 0), Is.EqualTo(files.Count));
Assert.That(JsonResponseHelper.GetPropertyValue(actual.Value, "uploadedBy", string.Empty), Is.EqualTo(!string.IsNullOrWhiteSpace(uploadedBy) ? uploadedBy : string.Empty));
Assert.That(JsonResponseHelper.GetPropertyValue(actual.Value, "errors", new List<string>()).Count, Is.EqualTo(0));
}

[TestCase(null)]
[TestCase("")]
public async Task GalleryController_UploadImage_InvalidGallery(string? id)
{
var controller = new GalleryController(_env, _config, _database, _file, _secretKey, _deviceDetector, _image, _logger, _localizer);
controller.ControllerContext.HttpContext = MockData.MockHttpContext(form: new Dictionary<string, StringValues>
{
{ "Id", id }
});

JsonResult actual = (JsonResult)await controller.UploadImage();
Assert.That(actual, Is.TypeOf<JsonResult>());
Assert.That(actual?.Value, Is.Not.Null);
Assert.That(JsonResponseHelper.GetPropertyValue(actual.Value, "success", false), Is.False);
Assert.That(JsonResponseHelper.GetPropertyValue(actual.Value, "uploaded", 0), Is.EqualTo(0));
Assert.That(JsonResponseHelper.GetPropertyValue(actual.Value, "errors", new List<string>()).Count, Is.GreaterThan(0));
}

[TestCase(null)]
[TestCase("")]
public async Task GalleryController_UploadImage_InvalidSecretKey(string? key)
{
var controller = new GalleryController(_env, _config, _database, _file, _secretKey, _deviceDetector, _image, _logger, _localizer);
controller.ControllerContext.HttpContext = MockData.MockHttpContext(form: new Dictionary<string, StringValues>
{
{ "Id", "default" },
{ "SecretKey", key }
});

JsonResult actual = (JsonResult)await controller.UploadImage();
Assert.That(actual, Is.TypeOf<JsonResult>());
Assert.That(actual?.Value, Is.Not.Null);
Assert.That(JsonResponseHelper.GetPropertyValue(actual.Value, "success", false), Is.False);
Assert.That(JsonResponseHelper.GetPropertyValue(actual.Value, "uploaded", 0), Is.EqualTo(0));
Assert.That(JsonResponseHelper.GetPropertyValue(actual.Value, "errors", new List<string>()).Count, Is.GreaterThan(0));
}

[TestCase()]
public async Task GalleryController_UploadImage_MissingGallery()
{
var controller = new GalleryController(_env, _config, _database, _file, _secretKey, _deviceDetector, _image, _logger, _localizer);
controller.ControllerContext.HttpContext = MockData.MockHttpContext(form: new Dictionary<string, StringValues>
{
{ "Id", Guid.NewGuid().ToString() }
});

JsonResult actual = (JsonResult)await controller.UploadImage();
Assert.That(actual, Is.TypeOf<JsonResult>());
Assert.That(actual?.Value, Is.Not.Null);
Assert.That(JsonResponseHelper.GetPropertyValue(actual.Value, "success", false), Is.False);
Assert.That(JsonResponseHelper.GetPropertyValue(actual.Value, "uploaded", 0), Is.EqualTo(0));
Assert.That(JsonResponseHelper.GetPropertyValue(actual.Value, "errors", new List<string>()).Count, Is.GreaterThan(0));
}

[TestCase()]
public async Task GalleryController_UploadImage_NoFiles()
{
var controller = new GalleryController(_env, _config, _database, _file, _secretKey, _deviceDetector, _image, _logger, _localizer);
controller.ControllerContext.HttpContext = MockData.MockHttpContext(form: new Dictionary<string, StringValues>
{
{ "Id", "default" },
{ "SecretKey", "password" }
});

JsonResult actual = (JsonResult)await controller.UploadImage();
Assert.That(actual, Is.TypeOf<JsonResult>());
Assert.That(actual?.Value, Is.Not.Null);
Assert.That(JsonResponseHelper.GetPropertyValue(actual.Value, "success", false), Is.False);
Assert.That(JsonResponseHelper.GetPropertyValue(actual.Value, "uploaded", 0), Is.EqualTo(0));
Assert.That(JsonResponseHelper.GetPropertyValue(actual.Value, "errors", new List<string>()).Count, Is.GreaterThan(0));
}

[TestCase()]
public async Task GalleryController_UploadImage_FileTooBig()
{
var controller = new GalleryController(_env, _config, _database, _file, _secretKey, _deviceDetector, _image, _logger, _localizer);
controller.ControllerContext.HttpContext = MockData.MockHttpContext(
form: new Dictionary<string, StringValues>
{
{ "Id", "default" },
{ "SecretKey", "password" }
},
files: new FormFileCollection() {
new FormFile(null, 0, int.MaxValue, "TestFile_001", $"{Guid.NewGuid()}.jpg")
});

JsonResult actual = (JsonResult)await controller.UploadImage();
Assert.That(actual, Is.TypeOf<JsonResult>());
Assert.That(actual?.Value, Is.Not.Null);
Assert.That(JsonResponseHelper.GetPropertyValue(actual.Value, "success", false), Is.False);
Assert.That(JsonResponseHelper.GetPropertyValue(actual.Value, "uploaded", 0), Is.EqualTo(0));
Assert.That(JsonResponseHelper.GetPropertyValue(actual.Value, "errors", new List<string>()).Count, Is.GreaterThan(0));
}

[TestCase()]
public async Task GalleryController_UploadImage_InvalidFileType()
{
var controller = new GalleryController(_env, _config, _database, _file, _secretKey, _deviceDetector, _image, _logger, _localizer);
controller.ControllerContext.HttpContext = MockData.MockHttpContext(
form: new Dictionary<string, StringValues>
{
{ "Id", "default" },
{ "SecretKey", "password" }
},
files: new FormFileCollection() {
new FormFile(null, 0, int.MaxValue, "TestFile_001", $"{Guid.NewGuid()}.blaa")
});

JsonResult actual = (JsonResult)await controller.UploadImage();
Assert.That(actual, Is.TypeOf<JsonResult>());
Assert.That(actual?.Value, Is.Not.Null);
Assert.That(JsonResponseHelper.GetPropertyValue(actual.Value, "success", false), Is.False);
Assert.That(JsonResponseHelper.GetPropertyValue(actual.Value, "uploaded", 0), Is.EqualTo(0));
Assert.That(JsonResponseHelper.GetPropertyValue(actual.Value, "errors", new List<string>()).Count, Is.GreaterThan(0));
}
}
}
Loading

0 comments on commit 13fe2ec

Please sign in to comment.