fix(test): Improve and fix the unit self-test.

This commit is contained in:
MacRsh
2025-08-06 02:48:57 +08:00
parent 1d09d55cd8
commit 7947a711a7
19 changed files with 1010 additions and 144 deletions

View File

@@ -29,8 +29,8 @@ extern "C" {
#if defined(MR_USE_SPRINTF_STD)
#define mr_vsnprintf(_b, _s, _f, _a) vsnprintf(_b, _s, _f, _a)
#define mr_vsprintf(_b, _f, _a) vsprintf(_b, _f, _a)
#define mr_snprintf(_b, _s, _f, ...) snprintf(_b, _s, _f, __VA_ARGS__)
#define mr_sprintf(_b, _f, ...) sprintf(_b, _f, __VA_ARGS__)
#define mr_snprintf(_b, _s, _f, ...) snprintf(_b, _s, _f, ##__VA_ARGS__)
#define mr_sprintf(_b, _f, ...) sprintf(_b, _f, ##__VA_ARGS__)
#else
/**
* @brief This function prints a formatted string to a buffer.

View File

@@ -37,6 +37,7 @@ extern "C" {
#define mr_strcpy(_d, _s) strcpy(_d, _s)
#define mr_strerror(_e) strerror(_e)
#define mr_strlen(_s) strlen(_s)
#define mr_strnlen(_s, _sz) strnlen(_s, _sz)
#define mr_strncmp(_s1, _s2, _sz) strncmp(_s1, _s2, _sz)
#define mr_strncpy(_d, _s, _sz) strncpy(_d, _s, _sz)
#define mr_strchr(_s, _c) strchr(_s, _c)

View File

@@ -105,29 +105,6 @@ MR_INLINE void mr_list_replace(mr_list_t *new, mr_list_t *old) {
old->next = old->prev = old;
}
/**
* @brief This function swaps two elements in the list.
*
* @param entry1 The first element.
* @param entry2 The second element.
*/
MR_INLINE void mr_list_swap(mr_list_t *entry1, mr_list_t *entry2) {
mr_list_t *tmp;
/* Remove from the list */
tmp = entry2->prev;
mr_list_del(entry2);
/* Replace in the list */
mr_list_replace(entry1, entry2);
if (tmp == entry1) {
tmp = entry2;
}
/* Add to the list */
mr_list_add(tmp, entry1);
}
/**
* @brief This function moves an element to the head of the list.
*

View File

@@ -31,28 +31,39 @@ extern mr_uint32_t __mr_test_status;
/* Test pass magic number definition */
#define __MR_TEST_MAGIC_PASS (0x70617373U)
/**
* @brief This macro function checks if the condition is true.
*
* @param _a The first operand.
* @param _cond The condition.
* @param _b The second operand.
* @param _type The operand type.
* @param _fmt The format string for the operand.
*/
/* Test printf macro definition */
#define __MR_TEST_PRINTF(_desc, _a_str, _a, _b_str, _b, _fmt) \
do { \
mr_printf("%s:%d\n", __FILE__, __LINE__); \
mr_printf("Expectation failed: %s\n", _desc); \
mr_printf(" %s = "_fmt \
"\n", \
(_a_str), (_a)); \
mr_printf(" %s = "_fmt \
"\n", \
(_b_str), (_b)); \
} while (0)
/* Test check macro definition */
#define __MR_TEST_CHECK(_a, _cond, _b, _type, _fmt) \
do { \
_type __a = (_type)(_a); \
_type __b = (_type)(_b); \
if (!(__a _cond __b)) { \
mr_printf("%s:%d: Test Failure\n", __FILE__, __LINE__); \
mr_printf("Expectation failed: %s %s %s\n", #_a, #_cond, #_b); \
mr_printf(" %s = "_fmt \
"\n", \
#_a, __a); \
mr_printf(" %s = "_fmt \
"\n", \
#_b, __b); \
__MR_TEST_PRINTF(#_a " " #_cond " " #_b, #_a, __a, #_b, __b, \
_fmt); \
__mr_test_status = ~__MR_TEST_MAGIC_PASS; \
} \
} while (0)
#define __MR_TEST_CHECK_NEAR(_a, _b, _e, _type, _fmt) \
do { \
_type __a = (_type)(_a); \
_type __b = (_type)(_b); \
_type __e = (_type)(_e); \
_type __c = (__a > __b) ? (__a - __b) : (__b - __a); \
if (!(__c <= __e)) { \
__MR_TEST_PRINTF("| " #_a " - " #_b " | <= " #_e, #_a, __a, #_b, \
__b, _fmt); \
__mr_test_status = ~__MR_TEST_MAGIC_PASS; \
} \
} while (0)
@@ -70,15 +81,34 @@ extern mr_uint32_t __mr_test_status;
__MR_TEST_CHECK(_a, >, _b, _type, _fmt)
#define __MR_TEST_GE(_a, _b, _type, _fmt) \
__MR_TEST_CHECK(_a, >=, _b, _type, _fmt)
#define __MR_TEST_NEAR(_a, _b, _e, _type, _fmt) \
__MR_TEST_CHECK_NEAR(_a, _b, _e, _type, _fmt)
/* Test condition macros definition */
#define __MR_TEST_COND_INT(_a, _cond, _b) \
__MR_TEST_##_cond(_a, _b, mr_int64_t, "%lld")
#define __MR_TEST_COND_UINT(_a, _cond, _b) \
__MR_TEST_##_cond(_a, _b, mr_uint64_t, "%llu")
#define __MR_TEST_COND_PTR(_a, _cond, _b) \
__MR_TEST_##_cond(_a, _b, mr_ptr_t, "%p")
#define __MR_TEST_COND_FLOAT(_a, _cond, _b) \
__MR_TEST_##_cond(_a, _b, mr_f32_t, "%f")
#define __MR_TEST_COND_DOUBLE(_a, _cond, _b) \
__MR_TEST_##_cond(_a, _b, mr_f64_t, "%lf")
#define __MR_TEST_COND_NEAR(_a, _b, _e) \
__MR_TEST_NEAR(_a, _b, _e, mr_f64_t, "%lf")
/* Test expect and assert macros definition */
#define __MR_TEST_EXPECT(_check) _check
#define __MR_TEST_ASSERT(_check) \
do { \
mr_uint32_t __s = __mr_test_status; \
__mr_test_status = __MR_TEST_MAGIC_PASS; \
_check; \
if (__mr_test_status == (~__MR_TEST_MAGIC_PASS)) { \
return; \
} \
__mr_test_status = __s; \
} while (0)
#endif /* defined(MR_USE_TEST) */

View File

@@ -26,135 +26,141 @@ extern "C" {
#if defined(MR_USE_TEST)
/* Test expect and assert equality macros definition */
#define MR_TEST_EXPECT_EQ_INT(_a, _b) \
__MR_TEST_EXPECT(__MR_TEST_EQ(_a, _b, mr_int64_t, "%lld"))
__MR_TEST_EXPECT(__MR_TEST_COND_INT(_a, EQ, _b))
#define MR_TEST_EXPECT_EQ_UINT(_a, _b) \
__MR_TEST_EXPECT(__MR_TEST_EQ(_a, _b, mr_uint64_t, "%llu"))
__MR_TEST_EXPECT(__MR_TEST_COND_UINT(_a, EQ, _b))
#define MR_TEST_EXPECT_EQ_PTR(_a, _b) \
__MR_TEST_EXPECT(__MR_TEST_EQ(_a, _b, mr_ptr_t, "%p"))
__MR_TEST_EXPECT(__MR_TEST_COND_PTR(_a, EQ, _b))
#define MR_TEST_EXPECT_EQ_FLOAT(_a, _b) \
__MR_TEST_EXPECT(__MR_TEST_EQ(_a, _b, float, "%f"))
__MR_TEST_EXPECT(__MR_TEST_COND_NEAR(_a, _b, 1e-6))
#define MR_TEST_EXPECT_EQ_DOUBLE(_a, _b) \
__MR_TEST_EXPECT(__MR_TEST_EQ(_a, _b, double, "%f"))
__MR_TEST_EXPECT(__MR_TEST_COND_NEAR(_a, _b, 1e-8))
#define MR_TEST_ASSERT_EQ_INT(_a, _b) \
__MR_TEST_ASSERT(__MR_TEST_EQ(_a, _b, mr_int64_t, "%lld"))
__MR_TEST_ASSERT(__MR_TEST_COND_INT(_a, EQ, _b))
#define MR_TEST_ASSERT_EQ_UINT(_a, _b) \
__MR_TEST_ASSERT(__MR_TEST_EQ(_a, _b, mr_uint64_t, "%llu"))
__MR_TEST_ASSERT(__MR_TEST_COND_UINT(_a, EQ, _b))
#define MR_TEST_ASSERT_EQ_PTR(_a, _b) \
__MR_TEST_ASSERT(__MR_TEST_EQ(_a, _b, mr_ptr_t, "%p"))
__MR_TEST_ASSERT(__MR_TEST_COND_PTR(_a, EQ, _b))
#define MR_TEST_ASSERT_EQ_FLOAT(_a, _b) \
__MR_TEST_ASSERT(__MR_TEST_EQ(_a, _b, float, "%f"))
__MR_TEST_ASSERT(__MR_TEST_COND_NEAR(_a, _b, 1e-6))
#define MR_TEST_ASSERT_EQ_DOUBLE(_a, _b) \
__MR_TEST_ASSERT(__MR_TEST_EQ(_a, _b, double, "%f"))
__MR_TEST_ASSERT(__MR_TEST_COND_NEAR(_a, _b, 1e-8))
/* Test expect and assert inequality macros definition */
#define MR_TEST_EXPECT_NE_INT(_a, _b) \
__MR_TEST_EXPECT(__MR_TEST_NE(_a, _b, mr_int64_t, "%lld"))
__MR_TEST_EXPECT(__MR_TEST_COND_INT(_a, NE, _b))
#define MR_TEST_EXPECT_NE_UINT(_a, _b) \
__MR_TEST_EXPECT(__MR_TEST_NE(_a, _b, mr_uint64_t, "%llu"))
__MR_TEST_EXPECT(__MR_TEST_COND_UINT(_a, NE, _b))
#define MR_TEST_EXPECT_NE_PTR(_a, _b) \
__MR_TEST_EXPECT(__MR_TEST_NE(_a, _b, mr_ptr_t, "%p"))
__MR_TEST_EXPECT(__MR_TEST_COND_PTR(_a, NE, _b))
#define MR_TEST_EXPECT_NE_FLOAT(_a, _b) \
__MR_TEST_EXPECT(__MR_TEST_NE(_a, _b, float, "%f"))
__MR_TEST_EXPECT(__MR_TEST_COND_FLOAT(_a, NE, _b))
#define MR_TEST_EXPECT_NE_DOUBLE(_a, _b) \
__MR_TEST_EXPECT(__MR_TEST_NE(_a, _b, double, "%f"))
__MR_TEST_EXPECT(__MR_TEST_COND_DOUBLE(_a, NE, _b))
#define MR_TEST_ASSERT_NE_INT(_a, _b) \
__MR_TEST_ASSERT(__MR_TEST_NE(_a, _b, mr_int64_t, "%lld"))
__MR_TEST_ASSERT(__MR_TEST_COND_INT(_a, NE, _b))
#define MR_TEST_ASSERT_NE_UINT(_a, _b) \
__MR_TEST_ASSERT(__MR_TEST_NE(_a, _b, mr_uint64_t, "%llu"))
__MR_TEST_ASSERT(__MR_TEST_COND_UINT(_a, NE, _b))
#define MR_TEST_ASSERT_NE_PTR(_a, _b) \
__MR_TEST_ASSERT(__MR_TEST_NE(_a, _b, mr_ptr_t, "%p"))
__MR_TEST_ASSERT(__MR_TEST_COND_PTR(_a, NE, _b))
#define MR_TEST_ASSERT_NE_FLOAT(_a, _b) \
__MR_TEST_ASSERT(__MR_TEST_NE(_a, _b, float, "%f"))
__MR_TEST_ASSERT(__MR_TEST_COND_FLOAT(_a, NE, _b))
#define MR_TEST_ASSERT_NE_DOUBLE(_a, _b) \
__MR_TEST_ASSERT(__MR_TEST_NE(_a, _b, double, "%f"))
__MR_TEST_ASSERT(__MR_TEST_COND_DOUBLE(_a, NE, _b))
/* Test expect and assert less than macros definition */
#define MR_TEST_EXPECT_LT_INT(_a, _b) \
__MR_TEST_EXPECT(__MR_TEST_LT(_a, _b, mr_int64_t, "%lld"))
__MR_TEST_EXPECT(__MR_TEST_COND_INT(_a, LT, _b))
#define MR_TEST_EXPECT_LT_UINT(_a, _b) \
__MR_TEST_EXPECT(__MR_TEST_LT(_a, _b, mr_uint64_t, "%llu"))
__MR_TEST_EXPECT(__MR_TEST_COND_UINT(_a, LT, _b))
#define MR_TEST_EXPECT_LT_PTR(_a, _b) \
__MR_TEST_EXPECT(__MR_TEST_LT(_a, _b, mr_ptr_t, "%p"))
__MR_TEST_EXPECT(__MR_TEST_COND_PTR(_a, LT, _b))
#define MR_TEST_EXPECT_LT_FLOAT(_a, _b) \
__MR_TEST_EXPECT(__MR_TEST_LT(_a, _b, float, "%f"))
__MR_TEST_EXPECT(__MR_TEST_COND_FLOAT(_a, LT, _b))
#define MR_TEST_EXPECT_LT_DOUBLE(_a, _b) \
__MR_TEST_EXPECT(__MR_TEST_LT(_a, _b, double, "%f"))
__MR_TEST_EXPECT(__MR_TEST_COND_DOUBLE(_a, LT, _b))
#define MR_TEST_ASSERT_LT_INT(_a, _b) \
__MR_TEST_ASSERT(__MR_TEST_LT(_a, _b, mr_int64_t, "%lld"))
__MR_TEST_ASSERT(__MR_TEST_COND_INT(_a, LT, _b))
#define MR_TEST_ASSERT_LT_UINT(_a, _b) \
__MR_TEST_ASSERT(__MR_TEST_LT(_a, _b, mr_uint64_t, "%llu"))
__MR_TEST_ASSERT(__MR_TEST_COND_UINT(_a, LT, _b))
#define MR_TEST_ASSERT_LT_PTR(_a, _b) \
__MR_TEST_ASSERT(__MR_TEST_LT(_a, _b, mr_ptr_t, "%p"))
__MR_TEST_ASSERT(__MR_TEST_COND_PTR(_a, LT, _b))
#define MR_TEST_ASSERT_LT_FLOAT(_a, _b) \
__MR_TEST_ASSERT(__MR_TEST_LT(_a, _b, float, "%f"))
__MR_TEST_ASSERT(__MR_TEST_COND_FLOAT(_a, LT, _b))
#define MR_TEST_ASSERT_LT_DOUBLE(_a, _b) \
__MR_TEST_ASSERT(__MR_TEST_LT(_a, _b, double, "%f"))
__MR_TEST_ASSERT(__MR_TEST_COND_DOUBLE(_a, LT, _b))
/* Test expect and assert less than or equal macros definition */
#define MR_TEST_EXPECT_LE_INT(_a, _b) \
__MR_TEST_EXPECT(__MR_TEST_LE(_a, _b, mr_int64_t, "%lld"))
__MR_TEST_EXPECT(__MR_TEST_COND_INT(_a, LE, _b))
#define MR_TEST_EXPECT_LE_UINT(_a, _b) \
__MR_TEST_EXPECT(__MR_TEST_LE(_a, _b, mr_uint64_t, "%llu"))
__MR_TEST_EXPECT(__MR_TEST_COND_UINT(_a, LE, _b))
#define MR_TEST_EXPECT_LE_PTR(_a, _b) \
__MR_TEST_EXPECT(__MR_TEST_LE(_a, _b, mr_ptr_t, "%p"))
__MR_TEST_EXPECT(__MR_TEST_COND_PTR(_a, LE, _b))
#define MR_TEST_EXPECT_LE_FLOAT(_a, _b) \
__MR_TEST_EXPECT(__MR_TEST_LE(_a, _b, float, "%f"))
__MR_TEST_EXPECT(__MR_TEST_COND_FLOAT(_a, LE, _b))
#define MR_TEST_EXPECT_LE_DOUBLE(_a, _b) \
__MR_TEST_EXPECT(__MR_TEST_LE(_a, _b, double, "%f"))
__MR_TEST_EXPECT(__MR_TEST_COND_DOUBLE(_a, LE, _b))
#define MR_TEST_ASSERT_LE_INT(_a, _b) \
__MR_TEST_ASSERT(__MR_TEST_LE(_a, _b, mr_int64_t, "%lld"))
__MR_TEST_ASSERT(__MR_TEST_COND_INT(_a, LE, _b))
#define MR_TEST_ASSERT_LE_UINT(_a, _b) \
__MR_TEST_ASSERT(__MR_TEST_LE(_a, _b, mr_uint64_t, "%llu"))
__MR_TEST_ASSERT(__MR_TEST_COND_UINT(_a, LE, _b))
#define MR_TEST_ASSERT_LE_PTR(_a, _b) \
__MR_TEST_ASSERT(__MR_TEST_LE(_a, _b, mr_ptr_t, "%p"))
__MR_TEST_ASSERT(__MR_TEST_COND_PTR(_a, LE, _b))
#define MR_TEST_ASSERT_LE_FLOAT(_a, _b) \
__MR_TEST_ASSERT(__MR_TEST_LE(_a, _b, float, "%f"))
__MR_TEST_ASSERT(__MR_TEST_COND_FLOAT(_a, LE, _b))
#define MR_TEST_ASSERT_LE_DOUBLE(_a, _b) \
__MR_TEST_ASSERT(__MR_TEST_LE(_a, _b, double, "%f"))
__MR_TEST_ASSERT(__MR_TEST_COND_DOUBLE(_a, LE, _b))
/* Test expect and assert greater than macros definition */
#define MR_TEST_EXPECT_GT_INT(_a, _b) \
__MR_TEST_EXPECT(__MR_TEST_GT(_a, _b, mr_int64_t, "%lld"))
__MR_TEST_EXPECT(__MR_TEST_COND_INT(_a, GT, _b))
#define MR_TEST_EXPECT_GT_UINT(_a, _b) \
__MR_TEST_EXPECT(__MR_TEST_GT(_a, _b, mr_uint64_t, "%llu"))
__MR_TEST_EXPECT(__MR_TEST_COND_UINT(_a, GT, _b))
#define MR_TEST_EXPECT_GT_PTR(_a, _b) \
__MR_TEST_EXPECT(__MR_TEST_GT(_a, _b, mr_ptr_t, "%p"))
__MR_TEST_EXPECT(__MR_TEST_COND_PTR(_a, GT, _b))
#define MR_TEST_EXPECT_GT_FLOAT(_a, _b) \
__MR_TEST_EXPECT(__MR_TEST_GT(_a, _b, float, "%f"))
__MR_TEST_EXPECT(__MR_TEST_COND_FLOAT(_a, GT, _b))
#define MR_TEST_EXPECT_GT_DOUBLE(_a, _b) \
__MR_TEST_EXPECT(__MR_TEST_GT(_a, _b, double, "%f"))
__MR_TEST_EXPECT(__MR_TEST_COND_DOUBLE(_a, GT, _b))
#define MR_TEST_ASSERT_GT_INT(_a, _b) \
__MR_TEST_ASSERT(__MR_TEST_GT(_a, _b, mr_int64_t, "%lld"))
__MR_TEST_ASSERT(__MR_TEST_COND_INT(_a, GT, _b))
#define MR_TEST_ASSERT_GT_UINT(_a, _b) \
__MR_TEST_ASSERT(__MR_TEST_GT(_a, _b, mr_uint64_t, "%llu"))
__MR_TEST_ASSERT(__MR_TEST_COND_UINT(_a, GT, _b))
#define MR_TEST_ASSERT_GT_PTR(_a, _b) \
__MR_TEST_ASSERT(__MR_TEST_GT(_a, _b, mr_ptr_t, "%p"))
__MR_TEST_ASSERT(__MR_TEST_COND_PTR(_a, GT, _b))
#define MR_TEST_ASSERT_GT_FLOAT(_a, _b) \
__MR_TEST_ASSERT(__MR_TEST_GT(_a, _b, float, "%f"))
__MR_TEST_ASSERT(__MR_TEST_COND_FLOAT(_a, GT, _b))
#define MR_TEST_ASSERT_GT_DOUBLE(_a, _b) \
__MR_TEST_ASSERT(__MR_TEST_GT(_a, _b, double, "%f"))
__MR_TEST_ASSERT(__MR_TEST_COND_DOUBLE(_a, GT, _b))
/* Test expect and assert greater than or equal macros definition */
#define MR_TEST_EXPECT_GE_INT(_a, _b) \
__MR_TEST_EXPECT(__MR_TEST_GE(_a, _b, mr_int64_t, "%lld"))
__MR_TEST_EXPECT(__MR_TEST_COND_INT(_a, GE, _b))
#define MR_TEST_EXPECT_GE_UINT(_a, _b) \
__MR_TEST_EXPECT(__MR_TEST_GE(_a, _b, mr_uint64_t, "%llu"))
__MR_TEST_EXPECT(__MR_TEST_COND_UINT(_a, GE, _b))
#define MR_TEST_EXPECT_GE_PTR(_a, _b) \
__MR_TEST_EXPECT(__MR_TEST_GE(_a, _b, mr_ptr_t, "%p"))
__MR_TEST_EXPECT(__MR_TEST_COND_PTR(_a, GE, _b))
#define MR_TEST_EXPECT_GE_FLOAT(_a, _b) \
__MR_TEST_EXPECT(__MR_TEST_GE(_a, _b, float, "%f"))
__MR_TEST_EXPECT(__MR_TEST_COND_FLOAT(_a, GE, _b))
#define MR_TEST_EXPECT_GE_DOUBLE(_a, _b) \
__MR_TEST_EXPECT(__MR_TEST_GE(_a, _b, double, "%f"))
__MR_TEST_EXPECT(__MR_TEST_COND_DOUBLE(_a, GE, _b))
#define MR_TEST_ASSERT_GE_INT(_a, _b) \
__MR_TEST_ASSERT(__MR_TEST_GE(_a, _b, mr_int64_t, "%lld"))
__MR_TEST_ASSERT(__MR_TEST_COND_INT(_a, GE, _b))
#define MR_TEST_ASSERT_GE_UINT(_a, _b) \
__MR_TEST_ASSERT(__MR_TEST_GE(_a, _b, mr_uint64_t, "%llu"))
__MR_TEST_ASSERT(__MR_TEST_COND_UINT(_a, GE, _b))
#define MR_TEST_ASSERT_GE_PTR(_a, _b) \
__MR_TEST_ASSERT(__MR_TEST_GE(_a, _b, mr_ptr_t, "%p"))
__MR_TEST_ASSERT(__MR_TEST_COND_PTR(_a, GE, _b))
#define MR_TEST_ASSERT_GE_FLOAT(_a, _b) \
__MR_TEST_ASSERT(__MR_TEST_GE(_a, _b, float, "%f"))
__MR_TEST_ASSERT(__MR_TEST_COND_FLOAT(_a, GE, _b))
#define MR_TEST_ASSERT_GE_DOUBLE(_a, _b) \
__MR_TEST_ASSERT(__MR_TEST_GE(_a, _b, double, "%f"))
__MR_TEST_ASSERT(__MR_TEST_COND_DOUBLE(_a, GE, _b))
/* Test expect and assert near macros definition */
#define MR_TEST_EXPECT_NEAR(_a, _b, _e) \
__MR_TEST_EXPECT(__MR_TEST_COND_NEAR(_a, _b, _e))
#define MR_TEST_ASSERT_NEAR(_a, _b, _e) \
__MR_TEST_ASSERT(__MR_TEST_COND_NEAR(_a, _b, _e))
/* Testcase entry type */
typedef void(mr_testcase_entry)(void);
@@ -183,9 +189,26 @@ typedef struct MR_ALIGN(MR_ALIGN_SIZE) mr_testcase {
__MR_TEST_EXPORT(_suite, _name, _entry, "1")
/**
* @brief This function runs all testcases.
* @brief This function runs a testcase.
*
* @param suite The testcase suite name.
* @param name The testcase name.
*/
int mr_test_all_run(void);
void mr_testcase_run(const char *suite, const char *name);
/**
* @brief This function runs a testsuite.
*
* @param suite The testsuite name.
*/
void mr_testsuite_run(const char *suite);
/**
* @brief This function runs all testcases.
*
* @return MR_TRUE on success, MR_FALSE on failure.
*/
mr_bool_t mr_test_run(void);
#endif /* defined(MR_USE_TEST) */
/** @} */

View File

@@ -90,6 +90,11 @@ void *mr_malloc(mr_size_t size) {
/* Align the size */
size = HEAP_ALIGN(size, MR_ALIGN_SIZE);
if (size == 0) {
/* Overflow */
mem = MR_NULL;
goto _exit;
}
/* Search for and take blocks that match the criteria */
for (blk = prev->next; blk->size < size; blk = blk->next) {

View File

@@ -211,7 +211,7 @@ int mr_vsnprintf(char *buf, mr_size_t size, const char *fmt, mr_va_list args) {
char eff;
/* Check parameter */
if ((!fmt) || (fmt[0] == '\0')) {
if (!fmt) {
return 0;
}
if (!buf) {
@@ -478,7 +478,7 @@ _default:
int mr_vsprintf(char *buf, const char *fmt, mr_va_list args) {
/* Format string no limit */
return mr_vsnprintf(buf, (mr_size_t)-1, fmt, args);
return mr_vsnprintf(buf, MR_SIZE_MAX - (mr_size_t)buf, fmt, args);
}
int mr_snprintf(char *buf, mr_size_t size, const char *fmt, ...) {

View File

@@ -16,7 +16,7 @@ int mr_sscanf(const char *buf, const char *fmt, ...) {
int ret;
/* Check parameter */
if ((!buf) || (!fmt) || (fmt[0] == '\0')) {
if ((!buf) || (!fmt)) {
return -1;
}

View File

@@ -9,6 +9,7 @@
#include <libc/mr_string.h>
#if defined(MR_USE_STRING)
#include <libc/mr_errno.h>
#endif /* defined(MR_USE_STRING) */
/* DeBruijn ffs32 */
const int __mr_ffs_debruijn32[32] = {
@@ -24,6 +25,7 @@ const int __mr_ffs_debruijn64[64] = {
55, 27, 41, 16, 35, 21, 32, 11, 26, 15, 20, 10, 14, 9, 8, 7,
};
#if defined(MR_USE_STRING)
void *mr_memccpy(void *dst, const void *src, int c, mr_size_t size) {
const char *s;
char *d;

188
test/kernel/list.c Normal file
View File

@@ -0,0 +1,188 @@
/**
* @copyright (c) 2024-2025, MacRsh
*
* @license SPDX-License-Identifier: Apache-2.0
*
* @date 2024-09-06 MacRsh First version
*/
#include <test/mr_test.h>
#if defined(MR_USE_TEST)
#include <mr-X/mr_list.h>
typedef struct test_node {
mr_list_t link;
int id;
} test_node_t;
/* -------------------------------------------------------------------------- */
/* Test: static init */
static void test_list_static_init(void) {
static mr_list_t head = MR_LIST_INIT(&head);
MR_TEST_ASSERT_EQ_INT(mr_list_is_empty(&head), MR_TRUE);
MR_TEST_ASSERT_EQ_PTR(head.next, &head);
MR_TEST_ASSERT_EQ_PTR(head.prev, &head);
}
MR_TEST_EXPORT(list, static_init, test_list_static_init);
/* -------------------------------------------------------------------------- */
/* Test: init/empty */
static void test_list_init_empty(void) {
mr_list_t head;
mr_list_init(&head);
MR_TEST_ASSERT_EQ_INT(mr_list_is_empty(&head), MR_TRUE);
}
MR_TEST_EXPORT(list, init_empty, test_list_init_empty);
/* -------------------------------------------------------------------------- */
/* Test: add elements */
static void test_list_add(void) {
test_node_t n1, n2, n3;
int ids[3], idx;
test_node_t *n;
mr_list_t *pos;
mr_list_t head;
mr_list_init(&head);
n1.id = 1;
n2.id = 2;
n3.id = 3;
mr_list_add(&head, &n1.link);
mr_list_add(&head, &n2.link);
mr_list_add(&head, &n3.link);
idx = 0;
MR_LIST_FOR_EACH(pos, &head) {
n = MR_LIST_ENTRY(pos, test_node_t, link);
ids[idx++] = n->id;
}
MR_TEST_ASSERT_EQ_INT(ids[0], 1);
MR_TEST_ASSERT_EQ_INT(ids[1], 2);
MR_TEST_ASSERT_EQ_INT(ids[2], 3);
}
MR_TEST_EXPORT(list, add, test_list_add);
/* -------------------------------------------------------------------------- */
/* Test: insert to head */
static void test_list_insert(void) {
test_node_t n1, n2;
test_node_t *n;
mr_list_t head;
mr_list_t *pos;
mr_list_init(&head);
n1.id = 1;
n2.id = 2;
mr_list_insert(&head, &n1.link);
mr_list_insert(&head, &n2.link);
pos = head.next;
n = MR_LIST_ENTRY(pos, test_node_t, link);
MR_TEST_ASSERT_EQ_INT(n->id, 2);
pos = pos->next;
n = MR_LIST_ENTRY(pos, test_node_t, link);
MR_TEST_ASSERT_EQ_INT(n->id, 1);
}
MR_TEST_EXPORT(list, insert, test_list_insert);
/* -------------------------------------------------------------------------- */
/* Test: remove element */
static void test_list_del(void) {
test_node_t n1, n2;
test_node_t *n;
mr_list_t head;
mr_list_init(&head);
n1.id = 1;
n2.id = 2;
mr_list_add(&head, &n1.link);
mr_list_add(&head, &n2.link);
mr_list_del(&n1.link);
n = MR_LIST_ENTRY(head.next, test_node_t, link);
MR_TEST_ASSERT_EQ_INT(mr_list_is_empty(&head), 0);
MR_TEST_ASSERT_EQ_INT(n->id, 2);
}
MR_TEST_EXPORT(list, del, test_list_del);
/* -------------------------------------------------------------------------- */
/* Test: replace element */
static void test_list_replace(void) {
test_node_t n1, n2, n3;
test_node_t *n;
mr_list_t head;
mr_list_t *pos;
mr_list_init(&head);
n1.id = 1;
n2.id = 2;
n3.id = 3;
mr_list_add(&head, &n1.link);
mr_list_add(&head, &n2.link);
mr_list_replace(&n3.link, &n1.link);
pos = head.next;
n = MR_LIST_ENTRY(pos, test_node_t, link);
MR_TEST_ASSERT_EQ_INT(n->id, 3);
pos = pos->next;
n = MR_LIST_ENTRY(pos, test_node_t, link);
MR_TEST_ASSERT_EQ_INT(n->id, 2);
}
MR_TEST_EXPORT(list, replace, test_list_replace);
/* -------------------------------------------------------------------------- */
/* Test: move element */
static void test_list_move(void) {
mr_list_t head1, head2;
test_node_t n1;
test_node_t *n;
mr_list_init(&head1);
mr_list_init(&head2);
n1.id = 42;
mr_list_add(&head1, &n1.link);
mr_list_move(&n1.link, &head2);
n = MR_LIST_ENTRY(head2.next, test_node_t, link);
MR_TEST_ASSERT_EQ_INT(mr_list_is_empty(&head1), 1);
MR_TEST_ASSERT_EQ_INT(mr_list_is_empty(&head2), 0);
MR_TEST_ASSERT_EQ_INT(n->id, 42);
}
MR_TEST_EXPORT(list, move, test_list_move);
/* -------------------------------------------------------------------------- */
/* Test: safe traversal and delete */
static void test_list_safe_foreach_del(void) {
test_node_t nodes[4];
mr_list_t *pos, *l;
int i, ids[2], idx;
mr_list_t head;
test_node_t *n;
mr_list_init(&head);
for (i = 0; i < 4; ++i) {
nodes[i].id = i;
mr_list_add(&head, &nodes[i].link);
}
MR_LIST_FOR_EACH_SAFE(pos, l, &head) {
test_node_t *node = MR_LIST_ENTRY(pos, test_node_t, link);
if ((node->id % 2) == 0) {
mr_list_del(pos);
}
}
idx = 0;
MR_LIST_FOR_EACH(pos, &head) {
n = MR_LIST_ENTRY(pos, test_node_t, link);
ids[idx++] = n->id;
}
MR_TEST_ASSERT_EQ_INT(idx, 2);
MR_TEST_ASSERT_EQ_INT(ids[0], 1);
MR_TEST_ASSERT_EQ_INT(ids[1], 3);
}
MR_TEST_EXPORT(list, safe_foreach_del, test_list_safe_foreach_del);
#endif /* defined(MR_USE_TEST) */

95
test/kernel/object.c Normal file
View File

@@ -0,0 +1,95 @@
/**
* @copyright (c) 2024-2025, MacRsh
*
* @license SPDX-License-Identifier: Apache-2.0
*
* @date 2024-09-06 MacRsh First version
*/
#include <test/mr_test.h>
#if defined(MR_USE_TEST)
#include <mr-X/mr_object.h>
typedef struct test_obj {
mr_object_t obj;
int data;
} test_obj_t;
static void test_obj_release(struct mr_object *obj) {
test_obj_t *t = (test_obj_t *)obj;
t->data = -1;
}
static const mr_clazz_t test_clazz = MR_CLAZZ_INIT("test", test_obj_release);
/* -------------------------------------------------------------------------- */
/* Test: Static initializer */
static void test_object_static_init(void) {
static test_obj_t o
= {.obj = MR_OBJECT_INIT(&o.o, &test_clazz), .data = 42};
MR_TEST_ASSERT_EQ_INT(MR_OBJECT_IS_INITED(&o.obj), MR_TRUE);
MR_TEST_ASSERT_EQ_INT(MR_OBJECT_CLAZZ_IS(&o.obj, &test_clazz), MR_TRUE);
}
MR_TEST_EXPORT(object, static_init, test_object_static_init);
/* -------------------------------------------------------------------------- */
/* Test: Dynamic init / del */
static void test_object_init_del(void) {
test_obj_t o;
MR_TEST_ASSERT_EQ_INT(mr_object_init(&o.obj, &test_clazz), 0);
MR_TEST_ASSERT_EQ_INT(MR_OBJECT_IS_INITED(&o.obj), MR_TRUE);
mr_object_del(&o.obj);
MR_TEST_ASSERT_EQ_INT(o.data, -1);
}
MR_TEST_EXPORT(object, init_del, test_object_init_del);
/* -------------------------------------------------------------------------- */
/* Test: Get / put reference counting */
static void test_object_refcount(void) {
mr_object_t *p;
test_obj_t o;
mr_object_init(&o.obj, &test_clazz);
p = mr_object_get(&o.obj);
MR_TEST_ASSERT_EQ_PTR(p, &o.obj);
p = mr_object_get(&o.obj);
MR_TEST_ASSERT_EQ_PTR(p, &o.obj);
MR_TEST_ASSERT_EQ_INT(mr_object_put(&o.obj), MR_FALSE);
MR_TEST_ASSERT_EQ_INT(mr_object_put(&o.obj), MR_FALSE);
MR_TEST_ASSERT_EQ_INT(mr_object_put(&o.obj), MR_TRUE);
}
MR_TEST_EXPORT(object, refcount, test_object_refcount);
/* -------------------------------------------------------------------------- */
/* Test: Null and double-init protection */
static void test_object_invalid(void) {
test_obj_t o;
MR_TEST_ASSERT_EQ_INT(mr_object_init(MR_NULL, &test_clazz), -MR_EINVAL);
MR_TEST_ASSERT_EQ_INT(mr_object_init(&o.obj, MR_NULL), 0);
mr_object_init(&o.obj, &test_clazz);
MR_TEST_ASSERT_EQ_INT(mr_object_init(&o.obj, &test_clazz), -MR_EINVAL);
}
MR_TEST_EXPORT(object, invalid, test_object_invalid);
/* -------------------------------------------------------------------------- */
/* Test: MR_OBJECT_CLAZZ_IS_OR */
static void test_object_clazz_or(void) {
test_obj_t o;
mr_object_init(&o.obj, &test_clazz);
MR_TEST_ASSERT_EQ_INT(MR_OBJECT_CLAZZ_IS_OR(&o.obj, &test_clazz, MR_NULL),
MR_TRUE);
MR_TEST_ASSERT_EQ_INT(MR_OBJECT_CLAZZ_IS_OR(&o.obj, MR_NULL, &test_clazz),
MR_TRUE);
MR_TEST_ASSERT_EQ_INT(MR_OBJECT_CLAZZ_IS_OR(&o.obj, MR_NULL, MR_NULL),
MR_FALSE);
}
MR_TEST_EXPORT(object, clazz_or, test_object_clazz_or);
#endif /* defined(MR_USE_TEST) */

74
test/kernel/ref.c Normal file
View File

@@ -0,0 +1,74 @@
/**
* @copyright (c) 2024-2025, MacRsh
*
* @license SPDX-License-Identifier: Apache-2.0
*
* @date 2024-09-06 MacRsh First version
*/
#include <test/mr_test.h>
#if defined(MR_USE_TEST)
#include <mr-X/mr_ref.h>
static void stub_release(mr_ref_t *ref) {
*ref = 0xdeadbeef;
}
/* -------------------------------------------------------------------------- */
/* Test: static init */
static void test_ref_static_init(void) {
static mr_ref_t r = MR_REF_INIT();
MR_TEST_ASSERT_EQ_INT(MR_REF_IS_INITED(r), MR_TRUE);
MR_TEST_ASSERT_EQ_INT(MR_REF_COUNT(r), 1);
}
MR_TEST_EXPORT(ref, static_init, test_ref_static_init);
/* -------------------------------------------------------------------------- */
/* Test: init/inited/count */
static void test_ref_init(void) {
mr_ref_t r;
mr_ref_init(&r);
MR_TEST_ASSERT_EQ_INT(MR_REF_IS_INITED(r), MR_TRUE);
MR_TEST_ASSERT_EQ_INT(MR_REF_COUNT(r), 1);
}
MR_TEST_EXPORT(ref, init, test_ref_init);
/* -------------------------------------------------------------------------- */
/* Test: get increments count */
static void test_ref_get(void) {
mr_ref_t r;
mr_ref_init(&r);
MR_TEST_ASSERT_EQ_INT(mr_ref_get(&r), MR_TRUE);
MR_TEST_ASSERT_EQ_INT(MR_REF_COUNT(r), 2);
MR_TEST_ASSERT_EQ_INT(mr_ref_get(&r), MR_TRUE);
MR_TEST_ASSERT_EQ_INT(MR_REF_COUNT(r), 3);
}
MR_TEST_EXPORT(ref, get, test_ref_get);
/* -------------------------------------------------------------------------- */
/* Test: put decrements and release */
static void test_ref_put(void) {
mr_ref_t r;
mr_ref_init(&r);
MR_TEST_ASSERT_EQ_INT(mr_ref_put(&r, stub_release), MR_TRUE);
MR_TEST_ASSERT_EQ_INT(r, 0xdeadbeef);
MR_TEST_ASSERT_EQ_INT(mr_ref_put(&r, stub_release), MR_FALSE);
MR_TEST_ASSERT_EQ_INT(r, 0xdeadbeef - 1);
}
MR_TEST_EXPORT(ref, put, test_ref_put);
/* -------------------------------------------------------------------------- */
/* Test: get after release fails */
static void test_ref_get_fail(void) {
mr_ref_t r;
mr_ref_init(&r);
mr_ref_put(&r, stub_release);
MR_TEST_ASSERT_EQ_INT(mr_ref_get(&r), MR_FALSE);
}
MR_TEST_EXPORT(ref, get_fail, test_ref_get_fail);
#endif /* defined(MR_USE_TEST) */

52
test/kernel/spinlock.c Normal file
View File

@@ -0,0 +1,52 @@
/**
* @copyright (c) 2024-2025, MacRsh
*
* @license SPDX-License-Identifier: Apache-2.0
*
* @date 2024-09-06 MacRsh First version
*/
#include <test/mr_test.h>
#if defined(MR_USE_TEST)
#include <mr-X/mr_spinlock.h>
/* -------------------------------------------------------------------------- */
/* Test: static initializer */
static void test_spinlock_static_init(void) {
static mr_spinlock_t lock = MR_SPINLOCK_INIT();
MR_TEST_ASSERT_EQ_INT(mr_spinlock_is_locked(&lock), 0);
}
MR_TEST_EXPORT(spinlock, static_init, test_spinlock_static_init);
/* -------------------------------------------------------------------------- */
/* Test: init / lock / unlock */
static void test_spinlock_lock_unlock(void) {
mr_spinlock_t lock;
mr_spinlock_init(&lock);
MR_TEST_ASSERT_EQ_INT(mr_spinlock_is_locked(&lock), 0);
mr_spinlock_lock(&lock);
MR_TEST_ASSERT_EQ_INT(mr_spinlock_is_locked(&lock), 1);
mr_spinlock_unlock(&lock);
MR_TEST_ASSERT_EQ_INT(mr_spinlock_is_locked(&lock), 0);
}
MR_TEST_EXPORT(spinlock, lock_unlock, test_spinlock_lock_unlock);
/* -------------------------------------------------------------------------- */
/* Test: lock_irqsave / unlock_irqrestore */
static void test_spinlock_irq_save_restore(void) {
mr_spinlock_t lock;
int mask;
mr_spinlock_init(&lock);
mask = mr_spinlock_lock_irqsave(&lock);
MR_TEST_ASSERT_EQ_INT(mr_spinlock_is_locked(&lock), 1);
mr_spinlock_unlock_irqrestore(&lock, mask);
MR_TEST_ASSERT_EQ_INT(mr_spinlock_is_locked(&lock), 0);
}
MR_TEST_EXPORT(spinlock, irq_save_restore, test_spinlock_irq_save_restore);
#endif /* defined(MR_USE_TEST) */

99
test/libc/atomic.c Normal file
View File

@@ -0,0 +1,99 @@
/**
* @copyright (c) 2024-2025, MacRsh
*
* @license SPDX-License-Identifier: Apache-2.0
*
* @date 2024-09-06 MacRsh First version
*/
#include <test/mr_test.h>
#if defined(MR_USE_TEST)
#include <libc/mr_atomic.h>
/* -------------------------------------------------------------------------- */
/* Test: static init */
static void test_atomic_static_init(void) {
static mr_atomic_t v = MR_ATOMIC_INIT(12345);
MR_TEST_ASSERT_EQ_INT(mr_atomic_load(&v), 12345);
}
MR_TEST_EXPORT(atomic, static_init, test_atomic_static_init);
/* -------------------------------------------------------------------------- */
/* Test: load/store */
static void test_atomic_load_store(void) {
mr_atomic_t v;
mr_atomic_init(&v, 0);
mr_atomic_store(&v, 42);
MR_TEST_ASSERT_EQ_INT(mr_atomic_load(&v), 42);
}
MR_TEST_EXPORT(atomic, load_store, test_atomic_load_store);
/* -------------------------------------------------------------------------- */
/* Test: exchange */
static void test_atomic_exchange(void) {
mr_atomic_t v, old;
mr_atomic_init(&v, 5);
old = mr_atomic_exchange(&v, 7);
MR_TEST_ASSERT_EQ_INT(old, 5);
MR_TEST_ASSERT_EQ_INT(mr_atomic_load(&v), 7);
}
MR_TEST_EXPORT(atomic, exchange, test_atomic_exchange);
/* -------------------------------------------------------------------------- */
/* Test: compare-exchange success/fail */
static void test_atomic_compare_exchange(void) {
mr_atomic_t v, expect;
mr_atomic_init(&v, 3);
mr_atomic_store(&expect, 3);
MR_TEST_ASSERT_EQ_INT(mr_atomic_compare_exchange(&v, &expect, 9), MR_TRUE);
MR_TEST_ASSERT_EQ_INT(v, 9);
expect = 3;
MR_TEST_ASSERT_EQ_INT(mr_atomic_compare_exchange(&v, &expect, 1), MR_FALSE);
MR_TEST_ASSERT_EQ_INT(expect, 9);
}
MR_TEST_EXPORT(atomic, compare_exchange, test_atomic_compare_exchange);
/* -------------------------------------------------------------------------- */
/* Test: fetch-add */
static void test_atomic_fetch_add(void) {
mr_atomic_t v;
mr_atomic_init(&v, 10);
MR_TEST_ASSERT_EQ_INT(mr_atomic_fetch_add(&v, 5), 10);
MR_TEST_ASSERT_EQ_INT(v, 15);
}
MR_TEST_EXPORT(atomic, fetch_add, test_atomic_fetch_add);
/* -------------------------------------------------------------------------- */
/* Test: fetch-sub */
static void test_atomic_fetch_sub(void) {
mr_atomic_t v;
mr_atomic_init(&v, 20);
MR_TEST_ASSERT_EQ_INT(mr_atomic_fetch_sub(&v, 8), 20);
MR_TEST_ASSERT_EQ_INT(v, 12);
}
MR_TEST_EXPORT(atomic, fetch_sub, test_atomic_fetch_sub);
/* -------------------------------------------------------------------------- */
/* Test: bitwise fetch-and/or/xor */
static void test_atomic_bitwise(void) {
mr_atomic_t v;
mr_atomic_init(&v, 0x0F);
MR_TEST_ASSERT_EQ_INT(mr_atomic_fetch_and(&v, 0x07), 0x0F);
MR_TEST_ASSERT_EQ_INT(v, 0x07);
MR_TEST_ASSERT_EQ_INT(mr_atomic_fetch_or(&v, 0x08), 0x07);
MR_TEST_ASSERT_EQ_INT(v, 0x0F);
MR_TEST_ASSERT_EQ_INT(mr_atomic_fetch_xor(&v, 0x0F), 0x0F);
MR_TEST_ASSERT_EQ_INT(v, 0x00);
}
MR_TEST_EXPORT(atomic, bitwise, test_atomic_bitwise);
#endif /* defined(MR_USE_TEST) */

View File

@@ -39,12 +39,22 @@ static void test_malloc_free_basic(void) {
mr_size_t usable;
void *p;
p = mr_malloc(0);
MR_TEST_ASSERT_EQ_PTR(p, MR_NULL);
mr_free(MR_NULL);
p = mr_malloc(128);
MR_TEST_ASSERT_NE_PTR(p, MR_NULL);
usable = mr_malloc_usable_size(p);
MR_TEST_ASSERT_GE_UINT(usable, 128);
usable = mr_malloc_usable_size(MR_NULL);
MR_TEST_ASSERT_EQ_UINT(usable, 0);
usable = mr_malloc_usable_size(p + 32);
MR_TEST_ASSERT_EQ_UINT(usable, 0);
canary_fill(p, usable);
MR_TEST_ASSERT_EQ_INT(canary_verify(p, usable), 1);
@@ -56,9 +66,15 @@ MR_TEST_EXPORT(malloc, free_basic, test_malloc_free_basic);
/* calloc test: memory must be zero-filled */
static void test_calloc_zero(void) {
const mr_size_t n = 16, sz = 32;
mr_size_t usable;
mr_size_t usable, i;
void *p;
p = mr_calloc(0, 0);
MR_TEST_ASSERT_EQ_PTR(p, MR_NULL);
p = mr_calloc(MR_SIZE_MAX / 2, 1);
MR_TEST_ASSERT_EQ_PTR(p, MR_NULL);
p = mr_calloc(n, sz);
MR_TEST_ASSERT_NE_PTR(p, MR_NULL);
@@ -66,7 +82,7 @@ static void test_calloc_zero(void) {
MR_TEST_ASSERT_GE_UINT(usable, n * sz);
/* Verify all bytes are zero */
for (mr_size_t i = 0; i < usable; ++i) {
for (i = 0; i < usable; ++i) {
MR_TEST_ASSERT_EQ_INT(((mr_uint8_t *)p)[i], 0);
}
@@ -83,12 +99,13 @@ static void test_realloc_resize(void) {
MR_TEST_ASSERT_NE_PTR(p1, MR_NULL);
canary_fill(p1, 64);
/* Expand */
p2 = mr_realloc(p1, MR_SIZE_MAX);
MR_TEST_ASSERT_EQ_PTR(p2, MR_NULL);
p2 = mr_realloc(p1, 256);
MR_TEST_ASSERT_NE_PTR(p2, MR_NULL);
MR_TEST_ASSERT_EQ_INT(canary_verify(p2, 64), 1);
/* Shrink */
p3 = mr_realloc(p2, 32);
MR_TEST_ASSERT_NE_PTR(p3, MR_NULL);
MR_TEST_ASSERT_EQ_INT(canary_verify(p3, 32), 1);
@@ -146,7 +163,10 @@ MR_TEST_EXPORT(malloc, frag_merge, test_frag_merge);
static void test_malloc_max(void) {
const mr_size_t huge = 3 * 1024;
mr_size_t usable;
void *p;
void *p, *n;
p = mr_malloc(MR_SIZE_MAX - 32);
MR_TEST_ASSERT_EQ_PTR(p, MR_NULL);
p = mr_malloc(huge);
if (p) {

106
test/libc/sprintf.c Normal file
View File

@@ -0,0 +1,106 @@
/**
* @copyright (c) 2024-2025, MacRsh
*
* @license SPDX-License-Identifier: Apache-2.0
*
* @date 2024-09-06 MacRsh First version
*/
#include <test/mr_test.h>
#if defined(MR_USE_TEST)
#include <libc/mr_sprintf.h>
#include <libc/mr_string.h>
/* -------------------------------------------------------------------------- */
/* Test: sprintf basic integer formatting */
static void test_sprintf_basic_int(void) {
char buf[64];
int ret;
ret = mr_sprintf(buf, "%d", 123);
MR_TEST_ASSERT_EQ_INT(ret, 3);
MR_TEST_ASSERT_EQ_INT(mr_strcmp(buf, "123"), 0);
ret = mr_sprintf(buf, "%04d", 42);
MR_TEST_ASSERT_EQ_INT(ret, 4);
MR_TEST_ASSERT_EQ_INT(mr_strcmp(buf, "0042"), 0);
ret = mr_sprintf(buf, "%x", 0xAB);
MR_TEST_ASSERT_EQ_INT(ret, 2);
MR_TEST_ASSERT_EQ_INT(mr_strcmp(buf, "ab"), 0);
}
MR_TEST_EXPORT(sprintf, basic_int, test_sprintf_basic_int);
/* -------------------------------------------------------------------------- */
/* Test: sprintf string formatting */
static void test_sprintf_string(void) {
char buf[64];
int ret;
ret = mr_sprintf(buf, "%s", "hello");
MR_TEST_ASSERT_EQ_INT(ret, 5);
MR_TEST_ASSERT_EQ_INT(mr_strcmp(buf, "hello"), 0);
ret = mr_sprintf(buf, "%10s", "test");
MR_TEST_ASSERT_EQ_INT(ret, 10);
MR_TEST_ASSERT_EQ_INT(mr_strcmp(buf, " test"), 0);
}
MR_TEST_EXPORT(sprintf, string, test_sprintf_string);
/* -------------------------------------------------------------------------- */
/* Test: sprintf mixed formatting */
static void test_sprintf_mixed(void) {
char buf[128];
int ret;
ret = mr_sprintf(buf, "Val: %d, Str: %s, Hex: %x", 42, "world", 255);
MR_TEST_ASSERT_EQ_INT(ret, 28);
MR_TEST_ASSERT_EQ_INT(mr_strcmp(buf, "Val: 42, Str: world, Hex: ff"), 0);
}
MR_TEST_EXPORT(sprintf, mixed, test_sprintf_mixed);
/* -------------------------------------------------------------------------- */
/* Test: snprintf with buffer size limit */
static void test_snprintf_limit(void) {
char buf[10];
int ret;
ret = mr_snprintf(buf, sizeof(buf), "%s", "1234567890");
MR_TEST_ASSERT_EQ_INT(ret, 10);
MR_TEST_ASSERT_EQ_INT(mr_strcmp(buf, "123456789"), 0);
}
MR_TEST_EXPORT(sprintf, snprintf_limit, test_snprintf_limit);
/* -------------------------------------------------------------------------- */
/* Test: sprintf pointer formatting */
static void test_sprintf_pointer(void) {
const void *ptr = (void *)0x12345678;
char buf[32];
int ret;
ret = mr_sprintf(buf, "%p", ptr);
MR_TEST_ASSERT_GT_INT(ret, 0);
MR_TEST_ASSERT_NE_PTR(mr_memchr(buf, '1', (mr_size_t)ret), MR_NULL);
}
MR_TEST_EXPORT(sprintf, pointer, test_sprintf_pointer);
/* -------------------------------------------------------------------------- */
/* Test: sprintf edge cases */
static void test_sprintf_edge_cases(void) {
char buf[64];
int ret;
ret = mr_sprintf(buf, "");
MR_TEST_ASSERT_EQ_INT(ret, 0);
MR_TEST_ASSERT_EQ_INT(buf[0], '\0');
ret = mr_sprintf(buf, "%05d", 7);
MR_TEST_ASSERT_EQ_INT(ret, 5);
MR_TEST_ASSERT_EQ_INT(mr_strcmp(buf, "00007"), 0);
ret = mr_sprintf(buf, "%-5d", 42);
MR_TEST_ASSERT_EQ_INT(ret, 5);
MR_TEST_ASSERT_EQ_INT(mr_strcmp(buf, "42 "), 0);
}
MR_TEST_EXPORT(sprintf, edge_cases, test_sprintf_edge_cases);
#endif /* defined(MR_USE_TEST) */

46
test/libc/sscanf.c Normal file
View File

@@ -0,0 +1,46 @@
/**
* @copyright (c) 2024-2025, MacRsh
*
* @license SPDX-License-Identifier: Apache-2.0
*
* @date 2024-09-06 MacRsh First version
*/
#include <test/mr_test.h>
#if defined(MR_USE_TEST)
#include <libc/mr_sscanf.h>
#include <libc/mr_string.h>
/* -------------------------------------------------------------------------- */
/* Test: basic integer and string extraction */
static void test_sscanf_basic(void) {
int val, ret;
char buf[8];
ret = mr_sscanf("42 hello", "%d %7s", &val, buf);
MR_TEST_ASSERT_EQ_INT(ret, 2);
MR_TEST_ASSERT_EQ_INT(val, 42);
MR_TEST_ASSERT_EQ_INT(mr_strcmp(buf, "hello"), 0);
}
MR_TEST_EXPORT(sscanf, basic, test_sscanf_basic);
/* -------------------------------------------------------------------------- */
/* Test: format mismatch */
static void test_sscanf_mismatch(void) {
int val, ret;
ret = mr_sscanf("abc", "%d", &val);
MR_TEST_ASSERT_EQ_INT(ret, 0);
}
MR_TEST_EXPORT(sscanf, mismatch, test_sscanf_mismatch);
/* -------------------------------------------------------------------------- */
/* Test: null / empty input */
static void test_sscanf_null_empty(void) {
int val;
MR_TEST_ASSERT_EQ_INT(mr_sscanf("", "%d", &val), -1);
MR_TEST_ASSERT_EQ_INT(mr_sscanf("123", "", &val), 0);
}
MR_TEST_EXPORT(sscanf, null_empty, test_sscanf_null_empty);
#endif /* defined(MR_USE_TEST) */

View File

@@ -51,6 +51,18 @@ static void test_memcpy_basic(void) {
mr_memcpy(dst, src, SZ);
MR_TEST_ASSERT_EQ_INT(canary_verify(dst, SZ), 1);
canary_fill(src, SZ / 3);
mr_memcpy(dst, src, SZ / 3);
MR_TEST_ASSERT_EQ_INT(canary_verify(dst, SZ / 3), 1);
canary_fill(src + 1, SZ - 1);
mr_memcpy(dst + 1, src + 1, SZ - 1);
MR_TEST_ASSERT_EQ_INT(canary_verify(dst + 1, SZ - 1), 1);
canary_fill(src + 1, SZ - 1);
mr_memcpy(dst, src + 1, SZ - 1);
MR_TEST_ASSERT_EQ_INT(canary_verify(dst, SZ - 1), 1);
mr_free(src);
mr_free(dst);
}
@@ -73,6 +85,11 @@ static void test_memset_basic(void) {
MR_TEST_ASSERT_EQ_INT(buf[i], 0x5A);
}
mr_memset(buf + 1, 0x5A, SZ - 1);
for (i = 1; i < SZ - 1; ++i) {
MR_TEST_ASSERT_EQ_INT(buf[i], 0x5A);
}
mr_free(buf);
}
MR_TEST_EXPORT(string, memset_basic, test_memset_basic);
@@ -103,9 +120,10 @@ MR_TEST_EXPORT(string, memchr_find, test_memchr_find);
static void test_memccpy_stop(void) {
const char src[16] = "Hello\0World";
char dst[16];
void *e;
mr_memset(dst, '\0', sizeof(dst));
void *e = mr_memccpy(dst, src, 'o', sizeof(dst));
e = mr_memccpy(dst, src, 'o', sizeof(dst));
MR_TEST_ASSERT_NE_PTR(e, MR_NULL);
MR_TEST_ASSERT_EQ_INT(dst[4], 'o');
MR_TEST_ASSERT_EQ_INT(dst[5], '\0');
@@ -129,15 +147,38 @@ static void test_strcpy_basic(void) {
}
MR_TEST_EXPORT(string, strcpy_basic, test_strcpy_basic);
/* -------------------------------------------------------------------------- */
/* Test: strerror copies C-string including terminator */
static void test_strerror_basic(void) {
mr_strerror(0);
mr_strerror(MR_EPERM);
mr_strerror(MR_ENOENT);
mr_strerror(MR_EIO);
mr_strerror(MR_EAGAIN);
mr_strerror(MR_ENOMEM);
mr_strerror(MR_EBUSY);
mr_strerror(MR_EEXIST);
mr_strerror(MR_EINVAL);
mr_strerror(MR_ENOSYS);
mr_strerror(MR_ETIMEDOUT);
mr_strerror(-99999);
}
MR_TEST_EXPORT(string, strerror_basic, test_strerror_basic);
/* -------------------------------------------------------------------------- */
/* Test: strncpy copies at most n bytes */
static void test_strncpy_trunc(void) {
const char *src = "long_string";
const char *long_src = "long_string";
const char *short_src = "str";
char buf[8];
mr_strncpy(buf, src, sizeof(buf));
mr_strncpy(buf, long_src, sizeof(buf));
buf[sizeof(buf) - 1] = '\0';
MR_TEST_ASSERT_EQ_INT(mr_memcmp(buf, "long_st", sizeof(buf)), 0);
mr_strncpy(buf, short_src, sizeof(buf));
buf[sizeof(buf) - 1] = '\0';
MR_TEST_ASSERT_EQ_INT(mr_memcmp(buf, "str", 4), 0);
}
MR_TEST_EXPORT(string, strncpy_trunc, test_strncpy_trunc);
@@ -174,4 +215,48 @@ static void test_strchr_find(void) {
MR_TEST_ASSERT_EQ_PTR(mr_strchr(s, 'X'), MR_NULL);
}
MR_TEST_EXPORT(string, strchr_find, test_strchr_find);
/* -------------------------------------------------------------------------- */
/* Test: ffs32 basic cases */
static void test_ffs32_basic(void) {
MR_TEST_ASSERT_EQ_INT(mr_ffs32(0), 0);
MR_TEST_ASSERT_EQ_INT(mr_ffs32(1), 1);
MR_TEST_ASSERT_EQ_INT(mr_ffs32(0x80000000U), 32);
MR_TEST_ASSERT_EQ_INT(mr_ffs32(0x00010000U), 17);
MR_TEST_ASSERT_EQ_INT(mr_ffs32(0x000000FFU), 1);
}
MR_TEST_EXPORT(string, ffs32_basic, test_ffs32_basic);
/* -------------------------------------------------------------------------- */
/* Test: ffs64 basic cases */
static void test_ffs64_basic(void) {
MR_TEST_ASSERT_EQ_INT(mr_ffs64(0), 0);
MR_TEST_ASSERT_EQ_INT(mr_ffs64(1ULL), 1);
MR_TEST_ASSERT_EQ_INT(mr_ffs64(0x8000000000000000ULL), 64);
MR_TEST_ASSERT_EQ_INT(mr_ffs64(0x0000000100000000ULL), 33);
MR_TEST_ASSERT_EQ_INT(mr_ffs64(0x00000000000000FFULL), 1);
}
MR_TEST_EXPORT(string, ffs64_basic, test_ffs64_basic);
/* -------------------------------------------------------------------------- */
/* Test: fls32 basic cases */
static void test_fls32_basic(void) {
MR_TEST_ASSERT_EQ_INT(mr_fls32(0), 0);
MR_TEST_ASSERT_EQ_INT(mr_fls32(1), 1);
MR_TEST_ASSERT_EQ_INT(mr_fls32(0x80000000U), 32);
MR_TEST_ASSERT_EQ_INT(mr_fls32(0x00010000U), 17);
MR_TEST_ASSERT_EQ_INT(mr_fls32(0x000000FFU), 8);
}
MR_TEST_EXPORT(string, fls32_basic, test_fls32_basic);
/* -------------------------------------------------------------------------- */
/* Test: fls64 basic cases */
static void test_fls64_basic(void) {
MR_TEST_ASSERT_EQ_INT(mr_fls64(0), 0);
MR_TEST_ASSERT_EQ_INT(mr_fls64(1ULL), 1);
MR_TEST_ASSERT_EQ_INT(mr_fls64(0x8000000000000000ULL), 64);
MR_TEST_ASSERT_EQ_INT(mr_fls64(0x0000000100000000ULL), 33);
MR_TEST_ASSERT_EQ_INT(mr_fls64(0x00000000000000FFULL), 8);
}
MR_TEST_EXPORT(string, fls64_basic, test_fls64_basic);
#endif /* defined(MR_USE_TEST) */

View File

@@ -10,6 +10,7 @@
#if defined(MR_USE_TEST)
#include <mr-X/mr_clock.h>
#include <libc/mr_assert.h>
#include <libc/mr_string.h>
/* Test status */
mr_uint32_t __mr_test_status = __MR_TEST_MAGIC_PASS;
@@ -24,45 +25,107 @@ static void end(void) {
}
__MR_TEST_EXPORT(sys, end, end, "1.end");
int mr_test_all_run(void) {
static mr_bool_t testcase_run(const mr_testcase_t *cs) {
mr_tick_t tick;
/* Check parameter */
MR_ASSERT(cs->entry != MR_NULL);
/* Test case begin */
mr_printf("[ RUN ] %s.%s\n", cs->suite, cs->name);
/* Reset test status */
__mr_test_status = __MR_TEST_MAGIC_PASS;
/* Get begin tick */
tick = mr_clock_tick();
/* Call test entry */
cs->entry();
/* Get difference tick */
tick = mr_clock_tick() - tick;
/* Test case end */
if (__mr_test_status == __MR_TEST_MAGIC_PASS) {
mr_printf(
"[ " MR_COLOR(MR_COLOR_GREEN, "OK") " ] %s.%s (%d tick)\n",
cs->suite, cs->name, tick);
return MR_TRUE;
} else {
mr_printf(
"[ " MR_COLOR(MR_COLOR_RED, "FAILED") " ] %s.%s (%d tick)\n",
cs->suite, cs->name, tick);
return MR_FALSE;
}
}
void mr_testcase_run(const char *suite, const char *name) {
const mr_testcase_t *start = &__mr_testcase_sys_start;
const mr_testcase_t *end = &__mr_testcase_sys_end;
const mr_testcase_t *cs;
/* Each test cases */
for (cs = start + 1; cs < end; cs++) {
/* Match testcase */
if ((!mr_strcmp(cs->suite, suite)) || (!mr_strcmp(cs->name, name))) {
continue;
}
/* Run testcase */
testcase_run(cs);
}
}
void mr_testsuite_run(const char *suite) {
const mr_testcase_t *start = &__mr_testcase_sys_start;
const mr_testcase_t *end = &__mr_testcase_sys_end;
const mr_testcase_t *cs;
int pass, fail;
mr_tick_t tick;
mr_bool_t ret;
/* Test begin */
mr_printf("[==========] Running tests\n");
mr_printf("[==========] Running '%s' suite\n", suite);
/* Each test cases */
for (pass = fail = 0, cs = start + 1; cs < end; cs++) {
MR_ASSERT(cs->entry != MR_NULL);
/* Match testcase */
if (mr_strcmp(cs->suite, suite) != 0) {
continue;
}
/* Test case begin */
mr_printf("[ RUN ] %s.%s\n", cs->suite, cs->name);
/* Reset test status */
__mr_test_status = __MR_TEST_MAGIC_PASS;
/* Get begin tick */
tick = mr_clock_tick();
/* Call test entry */
cs->entry();
/* Get difference tick */
tick = mr_clock_tick() - tick;
/* Test case end */
if (__mr_test_status == __MR_TEST_MAGIC_PASS) {
mr_printf("[ " MR_COLOR(MR_COLOR_GREEN,
"OK") " ] %s.%s (%d tick)\n",
cs->suite, cs->name, tick);
/* Run testcase */
ret = testcase_run(cs);
if (ret) {
pass++;
} else {
fail++;
}
}
/* Test summary */
mr_printf("[==========]\n");
mr_printf("[ PASSED ] %d tests\n", pass);
mr_printf("[ FAILED ] %d tests\n", fail);
}
mr_bool_t mr_test_run(void) {
const mr_testcase_t *start = &__mr_testcase_sys_start;
const mr_testcase_t *end = &__mr_testcase_sys_end;
const mr_testcase_t *cs;
int pass, fail;
mr_bool_t ret;
/* Test begin */
mr_printf("[==========] Running 'all' tests\n");
/* Each test cases */
for (pass = fail = 0, cs = start + 1; cs < end; cs++) {
/* Run testcase */
ret = testcase_run(cs);
if (ret) {
pass++;
} else {
mr_printf(
"[ " MR_COLOR(MR_COLOR_RED, "FAILED") " ] %s.%s (%d tick)\n",
cs->suite, cs->name, tick);
fail++;
}
}
@@ -72,7 +135,7 @@ int mr_test_all_run(void) {
mr_printf("[ PASSED ] %d tests\n", pass);
mr_printf("[ FAILED ] %d tests\n", fail);
/* Test end */
return 0;
/* Return result */
return (fail == 0) ? MR_TRUE : MR_FALSE;
}
#endif /* defined(MR_USE_TEST) */