using System.Collections.Generic; using System.Linq; using FluentAssertions; using Moq; using NUnit.Framework; using NzbDrone.Core.DecisionEngine; using NzbDrone.Core.MediaFiles; using NzbDrone.Core.MediaFiles.TrackImport; using NzbDrone.Core.Parser; using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Profiles; using NzbDrone.Core.Qualities; using NzbDrone.Core.Test.Framework; using NzbDrone.Core.Music; using NzbDrone.Test.Common; using FizzWare.NBuilder; namespace NzbDrone.Core.Test.MediaFiles.TrackImport { [TestFixture] public class ImportDecisionMakerFixture : CoreTest { private List _audioFiles; private LocalTrack _localTrack; private Artist _artist; private QualityModel _quality; private Mock _pass1; private Mock _pass2; private Mock _pass3; private Mock _fail1; private Mock _fail2; private Mock _fail3; [SetUp] public void Setup() { _pass1 = new Mock(); _pass2 = new Mock(); _pass3 = new Mock(); _fail1 = new Mock(); _fail2 = new Mock(); _fail3 = new Mock(); _pass1.Setup(c => c.IsSatisfiedBy(It.IsAny())).Returns(Decision.Accept()); _pass2.Setup(c => c.IsSatisfiedBy(It.IsAny())).Returns(Decision.Accept()); _pass3.Setup(c => c.IsSatisfiedBy(It.IsAny())).Returns(Decision.Accept()); _fail1.Setup(c => c.IsSatisfiedBy(It.IsAny())).Returns(Decision.Reject("_fail1")); _fail2.Setup(c => c.IsSatisfiedBy(It.IsAny())).Returns(Decision.Reject("_fail2")); _fail3.Setup(c => c.IsSatisfiedBy(It.IsAny())).Returns(Decision.Reject("_fail3")); _artist = Builder.CreateNew() .With(e => e.Profile = new Profile { Items = Qualities.QualityFixture.GetDefaultQualities() }) .Build(); _quality = new QualityModel(Quality.MP3_256); _localTrack = new LocalTrack { Artist = _artist, Quality = _quality, Tracks = new List { new Track() }, Path = @"C:\Test\Unsorted\The.Office.S03E115.DVDRip.XviD-OSiTV.avi" }; Mocker.GetMock() .Setup(c => c.GetLocalTrack(It.IsAny(), It.IsAny(), It.IsAny())) .Returns(_localTrack); GivenVideoFiles(new List { @"C:\Test\Unsorted\The.Office.S03E115.DVDRip.XviD-OSiTV.avi".AsOsAgnostic() }); } private void GivenSpecifications(params Mock[] mocks) { Mocker.SetConstant(mocks.Select(c => c.Object)); } private void GivenVideoFiles(IEnumerable videoFiles) { _audioFiles = videoFiles.ToList(); Mocker.GetMock() .Setup(c => c.FilterExistingFiles(_audioFiles, It.IsAny())) .Returns(_audioFiles); } [Test] public void should_call_all_specifications() { GivenSpecifications(_pass1, _pass2, _pass3, _fail1, _fail2, _fail3); Subject.GetImportDecisions(_audioFiles, new Artist(), null); _fail1.Verify(c => c.IsSatisfiedBy(_localTrack), Times.Once()); _fail2.Verify(c => c.IsSatisfiedBy(_localTrack), Times.Once()); _fail3.Verify(c => c.IsSatisfiedBy(_localTrack), Times.Once()); _pass1.Verify(c => c.IsSatisfiedBy(_localTrack), Times.Once()); _pass2.Verify(c => c.IsSatisfiedBy(_localTrack), Times.Once()); _pass3.Verify(c => c.IsSatisfiedBy(_localTrack), Times.Once()); } [Test] public void should_return_rejected_if_single_specs_fail() { GivenSpecifications(_fail1); var result = Subject.GetImportDecisions(_audioFiles, new Artist()); result.Single().Approved.Should().BeFalse(); } [Test] public void should_return_rejected_if_one_of_specs_fail() { GivenSpecifications(_pass1, _fail1, _pass2, _pass3); var result = Subject.GetImportDecisions(_audioFiles, new Artist()); result.Single().Approved.Should().BeFalse(); } [Test] public void should_return_pass_if_all_specs_pass() { GivenSpecifications(_pass1, _pass2, _pass3); var result = Subject.GetImportDecisions(_audioFiles, new Artist()); result.Single().Approved.Should().BeTrue(); } [Test] public void should_have_same_number_of_rejections_as_specs_that_failed() { GivenSpecifications(_pass1, _pass2, _pass3, _fail1, _fail2, _fail3); var result = Subject.GetImportDecisions(_audioFiles, new Artist()); result.Single().Rejections.Should().HaveCount(3); } [Test] public void should_not_blowup_the_process_due_to_failed_parse() { GivenSpecifications(_pass1); Mocker.GetMock() .Setup(c => c.GetLocalTrack(It.IsAny(), It.IsAny(), It.IsAny())) .Throws(); _audioFiles = new List { "The.Office.S03E115.DVDRip.XviD-OSiTV", "The.Office.S03E115.DVDRip.XviD-OSiTV", "The.Office.S03E115.DVDRip.XviD-OSiTV" }; GivenVideoFiles(_audioFiles); Subject.GetImportDecisions(_audioFiles, _artist); Mocker.GetMock() .Verify(c => c.GetLocalTrack(It.IsAny(), It.IsAny(), It.IsAny()), Times.Exactly(_audioFiles.Count)); ExceptionVerification.ExpectedErrors(3); } [Test] public void should_use_file_quality_if_folder_quality_is_null() { GivenSpecifications(_pass1, _pass2, _pass3); var expectedQuality = QualityParser.ParseQuality(_audioFiles.Single()); var result = Subject.GetImportDecisions(_audioFiles, _artist); result.Single().LocalTrack.Quality.Should().Be(expectedQuality); } [Test] public void should_use_file_quality_if_file_quality_was_determined_by_name() { GivenSpecifications(_pass1, _pass2, _pass3); var expectedQuality = QualityParser.ParseQuality(_audioFiles.Single()); var result = Subject.GetImportDecisions(_audioFiles, _artist, new ParsedTrackInfo{Quality = new QualityModel(Quality.MP3_256) }); result.Single().LocalTrack.Quality.Should().Be(expectedQuality); } [Test] public void should_use_folder_quality_when_file_quality_was_determined_by_the_extension() { GivenSpecifications(_pass1, _pass2, _pass3); GivenVideoFiles(new string[] { @"C:\Test\Unsorted\The.Office.S03E115.mkv".AsOsAgnostic() }); _localTrack.Path = _audioFiles.Single(); _localTrack.Quality.QualitySource = QualitySource.Extension; _localTrack.Quality.Quality = Quality.MP3_256; var expectedQuality = new QualityModel(Quality.MP3_256); var result = Subject.GetImportDecisions(_audioFiles, _artist, new ParsedTrackInfo { Quality = expectedQuality }); result.Single().LocalTrack.Quality.Should().Be(expectedQuality); } [Test] public void should_use_folder_quality_when_greater_than_file_quality() { GivenSpecifications(_pass1, _pass2, _pass3); GivenVideoFiles(new string[] { @"C:\Test\Unsorted\The.Office.S03E115.mkv".AsOsAgnostic() }); _localTrack.Path = _audioFiles.Single(); _localTrack.Quality.Quality = Quality.MP3_256; var expectedQuality = new QualityModel(Quality.MP3_256); var result = Subject.GetImportDecisions(_audioFiles, _artist, new ParsedTrackInfo { Quality = expectedQuality }); result.Single().LocalTrack.Quality.Should().Be(expectedQuality); } [Test] public void should_not_throw_if_episodes_are_not_found() { GivenSpecifications(_pass1); Mocker.GetMock() .Setup(c => c.GetLocalTrack(It.IsAny(), It.IsAny(), It.IsAny())) .Returns(new LocalTrack() { Path = "test" }); _audioFiles = new List { "The.Office.S03E115.DVDRip.XviD-OSiTV", "The.Office.S03E115.DVDRip.XviD-OSiTV", "The.Office.S03E115.DVDRip.XviD-OSiTV" }; GivenVideoFiles(_audioFiles); var decisions = Subject.GetImportDecisions(_audioFiles, _artist); Mocker.GetMock() .Verify(c => c.GetLocalTrack(It.IsAny(), It.IsAny(), It.IsAny()), Times.Exactly(_audioFiles.Count)); decisions.Should().HaveCount(3); decisions.First().Rejections.Should().NotBeEmpty(); } [Test] public void should_not_use_folder_for_full_season() { var videoFiles = new[] { @"C:\Test\Unsorted\Artist.Title.S01\S01E01.mkv".AsOsAgnostic(), @"C:\Test\Unsorted\Artist.Title.S01\S01E02.mkv".AsOsAgnostic(), @"C:\Test\Unsorted\Artist.Title.S01\S01E03.mkv".AsOsAgnostic() }; GivenSpecifications(_pass1); GivenVideoFiles(videoFiles); var folderInfo = Parser.Parser.ParseMusicTitle("Artist.Title.S01"); Subject.GetImportDecisions(_audioFiles, _artist, folderInfo); Mocker.GetMock() .Verify(c => c.GetLocalTrack(It.IsAny(), It.IsAny(), null), Times.Exactly(3)); Mocker.GetMock() .Verify(c => c.GetLocalTrack(It.IsAny(), It.IsAny(), It.Is(p => p != null)), Times.Never()); } [Test] public void should_not_use_folder_when_it_contains_more_than_one_valid_video_file() { var videoFiles = new[] { @"C:\Test\Unsorted\Artist.Title.S01E01\S01E01.mkv".AsOsAgnostic(), @"C:\Test\Unsorted\Artist.Title.S01E01\1x01.mkv".AsOsAgnostic() }; GivenSpecifications(_pass1); GivenVideoFiles(videoFiles); var folderInfo = Parser.Parser.ParseMusicTitle("Artist.Title.S01E01"); Subject.GetImportDecisions(_audioFiles, _artist, folderInfo); Mocker.GetMock() .Verify(c => c.GetLocalTrack(It.IsAny(), It.IsAny(), null), Times.Exactly(2)); Mocker.GetMock() .Verify(c => c.GetLocalTrack(It.IsAny(), It.IsAny(), It.Is(p => p != null)), Times.Never()); } [Test] public void should_use_folder_when_only_one_video_file() { var videoFiles = new[] { @"C:\Test\Unsorted\Artist.Title.S01E01\S01E01.mkv".AsOsAgnostic() }; GivenSpecifications(_pass1); GivenVideoFiles(videoFiles); var folderInfo = Parser.Parser.ParseMusicTitle("Artist.Title.S01E01"); Subject.GetImportDecisions(_audioFiles, _artist, folderInfo); Mocker.GetMock() .Verify(c => c.GetLocalTrack(It.IsAny(), It.IsAny(), It.IsAny()), Times.Exactly(1)); Mocker.GetMock() .Verify(c => c.GetLocalTrack(It.IsAny(), It.IsAny(), null), Times.Never()); } [Test] public void should_not_use_folder_name_if_file_name_is_scene_name() { var videoFiles = new[] { @"C:\Test\Unsorted\Artist.Title.S01E01.720p.HDTV-LOL\Artist.Title.S01E01.720p.HDTV-LOL.mkv".AsOsAgnostic() }; GivenSpecifications(_pass1); GivenVideoFiles(videoFiles); var folderInfo = Parser.Parser.ParseMusicTitle("Artist.Title.S01E01.720p.HDTV-LOL"); Subject.GetImportDecisions(_audioFiles, _artist, folderInfo); Mocker.GetMock() .Verify(c => c.GetLocalTrack(It.IsAny(), It.IsAny(), null), Times.Exactly(1)); Mocker.GetMock() .Verify(c => c.GetLocalTrack(It.IsAny(), It.IsAny(), It.Is(p => p != null)), Times.Never()); } [Test] public void should_not_use_folder_quality_when_it_is_unknown() { GivenSpecifications(_pass1, _pass2, _pass3); _artist.Profile = new Profile { Items = Qualities.QualityFixture.GetDefaultQualities(Quality.MP3_256, Quality.Unknown) }; var folderQuality = new QualityModel(Quality.Unknown); var result = Subject.GetImportDecisions(_audioFiles, _artist, new ParsedTrackInfo { Quality = folderQuality}); result.Single().LocalTrack.Quality.Should().Be(_quality); } [Test] public void should_return_a_decision_when_exception_is_caught() { Mocker.GetMock() .Setup(c => c.GetLocalTrack(It.IsAny(), It.IsAny(), It.IsAny())) .Throws(); _audioFiles = new List { "The.Office.S03E115.DVDRip.XviD-OSiTV" }; GivenVideoFiles(_audioFiles); Subject.GetImportDecisions(_audioFiles, _artist).Should().HaveCount(1); ExceptionVerification.ExpectedErrors(1); } } }