diff options
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/Jellyfin.Controller.Tests/Library/VersionResumeDataTests.cs | 30 | ||||
| -rw-r--r-- | tests/Jellyfin.Server.Implementations.Tests/Item/AlternateVersionQueryTranslationTests.cs | 36 |
2 files changed, 37 insertions, 29 deletions
diff --git a/tests/Jellyfin.Controller.Tests/Library/VersionResumeDataTests.cs b/tests/Jellyfin.Controller.Tests/Library/VersionResumeDataTests.cs index 5b0f003019..8642ab07f8 100644 --- a/tests/Jellyfin.Controller.Tests/Library/VersionResumeDataTests.cs +++ b/tests/Jellyfin.Controller.Tests/Library/VersionResumeDataTests.cs @@ -9,36 +9,40 @@ namespace Jellyfin.Controller.Tests.Library; public class VersionResumeDataTests { [Fact] - public void ApplyTo_OverridesResumeFieldsAndPercentage() + public void ApplyTo_PropagatesCompletionButNotPosition() { var lastPlayed = new DateTime(2026, 1, 2, 0, 0, 0, DateTimeKind.Utc); var resume = new VersionResumeData( - new UserItemData { Key = "version", PlaybackPositionTicks = 25, Played = true, LastPlayedDate = lastPlayed }, - RunTimeTicks: 100); + new UserItemData { Key = "version", PlaybackPositionTicks = 25, Played = true, LastPlayedDate = lastPlayed }); var dto = new UserItemDataDto { Key = "primary", PlaybackPositionTicks = 1, Played = false, PlayedPercentage = 1 }; resume.ApplyTo(dto); - Assert.Equal(25, dto.PlaybackPositionTicks); + // Completion state propagates to the primary... Assert.True(dto.Played); Assert.Equal(lastPlayed, dto.LastPlayedDate); - // The percentage is based on the resume version's own runtime, not the primary's. - Assert.NotNull(dto.PlayedPercentage); - Assert.Equal(25.0, dto.PlayedPercentage.Value, 5); + // ...but the in-progress resume position stays on the version that owns it. + Assert.Equal(1, dto.PlaybackPositionTicks); + Assert.Equal(1.0, dto.PlayedPercentage); } [Fact] - public void ApplyTo_WithoutRuntime_LeavesPercentageUntouched() + public void ApplyTo_DoesNotUnsetExistingPlayedOrRegressLastPlayed() { - var resume = new VersionResumeData(new UserItemData { Key = "version", PlaybackPositionTicks = 25 }, null); - var dto = new UserItemDataDto { Key = "primary", PlayedPercentage = 42 }; + var primaryLastPlayed = new DateTime(2026, 1, 5, 0, 0, 0, DateTimeKind.Utc); + var versionLastPlayed = new DateTime(2026, 1, 2, 0, 0, 0, DateTimeKind.Utc); + var resume = new VersionResumeData( + new UserItemData { Key = "version", Played = false, LastPlayedDate = versionLastPlayed }); + + var dto = new UserItemDataDto { Key = "primary", Played = true, LastPlayedDate = primaryLastPlayed }; resume.ApplyTo(dto); - Assert.Equal(25, dto.PlaybackPositionTicks); - Assert.NotNull(dto.PlayedPercentage); - Assert.Equal(42.0, dto.PlayedPercentage.Value, 5); + // A not-yet-completed version must not clear the primary's own completion, and the more recent + // LastPlayedDate is kept. + Assert.True(dto.Played); + Assert.Equal(primaryLastPlayed, dto.LastPlayedDate); } } diff --git a/tests/Jellyfin.Server.Implementations.Tests/Item/AlternateVersionQueryTranslationTests.cs b/tests/Jellyfin.Server.Implementations.Tests/Item/AlternateVersionQueryTranslationTests.cs index 823ff566a7..1f0de153a0 100644 --- a/tests/Jellyfin.Server.Implementations.Tests/Item/AlternateVersionQueryTranslationTests.cs +++ b/tests/Jellyfin.Server.Implementations.Tests/Item/AlternateVersionQueryTranslationTests.cs @@ -37,39 +37,43 @@ public sealed class AlternateVersionQueryTranslationTests : IDisposable } [Fact] - public void ResumeFilter_VersionProgress_SurfacesPrimary() + public void ResumeFilter_VersionProgress_SurfacesPlayedVersion() { - Guid userId, primaryId, otherId; + Guid userId, primaryId, versionId, otherId; using (var ctx = CreateDbContext()) { - (userId, primaryId, otherId) = Seed(ctx); + (userId, primaryId, versionId, otherId) = Seed(ctx); } using (var ctx = CreateDbContext()) { - // Mirrors the resumable filter in BaseItemRepository.TranslateQuery: progress on any - // version coalesces onto the primary's id. var inProgress = ctx.UserData .Where(ud => ud.UserId == userId && ud.PlaybackPositionTicks > 0); - var resumableMovieIds = inProgress - .Join(ctx.BaseItems, ud => ud.ItemId, bi => bi.Id, (ud, bi) => bi.PrimaryVersionId ?? bi.Id); // Scope to the seeded items; EnsureCreated also seeds a placeholder row. - var seededIds = new[] { primaryId, otherId }; + var seededIds = new[] { primaryId, versionId, otherId }; + // Mirrors the resumable=true filter in BaseItemRepository.TranslateQuery. + var inProgressIds = inProgress.Select(ud => ud.ItemId); var resumable = ctx.BaseItems - .Where(e => seededIds.Contains(e.Id) && e.PrimaryVersionId == null) - .Where(e => resumableMovieIds.Contains(e.Id)) + .Where(e => seededIds.Contains(e.Id)) + .Where(e => inProgressIds.Contains(e.Id)) + .Where(e => !ctx.BaseItems + .Where(s => s.Id != e.Id && (s.PrimaryVersionId ?? s.Id) == (e.PrimaryVersionId ?? e.Id)) + .Any(s => inProgress.Where(su => su.ItemId == s.Id).Max(su => su.LastPlayedDate) + > inProgress.Where(eu => eu.ItemId == e.Id).Max(eu => eu.LastPlayedDate))) .Select(e => e.Id) .ToList(); - Assert.Equal([primaryId], resumable); + Assert.Equal([versionId], resumable); - // The inverse (not-resumable) direction must exclude the primary as well. + // The not-resumable direction keeps primaries only. + var resumableMovieIds = inProgress + .Join(ctx.BaseItems, ud => ud.ItemId, bi => bi.Id, (ud, bi) => bi.PrimaryVersionId ?? bi.Id); var notResumable = ctx.BaseItems .Where(e => seededIds.Contains(e.Id) && e.PrimaryVersionId == null) - .Where(e => resumableMovieIds.Contains(e.Id) == false) + .Where(e => !resumableMovieIds.Contains(e.Id)) .Select(e => e.Id) .ToList(); @@ -84,7 +88,7 @@ public sealed class AlternateVersionQueryTranslationTests : IDisposable using (var ctx = CreateDbContext()) { - (userId, primaryId, otherId) = Seed(ctx); + (userId, primaryId, _, otherId) = Seed(ctx); } using (var ctx = CreateDbContext()) @@ -106,7 +110,7 @@ public sealed class AlternateVersionQueryTranslationTests : IDisposable } } - private static (Guid UserId, Guid PrimaryId, Guid OtherId) Seed(JellyfinDbContext ctx) + private static (Guid UserId, Guid PrimaryId, Guid VersionId, Guid OtherId) Seed(JellyfinDbContext ctx) { var user = new User("test", "auth-provider", "reset-provider"); ctx.Users.Add(user); @@ -129,7 +133,7 @@ public sealed class AlternateVersionQueryTranslationTests : IDisposable }); ctx.SaveChanges(); - return (user.Id, primary.Id, other.Id); + return (user.Id, primary.Id, version.Id, other.Id); } private JellyfinDbContext CreateDbContext() |
