circuitpython/atmel-samd/asf/common/utils/unit_test/suite.h
Scott Shawcroft 8f26d181c3 Blinking the LED works. Clocks should be set up correctly.
Everything works fine without USB being plugged in but faults (I think) when USB is plugged in. This is switched away from the USB code from the bootloader onto the USB code thats generated by Atmel Studio using the high level classes from ASF.
2016-08-22 23:53:11 -07:00

457 lines
14 KiB
C

/**
* \file
*
* \brief Test suite core declarations
*
* Copyright (c) 2011-2015 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
/*
* Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
*/
#ifndef TEST_SUITE_H_INCLUDED
#define TEST_SUITE_H_INCLUDED
#include <compiler.h>
#include <parts.h>
#include <stdio.h>
#if XMEGA
# include <progmem.h>
#endif
/**
* \defgroup test_suite_group Test Suite Framework
*
* This module is the test suite framework, which provides a set of standard
* functions and macros for defining and running test suites.
*
* A test \e suite consists of test \e cases. Each test case consists of a set
* of functions that are called in a specific order by the framework when the
* test suite is run. The runtime environment of a test is referred to as the
* test \e fixture. A setup function can be defined for the purpose of
* fulfilling preconditions that are needed for the test to run. To free up or
* reset resources which were used in the test case, a cleanup function can be
* defined.
*
* The following three functions can be defined for each test case:
* - fixture \e setup
* - test \e run
* - fixture \e cleanup
*
* The setup and/or cleanup functions may be skipped if they are not needed.
*
* A function may report an error or failure by use of the macros \ref test_fail
* , \ref test_assert_true and \ref test_assert_false. Note that only the first
* macro allows for the result value to be specified, while the two latter will
* automatically return TEST_FAIL if the specified condition is false.
*
* If any of the functions return a failure/error result, execution of that
* specific function is ended. However, depending on which function did not
* pass, execution of the test case may continue:
* - if the setup does not pass, the rest of the test case is skipped
* - if the test itself does not pass, cleanup will still be executed
*
* The result of the first function in the test case which does not pass
* determines the end result.
*
* Example code for definition of a test suite:
* \code
void setup_1(const struct test_case *test);
void run_1(const struct test_case *test);
void cleanup_1(const struct test_case *test);
void run_2(const struct test_case *test);
...
DEFINE_TEST_CASE(test_1,
setup_1,
run_1,
cleanup_1,
"First test");
DEFINE_TEST_CASE(test_2,
NULL,
run_2,
NULL,
"Second test");
DEFINE_TEST_ARRAY(my_tests) = {
&test_1,
&test_2,
};
DEFINE_TEST_SUITE(my_suite, my_tests, "Two-test suite");
test_suite_run(&my_suite);
...
\endcode
*
* Example code for definition of a test case:
* \code
void setup_1(const struct test_case *test)
{
void *resource = allocate_test_resource();
if (resource == NULL) {
test_fail(test, TEST_ERROR,
"Could not allocate test resource");
}
test_set_data(resource);
}
void run_1(const struct test_case *test)
{
void *resource = test_get_data();
int8_t test_result;
...
// TEST CODE
...
test_assert_true(test, test_result > 0,
"Test result is not larger than 0: %i", test_result);
test_assert_false(test, test_result > 2,
"Test result is larger than 2: %i", test_result);
}
void cleanup_1(const struct test_case *test)
{
void *resource = test_get_data();
free_test_resource(resource);
}
\endcode
*
* @{
*/
/**
* \brief A test case
*
* This structure represents a test case which tests one specific
* feature or behavior.
*/
struct test_case {
/**
* \brief Set up the environment in which \a test is to be run
*
* This may involve allocating memory, initializing hardware,
* etc. If something goes wrong, this function may call
* test_fail(), normally with a negative status code.
*/
void (*setup)(const struct test_case *test);
//! Run the test
void (*run)(const struct test_case *test);
/**
* \brief Clean up the environment after \a test has been run
*
* This may free up any memory allocated by setup(), gracefully
* shutting down hardware, etc. If something goes wrong, this
* function may call test_fail(), normally with a negative
* status code.
*/
void (*cleanup)(const struct test_case *test);
//! The name of the test case
const char *name;
};
/**
* \brief A test suite
*
* A test suite may contain one or more test cases which are to be run
* in sequence.
*/
struct test_suite {
//! The number of tests in this suite
unsigned int nr_tests;
//! Array of pointers to the test cases
const struct test_case *const *tests;
//! The name of the test suite
const char *name;
};
/**
* \name Wrappers for printing debug information
*
* \note The test suite framework feeds its output to printf. It is left up to
* the test application to set up the stream.
*/
//@{
#if XMEGA && !defined(__ICCAVR__)
# define dbg(__fmt_) \
printf_P(PROGMEM_STRING(__fmt_))
# define dbg_info(__fmt_, ...) \
printf_P(PROGMEM_STRING(__fmt_), __VA_ARGS__)
# define dbg_error(_x, ...) \
printf_P(PROGMEM_STRING(_x), __VA_ARGS__)
# define dbg_putchar(c) \
putc(c, stdout)
# define dbg_vprintf_pgm(...) \
vfprintf_P(stdout, __VA_ARGS__)
#else
# define dbg(__fmt_) \
printf(__fmt_)
# define dbg_info(__fmt_, ...) \
printf(__fmt_, __VA_ARGS__)
# define dbg_error(_x, ...) \
printf(_x, __VA_ARGS__)
# define dbg_putchar(c) \
putc(c, stdout)
# define dbg_vprintf_pgm(...) \
vfprintf(stdout, __VA_ARGS__)
#endif
//@}
//! \name Test suite definition macros
//@{
/**
* \brief Create a test case struct.
*
* \param _sym Variable name of the resulting struct
* \param _setup Function which sets up a test case environment. Can be NULL.
* \param _run Test function
* \param _cleanup Function which cleans up what was set up. Can be NULL.
* \param _name String describing the test case.
*/
#define DEFINE_TEST_CASE(_sym, _setup, _run, _cleanup, _name) \
static const char _test_str_##_sym[] = _name; \
static const struct test_case _sym = { \
.setup = _setup, \
.run = _run, \
.cleanup = _cleanup, \
.name = _test_str_##_sym, \
}
/**
* \brief Create an array of test case pointers.
*
* \param _sym Variable name of the resulting array
*/
#define DEFINE_TEST_ARRAY(_sym) \
const struct test_case *const _sym[]
/**
* \brief Create a test suite.
*
* \param _sym Variable name of the resulting struct
* \param _test_array Array of test cases, created with DEFINE_TEST_ARRAY()
* \param _name String describing the test suite.
*/
#define DEFINE_TEST_SUITE(_sym, _test_array, _name) \
static const char _test_str_##_sym[] = _name; \
const struct test_suite _sym = { \
.nr_tests = ARRAY_LEN(_test_array), \
.tests = _test_array, \
.name = _test_str_##_sym, \
}
//@}
#ifndef ARRAY_LEN
/**
* \internal
* \brief Convenience macro for counting elements in arrays
*/
# define ARRAY_LEN(a) (sizeof(a) / sizeof((a)[0]))
#endif
//! \name Test data access
//@{
extern void *test_priv_data;
/**
* \brief Set private data pointer for the current test.
*
* \param data Pointer to arbitrary run-time data for the test currently
* being run.
*/
static inline void test_set_data(void *data)
{
test_priv_data = data;
}
/**
* \brief Get the private data pointer for the current test.
*
* \return Pointer to arbitrary run-time data for the test currently
* being run, previously registered using test_set_data().
*/
static inline void *test_get_data(void)
{
return test_priv_data;
}
//@}
//! \name Test case pointer access
//@{
/**
* \brief Pointer to current test case
*/
extern struct test_case *test_case_ptr;
/**
* \internal
* \brief Set pointer to current test.
*/
static inline void test_set_case(const struct test_case *test)
{
test_case_ptr = (struct test_case *)test;
}
/**
* \internal
* \brief Get pointer to current test.
*/
static inline struct test_case *test_get_case(void)
{
return test_case_ptr;
}
//@}
//@{
//! \name Test result reporting
//@{
/**
* \brief Status codes returned by test cases and fixtures
*
* Note that test cases and especially fixtures may return any of the
* status codes defined by \ref status_code as well.
*/
enum test_status {
TEST_ERROR = -1, //!< Test error
TEST_PASS = 0, //!< Test success
TEST_FAIL = 1, //!< Test failure
};
/**
* \def test_fail(test, result, ...)
* \brief Fail the test
*
* Calling this function will cause the test to terminate with a
* failure. It will return directly to the test suite core, not to the
* caller.
*
* \param test Test case which failed
* \param result The result of the test (may not be 0)
* \param ... printf()-style format string and arguments
*/
#if XMEGA && !defined(__ICCAVR__)
# define test_priv_fail_ps(test, result, format, ...) \
do { \
static PROGMEM_DECLARE(char, _fmtstr[]) = format "%s"; \
test_case_fail(test, result, __FILE__, __LINE__, _fmtstr, \
__VA_ARGS__); \
} while (0)
# define test_fail(test, result, ...) \
test_priv_fail_ps(test, result, __VA_ARGS__, "")
#else
# define test_fail(test, result, ...) \
test_case_fail(test, result, __FILE__, __LINE__, __VA_ARGS__)
#endif
/**
* \brief Verify that \a condition is true
*
* If \a condition is false, fail the test with an error message
* indicating the condition which failed.
*
* \param test The test case currently being run
* \param condition Expression to be validated
* \param ... Format string and arguments
*/
#define test_assert_true(test, condition, ...) \
do { \
if (!(condition)) { \
test_fail(test, TEST_FAIL, __VA_ARGS__); \
} \
} while (0)
/**
* \brief Verify that \a condition is false
*
* If \a condition is true, fail the test with an error message
* indicating the condition which failed.
*
* \param test The test case currently being run
* \param condition Expression to be validated
* \param ... Format string and arguments
*/
#define test_assert_false(test, condition, ...) \
test_assert_true(test, !(condition), __VA_ARGS__)
//@}
//! \name Test suite interaction
//@{
extern int test_suite_run(const struct test_suite *suite);
//@}
#if defined(__GNUC__)
/* GCC should perform additional printf() argument sanity checks on the
* function call site to try to ensure arguments are printf() compatible */
__attribute__((format(__printf__, 5, 6)))
#endif
extern void test_case_fail(const struct test_case *test, int result,
const char *file, unsigned int line,
const char *fmt, ...);
//! @}
/**
* \brief Assert() macro definition for unit testing
*
* The Assert() macro is set up to use test_assert_true(),
* as this will only halt execution of the current test, allowing
* the remaining tests a chance to complete.
*/
#if defined(_ASSERT_ENABLE_) && defined(TEST_SUITE_DEFINE_ASSERT_MACRO)
# define Assert(expr) \
{ \
if (test_get_case() != NULL) { \
test_assert_true(test_get_case(), expr, \
"Assertion failed: %s", #expr); \
} else { \
if (!(expr)) { \
dbg_error("Assertion '%s' failed at %s:%d\r\n", \
#expr, __FILE__, __LINE__); \
while (true); \
} \
} \
}
#endif
#endif /* TEST_SUITE_H_INCLUDED */