using System.Collections.Generic; using System.IO; using System.IO.Abstractions; using System.IO.Abstractions.TestingHelpers; using System.Linq; using System.Threading.Tasks; using API.Entities; using API.Entities.Enums; using API.Helpers; using API.Services; using API.Services.Tasks.Metadata; using API.SignalR; using API.Tests.Helpers; using Microsoft.Extensions.Logging; using NSubstitute; using Xunit; namespace API.Tests.Services; public class WordCountAnalysisTests : AbstractDbTest { private readonly IReaderService _readerService; private readonly string _testDirectory = Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/BookService"); private const long WordCount = 37417; private const long MinHoursToRead = 1; private const long AvgHoursToRead = 2; private const long MaxHoursToRead = 4; public WordCountAnalysisTests() : base() { _readerService = new ReaderService(_unitOfWork, Substitute.For>(), Substitute.For(), Substitute.For(), new DirectoryService(Substitute.For>(), new MockFileSystem())); } protected override async Task ResetDb() { _context.Series.RemoveRange(_context.Series.ToList()); await _context.SaveChangesAsync(); } [Fact] public async Task ReadingTimeShouldBeNonZero() { await ResetDb(); var series = EntityFactory.CreateSeries("Test Series"); series.Format = MangaFormat.Epub; var chapter = EntityFactory.CreateChapter("", false, new List() { EntityFactory.CreateMangaFile( Path.Join(_testDirectory, "The Golden Harpoon; Or, Lost Among the Floes A Story of the Whaling Grounds.epub"), MangaFormat.Epub, 0) }); _context.Library.Add(new Library() { Name = "Test", Type = LibraryType.Book, Series = new List() {series} }); series.Volumes = new List() { EntityFactory.CreateVolume("0", new List() {chapter}) }; await _context.SaveChangesAsync(); var cacheService = new CacheHelper(new FileService()); var service = new WordCountAnalyzerService(Substitute.For>(), _unitOfWork, Substitute.For(), cacheService, _readerService); await service.ScanSeries(1, 1); Assert.Equal(WordCount, series.WordCount); Assert.Equal(MinHoursToRead, series.MinHoursToRead); Assert.Equal(AvgHoursToRead, series.AvgHoursToRead); Assert.Equal(MaxHoursToRead, series.MaxHoursToRead); // Validate the Chapter gets updated correctly var volume = series.Volumes.First(); Assert.Equal(WordCount, volume.WordCount); Assert.Equal(MinHoursToRead, volume.MinHoursToRead); Assert.Equal(AvgHoursToRead, volume.AvgHoursToRead); Assert.Equal(MaxHoursToRead, volume.MaxHoursToRead); Assert.Equal(WordCount, chapter.WordCount); Assert.Equal(MinHoursToRead, chapter.MinHoursToRead); Assert.Equal(AvgHoursToRead, chapter.AvgHoursToRead); Assert.Equal(MaxHoursToRead, chapter.MaxHoursToRead); } [Fact] public async Task ReadingTimeShouldIncreaseWhenNewBookAdded() { await ResetDb(); var series = EntityFactory.CreateSeries("Test Series"); series.Format = MangaFormat.Epub; var chapter = EntityFactory.CreateChapter("", false, new List() { EntityFactory.CreateMangaFile( Path.Join(_testDirectory, "The Golden Harpoon; Or, Lost Among the Floes A Story of the Whaling Grounds.epub"), MangaFormat.Epub, 0) }); _context.Library.Add(new Library() { Name = "Test", Type = LibraryType.Book, Series = new List() {series} }); series.Volumes = new List() { EntityFactory.CreateVolume("0", new List() {chapter}) }; await _context.SaveChangesAsync(); var cacheService = new CacheHelper(new FileService()); var service = new WordCountAnalyzerService(Substitute.For>(), _unitOfWork, Substitute.For(), cacheService, _readerService); await service.ScanSeries(1, 1); var chapter2 = EntityFactory.CreateChapter("2", false, new List() { EntityFactory.CreateMangaFile( Path.Join(_testDirectory, "The Golden Harpoon; Or, Lost Among the Floes A Story of the Whaling Grounds.epub"), MangaFormat.Epub, 0) }); series.Volumes.Add(EntityFactory.CreateVolume("1", new List() {chapter2})); series.Volumes.First().Chapters.Add(chapter2); await _unitOfWork.CommitAsync(); await service.ScanSeries(1, 1); Assert.Equal(WordCount * 2L, series.WordCount); Assert.Equal(MinHoursToRead * 2, series.MinHoursToRead); Assert.Equal(AvgHoursToRead * 2, series.AvgHoursToRead); Assert.Equal((MaxHoursToRead * 2) - 1, series.MaxHoursToRead); // This is just a rounding issue var firstVolume = series.Volumes.ElementAt(0); Assert.Equal(WordCount, firstVolume.WordCount); Assert.Equal(MinHoursToRead, firstVolume.MinHoursToRead); Assert.Equal(AvgHoursToRead, firstVolume.AvgHoursToRead); Assert.Equal(MaxHoursToRead, firstVolume.MaxHoursToRead); var secondVolume = series.Volumes.ElementAt(1); Assert.Equal(WordCount, secondVolume.WordCount); Assert.Equal(MinHoursToRead, secondVolume.MinHoursToRead); Assert.Equal(AvgHoursToRead, secondVolume.AvgHoursToRead); Assert.Equal(MaxHoursToRead, secondVolume.MaxHoursToRead); // Validate original chapter doesn't change Assert.Equal(WordCount, chapter.WordCount); Assert.Equal(MinHoursToRead, chapter.MinHoursToRead); Assert.Equal(AvgHoursToRead, chapter.AvgHoursToRead); Assert.Equal(MaxHoursToRead, chapter.MaxHoursToRead); // Validate new chapter gets updated Assert.Equal(WordCount, chapter2.WordCount); Assert.Equal(MinHoursToRead, chapter2.MinHoursToRead); Assert.Equal(AvgHoursToRead, chapter2.AvgHoursToRead); Assert.Equal(MaxHoursToRead, chapter2.MaxHoursToRead); } }