Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
using Moq;
using PhoneBook.Application.Contacts.AddContact;
using PhoneBook.Application.Interfaces;
using PhoneBook.Domain.Entities;
using PhoneBook.Domain.Validation;
using PhoneBook.Domain.Validation.Errors;

namespace PhoneBook.Tests.ApplicationTests;

public class AddContactTests
{
[Fact]
public async Task HandleAsync_ShouldReturnFailure_WhenRepositoryReturnsNull()
{
// Arrange
var repoMock = new Mock<IContactRepository>();
repoMock
.Setup(r => r.AddAsync(It.IsAny<Contact>()))
.ReturnsAsync((Result<Contact>?)null);

var handler = new AddContactHandler(repoMock.Object);
var request = new AddContactRequest("Billy", "Smith", "bs@mail.com", "555-0147");

// Act
var result = await handler.HandleAsync(request);

// Assert
Assert.True(result.IsFailure);
Assert.Contains(ContactRepositoryErrors.AddResponseNull, result.Errors);

}

[Fact]
public async Task HandleAsync_ShouldReturnFailure_WhenRespositoryReturnsFailure()
{
// Arrange
Error[] errors = { new("TestError", "Test error description") };

var repoMock = new Mock<IContactRepository>();
repoMock
.Setup(r => r.AddAsync(It.IsAny<Contact>()))
.ReturnsAsync(Result<Contact>.Failure(errors));

var handler = new AddContactHandler(repoMock.Object);
var request = new AddContactRequest("Billy", "Smith", "bs@mail.com", "555-0147");

// Act
var result = await handler.HandleAsync(request);

// Assert
Assert.True(result.IsFailure);
Assert.Contains(errors, result.Errors.ToArray());
}

[Fact]
public async Task HandleAsync_ShouldReturnSuccess_WhenRepositoryReturnsSuccess()
{
// Arrange
var repoMock = new Mock<IContactRepository>();
repoMock
.Setup(r => r.AddAsync(It.IsAny<Contact>()))
.ReturnsAsync(Result<Contact>.Success(new Contact()));

var handler = new AddContactHandler(repoMock.Object);
var request = new AddContactRequest("Billy", "Smith", "bs@mail.com", "555-0147");

// Act
var result = await handler.HandleAsync(request);

// Assert
Assert.True(result.IsSuccess);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
using Moq;
using PhoneBook.Application.Contacts.DeleteContact;
using PhoneBook.Application.Contacts.DTOs;
using PhoneBook.Application.Interfaces;
using PhoneBook.Domain.Entities;
using PhoneBook.Domain.Validation;
using PhoneBook.Domain.Validation.Errors;

namespace PhoneBook.Tests.ApplicationTests;

public class DeleteContactHandlerTests
{
[Fact]
public async Task HandleAsync_ShouldReturnFailure_WhenRepositoryReturnsNull()
{
// Arrange
var repoMock = new Mock<IContactRepository>();
repoMock
.Setup(r => r.DeleteAsync(It.IsAny<Contact>()))
.ReturnsAsync((Result<Contact>?)null);

var handler = new DeleteContactHandler(repoMock.Object);
var request = new ContactResponse(1, "Billy", "Smith", "555-0147", "bs@mail.com", 1);

// Act
var result = await handler.HandleAsync(request);

// Assert
Assert.True(result.IsFailure);
Assert.Contains(ContactRepositoryErrors.DeleteResponseNull, result.Errors);
}

[Fact]
public async Task HandleAsync_ShouldReturnFailure_WhenRepositoryResturnsFailure()
{
// Arrange
Error[] errors = { new("TestError", "Test error description") };

var repoMock = new Mock<IContactRepository>();
repoMock
.Setup(r => r.DeleteAsync(It.IsAny<Contact>()))
.ReturnsAsync((Result<Contact>.Failure(errors)));

var handler = new DeleteContactHandler(repoMock.Object);
var request = new ContactResponse(1, "Billy", "Smith", "555-0147", "bs@mail.com", 1);

// Act
var result = await handler.HandleAsync(request);

// Assert
Assert.True(result.IsFailure);
Assert.Contains(errors, result.Errors.ToArray());
}

[Fact]
public async Task HandleAsync_ShouldReturnSuccessWhenRepositoryReturnsSuccess()
{
// Arrange
var repoMock = new Mock<IContactRepository>();
repoMock
.Setup(r => r.DeleteAsync(It.IsAny<Contact>()))
.ReturnsAsync((Result<Contact>.Success(new Contact())));

var handler = new DeleteContactHandler(repoMock.Object);
var request = new ContactResponse(1, "Billy", "Smith", "555-0147", "bs@mail.com", 1);

// Act
var result = await handler.HandleAsync(request);

// Assert
Assert.True(result.IsSuccess);
}
}
29 changes: 29 additions & 0 deletions phonebook.jzhartman/PhoneBook.Tests/PhoneBook.Tests.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="coverlet.collector" Version="6.0.4" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
<PackageReference Include="Moq" Version="4.20.72" />
<PackageReference Include="xunit" Version="2.9.3" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\PhoneBook\PhoneBook.csproj" />
</ItemGroup>

<ItemGroup>
<Using Include="Xunit" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using PhoneBook.Application.Interfaces;
using PhoneBook.Domain.Entities;
using PhoneBook.Domain.Validation;
using PhoneBook.Domain.Validation.Errors;

namespace PhoneBook.Application.Categories.AddCategory;

public class AddCategoryHandler
{
private readonly ICategoryRepository _repo;

public AddCategoryHandler(ICategoryRepository repo)
{
_repo = repo;
}

public async Task<Result> HandleAsync(AddCategoryRequest category)
{
var result = await _repo.AddAsync(
new ContactCategory
{
Name = category.Name
});

if (result is null)
return Result.Failure(CategoryRepositoryErrors.AddResponseNull);

if (result.IsFailure)
return Result.Failure(result.Errors);

return Result.Success();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
namespace PhoneBook.Application.Categories.AddCategory;

public record AddCategoryRequest(string Name);
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
namespace PhoneBook.Application.Categories.DTOs;

public record CategoryResponse(int Id, string Name);
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
using PhoneBook.Application.Categories.DTOs;
using PhoneBook.Application.Interfaces;
using PhoneBook.Domain.Entities;
using PhoneBook.Domain.Validation;
using PhoneBook.Domain.Validation.Errors;

namespace PhoneBook.Application.Categories.DeleteCategory;

internal class DeleteCategoryByIdHandler
{
private readonly ICategoryRepository _categoryRepo;
private readonly IContactRepository _contactRepo;

public DeleteCategoryByIdHandler(ICategoryRepository categoryRepo, IContactRepository contactRepo)
{
_categoryRepo = categoryRepo;
_contactRepo = contactRepo;
}

public async Task<Result> HandleAsync(CategoryResponse categoryResponse)
{
if (categoryResponse.Name.ToUpper() == "UNCATEGORIZED")
return Result.Failure(CategoryRepositoryErrors.DeleteDefault);

var category = new ContactCategory
{
Id = categoryResponse.Id,
Name = categoryResponse.Name
};

var deleteCategoryResponse = await _categoryRepo.DeleteAsync(category);

if (deleteCategoryResponse is null)
return Result.Failure(CategoryRepositoryErrors.DeleteResponseNull);

if (deleteCategoryResponse.IsFailure)
return Result.Failure(deleteCategoryResponse.Errors);

return Result.Success();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
using PhoneBook.Application.Categories.DTOs;
using PhoneBook.Application.Interfaces;
using PhoneBook.Domain.Entities;
using PhoneBook.Domain.Validation;
using PhoneBook.Domain.Validation.Errors;

namespace PhoneBook.Application.Categories.GetAllCategories;

internal class GetAllCategoriesHandler
{
private readonly ICategoryRepository _repo;

public GetAllCategoriesHandler(ICategoryRepository repo)
{
_repo = repo;
}

public async Task<Result<List<CategoryResponse>>> HandleAsync()
{
var result = await _repo.GetAllAsync();

if (result is null || result.Value is null || result.Value.Count < 1)
return Result<List<CategoryResponse>>.Failure(new Error[] { CategoryRepositoryErrors.CategoryNotFound });

if (result.IsFailure)
return Result<List<CategoryResponse>>.Failure(result.Errors);

return Result<List<CategoryResponse>>.Success(MapToCategoryResponse(result.Value));
}

private List<CategoryResponse> MapToCategoryResponse(List<ContactCategory> categories)
{
var categoryResponseList = new List<CategoryResponse>();

foreach (var category in categories)
{
categoryResponseList.Add(new CategoryResponse
(
category.Id,
category.Name
));
}

return categoryResponseList;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using PhoneBook.Application.Categories.DTOs;
using PhoneBook.Application.Interfaces;
using PhoneBook.Domain.Validation;
using PhoneBook.Domain.Validation.Errors;

namespace PhoneBook.Application.Categories.GetCategoryById;

public class GetCategoryByIdHandler
{
private readonly ICategoryRepository _repo;

public GetCategoryByIdHandler(ICategoryRepository repo)
{
_repo = repo;
}

public async Task<Result<CategoryResponse>> HandleAsync(int categoryId)
{
var result = await _repo.GetByIdAsync(categoryId);

if (result is null || result.Value is null)
return Result<CategoryResponse>.Failure(CategoryRepositoryErrors.CategoryNotFound);

if (result.IsFailure)
return Result<CategoryResponse>.Failure(result.Errors);

return Result<CategoryResponse>.Success(new CategoryResponse
(
result.Value.Id,
result.Value.Name
));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using PhoneBook.Application.Interfaces;
using PhoneBook.Domain.Entities;
using PhoneBook.Domain.Validation;
using PhoneBook.Domain.Validation.Errors;

namespace PhoneBook.Application.Categories.UpdateCategory;

public class UpdateCategoryNameHandler
{
private readonly ICategoryRepository _repo;

public UpdateCategoryNameHandler(ICategoryRepository repo)
{
_repo = repo;
}

public async Task<Result> HandleAsync(UpdateCategoryNameRequest category)
{
if (category.OriginalName.ToUpper() == "UNCATEGORIZED")
return Result.Failure(CategoryRepositoryErrors.UpdateDefault);

var result = await _repo.UpdateAsync(new ContactCategory { Id = category.Id, Name = category.NewName });

if (result is null)
return Result.Failure(CategoryRepositoryErrors.UpdateResponseNull);

if (result.IsFailure)
return Result.Failure(result.Errors);

return Result.Success();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
namespace PhoneBook.Application.Categories.UpdateCategory;

public record UpdateCategoryNameRequest(int Id, string OriginalName, string NewName);
Loading