refactor(domain): introduce UserFactory and WorkplaceFactory for reconstitution
Consistent with ReservationFactory — moves Reconstitute out of the entity into a dedicated factory class, and makes the reconstitution constructor internal to restrict direct instantiation to within the domain assembly. Adds unit tests for all three factories. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -10,10 +10,7 @@ public class User : Entity
|
|||||||
public bool IsApproved { get; private set; }
|
public bool IsApproved { get; private set; }
|
||||||
public bool IsAdmin { get; private set; }
|
public bool IsAdmin { get; private set; }
|
||||||
|
|
||||||
public static User Reconstitute(Guid id, string email, string name, string passwordHash, bool isApproved, bool isAdmin) =>
|
internal User(Guid id, string email, string name, string passwordHash, bool isApproved, bool isAdmin) : base(id)
|
||||||
new(id, email, name, passwordHash, isApproved, isAdmin);
|
|
||||||
|
|
||||||
private User(Guid id, string email, string name, string passwordHash, bool isApproved, bool isAdmin) : base(id)
|
|
||||||
{
|
{
|
||||||
Email = email;
|
Email = email;
|
||||||
Name = name;
|
Name = name;
|
||||||
|
|||||||
7
src/backend/src/Randall.Domain/Users/UserFactory.cs
Normal file
7
src/backend/src/Randall.Domain/Users/UserFactory.cs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
namespace Randall.Domain.Users;
|
||||||
|
|
||||||
|
public static class UserFactory
|
||||||
|
{
|
||||||
|
public static User Reconstitute(Guid id, string email, string name, string passwordHash, bool isApproved, bool isAdmin) =>
|
||||||
|
new(id, email, name, passwordHash, isApproved, isAdmin);
|
||||||
|
}
|
||||||
@@ -8,10 +8,7 @@ public class Workplace : Entity
|
|||||||
public string Location { get; private set; }
|
public string Location { get; private set; }
|
||||||
public bool IsActive { get; private set; }
|
public bool IsActive { get; private set; }
|
||||||
|
|
||||||
public static Workplace Reconstitute(Guid id, string name, string location, bool isActive) =>
|
internal Workplace(Guid id, string name, string location, bool isActive) : base(id)
|
||||||
new(id, name, location, isActive);
|
|
||||||
|
|
||||||
private Workplace(Guid id, string name, string location, bool isActive) : base(id)
|
|
||||||
{
|
{
|
||||||
Name = name;
|
Name = name;
|
||||||
Location = location;
|
Location = location;
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
namespace Randall.Domain.Workplaces;
|
||||||
|
|
||||||
|
public static class WorkplaceFactory
|
||||||
|
{
|
||||||
|
public static Workplace Reconstitute(Guid id, string name, string location, bool isActive) =>
|
||||||
|
new(id, name, location, isActive);
|
||||||
|
}
|
||||||
@@ -6,7 +6,7 @@ namespace Randall.Infrastructure.Persistence.Mappers;
|
|||||||
public static class UserMapper
|
public static class UserMapper
|
||||||
{
|
{
|
||||||
public static User ToDomain(UserRecord record) =>
|
public static User ToDomain(UserRecord record) =>
|
||||||
User.Reconstitute(
|
UserFactory.Reconstitute(
|
||||||
record.Id,
|
record.Id,
|
||||||
record.Email,
|
record.Email,
|
||||||
record.Name,
|
record.Name,
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ namespace Randall.Infrastructure.Persistence.Mappers;
|
|||||||
public static class WorkplaceMapper
|
public static class WorkplaceMapper
|
||||||
{
|
{
|
||||||
public static Workplace ToDomain(WorkplaceRecord record) =>
|
public static Workplace ToDomain(WorkplaceRecord record) =>
|
||||||
Workplace.Reconstitute(
|
WorkplaceFactory.Reconstitute(
|
||||||
record.Id,
|
record.Id,
|
||||||
record.Name,
|
record.Name,
|
||||||
record.Location,
|
record.Location,
|
||||||
|
|||||||
@@ -0,0 +1,61 @@
|
|||||||
|
using Randall.Domain.Reservations;
|
||||||
|
|
||||||
|
namespace Randall.Domain.UnitTests.Reservations;
|
||||||
|
|
||||||
|
public class ReservationFactoryTests
|
||||||
|
{
|
||||||
|
private static readonly Guid Id = Guid.NewGuid();
|
||||||
|
private static readonly Guid WorkplaceId = Guid.NewGuid();
|
||||||
|
private const string Email = "jane@company.com";
|
||||||
|
private const string Name = "Jane Smith";
|
||||||
|
private static readonly DateOnly Date = new(2026, 6, 1);
|
||||||
|
private static readonly DateTime CreatedAt = new(2026, 5, 1, 12, 0, 0, DateTimeKind.Utc);
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Reconstitute_MapsAllFieldsExactly()
|
||||||
|
{
|
||||||
|
var reservation = ReservationFactory.Reconstitute(Id, WorkplaceId, Email, Name, Date, ReservationStatus.Active, CreatedAt);
|
||||||
|
|
||||||
|
Assert.Equal(Id, reservation.Id);
|
||||||
|
Assert.Equal(WorkplaceId, reservation.WorkplaceId);
|
||||||
|
Assert.Equal(Email, reservation.EmployeeEmail);
|
||||||
|
Assert.Equal(Name, reservation.EmployeeName);
|
||||||
|
Assert.Equal(Date, reservation.Date);
|
||||||
|
Assert.Equal(ReservationStatus.Active, reservation.Status);
|
||||||
|
Assert.Equal(CreatedAt, reservation.CreatedAt);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Reconstitute_PreservesProvidedId()
|
||||||
|
{
|
||||||
|
var reservation = ReservationFactory.Reconstitute(Id, WorkplaceId, Email, Name, Date, ReservationStatus.Active, CreatedAt);
|
||||||
|
|
||||||
|
Assert.Equal(Id, reservation.Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Reconstitute_CanRestoreActiveReservation()
|
||||||
|
{
|
||||||
|
var reservation = ReservationFactory.Reconstitute(Id, WorkplaceId, Email, Name, Date, ReservationStatus.Active, CreatedAt);
|
||||||
|
|
||||||
|
Assert.Equal(ReservationStatus.Active, reservation.Status);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Reconstitute_CanRestoreCancelledReservation()
|
||||||
|
{
|
||||||
|
var reservation = ReservationFactory.Reconstitute(Id, WorkplaceId, Email, Name, Date, ReservationStatus.Cancelled, CreatedAt);
|
||||||
|
|
||||||
|
Assert.Equal(ReservationStatus.Cancelled, reservation.Status);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Reconstitute_CanRestorePastReservation()
|
||||||
|
{
|
||||||
|
var pastDate = new DateOnly(2020, 1, 1);
|
||||||
|
|
||||||
|
var reservation = ReservationFactory.Reconstitute(Id, WorkplaceId, Email, Name, pastDate, ReservationStatus.Active, CreatedAt);
|
||||||
|
|
||||||
|
Assert.Equal(pastDate, reservation.Date);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
using Randall.Domain.Users;
|
||||||
|
|
||||||
|
namespace Randall.Domain.UnitTests.Users;
|
||||||
|
|
||||||
|
public class UserFactoryTests
|
||||||
|
{
|
||||||
|
private static readonly Guid Id = Guid.NewGuid();
|
||||||
|
private const string Email = "jane@company.com";
|
||||||
|
private const string Name = "Jane Smith";
|
||||||
|
private const string PasswordHash = "hashed-password";
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Reconstitute_MapsAllFieldsExactly()
|
||||||
|
{
|
||||||
|
var user = UserFactory.Reconstitute(Id, Email, Name, PasswordHash, isApproved: true, isAdmin: false);
|
||||||
|
|
||||||
|
Assert.Equal(Id, user.Id);
|
||||||
|
Assert.Equal(Email, user.Email);
|
||||||
|
Assert.Equal(Name, user.Name);
|
||||||
|
Assert.Equal(PasswordHash, user.PasswordHash);
|
||||||
|
Assert.True(user.IsApproved);
|
||||||
|
Assert.False(user.IsAdmin);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Reconstitute_PreservesProvidedId()
|
||||||
|
{
|
||||||
|
var user = UserFactory.Reconstitute(Id, Email, Name, PasswordHash, isApproved: false, isAdmin: false);
|
||||||
|
|
||||||
|
Assert.Equal(Id, user.Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Reconstitute_CanRestoreApprovedNonAdminUser()
|
||||||
|
{
|
||||||
|
var user = UserFactory.Reconstitute(Id, Email, Name, PasswordHash, isApproved: true, isAdmin: false);
|
||||||
|
|
||||||
|
Assert.True(user.IsApproved);
|
||||||
|
Assert.False(user.IsAdmin);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Reconstitute_CanRestoreUnapprovedUser()
|
||||||
|
{
|
||||||
|
var user = UserFactory.Reconstitute(Id, Email, Name, PasswordHash, isApproved: false, isAdmin: false);
|
||||||
|
|
||||||
|
Assert.False(user.IsApproved);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Reconstitute_CanRestoreAdminUser()
|
||||||
|
{
|
||||||
|
var user = UserFactory.Reconstitute(Id, Email, Name, PasswordHash, isApproved: true, isAdmin: true);
|
||||||
|
|
||||||
|
Assert.True(user.IsAdmin);
|
||||||
|
Assert.True(user.IsApproved);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
using Randall.Domain.Workplaces;
|
||||||
|
|
||||||
|
namespace Randall.Domain.UnitTests.Workplaces;
|
||||||
|
|
||||||
|
public class WorkplaceFactoryTests
|
||||||
|
{
|
||||||
|
private static readonly Guid Id = Guid.NewGuid();
|
||||||
|
private const string Name = "D13";
|
||||||
|
private const string Location = "Pod A";
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Reconstitute_MapsAllFieldsExactly()
|
||||||
|
{
|
||||||
|
var workplace = WorkplaceFactory.Reconstitute(Id, Name, Location, isActive: true);
|
||||||
|
|
||||||
|
Assert.Equal(Id, workplace.Id);
|
||||||
|
Assert.Equal(Name, workplace.Name);
|
||||||
|
Assert.Equal(Location, workplace.Location);
|
||||||
|
Assert.True(workplace.IsActive);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Reconstitute_PreservesProvidedId()
|
||||||
|
{
|
||||||
|
var workplace = WorkplaceFactory.Reconstitute(Id, Name, Location, isActive: true);
|
||||||
|
|
||||||
|
Assert.Equal(Id, workplace.Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Reconstitute_CanRestoreActiveWorkplace()
|
||||||
|
{
|
||||||
|
var workplace = WorkplaceFactory.Reconstitute(Id, Name, Location, isActive: true);
|
||||||
|
|
||||||
|
Assert.True(workplace.IsActive);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Reconstitute_CanRestoreInactiveWorkplace()
|
||||||
|
{
|
||||||
|
var workplace = WorkplaceFactory.Reconstitute(Id, Name, Location, isActive: false);
|
||||||
|
|
||||||
|
Assert.False(workplace.IsActive);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user