100% code coverage for heap, semaphores and events.
git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@903 35acf78f-673a-0410-8e92-d51de3d6d3f4
This commit is contained in:
parent
e8ae833287
commit
0a37ec19f6
10
readme.txt
10
readme.txt
|
@ -84,11 +84,11 @@ Win32-MinGW - ChibiOS/RT simulator and demo into a WIN32 process,
|
|||
- FIX: Removed usused list functions (bug 2755230)(backported in stable
|
||||
branch).
|
||||
- NEW: Added a code coverage analysis application under ./tests/coverage.
|
||||
- Added more test cases in order to improve the test suite code coverage (it
|
||||
was 74% in version 1.2.0).
|
||||
- Added a new "naked" context switch benchmark that better defines the
|
||||
real context switch time, for the STM32 the context switch is performed
|
||||
under 1.48uS.
|
||||
- NEW: Added more test cases in order to improve the test suite code coverage
|
||||
(it was 74% in version 1.2.0).
|
||||
- NEW: Added a new "naked" context switch benchmark that better defines the
|
||||
real context switch time, previous benchmarks introduced too much overhead
|
||||
to the measurement. The STM32 performs the context switch in under 1.48uS.
|
||||
|
||||
*** 1.2.0 ***
|
||||
- Added license exception text to the 1.2.0 branch.
|
||||
|
|
211
test/testevt.c
211
test/testevt.c
|
@ -29,7 +29,7 @@ static EventSource es1, es2;
|
|||
|
||||
static char *evt1_gettest(void) {
|
||||
|
||||
return "Events, wait and broadcast";
|
||||
return "Events, registration and dispatch";
|
||||
}
|
||||
|
||||
static void evt1_setup(void) {
|
||||
|
@ -37,58 +37,31 @@ static void evt1_setup(void) {
|
|||
chEvtClear(ALL_EVENTS);
|
||||
}
|
||||
|
||||
static msg_t thread(void *p) {
|
||||
|
||||
chEvtBroadcast(&es1);
|
||||
chThdSleepMilliseconds(50);
|
||||
chEvtBroadcast(&es2);
|
||||
return 0;
|
||||
}
|
||||
static void h1(eventid_t id) {test_emit_token('A');}
|
||||
static void h2(eventid_t id) {test_emit_token('B');}
|
||||
static void h3(eventid_t id) {test_emit_token('C');}
|
||||
static const evhandler_t evhndl[] = {h1, h2, h3};
|
||||
|
||||
static void evt1_execute(void) {
|
||||
eventmask_t m;
|
||||
EventListener el1, el2;
|
||||
systime_t target_time;
|
||||
|
||||
/*
|
||||
* Test on chEvtWaitOne().
|
||||
*/
|
||||
chEvtPend(5);
|
||||
m = chEvtWaitOne(ALL_EVENTS);
|
||||
test_assert(m == 1, "#1"); /* Single bit error.*/
|
||||
m = chEvtWaitOne(ALL_EVENTS);
|
||||
test_assert(m == 4, "#2"); /* Single bit error.*/
|
||||
m = chEvtClear(0);
|
||||
test_assert(m == 0, "#3"); /* Stuck event.*/
|
||||
|
||||
/*
|
||||
* Test on chEvtWaitAny().
|
||||
*/
|
||||
chEvtPend(5);
|
||||
m = chEvtWaitAny(ALL_EVENTS);
|
||||
test_assert(m == 5, "#4"); /* Unexpected pending.*/
|
||||
m = chEvtClear(0);
|
||||
test_assert(m == 0, "#5"); /* Stuck event.*/
|
||||
|
||||
/*
|
||||
* Test on chEvtWaitAll(), chEvtRegisterMask() and chEvtUnregister().
|
||||
* Testing chEvtRegisterMask() and chEvtUnregister().
|
||||
*/
|
||||
chEvtInit(&es1);
|
||||
chEvtInit(&es2);
|
||||
chEvtRegisterMask(&es1, &el1, 1);
|
||||
chEvtRegisterMask(&es2, &el2, 4);
|
||||
target_time = chTimeNow() + MS2ST(50);
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriority()-1, thread, "A");
|
||||
m = chEvtWaitAll(5);
|
||||
test_assert_time_window(target_time, target_time + ALLOWED_DELAY);
|
||||
m = chEvtClear(0);
|
||||
test_assert(m == 0, "#6"); /* Stuck event.*/
|
||||
|
||||
test_wait_threads();
|
||||
chEvtRegisterMask(&es1, &el2, 2);
|
||||
test_assert(chEvtIsListening(&es1), "#1"); /* Must not be empty */
|
||||
chEvtUnregister(&es1, &el1);
|
||||
chEvtUnregister(&es2, &el2);
|
||||
test_assert(!chEvtIsListening(&es1), "#7"); /* Stuck listener.*/
|
||||
test_assert(!chEvtIsListening(&es2), "#8"); /* Stuck listener.*/
|
||||
test_assert(chEvtIsListening(&es1), "#2"); /* Must not be empty */
|
||||
chEvtUnregister(&es1, &el2);
|
||||
test_assert(!chEvtIsListening(&es1), "#3"); /* Stuck listener.*/
|
||||
|
||||
/*
|
||||
* Testing chEvtDispatch().
|
||||
*/
|
||||
chEvtDispatch(evhndl, 7);
|
||||
test_assert_sequence("ABC");
|
||||
}
|
||||
|
||||
const struct testcase testevt1 = {
|
||||
|
@ -98,6 +71,152 @@ const struct testcase testevt1 = {
|
|||
evt1_execute
|
||||
};
|
||||
|
||||
static char *evt2_gettest(void) {
|
||||
|
||||
return "Events, wait and broadcast";
|
||||
}
|
||||
|
||||
static void evt2_setup(void) {
|
||||
|
||||
chEvtClear(ALL_EVENTS);
|
||||
}
|
||||
|
||||
static msg_t thread1(void *p) {
|
||||
|
||||
chThdSleepMilliseconds(50);
|
||||
chEvtSignal((Thread *)p, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static msg_t thread2(void *p) {
|
||||
|
||||
chEvtBroadcast(&es1);
|
||||
chThdSleepMilliseconds(50);
|
||||
chEvtBroadcast(&es2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void evt2_execute(void) {
|
||||
eventmask_t m;
|
||||
EventListener el1, el2;
|
||||
systime_t target_time;
|
||||
|
||||
/*
|
||||
* Test on chEvtWaitOne() without wait.
|
||||
*/
|
||||
chEvtPend(5);
|
||||
m = chEvtWaitOne(ALL_EVENTS);
|
||||
test_assert(m == 1, "#1"); /* Single bit error.*/
|
||||
m = chEvtWaitOne(ALL_EVENTS);
|
||||
test_assert(m == 4, "#2"); /* Single bit error.*/
|
||||
m = chEvtClear(0);
|
||||
test_assert(m == 0, "#3"); /* Stuck bit.*/
|
||||
|
||||
/*
|
||||
* Test on chEvtWaitOne() with wait.
|
||||
*/
|
||||
test_wait_tick();
|
||||
target_time = chTimeNow() + MS2ST(50);
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriority() - 1,
|
||||
thread1, chThdSelf());
|
||||
m = chEvtWaitOne(ALL_EVENTS);
|
||||
test_assert_time_window(target_time, target_time + ALLOWED_DELAY);
|
||||
test_assert(m == 1, "#5"); /* Single bit error.*/
|
||||
m = chEvtClear(0);
|
||||
test_assert(m == 0, "#6"); /* Stuck bit.*/
|
||||
test_wait_threads();
|
||||
|
||||
/*
|
||||
* Test on chEvtWaitAny() without wait.
|
||||
*/
|
||||
chEvtPend(5);
|
||||
m = chEvtWaitAny(ALL_EVENTS);
|
||||
test_assert(m == 5, "#7"); /* Unexpected pending bit.*/
|
||||
m = chEvtClear(0);
|
||||
test_assert(m == 0, "#8"); /* Stuck bit.*/
|
||||
|
||||
/*
|
||||
* Test on chEvtWaitAny() with wait.
|
||||
*/
|
||||
test_wait_tick();
|
||||
target_time = chTimeNow() + MS2ST(50);
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriority() - 1,
|
||||
thread1, chThdSelf());
|
||||
m = chEvtWaitAny(ALL_EVENTS);
|
||||
test_assert_time_window(target_time, target_time + ALLOWED_DELAY);
|
||||
test_assert(m == 1, "#9"); /* Single bit error.*/
|
||||
m = chEvtClear(0);
|
||||
test_assert(m == 0, "#10"); /* Stuck bit.*/
|
||||
test_wait_threads();
|
||||
|
||||
/*
|
||||
* Test on chEvtWaitAll().
|
||||
*/
|
||||
chEvtInit(&es1);
|
||||
chEvtInit(&es2);
|
||||
chEvtRegisterMask(&es1, &el1, 1);
|
||||
chEvtRegisterMask(&es2, &el2, 4);
|
||||
test_wait_tick();
|
||||
target_time = chTimeNow() + MS2ST(50);
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriority() - 1,
|
||||
thread2, "A");
|
||||
m = chEvtWaitAll(5);
|
||||
test_assert_time_window(target_time, target_time + ALLOWED_DELAY);
|
||||
m = chEvtClear(0);
|
||||
test_assert(m == 0, "#11"); /* Stuck event.*/
|
||||
test_wait_threads();
|
||||
chEvtUnregister(&es1, &el1);
|
||||
chEvtUnregister(&es2, &el2);
|
||||
test_assert(!chEvtIsListening(&es1), "#12"); /* Stuck listener.*/
|
||||
test_assert(!chEvtIsListening(&es2), "#13"); /* Stuck listener.*/
|
||||
}
|
||||
|
||||
const struct testcase testevt2 = {
|
||||
evt2_gettest,
|
||||
evt2_setup,
|
||||
NULL,
|
||||
evt2_execute
|
||||
};
|
||||
|
||||
#if CH_USE_EVENTS_TIMEOUT
|
||||
static char *evt3_gettest(void) {
|
||||
|
||||
return "Events, timeouts";
|
||||
}
|
||||
|
||||
static void evt3_setup(void) {
|
||||
|
||||
chEvtClear(ALL_EVENTS);
|
||||
}
|
||||
|
||||
static void evt3_execute(void) {
|
||||
eventmask_t m;
|
||||
|
||||
/*
|
||||
* Tests various timeout situations.
|
||||
*/
|
||||
m = chEvtWaitOneTimeout(ALL_EVENTS, TIME_IMMEDIATE);
|
||||
test_assert(m == 0, "#1");
|
||||
m = chEvtWaitAnyTimeout(ALL_EVENTS, TIME_IMMEDIATE);
|
||||
test_assert(m == 0, "#2");
|
||||
m = chEvtWaitAllTimeout(ALL_EVENTS, TIME_IMMEDIATE);
|
||||
test_assert(m == 0, "#3");
|
||||
m = chEvtWaitOneTimeout(ALL_EVENTS, 10);
|
||||
test_assert(m == 0, "#4");
|
||||
m = chEvtWaitAnyTimeout(ALL_EVENTS, 10);
|
||||
test_assert(m == 0, "#5");
|
||||
m = chEvtWaitAllTimeout(ALL_EVENTS, 10);
|
||||
test_assert(m == 0, "#6");
|
||||
#endif
|
||||
}
|
||||
|
||||
const struct testcase testevt3 = {
|
||||
evt3_gettest,
|
||||
evt3_setup,
|
||||
NULL,
|
||||
evt3_execute
|
||||
};
|
||||
|
||||
#endif /* CH_USE_EVENTS */
|
||||
|
||||
/*
|
||||
|
@ -106,6 +225,10 @@ const struct testcase testevt1 = {
|
|||
const struct testcase * const patternevt[] = {
|
||||
#if CH_USE_EVENTS
|
||||
&testevt1,
|
||||
&testevt2,
|
||||
#if CH_USE_EVENTS_TIMEOUT
|
||||
&testevt3,
|
||||
#endif
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
|
|
|
@ -44,21 +44,38 @@ static void heap1_execute(void) {
|
|||
p1 = chHeapAlloc(SIZE);
|
||||
p2 = chHeapAlloc(SIZE);
|
||||
p3 = chHeapAlloc(SIZE);
|
||||
chHeapFree(p1); /* Does not merge */
|
||||
chHeapFree(p2); /* Merges backward */
|
||||
chHeapFree(p3); /* Merges both sides */
|
||||
chHeapFree(p1); /* Does not merge */
|
||||
chHeapFree(p2); /* Merges backward */
|
||||
chHeapFree(p3); /* Merges both sides */
|
||||
test_assert(chHeapStatus(&n) == 1, "#1"); /* Heap fragmented.*/
|
||||
|
||||
/* Reverse order */
|
||||
p1 = chHeapAlloc(SIZE);
|
||||
p2 = chHeapAlloc(SIZE);
|
||||
p3 = chHeapAlloc(SIZE);
|
||||
chHeapFree(p3); /* Merges forward */
|
||||
chHeapFree(p2); /* Merges forward */
|
||||
chHeapFree(p1); /* Merges forward */
|
||||
chHeapFree(p3); /* Merges forward */
|
||||
chHeapFree(p2); /* Merges forward */
|
||||
chHeapFree(p1); /* Merges forward */
|
||||
test_assert(chHeapStatus(&n) == 1, "#2"); /* Heap fragmented.*/
|
||||
|
||||
test_assert(n == sz, "#3"); /* Heap size changed.*/
|
||||
/* Small fragments handling */
|
||||
p1 = chHeapAlloc(SIZE + 1);
|
||||
p2 = chHeapAlloc(SIZE);
|
||||
chHeapFree(p1);
|
||||
test_assert(chHeapStatus(&n) == 2, "#3"); /* Heap must contain 2 blocks.*/
|
||||
p1 = chHeapAlloc(SIZE);
|
||||
test_assert(chHeapStatus(&n) == 1, "#4"); /* Heap fragmented.*/
|
||||
chHeapFree(p2);
|
||||
chHeapFree(p1);
|
||||
|
||||
/* Allocate all handling */
|
||||
(void)chHeapStatus(&n);
|
||||
p1 = chHeapAlloc(n);
|
||||
test_assert(chHeapStatus(&n) == 0, "#5"); /* Heap must be empty.*/
|
||||
chHeapFree(p1);
|
||||
|
||||
test_assert(chHeapStatus(&n) == 1, "#6"); /* Heap fragmented.*/
|
||||
test_assert(n == sz, "#7"); /* Heap size changed.*/
|
||||
}
|
||||
else {
|
||||
test_print("--- Size : ");
|
||||
|
|
|
@ -85,7 +85,10 @@ static void sem2_setup(void) {
|
|||
static msg_t thread2(void *p) {
|
||||
|
||||
chThdSleepMilliseconds(50);
|
||||
chSemSignal(&sem1);
|
||||
chSysLock();
|
||||
chSemSignalI(&sem1); /* For coverage reasons */
|
||||
chSchRescheduleS();
|
||||
chSysUnlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -115,6 +118,7 @@ static void sem2_execute(void) {
|
|||
/*
|
||||
* Testing timeout condition.
|
||||
*/
|
||||
test_wait_tick();
|
||||
target_time = chTimeNow() + MS2ST(5 * 500);
|
||||
for (i = 0; i < 5; i++) {
|
||||
test_emit_token('A' + i);
|
||||
|
@ -134,6 +138,44 @@ const struct testcase testsem2 = {
|
|||
sem2_execute
|
||||
};
|
||||
#endif /* CH_USE_SEMAPHORES_TIMEOUT */
|
||||
|
||||
#if CH_USE_SEMSW
|
||||
static char *sem3_gettest(void) {
|
||||
|
||||
return "Semaphores, atomic signal-wait";
|
||||
}
|
||||
|
||||
static void sem3_setup(void) {
|
||||
|
||||
chSemInit(&sem1, 0);
|
||||
}
|
||||
|
||||
static msg_t thread3(void *p) {
|
||||
|
||||
chSemWait(&sem1);
|
||||
chSemSignal(&sem1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sem3_execute(void) {
|
||||
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriority()+1, thread3, "A");
|
||||
chSemSignalWait(&sem1, &sem1);
|
||||
test_assert(isempty(&sem1.s_queue), "#1"); /* Queue not empty */
|
||||
test_assert(sem1.s_cnt == 0, "#2"); /* Counter not zero */
|
||||
|
||||
chSemSignalWait(&sem1, &sem1);
|
||||
test_assert(isempty(&sem1.s_queue), "#3"); /* Queue not empty */
|
||||
test_assert(sem1.s_cnt == 0, "#4"); /* Counter not zero */
|
||||
}
|
||||
|
||||
const struct testcase testsem3 = {
|
||||
sem3_gettest,
|
||||
sem3_setup,
|
||||
NULL,
|
||||
sem3_execute
|
||||
};
|
||||
#endif /* CH_USE_SEMSW */
|
||||
#endif /* CH_USE_SEMAPHORES */
|
||||
|
||||
/*
|
||||
|
@ -145,6 +187,9 @@ const struct testcase * const patternsem[] = {
|
|||
#if CH_USE_SEMAPHORES_TIMEOUT
|
||||
&testsem2,
|
||||
#endif
|
||||
#if CH_USE_SEMSW
|
||||
&testsem3,
|
||||
#endif
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
|
|
|
@ -130,25 +130,27 @@ static char *thd4_gettest(void) {
|
|||
static void thd4_execute(void) {
|
||||
systime_t time;
|
||||
|
||||
test_wait_tick();
|
||||
|
||||
/* Timeouts in microseconds.*/
|
||||
time = chTimeNow();
|
||||
chThdSleepMicroseconds(100000);
|
||||
test_assert(chTimeIsWithin(time + US2ST(100000), time + US2ST(100000) + 1), "#1");
|
||||
test_assert_time_window(time + US2ST(100000), time + US2ST(100000) + 1);
|
||||
|
||||
/* Timeouts in milliseconds.*/
|
||||
time = chTimeNow();
|
||||
chThdSleepMilliseconds(100);
|
||||
test_assert(chTimeIsWithin(time + MS2ST(100), time + MS2ST(100) + 1), "#2");
|
||||
test_assert_time_window(time + MS2ST(100), time + MS2ST(100) + 1);
|
||||
|
||||
/* Timeouts in seconds.*/
|
||||
time = chTimeNow();
|
||||
chThdSleepSeconds(1);
|
||||
test_assert(chTimeIsWithin(time + S2ST(1), time + S2ST(1) + 1), "#3");
|
||||
test_assert_time_window(time + S2ST(1), time + S2ST(1) + 1);
|
||||
|
||||
/* Absolute timelines.*/
|
||||
time = chTimeNow() + MS2ST(100);
|
||||
chThdSleepUntil(time);
|
||||
test_assert(chTimeIsWithin(time, time + 1), "#4");
|
||||
test_assert_time_window(time, time + 1);
|
||||
}
|
||||
|
||||
const struct testcase testthd4 = {
|
||||
|
|
Loading…
Reference in New Issue