diff --git a/src/NzbDrone.Core.Test/DecisionEngineTests/NotInQueueSpecificationFixture.cs b/src/NzbDrone.Core.Test/DecisionEngineTests/NotInQueueSpecificationFixture.cs new file mode 100644 index 000000000..e9e9fb959 --- /dev/null +++ b/src/NzbDrone.Core.Test/DecisionEngineTests/NotInQueueSpecificationFixture.cs @@ -0,0 +1,200 @@ +using System; +using System.Collections.Generic; +using FizzWare.NBuilder; +using FluentAssertions; +using NUnit.Framework; +using NzbDrone.Core.DecisionEngine.Specifications; +using NzbDrone.Core.Parser.Model; +using NzbDrone.Core.Qualities; +using NzbDrone.Core.Tv; +using NzbDrone.Core.Test.Framework; + +namespace NzbDrone.Core.Test.DecisionEngineTests +{ + [TestFixture] + public class NotInQueueSpecificationFixture : CoreTest + { + private Series _series; + private Episode _episode; + private RemoteEpisode _remoteEpisode; + + private Series _otherSeries; + private Episode _otherEpisode; + + [SetUp] + public void Setup() + { + _series = Builder.CreateNew().Build(); + + _episode = Builder.CreateNew() + .With(e => e.SeriesId = _series.Id) + .Build(); + + _otherSeries = Builder.CreateNew() + .With(s => s.Id = 2) + .Build(); + + _otherEpisode = Builder.CreateNew() + .With(e => e.SeriesId = _otherSeries.Id) + .With(e => e.Id = 2) + .With(e => e.SeasonNumber = 2) + .With(e => e.EpisodeNumber = 2) + .Build(); + + _remoteEpisode = Builder.CreateNew() + .With(r => r.Series = _series) + .With(r => r.Episodes = new List { _episode }) + .With(r => r.ParsedEpisodeInfo = new ParsedEpisodeInfo { Quality = new QualityModel(Quality.DVD)}) + .Build(); + } + + [Test] + public void should_return_false_when_queue_is_empty() + { + Subject.IsInQueue(_remoteEpisode, new List()).Should().BeFalse(); + } + + [Test] + public void should_return_false_when_series_doesnt_match() + { + var remoteEpisode = Builder.CreateNew() + .With(r => r.Series = _otherSeries) + .With(r => r.Episodes = new List { _episode }) + .Build(); + + Subject.IsInQueue(_remoteEpisode, new List { remoteEpisode }).Should().BeFalse(); + } + + [Test] + public void should_return_false_when_quality_in_queue_is_lower() + { + var remoteEpisode = Builder.CreateNew() + .With(r => r.Series = _series) + .With(r => r.Episodes = new List { _episode }) + .With(r => r.ParsedEpisodeInfo = new ParsedEpisodeInfo + { + Quality = new QualityModel(Quality.SDTV) + }) + .Build(); + + Subject.IsInQueue(_remoteEpisode, new List { remoteEpisode }).Should().BeFalse(); + } + + [Test] + public void should_return_false_when_episode_doesnt_match() + { + var remoteEpisode = Builder.CreateNew() + .With(r => r.Series = _series) + .With(r => r.Episodes = new List { _otherEpisode }) + .With(r => r.ParsedEpisodeInfo = new ParsedEpisodeInfo + { + Quality = new QualityModel(Quality.DVD) + }) + .Build(); + + Subject.IsInQueue(_remoteEpisode, new List { remoteEpisode }).Should().BeFalse(); + } + + [Test] + public void should_return_true_when_qualities_are_the_same() + { + var remoteEpisode = Builder.CreateNew() + .With(r => r.Series = _series) + .With(r => r.Episodes = new List { _episode }) + .With(r => r.ParsedEpisodeInfo = new ParsedEpisodeInfo + { + Quality = new QualityModel(Quality.DVD) + }) + .Build(); + + Subject.IsInQueue(_remoteEpisode, new List { remoteEpisode }).Should().BeTrue(); + } + + [Test] + public void should_return_true_when_quality_in_queue_is_better() + { + var remoteEpisode = Builder.CreateNew() + .With(r => r.Series = _series) + .With(r => r.Episodes = new List { _episode }) + .With(r => r.ParsedEpisodeInfo = new ParsedEpisodeInfo + { + Quality = new QualityModel(Quality.HDTV720p) + }) + .Build(); + + Subject.IsInQueue(_remoteEpisode, new List { remoteEpisode }).Should().BeTrue(); + } + + [Test] + public void should_return_true_if_matching_multi_episode_is_in_queue() + { + var remoteEpisode = Builder.CreateNew() + .With(r => r.Series = _series) + .With(r => r.Episodes = new List { _episode, _otherEpisode }) + .With(r => r.ParsedEpisodeInfo = new ParsedEpisodeInfo + { + Quality = new QualityModel(Quality.HDTV720p) + }) + .Build(); + + Subject.IsInQueue(_remoteEpisode, new List { remoteEpisode }).Should().BeTrue(); + } + + [Test] + public void should_return_true_if_multi_episode_has_one_episode_in_queue() + { + var remoteEpisode = Builder.CreateNew() + .With(r => r.Series = _series) + .With(r => r.Episodes = new List { _episode }) + .With(r => r.ParsedEpisodeInfo = new ParsedEpisodeInfo + { + Quality = new QualityModel(Quality.HDTV720p) + }) + .Build(); + + _remoteEpisode.Episodes.Add(_otherEpisode); + + Subject.IsInQueue(_remoteEpisode, new List { remoteEpisode }).Should().BeTrue(); + } + + [Test] + public void should_return_true_if_multi_part_episode_is_already_in_queue() + { + var remoteEpisode = Builder.CreateNew() + .With(r => r.Series = _series) + .With(r => r.Episodes = new List { _episode, _otherEpisode }) + .With(r => r.ParsedEpisodeInfo = new ParsedEpisodeInfo + { + Quality = new QualityModel(Quality.HDTV720p) + }) + .Build(); + + _remoteEpisode.Episodes.Add(_otherEpisode); + + Subject.IsInQueue(_remoteEpisode, new List { remoteEpisode }).Should().BeTrue(); + } + + [Test] + public void should_return_true_if_multi_part_episode_has_two_episodes_in_queue() + { + var remoteEpisodes = Builder.CreateListOfSize(2) + .All() + .With(r => r.Series = _series) + .With(r => r.ParsedEpisodeInfo = new ParsedEpisodeInfo + { + Quality = + new QualityModel( + Quality.HDTV720p) + }) + .TheFirst(1) + .With(r => r.Episodes = new List {_episode}) + .TheNext(1) + .With(r => r.Episodes = new List {_otherEpisode}) + .Build(); + + _remoteEpisode.Episodes.Add(_otherEpisode); + + Subject.IsInQueue(_remoteEpisode, remoteEpisodes ).Should().BeTrue(); + } + } +} \ No newline at end of file diff --git a/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj b/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj index cbe2b0f67..4bdb919b9 100644 --- a/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj +++ b/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj @@ -111,6 +111,7 @@ + diff --git a/src/NzbDrone.Core/DecisionEngine/Specifications/NotInQueueSpecification.cs b/src/NzbDrone.Core/DecisionEngine/Specifications/NotInQueueSpecification.cs index 03a2b46f6..8b72ae357 100644 --- a/src/NzbDrone.Core/DecisionEngine/Specifications/NotInQueueSpecification.cs +++ b/src/NzbDrone.Core/DecisionEngine/Specifications/NotInQueueSpecification.cs @@ -4,6 +4,7 @@ using System.Linq; using NLog; using NzbDrone.Core.Download; using NzbDrone.Core.IndexerSearch.Definitions; +using NzbDrone.Core.Parser; using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Tv; @@ -12,11 +13,13 @@ namespace NzbDrone.Core.DecisionEngine.Specifications public class NotInQueueSpecification : IDecisionEngineSpecification { private readonly IProvideDownloadClient _downloadClientProvider; + private readonly IParsingService _parsingService; private readonly Logger _logger; - public NotInQueueSpecification(IProvideDownloadClient downloadClientProvider, Logger logger) + public NotInQueueSpecification(IProvideDownloadClient downloadClientProvider, IParsingService parsingService, Logger logger) { _downloadClientProvider = downloadClientProvider; + _parsingService = parsingService; _logger = logger; } @@ -40,29 +43,18 @@ namespace NzbDrone.Core.DecisionEngine.Specifications var queue = downloadClient.GetQueue().Select(queueItem => Parser.Parser.ParseTitle(queueItem.Title)).Where(episodeInfo => episodeInfo != null); - return !IsInQueue(subject, queue); + var mappedQueue = queue.Select(queueItem => _parsingService.Map(queueItem, 0)) + .Where(remoteEpisode => remoteEpisode.Series != null); + + return !IsInQueue(subject, mappedQueue); } - private bool IsInQueue(RemoteEpisode newEpisode, IEnumerable queue) + public bool IsInQueue(RemoteEpisode newEpisode, IEnumerable queue) { - var matchingTitle = queue.Where(q => String.Equals(q.SeriesTitle, newEpisode.Series.CleanTitle, StringComparison.InvariantCultureIgnoreCase)); - - var matchingTitleWithQuality = matchingTitle.Where(q => q.Quality >= newEpisode.ParsedEpisodeInfo.Quality); - - if (newEpisode.Series.SeriesType == SeriesTypes.Daily) - { - return matchingTitleWithQuality.Any(q => q.AirDate.Value.Date == newEpisode.ParsedEpisodeInfo.AirDate.Value.Date); - } + var matchingSeries = queue.Where(q => q.Series.Id == newEpisode.Series.Id); + var matchingTitleWithQuality = matchingSeries.Where(q => q.ParsedEpisodeInfo.Quality >= newEpisode.ParsedEpisodeInfo.Quality); - var matchingSeason = matchingTitleWithQuality.Where(q => q.SeasonNumber == newEpisode.ParsedEpisodeInfo.SeasonNumber); - - if (newEpisode.ParsedEpisodeInfo.FullSeason) - { - return matchingSeason.Any(); - } - - return matchingSeason.Any(q => q.EpisodeNumbers != null && q.EpisodeNumbers.Any(e => newEpisode.ParsedEpisodeInfo.EpisodeNumbers.Contains(e))); + return matchingTitleWithQuality.Any(q => q.Episodes.Select(e => e.Id).Intersect(newEpisode.Episodes.Select(e => e.Id)).Any()); } - } }