- /**
- * @file kc_assert.c
- * @brief アサーションモジュール
- * @copyright 2003 - 2023 Nomura Kei
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <math.h>
- #include <kc_assert.h>
- #include <kc_threads.h>
-
- // プロトタイプ宣言
- static void assert_default_handler(const char *msg);
- static const char *assert_hexdump(char *buf, const void *data, size_t size);
-
- // ハンドラ
- /**
- * Assertion 発生時に実行されるハンドラ。
- *
- * @param msg エラーメッセージ
- */
- void (*assert_handler)(const char *msg) = assert_default_handler;
-
- /** Assertion で利用するメッセージバッファ。 */
- static thread_local char assert_message[1024];
-
- /**
- * 指定された値が一致するか否か検査します。
- *
- * @param expected 期待する値
- * @param actual 実際の値
- * @param file ファイル
- * @param func 関数
- * @param line 行番号
- */
- void assert_equals_long_(
- long expected, long actual, const char *file, const char *func, int line)
- {
- bool is_success = (expected == actual);
- if (!is_success)
- {
- snprintf(assert_message, sizeof(assert_message),
- "%s:%d: %s: Assertion expected <%ld> but was <%ld>",
- file, line, func, expected, actual);
- assert_handler(assert_message);
- }
- }
-
- /**
- * 指定された値が一致するか否か検査します。
- *
- * @param expected 期待する値
- * @param actual 実際の値
- * @param file ファイル
- * @param func 関数
- * @param line 行番号
- */
- void assert_equals_double_(
- double expected, double actual, double delta, const char *file, const char *func, int line)
- {
- bool is_success = (fabs((double)expected - actual) < delta);
- if (!is_success)
- {
- snprintf(assert_message, sizeof(assert_message),
- "%s:%d: %s: Assertion expected <%f> but was <%f>",
- file, line, func, expected, actual);
- assert_handler(assert_message);
- }
- }
-
- /**
- * 指定された文字列が一致するか否か検査します。
- *
- * @param expected 期待する値
- * @param actual 実際の値
- * @param file ファイル
- * @param func 関数
- * @param line 行番号
- */
- void assert_equals_string_(
- const char *expected, const char *actual, const char *file, const char *func, int line)
- {
- bool is_success = (strcmp(expected, actual) == 0);
- if (!is_success)
- {
- snprintf(assert_message, sizeof(assert_message),
- "%s:%d: %s: Assertion expected <%s> but was <%s>",
- file, line, func, expected, actual);
- if (strlen(actual) == 6)
- {
- printf("[%s]\n", actual);
- printf("[%c][%02x]\n", actual[5], actual[5]);
- }
-
- assert_handler(assert_message);
- }
- }
-
- /**
- * 指定されたバイナリが一致するか否か検査します。
- *
- * @param expected 期待する値
- * @param actual 実際の値
- * @param file ファイル
- * @param func 関数
- * @param line 行番号
- */
- void assert_equals_binary_(
- const void *expected, const void *actual, size_t size, const char *file, const char *func, int line)
- {
- bool is_success = (memcmp(expected, actual, size) == 0);
- if (!is_success)
- {
- char expected_buf[64];
- char actual_buf[64];
- const char *expected_dump = assert_hexdump(expected_buf, expected, size);
- const char *actual_dump = assert_hexdump(actual_buf, actual, size);
- snprintf(assert_message, sizeof(assert_message),
- "%s:%d: %s: Assertion expected <%s> but was <%s>",
- file, line, func, expected_dump, actual_dump);
- assert_handler(assert_message);
- }
- }
-
- /**
- * 指定された値がNULLであることを検査します。
- *
- * @param condition 検査する値
- * @param file ファイル
- * @param func 関数
- * @param line 行番号
- */
- void assert_null_(const void *condition, const char *file, const char *func, int line)
- {
- bool is_success = (condition == NULL);
- if (!is_success)
- {
- snprintf(assert_message, sizeof(assert_message),
- "%s:%d: %s: Assertion condition is not null", file, line, func);
- assert_handler(assert_message);
- }
- }
-
- /**
- * 指定された値がNULLでないことを検査します。
- *
- * @param condition 検査する値
- * @param file ファイル
- * @param func 関数
- * @param line 行番号
- */
- void assert_not_null_(const void *condition, const char *file, const char *func, int line)
- {
- bool is_success = (condition != NULL);
- if (!is_success)
- {
- snprintf(assert_message, sizeof(assert_message),
- "%s:%d: %s: Assertion condition is null", file, line, func);
- assert_handler(assert_message);
- }
- }
-
- /**
- * 指定された値が false であることを検査します。
- *
- * @param condition 検査する値
- * @param file ファイル
- * @param func 関数
- * @param line 行番号
- */
- void assert_false_(bool condition, const char *file, const char *func, int line)
- {
- bool is_success = (!condition);
- if (!is_success)
- {
- snprintf(assert_message, sizeof(assert_message),
- "%s:%d: %s: Assertion condition is not false", file, line, func);
- assert_handler(assert_message);
- }
- }
-
- /**
- * 指定された値が true であることを検査します。
- *
- * @param condition 検査する値
- * @param file ファイル
- * @param func 関数
- * @param line 行番号
- */
- void assert_true_(bool condition, const char *file, const char *func, int line)
- {
- bool is_success = (condition);
- if (!is_success)
- {
- snprintf(assert_message, sizeof(assert_message),
- "%s:%d: %s: Assertion condition is not true", file, line, func);
- assert_handler(assert_message);
- }
- }
-
- /**
- * 常に失敗であることを示します。
- *
- * @param file ファイル
- * @param func 関数
- * @param line 行番号
- */
- void assert_fail_(const char *file, const char *func, int line)
- {
- snprintf(assert_message, sizeof(assert_message),
- "%s:%d: %s: Assertion fail()", file, line, func);
- assert_handler(assert_message);
- }
-
- /**
- * デフォルトアサーションハンドラ。
- *
- * @param is_success 成功か否か
- * @param msg メッセージ
- */
- static void assert_default_handler(const char *msg)
- {
- fprintf(stderr, "%s\n", msg);
- abort();
- }
-
- /**
- * 最大 16 バイトの16進数ダンプ文字列をバッファに格納します。
- *
- * @param buff 結果を格納するためのバッファ [48 以上のこと]
- * @param data データ
- * @param size データのサイズ
- */
- static const char *assert_hexdump(char *buf, const void *data, size_t size)
- {
- int dump_size = (size < 16) ? size : 16;
- const char *ptr = (const char *)data;
- char *write_ptr = buf;
- int write_size = 0;
- for (int i = 0; i < dump_size; i++)
- {
- write_size += sprintf(write_ptr, "%02X ", *ptr);
- write_ptr += write_size;
- ptr++;
- }
- return buf;
- }