ChibiOS/RT
2.5.1
test.c
Go to the documentation of this file.
00001 /*
00002     ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
00003                  2011,2012 Giovanni Di Sirio.
00004 
00005     This file is part of ChibiOS/RT.
00006 
00007     ChibiOS/RT is free software; you can redistribute it and/or modify
00008     it under the terms of the GNU General Public License as published by
00009     the Free Software Foundation; either version 3 of the License, or
00010     (at your option) any later version.
00011 
00012     ChibiOS/RT is distributed in the hope that it will be useful,
00013     but WITHOUT ANY WARRANTY; without even the implied warranty of
00014     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015     GNU General Public License for more details.
00016 
00017     You should have received a copy of the GNU General Public License
00018     along with this program.  If not, see <http://www.gnu.org/licenses/>.
00019 */
00020 
00021 /**
00022  * @file    test.c
00023  * @brief   Tests support code.
00024  *
00025  * @addtogroup test
00026  * @{
00027  */
00028 
00029 #include "ch.h"
00030 #include "hal.h"
00031 
00032 #include "test.h"
00033 #include "testthd.h"
00034 #include "testsem.h"
00035 #include "testmtx.h"
00036 #include "testmsg.h"
00037 #include "testmbox.h"
00038 #include "testevt.h"
00039 #include "testheap.h"
00040 #include "testpools.h"
00041 #include "testdyn.h"
00042 #include "testqueues.h"
00043 #include "testbmk.h"
00044 
00045 /*
00046  * Array of all the test patterns.
00047  */
00048 static ROMCONST struct testcase * ROMCONST *patterns[] = {
00049   patternthd,
00050   patternsem,
00051   patternmtx,
00052   patternmsg,
00053   patternmbox,
00054   patternevt,
00055   patternheap,
00056   patternpools,
00057   patterndyn,
00058   patternqueues,
00059   patternbmk,
00060   NULL
00061 };
00062 
00063 static bool_t local_fail, global_fail;
00064 static unsigned failpoint;
00065 static char tokens_buffer[MAX_TOKENS];
00066 static char *tokp;
00067 
00068 /*
00069  * Static working areas, the following areas can be used for threads or
00070  * used as temporary buffers.
00071  */
00072 union test_buffers test;
00073 
00074 /*
00075  * Pointers to the spawned threads.
00076  */
00077 Thread *threads[MAX_THREADS];
00078 
00079 /*
00080  * Pointers to the working areas.
00081  */
00082 void * ROMCONST wa[5] = {test.wa.T0, test.wa.T1, test.wa.T2,
00083                          test.wa.T3, test.wa.T4};
00084 
00085 /*
00086  * Console output.
00087  */
00088 static BaseSequentialStream *chp;
00089 
00090 /**
00091  * @brief   Prints a decimal unsigned number.
00092  *
00093  * @param[in] n         the number to be printed
00094  */
00095 void test_printn(uint32_t n) {
00096   char buf[16], *p;
00097 
00098   if (!n)
00099     chSequentialStreamPut(chp, '0');
00100   else {
00101     p = buf;
00102     while (n)
00103       *p++ = (n % 10) + '0', n /= 10;
00104     while (p > buf)
00105       chSequentialStreamPut(chp, *--p);
00106   }
00107 }
00108 
00109 /**
00110  * @brief   Prints a line without final end-of-line.
00111  *
00112  * @param[in] msgp      the message
00113  */
00114 void test_print(const char *msgp) {
00115 
00116   while (*msgp)
00117     chSequentialStreamPut(chp, *msgp++);
00118 }
00119 
00120 /**
00121  * @brief   Prints a line.
00122  *
00123  * @param[in] msgp      the message
00124  */
00125 void test_println(const char *msgp) {
00126 
00127   test_print(msgp);
00128   chSequentialStreamWrite(chp, (const uint8_t *)"\r\n", 2);
00129 }
00130 
00131 /*
00132  * Tokens.
00133  */
00134 static void clear_tokens(void) {
00135 
00136   tokp = tokens_buffer;
00137 }
00138 
00139 static void print_tokens(void) {
00140   char *cp = tokens_buffer;
00141 
00142   while (cp < tokp)
00143     chSequentialStreamPut(chp, *cp++);
00144 }
00145 
00146 /**
00147  * @brief   Emits a token into the tokens buffer.
00148  *
00149  * @param[in] token     the token as a char
00150  */
00151 void test_emit_token(char token) {
00152 
00153   chSysLock();
00154   *tokp++ = token;
00155   chSysUnlock();
00156 }
00157 
00158 /*
00159  * Assertions.
00160  */
00161 bool_t _test_fail(unsigned point) {
00162 
00163   local_fail = TRUE;
00164   global_fail = TRUE;
00165   failpoint = point;
00166   return TRUE;
00167 }
00168 
00169 bool_t _test_assert(unsigned point, bool_t condition) {
00170 
00171   if (!condition)
00172     return _test_fail(point);
00173   return FALSE;
00174 }
00175 
00176 bool_t _test_assert_sequence(unsigned point, char *expected) {
00177   char *cp = tokens_buffer;
00178   while (cp < tokp) {
00179     if (*cp++ != *expected++)
00180      return _test_fail(point);
00181   }
00182   if (*expected)
00183     return _test_fail(point);
00184   clear_tokens();
00185   return FALSE;
00186 }
00187 
00188 bool_t _test_assert_time_window(unsigned point, systime_t start, systime_t end) {
00189 
00190   return _test_assert(point, chTimeIsWithin(start, end));
00191 }
00192 
00193 /*
00194  * Threads utils.
00195  */
00196 
00197 /**
00198  * @brief   Sets a termination request in all the test-spawned threads.
00199  */
00200 void test_terminate_threads(void) {
00201   int i;
00202 
00203   for (i = 0; i < MAX_THREADS; i++)
00204     if (threads[i])
00205       chThdTerminate(threads[i]);
00206 }
00207 
00208 /**
00209  * @brief   Waits for the completion of all the test-spawned threads.
00210  */
00211 void test_wait_threads(void) {
00212   int i;
00213 
00214   for (i = 0; i < MAX_THREADS; i++)
00215     if (threads[i] != NULL) {
00216       chThdWait(threads[i]);
00217       threads[i] = NULL;
00218     }
00219 }
00220 
00221 #if CH_DBG_THREADS_PROFILING
00222 /**
00223  * @brief   CPU pulse.
00224  * @note    The current implementation is not totally reliable.
00225  *
00226  * @param[in] duration      CPU pulse duration in milliseconds
00227  */
00228 void test_cpu_pulse(unsigned duration) {
00229   systime_t start, end, now;
00230 
00231   start = chThdSelf()->p_time;
00232   end = start + MS2ST(duration);
00233   do {
00234     now = chThdSelf()->p_time;
00235 #if defined(SIMULATOR)
00236     ChkIntSources();
00237 #endif
00238   }
00239   while (end > start ? (now >= start) && (now < end) :
00240                        (now >= start) || (now < end));
00241 }
00242 #endif
00243 
00244 /**
00245  * @brief   Delays execution until next system time tick.
00246  *
00247  * @return              The system time.
00248  */
00249 systime_t test_wait_tick(void) {
00250 
00251   chThdSleep(1);
00252   return chTimeNow();
00253 }
00254 
00255 /*
00256  * Timer utils.
00257  */
00258 
00259 /**
00260  * @brief   Set to @p TRUE when the test timer reaches its deadline.
00261  */
00262 bool_t test_timer_done;
00263 
00264 static VirtualTimer vt;
00265 static void tmr(void *p) {
00266   (void)p;
00267 
00268   test_timer_done = TRUE;
00269 }
00270 
00271 /**
00272  * @brief   Starts the test timer.
00273  *
00274  * @param[in] ms        time in milliseconds
00275  */
00276 void test_start_timer(unsigned ms) {
00277 
00278   systime_t duration = MS2ST(ms);
00279   test_timer_done = FALSE;
00280   chVTSet(&vt, duration, tmr, NULL);
00281 }
00282 
00283 /*
00284  * Test suite execution.
00285  */
00286 static void execute_test(const struct testcase *tcp) {
00287   int i;
00288 
00289   /* Initialization */
00290   clear_tokens();
00291   local_fail = FALSE;
00292   for (i = 0; i < MAX_THREADS; i++)
00293     threads[i] = NULL;
00294 
00295   if (tcp->setup != NULL)
00296     tcp->setup();
00297   tcp->execute();
00298   if (tcp->teardown != NULL)
00299     tcp->teardown();
00300 
00301   test_wait_threads();
00302 }
00303 
00304 static void print_line(void) {
00305   unsigned i;
00306 
00307   for (i = 0; i < 76; i++)
00308     chSequentialStreamPut(chp, '-');
00309   chSequentialStreamWrite(chp, (const uint8_t *)"\r\n", 2);
00310 }
00311 
00312 /**
00313  * @brief   Test execution thread function.
00314  *
00315  * @param[in] p         pointer to a @p BaseChannel object for test output
00316  * @return              A failure boolean value.
00317  */
00318 msg_t TestThread(void *p) {
00319   int i, j;
00320 
00321   chp = p;
00322   test_println("");
00323   test_println("*** ChibiOS/RT test suite");
00324   test_println("***");
00325   test_print("*** Kernel:       ");
00326   test_println(CH_KERNEL_VERSION);
00327   test_print("*** Compiled:     ");
00328   test_println(__DATE__ " - " __TIME__);
00329 #ifdef CH_COMPILER_NAME
00330   test_print("*** Compiler:     ");
00331   test_println(CH_COMPILER_NAME);
00332 #endif
00333   test_print("*** Architecture: ");
00334   test_println(CH_ARCHITECTURE_NAME);
00335 #ifdef CH_CORE_VARIANT_NAME
00336   test_print("*** Core Variant: ");
00337   test_println(CH_CORE_VARIANT_NAME);
00338 #endif
00339 #ifdef CH_PORT_INFO
00340   test_print("*** Port Info:    ");
00341   test_println(CH_PORT_INFO);
00342 #endif
00343 #ifdef PLATFORM_NAME
00344   test_print("*** Platform:     ");
00345   test_println(PLATFORM_NAME);
00346 #endif
00347 #ifdef BOARD_NAME
00348   test_print("*** Test Board:   ");
00349   test_println(BOARD_NAME);
00350 #endif
00351   test_println("");
00352 
00353   global_fail = FALSE;
00354   i = 0;
00355   while (patterns[i]) {
00356     j = 0;
00357     while (patterns[i][j]) {
00358       print_line();
00359       test_print("--- Test Case ");
00360       test_printn(i + 1);
00361       test_print(".");
00362       test_printn(j + 1);
00363       test_print(" (");
00364       test_print(patterns[i][j]->name);
00365       test_println(")");
00366 #if DELAY_BETWEEN_TESTS > 0
00367       chThdSleepMilliseconds(DELAY_BETWEEN_TESTS);
00368 #endif
00369       execute_test(patterns[i][j]);
00370       if (local_fail) {
00371         test_print("--- Result: FAILURE (#");
00372         test_printn(failpoint);
00373         test_print(" [");
00374         print_tokens();
00375         test_println("])");
00376       }
00377       else
00378         test_println("--- Result: SUCCESS");
00379       j++;
00380     }
00381     i++;
00382   }
00383   print_line();
00384   test_println("");
00385   test_print("Final result: ");
00386   if (global_fail)
00387     test_println("FAILURE");
00388   else
00389     test_println("SUCCESS");
00390 
00391   return (msg_t)global_fail;
00392 }
00393 
00394 /** @} */