mocking
Mocking skill for the ikigai project
Installation
Follow the repository instructions for this skill and your agent. Review the files and dependencies before adding it to your workflow.
View source ↗GuidesSkill instructions
Mocking
Description
MOCKABLE wrapper patterns for testing external dependencies.
Philosophy
Mock external dependencies, never our own code. External means: libraries (talloc, yyjson, curl), system calls (open, read, write, stat), and vendor inline functions.
The MOCKABLE Pattern
wrapper.h provides zero-overhead mocking via weak symbols:
// wrapper.h
#ifdef NDEBUG
#define MOCKABLE static inline // Release: zero overhead
#else
#define MOCKABLE __attribute__((weak)) // Debug: overridable
#endif
MOCKABLE int posix_write_(int fd, const void *buf, size_t count);
Using Mocks in Tests
Override the weak symbol in your test file:
// test_file.c
#include "wrapper.h"
// Override - this replaces the weak symbol
int posix_write_(int fd, const void *buf, size_t count) {
return -1; // Simulate write failure
}
void test_write_error_handling(void) {
// Now any code calling posix_write_() gets our mock
res_t r = save_file("test.txt", "content");
assert(IS_ERR(r));
}
Available Wrappers
POSIX System Calls
| Wrapper | Wraps |
|---|---|
posix_open_() |
open() |
posix_close_() |
close() |
posix_read_() |
read() |
posix_write_() |
write() |
posix_stat_() |
stat() |
posix_mkdir_() |
mkdir() |
posix_access_() |
access() |
posix_rename_() |
rename() |
posix_getcwd_() |
getcwd() |
posix_pipe_() |
pipe() |
posix_fcntl_() |
fcntl() |
posix_select_() |
select() |
posix_sigaction_() |
sigaction() |
posix_ioctl_() |
ioctl() |
posix_tcgetattr_() |
tcgetattr() |
posix_tcsetattr_() |
tcsetattr() |
posix_tcflush_() |
tcflush() |
POSIX stdio
| Wrapper | Wraps |
|---|---|
fopen_() |
fopen() |
fclose_() |
fclose() |
fread_() |
fread() |
fwrite_() |
fwrite() |
fseek_() |
fseek() |
ftell_() |
ftell() |
posix_fdopen_() |
fdopen() |
popen_() |
popen() |
pclose_() |
pclose() |
opendir_() |
opendir() |
C Standard Library
| Wrapper | Wraps |
|---|---|
snprintf_() |
snprintf() |
vsnprintf_() |
vsnprintf() |
gmtime_() |
gmtime() |
strftime_() |
strftime() |
talloc
| Wrapper | Wraps |
|---|---|
talloc_zero_() |
talloc_zero_size() |
talloc_strdup_() |
talloc_strdup() |
talloc_array_() |
talloc_zero_size() |
talloc_realloc_() |
talloc_realloc_size() |
talloc_asprintf_() |
talloc_vasprintf() |
yyjson
| Wrapper | Wraps |
|---|---|
yyjson_read_file_() |
yyjson_read_file() |
yyjson_mut_write_file_() |
yyjson_mut_write_file() |
yyjson_read_() |
yyjson_read() |
yyjson_doc_get_root_() |
yyjson_doc_get_root() |
yyjson_obj_get_() |
yyjson_obj_get() |
yyjson_get_sint_() |
yyjson_get_sint() |
yyjson_get_str_() |
yyjson_get_str() |
yyjson_mut_obj_add_str_() |
yyjson_mut_obj_add_str() |
yyjson_mut_obj_add_int_() |
yyjson_mut_obj_add_int() |
yyjson_mut_obj_add_uint_() |
yyjson_mut_obj_add_uint() |
yyjson_mut_obj_() |
yyjson_mut_obj() |
yyjson_mut_arr_() |
yyjson_mut_arr() |
yyjson_mut_obj_add_val_() |
yyjson_mut_obj_add_val() |
yyjson_mut_arr_add_val_() |
yyjson_mut_arr_add_val() |
yyjson_mut_obj_add_bool_() |
yyjson_mut_obj_add_bool() |
yyjson_val_mut_copy_() |
yyjson_val_mut_copy() |
libcurl (Easy API)
| Wrapper | Wraps |
|---|---|
curl_easy_init_() |
curl_easy_init() |
curl_easy_cleanup_() |
curl_easy_cleanup() |
curl_easy_perform_() |
curl_easy_perform() |
curl_easy_setopt_() |
curl_easy_setopt() |
curl_easy_getinfo_() |
curl_easy_getinfo() |
curl_easy_strerror_() |
curl_easy_strerror() |
curl_slist_append_() |
curl_slist_append() |
curl_slist_free_all_() |
curl_slist_free_all() |
libcurl (Multi API)
| Wrapper | Wraps |
|---|---|
curl_multi_init_() |
curl_multi_init() |
curl_multi_cleanup_() |
curl_multi_cleanup() |
curl_multi_add_handle_() |
curl_multi_add_handle() |
curl_multi_remove_handle_() |
curl_multi_remove_handle() |
curl_multi_perform_() |
curl_multi_perform() |
curl_multi_fdset_() |
curl_multi_fdset() |
curl_multi_timeout_() |
curl_multi_timeout() |
curl_multi_info_read_() |
curl_multi_info_read() |
curl_multi_strerror_() |
curl_multi_strerror() |
libpq (PostgreSQL)
| Wrapper | Wraps |
|---|---|
PQgetvalue_() |
PQgetvalue() |
pq_exec_() |
PQexec() |
pq_exec_params_() |
PQexecParams() |
PQresultStatus_() |
PQresultStatus() |
pthread
| Wrapper | Wraps |
|---|---|
pthread_mutex_init_() |
pthread_mutex_init() |
pthread_mutex_destroy_() |
pthread_mutex_destroy() |
pthread_mutex_lock_() |
pthread_mutex_lock() |
pthread_mutex_unlock_() |
pthread_mutex_unlock() |
pthread_create_() |
pthread_create() |
pthread_join_() |
pthread_join() |
Internal ikigai Functions
| Wrapper | Wraps |
|---|---|
ik_db_init_() |
ik_db_init() |
ik_db_message_insert_() |
ik_db_message_insert() |
ik_scrollback_append_line_() |
ik_scrollback_append_line() |
ik_repl_render_frame_() |
ik_repl_render_frame() |
ik_agent_get_provider_() |
ik_agent_get_provider() |
ik_request_build_from_conversation_() |
ik_request_build_from_conversation() |
ik_http_multi_create_() |
ik_http_multi_create() |
ik_http_multi_info_read_() |
ik_http_multi_info_read() |
ik_agent_start_tool_execution_() |
ik_agent_start_tool_execution() |
ik_agent_should_continue_tool_loop_() |
ik_agent_should_continue_tool_loop() |
ik_repl_submit_tool_loop_continuation_() |
ik_repl_submit_tool_loop_continuation() |
ik_agent_add_message_() |
ik_agent_add_message() |
ik_agent_transition_to_idle_() |
ik_agent_transition_to_idle() |
Adding New Wrappers
When you need to mock a new external dependency:
- Add declaration to
wrapper.h:
MOCKABLE return_type function_name_(args);
- Add implementation to
wrapper.c:
return_type function_name_(args) {
return original_function(args);
}
-
Replace direct calls in production code with the wrapper
-
Override in tests to inject failures
Wrapping Vendor Inline Functions
Problem: Inline functions like yyjson_doc_get_root() expand at every call site, creating untestable branches.
Solution: Wrap once, use wrapper everywhere:
// sse_parser.h
yyjson_val *yyjson_doc_get_root_wrapper(yyjson_doc *doc);
// sse_parser.c
yyjson_val *yyjson_doc_get_root_wrapper(yyjson_doc *doc) {
return yyjson_doc_get_root(doc); // Inline expands here only
}
// Test both branches once
void test_wrapper_null(void) {
assert(yyjson_doc_get_root_wrapper(NULL) == NULL);
}
void test_wrapper_valid(void) {
yyjson_doc *doc = create_test_doc();
assert(yyjson_doc_get_root_wrapper(doc) != NULL);
}
What NOT to Mock
- Our own code (refactor instead)
- Pure functions (test directly)
- Simple data structures
References
-
src/wrapper.h- MOCKABLE declarations -
src/wrapper.c- Wrapper implementations -
src/openai/sse_parser.h- Inline wrapper example
Examples
Read the usage examples in the source repository.
View source ↗Source history
- Indexed on
- 2026-01-20
- Index updated
- 2026-01-26
- Branch
- main
Index and sync dates describe this directory. View the source repository for code history.
GitHub ↗chat Comments (0)
Sign in to join the discussion and leave a comment.
No comments yet. Be the first to share your thoughts!