/// <summary>
        /// Run selected tests and return a test result. The test is run synchronously,
        /// and the listener interface is notified as it progresses.
        /// </summary>
        /// <param name="listener">Interface to receive EventListener notifications.</param>
        /// <param name="filter">A test filter used to select tests to be run</param>
        /// <returns></returns>
        public ITestResult Run(ITestListener listener, ITestFilter filter)
        {
            log.Info("Running tests");
            if (_loadedTest == null)
                throw new InvalidOperationException("Run was called but no test has been loaded.");

            // Save Console.Out and Error for later restoration
            TextWriter savedOut = Console.Out;
            TextWriter savedErr = Console.Error;

            TestExecutionContext initialContext = CreateTestExecutionContext(_settings);

#if NUNITLITE
            initialContext.Listener = listener;

            WorkItem workItem = WorkItem.CreateWorkItem(_loadedTest, initialContext, filter);
            workItem.Completed += new EventHandler(OnRunCompleted);
            workItem.Execute();

            _runComplete.WaitOne();

            return workItem.Result;
#else
            QueuingEventListener queue = new QueuingEventListener();

            if (_settings.Contains("CaptureStandardOutput"))
                initialContext.Out = new EventListenerTextWriter(queue, TestOutputType.Out);
            if (_settings.Contains("CapureStandardError"))
                initialContext.Error = new EventListenerTextWriter(queue, TestOutputType.Error);

            initialContext.Listener = queue;

            int numWorkers = _settings.Contains("NumberOfTestWorkers")
                ? (int)_settings["NumberOfTestWorkers"]
                : 0;

            WorkItemDispatcher dispatcher = null;

            if (numWorkers > 0)
            {
                dispatcher = new WorkItemDispatcher(numWorkers);
                initialContext.Dispatcher = dispatcher;
            }

            WorkItem workItem = WorkItem.CreateWorkItem(_loadedTest, initialContext, filter);
            workItem.Completed += new EventHandler(OnRunCompleted);

            using (EventPump pump = new EventPump(listener, queue.Events))
            {
                pump.Start();

                if (dispatcher != null)
                {
                    dispatcher.Dispatch(workItem);
                    dispatcher.Start();
                }
                else
                    workItem.Execute();

                _runComplete.WaitOne();
            }

            Console.SetOut(savedOut);
            Console.SetError(savedErr);

            if (dispatcher != null)
            {
                dispatcher.Stop();
                dispatcher = null;
            }

            return workItem.Result;
#endif
        }
        /// <summary>
        /// Run selected tests and return a test result. The test is run synchronously,
        /// and the listener interface is notified as it progresses.
        /// </summary>
        /// <param name="listener">Interface to receive EventListener notifications.</param>
        /// <param name="filter">A test filter used to select tests to be run</param>
        /// <returns></returns>
        public ITestResult Run(ITestListener listener, ITestFilter filter)
        {
            log.Info("Running tests");
            if (_loadedTest == null)
                throw new InvalidOperationException("The Run method was called but no test has been loaded");

            // Save Console.Out and Error for later restoration
            TextWriter savedOut = Console.Out;
            TextWriter savedErr = Console.Error;

            TestExecutionContext initialContext = CreateTestExecutionContext(_settings);

#if NUNITLITE
            initialContext.Listener = listener;

            WorkItem workItem = WorkItem.CreateWorkItem(_loadedTest, initialContext, filter);
            workItem.Completed += new EventHandler(OnRunCompleted);
            workItem.Execute();

            _runComplete.WaitOne();

            return workItem.Result;
#else
            QueuingEventListener queue = new QueuingEventListener();

            if (_settings.Contains(DriverSettings.CaptureStandardOutput))
                initialContext.Out = new EventListenerTextWriter(queue, TestOutputType.Out);
            if (_settings.Contains(DriverSettings.CaptureStandardError))
                initialContext.Error = new EventListenerTextWriter(queue, TestOutputType.Error);

            initialContext.Listener = queue;

            int levelOfParallelization = _settings.Contains(DriverSettings.NumberOfTestWorkers)
                ? (int)_settings[DriverSettings.NumberOfTestWorkers]
                : _loadedTest.Properties.ContainsKey(PropertyNames.LevelOfParallelization)
                    ? (int)_loadedTest.Properties.Get(PropertyNames.LevelOfParallelization)
                    : Math.Max(Environment.ProcessorCount, 2);

            WorkItemDispatcher dispatcher = null;

            if (levelOfParallelization > 0)
            {
                dispatcher = new WorkItemDispatcher(levelOfParallelization);
                initialContext.Dispatcher = dispatcher;
                // Assembly does not have IApplyToContext attributes applied
                // when the test is built, so  we do it here.
                // TODO: Generalize this
                if (_loadedTest.Properties.ContainsKey(PropertyNames.ParallelScope))
                    initialContext.ParallelScope = 
                        (ParallelScope)_loadedTest.Properties.Get(PropertyNames.ParallelScope) & ~ParallelScope.Self;
            }

            WorkItem workItem = WorkItem.CreateWorkItem(_loadedTest, initialContext, filter);
            workItem.Completed += new EventHandler(OnRunCompleted);

            using (EventPump pump = new EventPump(listener, queue.Events))
            {
                pump.Start();

                if (dispatcher != null)
                {
                    dispatcher.Dispatch(workItem);
                    dispatcher.Start();
                }
                else
                    workItem.Execute();

                _runComplete.WaitOne();
            }

            Console.SetOut(savedOut);
            Console.SetError(savedErr);

            if (dispatcher != null)
            {
                dispatcher.Stop();
                dispatcher = null;
            }

            return workItem.Result;
#endif
        }