Skip to content

Extends test set for EventFlags class #5081

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 20, 2017
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
368 changes: 341 additions & 27 deletions TESTS/mbedmicro-rtos-mbed/event_flags/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,47 +17,361 @@

#include "mbed.h"
#include "greentea-client/test_env.h"
#include "rtos.h"
#include "unity/unity.h"
#include "utest/utest.h"

using utest::v1::Case;

#if defined(MBED_RTOS_SINGLE_THREAD)
#error [NOT_SUPPORTED] test not supported
#endif

#define TEST_STACK_SIZE 512
#define THREAD_STACK_SIZE 320 /* 512B stack on GCC_ARM compiler cause out of memory on some 16kB RAM boards e.g. NUCLEO_F070RB */

#define MAX_FLAG_POS 30
#define PROHIBITED_FLAG_POS 31

#define EVENT_SET_VALUE 0x01
const int EVENT_TO_EMIT = 100;
const int EVENT_HANDLE_DELAY = 25;
/* flags */
#define FLAG01 0x1FFF /* 00000000000000000001111111111111 */
#define FLAG02 0x3FFE000 /* 00000011111111111110000000000000 */
#define FLAG03 0x7C000000 /* 01111100000000000000000000000000 */
#define PROHIBITED_FLAG 0x80000000 /* 10000000000000000000000000000000 */
#define NO_FLAGS 0x0

DigitalOut led(LED1);
EventFlags event_flags;
Semaphore sync_sem(0, 1);

int events_counter = 0;
/* In order to successfully run this test suite when compiled with --profile=debug
* error() has to be redefined as noop.
*
* EventFlags calls RTX API which uses Event Recorder functionality. When compiled
* with MBED_TRAP_ERRORS_ENABLED=1 (set in debug profile) EvrRtxEventFlagsError() calls error()
* which aborts test program.
*/
#if defined(MBED_TRAP_ERRORS_ENABLED) && MBED_TRAP_ERRORS_ENABLED
void error(const char* format, ...) {
(void) format;
}
#endif

void led_thread() {
while (true) {
event_flags.wait_all(EVENT_SET_VALUE);
led = !led;
events_counter++;
template<uint32_t flags, uint32_t wait_ms>
void send_thread(EventFlags *ef)
{
for (uint32_t i = 0; i <= MAX_FLAG_POS; i++) {
const uint32_t flag = flags & (1 << i);
if (flag) {
ef->set(flag);
Thread::wait(wait_ms);
}
}
}

int main (void) {
GREENTEA_SETUP(10, "default_auto");
template<uint32_t flags, uint32_t wait_ms>
void send_thread_sync(EventFlags *ef)
{
for (uint32_t i = 0; i <= MAX_FLAG_POS; i++) {
const uint32_t flag = flags & (1 << i);
if (flag) {
sync_sem.wait();
ef->set(flag);
Thread::wait(wait_ms);
}
}
}

Thread thread(osPriorityNormal, TEST_STACK_SIZE);
thread.start(led_thread);
template<uint32_t flags>
void wait_thread_all(EventFlags *ef)
{
uint32_t ret, flags_after_clear;
ret = ef->wait_all(flags);
flags_after_clear = ef->get();
TEST_ASSERT(flags | ret);
TEST_ASSERT(flags | ~flags_after_clear);
}

bool result = false;

while (true) {
Thread::wait(2 * EVENT_HANDLE_DELAY);
event_flags.set(EVENT_SET_VALUE);
if (events_counter == EVENT_TO_EMIT) {
result = true;
break;
}
/** Test if get on empty EventFlags object return NO_FLAGS

Given a empty EventFlags object
When call @a get
Then @a get return status is NO_FLAGS
*/
void test_empty_get(void)
{
EventFlags ev;
uint32_t flags;

flags = ev.get();
TEST_ASSERT_EQUAL(NO_FLAGS, flags);
}

/** Test if clear on empty EventFlags object return NO_FLAGS

Given a empty EventFlags object
When call @a clear(NO_FLAGS)
Then @a clear return status is NO_FLAGS
*/
void test_empty_clear(void)
{
EventFlags ev;
uint32_t flags;

flags = ev.clear(NO_FLAGS);
TEST_ASSERT_EQUAL(NO_FLAGS, flags);
}

/** Test if set on empty EventFlags object return NO_FLAGS

Given a empty EventFlags object
When call @a set(NO_FLAGS)
Then @a set return status is NO_FLAGS
*/
void test_empty_set(void)
{
EventFlags ev;
uint32_t flags;

flags = ev.set(NO_FLAGS);
TEST_ASSERT_EQUAL(NO_FLAGS, flags);
}

/** Test if call of set/clean with PROHIBITED_FLAG doesn't invalidates object flags

Given a EventFlags object with all flags already set
When call @a clear(PROHIBITED_FLAG) with prohibited flag
Then @a clear return status is osFlagsErrorParameter and object flags stays unchanged
When call @a set(PROHIBITED_FLAG) with prohibited flag
Then @a set return status is osFlagsErrorParameter and object flags stays unchanged

@note Each signal has up to 31 event flags 0x1, 0x2, 0x4, 0x8, ..., 0x40000000
Most significant bit is reserved and thereby flag 0x80000000 is prohibited
*/
void test_prohibited(void)
{
EventFlags ev;
uint32_t flags;

ev.set(FLAG01 | FLAG02 | FLAG03);

flags = ev.clear(PROHIBITED_FLAG);
TEST_ASSERT_EQUAL(osFlagsErrorParameter, flags);

flags = ev.get();
TEST_ASSERT_EQUAL(FLAG01 | FLAG02 | FLAG03, flags);

flags = ev.set(PROHIBITED_FLAG);
TEST_ASSERT_EQUAL(osFlagsErrorParameter, flags);

flags = ev.get();
TEST_ASSERT_EQUAL(FLAG01 | FLAG02 | FLAG03, flags);
}

/** Test set/get/clear for full flag range

Given a EventFlags object
When call @a clear
Then @a clear return status is already set flags
When call @a set with specified flag
Then @a set return status is flags after setting
When call @a get
Then @a get return status is set flags
*/
void test_set_get_clear_full_flag_range(void)
{
EventFlags ev;
uint32_t flag, flags, ret;

flags = NO_FLAGS;
for (int i = 0; i <= MAX_FLAG_POS; i++) {
ret = ev.clear();
TEST_ASSERT_EQUAL(flags, ret);
flags = 1 << i;
ret = ev.set(flags);
TEST_ASSERT_EQUAL(flags, ret);
ret = ev.get();
TEST_ASSERT_EQUAL(flags, ret);
}

ev.clear();
flags = NO_FLAGS;
for (int i = 0; i <= MAX_FLAG_POS; i++) {
ret = ev.clear(NO_FLAGS);
TEST_ASSERT_EQUAL(flags, ret);
flag = 1 << i;
flags |= flag;
ret = ev.set(flag);
TEST_ASSERT_EQUAL(flags, ret);
ret = ev.get();
TEST_ASSERT_EQUAL(flags, ret);
}
}

/** Test if multi-threaded flag set cause wait_all to return

Given a EventFlags object and three threads are started in parallel
When threads set specified flags
Then main thread waits until receive all of them
*/
void test_multi_thread_all(void)
{
EventFlags ef;
Thread thread1(osPriorityNormal, THREAD_STACK_SIZE);
Thread thread2(osPriorityNormal, THREAD_STACK_SIZE);
Thread thread3(osPriorityNormal, THREAD_STACK_SIZE);
thread1.start(callback(send_thread<FLAG01, 1>, &ef));
thread2.start(callback(send_thread<FLAG02, 2>, &ef));
thread3.start(callback(send_thread<FLAG03, 3>, &ef));

uint32_t ret = ef.wait_all(FLAG01 | FLAG02 | FLAG03);
TEST_ASSERT_EQUAL(FLAG01 | FLAG02 | FLAG03, ret);
}

/** Test if multi-threaded flag set cause wait_any to return

Given a EventFlags object and three threads are started in parallel
When threads set specified flags
Then main thread waits until receive all of them
*/
void test_multi_thread_any(void)
{
EventFlags ef;
uint32_t ret;
Thread thread1(osPriorityNormal, THREAD_STACK_SIZE);
Thread thread2(osPriorityNormal, THREAD_STACK_SIZE);
Thread thread3(osPriorityNormal, THREAD_STACK_SIZE);
thread1.start(callback(send_thread<FLAG01, 1>, &ef));
thread2.start(callback(send_thread<FLAG02, 1>, &ef));
thread3.start(callback(send_thread<FLAG03, 1>, &ef));

for (int i = 0; i <= MAX_FLAG_POS; i++) {
uint32_t flag = 1 << i;
ret = ef.wait_any(flag);
TEST_ASSERT(flag | ret);
}
ret = ef.get();
TEST_ASSERT_EQUAL(NO_FLAGS, ret);
}

/** Test if multi-threaded flag set cause wait_any(with timeout) to return

Given a EventFlags object and thread is running
When main thread call @ wait_any with timeout
Then when timeout expires @ wait_any return status is osFlagsErrorTimeout
When main thread call @ wait_any with timeout and thread set specified flags
Then main thread waits until receive all of them and @ wait_any return status is wait flag
*/
void test_multi_thread_any_timeout(void)
{
EventFlags ef;
uint32_t ret;
Thread thread(osPriorityNormal, THREAD_STACK_SIZE);
thread.start(callback(send_thread_sync<FLAG01 | FLAG02 | FLAG03, 1>, &ef));

for (int i = 0; i <= MAX_FLAG_POS; i++) {
uint32_t flag = 1 << i;

ret = ef.wait_any(flag, 10);
TEST_ASSERT_EQUAL(osFlagsErrorTimeout, ret);

sync_sem.release();
ret = ef.wait_any(flag, 10);
TEST_ASSERT_EQUAL(flag, ret);
}
ret = ef.get();
TEST_ASSERT_EQUAL(NO_FLAGS, ret);
}

/** Test if multi-threaded flag set cause wait_any(without clear) to return

Given a EventFlags object and three threads are started in parallel
When threads set specified flags
Then main thread waits until receive all of them
*/
void test_multi_thread_any_no_clear(void)
{
EventFlags ef;
uint32_t ret;
Thread thread1(osPriorityNormal, THREAD_STACK_SIZE);
Thread thread2(osPriorityNormal, THREAD_STACK_SIZE);
Thread thread3(osPriorityNormal, THREAD_STACK_SIZE);
thread1.start(callback(send_thread<FLAG01, 1>, &ef));
thread2.start(callback(send_thread<FLAG02, 1>, &ef));
thread3.start(callback(send_thread<FLAG03, 1>, &ef));

for (int i = 0; i <= MAX_FLAG_POS; i++) {
uint32_t flag = 1 << i;
ret = ef.wait_any(flag, osWaitForever, false);
TEST_ASSERT(flag | ret);
ret = ef.clear(flag);
TEST_ASSERT(ret < osFlagsError);
}
ret = ef.get();
TEST_ASSERT_EQUAL(NO_FLAGS, ret);
}

/** Test multi-threaded wait_any

Given a EventFlags object and three threads are started in parallel
When flags are set in main thread
Then other threads waits until receive all of them
*/
void test_multi_thread_all_many_wait(void)
{
EventFlags ef;
{
Thread thread1(osPriorityNormal, THREAD_STACK_SIZE);
Thread thread2(osPriorityNormal, THREAD_STACK_SIZE);
Thread thread3(osPriorityNormal, THREAD_STACK_SIZE);
thread1.start(callback(wait_thread_all<FLAG01>, &ef));
thread2.start(callback(wait_thread_all<FLAG02>, &ef));
thread3.start(callback(wait_thread_all<FLAG03>, &ef));

ef.set(FLAG01 | FLAG02 | FLAG03);
thread1.join();
thread2.join();
thread3.join();
TEST_ASSERT_EQUAL(NO_FLAGS, ef.get());
}
GREENTEA_TESTSUITE_RESULT(result);
return 0;

{
Thread thread1(osPriorityNormal, THREAD_STACK_SIZE);
Thread thread2(osPriorityNormal, THREAD_STACK_SIZE);
Thread thread3(osPriorityNormal, THREAD_STACK_SIZE);
thread1.start(callback(wait_thread_all<FLAG01>, &ef));
thread2.start(callback(wait_thread_all<FLAG02>, &ef));
thread3.start(callback(wait_thread_all<FLAG03>, &ef));

ef.set(FLAG01);
thread1.join();
ef.set(FLAG02);
thread2.join();
ef.set(FLAG03);
thread3.join();
TEST_ASSERT_EQUAL(NO_FLAGS, ef.get());
}
}

utest::v1::status_t test_setup(const size_t number_of_cases)
{
GREENTEA_SETUP(10, "default_auto");
return utest::v1::verbose_test_setup_handler(number_of_cases);
}

Case cases[] = {
Case("Test empty clear", test_empty_clear),
Case("Test empty get", test_empty_get),
Case("Test empty set", test_empty_set),
Case("Test clear/set with prohibited flag", test_prohibited),
Case("Test set/get/clear for full flag range", test_set_get_clear_full_flag_range),
Case("Test multi-threaded wait_all", test_multi_thread_all),
Case("Test multi-threaded wait_any", test_multi_thread_any),
Case("Test multi-threaded wait_all many wait", test_multi_thread_all_many_wait),
Case("Test multi-threaded wait_any timeout", test_multi_thread_any_timeout),
Case("Test multi-threaded wait_any no clear", test_multi_thread_any_no_clear)
};

utest::v1::Specification specification(test_setup, cases);

int main()
{
return !utest::v1::Harness::run(specification);
}