Merge p11-w1-description-schema into dev (P11 11.G: release Description field, migration authored)

This commit is contained in:
daniel-c-harvey
2026-06-16 00:38:13 -04:00
17 changed files with 463 additions and 4 deletions
+76
View File
@@ -161,6 +161,82 @@ public class MediumWritePathTests
Assert.That(dto.ReleaseType, Is.Null);
}
// 11.G — Description round-trips through both converter directions verbatim (no medium dance,
// unlike ReleaseType): entity → DTO preserves the prose, and DTO → entity carries it back.
[Test]
public void Convert_Description_RoundTripsBothDirections()
{
const string prose = "A late-night set\nrecorded at the Vault.";
var entity = new ReleaseEntity
{
Title = "Live at the Vault", Artist = "Artist A",
Medium = ReleaseMedium.Session, Description = prose,
};
var dto = TrackConverter.Convert(entity);
Assert.That(dto.Description, Is.EqualTo(prose), "entity → DTO preserves Description");
var back = TrackConverter.Convert(dto);
Assert.That(back.Description, Is.EqualTo(prose), "DTO → entity preserves Description");
}
// 11.G — a null Description round-trips as null in both directions (existing rows migrate as NULL).
[Test]
public void Convert_NullDescription_RoundTripsAsNull()
{
var entity = new ReleaseEntity { Title = "Studio Album", Artist = "Artist C", Description = null };
var dto = TrackConverter.Convert(entity);
Assert.That(dto.Description, Is.Null);
var back = TrackConverter.Convert(dto);
Assert.That(back.Description, Is.Null);
}
// 11.G — Description rides the release-cardinal write channel onto the persisted release row,
// exactly as Genre does. FindOrCreateRelease is the upload-path projection point.
[Test]
public async Task FindOrCreateRelease_NewRelease_PersistsDescription()
{
const string prose = "Three cuts pressed for the summer.";
var manager = CreateManager(CreateRepository());
var data = ReleaseData("Studio Album", "Artist C", ReleaseMedium.Cut);
data.Description = prose;
var result = await manager.FindOrCreateRelease("Studio Album", "Artist C", data);
Assert.That(result.Success, Is.True);
Assert.That(result.Value!.Description, Is.EqualTo(prose));
var stored = await CreateRepository().GetReleaseByIdAsync(result.Value.Id);
Assert.That(stored!.Description, Is.EqualTo(prose));
}
// 11.C — editing a track's linked release sets the Description on the persisted release row,
// mirroring the PUT api/track/meta apply (release.Description = request.Description).
[Test]
public async Task Update_SetsReleaseDescription_PersistsDescription()
{
const string prose = "Now with a proper blurb.";
var repo = CreateRepository();
ITrackService manager = CreateManager(repo);
var release = new ReleaseEntity { Title = "Studio Album", Artist = "Artist C", Medium = ReleaseMedium.Cut };
var track = new TrackEntity { EntryKey = "ek-1", TrackName = "Track", Release = release };
_context.Tracks.Add(track);
await _context.SaveChangesAsync();
var loaded = (await manager.GetById(track.Id)).Value!;
loaded.Release!.Description = prose;
var result = await manager.Update(loaded);
Assert.That(result.Success, Is.True);
var stored = await CreateRepository().GetReleaseByIdAsync(release.Id);
Assert.That(stored!.Description, Is.EqualTo(prose));
}
// 9.5.C — releaseId filter returns only the tracks of the given release. Built on the repository
// directly to assert the WHERE release_id predicate in isolation.
[Test]