using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging.Abstractions; using TaskTracker.Api.Controllers; using TaskTracker.Core.DTOs; using TaskTracker.Core.Entities; using TaskTracker.Infrastructure.Data; using TaskTracker.Infrastructure.Repositories; using Xunit; namespace TaskTracker.Tests; public class TasksControllerDeadlineTests { [Fact] public async Task Create_copies_due_at_including_offset_to_created_task() { await using var db = CreateDbContext(); var controller = CreateController(db); var dueAt = DateTimeOffset.Parse("2026-08-14T11:00:00-04:00"); var result = await controller.Create(new CreateTaskRequest { Title = "deadline", DueAt = dueAt }); var created = Assert.IsType(result); var response = Assert.IsType>(created.Value); Assert.Equal(dueAt, response.Data!.DueAt); } [Fact] public async Task Update_changes_due_at_when_value_is_supplied() { await using var db = CreateDbContext(); var task = await AddTaskAsync(db, DateTimeOffset.Parse("2026-08-14T11:00:00-04:00")); var controller = CreateController(db); var dueAt = DateTimeOffset.Parse("2026-08-15T09:30:00+02:00"); var result = await controller.Update(task.Id, new UpdateTaskRequest { DueAt = dueAt }); var ok = Assert.IsType(result); var response = Assert.IsType>(ok.Value); Assert.Equal(dueAt, response.Data!.DueAt); } [Fact] public async Task Update_clears_due_at_only_when_clear_due_at_is_true() { await using var db = CreateDbContext(); var task = await AddTaskAsync(db, DateTimeOffset.Parse("2026-08-14T11:00:00-04:00")); var controller = CreateController(db); var result = await controller.Update(task.Id, new UpdateTaskRequest { ClearDueAt = true }); var ok = Assert.IsType(result); var response = Assert.IsType>(ok.Value); Assert.Null(response.Data!.DueAt); } [Fact] public async Task Update_with_omitted_due_at_preserves_existing_due_at() { await using var db = CreateDbContext(); var dueAt = DateTimeOffset.Parse("2026-08-14T11:00:00-04:00"); var task = await AddTaskAsync(db, dueAt); var controller = CreateController(db); var result = await controller.Update(task.Id, new UpdateTaskRequest { Title = "renamed" }); var ok = Assert.IsType(result); var response = Assert.IsType>(ok.Value); Assert.Equal(dueAt, response.Data!.DueAt); } private static TaskTrackerDbContext CreateDbContext() { var options = new DbContextOptionsBuilder() .UseInMemoryDatabase(Guid.NewGuid().ToString()) .Options; return new TaskTrackerDbContext(options); } private static TasksController CreateController(TaskTrackerDbContext db) => new(new TaskRepository(db), NullLogger.Instance); private static async Task AddTaskAsync(TaskTrackerDbContext db, DateTimeOffset dueAt) { var task = new WorkTask { Title = "existing", DueAt = dueAt }; db.Tasks.Add(task); await db.SaveChangesAsync(); return task; } }