public TestResultGrp RunTests(TestCase TestCaseDel, System.Threading.ThreadPriority threadPriorty,
                                      bool ShowProgress)
        {
            Progress display = null;

            if (ShowProgress)
            {
                display = new Progress(this);
            }

            _testCaseDel += TestCaseDel;
            if (TestCaseDel != null)             //add no-op cleanup functions
            {
                for (int i = 0; i < TestCaseDel.GetInvocationList().Length; ++i)
                {
                    _preClean     += new TestCleanup(TestRunner.NoOp);
                    _postClean    += new TestCleanup(TestRunner.NoOp);
                    _testValidity += new TestValidity(TestRunner.TestOK);
                }
            }

            ThreadStart ts = new ThreadStart(ThreadMethod);
            Thread      t  = new Thread(ts);

            t.Priority = threadPriorty;
            _testsStoppedEvent.Reset();
            t.Start();

            if (ShowProgress)
            {
                display.ShowDialog();
            }

            _testsStoppedEvent.WaitOne();
            if (TestsDone)
            {
                StackFrame sf              = new StackFrame(_testMethodDepth, false);
                MethodBase caller          = sf.GetMethod();
                object[]   motivationsAtts = caller.GetCustomAttributes(typeof(DotNetPerformance.BenchmarkAttribute), true);
                string     motivation      = "";
                string     testName        = caller.DeclaringType.Name;
                if (motivationsAtts != null && motivationsAtts.Length != 0)
                {
                    BenchmarkAttribute ma = (BenchmarkAttribute)motivationsAtts[0];
                    motivation = ma.Motivation;
                    if (ma.TestName != String.Empty)
                    {
                        testName = ma.TestName;
                    }
                }
                return(new TestResultGrp(_results, testName, motivation));
            }
            else
            {
                t.Abort();
                return(new TestResultGrp(null, "", ""));
            }
        }
        public void ThreadMethod()
        {
            Delegate[] preCleanupFunctions  = _preClean.GetInvocationList();
            Delegate[] testCases            = _testCaseDel.GetInvocationList();
            Delegate[] postCleanupFunctions = _postClean.GetInvocationList();
            Delegate[] checkFunctions       = _testValidity.GetInvocationList();

            //get run ordering and initialise
            Int32 numberTestCases = testCases.GetLength(0);
            Int32 totalNumberRuns = numberTestCases * _numberRuns;

            TestResult[] results = new TestResult[numberTestCases];
            TimeSpan[,] runTimes = new TimeSpan[numberTestCases, _numberRuns];
            string[,] errTxt     = new string[numberTestCases, _numberRuns];
            Int32[] runsSoFar      = new Int32[numberTestCases];
            Int32[] runNumberOrder = GetRandomSequence(numberTestCases, totalNumberRuns);

            //run tests
            for (Int32 i = 0; i < totalNumberRuns; ++i)
            {
                PercentageDone = i * 100 / totalNumberRuns;
                Int32       testCaseToRun = runNumberOrder[i];
                TestCleanup preClean      = (TestCleanup)preCleanupFunctions[testCaseToRun];
                if (preClean != null)
                {
                    preClean();
                }
                TestCase tc = (TestCase)testCases[testCaseToRun];

                bool   testOK = false;
                string testError;

                if (tc == null)
                {
                    throw new ArgumentException("Null test case delegates are not allowed");
                }
                HiResTimer hrt = new HiResTimer();
                for (int count = 0; count < _testReReuns && !testOK; ++count)
                {
                    hrt.Start();
                    try{
                        tc(_numberIterations);
                    }
                    catch (Exception e) {
                        if (e is ThreadAbortException)
                        {
                            return;                                                    //this exception occurs when test cancelled
                        }
                        System.Windows.Forms.MessageBox.Show(String.Format("Exception caught: {0}", e.Message));
                        PercentageDone = 100;
                        _testsStoppedEvent.Set();
                        return;
                    }
                    hrt.Stop();

                    TestCleanup postClean = (TestCleanup)postCleanupFunctions[testCaseToRun];
                    if (postClean != null)
                    {
                        postClean();
                    }

                    TestValidity tv = (TestValidity)checkFunctions[testCaseToRun];
                    if (tv != null)
                    {
                        testOK = tv(out testError);
                    }
                    else
                    {
                        testError = String.Empty;
                    }
                    runTimes[testCaseToRun, runsSoFar[testCaseToRun]] = hrt.ElapsedTimeSpan;
                    errTxt[testCaseToRun, runsSoFar[testCaseToRun]]   = testError;
                }
                ++runsSoFar[testCaseToRun];
            }

            //post-process
            _results  = PostProcessResults(testCases, runTimes, errTxt);
            TestsDone = true;
            _testsStoppedEvent.Set();
            PercentageDone = 100;
        }