source: git/libpolys/tests/cxxtest/Win32Gui.h @ 405407

spielwiese
Last change on this file since 405407 was 4aa8610, checked in by Mohamed Barakat <mohamed.barakat@…>, 13 years ago
created libpolys/tests and set up the beginning of a test-suite using cxxtest
  • Property mode set to 100644
File size: 16.1 KB
Line 
1#ifndef __cxxtest__Win32Gui_h__
2#define __cxxtest__Win32Gui_h__
3
4//
5// The Win32Gui displays a simple progress bar using the Win32 API.
6//
7// It accepts the following command line options:
8//   -minimized    Start minimized, pop up on error
9//   -keep         Don't close the window at the end
10//   -title TITLE  Set the window caption
11//
12// If both -minimized and -keep are specified, GUI will only keep the
13// window if it's in focus.
14//
15// N.B. If you're wondering why this class doesn't use any standard
16// library or STL (<string> would have been nice) it's because it only
17// uses "straight" Win32 API.
18//
19
20#include <cxxtest/Gui.h>
21
22#include <windows.h>
23#include <commctrl.h>
24
25namespace CxxTest
26{
27    class Win32Gui : public GuiListener
28    {
29    public:
30        void enterGui( int &argc, char **argv )
31        {
32            parseCommandLine( argc, argv );
33        }
34       
35        void enterWorld( const WorldDescription &wd )
36        {
37            getTotalTests( wd );
38            _testsDone = 0;
39            startGuiThread();
40        }
41
42        void guiEnterSuite( const char *suiteName )
43        {
44            showSuiteName( suiteName );
45            reset( _suiteStart );
46        }
47
48        void guiEnterTest( const char *suiteName, const char *testName )
49        {
50            ++ _testsDone;
51            setTestCaption( suiteName, testName );
52            showTestName( testName );
53            showTestsDone();
54            progressBarMessage( PBM_STEPIT );
55            reset( _testStart );
56        }
57
58        void yellowBar()
59        {
60            setColor( 255, 255, 0 );
61            setIcon( IDI_WARNING );
62            getTotalTests();
63        }
64       
65        void redBar()
66        {
67            if ( _startMinimized )
68                showMainWindow( SW_SHOWNORMAL );
69            setColor( 255, 0, 0 );
70            setIcon( IDI_ERROR );
71            getTotalTests();
72        }
73
74        void leaveGui()
75        {
76            if ( keep() )
77            {
78                showSummary();
79                WaitForSingleObject( _gui, INFINITE );
80            }
81            DestroyWindow( _mainWindow );
82        }
83
84    private:
85        const char *_title;
86        bool _startMinimized, _keep;
87        HANDLE _gui;
88        WNDCLASSEX _windowClass;
89        HWND _mainWindow, _progressBar, _statusBar;
90        HANDLE _canStartTests;
91        unsigned _numTotalTests, _testsDone;
92        char _strTotalTests[WorldDescription::MAX_STRLEN_TOTAL_TESTS];
93        enum { 
94            STATUS_SUITE_NAME, STATUS_SUITE_TIME,
95            STATUS_TEST_NAME, STATUS_TEST_TIME,
96            STATUS_TESTS_DONE, STATUS_WORLD_TIME,
97            STATUS_TOTAL_PARTS
98        };
99        int _statusWidths[STATUS_TOTAL_PARTS];
100        unsigned _statusOffsets[STATUS_TOTAL_PARTS];
101        unsigned _statusTotal;
102        char _statusTestsDone[sizeof("1000000000 of  (100%)") + WorldDescription::MAX_STRLEN_TOTAL_TESTS];
103        DWORD _worldStart, _suiteStart, _testStart;
104        char _timeString[sizeof("00:00:00")];
105
106        void parseCommandLine( int argc, char **argv )
107        {
108            _startMinimized = _keep = false;
109            _title = argv[0];
110           
111            for ( int i = 1; i < argc; ++ i )
112            {
113                if ( !lstrcmpA( argv[i], "-minimized" ) )
114                    _startMinimized = true;
115                else if ( !lstrcmpA( argv[i], "-keep" ) )
116                    _keep = true;
117                else if ( !lstrcmpA( argv[i], "-title" ) && (i + 1 < argc) )
118                    _title = argv[++i];
119            }
120        }
121       
122        void getTotalTests()
123        {
124            getTotalTests( tracker().world() );
125        }
126
127        void getTotalTests( const WorldDescription &wd )
128        {
129            _numTotalTests = wd.numTotalTests();
130            wd.strTotalTests( _strTotalTests );
131        }
132
133        void startGuiThread()
134        {
135            _canStartTests = CreateEvent( NULL, TRUE, FALSE, NULL );
136                        DWORD threadId;
137            _gui = CreateThread( NULL, 0, &(Win32Gui::guiThread), (LPVOID)this, 0, &threadId );
138            WaitForSingleObject( _canStartTests, INFINITE );
139        }
140
141        static DWORD WINAPI guiThread( LPVOID parameter )
142        {
143            ((Win32Gui *)parameter)->gui();
144            return 0;
145        }
146
147        void gui()
148        {
149            registerWindowClass();
150            createMainWindow();
151            initCommonControls();
152            createProgressBar();
153            createStatusBar();
154            centerMainWindow();
155            showMainWindow();
156            startTimer();
157            startTests();
158
159            messageLoop();
160        }
161
162        void registerWindowClass()
163        {
164            _windowClass.cbSize = sizeof(_windowClass);
165            _windowClass.style = CS_HREDRAW | CS_VREDRAW;
166            _windowClass.lpfnWndProc = &(Win32Gui::windowProcedure);
167            _windowClass.cbClsExtra = 0;
168            _windowClass.cbWndExtra = sizeof(LONG);
169            _windowClass.hInstance = (HINSTANCE)NULL;
170            _windowClass.hIcon = (HICON)NULL;
171            _windowClass.hCursor = (HCURSOR)NULL;
172            _windowClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
173            _windowClass.lpszMenuName = NULL;
174            _windowClass.lpszClassName = TEXT("CxxTest Window Class");
175            _windowClass.hIconSm = (HICON)NULL;
176
177            RegisterClassEx( &_windowClass );
178        }
179
180        void createMainWindow()
181        {
182            _mainWindow = createWindow( _windowClass.lpszClassName, WS_OVERLAPPEDWINDOW );
183        }
184
185        void initCommonControls()
186        {
187            HMODULE dll = LoadLibraryA( "comctl32.dll" );
188            if ( !dll )
189                return;
190               
191            typedef void (WINAPI *FUNC)( void );
192            FUNC func = (FUNC)GetProcAddress( dll, "InitCommonControls" );
193            if ( !func )
194                return;
195
196            func();
197        }
198
199        void createProgressBar()
200        {
201            _progressBar = createWindow( PROGRESS_CLASS, WS_CHILD | WS_VISIBLE | PBS_SMOOTH, _mainWindow );
202
203#ifdef PBM_SETRANGE32
204            progressBarMessage( PBM_SETRANGE32, 0, _numTotalTests );
205#else // No PBM_SETRANGE32, use PBM_SETRANGE
206            progressBarMessage( PBM_SETRANGE, 0, MAKELPARAM( 0, (WORD)_numTotalTests ) );
207#endif // PBM_SETRANGE32
208            progressBarMessage( PBM_SETPOS, 0 );
209            progressBarMessage( PBM_SETSTEP, 1 );
210            greenBar();
211            UpdateWindow( _progressBar );
212        }
213
214        void createStatusBar()
215        {
216            _statusBar = createWindow( STATUSCLASSNAME, WS_CHILD | WS_VISIBLE, _mainWindow );
217            setRatios( 4, 1, 3, 1, 3, 1 );
218        }
219
220        void setRatios( unsigned suiteNameRatio, unsigned suiteTimeRatio,
221                        unsigned testNameRatio, unsigned testTimeRatio,
222                        unsigned testsDoneRatio, unsigned worldTimeRatio )
223        {
224            _statusTotal = 0;
225            _statusOffsets[STATUS_SUITE_NAME] = (_statusTotal += suiteNameRatio);
226            _statusOffsets[STATUS_SUITE_TIME] = (_statusTotal += suiteTimeRatio);
227            _statusOffsets[STATUS_TEST_NAME] = (_statusTotal += testNameRatio);
228            _statusOffsets[STATUS_TEST_TIME] = (_statusTotal += testTimeRatio);
229            _statusOffsets[STATUS_TESTS_DONE] = (_statusTotal += testsDoneRatio);
230            _statusOffsets[STATUS_WORLD_TIME] = (_statusTotal += worldTimeRatio);
231        }
232
233        HWND createWindow( LPCTSTR className, DWORD style, HWND parent = (HWND)NULL )
234        {
235            return CreateWindow( className, NULL, style, 0, 0, 0, 0, parent,
236                                 (HMENU)NULL, (HINSTANCE)NULL, (LPVOID)this );
237        }
238
239        void progressBarMessage( UINT message, WPARAM wParam = 0, LPARAM lParam = 0 )
240        {
241            SendMessage( _progressBar, message, wParam, lParam );
242        }
243
244        void centerMainWindow()
245        {
246            RECT screen;
247            getScreenArea( screen );
248
249            LONG screenWidth = screen.right - screen.left;
250            LONG screenHeight = screen.bottom - screen.top;
251
252            LONG xCenter = (screen.right + screen.left) / 2;
253            LONG yCenter = (screen.bottom + screen.top) / 2;
254
255            LONG windowWidth = (screenWidth * 4) / 5;
256            LONG windowHeight = screenHeight / 10;
257            LONG minimumHeight = 2 * (GetSystemMetrics( SM_CYCAPTION ) + GetSystemMetrics( SM_CYFRAME ));
258            if ( windowHeight < minimumHeight )
259                windowHeight = minimumHeight;
260
261            SetWindowPos( _mainWindow, HWND_TOP,
262                          xCenter - (windowWidth / 2), yCenter - (windowHeight / 2),
263                          windowWidth, windowHeight, 0 );
264        }
265
266        void getScreenArea( RECT &area )
267        {
268            if ( !getScreenAreaWithoutTaskbar( area ) )
269                getWholeScreenArea( area );
270        }
271
272        bool getScreenAreaWithoutTaskbar( RECT &area )
273        {
274            return (SystemParametersInfo( SPI_GETWORKAREA, sizeof(RECT), &area, 0 ) != 0);
275        }
276
277        void getWholeScreenArea( RECT &area )
278        {
279            area.left = area.top = 0;
280            area.right = GetSystemMetrics( SM_CXSCREEN );
281            area.bottom = GetSystemMetrics( SM_CYSCREEN );
282        }
283
284        void showMainWindow()
285        {
286            showMainWindow( _startMinimized ? SW_MINIMIZE : SW_SHOWNORMAL );
287            UpdateWindow( _mainWindow );
288        }
289
290        void showMainWindow( int mode )
291        {
292            ShowWindow( _mainWindow, mode );
293        }
294
295        enum { TIMER_ID = 1, TIMER_DELAY = 1000 };
296
297        void startTimer()
298        {
299            reset( _worldStart );
300            reset( _suiteStart );
301            reset( _testStart );
302            SetTimer( _mainWindow, TIMER_ID, TIMER_DELAY, 0 );
303        }
304
305        void reset( DWORD &tick )
306        {
307            tick = GetTickCount();
308        }
309
310        void startTests()
311        {
312            SetEvent( _canStartTests );
313        }
314
315        void messageLoop()
316        {
317            MSG message;
318            while ( BOOL haveMessage = GetMessage( &message, NULL, 0, 0 ) )
319                if ( haveMessage != -1 )
320                    DispatchMessage( &message );
321        }
322
323        static LRESULT CALLBACK windowProcedure( HWND window, UINT message, WPARAM wParam, LPARAM lParam )
324        {
325            if ( message == WM_CREATE )
326                setUp( window, (LPCREATESTRUCT)lParam );
327
328            Win32Gui *that = (Win32Gui *)GetWindowLong( window, GWL_USERDATA );
329            return that->handle( window, message, wParam, lParam );
330        }
331
332        static void setUp( HWND window, LPCREATESTRUCT create )
333        {
334            SetWindowLong( window, GWL_USERDATA, (LONG)create->lpCreateParams );
335        }
336
337        LRESULT handle( HWND window, UINT message, WPARAM wParam, LPARAM lParam )
338        {
339            switch ( message )
340            {
341            case WM_SIZE: resizeControls(); break;
342
343            case WM_TIMER: updateTime(); break;
344
345            case WM_CLOSE:
346            case WM_DESTROY:
347            case WM_QUIT:
348                ExitProcess( 0 );
349
350            default: return DefWindowProc( window, message, wParam, lParam );
351            }
352            return 0;
353        }
354
355        void resizeControls()
356        {
357            RECT r;
358            GetClientRect( _mainWindow, &r );
359            LONG width = r.right - r.left;
360            LONG height = r.bottom - r.top;
361
362            GetClientRect( _statusBar, &r );
363            LONG statusHeight = r.bottom - r.top;
364            LONG resizeGripWidth = statusHeight;
365            LONG progressHeight = height - statusHeight;
366
367            SetWindowPos( _progressBar, HWND_TOP, 0, 0, width, progressHeight, 0 );
368            SetWindowPos( _statusBar, HWND_TOP, 0, progressHeight, width, statusHeight, 0 );
369            setStatusParts( width - resizeGripWidth );
370        }
371
372        void setStatusParts( LONG width )
373        {
374            for ( unsigned i = 0; i < STATUS_TOTAL_PARTS; ++ i )
375                _statusWidths[i] = (width * _statusOffsets[i]) / _statusTotal;
376
377            statusBarMessage( SB_SETPARTS, STATUS_TOTAL_PARTS, _statusWidths );
378        }
379
380        void statusBarMessage( UINT message, WPARAM wParam = 0, const void *lParam = 0 )
381        {
382            SendMessage( _statusBar, message, wParam, (LPARAM)lParam );
383        }
384
385        void greenBar()
386        {
387            setColor( 0, 255, 0 );
388            setIcon( IDI_INFORMATION );
389        }
390
391#ifdef PBM_SETBARCOLOR
392        void setColor( BYTE red, BYTE green, BYTE blue )
393        {
394            progressBarMessage( PBM_SETBARCOLOR, 0, RGB( red, green, blue ) );
395        }
396#else // !PBM_SETBARCOLOR
397        void setColor( BYTE, BYTE, BYTE ) 
398        {
399        }
400#endif // PBM_SETBARCOLOR
401
402        void setIcon( LPCTSTR icon )
403        {
404            SendMessage( _mainWindow, WM_SETICON, ICON_BIG, (LPARAM)loadStandardIcon( icon ) );
405        }
406
407        HICON loadStandardIcon( LPCTSTR icon )
408        {
409            return LoadIcon( (HINSTANCE)NULL, icon );
410        }
411
412        void setTestCaption( const char *suiteName, const char *testName )
413        {
414            setCaption( suiteName, "::", testName, "()" );
415        }
416
417        void setCaption( const char *a = "", const char *b = "", const char *c = "", const char *d = "" )
418        {
419            unsigned length = lstrlenA( _title ) + sizeof( " - " ) +
420                lstrlenA( a ) + lstrlenA( b ) + lstrlenA( c ) + lstrlenA( d );
421            char *name = allocate( length );
422            lstrcpyA( name, _title );
423            lstrcatA( name, " - " );
424            lstrcatA( name, a );
425            lstrcatA( name, b );
426            lstrcatA( name, c );
427            lstrcatA( name, d );
428            SetWindowTextA( _mainWindow, name );
429            deallocate( name );
430        }
431
432        void showSuiteName( const char *suiteName )
433        {
434            setStatusPart( STATUS_SUITE_NAME, suiteName );
435        }
436
437        void showTestName( const char *testName )
438        {
439            setStatusPart( STATUS_TEST_NAME, testName );
440        }
441
442        void showTestsDone()
443        {
444            wsprintfA( _statusTestsDone, "%u of %s (%u%%)",
445                       _testsDone, _strTotalTests,
446                       (_testsDone * 100) / _numTotalTests );
447            setStatusPart( STATUS_TESTS_DONE, _statusTestsDone );
448        }
449
450        void updateTime()
451        {
452            setStatusTime( STATUS_WORLD_TIME, _worldStart );
453            setStatusTime( STATUS_SUITE_TIME, _suiteStart );
454            setStatusTime( STATUS_TEST_TIME, _testStart );
455        }
456
457        void setStatusTime( unsigned part, DWORD start )
458        {
459            unsigned total = (GetTickCount() - start) / 1000;
460            unsigned hours = total / 3600;
461            unsigned minutes = (total / 60) % 60;
462            unsigned seconds = total % 60;
463
464            if ( hours )
465                wsprintfA( _timeString, "%u:%02u:%02u", hours, minutes, seconds );
466            else
467                wsprintfA( _timeString, "%02u:%02u", minutes, seconds );
468
469            setStatusPart( part, _timeString );
470        }
471
472        bool keep()
473        {
474            if ( !_keep )
475                return false;
476            if ( !_startMinimized )
477                return true;
478            return (_mainWindow == GetForegroundWindow());
479        }
480
481        void showSummary()
482        {
483            stopTimer();
484            setSummaryStatusBar();
485            setSummaryCaption();
486        }
487
488        void setStatusPart( unsigned part, const char *text )
489        {
490            statusBarMessage( SB_SETTEXTA, part, text );
491        }
492
493        void stopTimer()
494        {
495            KillTimer( _mainWindow, TIMER_ID );
496            setStatusTime( STATUS_WORLD_TIME, _worldStart );
497        }
498
499        void setSummaryStatusBar()
500        {
501            setRatios( 0, 0, 0, 0, 1, 1 );
502            resizeControls();
503       
504            const char *tests = (_numTotalTests == 1) ? "test" : "tests";
505            if ( tracker().failedTests() )
506                wsprintfA( _statusTestsDone, "Failed %u of %s %s",
507                          tracker().failedTests(), _strTotalTests, tests );
508            else
509                wsprintfA( _statusTestsDone, "%s %s passed", _strTotalTests, tests );
510
511            setStatusPart( STATUS_TESTS_DONE, _statusTestsDone );
512        }
513
514        void setSummaryCaption()
515        {
516            setCaption( _statusTestsDone );
517        }
518
519        char *allocate( unsigned length )
520        {
521            return (char *)HeapAlloc( GetProcessHeap(), 0, length );
522        }
523
524        void deallocate( char *data )
525        {
526            HeapFree( GetProcessHeap(), 0, data );
527        }
528    };
529};
530
531#endif // __cxxtest__Win32Gui_h__
Note: See TracBrowser for help on using the repository browser.