1 /*
2  *  BCUnit - A Unit testing framework library for C.
3  *  Copyright (C) 2001       Anil Kumar
4  *  Copyright (C) 2004-2006  Anil Kumar, Jerry St.Clair
5  *
6  *  This library is free software; you can redistribute it and/or
7  *  modify it under the terms of the GNU Library General Public
8  *  License as published by the Free Software Foundation; either
9  *  version 2 of the License, or (at your option) any later version.
10  *
11  *  This library is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  *  Library General Public License for more details.
15  *
16  *  You should have received a copy of the GNU Library General Public
17  *  License along with this library; if not, write to the Free Software
18  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20 
21 /*
22  *  Implementation of the Curses based Test Interface.
23  *
24  *  01/Nov/2001   Started Curses based interface for BCUnit. (AK)
25  *
26  *  04/Nov/2001   Added Scrolling Capability to the Details Window. (AK)
27  *
28  *  24/Nov/2001   Added List and Show Failure Capability to the Details Window.
29  *                Also added group initialization failure message handler. (AK)
30  *
31  *  09-Aug-2004   New interface, made all curses local functions static. (JDS)
32  *
33  *  30-Apr-2006   Suite/test selection is now by number rather than name.
34  *                Inactive suites/tests now reported.
35  *                Interface supports (de)activation of tests/suites.
36  *                Help function added for both menu levels.
37  *                Option menu added.  (JDS)
38  *
39  *  02-May-2006   Added internationalization hooks.  (JDS)
40  */
41 
42 /** @file
43  * Curses test interface with interactive output (implementation).
44  */
45 /** @addtogroup Curses
46  @{
47 */
48 
49 #include <stdlib.h>
50 #include <stdio.h>
51 #include <ctype.h>
52 #include <assert.h>
53 #include <string.h>
54 #include <curses.h>
55 
56 #include "BCUnit.h"
57 #include "TestDB.h"
58 #include "Util.h"
59 #include "TestRun.h"
60 #include "CUCurses.h"
61 #include "BCUnit_intl.h"
62 
63 /*=================================================================
64  *  Global / Static data definitions
65  *=================================================================*/
66 
67 /* Type Definitions */
68 
69 #ifndef false
70 #define false   (0)       /**< Local boolean definition for false. */
71 #endif
72 
73 #ifndef true
74 #define true  (~false)    /**< Local boolean definition for true. */
75 #endif
76 
77 /** Curses interface status flag. */
78 typedef enum
79 {
80   CONTINUE = 1,   /**< Continue processing commands in current menu. */
81   MOVE_UP,        /**< Move up to the previous menu. */
82   STOP            /**< Stop processing (user selected 'Quit'). */
83 } STATUS;
84 
85 /** Menu type. */
86 typedef enum
87 {
88   MAIN_MENU = 1,
89   GROUP_MENU
90 } MENU_TYPE;
91 
92 /** Pointers to curses interface windows. */
93 typedef struct
94 {
95   WINDOW* pMainWin;           /**< Main window. */
96   WINDOW* pTitleWin;          /**< Title window. */
97   WINDOW* pProgressWin;       /**< Progress bar window. */
98   WINDOW* pSummaryWin;        /**< Summary window. */
99   WINDOW* pRunSummaryWin;     /**< Run Summary window. */
100   WINDOW* pDetailsWin;        /**< Details window. */
101   WINDOW* pOptionsWin;        /**< Options window. */
102 } APPWINDOWS;
103 
104 /** Window elements. */
105 typedef struct
106 {
107   WINDOW*      pPad;          /**< Pointer to the pad. */
108   unsigned int uiRows;        /**< Number of rows in pad. */
109   unsigned int uiColumns;     /**< Number of columns in pad. */
110   unsigned int uiPadRow;      /**< Current pad row. */
111   unsigned int uiPadCol;      /**< Current pad column. */
112   unsigned int uiWinLeft;     /**< Left position of containing window. */
113   unsigned int uiWinTop;      /**< Top position of containing window. */
114   unsigned int uiWinRows;     /**< Number of rows in containing window. */
115   unsigned int uiWinColumns;  /**< Number of columns in containing window. */
116 } APPPAD;
117 
118 /*
119  * Constants definitions
120  */
121 /** Standard string length. */
122 #define STRING_LENGTH 128
123 /** String holding main menu run options. */
124 static const char* MAIN_OPTIONS =
125     N_("(R)un  (S)elect  (L)ist  (A)ctivate  (F)ailures  (O)ptions  (H)elp  (Q)uit");
126 /** String holding suite menu run options. */
127 static const char* SUITE_OPTIONS =
128     N_("(R)un  (S)elect  (L)ist  (A)ctivate  (F)ailures  (O)ptions  (H)elp  (U)p  (Q)uit");
129 
130 /*
131  * Color Pairs Initialized for the Various Parameter Display
132  */
133 static const int CLEAR_COLOR                = 1;  /**< Clear color.*/
134 static const int TITLE_COLOR                = 2;  /**< Title color.*/
135 static const int PROGRESS_BACKGROUND_COLOR  = 3;  /**< progress bar background color.*/
136 static const int PROGRESS_SUCCESS_COLOR     = 4;  /**< Progress bar success color.*/
137 static const int PROGRESS_FAILURE_COLOR     = 5;  /**< Progress bar failure color.*/
138 static const int MENU_COLOR                 = 6;  /**< Menu color.*/
139 
140 static const char* const f_szProgress = N_("Progress    "); /**< Text for progress bar. */
141 
142 static const char*  f_szOptions = NULL;         /**< String containing options. */
143 
144 static CU_pTest     f_pCurrentTest = NULL;      /**< Pointer to the test currently being run. */
145 static CU_pSuite    f_pCurrentSuite = NULL;     /**< Pointer to the suite currently being run. */
146 
147 static unsigned int f_uiTotalTests = 0;         /**< Number of tests in registered suites. */
148 static unsigned int f_uiTestsRun = 0;           /**< Number of tests actually run. */
149 static unsigned int f_uiTestsSkipped = 0;       /**< Number of tests skipped during run. */
150 static unsigned int f_uiTestsFailed = 0;        /**< Number of tests having failed assertions. */
151 static unsigned int f_uiTestsRunSuccessful = 0; /**< Number of tests run with no failed assertions. */
152 
153 static unsigned int f_uiTotalSuites = 0;        /**< Number of registered suites. */
154 static unsigned int f_uiSuitesSkipped = 0;      /**< Number of suites skipped during run. */
155 
156 static short f_nLeft;                           /**< Left window position. */
157 static short f_nTop;                            /**< Top window position. */
158 static short f_nWidth;                          /**< Width of window. */
159 static short f_nHeight;                         /**< Height of window. */
160 
161 /** Common width measurements for output formatting. */
162 static size_t f_yes_width = 0;
163 static size_t f_no_width = 0;
164 
165 /** Pointers to curses interface windows. */
166 static APPWINDOWS application_windows = {NULL, NULL, NULL, NULL, NULL, NULL, NULL};
167 /** Details window definition. */
168 static APPPAD  details_pad = {NULL, 0, 0, 0, 0, 0, 0, 0, 0};
169 
170 /*=================================================================
171  *  Static function forward declarations
172  *=================================================================*/
173 static bool initialize_windows(void);
174 static void uninitialize_windows(void);
175 
176 static void refresh_windows(void);
177 static void refresh_title_window(void);
178 static void refresh_progress_window(void);
179 static void refresh_summary_window(void);
180 static void refresh_run_summary_window(void);
181 static void refresh_details_window(void);
182 static void refresh_options_window(void);
183 static void show_detail_window_message(const char* msg);
184 
185 static bool create_pad(APPPAD* pPad, WINDOW* pParent, unsigned int uiRows, unsigned int uiCols);
186 static void scroll_window(int nCommand, APPPAD* pPad, void (*parent_refresh)(void));
187 
188 static bool test_initialize(void);
189 
190 static void show_progress_bar(void);
191 static const char* get_hotkey(const char* szStr, int* pPos);
192 static void read_input_string(const char szPropmt[], char szValue[], int nBytes);
193 
194 static STATUS curses_registry_level_run(CU_pTestRegistry pRegistry);
195 static STATUS curses_suite_level_run(CU_pSuite pSuite);
196 static STATUS curses_set_options_run(void);
197 
198 static CU_ErrorCode curses_run_all_tests(CU_pTestRegistry pRegistry);
199 static CU_ErrorCode curses_run_suite_tests(CU_pSuite pSuite);
200 static CU_ErrorCode curses_run_single_test(CU_pSuite pSuite, CU_pTest pTest);
201 
202 static void curses_test_start_message_handler(const CU_pTest pTest, const CU_pSuite pSuite);
203 static void curses_test_complete_message_handler(const CU_pTest pTest, const CU_pSuite pSuite,
204                                                  const CU_pFailureRecord pFailure);
205 static void curses_all_tests_complete_message_handler(const CU_pFailureRecord pFailure);
206 static void curses_suite_init_failure_message_handler(const CU_pSuite pSuite);
207 
208 static void list_suites(CU_pTestRegistry pRegistry);
209 static void list_tests(CU_pSuite pSuite);
210 static void show_failures(void);
211 static void show_registry_level_help(void);
212 static void show_suite_level_help(CU_pSuite pSuite);
213 
214 static void reset_run_parameters(void);
215 
216 /*=================================================================
217  *  Public Interface functions
218  *=================================================================*/
CU_curses_run_tests(void)219 void CU_curses_run_tests(void)
220 {
221   setvbuf(stdout, NULL, _IONBF, 0);
222   setvbuf(stderr, NULL, _IONBF, 0);
223 
224   f_szOptions = _(MAIN_OPTIONS);
225   if (!initialize_windows()) {
226     return;
227   }
228 
229   if (!test_initialize()) {
230     goto test_initialize_fail;
231   }
232 
233   f_yes_width = strlen(_("Yes"));
234   f_no_width  = strlen(_("No"));
235 
236   show_detail_window_message(_("Welcome to BCUnit.  Press the indicated key to run the command."));
237   curses_registry_level_run(CU_get_registry());
238 
239   /* fall thru */
240 
241 test_initialize_fail:
242   uninitialize_windows();
243 }
244 
245 /*=================================================================
246  *  Static function implementation
247  *=================================================================*/
248 /** Initialize the curses interface windows. */
initialize_windows(void)249 static bool initialize_windows(void)
250 {
251   bool bStatus = false;
252 
253   if (NULL == (application_windows.pMainWin = initscr())) {
254     goto main_fail;
255   }
256 
257   start_color();
258 
259   f_nLeft = application_windows.pMainWin->_begx;
260   f_nTop = application_windows.pMainWin->_begy;
261   f_nWidth = application_windows.pMainWin->_maxx;
262   f_nHeight = application_windows.pMainWin->_maxy;
263 
264   if (NULL == (application_windows.pTitleWin = newwin(3, f_nWidth, 0, 0))) {
265     goto title_fail;
266   }
267 
268   if (NULL == (application_windows.pProgressWin = newwin(2, f_nWidth, 3, 0))) {
269     goto progress_fail;
270   }
271 
272   if (NULL == (application_windows.pSummaryWin = newwin(1, f_nWidth, 5, 0))) {
273     goto summary_fail;
274   }
275 
276   if (NULL == (application_windows.pRunSummaryWin = newwin(1, f_nWidth, 6, 0))) {
277     goto run_summary_fail;
278   }
279 
280   if (NULL == (application_windows.pDetailsWin = newwin(f_nHeight - f_nTop - 7 , f_nWidth, 7, 0))) {
281     goto details_fail;
282   }
283 
284   if (NULL == (application_windows.pOptionsWin = newwin(1, f_nWidth, f_nHeight - f_nTop, 0))) {
285     goto option_fail;
286   }
287 
288   curs_set(0);
289   noecho();
290   cbreak();
291   keypad(application_windows.pMainWin, CU_TRUE);
292   init_pair(CLEAR_COLOR, COLOR_WHITE, COLOR_BLACK);
293   init_pair(TITLE_COLOR, COLOR_WHITE, COLOR_BLACK);
294   init_pair(PROGRESS_BACKGROUND_COLOR, COLOR_BLACK, COLOR_WHITE);
295   init_pair(PROGRESS_SUCCESS_COLOR, COLOR_WHITE, COLOR_GREEN);
296   init_pair(PROGRESS_FAILURE_COLOR, COLOR_WHITE, COLOR_RED);
297   init_pair(MENU_COLOR, COLOR_GREEN, COLOR_BLACK);
298 
299   refresh_windows();
300   bStatus = true;
301   goto main_fail;
302 
303   /*
304    * Error Handlers for all the stages.
305    */
306 option_fail:
307   delwin(application_windows.pDetailsWin);
308 
309 details_fail:
310   delwin(application_windows.pRunSummaryWin);
311 
312 run_summary_fail:
313   delwin(application_windows.pSummaryWin);
314 
315 summary_fail:
316   delwin(application_windows.pProgressWin);
317 
318 progress_fail:
319   delwin(application_windows.pTitleWin);
320 
321 title_fail:
322   endwin();
323 
324 main_fail:
325   return bStatus;
326 
327 }
328 
329 /*------------------------------------------------------------------------*/
330 /** Clean up and delete curses interface windows. */
uninitialize_windows(void)331 static void uninitialize_windows(void)
332 {
333   curs_set(1);
334   echo();
335   nocbreak();
336   keypad(application_windows.pMainWin, CU_FALSE);
337 
338   if (details_pad.pPad) {
339     delwin(details_pad.pPad);
340   }
341 
342   delwin(application_windows.pOptionsWin);
343   delwin(application_windows.pDetailsWin);
344   delwin(application_windows.pRunSummaryWin);
345   delwin(application_windows.pSummaryWin);
346   delwin(application_windows.pProgressWin);
347   delwin(application_windows.pTitleWin);
348 
349   clear();
350   refresh();
351   endwin();
352 }
353 
354 
355 /*------------------------------------------------------------------------*/
356 /** Refresh curses interface windows.  */
refresh_windows(void)357 static void refresh_windows(void)
358 {
359   refresh();
360 
361   f_nLeft = application_windows.pMainWin->_begx;
362   f_nTop = application_windows.pMainWin->_begy;
363   f_nWidth = application_windows.pMainWin->_maxx;
364   f_nHeight = application_windows.pMainWin->_maxy;
365 
366   refresh_title_window();
367   refresh_progress_window();
368   refresh_run_summary_window();
369   refresh_summary_window();
370   refresh_details_window();
371   refresh_options_window();
372 }
373 
374 /*------------------------------------------------------------------------*/
375 /** Refresh the title window. */
refresh_title_window(void)376 static void refresh_title_window(void)
377 {
378   char szPackageTitle[STRING_LENGTH];
379   char* szSite = N_("https://github.com/BelledonneCommunications/bcunit/");
380   static bool bFirstTime = true;
381 
382   if (!bFirstTime) {
383     bFirstTime = false;
384     return;
385   }
386 
387   snprintf(szPackageTitle, STRING_LENGTH,
388            "%s%s", _("BCUnit - A Unit testing framework for C - Version "), CU_VERSION);
389   wattrset(application_windows.pTitleWin, A_BOLD | COLOR_PAIR(TITLE_COLOR));
390   mvwprintw(application_windows.pTitleWin,
391             0, f_nLeft + (f_nWidth - strlen(szPackageTitle))/2,
392             "%s", szPackageTitle);
393 
394   wattrset(application_windows.pTitleWin, A_BOLD | A_UNDERLINE | COLOR_PAIR(TITLE_COLOR));
395   mvwprintw(application_windows.pTitleWin, 1, f_nLeft + (f_nWidth - strlen(_(szSite)))/2,
396             "%s", _(szSite));
397   wattrset(application_windows.pTitleWin, A_NORMAL);
398 
399   wrefresh(application_windows.pTitleWin);
400 }
401 
402 /*------------------------------------------------------------------------*/
403 /** Refresh the progress bar window. */
refresh_progress_window(void)404 static void refresh_progress_window(void)
405 {
406   wattrset(application_windows.pProgressWin, A_BOLD);
407   mvwprintw(application_windows.pProgressWin, 0, 1, (char *)_(f_szProgress));
408   show_progress_bar();
409   wrefresh(application_windows.pProgressWin);
410 }
411 
412 /*------------------------------------------------------------------------*/
413 /** Refresh the summary window. */
refresh_summary_window(void)414 static void refresh_summary_window(void)
415 {
416   char szTemp[STRING_LENGTH];
417 
418   memset(szTemp, 0, sizeof(szTemp));
419   snprintf(szTemp, STRING_LENGTH, _("Tests Run : %6u   Success : %6u   Failed : %6u"),
420                                   f_uiTestsRun, f_uiTestsRunSuccessful,
421                                   f_uiTestsRun - f_uiTestsRunSuccessful);
422   werase(application_windows.pSummaryWin);
423   mvwprintw(application_windows.pSummaryWin, 0, 1, "%s", szTemp);
424   wrefresh(application_windows.pSummaryWin);
425 }
426 
427 /*------------------------------------------------------------------------*/
428 /** Prints a custom message in the detail window. */
show_detail_window_message(const char * msg)429 static void show_detail_window_message(const char *msg)
430 {
431   if (NULL != msg) {
432 
433     if (!create_pad(&details_pad, application_windows.pDetailsWin, 1, 256)) {
434       return;
435     }
436 
437     assert(256 >= strlen(msg));
438     mvwprintw(details_pad.pPad, 0, 0, "%s", msg);
439     refresh_details_window();
440   }
441 }
442 
443 /*------------------------------------------------------------------------*/
444 /** Refresh the run summary window. */
refresh_run_summary_window(void)445 static void refresh_run_summary_window(void)
446 {
447   const char* szRunSummary = N_("Running test  \'%s\' of Suite \'%s\'");
448   char szTemp[STRING_LENGTH];
449 
450   if (f_pCurrentTest && f_pCurrentSuite) {
451     assert(NULL != f_pCurrentTest->pName);
452     assert(NULL != f_pCurrentSuite->pName);
453     snprintf(szTemp, STRING_LENGTH, _(szRunSummary),
454              f_pCurrentTest->pName, f_pCurrentSuite->pName);
455   }
456   else {
457     snprintf(szTemp, STRING_LENGTH, "%s", "");
458   }
459   werase(application_windows.pRunSummaryWin);
460   mvwprintw(application_windows.pRunSummaryWin, 0, 1, "%s", szTemp);
461   wrefresh(application_windows.pRunSummaryWin);
462 }
463 
464 /*------------------------------------------------------------------------*/
465 /** Refresh the details window. */
refresh_details_window(void)466 static void refresh_details_window(void)
467 {
468   const char* szDetailsTitle = N_(" Details Window ");
469 
470   box(application_windows.pDetailsWin, ACS_VLINE, ACS_HLINE);
471   mvwprintw(application_windows.pDetailsWin, 0,
472             f_nLeft + (f_nWidth - strlen(_(szDetailsTitle)))/2, "%s", _(szDetailsTitle));
473   scrollok(application_windows.pDetailsWin, CU_TRUE);
474   wrefresh(application_windows.pDetailsWin);
475 
476   if (details_pad.pPad) {
477     prefresh(details_pad.pPad, details_pad.uiPadRow, details_pad.uiPadCol,
478              details_pad.uiWinTop, details_pad.uiWinLeft,
479              details_pad.uiWinTop + details_pad.uiWinRows,
480              details_pad.uiWinLeft + details_pad.uiWinColumns);
481   }
482 }
483 
484 /*------------------------------------------------------------------------*/
485 /** Refresh the options window. */
refresh_options_window(void)486 static void refresh_options_window(void)
487 {
488   int nPos = 0;
489   const char* szHotKey = NULL;
490 
491   wclear(application_windows.pOptionsWin);
492   mvwprintw(application_windows.pOptionsWin, 0, 1, "%s", f_szOptions);
493 
494   get_hotkey(f_szOptions, NULL);
495   wattron(application_windows.pOptionsWin, A_BOLD);
496   while (NULL != (szHotKey = get_hotkey((const char*)NULL, &nPos))) {
497     mvwaddstr(application_windows.pOptionsWin, 0, nPos + 1, szHotKey);
498   }
499   wattroff(application_windows.pOptionsWin, A_BOLD);
500 
501   wrefresh(application_windows.pOptionsWin);
502 }
503 
504 /*------------------------------------------------------------------------*/
505 /** Show the progress bar window. */
show_progress_bar(void)506 static void show_progress_bar(void)
507 {
508   int nLength = 0;
509   int nIndex = 0;
510   int nStart = strlen(_(f_szProgress));
511   int nColorID = 0;
512 
513   if (0 == (f_uiTestsRun + f_uiTestsSkipped)) {
514     nLength = f_nWidth - f_nLeft - nStart - 6;
515     nColorID = PROGRESS_BACKGROUND_COLOR;
516   }
517   else {
518     nLength = (f_nWidth - f_nLeft - nStart - 6) * ((double)(f_uiTestsRun + f_uiTestsSkipped) / f_uiTotalTests);
519     nColorID = (!f_uiTestsSkipped && f_uiTestsRun == f_uiTestsRunSuccessful)
520             ? PROGRESS_SUCCESS_COLOR
521             : PROGRESS_FAILURE_COLOR;
522   }
523 
524   wattron(application_windows.pProgressWin, A_BOLD | COLOR_PAIR(nColorID));
525   for (nIndex = 0; nIndex < nLength; nIndex++) {
526     mvwprintw(application_windows.pProgressWin, 0, nStart + nIndex, " ");
527   }
528   wattroff(application_windows.pProgressWin, COLOR_PAIR(nColorID));
529 }
530 
531 /*------------------------------------------------------------------------*/
532 /** Initialize the message handlers in preparation for running tests. */
test_initialize(void)533 static bool test_initialize(void)
534 {
535   if (NULL == CU_get_registry()) {
536     return false;
537   }
538 
539   CU_set_test_start_handler(curses_test_start_message_handler);
540   CU_set_test_complete_handler(curses_test_complete_message_handler);
541   CU_set_all_test_complete_handler(curses_all_tests_complete_message_handler);
542   CU_set_suite_init_failure_handler(curses_suite_init_failure_message_handler);
543   return true;
544 }
545 
546 /*------------------------------------------------------------------------*/
547 /** Parse a string and return the coded hotkeys.
548  * If called with szStr non-NULL, the string is simply stored.
549  * Subsequent calls with szStr NULL will cause the
550  * hotkeys in the string (chars between parentheses) to
551  * be returned sequentially in the order in which they
552  * appear in the original string.
553  * @param szStr String to parse (non-NULL to set, NULL to parse).
554  * @param pPos  Used to store position of the next '('.
555  * @return If szStr is non-NULL, it is returned.  If szStr is NULL,
556  *         the next hotkey character is returned, or NULL if there
557  *         are no more hotkey characters in the original string.
558  */
get_hotkey(const char * szStr,int * pPos)559 static const char* get_hotkey(const char* szStr, int* pPos)
560 {
561   static char szTemp[128] = "";
562   static char szString[128] = "";
563   static int nPos = 0;
564 
565   int nTempIndex;
566   char* pS = NULL;
567 
568   if (szStr) {
569     nPos = 0;
570     strcpy(szString, szStr);
571     return szString;
572   }
573 
574   memset(szTemp, 0, sizeof(szTemp));
575   for (nTempIndex = 0, pS = szString + nPos; *pS; nPos++, pS++) {
576     if (!nTempIndex && '(' == *pS) {
577       szTemp[nTempIndex++] = *pS;
578       *pPos = nPos;
579     }
580     else if (nTempIndex && ')' == *pS) {
581       szTemp[nTempIndex++] = *pS;
582       szTemp[nTempIndex++] = '\0';
583       return szTemp;
584     }
585     else if (nTempIndex) {
586       szTemp[nTempIndex++] = *pS;
587     }
588   }
589 
590   return NULL;
591 }
592 
593 /*------------------------------------------------------------------------*/
594 /**
595  *  Main loop for curses interface.
596  *  Displays actions and responds based on user imput.
597  *  @param pRegistry The CU_pTestRegistry to use for testing.
598  *                   If NULL, uses the default registry.
599  */
curses_registry_level_run(CU_pTestRegistry pRegistry)600 static STATUS curses_registry_level_run(CU_pTestRegistry pRegistry)
601 {
602   char szSuiteNumber[STRING_LENGTH];
603   CU_pSuite pSuite = NULL;
604   bool bContinue = true;
605   char szTemp[STRING_LENGTH];
606   long suite_num;
607 
608   if (NULL == pRegistry) {
609     pRegistry = CU_get_registry();
610   }
611   assert(NULL != pRegistry);
612 
613   while (bContinue) {
614     int option = toupper(getch());
615 
616     if (option == _("R")[0]) {
617       curses_run_all_tests(pRegistry);
618     }
619 
620     else if (option == _("S")[0]) {
621       if (0 == pRegistry->uiNumberOfSuites) {
622         fprintf(stdout, "\n%s", _("No suites are registered."));
623       }
624       else {
625         list_suites(pRegistry);
626         snprintf(szTemp, STRING_LENGTH, _("Enter number of suite to select (1-%u) : "),
627                                         pRegistry->uiNumberOfSuites);
628         read_input_string(szTemp, szSuiteNumber, STRING_LENGTH);
629         refresh_details_window();
630         suite_num = atol(szSuiteNumber);
631         pSuite = CU_get_suite_by_index(suite_num, pRegistry);
632         if (NULL != pSuite) {
633           assert(NULL != pSuite->pName);
634           snprintf(szTemp, STRING_LENGTH, _("Suite '%s' selected."), pSuite->pName);
635           show_detail_window_message(szTemp);
636           if (STOP == curses_suite_level_run(pSuite)) {
637             bContinue = false;
638           }
639           f_szOptions = _(MAIN_OPTIONS);
640           refresh_options_window();
641         }
642         else {
643           show_detail_window_message(_("Suite not found."));
644         }
645       }
646     }
647 
648     else if (option == _("L")[0]) {
649       list_suites(pRegistry);
650     }
651 
652     else if (option == _("A")[0]) {
653       if (0 == pRegistry->uiNumberOfSuites) {
654         fprintf(stdout, "\n%s", _("No suites are registered."));
655       }
656       else {
657         while (1) {
658           list_suites(pRegistry);
659           snprintf(szTemp, STRING_LENGTH, _("Enter number of suite to select (1-%u) : "),
660                                           pRegistry->uiNumberOfSuites);
661           read_input_string(szTemp, szSuiteNumber, STRING_LENGTH);
662           refresh_details_window();
663           suite_num = atol(szSuiteNumber);
664           pSuite = CU_get_suite_by_index(suite_num, pRegistry);
665           if (NULL != pSuite) {
666             CU_set_suite_active(pSuite, (CU_FALSE == pSuite->fActive) ? CU_TRUE : CU_FALSE);
667           }
668           else {
669             break;
670           }
671         }
672         f_szOptions = _(MAIN_OPTIONS);
673         refresh_options_window();
674       }
675     }
676 
677     else if (option == _("F")[0]) {
678       show_failures();
679     }
680 
681     else if (option == _("O")[0]) {
682       curses_set_options_run();
683     }
684 
685     else if (option == _("Q")[0]) {
686       return bContinue = false;
687     }
688 
689     else if ((option == KEY_UP) ||
690              (option == KEY_DOWN) ||
691              (option == KEY_RIGHT) ||
692              (option == KEY_LEFT)) {
693       scroll_window(option, &details_pad, refresh_details_window);
694     }
695 
696     else if ((option == _("H")[0]) || (option == _("?")[0])) {
697       show_registry_level_help();
698     }
699   }
700 
701   return STOP;
702 }
703 
704 /*------------------------------------------------------------------------*/
705 /** Run a selected suite within the curses interface.
706  *  Displays actions and responds based on user imput.
707  *  @param pSuite The suite to use for testing (non-NULL).
708  */
curses_suite_level_run(CU_pSuite pSuite)709 static STATUS curses_suite_level_run(CU_pSuite pSuite)
710 {
711   char szTestNumber[STRING_LENGTH];
712   char szTemp[STRING_LENGTH];
713   CU_pTestRegistry pRegistry = CU_get_registry();
714   CU_pTest pTest = NULL;
715   long test_num;
716 
717   assert(NULL != pRegistry);
718   assert(NULL != pSuite);
719   assert(NULL != pSuite->pName);
720 
721   f_szOptions = _(SUITE_OPTIONS);
722   refresh_options_window();
723 
724   while (true) {
725     int option = toupper(getch());
726 
727     if (option == _("R")[0]) {
728       curses_run_suite_tests(pSuite);
729     }
730 
731     else if (option == _("S")[0]) {
732       if (0 == pSuite->uiNumberOfTests) {
733         snprintf(szTemp, STRING_LENGTH,
734                  _("Suite %s contains no tests."), pSuite->pName);
735         show_detail_window_message(szTemp);
736       }
737       else {
738         list_tests(pSuite);
739         snprintf(szTemp, STRING_LENGTH, "%s",
740                                         _("Enter number of test to select (1-%u) : "),
741                                         pRegistry->uiNumberOfSuites);
742         read_input_string(szTemp, szTestNumber, STRING_LENGTH);
743         test_num = atol(szTestNumber);
744         pTest = CU_get_test_by_index(test_num, pSuite);
745         if (NULL != pTest) {
746           curses_run_single_test(pSuite, pTest);
747         }
748         else {
749           show_detail_window_message(_("Test not found."));
750         }
751         refresh_details_window();
752       }
753     }
754 
755     else if (option == _("L")[0]) {
756       list_tests(pSuite);
757     }
758 
759     else if (option == _("F")[0]) {
760       show_failures();
761     }
762 
763     else if (option == _("A")[0]) {
764       if (0 == pSuite->uiNumberOfTests) {
765         snprintf(szTemp, STRING_LENGTH,
766                  _("Suite %s contains no tests."), pSuite->pName);
767         show_detail_window_message(szTemp);
768       }
769       else {
770         while (1) {
771           list_tests(pSuite);
772           snprintf(szTemp, STRING_LENGTH, "%s",
773                                           _("Enter number of test to select (1-%u) : "),
774                                           pRegistry->uiNumberOfSuites);
775           read_input_string(szTemp, szTestNumber, STRING_LENGTH);
776           test_num = atol(szTestNumber);
777           pTest = CU_get_test_by_index(test_num, pSuite);
778           if (NULL != pTest) {
779             CU_set_test_active(pTest, (CU_FALSE == pTest->fActive) ? CU_TRUE : CU_FALSE);
780           }
781           else {
782             break;
783           }
784         }
785         f_szOptions = _(SUITE_OPTIONS);
786         refresh_options_window();
787       }
788     }
789 
790     else if (option == _("O")[0]) {
791       curses_set_options_run();
792     }
793 
794     else if (option == _("U")[0]) {
795       return CONTINUE;
796     }
797 
798     else if (option == _("Q")[0]) {
799       return STOP;
800     }
801 
802     else if ((option == KEY_UP) ||
803              (option == KEY_DOWN) ||
804              (option == KEY_RIGHT) ||
805              (option == KEY_LEFT)) {
806       scroll_window(option, &details_pad, refresh_details_window);
807     }
808 
809     else if ((option == _("H")[0]) || (option == _("?")[0])) {
810       show_suite_level_help(pSuite);
811     }
812   }
813 
814   return CONTINUE;
815 }
816 
817 /*------------------------------------------------------------------------*/
818 /** Display a prompt, then read a string from the keyboard.
819  * @param szPrompt The prompt to display.
820  * @param szValue  The string in which to store the response.
821  * @param nBytes   The length of the szValue buffer.
822  */
read_input_string(const char szPrompt[],char szValue[],int nBytes)823 static void read_input_string(const char szPrompt[], char szValue[], int nBytes)
824 {
825   echo();
826   curs_set(1);
827   nocbreak();
828 
829   wclear(application_windows.pOptionsWin);
830   mvwprintw(application_windows.pOptionsWin, 0, 1, "%s", szPrompt);
831   wgetnstr(application_windows.pOptionsWin, szValue, nBytes - 1);
832   refresh_options_window();
833 
834   cbreak();
835   curs_set(0);
836   noecho();
837 }
838 
839 /*------------------------------------------------------------------------*/
840 /** Scroll a window.
841  * @param nCommand       Code for the direction to scroll.
842  * @param pPad           The window to scroll.
843  * @param parent_refresh Function to call to refresh the parent window.
844  */
scroll_window(int nCommand,APPPAD * pPad,void (* parent_refresh)(void))845 static void scroll_window(int nCommand, APPPAD* pPad, void (*parent_refresh)(void))
846 {
847   if (NULL == pPad->pPad) {
848     return;
849   }
850 
851   switch (nCommand) {
852     case KEY_UP:
853       if (pPad->uiPadRow) {
854         --pPad->uiPadRow;
855         (*parent_refresh)();
856       }
857       break;
858 
859     case KEY_DOWN:
860       if (pPad->uiRows - 1 > pPad->uiPadRow + pPad->uiWinRows) {
861         ++pPad->uiPadRow;
862         (*parent_refresh)();
863       }
864       break;
865 
866     case KEY_LEFT:
867       if (pPad->uiPadCol) {
868         --pPad->uiPadCol;
869         (*parent_refresh)();
870       }
871       break;
872 
873     case KEY_RIGHT:
874       if (details_pad.uiColumns - 1 > details_pad.uiPadCol + details_pad.uiWinColumns) {
875         ++pPad->uiPadCol;
876         (*parent_refresh)();
877       }
878       break;
879 
880     default:
881       break;
882   }
883 }
884 
885 /*------------------------------------------------------------------------*/
886 /** Create a window having specified parent and dimensions.
887  * @param pPad    Pointer to the new window.
888  * @param pParent Parent window.
889  * @param uiRows  Number of rows for new window.
890  * @param uiCols  Number of columnss for new window.
891  */
create_pad(APPPAD * pPad,WINDOW * pParent,unsigned int uiRows,unsigned int uiCols)892 static bool create_pad(APPPAD* pPad, WINDOW* pParent, unsigned int uiRows,
893     unsigned int uiCols)
894 {
895   bool bStatus = false;
896 
897   assert(pParent);
898   if (pPad->pPad) {
899     delwin(pPad->pPad);
900   }
901 
902   if (NULL != pPad && NULL == (pPad->pPad = newpad(uiRows, uiCols))) {
903     goto newpad_fail;
904   }
905 
906   pPad->uiRows = uiRows;
907   pPad->uiColumns = uiCols;
908   pPad->uiPadRow = 0;
909   pPad->uiPadCol = 0;
910   pPad->uiWinLeft = application_windows.pDetailsWin->_begx + 1;
911   pPad->uiWinTop = application_windows.pDetailsWin->_begy + 1;
912   pPad->uiWinColumns = application_windows.pDetailsWin->_maxx - 2;
913   pPad->uiWinRows = application_windows.pDetailsWin->_maxy - 2;
914 
915   bStatus = true;
916 
917 newpad_fail:
918   return bStatus;
919 }
920 
921 /*------------------------------------------------------------------------*/
922 /** Prints help text for registry level to detail window. */
show_registry_level_help(void)923 static void show_registry_level_help(void)
924 {
925   if (!create_pad(&details_pad, application_windows.pDetailsWin, 8, 256)) {
926     return;
927   }
928 
929   mvwprintw(details_pad.pPad, 0, 0, _("Commands:  R - run all tests in all suites"));
930   mvwprintw(details_pad.pPad, 1, 0, _("           S - Select a suite to run or modify"));
931   mvwprintw(details_pad.pPad, 2, 0, _("           L - List all registered suites"));
932   mvwprintw(details_pad.pPad, 3, 0, _("           A - Activate or deactivate a suite (toggle)"));
933   mvwprintw(details_pad.pPad, 4, 0, _("           F - Show failures from last test run"));
934   mvwprintw(details_pad.pPad, 5, 0, _("           O - Set BCUnit options"));
935   mvwprintw(details_pad.pPad, 6, 0, _("           H - Show this help message"));
936   mvwprintw(details_pad.pPad, 7, 0, _("           Q - Quit the application"));
937   refresh_details_window();
938 }
939 
940 /*------------------------------------------------------------------------*/
941 /** Prints help text for suite level to detail window. */
show_suite_level_help(CU_pSuite pSuite)942 static void show_suite_level_help(CU_pSuite pSuite)
943 {
944   char szTemp[STRING_LENGTH];
945 
946   assert(NULL != pSuite);
947   assert(NULL != pSuite->pName);
948 
949   if (!create_pad(&details_pad, application_windows.pDetailsWin, 9, 256)) {
950     return;
951   }
952 
953   snprintf(szTemp, STRING_LENGTH,   _("Commands:  R - run all tests in suite %s"),
954                                     pSuite->pName);
955   mvwprintw(details_pad.pPad, 0, 0, szTemp);
956   mvwprintw(details_pad.pPad, 1, 0, _("           S - Select and run a test"));
957   snprintf(szTemp, STRING_LENGTH,   _("           L - List all tests registered in suite %s"),
958                                     pSuite->pName);
959   mvwprintw(details_pad.pPad, 2, 0, szTemp);
960   mvwprintw(details_pad.pPad, 3, 0, _("           A - Activate or deactivate a test (toggle)"));
961   mvwprintw(details_pad.pPad, 4, 0, _("           F - Show failures from last test run"));
962   mvwprintw(details_pad.pPad, 5, 0, _("           M - Move up to main menu"));
963   mvwprintw(details_pad.pPad, 6, 0, _("           O - Set BCUnit options"));
964   mvwprintw(details_pad.pPad, 7, 0, _("           H - Show this help message"));
965   mvwprintw(details_pad.pPad, 8, 0, _("           Q - Quit the application"));
966   refresh_details_window();
967 }
968 
969 /*------------------------------------------------------------------------*/
970 /** Print a list of registered suites to the detail window.
971  *  @param pRegistry The CU_pTestRegistry to query (non-NULL).
972  */
list_suites(CU_pTestRegistry pRegistry)973 static void list_suites(CU_pTestRegistry pRegistry)
974 {
975 
976   CU_pSuite pCurSuite = NULL;
977   int i;
978   char szTemp[STRING_LENGTH];
979   static size_t width[6];
980 
981   if (NULL == pRegistry) {
982     pRegistry = CU_get_registry();
983   }
984 
985   assert(pRegistry);
986 
987   if (0 == pRegistry->uiNumberOfSuites) {
988     show_detail_window_message(_("No suites are registered."));
989     return;
990   }
991 
992   assert(pRegistry->pSuite);
993 
994   if (!create_pad(&details_pad, application_windows.pDetailsWin, pRegistry->uiNumberOfSuites + 4, 256)) {
995     return;
996   }
997 
998   /* only need to calculate formatting widths once */
999   if (0 == width[0]) {
1000     width[0] = CU_number_width(pRegistry->uiNumberOfSuites) + 1;
1001     width[1] = 34;
1002     width[2] = CU_MAX(strlen(_("Init?")), CU_MAX(f_yes_width, f_no_width)) + 1;
1003     width[3] = CU_MAX(strlen(_("Cleanup?")), CU_MAX(f_yes_width, f_no_width)) + 1;
1004     width[4] = CU_MAX(strlen(_("#Tests")), CU_number_width(pRegistry->uiNumberOfTests) + 1) + 1;
1005     width[5] = CU_MAX(strlen(_("Active?")), CU_MAX(f_yes_width, f_no_width)) + 1;
1006   }
1007 
1008   snprintf(szTemp, STRING_LENGTH, "%*s  %-*s%*s%*s%*s%*s",
1009                                   width[0], _("#"),
1010                                   width[1], _("Suite Name"),
1011                                   width[2], _("Init?"),
1012                                   width[3], _("Cleanup?"),
1013                                   width[4], _("#Tests"),
1014                                   width[5], _("Active?"));
1015   mvwprintw(details_pad.pPad, 0, 0, "%s", szTemp);
1016 
1017   for (i = 0, pCurSuite = pRegistry->pSuite; pCurSuite; pCurSuite = pCurSuite->pNext, i++) {
1018     assert(NULL != pCurSuite->pName);
1019     snprintf(szTemp, STRING_LENGTH, "%*d. %-*.*s%*s%*s%*u%*s",
1020              width[0], i+1,
1021              width[1], width[1] - 1, pCurSuite->pName,
1022              width[2]-1, (NULL != pCurSuite->pInitializeFunc) ? _("Yes") : _("No"),
1023              width[3],   (NULL != pCurSuite->pCleanupFunc) ? _("Yes") : _("No"),
1024              width[4],   pCurSuite->uiNumberOfTests,
1025              width[5],   (CU_FALSE != pCurSuite->fActive) ? _("Yes") : _("No"));
1026     mvwprintw(details_pad.pPad, i + 2, 0, "%s", szTemp);
1027   }
1028 
1029   mvwprintw(details_pad.pPad, i + 2, 0, "%s",
1030             "---------------------------------------------------------------------------");
1031   mvwprintw(details_pad.pPad, i + 3, 0,
1032             _("Total Number of Suites : %-u"), pRegistry->uiNumberOfSuites);
1033   refresh_details_window();
1034 }
1035 
1036 /*------------------------------------------------------------------------*/
1037 /** Print a list of tests contained in a specified suite to the detail window.
1038  *  @param pSuite  The suite to query (non-NULL).
1039  */
list_tests(CU_pSuite pSuite)1040 static void list_tests(CU_pSuite pSuite)
1041 {
1042   CU_pTest pCurTest = NULL;
1043   unsigned int i;
1044   char szTemp[STRING_LENGTH];
1045   static size_t width[3];
1046 
1047   assert(NULL != pSuite);
1048   assert(NULL != pSuite->pName);
1049 
1050   if (!create_pad(&details_pad, application_windows.pDetailsWin, pSuite->uiNumberOfTests + 5, 256)) {
1051     return;
1052   }
1053 
1054   if (0 == pSuite->uiNumberOfTests) {
1055     snprintf(szTemp, STRING_LENGTH,
1056              _("Suite %s contains no tests."), pSuite->pName);
1057     show_detail_window_message(szTemp);
1058     return;
1059   }
1060 
1061   assert(pSuite->pTest);
1062 
1063   /* only number of tests can change between calls */
1064   width[0] = CU_number_width(pSuite->uiNumberOfTests) + 1;
1065   if (0 == width[1]) {
1066     width[1] = 34;
1067     width[2] = CU_MAX(strlen(_("Active?")), CU_MAX(f_yes_width, f_no_width)) + 1;
1068   }
1069 
1070   snprintf(szTemp, STRING_LENGTH, "%s: %s", _("Suite"), pSuite->pName);
1071   mvwprintw(details_pad.pPad, 0, 0, szTemp);
1072 
1073   snprintf(szTemp, STRING_LENGTH,
1074            "%*s  %-*s%*s",
1075            width[0], _("#"),
1076            width[1], _("Test Name"),
1077            width[2], _("Active?"));
1078   mvwprintw(details_pad.pPad, 1, 0, szTemp);
1079 
1080   for (i = 0, pCurTest = pSuite->pTest ;
1081        NULL != pCurTest ;
1082        pCurTest = pCurTest->pNext, i++) {
1083     assert(NULL != pCurTest->pName);
1084     snprintf(szTemp, STRING_LENGTH,
1085              "%*u. %-*.*s%*s",
1086              width[0], i + 1,
1087              width[1], width[1]-1, pCurTest->pName,
1088              width[2]-1, (CU_FALSE != pCurTest->fActive) ? _("Yes") : _("No"));
1089     mvwprintw(details_pad.pPad, i + 3, 0, "%s", szTemp);
1090   }
1091 
1092   mvwprintw(details_pad.pPad, i + 3, 0, "%s",
1093             "---------------------------------------------");
1094   mvwprintw(details_pad.pPad, i + 4, 0,
1095             _("Total Number of Tests : %-u"), pSuite->uiNumberOfTests);
1096   refresh_details_window();
1097 }
1098 
1099 /*------------------------------------------------------------------------*/
1100 /** Display the record of test failures in the detail window. */
show_failures(void)1101 static void show_failures(void)
1102 {
1103   int i;
1104   CU_pFailureRecord pFailure = CU_get_failure_list();
1105   unsigned int nFailures = CU_get_number_of_failure_records();
1106 
1107   if (0 == nFailures) {
1108     show_detail_window_message(_("No failures."));
1109     return;
1110   }
1111 
1112   assert(pFailure);
1113 
1114   if (!create_pad(&details_pad, application_windows.pDetailsWin, nFailures + 5, 256)) {
1115     return;
1116   }
1117 
1118   mvwprintw(details_pad.pPad, 1, 0, "%s", _("   src_file:line# : (suite:test) : failure_condition"));
1119 
1120   for (i = 0 ; pFailure ; pFailure = pFailure->pNext, i++) {
1121     char szTemp[STRING_LENGTH];
1122 
1123     snprintf(szTemp, STRING_LENGTH, "%d. %s:%d : (%s : %s) : %s", i + 1,
1124         ((NULL != pFailure->strFileName) ? pFailure->strFileName : ""),
1125         pFailure->uiLineNumber,
1126         (((NULL != pFailure->pSuite) && (NULL != pFailure->pSuite->pName))
1127             ? pFailure->pSuite->pName : ""),
1128         (((NULL != pFailure->pTest)  && (NULL != pFailure->pTest->pName))
1129             ? pFailure->pTest->pName : ""),
1130         ((NULL != pFailure->strCondition) ? pFailure->strCondition : ""));
1131 
1132     mvwprintw(details_pad.pPad, i + 3, 0, "%s", szTemp);
1133   }
1134 
1135   mvwprintw(details_pad.pPad, i + 3, 0, "%s", "=============================================");
1136   mvwprintw(details_pad.pPad, i + 4, 0, _("Total Number of Failures : %-u"), nFailures);
1137   refresh_details_window();
1138 }
1139 
1140 /*------------------------------------------------------------------------*/
1141 /**
1142  *  Sets BCUnit options interactively using curses interface.
1143  *  Displays actions and responds based on user imput.
1144  */
curses_set_options_run(void)1145 static STATUS curses_set_options_run(void)
1146 {
1147   char szTemp[STRING_LENGTH];
1148   STATUS eStatus = CONTINUE;
1149   long option_num;
1150 
1151   if (!create_pad(&details_pad, application_windows.pDetailsWin, 3, 256)) {
1152     return eStatus;
1153   }
1154 
1155   mvwprintw(details_pad.pPad, 0, 0, _("BCUnit Options:"));
1156 
1157   while (CONTINUE == eStatus) {
1158 
1159     snprintf(szTemp, STRING_LENGTH,   _("   1 - Inactive suites/tests treated as runtime failures     %s"),
1160                                       (CU_FALSE != CU_get_fail_on_inactive()) ? _("Yes") : _("No "));
1161     mvwprintw(details_pad.pPad, 2, 0, szTemp);
1162     refresh_details_window();
1163     read_input_string(_("Enter number of option to change : "), szTemp, STRING_LENGTH);
1164     option_num = atol(szTemp);
1165 
1166     switch (option_num) {
1167       case 1:
1168         CU_set_fail_on_inactive((CU_FALSE == CU_get_fail_on_inactive()) ? CU_TRUE : CU_FALSE);
1169         break;
1170 
1171       default:
1172         eStatus = MOVE_UP;
1173         break;
1174     }
1175   }
1176   return eStatus;
1177 }
1178 
1179 /*------------------------------------------------------------------------*/
1180 /** Run all tests within the curses interface.
1181  * The test registry is changed to the specified registry
1182  * before running the tests, and reset to the original
1183  * registry when done.
1184  * @param pRegistry The CU_pTestRegistry containing the tests
1185  *                  to be run (non-NULL).
1186  * @return An error code indicating the error status
1187  *         during the test run.
1188  */
curses_run_all_tests(CU_pTestRegistry pRegistry)1189 static CU_ErrorCode curses_run_all_tests(CU_pTestRegistry pRegistry)
1190 {
1191   CU_pTestRegistry pOldRegistry = NULL;
1192   CU_ErrorCode result;
1193 
1194   assert(pRegistry);
1195 
1196   reset_run_parameters();
1197   f_uiTotalTests = pRegistry->uiNumberOfTests;
1198   f_uiTotalSuites = pRegistry->uiNumberOfSuites;
1199 
1200   if (NULL != pRegistry) {
1201     pOldRegistry = CU_set_registry(pRegistry);
1202   }
1203   result = CU_run_all_tests();
1204   if (NULL != pOldRegistry) {
1205     CU_set_registry(pOldRegistry);
1206   }
1207   return result;
1208 }
1209 
1210 /*------------------------------------------------------------------------*/
1211 /** Run a specified suite within the curses interface.
1212  * @param pSuite The suite to be run (non-NULL).
1213  * @return An error code indicating the error status
1214  *         during the test run.
1215  */
curses_run_suite_tests(CU_pSuite pSuite)1216 static CU_ErrorCode curses_run_suite_tests(CU_pSuite pSuite)
1217 {
1218   reset_run_parameters();
1219   f_uiTotalTests = pSuite->uiNumberOfTests;
1220   f_uiTotalSuites = 1;
1221   return CU_run_suite(pSuite);
1222 }
1223 
1224 /*------------------------------------------------------------------------*/
1225 /** Run a specific test for the specified suite within
1226  * the curses interface.
1227  * @param pSuite The suite containing the test to be run (non-NULL).
1228  * @param pTest  The test to be run (non-NULL).
1229  * @return An error code indicating the error status
1230  *         during the test run.
1231  */
curses_run_single_test(CU_pSuite pSuite,CU_pTest pTest)1232 static CU_ErrorCode curses_run_single_test(CU_pSuite pSuite, CU_pTest pTest)
1233 {
1234   reset_run_parameters();
1235   f_uiTotalTests = 1;
1236   f_uiTotalSuites = 1;
1237   return CU_run_test(pSuite, pTest);
1238 }
1239 
1240 /*------------------------------------------------------------------------*/
1241 /** Reset the local run counters and prepare for a test run. */
reset_run_parameters(void)1242 static void reset_run_parameters(void)
1243 {
1244   f_pCurrentTest = NULL;
1245   f_pCurrentSuite = NULL;
1246   f_uiTestsRunSuccessful = f_uiTestsRun = f_uiTotalTests = f_uiTestsFailed = f_uiTestsSkipped = 0;
1247   f_uiTotalSuites = f_uiSuitesSkipped = 0;
1248   refresh_progress_window();
1249   refresh_summary_window();
1250   refresh_run_summary_window();
1251 }
1252 
1253 /*------------------------------------------------------------------------*/
1254 /** Handler function called at start of each test.
1255  * @param pTest  The test being run.
1256  * @param pSuite The suite containing the test.
1257  */
curses_test_start_message_handler(const CU_pTest pTest,const CU_pSuite pSuite)1258 static void curses_test_start_message_handler(const CU_pTest pTest, const CU_pSuite pSuite)
1259 {
1260   f_pCurrentTest = (CU_pTest)pTest;
1261   f_pCurrentSuite = (CU_pSuite)pSuite;
1262   refresh_run_summary_window();
1263 }
1264 
1265 /*------------------------------------------------------------------------*/
1266 /** Handler function called at completion of each test.
1267  * @param pTest   The test being run.
1268  * @param pSuite  The suite containing the test.
1269  * @param pFailure Pointer to the 1st failure record for this test.
1270  */
curses_test_complete_message_handler(const CU_pTest pTest,const CU_pSuite pSuite,const CU_pFailureRecord pFailure)1271 static void curses_test_complete_message_handler(const CU_pTest pTest,
1272                                                  const CU_pSuite pSuite,
1273                                                  const CU_pFailureRecord pFailure)
1274 {
1275   /* Not used in curses implementation - quiet compiler warning */
1276   CU_UNREFERENCED_PARAMETER(pTest);
1277   CU_UNREFERENCED_PARAMETER(pSuite);
1278   CU_UNREFERENCED_PARAMETER(pFailure);
1279 
1280   f_uiTestsRun++;
1281   if (CU_get_number_of_tests_failed() != f_uiTestsFailed) {
1282     f_uiTestsFailed++;
1283   }
1284   else {
1285     f_uiTestsRunSuccessful++;
1286   }
1287 
1288   refresh_summary_window();
1289   refresh_progress_window();
1290 }
1291 
1292 /*------------------------------------------------------------------------*/
1293 /** Handler function called at completion of all tests in a suite.
1294  * @param pFailure Pointer to the test failure record list.
1295  */
curses_all_tests_complete_message_handler(const CU_pFailureRecord pFailure)1296 static void curses_all_tests_complete_message_handler(const CU_pFailureRecord pFailure)
1297 {
1298   /* Not used in curses implementation - quiet compiler warning */
1299   CU_UNREFERENCED_PARAMETER(pFailure);
1300 
1301   f_pCurrentTest = NULL;
1302   f_pCurrentSuite = NULL;
1303 
1304   if (!create_pad(&details_pad, application_windows.pDetailsWin, 21, 256)) {
1305     return;
1306   }
1307 
1308   mvwprintw(details_pad.pPad,  0, 0, "%s", _("======  Suite Run Summary  ======"));
1309   mvwprintw(details_pad.pPad,  1, 0, _("    TOTAL SUITES: %4u"), f_uiTotalSuites);
1310   mvwprintw(details_pad.pPad,  2, 0, _("             Run: %4u"), f_uiTotalSuites - f_uiSuitesSkipped);
1311   mvwprintw(details_pad.pPad,  3, 0, _("         Skipped: %4u"), f_uiSuitesSkipped);
1312   mvwprintw(details_pad.pPad,  4, 0, _("        Inactive: %4u"), CU_get_number_of_suites_inactive());
1313 
1314   mvwprintw(details_pad.pPad,  6, 0, "%s", _("======  Test Run Summary  ======="));
1315   mvwprintw(details_pad.pPad,  7, 0, _("     TOTAL TESTS: %4u"), f_uiTotalTests);
1316   mvwprintw(details_pad.pPad,  8, 0, _("             Run: %4u"), f_uiTestsRun);
1317   mvwprintw(details_pad.pPad,  9, 0, _("         Skipped: %4u"), f_uiTestsSkipped);
1318   mvwprintw(details_pad.pPad, 10, 0, _("      Successful: %4u"), f_uiTestsRunSuccessful);
1319   mvwprintw(details_pad.pPad, 11, 0, _("          Failed: %4u"), f_uiTestsFailed);
1320   mvwprintw(details_pad.pPad, 12, 0, _("        Inactive: %4u"), CU_get_number_of_tests_inactive());
1321 
1322   mvwprintw(details_pad.pPad, 14, 0, "%s", _("======  Assertion Summary  ======"));
1323   mvwprintw(details_pad.pPad, 15, 0, _("   TOTAL ASSERTS: %4u"), CU_get_number_of_asserts());
1324   mvwprintw(details_pad.pPad, 16, 0, _("          Passed: %4u"), CU_get_number_of_successes());
1325   mvwprintw(details_pad.pPad, 17, 0, _("          Failed: %4u"), CU_get_number_of_failures());
1326 
1327 
1328   mvwprintw(details_pad.pPad, 19, 0, "%s", _("======  Failure Summary  ======"));
1329   mvwprintw(details_pad.pPad, 20, 0, _("  TOTAL FAILURES: %4u"), CU_get_number_of_failure_records());
1330 
1331   refresh_details_window();
1332   refresh_run_summary_window();
1333 }
1334 
1335 /*------------------------------------------------------------------------*/
1336 /** Handler function called when suite initialization fails.
1337  * @param pSuite The suite for which initialization failed.
1338  */
curses_suite_init_failure_message_handler(const CU_pSuite pSuite)1339 static void curses_suite_init_failure_message_handler(const CU_pSuite pSuite)
1340 {
1341   assert(pSuite);
1342   f_uiTestsSkipped += pSuite->uiNumberOfTests;
1343   f_uiSuitesSkipped++;
1344 
1345   refresh_summary_window();
1346   refresh_progress_window();
1347 }
1348 
1349 /** @} */
1350