using Microsoft.EntityFrameworkCore; using Novelly.Api.Activity; using Novelly.Api.Beats; using Novelly.Api.Chapters; using Novelly.Api.Novels; using Novelly.Api.Users; namespace Novelly.Api.Tests; [TestFixture] public class ActivityTests : ServiceTestFixture { private Guid AsNewUser(GlobalRole globalRole) { var user = new NovellyUser { Id = Guid.NewGuid(), UserName = $"{Guid.NewGuid()}@novelly.test", Email = $"{Guid.NewGuid()}@novelly.test", DisplayName = "Test User", GlobalRole = globalRole }; Db.Context.Users.Add(user); Db.Context.SaveChanges(); UserContext.UserId = user.Id; UserContext.GlobalRole = globalRole; return user.Id; } [Test] public async Task Writing_prose_records_the_word_delta_for_that_day() { var novel = await Novels.CreateAsync(new CreateNovelRequest("The Salt Road")); var chapter = await Chapters.CreateAsync(novel.Id, new CreateChapterRequest("Landfall")); await Chapters.UpdateAsync(chapter!.Id, new UpdateChapterRequest(Prose: "one two three four five")); var calendar = await Activity.GetForNovelAsync(novel.Id, days: 7); Assert.That(calendar.Days.Sum(d => d.Words), Is.EqualTo(5)); } [Test] public async Task Editing_a_beat_records_one_edit_not_two() { var novel = await Novels.CreateAsync(new CreateNovelRequest("The Salt Road")); var chapter = await Chapters.CreateAsync(novel.Id, new CreateChapterRequest("Landfall")); var beat = await Beats.CreateAsync(chapter!.Id, new CreateBeatRequest("She finds the map")); await Beats.UpdateAsync(beat!.Id, new UpdateBeatRequest(WhatHappened: "She finds the map under the floorboards.")); var beatEvents = await Db.Context.ActivityEvents.CountAsync(e => e.EntityKind == ActivityEntityKind.Beat); var chapterEvents = await Db.Context.ActivityEvents.CountAsync(e => e.EntityKind == ActivityEntityKind.Chapter); Assert.Multiple(() => { Assert.That(beatEvents, Is.EqualTo(2)); Assert.That(chapterEvents, Is.EqualTo(1)); }); } [Test] public async Task Deleting_a_chapter_records_a_negative_word_delta() { var novel = await Novels.CreateAsync(new CreateNovelRequest("The Salt Road")); var chapter = await Chapters.CreateAsync(novel.Id, new CreateChapterRequest("Landfall", Prose: "one two three")); await Chapters.DeleteAsync(chapter!.Id); var calendar = await Activity.GetForNovelAsync(novel.Id, days: 7); Assert.That(calendar.Days.Sum(d => d.Words), Is.EqualTo(0)); } [Test] public async Task The_calendar_groups_multiple_edits_into_one_day() { var novel = await Novels.CreateAsync(new CreateNovelRequest("The Salt Road")); var chapter = await Chapters.CreateAsync(novel.Id, new CreateChapterRequest("Landfall")); await Chapters.UpdateAsync(chapter!.Id, new UpdateChapterRequest(Summary: "First pass")); await Chapters.UpdateAsync(chapter.Id, new UpdateChapterRequest(Summary: "Second pass")); var calendar = await Activity.GetForNovelAsync(novel.Id, days: 7); Assert.Multiple(() => { Assert.That(calendar.Days, Has.Count.EqualTo(1)); Assert.That(calendar.Days[0].Edits, Is.EqualTo(4)); }); } [Test] public async Task The_calendar_omits_days_with_no_activity() { var novel = await Novels.CreateAsync(new CreateNovelRequest("The Salt Road")); var calendar = await Activity.GetForNovelAsync(novel.Id, days: 7); Assert.That(calendar.Days, Has.Count.EqualTo(1)); } [Test] public async Task The_calendar_excludes_novels_the_user_cannot_read() { var novel = await Novels.CreateAsync(new CreateNovelRequest("Someone Else's Novel")); AsNewUser(GlobalRole.Writer); await Novels.CreateAsync(new CreateNovelRequest("My Own Novel")); var calendar = await Activity.GetForCurrentUserAsync(days: 7); Assert.That(calendar.TotalEdits, Is.EqualTo(1)); } [Test] public async Task Deleting_a_novel_removes_its_activity_events() { var novel = await Novels.CreateAsync(new CreateNovelRequest("The Salt Road")); await Chapters.CreateAsync(novel.Id, new CreateChapterRequest("Landfall")); await Novels.DeleteAsync(novel.Id); Assert.That(await Db.Context.ActivityEvents.CountAsync(e => e.NovelId == novel.Id), Is.EqualTo(0)); } }