diff --git a/src/MiniSkeletonAPI.Presentation/LocalDatabase.db-shm b/src/MiniSkeletonAPI.Presentation/LocalDatabase.db-shm new file mode 100644 index 0000000..7cc364f Binary files /dev/null and b/src/MiniSkeletonAPI.Presentation/LocalDatabase.db-shm differ diff --git a/src/MiniSkeletonAPI.Presentation/LocalDatabase.db-wal b/src/MiniSkeletonAPI.Presentation/LocalDatabase.db-wal new file mode 100644 index 0000000..132f01a Binary files /dev/null and b/src/MiniSkeletonAPI.Presentation/LocalDatabase.db-wal differ diff --git a/tests/Application.UnitTests/Application.UnitTests.csproj b/tests/Application.UnitTests/Application.UnitTests.csproj new file mode 100644 index 0000000..581c183 --- /dev/null +++ b/tests/Application.UnitTests/Application.UnitTests.csproj @@ -0,0 +1,30 @@ + + + + net8.0 + enable + enable + + false + true + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/Application.UnitTests/Common/Behaviours/RequestLoggerTests.cs b/tests/Application.UnitTests/Common/Behaviours/RequestLoggerTests.cs new file mode 100644 index 0000000..c641f7e --- /dev/null +++ b/tests/Application.UnitTests/Common/Behaviours/RequestLoggerTests.cs @@ -0,0 +1,45 @@ +using MiniSkeletonAPI.Application.Common.Behaviours; +using MiniSkeletonAPI.Application.Common.Interfaces; +using MiniSkeletonAPI.Application.TodoItems.Commands.CreateTodoItem; +using Microsoft.Extensions.Logging; +using Moq; +using NUnit.Framework; + +namespace Application.UnitTests.Common.Behaviours; + +public class RequestLoggerTests +{ + private Mock> _logger = null!; + private Mock _user = null!; + private Mock _identityService = null!; + + [SetUp] + public void Setup() + { + _logger = new Mock>(); + _user = new Mock(); + _identityService = new Mock(); + } + + [Test] + public async Task ShouldCallGetUserNameAsyncOnceIfAuthenticated() + { + _user.Setup(x => x.Id).Returns(Guid.NewGuid().ToString()); + + var requestLogger = new LoggingBehaviour(_logger.Object, _user.Object, _identityService.Object); + + await requestLogger.Process(new CreateTodoItemCommand { ListId = new Guid(), Title = "title" }, new CancellationToken()); + + _identityService.Verify(i => i.GetUserNameAsync(It.IsAny()), Times.Once); + } + + [Test] + public async Task ShouldNotCallGetUserNameAsyncOnceIfUnauthenticated() + { + var requestLogger = new LoggingBehaviour(_logger.Object, _user.Object, _identityService.Object); + + await requestLogger.Process(new CreateTodoItemCommand { ListId = new Guid(), Title = "title" }, new CancellationToken()); + + _identityService.Verify(i => i.GetUserNameAsync(It.IsAny()), Times.Never); + } +} diff --git a/tests/Application.UnitTests/Common/Exceptions/ValidationExceptionTests.cs b/tests/Application.UnitTests/Common/Exceptions/ValidationExceptionTests.cs new file mode 100644 index 0000000..ace0090 --- /dev/null +++ b/tests/Application.UnitTests/Common/Exceptions/ValidationExceptionTests.cs @@ -0,0 +1,55 @@ +using MiniSkeletonAPI.Application.Common.Exceptions; +using FluentAssertions; +using FluentValidation.Results; +using NUnit.Framework; + +namespace Application.UnitTests.Common.Exceptions; + +public class ValidationExceptionTests +{ + [Test] + public void DefaultConstructorCreatesAnEmptyErrorDictionary() + { + var actual = new ValidationException().Errors; + + actual.Keys.Should().BeEquivalentTo(Array.Empty()); + } + + [Test] + public void SingleValidationFailureCreatesASingleElementErrorDictionary() + { + var failures = new List + { + new ValidationFailure("Password", "must contain at least 8 characters"), + }; + + var actual = new ValidationException(failures).Errors; + + actual.Keys.Should().BeEquivalentTo(new string[] { "Password" }); + actual["Password"].Should().BeEquivalentTo(new string[] { "must contain at least 8 characters" }); + } + + [Test] + public void MulitpleValidationFailureForMultiplePropertiesCreatesAMultipleElementErrorDictionaryEachWithMultipleValues() + { + var failures = new List + { + new ValidationFailure("Password", "must contain at least 8 characters"), + new ValidationFailure("Password", "must contain a digit"), + new ValidationFailure("Password", "must contain upper case letter"), + new ValidationFailure("Password", "must contain lower case letter"), + }; + + var actual = new ValidationException(failures).Errors; + + actual.Keys.Should().BeEquivalentTo(new string[] { "Password" }); + + actual["Password"].Should().BeEquivalentTo(new string[] + { + "must contain lower case letter", + "must contain upper case letter", + "must contain at least 8 characters", + "must contain a digit", + }); + } +} diff --git a/tests/Application.UnitTests/Common/Mappings/MappingTests.cs b/tests/Application.UnitTests/Common/Mappings/MappingTests.cs new file mode 100644 index 0000000..36e0400 --- /dev/null +++ b/tests/Application.UnitTests/Common/Mappings/MappingTests.cs @@ -0,0 +1,53 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using AutoMapper; +using MiniSkeletonAPI.Application.Common.Interfaces; +using MiniSkeletonAPI.Application.Common.Models; +using MiniSkeletonAPI.Application.TodoItems.Queries.GetTodoItemsWithPagination; +using MiniSkeletonAPI.Application.TodoLists.Queries.GetTodos; +using MiniSkeletonAPI.Domain.Entities; +using NUnit.Framework; + +namespace Application.UnitTests.Common.Mappings; + +public class MappingTests +{ + private readonly IConfigurationProvider _configuration; + private readonly IMapper _mapper; + + public MappingTests() + { + _configuration = new MapperConfiguration(config => + config.AddMaps(Assembly.GetAssembly(typeof(IApplicationDbContext)))); + + _mapper = _configuration.CreateMapper(); + } + + [Test] + public void ShouldHaveValidConfiguration() + { + _configuration.AssertConfigurationIsValid(); + } + + [Test] + [TestCase(typeof(TodoList), typeof(TodoListDto))] + [TestCase(typeof(TodoItem), typeof(TodoItemDto))] + [TestCase(typeof(TodoList), typeof(LookupDto))] + [TestCase(typeof(TodoItem), typeof(LookupDto))] + [TestCase(typeof(TodoItem), typeof(TodoItemBriefDto))] + public void ShouldSupportMappingFromSourceToDestination(Type source, Type destination) + { + var instance = GetInstanceOf(source); + + _mapper.Map(instance, source, destination); + } + + private object GetInstanceOf(Type type) + { + if (type.GetConstructor(Type.EmptyTypes) != null) + return Activator.CreateInstance(type)!; + + // Type without parameterless constructor + return RuntimeHelpers.GetUninitializedObject(type); + } +} diff --git a/tests/Application.UnitTests/UnitTest1.cs b/tests/Application.UnitTests/UnitTest1.cs new file mode 100644 index 0000000..f582c5f --- /dev/null +++ b/tests/Application.UnitTests/UnitTest1.cs @@ -0,0 +1,16 @@ +namespace Application.UnitTests +{ + public class Tests + { + [SetUp] + public void Setup() + { + } + + [Test] + public void Test1() + { + Assert.Pass(); + } + } +} \ No newline at end of file