Click here to Skip to main content
15,891,529 members
Articles / Desktop Programming / WPF

PlantUML Editor: A Fast and Simple UML Editor using WPF

Rate me:
Please Sign up or sign in to vote.
4.98/5 (65 votes)
11 Jun 2011CPOL16 min read 238K   6.4K   233  
A WPF smart client to generate UML diagrams from plain text using plantuml tool
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SubSpec;
using Utilities;
using Xunit;
using System.Diagnostics;
using System.Threading;
using System.Windows.Threading;

namespace Test.Utilities
{
    public class TestBackgroundThread
    {
        [Specification]
        public void WaitForAllWork_should_return_immediately_if_no_work_queued()
        {
            var stopWatch = new Stopwatch();
            "Given no work going on".Context(() =>
            {
                Assert.False(BackgroundWork.IsWorkOrTimerQueued());
            });

            var result = default(bool);
            "When WaitForAllWork is called".Do(() =>
            {
                stopWatch.Start();
                result = BackgroundWork.WaitForAllWork(TimeSpan.FromSeconds(1));
            });

            "It should return immediately without going into any wait period".Assert(() =>
            {
                Assert.True(stopWatch.Elapsed < TimeSpan.FromSeconds(1));
            });

            "It should return true".Assert(() =>
            {
                Assert.True(result);
            });
        }

        [Specification][STAThread]
        public void DoWork_should_queue_a_new_thread_to_do_the_work()
        {
            TimeSpan howLongWorkTakes = TimeSpan.FromSeconds(1);
            
            var doWorkCalled = false;
            var successCallbackFired = false;
            var onExceptionFired = false;

            var doWorkThreadId = default(int);
            var onCompleteThreadId = default(int);
            var onExceptionThreadId = default(int);
            var letsThrowException = false;

            Stopwatch stopWatch = new Stopwatch();
            DispatcherFrame frame = default(DispatcherFrame);
                    
            Func<bool> waitForWorkDone = () => {
                TimeSpan timeout = howLongWorkTakes.Add(TimeSpan.FromSeconds(5));
                if (BackgroundWork.WaitForAllWork(timeout))
                {
                    // Let the Disptacher.BeginInvoke calls proceed
                    Dispatcher.PushFrame(frame);
                    return true;
                }
                else
                {
                    // waiting timed out. Work did not finish on time.
                    return false;
                }
            };

            Action callbackFiredOnDispatcher = () => {
                frame.Continue = false; // Dispatcher should stop now
            };

            "Given no background work running".Context(() =>
            {
                Assert.False(BackgroundWork.IsWorkOrTimerQueued());                
                frame = new DispatcherFrame();

                doWorkCalled = false;
                successCallbackFired = false;
                onExceptionFired = false;

                doWorkThreadId = default(int);
                onCompleteThreadId = default(int);
                onExceptionThreadId = default(int);
                
                stopWatch.Reset();
                stopWatch.Start();
            });

            "When a new work is queued".Do(() =>
            {
                var shouldThrowException = letsThrowException;
                BackgroundWork.DoWork(() => // doWork
                {
                    doWorkThreadId = Thread.CurrentThread.ManagedThreadId;
                    doWorkCalled = true;

                    // Simulate some delay in background work
                    Thread.Sleep(howLongWorkTakes); 

                    if (shouldThrowException)
                    {
                        throw new ApplicationException("Exception");
                    }                                
                }, () => // onComplete
                {
                    onCompleteThreadId = Thread.CurrentThread.ManagedThreadId;
                    successCallbackFired = true;

                    callbackFiredOnDispatcher();
                }, (x) => // onException
                {
                    onExceptionThreadId = Thread.CurrentThread.ManagedThreadId;
                    onExceptionFired = true;

                    callbackFiredOnDispatcher();
                });
            });

            "It should return control immediately without blocking the current thread".Assert(() =>
            {
                Assert.True(stopWatch.Elapsed < howLongWorkTakes);
                Assert.True(waitForWorkDone());
            });

            "It should return true if IsWorkQueued is called".Assert(() =>
            {
                Assert.True(BackgroundWork.IsWorkOrTimerQueued());
                Assert.True(waitForWorkDone());
            });

            "It should wait for the work to complete if WaitForAllWork is called".Assert(() =>
            {
                Assert.True(waitForWorkDone());

                // The work should finish within the duration it takes with max 1 sec buffer
                // for additional stuff xunit does.
                Assert.True(stopWatch.Elapsed < howLongWorkTakes.Add(TimeSpan.FromSeconds(1)));
            });

            "It should execute the work in a separate thread".Assert(() => 
            {
                Assert.True(waitForWorkDone());

                Assert.True(doWorkCalled);
                Assert.NotEqual(Thread.CurrentThread.ManagedThreadId, doWorkThreadId);
            });

            "It should fire onComplete on the same thread as UI thread".Assert(() =>
            {
                Assert.True(waitForWorkDone());

                Assert.True(successCallbackFired);
                Assert.Equal(Thread.CurrentThread.ManagedThreadId, onCompleteThreadId);
            });
            
            "It should not fire onException if there's no exception".Assert(() =>
            {
                Assert.True(waitForWorkDone());

                Assert.False(onExceptionFired);

                letsThrowException = true; // This is for next assert                
            });

            "It should fire exception on UI thread".Assert(() =>
            {
                Assert.True(waitForWorkDone());

                Assert.False(successCallbackFired);
                Assert.True(onExceptionFired);
                Assert.Equal(Thread.CurrentThread.ManagedThreadId, onExceptionThreadId);
            });
        }

        
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect BT, UK (ex British Telecom)
United Kingdom United Kingdom

Comments and Discussions