public static void TestCancellationByException()
        {
            bool wasCanceled = false;
            using (ThreadWorker worker = new ThreadWorker(new ProgressContext()))
            {
                worker.Work += (object sender, ThreadWorkerEventArgs e) =>
                    {
                        throw new OperationCanceledException();
                    };
                worker.Completing += (object sender, ThreadWorkerEventArgs e) =>
                    {
                        wasCanceled = e.Result == FileOperationStatus.Canceled;
                    };
                worker.Run();
                worker.Join();
            }

            Assert.That(wasCanceled, Is.True, "The operation was canceled and should return status as such.");
        }
        public static void TestCancellationByRequest()
        {
            bool wasCanceled = false;
            FakeRuntimeEnvironment environment = (FakeRuntimeEnvironment)OS.Current;
            using (ThreadWorker worker = new ThreadWorker(new ProgressContext()))
            {
                worker.Work += (object sender, ThreadWorkerEventArgs e) =>
                {
                    e.Progress.Cancel = true;
                    environment.CurrentTiming.CurrentTiming = TimeSpan.FromSeconds(1);
                    e.Progress.AddCount(1);
                };
                worker.Completing += (object sender, ThreadWorkerEventArgs e) =>
                {
                    wasCanceled = e.Result == FileOperationStatus.Canceled;
                };
                worker.Run();
                worker.Join();
            }

            Assert.That(wasCanceled, Is.True, "The operation was canceled and should return status as such.");
        }
        public static void TestSimple()
        {
            int workThreadId = -1;
            FileOperationStatus returnedStatus = FileOperationStatus.UnspecifiedError;

            bool done = false;
            using (ThreadWorker worker = new ThreadWorker(new ProgressContext()))
            {
                worker.Work += (object sender, ThreadWorkerEventArgs e) =>
                    {
                        workThreadId = Thread.CurrentThread.ManagedThreadId;
                        e.Result = FileOperationStatus.Success;
                    };
                worker.Completing += (object sender, ThreadWorkerEventArgs e) =>
                    {
                        returnedStatus = e.Result;
                        done = true;
                    };
                worker.Run();
                worker.Join();
            }

            Assert.That(returnedStatus, Is.EqualTo(FileOperationStatus.Success), "The status should be returned as successful.");
            Assert.That(workThreadId, Is.Not.EqualTo(Thread.CurrentThread.ManagedThreadId), "The work should not be performed on the caller thread.");
            Assert.That(done, Is.True, "The background work must have executed the completed handler now.");
        }
        public static void TestPrepare()
        {
            bool wasPrepared = false;
            using (ThreadWorker worker = new ThreadWorker(new ProgressContext()))
            {
                worker.Prepare += (object sender, ThreadWorkerEventArgs e) =>
                    {
                        wasPrepared = true;
                    };
                worker.Run();
                worker.Join();
            }

            Assert.That(wasPrepared, Is.True, "The Prepare event should be raised.");
        }
        public static void TestProgress()
        {
            FakeRuntimeEnvironment environment = (FakeRuntimeEnvironment)OS.Current;
            int progressCalls = 0;

            ProgressContext progress = new ProgressContext();
            using (ThreadWorker worker = new ThreadWorker(progress))
            {
                worker.Work += (object sender, ThreadWorkerEventArgs e) =>
                    {
                        environment.CurrentTiming.CurrentTiming = TimeSpan.FromSeconds(1);
                        e.Progress.AddCount(1);
                        e.Result = FileOperationStatus.Success;
                    };
                progress.Progressing += (object sender, ProgressEventArgs e) =>
                    {
                        ++progressCalls;
                    };
                worker.Run();
                worker.Join();
            }

            Assert.That(progressCalls, Is.EqualTo(1), "The Progressing event should be raised exactly one time.");
        }
        public static void TestObjectDisposedException()
        {
            ThreadWorker worker = new ThreadWorker(new ProgressContext());
            worker.Work += (object sender, ThreadWorkerEventArgs e) =>
                {
                    e.Result = FileOperationStatus.Success;
                };
            try
            {
                worker.Run();
                worker.Join();
            }
            finally
            {
                worker.Dispose();
            }

            bool hasCompleted = false;
            Assert.Throws<ObjectDisposedException>(() => { worker.Run(); });
            Assert.Throws<ObjectDisposedException>(() => { worker.Join(); });
            Assert.Throws<ObjectDisposedException>(() => { hasCompleted = worker.HasCompleted; });
            Assert.That(!hasCompleted, "Although the thread has completed, the variable should still be false since the attempt to set it is after Dispose().");
            Assert.DoesNotThrow(() => { worker.Dispose(); });
        }
 public static void TestHasCompleted()
 {
     using (ThreadWorker worker = new ThreadWorker(new ProgressContext()))
     {
         bool wasCompletedInWork = false;
         worker.Work += (object sender, ThreadWorkerEventArgs e) =>
         {
             wasCompletedInWork = worker.HasCompleted;
         };
         bool wasCompletedInCompleted = false;
         worker.Completing += (object sender, ThreadWorkerEventArgs e) =>
         {
             wasCompletedInCompleted = worker.HasCompleted;
         };
         worker.Run();
         worker.Join();
         Assert.That(!wasCompletedInWork, "Completion is not set as true in the work event.");
         Assert.That(!wasCompletedInCompleted, "Completion is not set as true until after the completed event.");
         Assert.That(worker.HasCompleted, "Completion should be set as true when the thread is joined.");
     }
 }
        public static void TestErrorSetInWorkCompleted()
        {
            bool errorInWork = false;
            using (ThreadWorker worker = new ThreadWorker(new ProgressContext()))
            {
                worker.Work += (object sender, ThreadWorkerEventArgs e) =>
                {
                    throw new InvalidOperationException();
                };
                worker.Completing += (object sender, ThreadWorkerEventArgs e) =>
                {
                    errorInWork = e.Result == FileOperationStatus.Exception;
                };
                worker.Run();
                worker.Join();
            }

            Assert.That(errorInWork, Is.True, "The operation was interrupted by an exception and should return status as such.");
        }
        public static void TestFinishInBackground()
        {
            bool didComplete = false;
            ProgressContext progress = new ProgressContext();
            progress.Progressing += (object sender2, ProgressEventArgs e2) =>
            {
                didComplete = true;
            };

            using (ThreadWorker threadWorker = new ThreadWorker(progress))
            {
                threadWorker.Work += (object sender, ThreadWorkerEventArgs e) =>
                {
                    using (WorkerGroup workerGroup = new WorkerGroup(progress))
                    {
                        IThreadWorker worker = workerGroup.CreateWorker();
                        worker.Work += (object sender2, ThreadWorkerEventArgs e2) =>
                        {
                            e2.Progress.NotifyLevelStart();
                            e2.Progress.NotifyLevelFinished();
                        };
                        worker.Run();
                    }
                };
                threadWorker.Run();
            }

            Assert.That(didComplete, "Execution should continue here, with the flag set indicating that the progress event occurred.");
        }
 /// <summary>
 /// Perform a background operation with support for progress bars and cancel.
 /// </summary>
 /// <param name="displayText">A text that may be used as a reference in various messages.</param>
 /// <param name="work">A 'work' delegate, taking a ProgressContext and return a FileOperationStatus. Executed on a background thread. Not the calling/GUI thread.</param>
 /// <param name="complete">A 'complete' delegate, taking the final status. Executed on the original caller thread, typically the GUI thread.</param>
 public void BackgroundWorkWithProgress(Func<ProgressContext, FileOperationStatus> work, Action<FileOperationStatus> complete)
 {
     ProgressContext progress = new ProgressContext();
     ProgressBar progressBar = CreateProgressBar(progress);
     OnProgressBarCreated(new ControlEventArgs(progressBar));
     progress.Progressing += (object sender, ProgressEventArgs e) =>
     {
         progressBar.Value = e.Percent;
     };
     ThreadWorker threadWorker = new ThreadWorker(progress);
     threadWorker.Work += (object sender, ThreadWorkerEventArgs e) =>
     {
         e.Result = work(e.Progress);
     };
     threadWorker.Completing += (object sender, ThreadWorkerEventArgs e) =>
     {
         try
         {
             complete(e.Result);
             progressBar.Parent = null;
         }
         finally
         {
             progressBar.Dispose();
         }
     };
     threadWorker.Completed += (object sender, ThreadWorkerEventArgs e) =>
     {
         IDisposable disposable = sender as IDisposable;
         if (disposable != null)
         {
             disposable.Dispose();
         }
         Interlocked.Decrement(ref _workerCount);
     };
     Interlocked.Increment(ref _workerCount);
     threadWorker.Run();
 }