A few days ago, somebody came into my office and plopped down a box. It seemed very light. He said that it was a new PC. I thought hmmm…. The box seems empty…Why am I getting a new PC?.

Apparently an inventory was made and my current hardware was at the lower end of the list.

So I started up the Dell Optiplex 755 with 4 gigs of RAM, and it was running Vista 64. Super: I hadn’t done much with 64 bit code yet.

Sure enough, debugging 64 bit native applications shows that the CPU has 64 bit wide registers (and more registers!). If I attach to a 64 bit process, the Debug->Windows->Registers looks like:

RAX = 0000000000000000 RBX = 000000001DEB7818 RCX = 000000000F99A027

RDX = 0000000000000000 RSI = 0000000000000001 RDI = 00000000242E5454

R8  = 000000001FD3FCB8 R9  = 0000000000000000 R10 = 0000000000000000

R11 = 0000000000000206 R12 = 0000000000000000 R13 = 0000000000000000

R14 = 0000000000000000 R15 = 0000000000000000 RIP = 000007FEF0FD3D29

RSP = 000000001FD3FCF0 RBP = 0000000000000000 EFL = 00000246

If I attach to a 32 bit process:

EAX = 00000000 EBX = 006AC138 ECX = 79E74400 EDX = 00000000 ESI = 00DF6700

EDI = 00000000 EIP = 59B80265 ESP = 001DDEE8 EBP = 001DDEE8 EFL = 00000206

001DDEFC = 06CD35C8

(The debugger is pretty amazing!)

The sheer size of the registers means instead of a maximum 2^32 =4 gig virtual address space, we have 2^64

To calculate that, type this in the Fox command window:

?LOG10(2^64)

?2^64

Which shows 19.27, 1.844674E+19

That means 19.27 zeros: 18,000,000,000,000,000,000 which is 18 billion billion or 18 exabytes!

Coincidentally, we have some new 64 bit code that was recently created by “patching” the 32 bit version, and I wanted some test tools for it.

I have a VS Test Project with many (32 bit) tests. (Use Visual Studio Test framework to create tests for your code)

So I created my own Test Host in a day:

This Test Host:

·         Uses the existing 32 bit test source code as linked files: if you make changes to the tests, they will automatically be updated in both 32 and 64 bit versions

·         Can be built as 32 bit or 64 bit (Project->Properties->Compile->Advanced Compile Options->Target CPU->AnyCPU or x86), so it can run tests in either 32 or 64 bits.  When set as AnyCPU and running on 64 bit OS like Vista 64, then it will run as 64 bit.

·         Does not require test deployment: you can test in place. VSTestHost requires deployment.

·         Uses reflection on itself to get and run the TestInitialize, TestCleanup and TestMethods.

·         Can run selected tests in a loop for stress tests, like leak detection.

·         Uses XAML and Data Binding (see Create your own media browser: Display your pictures, music, movies in a XAML tooltip)

o   Notice how the enabling and disabling of buttons is done via data binding.

o   The data binding updates the status (Success,Failure/Pending) and its color in the ListView.

o   Shows the test methods in a ListView with click/sort column headers.

·         The tests run on a worker thread. The UI is thus responsive and not blocked.

·         A progress bar and stopwatch also show

·         Can be run without UI: another assembly can call it to run tests

·         Can determine if it’s running 64 or 32:  IntPtr.Size=8 bytes on 64, 4 bytes on 32.

I’m thinking about adding a new 32 bit test case (for running in the VS IDE) that will launch all the 64 bit tests, or a new one for each of the 32 bit test cases, but that’s lower priority.

This new test host has already helped me find several 64 bit issues.

Follow my prior post: Use Visual Studio Test framework to create tests for your code to create a project.  (If you don’t have Fox or Excel, you can either get them or remove the Fox/Excel code in the test)

If you add these lines to the test

System.Diagnostics.Debug.WriteLine("Sizeof IntPtr = " + IntPtr.Size.ToString)

System.Diagnostics.Debug.WriteLine(System.Diagnostics.Process.GetCurrentProcess.MainModule.FileName)

You’ll get the output:

Sizeof IntPtr = 4

C:\Program Files (x86)\Microsoft Visual Studio 9.0\Common7\IDE\vstesthost.exe

Nothing unexpected. VSTestHost is a 32 bit EXE, which means only 32 bit code is run.

To make the test host more interesting, add a few more tests to the bottom of UnitTests1:

Shared oRandom As New Random

<TestMethod()> _

Sub EmptyTest()

End Sub

<TestMethod()> _

Sub AlwaysFail()

Assert.IsTrue(False, "True is never false!")

End Sub

<TestMethod()> _

Sub SometimesFail()

If oRandom.NextDouble < 0.4 Then

Assert.IsTrue(False, "True is never false!")

End If

End Sub

<TestMethod()> _

Sub RarelyFails()

If oRandom.NextDouble < 0.02 Then

Assert.IsTrue(False, "True is rarely false!")

End If

End Sub

To create the Test Host:

Right Click on the Solution from above in Solution explorer, choose Add->New Project. This time choose Windows->WPF Application. Put in a folder next to the folder of the existing test project. I called mine MyTestHost

Right Click on MyTestHost in solution explorer, choose Set As Startup Project. That way, hitting F5 will run this new project.

Delete the Window1.XAML in the solution explorer. We’ll create our own.

Delete MyTestHost->Application.xaml  (we have our own Sub Main)

Right Click on MyTestHost in solution explorer, choose Add New Item, Code->Class. Name it MyTestHost.vb

Right Click on MyTestHost in solution explorer, choose Add Existing Item, navigate to the UnitTest1.vb file in the other project. Make sure you add as a Lnked File. The “Add” button on the dialog has a little down arrow that allows you to choose Add As Link.

Note: the Fox code in the unit test TestMethod1 will fail in 64 because there is no 64 bit version of it.

Microsoft.VisualStudio.QualityTools.UnitTestFramework

System.Windows.Forms

There are 3 sections of code to paste below: Window1.XAML, Window1.XAML.VB (the code behind file), and MyTestHost.vb

Hit F5, click on the button  to run the tests.

You can force the Testmethod1 to fail simply by forcing Excel to close before it’s done.

<Window1.XAML code to paste>

<Window x:Class="Window1"

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

Title="Window1" Height="711" Width="1043">

<Grid DataContext="{Binding}">

<TextBlock Height="21" HorizontalAlignment="Right" Margin="0,12,16,0" Name="tbClock" VerticalAlignment="Top" Width="81" Text="{Binding Path=Clock}"/>

<ListView Margin="22,49,54,90" Name="ListView1" ItemsSource="{Binding Path=TestMethods}" >

<ListView.View>

<GridView >

<GridViewColumn>Selected

<GridViewColumn.CellTemplate>

<DataTemplate>

<CheckBox Name="ChkBox" IsChecked="{Binding Path=Selected}"></CheckBox>

</DataTemplate>

</GridViewColumn.CellTemplate>

</GridViewColumn>

<GridViewColumn>Status

<GridViewColumn.CellTemplate>

<DataTemplate>

<TextBlock Width="50" Text="{Binding Path=Status}"  Foreground="{Binding Path=StatusColor}"></TextBlock>

</DataTemplate>

</GridViewColumn.CellTemplate>

</GridViewColumn>

<GridViewColumn>TestName

<GridViewColumn.CellTemplate>

<DataTemplate>

<TextBlock Text="{Binding Path=TestName}"></TextBlock>

</DataTemplate>

</GridViewColumn.CellTemplate>

</GridViewColumn>

<GridViewColumn>Description

<GridViewColumn.CellTemplate>

<DataTemplate>

<TextBlock Text="{Binding Path=Description}"></TextBlock>

</DataTemplate>

</GridViewColumn.CellTemplate>

</GridViewColumn>

<GridViewColumn>TestClass

<GridViewColumn.CellTemplate>

<DataTemplate>

<TextBlock Text="{Binding Path=TestClass}"></TextBlock>

</DataTemplate>

</GridViewColumn.CellTemplate>

</GridViewColumn>

<GridViewColumn>mSecs

<GridViewColumn.CellTemplate>

<DataTemplate>

<TextBlock Text="{Binding Path=mSecs}" Width="40" HorizontalAlignment="Right"></TextBlock>

</DataTemplate>

</GridViewColumn.CellTemplate>

</GridViewColumn>

<GridViewColumn>ErrorMessage

<GridViewColumn.CellTemplate>

<DataTemplate>

<TextBlock Text="{Binding Path=ErrorMessage}" ToolTip="{Binding Path=ErrorMessage}"></TextBlock>

</DataTemplate>

</GridViewColumn.CellTemplate>

</GridViewColumn>

<GridViewColumn>Owner

<GridViewColumn.CellTemplate>

<DataTemplate>

<TextBlock Text="{Binding Path=Owner}"></TextBlock>

</DataTemplate>

</GridViewColumn.CellTemplate>

</GridViewColumn>

<GridViewColumn>Pri

<GridViewColumn.CellTemplate>

<DataTemplate>

<TextBlock Text="{Binding Path=Pri}"></TextBlock>

</DataTemplate>

</GridViewColumn.CellTemplate>

</GridViewColumn>

</GridView>

</ListView.View>

</ListView>

<Button Height="23" HorizontalAlignment="Left" Margin="22,0,0,35"

Name="btnSelectAll" VerticalAlignment="Bottom" Width="85" ButtonBase.Click="btnClicked">Select_All</Button>

<Button Height="23" HorizontalAlignment="Left" Margin="117,0,0,35"

Name="btnInvertSelection" VerticalAlignment="Bottom" Width="85" ButtonBase.Click="btnClicked">_InvertSelection</Button>

<CheckBox Height="16" HorizontalAlignment="Left" Margin="215,0,0,65"

Name="chkLoopForever" VerticalAlignment="Bottom" Width="120" IsEnabled="{Binding Path=NotIsTestRunning}">_LoopForever</CheckBox>

<Button Height="23" HorizontalAlignment="Left" Margin="215,0,0,35"

Name="btnRunSelected" VerticalAlignment="Bottom" ButtonBase.Click="btnClicked"  Width="85" IsEnabled="{Binding Path=NotIsTestRunning}">_RunSelected</Button>

<Button Height="23" HorizontalAlignment="Left" Margin="315,0,0,35"

Name="btnAbortRun" VerticalAlignment="Bottom" ButtonBase.Click="btnClicked" IsEnabled="{Binding Path=IsTestRunning}" Width="56.82">_AbortRun</Button>

<Button Height="23" HorizontalAlignment="Right" Margin="0,0,54,35"

Name="btnQuit" VerticalAlignment="Bottom" Width="85" ButtonBase.Click="btnClicked" IsCancel="True">_Quit</Button>

<ProgressBar Height="14" HorizontalAlignment="Right" Margin="0,0,16,0"

Name="ProgressBar1" VerticalAlignment="Top" Width="123"  />

</Grid>

</Window>

</Window1.XAML code to paste >

<Window1.XAML.vb code to paste >

Imports System.ComponentModel

Imports System.Collections.ObjectModel

Class Window1

Implements INotifyPropertyChanged   ' so XAML UI updates

Private m_SelectedTests As New Collection(Of TestItem)

Private m_StatusText As String

Private m_IsTestRunning As Boolean = False

Private m_Clock As String

Private m_nTestPass As Integer

Friend StopWatch As Diagnostics.Stopwatch

Public Property Clock() As String

Get

Return m_Clock

End Get

Set(ByVal value As String)

If m_Clock <> value Then

m_Clock = value

RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("Clock"))

End If

End Set

End Property

Public Property IsTestRunning() As Boolean

Get

Return m_IsTestRunning

End Get

Set(ByVal value As Boolean)

m_IsTestRunning = value

RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("IsTestRunning"))

RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("NotIsTestRunning"))

End Set

End Property

Public ReadOnly Property NotIsTestRunning() As Boolean

Get

Return Not m_IsTestRunning

End Get

End Property

Public Property StatusText() As String

Get

Return m_StatusText

End Get

Set(ByVal value As String)

Dim strTitle = "TestHost "

If IntPtr.Size > 4 Then

strTitle += "amd64 64 bit"

Else

strTitle += "x86 32 bit"

End If

strTitle += " Total Tests = " + TestMethods.Count.ToString

If m_nTestPass > 0 Then

strTitle += " Test Pass #" + m_nTestPass.ToString + " PeakWorkingSet =" + Process.GetCurrentProcess.PeakWorkingSet64.ToString("n0")

End If

m_StatusText = strTitle + " " + value

Me.Title = m_StatusText    ' in case of process crash, we can still see window title

RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("StatusText"))

End Set

End Property

Get

Return m_TestMethods

End Get

End Property

Sub New(ByVal TestMethods As ReadOnlyCollection(Of TestItem))

InitializeComponent()

m_TestMethods = TestMethods

StatusText = "" ' init window title

Me.ProgressBar1.Visibility = Windows.Visibility.Hidden

Me.ProgressBar1.Minimum = 0

Me.ProgressBar1.Maximum = 100

Me.ProgressBar1.Value = 0

Me.DataContext = Me ' so XAML can databind to our members

End Sub

Sub OnWindowClosed(ByVal sender As Object, ByVal e As EventArgs)

End Sub

Private Sub btnClicked(ByVal sender As System.Windows.Controls.Button, ByVal e As RoutedEventArgs)

Debug.WriteLine((New StackTrace).GetFrame(0).GetMethod.Name + " " + sender.Name)

Select Case CStr(sender.Name)

Case "btnSelectAll"

For Each lstItem In ListView1.Items

Dim tstItem = CType(lstItem, TestItem)

If Not tstItem.Selected Then

tstItem.Selected = True

End If

Next

Case "btnInvertSelection"

For Each lstItem In ListView1.Items

Dim tstItem = CType(lstItem, TestItem)

tstItem.Selected = Not tstItem.Selected

Next

Case "btnRunSelected"

m_SelectedTests.Clear()

m_nTestPass = 1

For Each lstItem In ListView1.Items ' Get the user selected items in display order

Dim tstItem = CType(lstItem, TestItem)

tstItem.Reset() ' reset all to not run yet (doesn't reset checkbox)

If tstItem.Selected Then

tstItem.Status = TestItem.TstStatus.Pending

End If

Next

If Me.chkLoopForever.IsChecked Then

Do While True

DoRunSelected()

For Each lstItem In ListView1.Items

Dim tstItem = CType(lstItem, TestItem)

If tstItem.Status = TestItem.TstStatus.Aborted OrElse tstItem.Status = TestItem.TstStatus.Failed Then

Me.StatusText = String.Format(" Failed  {0}", DateTime.Now.ToString)

Exit Do

End If

tstItem.Reset()

Next

m_nTestPass += 1

Loop

Else

DoRunSelected()

End If

Case "btnAbortRun"

TestItem.ShutDown()

For Each tstItem In m_SelectedTests

If tstItem.Status = TestItem.TstStatus.Pending Then

tstItem.Status = TestItem.TstStatus.NotRun

End If

Next

Case "btnQuit"

TestItem.ShutDown()

Me.Close()

Case Else

Debug.Assert(False, "Unhandled button")

End Select

End Sub

Private Sub DoRunSelected()

IsTestRunning = True

Dim nTestsRun = 0

Dim nTestsFailed = 0

StopWatch = Diagnostics.Stopwatch.StartNew

Me.StatusText = String.Format("{0} Test run ({1}/{2}) ", DateTime.Now.ToString, nTestsRun, m_SelectedTests.Count)

Try

For Each lstItem In ListView1.Items

Dim tstItem = CType(lstItem, TestItem)

If tstItem.Selected Then

Me.ProgressBar1.Visibility = Windows.Visibility.Visible

tstItem.RunTest(Me)   ' actually run the test

Me.ProgressBar1.Visibility = Windows.Visibility.Hidden

nTestsRun += 1

If tstItem.Status = TestItem.TstStatus.Failed Then

nTestsFailed += 1

End If

Me.StatusText = String.Format("{0} Test run {1}/{2}  #Failed = {3}", DateTime.Now.ToString, nTestsRun, m_SelectedTests.Count, nTestsFailed)

If tstItem.Status = TestItem.TstStatus.Aborted Then

Exit For

End If

End If

Next

Catch ex As Exception

End Try

Me.StatusText = String.Format("  Done: {0:f2} secs", StopWatch.ElapsedMilliseconds / 1000)

IsTestRunning = False

End Sub

Private Sub ListBox1_KeyUp(ByVal sender As Object, ByVal args As System.Windows.Input.KeyEventArgs) Handles ListView1.KeyUp

If args.Key = Key.Space Then

Dim lb As System.Windows.Controls.ListBox = CType(sender, System.Windows.Controls.ListBox)

If lb.SelectedIndex >= 0 Then

Dim lbi = CType(lb.ItemContainerGenerator.ContainerFromIndex(lb.SelectedIndex), System.Windows.Controls.ListBoxItem)

If lbi IsNot Nothing Then

Dim tstItem = CType(lbi.Content, TestItem)

tstItem.Selected = Not tstItem.Selected

End If

End If

End If

End Sub

'see http://blogs.msdn.com/calvin_hsia/archive/2007/11/29/6600915.aspx

Dim m_LastDir As System.ComponentModel.ListSortDirection = System.ComponentModel.ListSortDirection.Ascending

Private Sub OnHeaderClicked(ByVal sender As Object, ByVal e As RoutedEventArgs)

Dim direction = System.ComponentModel.ListSortDirection.Ascending

If gvHdr IsNot Nothing AndAlso gvHdr.Column IsNot Nothing Then

Dim hdr As String

If m_LastDir = System.ComponentModel.ListSortDirection.Ascending Then

direction = System.ComponentModel.ListSortDirection.Descending

End If

End If

Sort(hdr, direction)

m_LastDir = direction

End If

End If

End Sub

Private Sub Sort(ByVal sortby As String, ByVal dir As System.ComponentModel.ListSortDirection)

Me.ListView1.Items.SortDescriptions.Clear()

Dim sd = New System.ComponentModel.SortDescription(sortby, dir)

Me.ListView1.Items.Refresh()

End Sub

Public Event PropertyChanged(ByVal sender As Object, ByVal e As System.ComponentModel.PropertyChangedEventArgs) _

Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged

End Class

</Window1.XAML.vb code to paste >

<MyTestHost.vb code to paste >

Imports System.Reflection

Imports System.Windows

Imports System.Collections.ObjectModel

Imports System.Windows.Controls

Imports System.ComponentModel

Imports Microsoft.VisualStudio.TestTools.UnitTesting

Public Class MyTestHost

Private Shared m_TestMethods As ReadOnlyCollection(Of TestItem)

Shared Sub Main()

m_TestMethods = GetTestMethods()

If System.Environment.GetCommandLineArgs.Count > 1 Then ' arg 0 is the fullpath name of the app

Dim testname = System.Environment.GetCommandLineArgs(1)

Else

' show UI

Dim wpfApplicationWindow As System.Windows.Window = New Window1(m_TestMethods)

wpfApplicationWindow.ShowDialog()

End If

End Sub

Public Shared Function GetTestMethods() As ReadOnlyCollection(Of TestItem)  ' can be called from other assemblies

Dim retval As New Collection(Of TestItem)

Dim MyAsm = Assembly.GetExecutingAssembly

Dim TestClasses = From typ In MyAsm.GetTypes Where typ.GetCustomAttributes(GetType(TestClassAttribute), True).Length > 0

For Each TestClassName In TestClasses

Debug.WriteLine("Test class " + TestClassName.Name)

Dim TestClassInstance = MyAsm.CreateInstance(TestClassName.FullName)

Dim TestMethods = From meth In TestClassInstance.GetType.GetMethods _

Where meth.GetCustomAttributes(GetType(TestMethodAttribute), True).Length > 0 _

AndAlso Not meth.GetCustomAttributes(GetType(IgnoreAttribute), True).Length > 0

Debug.WriteLine("Count=" + TestMethods.Count.ToString)

' you can define your own TestContext class

'Dim tstContext = New VBTest64TestContext

'Dim TestContext_Property As PropertyInfo = TestClassInstance.GetType.GetProperty("TestContext")

'If TestContext_Property IsNot Nothing Then

'    TestContext_Property.SetValue(TestClassInstance, tstContext, BindingFlags.SetProperty, Nothing, Nothing, Nothing)

'End If

Dim TestInitialize_method As MethodInfo = TestClassInstance.GetType.GetMethod("TestInitialize")

Dim TestCleanup_method As MethodInfo = TestClassInstance.GetType.GetMethod("TestCleanup")

For Each meth In TestMethods ' In From dd In meths Where dd.Name.StartsWith("PepperQu")

Debug.WriteLine(meth.Name)

Dim TestDesc = ""

Dim TestOwner = ""

Dim TestPriority = ""

Dim Tmp = meth.GetCustomAttributes(GetType(Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute), True)

If Tmp.Length > 0 Then

TestDesc = CType(Tmp(0), Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute).Description

End If

Tmp = meth.GetCustomAttributes(GetType(OwnerAttribute), True)

If Tmp.Length > 0 Then

TestOwner = CType(Tmp(0), OwnerAttribute).Owner

End If

Tmp = meth.GetCustomAttributes(GetType(PriorityAttribute), True)

If Tmp.Length > 0 Then

TestPriority = CType(Tmp(0), PriorityAttribute).Priority.ToString

End If

TestOwner, TestPriority, meth, _

TestClassInstance, TestInitialize_method, TestCleanup_method))

Next

Next

End Function

End Class

Public Class TestItem

Implements INotifyPropertyChanged

Enum TstStatus

Idle

Pending

Running

Passed

Aborted

NotRun

Failed

End Enum

Private m_TestName As String

Private m_TestClass As String

Private m_Description As String

Private m_TestOwner As String

Private m_TestPriority As String

Private m_Selected As Boolean = True  ' default to checkbox selected

Private m_TestStatus As TstStatus = TstStatus.Idle

Private m_TestInitialize_method As MethodInfo

Private m_TestCleanup_method As MethodInfo

Private m_TestMethodInfo As MethodInfo  ' the actual test to run

Private m_TestClassInstance As Object

Private m_ElapsedTime As String

Private m_ErrorMessage As String

Private m_Stopwatch As Diagnostics.Stopwatch

Sub New(ByVal TestName As String, ByVal TestClass As String, ByVal testDesc As String, _

ByVal TestOwner As String, ByVal TestPriority As String, _

ByVal meth As MethodInfo, ByVal TestClassInstance As Object, _

ByVal TestInitialize_method As MethodInfo, ByVal TestCleanup_method As MethodInfo)

m_TestName = TestName

m_TestClass = TestClass

m_Description = testDesc

m_TestOwner = TestOwner

m_TestPriority = TestPriority

m_TestMethodInfo = meth

m_TestInitialize_method = TestInitialize_method

m_TestCleanup_method = TestCleanup_method

m_TestClassInstance = TestClassInstance

End Sub

Shared Sub ShutDown()

System.Windows.Forms.Application.DoEvents()

Loop

End If

End Sub

m_Stopwatch = Stopwatch.StartNew

Dim stat As TstStatus = TstStatus.Running

Status = TstStatus.Running

Dim fDidRunCleanup = False

Debug.WriteLine(TestName)

Try

If m_TestInitialize_method IsNot Nothing Then

m_TestInitialize_method.Invoke(m_TestClassInstance, BindingFlags.InvokeMethod, Nothing, Nothing, Nothing)

End If

' run the test

m_TestMethodInfo.Invoke(m_TestClassInstance, Reflection.BindingFlags.InvokeMethod, Nothing, Nothing, Nothing)

If m_TestCleanup_method IsNot Nothing Then

m_TestCleanup_method.Invoke(m_TestClassInstance, BindingFlags.InvokeMethod, Nothing, Nothing, Nothing)

fDidRunCleanup = True

End If

stat = TstStatus.Passed

If Not fDidRunCleanup Then

If m_TestCleanup_method IsNot Nothing Then

m_TestCleanup_method.Invoke(m_TestClassInstance, BindingFlags.InvokeMethod, Nothing, Nothing, Nothing)

fDidRunCleanup = True

End If

End If

Status = TstStatus.Aborted

ErrorMessage = "User aborted test run"

Throw ex

End If

Debug.WriteLine(String.Format("Got exception {0} {1}", m_TestMethodInfo.Name, ex.InnerException.Message))

ErrorMessage = ex.InnerException.Message

stat = TstStatus.Failed

End Try

Me.Status = stat

mSecs = m_Stopwatch.ElapsedMilliseconds.ToString

m_Stopwatch.Stop()

Debug.WriteLine(TestName + " Done")

End Sub

End Sub

Friend Sub RunTest(ByVal mWindow As Window1)

If mWindow IsNot Nothing Then

Dim pbar As ProgressBar = mWindow.ProgressBar1

pbar.Value = DateTime.Now.Millisecond / 10

mWindow.Clock = (mWindow.StopWatch.ElapsedMilliseconds / 1000).ToString("f1")

End If

System.Windows.Forms.Application.DoEvents()

Loop

End Sub

Public Sub Reset()

mSecs = ""

ErrorMessage = ""

Status = TstStatus.Idle

End Sub

Public Property ErrorMessage() As String

Get

Return m_ErrorMessage

End Get

Set(ByVal value As String)

m_ErrorMessage = value

RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("ErrorMessage"))

End Set

End Property

Public Property mSecs() As String

Get

Return m_ElapsedTime

End Get

Set(ByVal value As String)

m_ElapsedTime = value

RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("mSecs"))

End Set

End Property

Public Property Status() As TstStatus

Get

Return m_TestStatus

End Get

Set(ByVal value As TstStatus)

If value <> m_TestStatus Then

m_TestStatus = value

RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("Status"))

RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("StatusColor"))

End If

End Set

End Property

Public ReadOnly Property StatusColor() As String

Get

Select Case m_TestStatus

Case TstStatus.Failed

Return "Red"

Case TstStatus.Idle

Return "LightBlue"

Case TstStatus.Pending

Return "Purple"

Case TstStatus.Aborted

Return "Red"

Case TstStatus.Passed

Return "Green"

Case TstStatus.NotRun

Return "Black"

Case Else

Return "Blue"

End Select

End Get

End Property

Public ReadOnly Property TestName() As String

Get

Return m_TestName

End Get

End Property

Public ReadOnly Property TestClass() As String

Get

Return m_TestClass

End Get

End Property

Public ReadOnly Property Description() As String

Get

Return m_Description

End Get

End Property

Public ReadOnly Property Owner() As String

Get

Return m_TestOwner

End Get

End Property

Public ReadOnly Property Pri() As String

Get

Return m_TestPriority

End Get

End Property

Public Property Selected() As Boolean

Get

Return m_Selected

End Get

Set(ByVal value As Boolean)

m_Selected = value

RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("Selected"))

End Set

End Property

Public Overrides Function ToString() As String

End Function

Public Event PropertyChanged(ByVal sender As Object, ByVal e As PropertyChangedEventArgs) Implements INotifyPropertyChanged.PropertyChanged

End Class

</MyTestHost.vb code to paste >

End of blog entry