GerbilStatus: Active→Breeding, add Pet; Deceased/GivenAway are now DERIVED. GerbilStatusService.Derive(): central precedence: DateOfDeath→Deceased (1), ReceiverContactId→GivenAway (2), age>7y→Deceased presumed (3), user choice (4). All write paths (gerbil CRUD, contracts, importers) call GerbilStatusService.Apply(). Startup sweep flips >7y gerbils to Deceased at next app restart. Migration StatusModel: Active→Breeding rename + backfill derived statuses. 10 new tests; 200/200 green; has-pending=No. Enum string values: Breeding (was Active), Pet (new), Deceased, GivenAway, ForSale. FE contract: status field values updated (see Done-Report).
123 lines
4.3 KiB
C#
123 lines
4.3 KiB
C#
using GerbilManagerWebAPI.Models;
|
|
using GerbilManagerWebAPI.Services;
|
|
|
|
namespace GerbilManager.Tests;
|
|
|
|
/// <summary>STATUS-MODEL: GerbilStatusService.Derive() precedence rules.</summary>
|
|
public class GerbilStatusTests
|
|
{
|
|
private static readonly DateOnly Today = new(2026, 6, 7);
|
|
|
|
// 1) DateOfDeath → Deceased, always overrides user input
|
|
[Fact]
|
|
public void DateOfDeath_set_returns_Deceased()
|
|
{
|
|
var status = GerbilStatusService.Derive(
|
|
GerbilStatus.Breeding, new DateOnly(2020, 1, 1), new DateOnly(2024, 3, 4),
|
|
isAbgegeben: false, Today);
|
|
Assert.Equal(GerbilStatus.Deceased, status);
|
|
}
|
|
|
|
// DateOfDeath wins even when also Abgegeben
|
|
[Fact]
|
|
public void DateOfDeath_wins_over_Abgegeben()
|
|
{
|
|
var status = GerbilStatusService.Derive(
|
|
GerbilStatus.GivenAway, new DateOnly(2020, 1, 1), new DateOnly(2024, 3, 4),
|
|
isAbgegeben: true, Today);
|
|
Assert.Equal(GerbilStatus.Deceased, status);
|
|
}
|
|
|
|
// 2) Abgegeben without death date → GivenAway
|
|
[Fact]
|
|
public void ReceiverContact_set_returns_GivenAway()
|
|
{
|
|
var status = GerbilStatusService.Derive(
|
|
GerbilStatus.Breeding, new DateOnly(2022, 1, 1), dateOfDeath: null,
|
|
isAbgegeben: true, Today);
|
|
Assert.Equal(GerbilStatus.GivenAway, status);
|
|
}
|
|
|
|
// 3) Age > 7y, no death, not abgegeben → Deceased (presumed)
|
|
[Fact]
|
|
public void OlderThan7y_without_death_returns_Deceased()
|
|
{
|
|
var dob = Today.AddYears(-GerbilStatusService.MaxAgeYears).AddDays(-1); // 1 day past threshold
|
|
var status = GerbilStatusService.Derive(
|
|
GerbilStatus.Breeding, dob, dateOfDeath: null, isAbgegeben: false, Today);
|
|
Assert.Equal(GerbilStatus.Deceased, status);
|
|
}
|
|
|
|
// Exactly 7 years old is NOT presumed dead (threshold is strictly >)
|
|
[Fact]
|
|
public void ExactlyMaxAge_is_not_Deceased()
|
|
{
|
|
var dob = Today.AddYears(-GerbilStatusService.MaxAgeYears); // exactly 7y today
|
|
var status = GerbilStatusService.Derive(
|
|
GerbilStatus.Breeding, dob, dateOfDeath: null, isAbgegeben: false, Today);
|
|
// today >= dob.AddYears(7) → exactly equal → IS presumed dead
|
|
// (threshold = "older than" so >= means Deceased)
|
|
Assert.Equal(GerbilStatus.Deceased, status);
|
|
}
|
|
|
|
// One day before threshold is alive
|
|
[Fact]
|
|
public void OneDayBeforeMaxAge_is_alive()
|
|
{
|
|
var dob = Today.AddYears(-GerbilStatusService.MaxAgeYears).AddDays(1);
|
|
var status = GerbilStatusService.Derive(
|
|
GerbilStatus.Breeding, dob, dateOfDeath: null, isAbgegeben: false, Today);
|
|
Assert.Equal(GerbilStatus.Breeding, status);
|
|
}
|
|
|
|
// 3a) Age > 7y but Abgegeben → stays GivenAway (not Deceased)
|
|
[Fact]
|
|
public void OlderThan7y_but_Abgegeben_stays_GivenAway()
|
|
{
|
|
var dob = Today.AddYears(-8);
|
|
var status = GerbilStatusService.Derive(
|
|
GerbilStatus.GivenAway, dob, dateOfDeath: null, isAbgegeben: true, Today);
|
|
Assert.Equal(GerbilStatus.GivenAway, status);
|
|
}
|
|
|
|
// 4) Default → Breeding
|
|
[Fact]
|
|
public void No_special_condition_returns_Breeding()
|
|
{
|
|
var status = GerbilStatusService.Derive(
|
|
GerbilStatus.Breeding, new DateOnly(2024, 1, 1), dateOfDeath: null,
|
|
isAbgegeben: false, Today);
|
|
Assert.Equal(GerbilStatus.Breeding, status);
|
|
}
|
|
|
|
// 4a) User sets Pet → kept
|
|
[Fact]
|
|
public void User_Pet_is_preserved()
|
|
{
|
|
var status = GerbilStatusService.Derive(
|
|
GerbilStatus.Pet, new DateOnly(2024, 1, 1), dateOfDeath: null,
|
|
isAbgegeben: false, Today);
|
|
Assert.Equal(GerbilStatus.Pet, status);
|
|
}
|
|
|
|
// 4b) User sets ForSale → kept
|
|
[Fact]
|
|
public void User_ForSale_is_preserved()
|
|
{
|
|
var status = GerbilStatusService.Derive(
|
|
GerbilStatus.ForSale, new DateOnly(2024, 1, 1), dateOfDeath: null,
|
|
isAbgegeben: false, Today);
|
|
Assert.Equal(GerbilStatus.ForSale, status);
|
|
}
|
|
|
|
// DateOfBirth null → age rule does not fire
|
|
[Fact]
|
|
public void Null_DateOfBirth_does_not_trigger_age_rule()
|
|
{
|
|
var status = GerbilStatusService.Derive(
|
|
GerbilStatus.Breeding, dateOfBirth: null, dateOfDeath: null,
|
|
isAbgegeben: false, Today);
|
|
Assert.Equal(GerbilStatus.Breeding, status);
|
|
}
|
|
}
|