|
ChibiOS/RT
2.5.1 |
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 /** @} */