public void DownloadAllPodcastsWithoutNetworkCheck_HandlesMultipleCalls_Concurrent()
        {
            // arrange
            int taskStartCount = 0;

            SetupMockControlFileFor2Podcasts();
            SetupEpisodesFor2Podcasts();
            ViewModel.Initialise();
            ViewModel.FindEpisodesToDownload();
            A.CallTo(() => MockTaskPool.RunAllTasks(A <int> .Ignored, A <ITask[]> .Ignored))
            .Invokes(() =>
            {
                taskStartCount++;
                if (taskStartCount > 1)
                {
                    throw new Exception("Concurrent calls are not being trapped");
                }
                ViewModel.DownloadAllPodcastsWithoutNetworkCheck().Wait();
            });

            // act
            ViewModel.DownloadAllPodcastsWithoutNetworkCheck().Wait();

            // assert
            A.CallTo(() => MockCrashReporter.LogNonFatalException(A <Exception> .Ignored)).MustNotHaveHappened();
            A.CallTo(() => MockLogger.Warning(A <ILogger.MessageGenerator> .Ignored)).MustHaveHappened(1, Times.Exactly);
            Assert.AreEqual(1, ObservedResults.StartDownloadingCount, "start count");
            Assert.AreEqual(1, ObservedResults.EndDownloadingCount, "end count");
            Assert.AreEqual(1, taskStartCount, "task start count");
        }
        private SyncItemMocker SetupFireStatusEvent(Guid id, StatusUpdateLevel level, bool complete, Exception ex, string message)
        {
            var syncItemMocker = new SyncItemMocker().ApplyId(id).ApplyEpisodeTitle("EpisodeTitle");
            EventHandler <StatusUpdateEventArgs> statusEventHandler = null;
            StatusUpdateEventArgs statusArgs =
                ex != null
                ? new StatusUpdateEventArgs(level, message, ex, complete, syncItemMocker.GetMockedSyncItem())
                : new StatusUpdateEventArgs(level, message, complete, syncItemMocker.GetMockedSyncItem());

            A.CallTo(() =>
                     MockSyncItemToEpisodeDownloaderTaskConverter.ConvertItemsToTasks
                     (
                         A <IList <ISyncItem> > .Ignored,
                         A <EventHandler <StatusUpdateEventArgs> > .Ignored,
                         A <EventHandler <ProgressEventArgs> > .Ignored
                     ))
            .ReturnsLazily((IList <ISyncItem> items, EventHandler <StatusUpdateEventArgs> statusEvent, EventHandler <ProgressEventArgs> progressEvent) =>
            {
                statusEventHandler = statusEvent;
                return(new IEpisodeDownloader[0]);
            });
            A.CallTo(() => MockTaskPool.RunAllTasks(A <int> .Ignored, A <ITask[]> .Ignored))
            .Invokes(() =>
            {
                statusEventHandler?.Invoke(this, statusArgs);
            });
            return(syncItemMocker);
        }
        private SyncItemMocker SetupFireProgressEvent(Guid id, int percentage)
        {
            var syncItemMocker = new SyncItemMocker().ApplyId(id).ApplyEpisodeTitle("EpisodeTitle");
            EventHandler <ProgressEventArgs> progressEventHandler = null;
            ProgressEventArgs progressArgs = new ProgressEventArgs();

            A.CallTo(() =>
                     MockSyncItemToEpisodeDownloaderTaskConverter.ConvertItemsToTasks
                     (
                         A <IList <ISyncItem> > .Ignored,
                         A <EventHandler <StatusUpdateEventArgs> > .Ignored,
                         A <EventHandler <ProgressEventArgs> > .Ignored
                     ))
            .ReturnsLazily((IList <ISyncItem> items, EventHandler <StatusUpdateEventArgs> statusEvent, EventHandler <ProgressEventArgs> progressEvent) =>
            {
                progressEventHandler = progressEvent;
                return(new IEpisodeDownloader[0]);
            });
            A.CallTo(() => MockTaskPool.RunAllTasks(A <int> .Ignored, A <ITask[]> .Ignored))
            .Invokes(() =>
            {
                progressArgs.TotalItemsToProcess = 100;
                progressArgs.ItemsProcessed      = percentage;
                progressArgs.ProgressPercentage  = percentage;
                progressArgs.UserState           = syncItemMocker.GetMockedSyncItem();
                progressEventHandler?.Invoke(this, progressArgs);
            });
            return(syncItemMocker);
        }
        public void CancelAllJobsAndExit_Exits()
        {
            // arrange
            int taskStartCount = 0;

            SetupMockControlFileFor2Podcasts();
            SetupEpisodesFor2Podcasts();
            ViewModel.Initialise();
            ViewModel.FindEpisodesToDownload();

            // act
            A.CallTo(() => MockTaskPool.RunAllTasks(A <int> .Ignored, A <ITask[]> .Ignored))
            .Invokes(() =>
            {
                taskStartCount++;
                if (taskStartCount > 1)
                {
                    throw new Exception("Concurrent calls are not being trapped");
                }
                ViewModel.RequestExit();
                ViewModel.CancelAllJobsAndExit();
            });
            ViewModel.DownloadAllPodcastsWithoutNetworkCheck().Wait();

            // assert
            A.CallTo(() => MockCrashReporter.LogNonFatalException(A <Exception> .Ignored)).MustNotHaveHappened();
            A.CallTo(() => MockTaskPool.CancelAllTasks()).MustHaveHappened(1, Times.Exactly);
            Assert.AreEqual(1, ObservedResults.ExitCount, "exit count");
        }
        public void RequestExit_Prompts()
        {
            // arrange
            bool result         = true;
            int  taskStartCount = 0;

            SetupMockControlFileFor2Podcasts();
            SetupEpisodesFor2Podcasts();
            ViewModel.Initialise();
            ViewModel.FindEpisodesToDownload();

            // act
            A.CallTo(() => MockTaskPool.RunAllTasks(A <int> .Ignored, A <ITask[]> .Ignored))
            .Invokes(() =>
            {
                taskStartCount++;
                if (taskStartCount > 1)
                {
                    throw new Exception("Concurrent calls are not being trapped");
                }
                result = ViewModel.RequestExit();
            });
            ViewModel.DownloadAllPodcastsWithoutNetworkCheck().Wait();

            // assert
            A.CallTo(() => MockCrashReporter.LogNonFatalException(A <Exception> .Ignored)).MustNotHaveHappened();
            Assert.AreEqual(result, false, "result");
            Assert.AreEqual("dialog title", ObservedResults.LastExitPromptTitle, "exit prompt title");
            Assert.AreEqual("exit message", ObservedResults.LastExitPromptMessage, "exit prompt message");
            Assert.AreEqual("exit ok", ObservedResults.LastExitPromptOk, "exit prompt ok");
            Assert.AreEqual("exit cancel", ObservedResults.LastExitPromptCancel, "exit prompt cancel");
        }
        public async Task DownloadAllPodcastsWithoutNetworkCheck_SetsMaxDownloads()
        {
            // arrange
            SetupMockControlFileFor2Podcasts();
            SetupEpisodesFor2Podcasts();
            ViewModel.Initialise();
            ViewModel.FindEpisodesToDownload();

            // act
            await ViewModel.DownloadAllPodcastsWithoutNetworkCheck().ConfigureAwait(false);

            // assert
            A.CallTo(() => MockCrashReporter.LogNonFatalException(A <Exception> .Ignored)).MustNotHaveHappened();
            A.CallTo(() => MockNetworkHelper.SetNetworkConnectionLimit(MAX_DOWNLOADS)).MustHaveHappened(1, Times.Exactly);
            A.CallTo(() => MockTaskPool.RunAllTasks(MAX_DOWNLOADS, A <ITask[]> .Ignored)).MustHaveHappened(1, Times.Exactly);
        }
        public void DownloadAllPodcastsWithoutNetworkCheck_HandlesMultipleCalls_Sequential()
        {
            // arrange
            SetupMockControlFileFor2Podcasts();
            SetupEpisodesFor2Podcasts();
            ViewModel.Initialise();
            ViewModel.FindEpisodesToDownload();

            // act
            ViewModel.DownloadAllPodcastsWithoutNetworkCheck().Wait();
            ViewModel.DownloadAllPodcastsWithoutNetworkCheck().Wait();

            // assert
            A.CallTo(() => MockCrashReporter.LogNonFatalException(A <Exception> .Ignored)).MustNotHaveHappened();
            A.CallTo(() => MockLogger.Warning(A <ILogger.MessageGenerator> .Ignored)).MustNotHaveHappened();
            A.CallTo(() => MockTaskPool.RunAllTasks(A <int> .Ignored, A <ITask[]> .Ignored)).MustHaveHappened(2, Times.Exactly);
            Assert.AreEqual(2, ObservedResults.StartDownloadingCount, "start count");
            Assert.AreEqual(2, ObservedResults.EndDownloadingCount, "end count");
        }
        public async Task DownloadAllPodcastsWithoutNetworkCheck_HandlesException()
        {
            // arrange
            SetupMockControlFileFor2Podcasts();
            SetupEpisodesFor2Podcasts();
            ViewModel.Initialise();
            ViewModel.FindEpisodesToDownload();
            var testException = new Exception("TEST EXCEPTION");

            A.CallTo(() => MockTaskPool.RunAllTasks(A <int> .Ignored, A <ITask[]> .Ignored)).Throws(testException);

            // act
            await ViewModel.DownloadAllPodcastsWithoutNetworkCheck().ConfigureAwait(false);

            // assert
            Assert.AreEqual(1, ObservedResults.StartDownloadingCount, "start count");
            Assert.AreEqual(1, ObservedResults.EndDownloadingCount, "end count");
            A.CallTo(() => MockCrashReporter.LogNonFatalException(testException)).MustHaveHappened(1, Times.Exactly);
            A.CallTo(() => MockLogger.LogException(A <ILogger.MessageGenerator> .Ignored, testException)).MustHaveHappened(1, Times.Exactly);
            Assert.AreEqual("TEST EXCEPTION", ObservedResults.LastDisplayMessage);
        }