mirror of https://github.com/ErsatzTV/ErsatzTV.git
10 changed files with 216 additions and 6 deletions
@ -0,0 +1,88 @@ |
|||||||
|
using ErsatzTV.Core.Domain; |
||||||
|
using ErsatzTV.Core.Scheduling; |
||||||
|
using FluentAssertions; |
||||||
|
using NUnit.Framework; |
||||||
|
|
||||||
|
namespace ErsatzTV.Core.Tests.Scheduling; |
||||||
|
|
||||||
|
[TestFixture] |
||||||
|
public class SeasonEpisodeContentTests |
||||||
|
{ |
||||||
|
[Test] |
||||||
|
public void Episodes_Should_Sort_By_EpisodeNumber() |
||||||
|
{ |
||||||
|
List<MediaItem> contents = Episodes(10); |
||||||
|
var state = new CollectionEnumeratorState(); |
||||||
|
|
||||||
|
var chronologicalContent = new SeasonEpisodeMediaCollectionEnumerator(contents, state); |
||||||
|
|
||||||
|
for (var i = 1; i <= 10; i++) |
||||||
|
{ |
||||||
|
chronologicalContent.Current.IsSome.Should().BeTrue(); |
||||||
|
chronologicalContent.Current.Map(x => x.Id).IfNone(-1).Should().Be(i); |
||||||
|
chronologicalContent.MoveNext(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
[Test] |
||||||
|
public void State_Index_Should_Increment() |
||||||
|
{ |
||||||
|
List<MediaItem> contents = Episodes(10); |
||||||
|
var state = new CollectionEnumeratorState(); |
||||||
|
|
||||||
|
var chronologicalContent = new SeasonEpisodeMediaCollectionEnumerator(contents, state); |
||||||
|
|
||||||
|
for (var i = 0; i < 10; i++) |
||||||
|
{ |
||||||
|
chronologicalContent.State.Index.Should().Be(i % 10); |
||||||
|
chronologicalContent.MoveNext(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
[Test] |
||||||
|
public void State_Should_Impact_Iterator_Start() |
||||||
|
{ |
||||||
|
List<MediaItem> contents = Episodes(10); |
||||||
|
var state = new CollectionEnumeratorState { Index = 5 }; |
||||||
|
|
||||||
|
var chronologicalContent = new SeasonEpisodeMediaCollectionEnumerator(contents, state); |
||||||
|
|
||||||
|
for (var i = 6; i <= 10; i++) |
||||||
|
{ |
||||||
|
chronologicalContent.Current.IsSome.Should().BeTrue(); |
||||||
|
chronologicalContent.Current.Map(x => x.Id).IfNone(-1).Should().Be(i); |
||||||
|
chronologicalContent.State.Index.Should().Be(i - 1); |
||||||
|
chronologicalContent.MoveNext(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
[Test] |
||||||
|
[Timeout(1000)] |
||||||
|
public void State_Should_Reset_When_Invalid() |
||||||
|
{ |
||||||
|
List<MediaItem> contents = Episodes(10); |
||||||
|
var state = new CollectionEnumeratorState { Index = 10 }; |
||||||
|
|
||||||
|
var chronologicalContent = new SeasonEpisodeMediaCollectionEnumerator(contents, state); |
||||||
|
|
||||||
|
chronologicalContent.State.Index.Should().Be(0); |
||||||
|
chronologicalContent.State.Seed.Should().Be(0); |
||||||
|
} |
||||||
|
|
||||||
|
private static List<MediaItem> Episodes(int count) => |
||||||
|
Range(1, count).Map( |
||||||
|
i => (MediaItem)new Episode |
||||||
|
{ |
||||||
|
Id = i, |
||||||
|
EpisodeMetadata = new List<EpisodeMetadata> |
||||||
|
{ |
||||||
|
new() |
||||||
|
{ |
||||||
|
ReleaseDate = new DateTime(2020, 1, 20 - i), |
||||||
|
EpisodeNumber = i |
||||||
|
} |
||||||
|
} |
||||||
|
}) |
||||||
|
.Reverse() |
||||||
|
.ToList(); |
||||||
|
} |
@ -0,0 +1,38 @@ |
|||||||
|
using ErsatzTV.Core.Domain; |
||||||
|
using ErsatzTV.Core.Interfaces.Scheduling; |
||||||
|
|
||||||
|
namespace ErsatzTV.Core.Scheduling; |
||||||
|
|
||||||
|
public sealed class SeasonEpisodeMediaCollectionEnumerator : IMediaCollectionEnumerator |
||||||
|
{ |
||||||
|
private readonly IList<MediaItem> _sortedMediaItems; |
||||||
|
|
||||||
|
public SeasonEpisodeMediaCollectionEnumerator( |
||||||
|
IEnumerable<MediaItem> mediaItems, |
||||||
|
CollectionEnumeratorState state) |
||||||
|
{ |
||||||
|
_sortedMediaItems = mediaItems.OrderBy(identity, new SeasonEpisodeMediaComparer()).ToList(); |
||||||
|
|
||||||
|
State = new CollectionEnumeratorState { Seed = state.Seed }; |
||||||
|
|
||||||
|
if (state.Index >= _sortedMediaItems.Count) |
||||||
|
{ |
||||||
|
state.Index = 0; |
||||||
|
state.Seed = 0; |
||||||
|
} |
||||||
|
|
||||||
|
while (State.Index < state.Index) |
||||||
|
{ |
||||||
|
MoveNext(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public CollectionEnumeratorState State { get; } |
||||||
|
|
||||||
|
public Option<MediaItem> Current => _sortedMediaItems.Any() ? _sortedMediaItems[State.Index] : None; |
||||||
|
|
||||||
|
public void MoveNext() => State.Index = (State.Index + 1) % _sortedMediaItems.Count; |
||||||
|
|
||||||
|
public Option<MediaItem> Peek(int offset) => |
||||||
|
_sortedMediaItems.Any() ? _sortedMediaItems[(State.Index + offset) % _sortedMediaItems.Count] : None; |
||||||
|
} |
@ -0,0 +1,54 @@ |
|||||||
|
using ErsatzTV.Core.Domain; |
||||||
|
|
||||||
|
namespace ErsatzTV.Core.Scheduling; |
||||||
|
|
||||||
|
internal class SeasonEpisodeMediaComparer : IComparer<MediaItem> |
||||||
|
{ |
||||||
|
public int Compare(MediaItem x, MediaItem y) |
||||||
|
{ |
||||||
|
if (x == null || y == null) |
||||||
|
{ |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
int season1 = x switch |
||||||
|
{ |
||||||
|
Episode e => e.Season?.SeasonNumber ?? int.MaxValue, |
||||||
|
_ => int.MaxValue |
||||||
|
}; |
||||||
|
|
||||||
|
int season2 = y switch |
||||||
|
{ |
||||||
|
Episode e => e.Season?.SeasonNumber ?? int.MaxValue, |
||||||
|
_ => int.MaxValue |
||||||
|
}; |
||||||
|
|
||||||
|
if (season1 != season2) |
||||||
|
{ |
||||||
|
return season1.CompareTo(season2); |
||||||
|
} |
||||||
|
|
||||||
|
int episode1 = x switch |
||||||
|
{ |
||||||
|
Episode e => e.EpisodeMetadata.HeadOrNone().Match( |
||||||
|
em => em.EpisodeNumber, |
||||||
|
() => int.MaxValue), |
||||||
|
_ => int.MaxValue |
||||||
|
}; |
||||||
|
|
||||||
|
int episode2 = y switch |
||||||
|
{ |
||||||
|
Episode e => e.EpisodeMetadata.HeadOrNone().Match( |
||||||
|
em => em.EpisodeNumber, |
||||||
|
() => int.MaxValue), |
||||||
|
_ => int.MaxValue |
||||||
|
}; |
||||||
|
|
||||||
|
if (episode1 != episode2) |
||||||
|
{ |
||||||
|
return episode1.CompareTo(episode2); |
||||||
|
} |
||||||
|
|
||||||
|
return x.Id.CompareTo(y.Id); |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue