From a202724feaf68aaf44986e2bc336de0008bb2c64 Mon Sep 17 00:00:00 2001 From: Giovanni Di Sirio Date: Tue, 17 Oct 2017 07:17:26 +0000 Subject: OS library test suite, not finished. git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@10840 35acf78f-673a-0410-8e92-d51de3d6d3f4 --- test/oslib/source/test/oslib_test_root.c | 146 +++++++ test/oslib/source/test/oslib_test_root.h | 95 +++++ test/oslib/source/test/oslib_test_sequence_001.c | 515 +++++++++++++++++++++++ test/oslib/source/test/oslib_test_sequence_001.h | 27 ++ test/oslib/source/test/oslib_test_sequence_002.c | 416 ++++++++++++++++++ test/oslib/source/test/oslib_test_sequence_002.h | 27 ++ test/oslib/source/test/oslib_test_sequence_003.c | 303 +++++++++++++ test/oslib/source/test/oslib_test_sequence_003.h | 27 ++ test/oslib/source/test/oslib_test_sequence_004.c | 279 ++++++++++++ test/oslib/source/test/oslib_test_sequence_004.h | 27 ++ 10 files changed, 1862 insertions(+) create mode 100644 test/oslib/source/test/oslib_test_root.c create mode 100644 test/oslib/source/test/oslib_test_root.h create mode 100644 test/oslib/source/test/oslib_test_sequence_001.c create mode 100644 test/oslib/source/test/oslib_test_sequence_001.h create mode 100644 test/oslib/source/test/oslib_test_sequence_002.c create mode 100644 test/oslib/source/test/oslib_test_sequence_002.h create mode 100644 test/oslib/source/test/oslib_test_sequence_003.c create mode 100644 test/oslib/source/test/oslib_test_sequence_003.h create mode 100644 test/oslib/source/test/oslib_test_sequence_004.c create mode 100644 test/oslib/source/test/oslib_test_sequence_004.h (limited to 'test/oslib/source') diff --git a/test/oslib/source/test/oslib_test_root.c b/test/oslib/source/test/oslib_test_root.c new file mode 100644 index 000000000..675595015 --- /dev/null +++ b/test/oslib/source/test/oslib_test_root.c @@ -0,0 +1,146 @@ +/* + ChibiOS - Copyright (C) 2006..2017 Giovanni Di Sirio + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @mainpage Test Suite Specification + * Test suite for ChibiOS OS Library. The purpose of this suite is to + * perform unit tests on the library modules and to converge to 100% + * code coverage through successive improvements. + * + *

Test Sequences

+ * - @subpage oslib_test_sequence_001 + * - @subpage oslib_test_sequence_002 + * - @subpage oslib_test_sequence_003 + * - @subpage oslib_test_sequence_004 + * . + */ + +/** + * @file oslib_test_root.c + * @brief Test Suite root structures code. + */ + +#include "hal.h" +#include "oslib_test_root.h" + +#if !defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Module exported variables. */ +/*===========================================================================*/ + +/** + * @brief Array of test sequences. + */ +const testsequence_t * const oslib_test_suite_array[] = { +#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__) + &oslib_test_sequence_001, +#endif +#if (CH_CFG_USE_MAILBOXES) || defined(__DOXYGEN__) + &oslib_test_sequence_002, +#endif +#if (CH_CFG_USE_MEMPOOLS) || defined(__DOXYGEN__) + &oslib_test_sequence_003, +#endif +#if (CH_CFG_USE_HEAP) || defined(__DOXYGEN__) + &oslib_test_sequence_004, +#endif + NULL +}; + +/** + * @brief Test suite root structure. + */ +const testsuite_t oslib_test_suite = { + NULL, + oslib_test_suite_array +}; + +/*===========================================================================*/ +/* Shared code. */ +/*===========================================================================*/ + +void test_print_port_info(void) { + +#ifdef PORT_COMPILER_NAME + test_print("*** Compiler: "); + test_println(PORT_COMPILER_NAME); +#endif + test_print("*** Architecture: "); + test_println(PORT_ARCHITECTURE_NAME); +#ifdef PORT_CORE_VARIANT_NAME + test_print("*** Core Variant: "); + test_println(PORT_CORE_VARIANT_NAME); +#endif +#ifdef PORT_INFO + test_print("*** Port Info: "); + test_println(PORT_INFO); +#endif +} + +/* + * Global test buffer holding 5 working areas. + */ +ALIGNED_VAR(PORT_WORKING_AREA_ALIGN) uint8_t test_buffer[WA_SIZE * 5]; + +/* + * Pointers to the spawned threads. + */ +thread_t *threads[MAX_THREADS]; + +/* + * Pointers to the working areas. + */ +void * ROMCONST wa[5] = {test_buffer + (WA_SIZE * 0), + test_buffer + (WA_SIZE * 1), + test_buffer + (WA_SIZE * 2), + test_buffer + (WA_SIZE * 3), + test_buffer + (WA_SIZE * 4)}; + +/* + * Sets a termination request in all the test-spawned threads. + */ +void test_terminate_threads(void) { + unsigned i; + + for (i = 0; i < MAX_THREADS; i++) + if (threads[i]) + chThdTerminate(threads[i]); +} + +/* + * Waits for the completion of all the test-spawned threads. + */ +void test_wait_threads(void) { + unsigned i; + + for (i = 0; i < MAX_THREADS; i++) + if (threads[i] != NULL) { + chThdWait(threads[i]); + threads[i] = NULL; + } +} + +/* + * Delays execution until next system time tick. + */ +systime_t test_wait_tick(void) { + + chThdSleep(1); + return chVTGetSystemTime(); +} + +#endif /* !defined(__DOXYGEN__) */ diff --git a/test/oslib/source/test/oslib_test_root.h b/test/oslib/source/test/oslib_test_root.h new file mode 100644 index 000000000..fe823f874 --- /dev/null +++ b/test/oslib/source/test/oslib_test_root.h @@ -0,0 +1,95 @@ +/* + ChibiOS - Copyright (C) 2006..2017 Giovanni Di Sirio + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file oslib_test_root.h + * @brief Test Suite root structures header. + */ + +#ifndef OSLIB_TEST_ROOT_H +#define OSLIB_TEST_ROOT_H + +#include "ch_test.h" + +#include "oslib_test_sequence_001.h" +#include "oslib_test_sequence_002.h" +#include "oslib_test_sequence_003.h" +#include "oslib_test_sequence_004.h" + +#if !defined(__DOXYGEN__) + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +extern const testsuite_t oslib_test_suite; + +#ifdef __cplusplus +extern "C" { +#endif +#ifdef __cplusplus +} +#endif + +/*===========================================================================*/ +/* Shared definitions. */ +/*===========================================================================*/ + +#define TEST_SUITE_NAME "ChibiOS/RT Test Suite" + +/* + * Allowed delay in timeout checks. + */ +#define ALLOWED_DELAY TIME_MS2I(2) + +/* + * Maximum number of test threads. + */ +#define MAX_THREADS 5 + +/* + * Stack size of test threads. + */ +#if defined(CH_ARCHITECTURE_AVR) || defined(CH_ARCHITECTURE_MSP430) +#define THREADS_STACK_SIZE 48 +#elif defined(CH_ARCHITECTURE_STM8) +#define THREADS_STACK_SIZE 64 +#elif defined(CH_ARCHITECTURE_SIMIA32) +#define THREADS_STACK_SIZE 512 +#else +#define THREADS_STACK_SIZE 128 +#endif + +/* + * Working Area size of test threads. + */ +#define WA_SIZE MEM_ALIGN_NEXT(THD_WORKING_AREA_SIZE(THREADS_STACK_SIZE), \ + PORT_WORKING_AREA_ALIGN) + +#define TEST_REPORT_HOOK_HEADER test_print_port_info(); + +extern uint8_t test_buffer[WA_SIZE * 5]; +extern thread_t *threads[MAX_THREADS]; +extern void * ROMCONST wa[5]; + +void test_print_port_info(void); +void test_terminate_threads(void); +void test_wait_threads(void); +systime_t test_wait_tick(void); + +#endif /* !defined(__DOXYGEN__) */ + +#endif /* OSLIB_TEST_ROOT_H */ diff --git a/test/oslib/source/test/oslib_test_sequence_001.c b/test/oslib/source/test/oslib_test_sequence_001.c new file mode 100644 index 000000000..49264f5d5 --- /dev/null +++ b/test/oslib/source/test/oslib_test_sequence_001.c @@ -0,0 +1,515 @@ +/* + ChibiOS - Copyright (C) 2006..2017 Giovanni Di Sirio + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#include "hal.h" +#include "oslib_test_root.h" + +/** + * @file oslib_test_sequence_001.c + * @brief Test Sequence 001 code. + * + * @page oslib_test_sequence_001 [1] Binary Semaphores + * + * File: @ref oslib_test_sequence_001.c + * + *

Description

+ * This sequence tests the ChibiOS library functionalities related to + * binary semaphores. + * + *

Conditions

+ * This sequence is only executed if the following preprocessor condition + * evaluates to true: + * - CH_CFG_USE_SEMAPHORES + * . + * + *

Test Cases

+ * - @subpage oslib_test_001_001 + * - @subpage oslib_test_001_002 + * - @subpage oslib_test_001_003 + * - @subpage oslib_test_001_004 + * - @subpage oslib_test_001_005 + * - @subpage oslib_test_001_006 + * . + */ + +#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__) + +/**************************************************************************** + * Shared code. + ****************************************************************************/ + +#include "ch.h" + +static semaphore_t sem1; + +static THD_FUNCTION(thread1, p) { + + chSemWait(&sem1); + test_emit_token(*(char *)p); +} + +static THD_FUNCTION(thread2, p) { + + (void)p; + chThdSleepMilliseconds(50); + chSysLock(); + chSemSignalI(&sem1); /* For coverage reasons */ + chSchRescheduleS(); + chSysUnlock(); +} + +static THD_FUNCTION(thread3, p) { + + (void)p; + chSemWait(&sem1); + chSemSignal(&sem1); +} + +static THD_FUNCTION(thread4, p) { + + chBSemSignal((binary_semaphore_t *)p); +} + +/**************************************************************************** + * Test cases. + ****************************************************************************/ + +/** + * @page oslib_test_001_001 [1.1] Semaphore primitives, no state change + * + *

Description

+ * Wait, Signal and Reset primitives are tested. The testing thread + * does not trigger a state change. + * + *

Test Steps

+ * - [1.1.1] The function chSemWait() is invoked, after return the + * counter and the returned message are tested. + * - [1.1.2] The function chSemSignal() is invoked, after return the + * counter is tested. + * - [1.1.3] The function chSemReset() is invoked, after return the + * counter is tested. + * . + */ + +static void oslib_test_001_001_setup(void) { + chSemObjectInit(&sem1, 1); +} + +static void oslib_test_001_001_teardown(void) { + chSemReset(&sem1, 0); +} + +static void oslib_test_001_001_execute(void) { + + /* [1.1.1] The function chSemWait() is invoked, after return the + counter and the returned message are tested.*/ + test_set_step(1); + { + msg_t msg; + + msg = chSemWait(&sem1); + test_assert_lock(chSemGetCounterI(&sem1) == 0, "wrong counter value"); + test_assert(MSG_OK == msg, "wrong returned message"); + } + + /* [1.1.2] The function chSemSignal() is invoked, after return the + counter is tested.*/ + test_set_step(2); + { + chSemSignal(&sem1); + test_assert_lock(chSemGetCounterI(&sem1) == 1, "wrong counter value"); + } + + /* [1.1.3] The function chSemReset() is invoked, after return the + counter is tested.*/ + test_set_step(3); + { + chSemReset(&sem1, 2); + test_assert_lock(chSemGetCounterI(&sem1) == 2, "wrong counter value"); + } +} + +static const testcase_t oslib_test_001_001 = { + "Semaphore primitives, no state change", + oslib_test_001_001_setup, + oslib_test_001_001_teardown, + oslib_test_001_001_execute +}; + +/** + * @page oslib_test_001_002 [1.2] Semaphore enqueuing test + * + *

Description

+ * Five threads with randomized priorities are enqueued to a semaphore + * then awakened one at time. The test expects that the threads reach + * their goal in FIFO order or priority order depending on the @p + * CH_CFG_USE_SEMAPHORES_PRIORITY configuration setting. + * + *

Test Steps

+ * - [1.2.1] Five threads are created with mixed priority levels (not + * increasing nor decreasing). Threads enqueue on a semaphore + * initialized to zero. + * - [1.2.2] The semaphore is signaled 5 times. The thread activation + * sequence is tested. + * . + */ + +static void oslib_test_001_002_setup(void) { + chSemObjectInit(&sem1, 0); +} + +static void oslib_test_001_002_execute(void) { + + /* [1.2.1] Five threads are created with mixed priority levels (not + increasing nor decreasing). Threads enqueue on a semaphore + initialized to zero.*/ + test_set_step(1); + { + threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()+5, thread1, "A"); + threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriorityX()+1, thread1, "B"); + threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriorityX()+3, thread1, "C"); + threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriorityX()+4, thread1, "D"); + threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriorityX()+2, thread1, "E"); + } + + /* [1.2.2] The semaphore is signaled 5 times. The thread activation + sequence is tested.*/ + test_set_step(2); + { + chSemSignal(&sem1); + chSemSignal(&sem1); + chSemSignal(&sem1); + chSemSignal(&sem1); + chSemSignal(&sem1); + test_wait_threads(); +#if CH_CFG_USE_SEMAPHORES_PRIORITY + test_assert_sequence("ADCEB", "invalid sequence"); +#else + test_assert_sequence("ABCDE", "invalid sequence"); +#endif + } +} + +static const testcase_t oslib_test_001_002 = { + "Semaphore enqueuing test", + oslib_test_001_002_setup, + NULL, + oslib_test_001_002_execute +}; + +/** + * @page oslib_test_001_003 [1.3] Semaphore timeout test + * + *

Description

+ * The three possible semaphore waiting modes (do not wait, wait with + * timeout, wait without timeout) are explored. The test expects that + * the semaphore wait function returns the correct value in each of the + * above scenario and that the semaphore structure status is correct + * after each operation. + * + *

Test Steps

+ * - [1.3.1] Testing special case TIME_IMMEDIATE. + * - [1.3.2] Testing non-timeout condition. + * - [1.3.3] Testing timeout condition. + * . + */ + +static void oslib_test_001_003_setup(void) { + chSemObjectInit(&sem1, 0); +} + +static void oslib_test_001_003_execute(void) { + unsigned i; + systime_t target_time; + msg_t msg; + + /* [1.3.1] Testing special case TIME_IMMEDIATE.*/ + test_set_step(1); + { + msg = chSemWaitTimeout(&sem1, TIME_IMMEDIATE); + test_assert(msg == MSG_TIMEOUT, "wrong wake-up message"); + test_assert(queue_isempty(&sem1.queue), "queue not empty"); + test_assert(sem1.cnt == 0, "counter not zero"); + } + + /* [1.3.2] Testing non-timeout condition.*/ + test_set_step(2); + { + threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX() - 1, + thread2, 0); + msg = chSemWaitTimeout(&sem1, TIME_MS2I(500)); + test_wait_threads(); + test_assert(msg == MSG_OK, "wrong wake-up message"); + test_assert(queue_isempty(&sem1.queue), "queue not empty"); + test_assert(sem1.cnt == 0, "counter not zero"); + } + + /* [1.3.3] Testing timeout condition.*/ + test_set_step(3); + { + target_time = test_wait_tick() + TIME_MS2I(5 * 50); + for (i = 0; i < 5; i++) { + test_emit_token('A' + i); + msg = chSemWaitTimeout(&sem1, TIME_MS2I(50)); + test_assert(msg == MSG_TIMEOUT, "wrong wake-up message"); + test_assert(queue_isempty(&sem1.queue), "queue not empty"); + test_assert(sem1.cnt == 0, "counter not zero"); + } + test_assert_sequence("ABCDE", "invalid sequence"); + test_assert_time_window(target_time, target_time + ALLOWED_DELAY, + "out of time window"); + } +} + +static const testcase_t oslib_test_001_003 = { + "Semaphore timeout test", + oslib_test_001_003_setup, + NULL, + oslib_test_001_003_execute +}; + +/** + * @page oslib_test_001_004 [1.4] Testing chSemAddCounterI() functionality + * + *

Description

+ * The functon is tested by waking up a thread then the semaphore + * counter value is tested. + * + *

Test Steps

+ * - [1.4.1] A thread is created, it goes to wait on the semaphore. + * - [1.4.2] The semaphore counter is increased by two, it is then + * tested to be one, the thread must have completed. + * . + */ + +static void oslib_test_001_004_setup(void) { + chSemObjectInit(&sem1, 0); +} + +static void oslib_test_001_004_execute(void) { + + /* [1.4.1] A thread is created, it goes to wait on the semaphore.*/ + test_set_step(1); + { + threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()+1, thread1, "A"); + } + + /* [1.4.2] The semaphore counter is increased by two, it is then + tested to be one, the thread must have completed.*/ + test_set_step(2); + { + chSysLock(); + chSemAddCounterI(&sem1, 2); + chSchRescheduleS(); + chSysUnlock(); + test_wait_threads(); + test_assert_lock(chSemGetCounterI(&sem1) == 1, "invalid counter"); + test_assert_sequence("A", "invalid sequence"); + } +} + +static const testcase_t oslib_test_001_004 = { + "Testing chSemAddCounterI() functionality", + oslib_test_001_004_setup, + NULL, + oslib_test_001_004_execute +}; + +/** + * @page oslib_test_001_005 [1.5] Testing chSemWaitSignal() functionality + * + *

Description

+ * This test case explicitly addresses the @p chSemWaitSignal() + * function. A thread is created that performs a wait and a signal + * operations. The tester thread is awakened from an atomic wait/signal + * operation. The test expects that the semaphore wait function returns + * the correct value in each of the above scenario and that the + * semaphore structure status is correct after each operation. + * + *

Test Steps

+ * - [1.5.1] An higher priority thread is created that performs + * non-atomical wait and signal operations on a semaphore. + * - [1.5.2] The function chSemSignalWait() is invoked by specifying + * the same semaphore for the wait and signal phases. The counter + * value must be one on exit. + * - [1.5.3] The function chSemSignalWait() is invoked again by + * specifying the same semaphore for the wait and signal phases. The + * counter value must be one on exit. + * . + */ + +static void oslib_test_001_005_setup(void) { + chSemObjectInit(&sem1, 0); +} + +static void oslib_test_001_005_teardown(void) { + test_wait_threads(); +} + +static void oslib_test_001_005_execute(void) { + + /* [1.5.1] An higher priority thread is created that performs + non-atomical wait and signal operations on a semaphore.*/ + test_set_step(1); + { + threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()+1, thread3, 0); + } + + /* [1.5.2] The function chSemSignalWait() is invoked by specifying + the same semaphore for the wait and signal phases. The counter + value must be one on exit.*/ + test_set_step(2); + { + chSemSignalWait(&sem1, &sem1); + test_assert(queue_isempty(&sem1.queue), "queue not empty"); + test_assert(sem1.cnt == 0, "counter not zero"); + } + + /* [1.5.3] The function chSemSignalWait() is invoked again by + specifying the same semaphore for the wait and signal phases. The + counter value must be one on exit.*/ + test_set_step(3); + { + chSemSignalWait(&sem1, &sem1); + test_assert(queue_isempty(&sem1.queue), "queue not empty"); + test_assert(sem1.cnt == 0, "counter not zero"); + } +} + +static const testcase_t oslib_test_001_005 = { + "Testing chSemWaitSignal() functionality", + oslib_test_001_005_setup, + oslib_test_001_005_teardown, + oslib_test_001_005_execute +}; + +/** + * @page oslib_test_001_006 [1.6] Testing Binary Semaphores special case + * + *

Description

+ * This test case tests the binary semaphores functionality. The test + * both checks the binary semaphore status and the expected status of + * the underlying counting semaphore. + * + *

Test Steps

+ * - [1.6.1] Creating a binary semaphore in "taken" state, the state is + * checked. + * - [1.6.2] Resetting the binary semaphore in "taken" state, the state + * must not change. + * - [1.6.3] Starting a signaler thread at a lower priority. + * - [1.6.4] Waiting for the binary semaphore to be signaled, the + * semaphore is expected to be taken. + * - [1.6.5] Signaling the binary semaphore, checking the binary + * semaphore state to be "not taken" and the underlying counter + * semaphore counter to be one. + * - [1.6.6] Signaling the binary semaphore again, the internal state + * must not change from "not taken". + * . + */ + +static void oslib_test_001_006_teardown(void) { + test_wait_threads(); +} + +static void oslib_test_001_006_execute(void) { + binary_semaphore_t bsem; + msg_t msg; + + /* [1.6.1] Creating a binary semaphore in "taken" state, the state is + checked.*/ + test_set_step(1); + { + chBSemObjectInit(&bsem, true); + test_assert_lock(chBSemGetStateI(&bsem) == true, "not taken"); + } + + /* [1.6.2] Resetting the binary semaphore in "taken" state, the state + must not change.*/ + test_set_step(2); + { + chBSemReset(&bsem, true); + test_assert_lock(chBSemGetStateI(&bsem) == true, "not taken"); + } + + /* [1.6.3] Starting a signaler thread at a lower priority.*/ + test_set_step(3); + { + threads[0] = chThdCreateStatic(wa[0], WA_SIZE, + chThdGetPriorityX()-1, thread4, &bsem); + } + + /* [1.6.4] Waiting for the binary semaphore to be signaled, the + semaphore is expected to be taken.*/ + test_set_step(4); + { + msg = chBSemWait(&bsem); + test_assert_lock(chBSemGetStateI(&bsem) == true, "not taken"); + test_assert(msg == MSG_OK, "unexpected message"); + } + + /* [1.6.5] Signaling the binary semaphore, checking the binary + semaphore state to be "not taken" and the underlying counter + semaphore counter to be one.*/ + test_set_step(5); + { + chBSemSignal(&bsem); + test_assert_lock(chBSemGetStateI(&bsem) ==false, "still taken"); + test_assert_lock(chSemGetCounterI(&bsem.sem) == 1, "unexpected counter"); + } + + /* [1.6.6] Signaling the binary semaphore again, the internal state + must not change from "not taken".*/ + test_set_step(6); + { + chBSemSignal(&bsem); + test_assert_lock(chBSemGetStateI(&bsem) == false, "taken"); + test_assert_lock(chSemGetCounterI(&bsem.sem) == 1, "unexpected counter"); + } +} + +static const testcase_t oslib_test_001_006 = { + "Testing Binary Semaphores special case", + NULL, + oslib_test_001_006_teardown, + oslib_test_001_006_execute +}; + +/**************************************************************************** + * Exported data. + ****************************************************************************/ + +/** + * @brief Array of test cases. + */ +const testcase_t * const oslib_test_sequence_001_array[] = { + &oslib_test_001_001, + &oslib_test_001_002, + &oslib_test_001_003, + &oslib_test_001_004, + &oslib_test_001_005, + &oslib_test_001_006, + NULL +}; + +/** + * @brief Binary Semaphores. + */ +const testsequence_t oslib_test_sequence_001 = { + NULL, + oslib_test_sequence_001_array +}; + +#endif /* CH_CFG_USE_SEMAPHORES */ diff --git a/test/oslib/source/test/oslib_test_sequence_001.h b/test/oslib/source/test/oslib_test_sequence_001.h new file mode 100644 index 000000000..161c5278b --- /dev/null +++ b/test/oslib/source/test/oslib_test_sequence_001.h @@ -0,0 +1,27 @@ +/* + ChibiOS - Copyright (C) 2006..2017 Giovanni Di Sirio + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file oslib_test_sequence_001.h + * @brief Test Sequence 001 header. + */ + +#ifndef OSLIB_TEST_SEQUENCE_001_H +#define OSLIB_TEST_SEQUENCE_001_H + +extern const testsequence_t oslib_test_sequence_001; + +#endif /* OSLIB_TEST_SEQUENCE_001_H */ diff --git a/test/oslib/source/test/oslib_test_sequence_002.c b/test/oslib/source/test/oslib_test_sequence_002.c new file mode 100644 index 000000000..5b4f10859 --- /dev/null +++ b/test/oslib/source/test/oslib_test_sequence_002.c @@ -0,0 +1,416 @@ +/* + ChibiOS - Copyright (C) 2006..2017 Giovanni Di Sirio + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#include "hal.h" +#include "oslib_test_root.h" + +/** + * @file oslib_test_sequence_002.c + * @brief Test Sequence 002 code. + * + * @page oslib_test_sequence_002 [2] Mailboxes + * + * File: @ref oslib_test_sequence_002.c + * + *

Description

+ * This sequence tests the ChibiOS libraryfunctionalities related to + * mailboxes. + * + *

Conditions

+ * This sequence is only executed if the following preprocessor condition + * evaluates to true: + * - CH_CFG_USE_MAILBOXES + * . + * + *

Test Cases

+ * - @subpage oslib_test_002_001 + * - @subpage oslib_test_002_002 + * - @subpage oslib_test_002_003 + * . + */ + +#if (CH_CFG_USE_MAILBOXES) || defined(__DOXYGEN__) + +/**************************************************************************** + * Shared code. + ****************************************************************************/ + +#define MB_SIZE 4 + +static msg_t mb_buffer[MB_SIZE]; +static MAILBOX_DECL(mb1, mb_buffer, MB_SIZE); + +/**************************************************************************** + * Test cases. + ****************************************************************************/ + +/** + * @page oslib_test_002_001 [2.1] Mailbox normal API, non-blocking tests + * + *

Description

+ * The mailbox normal API is tested without triggering blocking + * conditions. + * + *

Test Steps

+ * - [2.1.1] Testing the mailbox size. + * - [2.1.2] Resetting the mailbox, conditions are checked, no errors + * expected. + * - [2.1.3] Testing the behavior of API when the mailbox is in reset + * state then return in active state. + * - [2.1.4] Filling the mailbox using chMBPostTimeout() and + * chMBPostAheadTimeout() once, no errors expected. + * - [2.1.5] Testing intermediate conditions. Data pointers must be + * aligned, semaphore counters are checked. + * - [2.1.6] Emptying the mailbox using chMBFetchTimeout(), no errors + * expected. + * - [2.1.7] Posting and then fetching one more message, no errors + * expected. + * - [2.1.8] Testing final conditions. Data pointers must be aligned to + * buffer start, semaphore counters are checked. + * . + */ + +static void oslib_test_002_001_setup(void) { + chMBObjectInit(&mb1, mb_buffer, MB_SIZE); +} + +static void oslib_test_002_001_teardown(void) { + chMBReset(&mb1); +} + +static void oslib_test_002_001_execute(void) { + msg_t msg1, msg2; + unsigned i; + + /* [2.1.1] Testing the mailbox size.*/ + test_set_step(1); + { + test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "wrong size"); + } + + /* [2.1.2] Resetting the mailbox, conditions are checked, no errors + expected.*/ + test_set_step(2); + { + chMBReset(&mb1); + test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "not empty"); + test_assert_lock(chMBGetUsedCountI(&mb1) == 0, "still full"); + test_assert_lock(mb1.buffer == mb1.wrptr, "write pointer not aligned to base"); + test_assert_lock(mb1.buffer == mb1.rdptr, "read pointer not aligned to base"); + } + + /* [2.1.3] Testing the behavior of API when the mailbox is in reset + state then return in active state.*/ + test_set_step(3); + { + msg1 = chMBPostTimeout(&mb1, (msg_t)0, TIME_INFINITE); + test_assert(msg1 == MSG_RESET, "not in reset state"); + msg1 = chMBPostAheadTimeout(&mb1, (msg_t)0, TIME_INFINITE); + test_assert(msg1 == MSG_RESET, "not in reset state"); + msg1 = chMBFetchTimeout(&mb1, &msg2, TIME_INFINITE); + test_assert(msg1 == MSG_RESET, "not in reset state"); + chMBResumeX(&mb1); + } + + /* [2.1.4] Filling the mailbox using chMBPostTimeout() and + chMBPostAheadTimeout() once, no errors expected.*/ + test_set_step(4); + { + for (i = 0; i < MB_SIZE - 1; i++) { + msg1 = chMBPostTimeout(&mb1, 'B' + i, TIME_INFINITE); + test_assert(msg1 == MSG_OK, "wrong wake-up message"); + } + msg1 = chMBPostAheadTimeout(&mb1, 'A', TIME_INFINITE); + test_assert(msg1 == MSG_OK, "wrong wake-up message"); + } + + /* [2.1.5] Testing intermediate conditions. Data pointers must be + aligned, semaphore counters are checked.*/ + test_set_step(5); + { + test_assert_lock(chMBGetFreeCountI(&mb1) == 0, "still empty"); + test_assert_lock(chMBGetUsedCountI(&mb1) == MB_SIZE, "not full"); + test_assert_lock(mb1.rdptr == mb1.wrptr, "pointers not aligned"); + } + + /* [2.1.6] Emptying the mailbox using chMBFetchTimeout(), no errors + expected.*/ + test_set_step(6); + { + for (i = 0; i < MB_SIZE; i++) { + msg1 = chMBFetchTimeout(&mb1, &msg2, TIME_INFINITE); + test_assert(msg1 == MSG_OK, "wrong wake-up message"); + test_emit_token(msg2); + } + test_assert_sequence("ABCD", "wrong get sequence"); + } + + /* [2.1.7] Posting and then fetching one more message, no errors + expected.*/ + test_set_step(7); + { + msg1 = chMBPostTimeout(&mb1, 'B' + i, TIME_INFINITE); + test_assert(msg1 == MSG_OK, "wrong wake-up message"); + msg1 = chMBFetchTimeout(&mb1, &msg2, TIME_INFINITE); + test_assert(msg1 == MSG_OK, "wrong wake-up message"); + } + + /* [2.1.8] Testing final conditions. Data pointers must be aligned to + buffer start, semaphore counters are checked.*/ + test_set_step(8); + { + test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "not empty"); + test_assert_lock(chMBGetUsedCountI(&mb1) == 0, "still full"); + test_assert(mb1.buffer == mb1.wrptr, "write pointer not aligned to base"); + test_assert(mb1.buffer == mb1.rdptr, "read pointer not aligned to base"); + } +} + +static const testcase_t oslib_test_002_001 = { + "Mailbox normal API, non-blocking tests", + oslib_test_002_001_setup, + oslib_test_002_001_teardown, + oslib_test_002_001_execute +}; + +/** + * @page oslib_test_002_002 [2.2] Mailbox I-Class API, non-blocking tests + * + *

Description

+ * The mailbox I-Class API is tested without triggering blocking + * conditions. + * + *

Test Steps

+ * - [2.2.1] Testing the mailbox size. + * - [2.2.2] Resetting the mailbox, conditions are checked, no errors + * expected. The mailbox is then returned in active state. + * - [2.2.3] Filling the mailbox using chMBPostI() and chMBPostAheadI() + * once, no errors expected. + * - [2.2.4] Testing intermediate conditions. Data pointers must be + * aligned, semaphore counters are checked. + * - [2.2.5] Emptying the mailbox using chMBFetchI(), no errors + * expected. + * - [2.2.6] Posting and then fetching one more message, no errors + * expected. + * - [2.2.7] Testing final conditions. Data pointers must be aligned to + * buffer start, semaphore counters are checked. + * . + */ + +static void oslib_test_002_002_setup(void) { + chMBObjectInit(&mb1, mb_buffer, MB_SIZE); +} + +static void oslib_test_002_002_teardown(void) { + chMBReset(&mb1); +} + +static void oslib_test_002_002_execute(void) { + msg_t msg1, msg2; + unsigned i; + + /* [2.2.1] Testing the mailbox size.*/ + test_set_step(1); + { + test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "wrong size"); + } + + /* [2.2.2] Resetting the mailbox, conditions are checked, no errors + expected. The mailbox is then returned in active state.*/ + test_set_step(2); + { + chSysLock(); + chMBResetI(&mb1); + chSysUnlock(); + test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "not empty"); + test_assert_lock(chMBGetUsedCountI(&mb1) == 0, "still full"); + test_assert_lock(mb1.buffer == mb1.wrptr, "write pointer not aligned to base"); + test_assert_lock(mb1.buffer == mb1.rdptr, "read pointer not aligned to base"); + chMBResumeX(&mb1); + } + + /* [2.2.3] Filling the mailbox using chMBPostI() and chMBPostAheadI() + once, no errors expected.*/ + test_set_step(3); + { + for (i = 0; i < MB_SIZE - 1; i++) { + chSysLock(); + msg1 = chMBPostI(&mb1, 'B' + i); + chSysUnlock(); + test_assert(msg1 == MSG_OK, "wrong wake-up message"); + } + chSysLock(); + msg1 = chMBPostAheadI(&mb1, 'A'); + chSysUnlock(); + test_assert(msg1 == MSG_OK, "wrong wake-up message"); + } + + /* [2.2.4] Testing intermediate conditions. Data pointers must be + aligned, semaphore counters are checked.*/ + test_set_step(4); + { + test_assert_lock(chMBGetFreeCountI(&mb1) == 0, "still empty"); + test_assert_lock(chMBGetUsedCountI(&mb1) == MB_SIZE, "not full"); + test_assert_lock(mb1.rdptr == mb1.wrptr, "pointers not aligned"); + } + + /* [2.2.5] Emptying the mailbox using chMBFetchI(), no errors + expected.*/ + test_set_step(5); + { + for (i = 0; i < MB_SIZE; i++) { + chSysLock(); + msg1 = chMBFetchI(&mb1, &msg2); + chSysUnlock(); + test_assert(msg1 == MSG_OK, "wrong wake-up message"); + test_emit_token(msg2); + } + test_assert_sequence("ABCD", "wrong get sequence"); + } + + /* [2.2.6] Posting and then fetching one more message, no errors + expected.*/ + test_set_step(6); + { + msg1 = chMBPostTimeout(&mb1, 'B' + i, TIME_INFINITE); + test_assert(msg1 == MSG_OK, "wrong wake-up message"); + msg1 = chMBFetchTimeout(&mb1, &msg2, TIME_INFINITE); + test_assert(msg1 == MSG_OK, "wrong wake-up message"); + } + + /* [2.2.7] Testing final conditions. Data pointers must be aligned to + buffer start, semaphore counters are checked.*/ + test_set_step(7); + { + test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "not empty"); + test_assert_lock(chMBGetUsedCountI(&mb1) == 0, "still full"); + test_assert(mb1.buffer == mb1.wrptr, "write pointer not aligned to base"); + test_assert(mb1.buffer == mb1.rdptr, "read pointer not aligned to base"); + } +} + +static const testcase_t oslib_test_002_002 = { + "Mailbox I-Class API, non-blocking tests", + oslib_test_002_002_setup, + oslib_test_002_002_teardown, + oslib_test_002_002_execute +}; + +/** + * @page oslib_test_002_003 [2.3] Mailbox timeouts + * + *

Description

+ * The mailbox API is tested for timeouts. + * + *

Test Steps

+ * - [2.3.1] Filling the mailbox. + * - [2.3.2] Testing chMBPostTimeout(), chMBPostI(), + * chMBPostAheadTimeout() and chMBPostAheadI() timeout. + * - [2.3.3] Resetting the mailbox. The mailbox is then returned in + * active state. + * - [2.3.4] Testing chMBFetchTimeout() and chMBFetchI() timeout. + * . + */ + +static void oslib_test_002_003_setup(void) { + chMBObjectInit(&mb1, mb_buffer, MB_SIZE); +} + +static void oslib_test_002_003_teardown(void) { + chMBReset(&mb1); +} + +static void oslib_test_002_003_execute(void) { + msg_t msg1, msg2; + unsigned i; + + /* [2.3.1] Filling the mailbox.*/ + test_set_step(1); + { + for (i = 0; i < MB_SIZE; i++) { + msg1 = chMBPostTimeout(&mb1, 'B' + i, TIME_INFINITE); + test_assert(msg1 == MSG_OK, "wrong wake-up message"); + } + } + + /* [2.3.2] Testing chMBPostTimeout(), chMBPostI(), + chMBPostAheadTimeout() and chMBPostAheadI() timeout.*/ + test_set_step(2); + { + msg1 = chMBPostTimeout(&mb1, 'X', 1); + test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message"); + chSysLock(); + msg1 = chMBPostI(&mb1, 'X'); + chSysUnlock(); + test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message"); + msg1 = chMBPostAheadTimeout(&mb1, 'X', 1); + test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message"); + chSysLock(); + msg1 = chMBPostAheadI(&mb1, 'X'); + chSysUnlock(); + test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message"); + } + + /* [2.3.3] Resetting the mailbox. The mailbox is then returned in + active state.*/ + test_set_step(3); + { + chMBReset(&mb1); + chMBResumeX(&mb1); + } + + /* [2.3.4] Testing chMBFetchTimeout() and chMBFetchI() timeout.*/ + test_set_step(4); + { + msg1 = chMBFetchTimeout(&mb1, &msg2, 1); + test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message"); + chSysLock(); + msg1 = chMBFetchI(&mb1, &msg2); + chSysUnlock(); + test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message"); + } +} + +static const testcase_t oslib_test_002_003 = { + "Mailbox timeouts", + oslib_test_002_003_setup, + oslib_test_002_003_teardown, + oslib_test_002_003_execute +}; + +/**************************************************************************** + * Exported data. + ****************************************************************************/ + +/** + * @brief Array of test cases. + */ +const testcase_t * const oslib_test_sequence_002_array[] = { + &oslib_test_002_001, + &oslib_test_002_002, + &oslib_test_002_003, + NULL +}; + +/** + * @brief Mailboxes. + */ +const testsequence_t oslib_test_sequence_002 = { + NULL, + oslib_test_sequence_002_array +}; + +#endif /* CH_CFG_USE_MAILBOXES */ diff --git a/test/oslib/source/test/oslib_test_sequence_002.h b/test/oslib/source/test/oslib_test_sequence_002.h new file mode 100644 index 000000000..7525db632 --- /dev/null +++ b/test/oslib/source/test/oslib_test_sequence_002.h @@ -0,0 +1,27 @@ +/* + ChibiOS - Copyright (C) 2006..2017 Giovanni Di Sirio + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file oslib_test_sequence_002.h + * @brief Test Sequence 002 header. + */ + +#ifndef OSLIB_TEST_SEQUENCE_002_H +#define OSLIB_TEST_SEQUENCE_002_H + +extern const testsequence_t oslib_test_sequence_002; + +#endif /* OSLIB_TEST_SEQUENCE_002_H */ diff --git a/test/oslib/source/test/oslib_test_sequence_003.c b/test/oslib/source/test/oslib_test_sequence_003.c new file mode 100644 index 000000000..c103873ac --- /dev/null +++ b/test/oslib/source/test/oslib_test_sequence_003.c @@ -0,0 +1,303 @@ +/* + ChibiOS - Copyright (C) 2006..2017 Giovanni Di Sirio + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#include "hal.h" +#include "oslib_test_root.h" + +/** + * @file oslib_test_sequence_003.c + * @brief Test Sequence 003 code. + * + * @page oslib_test_sequence_003 [3] Memory Pools + * + * File: @ref oslib_test_sequence_003.c + * + *

Description

+ * This sequence tests the ChibiOS library functionalities related to + * memory pools. + * + *

Conditions

+ * This sequence is only executed if the following preprocessor condition + * evaluates to true: + * - CH_CFG_USE_MEMPOOLS + * . + * + *

Test Cases

+ * - @subpage oslib_test_003_001 + * - @subpage oslib_test_003_002 + * - @subpage oslib_test_003_003 + * . + */ + +#if (CH_CFG_USE_MEMPOOLS) || defined(__DOXYGEN__) + +/**************************************************************************** + * Shared code. + ****************************************************************************/ + +#define MEMORY_POOL_SIZE 4 + +static uint32_t objects[MEMORY_POOL_SIZE]; +static MEMORYPOOL_DECL(mp1, sizeof (uint32_t), PORT_NATURAL_ALIGN, NULL); + +#if CH_CFG_USE_SEMAPHORES +static GUARDEDMEMORYPOOL_DECL(gmp1, sizeof (uint32_t), PORT_NATURAL_ALIGN); +#endif + +static void *null_provider(size_t size, unsigned align) { + + (void)size; + (void)align; + + return NULL; +} + +/**************************************************************************** + * Test cases. + ****************************************************************************/ + +/** + * @page oslib_test_003_001 [3.1] Loading and emptying a memory pool + * + *

Description

+ * The memory pool functionality is tested by loading and emptying it, + * all conditions are tested. + * + *

Test Steps

+ * - [3.1.1] Adding the objects to the pool using chPoolLoadArray(). + * - [3.1.2] Emptying the pool using chPoolAlloc(). + * - [3.1.3] Now must be empty. + * - [3.1.4] Adding the objects to the pool using chPoolFree(). + * - [3.1.5] Emptying the pool using chPoolAlloc() again. + * - [3.1.6] Now must be empty again. + * - [3.1.7] Covering the case where a provider is unable to return + * more memory. + * . + */ + +static void oslib_test_003_001_setup(void) { + chPoolObjectInit(&mp1, sizeof (uint32_t), NULL); +} + +static void oslib_test_003_001_execute(void) { + unsigned i; + + /* [3.1.1] Adding the objects to the pool using chPoolLoadArray().*/ + test_set_step(1); + { + chPoolLoadArray(&mp1, objects, MEMORY_POOL_SIZE); + } + + /* [3.1.2] Emptying the pool using chPoolAlloc().*/ + test_set_step(2); + { + for (i = 0; i < MEMORY_POOL_SIZE; i++) + test_assert(chPoolAlloc(&mp1) != NULL, "list empty"); + } + + /* [3.1.3] Now must be empty.*/ + test_set_step(3); + { + test_assert(chPoolAlloc(&mp1) == NULL, "list not empty"); + } + + /* [3.1.4] Adding the objects to the pool using chPoolFree().*/ + test_set_step(4); + { + for (i = 0; i < MEMORY_POOL_SIZE; i++) + chPoolFree(&mp1, &objects[i]); + } + + /* [3.1.5] Emptying the pool using chPoolAlloc() again.*/ + test_set_step(5); + { + for (i = 0; i < MEMORY_POOL_SIZE; i++) + test_assert(chPoolAlloc(&mp1) != NULL, "list empty"); + } + + /* [3.1.6] Now must be empty again.*/ + test_set_step(6); + { + test_assert(chPoolAlloc(&mp1) == NULL, "list not empty"); + } + + /* [3.1.7] Covering the case where a provider is unable to return + more memory.*/ + test_set_step(7); + { + chPoolObjectInit(&mp1, sizeof (uint32_t), null_provider); + test_assert(chPoolAlloc(&mp1) == NULL, "provider returned memory"); + } +} + +static const testcase_t oslib_test_003_001 = { + "Loading and emptying a memory pool", + oslib_test_003_001_setup, + NULL, + oslib_test_003_001_execute +}; + +#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__) +/** + * @page oslib_test_003_002 [3.2] Loading and emptying a guarded memory pool without waiting + * + *

Description

+ * The memory pool functionality is tested by loading and emptying it, + * all conditions are tested. + * + *

Conditions

+ * This test is only executed if the following preprocessor condition + * evaluates to true: + * - CH_CFG_USE_SEMAPHORES + * . + * + *

Test Steps

+ * - [3.2.1] Adding the objects to the pool using + * chGuardedPoolLoadArray(). + * - [3.2.2] Emptying the pool using chGuardedPoolAllocTimeout(). + * - [3.2.3] Now must be empty. + * - [3.2.4] Adding the objects to the pool using chGuardedPoolFree(). + * - [3.2.5] Emptying the pool using chGuardedPoolAllocTimeout() again. + * - [3.2.6] Now must be empty again. + * . + */ + +static void oslib_test_003_002_setup(void) { + chGuardedPoolObjectInit(&gmp1, sizeof (uint32_t)); +} + +static void oslib_test_003_002_execute(void) { + unsigned i; + + /* [3.2.1] Adding the objects to the pool using + chGuardedPoolLoadArray().*/ + test_set_step(1); + { + chGuardedPoolLoadArray(&gmp1, objects, MEMORY_POOL_SIZE); + } + + /* [3.2.2] Emptying the pool using chGuardedPoolAllocTimeout().*/ + test_set_step(2); + { + for (i = 0; i < MEMORY_POOL_SIZE; i++) + test_assert(chGuardedPoolAllocTimeout(&gmp1, TIME_IMMEDIATE) != NULL, "list empty"); + } + + /* [3.2.3] Now must be empty.*/ + test_set_step(3); + { + test_assert(chGuardedPoolAllocTimeout(&gmp1, TIME_IMMEDIATE) == NULL, "list not empty"); + } + + /* [3.2.4] Adding the objects to the pool using + chGuardedPoolFree().*/ + test_set_step(4); + { + for (i = 0; i < MEMORY_POOL_SIZE; i++) + chGuardedPoolFree(&gmp1, &objects[i]); + } + + /* [3.2.5] Emptying the pool using chGuardedPoolAllocTimeout() + again.*/ + test_set_step(5); + { + for (i = 0; i < MEMORY_POOL_SIZE; i++) + test_assert(chGuardedPoolAllocTimeout(&gmp1, TIME_IMMEDIATE) != NULL, "list empty"); + } + + /* [3.2.6] Now must be empty again.*/ + test_set_step(6); + { + test_assert(chGuardedPoolAllocTimeout(&gmp1, TIME_IMMEDIATE) == NULL, "list not empty"); + } +} + +static const testcase_t oslib_test_003_002 = { + "Loading and emptying a guarded memory pool without waiting", + oslib_test_003_002_setup, + NULL, + oslib_test_003_002_execute +}; +#endif /* CH_CFG_USE_SEMAPHORES */ + +#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__) +/** + * @page oslib_test_003_003 [3.3] Guarded Memory Pools timeout + * + *

Description

+ * The timeout features for the Guarded Memory Pools is tested. + * + *

Conditions

+ * This test is only executed if the following preprocessor condition + * evaluates to true: + * - CH_CFG_USE_SEMAPHORES + * . + * + *

Test Steps

+ * - [3.3.1] Trying to allocate with 100mS timeout, must fail because + * the pool is empty. + * . + */ + +static void oslib_test_003_003_setup(void) { + chGuardedPoolObjectInit(&gmp1, sizeof (uint32_t)); +} + +static void oslib_test_003_003_execute(void) { + + /* [3.3.1] Trying to allocate with 100mS timeout, must fail because + the pool is empty.*/ + test_set_step(1); + { + test_assert(chGuardedPoolAllocTimeout(&gmp1, TIME_MS2I(100)) == NULL, "list not empty"); + } +} + +static const testcase_t oslib_test_003_003 = { + "Guarded Memory Pools timeout", + oslib_test_003_003_setup, + NULL, + oslib_test_003_003_execute +}; +#endif /* CH_CFG_USE_SEMAPHORES */ + +/**************************************************************************** + * Exported data. + ****************************************************************************/ + +/** + * @brief Array of test cases. + */ +const testcase_t * const oslib_test_sequence_003_array[] = { + &oslib_test_003_001, +#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__) + &oslib_test_003_002, +#endif +#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__) + &oslib_test_003_003, +#endif + NULL +}; + +/** + * @brief Memory Pools. + */ +const testsequence_t oslib_test_sequence_003 = { + NULL, + oslib_test_sequence_003_array +}; + +#endif /* CH_CFG_USE_MEMPOOLS */ diff --git a/test/oslib/source/test/oslib_test_sequence_003.h b/test/oslib/source/test/oslib_test_sequence_003.h new file mode 100644 index 000000000..57fc77602 --- /dev/null +++ b/test/oslib/source/test/oslib_test_sequence_003.h @@ -0,0 +1,27 @@ +/* + ChibiOS - Copyright (C) 2006..2017 Giovanni Di Sirio + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file oslib_test_sequence_003.h + * @brief Test Sequence 003 header. + */ + +#ifndef OSLIB_TEST_SEQUENCE_003_H +#define OSLIB_TEST_SEQUENCE_003_H + +extern const testsequence_t oslib_test_sequence_003; + +#endif /* OSLIB_TEST_SEQUENCE_003_H */ diff --git a/test/oslib/source/test/oslib_test_sequence_004.c b/test/oslib/source/test/oslib_test_sequence_004.c new file mode 100644 index 000000000..cceae6958 --- /dev/null +++ b/test/oslib/source/test/oslib_test_sequence_004.c @@ -0,0 +1,279 @@ +/* + ChibiOS - Copyright (C) 2006..2017 Giovanni Di Sirio + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#include "hal.h" +#include "oslib_test_root.h" + +/** + * @file oslib_test_sequence_004.c + * @brief Test Sequence 004 code. + * + * @page oslib_test_sequence_004 [4] Memory Heaps + * + * File: @ref oslib_test_sequence_004.c + * + *

Description

+ * This sequence tests the ChibiOS library functionalities related to + * memory heaps. + * + *

Conditions

+ * This sequence is only executed if the following preprocessor condition + * evaluates to true: + * - CH_CFG_USE_HEAP + * . + * + *

Test Cases

+ * - @subpage oslib_test_004_001 + * - @subpage oslib_test_004_002 + * . + */ + +#if (CH_CFG_USE_HEAP) || defined(__DOXYGEN__) + +/**************************************************************************** + * Shared code. + ****************************************************************************/ + +#define ALLOC_SIZE 16 +#define HEAP_SIZE (ALLOC_SIZE * 8) + +memory_heap_t test_heap; + +/**************************************************************************** + * Test cases. + ****************************************************************************/ + +/** + * @page oslib_test_004_001 [4.1] Allocation and fragmentation + * + *

Description

+ * Series of allocations/deallocations are performed in carefully + * designed sequences in order to stimulate all the possible code paths + * inside the allocator. The test expects to find the heap back to the + * initial status after each sequence. + * + *

Test Steps

+ * - [4.1.1] Testing initial conditions, the heap must not be + * fragmented and one free block present. + * - [4.1.2] Trying to allocate an block bigger than available space, + * an error is expected. + * - [4.1.3] Single block allocation using chHeapAlloc() then the block + * is freed using chHeapFree(), must not fail. + * - [4.1.4] Using chHeapStatus() to assess the heap state. There must + * be at least one free block of sufficient size. + * - [4.1.5] Allocating then freeing in the same order. + * - [4.1.6] Allocating then freeing in reverse order. + * - [4.1.7] Small fragments handling. Checking the behavior when + * allocating blocks with size not multiple of alignment unit. + * - [4.1.8] Skipping a fragment, the first fragment in the list is too + * small so the allocator must pick the second one. + * - [4.1.9] Allocating the whole available space. + * - [4.1.10] Testing final conditions. The heap geometry must be the + * same than the one registered at beginning. + * . + */ + +static void oslib_test_004_001_setup(void) { + chHeapObjectInit(&test_heap, test_buffer, sizeof(test_buffer)); +} + +static void oslib_test_004_001_execute(void) { + void *p1, *p2, *p3; + size_t n, sz; + + /* [4.1.1] Testing initial conditions, the heap must not be + fragmented and one free block present.*/ + test_set_step(1); + { + test_assert(chHeapStatus(&test_heap, &sz, NULL) == 1, "heap fragmented"); + } + + /* [4.1.2] Trying to allocate an block bigger than available space, + an error is expected.*/ + test_set_step(2); + { + p1 = chHeapAlloc(&test_heap, sizeof test_buffer * 2); + test_assert(p1 == NULL, "allocation not failed"); + } + + /* [4.1.3] Single block allocation using chHeapAlloc() then the block + is freed using chHeapFree(), must not fail.*/ + test_set_step(3); + { + p1 = chHeapAlloc(&test_heap, ALLOC_SIZE); + test_assert(p1 != NULL, "allocation failed"); + chHeapFree(p1); + } + + /* [4.1.4] Using chHeapStatus() to assess the heap state. There must + be at least one free block of sufficient size.*/ + test_set_step(4); + { + size_t total_size, largest_size; + + n = chHeapStatus(&test_heap, &total_size, &largest_size); + test_assert(n == 1, "missing free block"); + test_assert(total_size >= ALLOC_SIZE, "unexpected heap state"); + test_assert(total_size == largest_size, "unexpected heap state"); + } + + /* [4.1.5] Allocating then freeing in the same order.*/ + test_set_step(5); + { + p1 = chHeapAlloc(&test_heap, ALLOC_SIZE); + p2 = chHeapAlloc(&test_heap, ALLOC_SIZE); + p3 = chHeapAlloc(&test_heap, ALLOC_SIZE); + chHeapFree(p1); /* Does not merge.*/ + chHeapFree(p2); /* Merges backward.*/ + chHeapFree(p3); /* Merges both sides.*/ + test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented"); + } + + /* [4.1.6] Allocating then freeing in reverse order.*/ + test_set_step(6); + { + p1 = chHeapAlloc(&test_heap, ALLOC_SIZE); + p2 = chHeapAlloc(&test_heap, ALLOC_SIZE); + p3 = chHeapAlloc(&test_heap, ALLOC_SIZE); + chHeapFree(p3); /* Merges forward.*/ + chHeapFree(p2); /* Merges forward.*/ + chHeapFree(p1); /* Merges forward.*/ + test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented"); + } + + /* [4.1.7] Small fragments handling. Checking the behavior when + allocating blocks with size not multiple of alignment unit.*/ + test_set_step(7); + { + p1 = chHeapAlloc(&test_heap, ALLOC_SIZE + 1); + p2 = chHeapAlloc(&test_heap, ALLOC_SIZE); + chHeapFree(p1); + test_assert(chHeapStatus(&test_heap, &n, NULL) == 2, "invalid state"); + p1 = chHeapAlloc(&test_heap, ALLOC_SIZE); + /* Note, the first situation happens when the alignment size is smaller + than the header size, the second in the other cases.*/ + test_assert((chHeapStatus(&test_heap, &n, NULL) == 1) || + (chHeapStatus(&test_heap, &n, NULL) == 2), "heap fragmented"); + chHeapFree(p2); + chHeapFree(p1); + test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented"); + } + + /* [4.1.8] Skipping a fragment, the first fragment in the list is too + small so the allocator must pick the second one.*/ + test_set_step(8); + { + p1 = chHeapAlloc(&test_heap, ALLOC_SIZE); + p2 = chHeapAlloc(&test_heap, ALLOC_SIZE); + chHeapFree(p1); + test_assert( chHeapStatus(&test_heap, &n, NULL) == 2, "invalid state"); + p1 = chHeapAlloc(&test_heap, ALLOC_SIZE * 2); /* Skips first fragment.*/ + chHeapFree(p1); + chHeapFree(p2); + test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented"); + } + + /* [4.1.9] Allocating the whole available space.*/ + test_set_step(9); + { + (void)chHeapStatus(&test_heap, &n, NULL); + p1 = chHeapAlloc(&test_heap, n); + test_assert(p1 != NULL, "allocation failed"); + test_assert(chHeapStatus(&test_heap, NULL, NULL) == 0, "not empty"); + chHeapFree(p1); + } + + /* [4.1.10] Testing final conditions. The heap geometry must be the + same than the one registered at beginning.*/ + test_set_step(10); + { + test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented"); + test_assert(n == sz, "size changed"); + } +} + +static const testcase_t oslib_test_004_001 = { + "Allocation and fragmentation", + oslib_test_004_001_setup, + NULL, + oslib_test_004_001_execute +}; + +/** + * @page oslib_test_004_002 [4.2] Default Heap + * + *

Description

+ * The default heap is pre-allocated in the system. We test base + * functionality. + * + *

Test Steps

+ * - [4.2.1] Single block allocation using chHeapAlloc() then the block + * is freed using chHeapFree(), must not fail. + * - [4.2.2] Testing allocation failure. + * . + */ + +static void oslib_test_004_002_execute(void) { + void *p1; + size_t total_size, largest_size; + + /* [4.2.1] Single block allocation using chHeapAlloc() then the block + is freed using chHeapFree(), must not fail.*/ + test_set_step(1); + { + (void)chHeapStatus(NULL, &total_size, &largest_size); + p1 = chHeapAlloc(&test_heap, ALLOC_SIZE); + test_assert(p1 != NULL, "allocation failed"); + chHeapFree(p1); + } + + /* [4.2.2] Testing allocation failure.*/ + test_set_step(2); + { + p1 = chHeapAlloc(NULL, (size_t)-256); + test_assert(p1 == NULL, "allocation not failed"); + } +} + +static const testcase_t oslib_test_004_002 = { + "Default Heap", + NULL, + NULL, + oslib_test_004_002_execute +}; + +/**************************************************************************** + * Exported data. + ****************************************************************************/ + +/** + * @brief Array of test cases. + */ +const testcase_t * const oslib_test_sequence_004_array[] = { + &oslib_test_004_001, + &oslib_test_004_002, + NULL +}; + +/** + * @brief Memory Heaps. + */ +const testsequence_t oslib_test_sequence_004 = { + NULL, + oslib_test_sequence_004_array +}; + +#endif /* CH_CFG_USE_HEAP */ diff --git a/test/oslib/source/test/oslib_test_sequence_004.h b/test/oslib/source/test/oslib_test_sequence_004.h new file mode 100644 index 000000000..c301863f2 --- /dev/null +++ b/test/oslib/source/test/oslib_test_sequence_004.h @@ -0,0 +1,27 @@ +/* + ChibiOS - Copyright (C) 2006..2017 Giovanni Di Sirio + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file oslib_test_sequence_004.h + * @brief Test Sequence 004 header. + */ + +#ifndef OSLIB_TEST_SEQUENCE_004_H +#define OSLIB_TEST_SEQUENCE_004_H + +extern const testsequence_t oslib_test_sequence_004; + +#endif /* OSLIB_TEST_SEQUENCE_004_H */ -- cgit v1.2.3