using Microsoft.EntityFrameworkCore;
using TaskLedger.Api.Domain.Entities;
using TaskLedger.Api.Infrastructure.Data;
using TaskLedger.Api.Services;
using TaskEntity = TaskLedger.Api.Domain.Entities.Task;
namespace TaskLedger.Api.Tests.Services;
///
/// Unit tests for TaskService.
///
public class TaskServiceTests
{
///
/// Creates an in-memory database context for testing.
///
private AppDbContext CreateInMemoryDbContext()
{
var options = new DbContextOptionsBuilder()
.UseInMemoryDatabase(databaseName: Guid.NewGuid().ToString())
.Options;
return new AppDbContext(options);
}
[Fact]
public async System.Threading.Tasks.Task CreateTaskAsync_WithValidTitle_ShouldCreateTask()
{
// Arrange
using var context = CreateInMemoryDbContext();
var service = new TaskService(context);
var title = "Test Task";
var description = "Test Description";
// Act
var result = await service.CreateTaskAsync(title, description);
// Assert
Assert.NotNull(result);
Assert.Equal(title, result.Title);
Assert.Equal(description, result.Description);
Assert.False(result.IsCompleted);
Assert.True(result.CreatedUtc <= DateTime.UtcNow);
Assert.True(result.CreatedUtc > DateTime.UtcNow.AddMinutes(-1));
Assert.True(result.Id > 0);
// Verify it was saved to database
var savedTask = await context.Tasks.FindAsync(result.Id);
Assert.NotNull(savedTask);
Assert.Equal(title, savedTask!.Title);
}
[Fact]
public async System.Threading.Tasks.Task CreateTaskAsync_WithNullTitle_ShouldThrowArgumentException()
{
// Arrange
using var context = CreateInMemoryDbContext();
var service = new TaskService(context);
// Act & Assert
await Assert.ThrowsAsync(() => service.CreateTaskAsync(null!, "Description"));
}
[Fact]
public async System.Threading.Tasks.Task CreateTaskAsync_WithEmptyTitle_ShouldThrowArgumentException()
{
// Arrange
using var context = CreateInMemoryDbContext();
var service = new TaskService(context);
// Act & Assert
await Assert.ThrowsAsync(() => service.CreateTaskAsync(string.Empty, "Description"));
}
[Fact]
public async System.Threading.Tasks.Task CreateTaskAsync_WithWhitespaceTitle_ShouldThrowArgumentException()
{
// Arrange
using var context = CreateInMemoryDbContext();
var service = new TaskService(context);
// Act & Assert
await Assert.ThrowsAsync(() => service.CreateTaskAsync(" ", "Description"));
}
[Fact]
public async System.Threading.Tasks.Task CreateTaskAsync_WithNullDescription_ShouldCreateTask()
{
// Arrange
using var context = CreateInMemoryDbContext();
var service = new TaskService(context);
var title = "Test Task";
// Act
var result = await service.CreateTaskAsync(title, null);
// Assert
Assert.NotNull(result);
Assert.Equal(title, result.Title);
Assert.Null(result.Description);
}
[Fact]
public async System.Threading.Tasks.Task CreateTaskAsync_ShouldSetCreatedUtcToUtcNow()
{
// Arrange
using var context = CreateInMemoryDbContext();
var service = new TaskService(context);
var beforeCreation = DateTime.UtcNow;
// Act
var result = await service.CreateTaskAsync("Test Task", "Description");
var afterCreation = DateTime.UtcNow;
// Assert
Assert.True(result.CreatedUtc >= beforeCreation);
Assert.True(result.CreatedUtc <= afterCreation);
Assert.Equal(DateTimeKind.Utc, result.CreatedUtc.Kind);
}
[Fact]
public async System.Threading.Tasks.Task CreateTaskAsync_ShouldTrimTitleAndDescription()
{
// Arrange
using var context = CreateInMemoryDbContext();
var service = new TaskService(context);
var title = " Test Task ";
var description = " Test Description ";
// Act
var result = await service.CreateTaskAsync(title, description);
// Assert
Assert.Equal("Test Task", result.Title);
Assert.Equal("Test Description", result.Description);
}
[Fact]
public async System.Threading.Tasks.Task GetAllTasksAsync_WithNoTasks_ShouldReturnEmptyList()
{
// Arrange
using var context = CreateInMemoryDbContext();
var service = new TaskService(context);
// Act
var result = await service.GetAllTasksAsync();
// Assert
Assert.NotNull(result);
Assert.Empty(result);
}
[Fact]
public async System.Threading.Tasks.Task GetAllTasksAsync_WithMultipleTasks_ShouldReturnAllTasksOrderedByCreatedUtc()
{
// Arrange
using var context = CreateInMemoryDbContext();
var service = new TaskService(context);
var task1 = await service.CreateTaskAsync("First Task", "First");
await System.Threading.Tasks.Task.Delay(10); // Small delay to ensure different CreatedUtc
var task2 = await service.CreateTaskAsync("Second Task", "Second");
await System.Threading.Tasks.Task.Delay(10);
var task3 = await service.CreateTaskAsync("Third Task", "Third");
// Act
var result = (await service.GetAllTasksAsync()).ToList();
// Assert
Assert.Equal(3, result.Count);
Assert.Equal("First Task", result[0].Title);
Assert.Equal("Second Task", result[1].Title);
Assert.Equal("Third Task", result[2].Title);
Assert.True(result[0].CreatedUtc <= result[1].CreatedUtc);
Assert.True(result[1].CreatedUtc <= result[2].CreatedUtc);
}
}