@@ -59,6 +59,7 @@ include_directories( | |||||
"${PROJECT_SOURCE_DIR}/dependencies/SDL2_ttf/include" | "${PROJECT_SOURCE_DIR}/dependencies/SDL2_ttf/include" | ||||
"${PROJECT_SOURCE_DIR}/dependencies/minIni/dev" | "${PROJECT_SOURCE_DIR}/dependencies/minIni/dev" | ||||
"${PROJECT_SOURCE_DIR}/dependencies/bdd-for-c" | "${PROJECT_SOURCE_DIR}/dependencies/bdd-for-c" | ||||
"${PROJECT_SOURCE_DIR}/dependencies/bdd-for-c-mocks" | |||||
"${PROJECT_SOURCE_DIR}/dependencies/portmidi/pm_common" | "${PROJECT_SOURCE_DIR}/dependencies/portmidi/pm_common" | ||||
"${PROJECT_SOURCE_DIR}/dependencies/spine-runtimes/spine-c/spine-c/include" | "${PROJECT_SOURCE_DIR}/dependencies/spine-runtimes/spine-c/spine-c/include" | ||||
"${PROJECT_SOURCE_DIR}/dependencies/getopt-for-windows" | "${PROJECT_SOURCE_DIR}/dependencies/getopt-for-windows" | ||||
@@ -191,8 +192,7 @@ endif() | |||||
add_executable( | add_executable( | ||||
game-test-geometry | game-test-geometry | ||||
dependencies/bdd-for-c/bdd-for-c.h | dependencies/bdd-for-c/bdd-for-c.h | ||||
src/packages/test/IZ_mock.h | |||||
src/packages/test/IZ_test.h | |||||
dependencies/bdd-for-c-mocks/bdd-for-c-mocks.h | |||||
src/packages/game/geometry/IZ_rect.h | src/packages/game/geometry/IZ_rect.h | ||||
src/packages/game/geometry/IZ_rect.c | src/packages/game/geometry/IZ_rect.c | ||||
@@ -204,8 +204,7 @@ add_executable( | |||||
add_executable( | add_executable( | ||||
game-test-input | game-test-input | ||||
dependencies/bdd-for-c/bdd-for-c.h | dependencies/bdd-for-c/bdd-for-c.h | ||||
src/packages/test/IZ_mock.h | |||||
src/packages/test/IZ_test.h | |||||
dependencies/bdd-for-c-mocks/bdd-for-c-mocks.h | |||||
__mocks__/dependencies/minIni/minIni.mock.h | __mocks__/dependencies/minIni/minIni.mock.h | ||||
__mocks__/dependencies/SDL2/SDL_keyboard.mock.h | __mocks__/dependencies/SDL2/SDL_keyboard.mock.h | ||||
@@ -234,11 +233,12 @@ add_executable( | |||||
add_executable( | add_executable( | ||||
game-test-output | game-test-output | ||||
dependencies/bdd-for-c/bdd-for-c.h | dependencies/bdd-for-c/bdd-for-c.h | ||||
src/packages/test/IZ_mock.h | |||||
src/packages/test/IZ_test.h | |||||
dependencies/bdd-for-c-mocks/bdd-for-c-mocks.h | |||||
__mocks__/dependencies/minIni/minIni.mock.h | __mocks__/dependencies/minIni/minIni.mock.h | ||||
__mocks__/dependencies/SDL2/SDL_stdinc.mock.h | __mocks__/dependencies/SDL2/SDL_stdinc.mock.h | ||||
__mocks__/dependencies/SDL2/SDL_render.mock.h | __mocks__/dependencies/SDL2/SDL_render.mock.h | ||||
src/packages/config/IZ_config.h | src/packages/config/IZ_config.h | ||||
src/packages/game/output/video/IZ_video.h | src/packages/game/output/video/IZ_video.h | ||||
src/packages/game/output/video/IZ_video.c | src/packages/game/output/video/IZ_video.c | ||||
@@ -248,21 +248,25 @@ add_executable( | |||||
add_executable( | add_executable( | ||||
game-test-memory | game-test-memory | ||||
dependencies/bdd-for-c/bdd-for-c.h | dependencies/bdd-for-c/bdd-for-c.h | ||||
src/packages/test/IZ_mock.h | |||||
src/packages/test/IZ_test.h | |||||
dependencies/bdd-for-c-mocks/bdd-for-c-mocks.h | |||||
src/packages/timer/IZ_timer.h | src/packages/timer/IZ_timer.h | ||||
src/packages/timer/IZ_timer.c | src/packages/timer/IZ_timer.c | ||||
src/packages/stdinc/IZ_stdlib.h | src/packages/stdinc/IZ_stdlib.h | ||||
__mocks__/src/packages/stdinc/IZ_stdlib.mock.h | __mocks__/src/packages/stdinc/IZ_stdlib.mock.h | ||||
src/packages/stdinc/IZ_string.h | src/packages/stdinc/IZ_string.h | ||||
__mocks__/src/packages/stdinc/IZ_string.mock.h | __mocks__/src/packages/stdinc/IZ_string.mock.h | ||||
src/packages/log/IZ_log.h | src/packages/log/IZ_log.h | ||||
__mocks__/src/packages/log/IZ_log.mock.h | __mocks__/src/packages/log/IZ_log.mock.h | ||||
src/packages/game/data/IZ_list.c | |||||
src/packages/game/data/IZ_list.h | |||||
src/packages/game/memory/IZ_pool.h | src/packages/game/memory/IZ_pool.h | ||||
src/packages/game/memory/IZ_pool.c | src/packages/game/memory/IZ_pool.c | ||||
src/packages/game/memory/memory.test.c | src/packages/game/memory/memory.test.c | ||||
src/packages/game/data/IZ_list.c | |||||
src/packages/game/data/IZ_list.h | |||||
) | ) | ||||
target_link_libraries( | target_link_libraries( | ||||
@@ -274,13 +278,22 @@ target_link_libraries( | |||||
add_executable( | add_executable( | ||||
game-test-data | game-test-data | ||||
dependencies/bdd-for-c/bdd-for-c.h | dependencies/bdd-for-c/bdd-for-c.h | ||||
src/packages/test/IZ_mock.h | |||||
src/packages/test/IZ_test.h | |||||
dependencies/bdd-for-c-mocks/bdd-for-c-mocks.h | |||||
src/packages/stdinc/IZ_stdlib.h | |||||
__mocks__/src/packages/stdinc/IZ_stdlib.mock.h | |||||
src/packages/game/data/IZ_list.h | src/packages/game/data/IZ_list.h | ||||
src/packages/game/data/IZ_list.c | src/packages/game/data/IZ_list.c | ||||
src/packages/game/data/data.test.c | src/packages/game/data/data.test.c | ||||
) | ) | ||||
target_link_libraries( | |||||
game-test-data | |||||
SDL2main | |||||
SDL2 | |||||
) | |||||
add_executable( | add_executable( | ||||
server | server | ||||
dependencies/sqlite/sqlite3.h | dependencies/sqlite/sqlite3.h | ||||
@@ -1,8 +1,8 @@ | |||||
#ifndef SDL_JOYSTICK_MOCK_H | #ifndef SDL_JOYSTICK_MOCK_H | ||||
#define SDL_JOYSTICK_MOCK_H | #define SDL_JOYSTICK_MOCK_H | ||||
#include <bdd-for-c-mocks.h> | |||||
#include "../../../src/packages/common/IZ_common.h" | #include "../../../src/packages/common/IZ_common.h" | ||||
#include "../../../src/packages/test/IZ_test.h" | |||||
typedef struct _SDL_Joystick {} SDL_Joystick; | typedef struct _SDL_Joystick {} SDL_Joystick; | ||||
@@ -1,8 +1,8 @@ | |||||
#ifndef SDL_KEYBOARD_MOCK_H | #ifndef SDL_KEYBOARD_MOCK_H | ||||
#define SDL_KEYBOARD_MOCK_H | #define SDL_KEYBOARD_MOCK_H | ||||
#include <bdd-for-c-mocks.h> | |||||
#include "../../../src/packages/common/IZ_common.h" | #include "../../../src/packages/common/IZ_common.h" | ||||
#include "../../../src/packages/test/IZ_test.h" | |||||
mock(SDL_GetKeyName) const char* SDL_GetKeyName(i32 key) { | mock(SDL_GetKeyName) const char* SDL_GetKeyName(i32 key) { | ||||
mock_return(SDL_GetKeyName) ""; | mock_return(SDL_GetKeyName) ""; | ||||
@@ -1,8 +1,8 @@ | |||||
#ifndef SDL_RENDER_MOCK_H | #ifndef SDL_RENDER_MOCK_H | ||||
#define SDL_RENDER_MOCK_H | #define SDL_RENDER_MOCK_H | ||||
#include <bdd-for-c-mocks.h> | |||||
#include "../../../src/packages/common/IZ_common.h" | #include "../../../src/packages/common/IZ_common.h" | ||||
#include "../../../src/packages/test/IZ_test.h" | |||||
typedef struct SDL_Renderer SDL_Renderer; | typedef struct SDL_Renderer SDL_Renderer; | ||||
@@ -2,8 +2,8 @@ | |||||
#define SDL_STDINC_MOCK_H | #define SDL_STDINC_MOCK_H | ||||
#include <string.h> | #include <string.h> | ||||
#include <bdd-for-c-mocks.h> | |||||
#include "../../../src/packages/common/IZ_common.h" | #include "../../../src/packages/common/IZ_common.h" | ||||
#include "../../../src/packages/test/IZ_test.h" | |||||
mock(SDL_memcpy) void* SDL_memcpy(void* dst, const void* src, size_t len) { | mock(SDL_memcpy) void* SDL_memcpy(void* dst, const void* src, size_t len) { | ||||
mock_return(SDL_memcpy) memcpy(dst, src, len); | mock_return(SDL_memcpy) memcpy(dst, src, len); | ||||
@@ -1,8 +1,8 @@ | |||||
#ifndef MININI_MOCK_H | #ifndef MININI_MOCK_H | ||||
#define MININI_MOCK_H | #define MININI_MOCK_H | ||||
#include <bdd-for-c-mocks.h> | |||||
#include "../../../src/packages/common/IZ_common.h" | #include "../../../src/packages/common/IZ_common.h" | ||||
#include "../../../src/packages/test/IZ_test.h" | |||||
mock(ini_getl) long ini_getl(const char *Section, const char *Key, long DefValue, const char *Filename) { | mock(ini_getl) long ini_getl(const char *Section, const char *Key, long DefValue, const char *Filename) { | ||||
mock_return(ini_getl) DefValue; | mock_return(ini_getl) DefValue; | ||||
@@ -1,7 +1,7 @@ | |||||
#ifndef IZ_LOG_MOCK_H | #ifndef IZ_LOG_MOCK_H | ||||
#define IZ_LOG_MOCK_H | #define IZ_LOG_MOCK_H | ||||
#include "../../../src/packages/test/IZ_mock.h" | |||||
#include <bdd-for-c-mocks.h> | |||||
#include "../../../src/packages/log/IZ_log.h" | #include "../../../src/packages/log/IZ_log.h" | ||||
mock_modes(IZ_LogInfo) { | mock_modes(IZ_LogInfo) { | ||||
@@ -1,8 +1,8 @@ | |||||
#ifndef IZ_STDLIB_MOCK_C | #ifndef IZ_STDLIB_MOCK_C | ||||
#define IZ_STDLIB_MOCK_C | #define IZ_STDLIB_MOCK_C | ||||
#include <bdd-for-c-mocks.h> | |||||
#include <SDL_stdinc.h> | #include <SDL_stdinc.h> | ||||
#include "../../../../src/packages/test/IZ_mock.h" | |||||
mock(IZ_malloc) void* IZ_malloc(size_t size) { | mock(IZ_malloc) void* IZ_malloc(size_t size) { | ||||
mock_return(IZ_malloc) SDL_malloc(size); | mock_return(IZ_malloc) SDL_malloc(size); | ||||
@@ -1,7 +1,7 @@ | |||||
#ifndef IZ_STRING_MOCK_C | #ifndef IZ_STRING_MOCK_C | ||||
#define IZ_STRING_MOCK_C | #define IZ_STRING_MOCK_C | ||||
#include "../../../../src/packages/test/IZ_mock.h" | |||||
#include <bdd-for-c-mocks.h> | |||||
mock(IZ_memset) void* IZ_memset(void* dst, int c, size_t len) { | mock(IZ_memset) void* IZ_memset(void* dst, int c, size_t len) { | ||||
mock_return(IZ_memset) 0; | mock_return(IZ_memset) 0; | ||||
@@ -9,3 +9,4 @@ https://github.com/Chunde/getopt-for-windows | |||||
https://libwebsockets.org/repo/libwebsockets | https://libwebsockets.org/repo/libwebsockets | ||||
https://github.com/openssl/openssl | https://github.com/openssl/openssl | ||||
https://www.sqlite.org/download.html (use SQLite amalgamated source code, unpack into `sqlite` directory) | https://www.sqlite.org/download.html (use SQLite amalgamated source code, unpack into `sqlite` directory) | ||||
https://code.modal.sh/TheoryOfNekomata/bdd-for-c-mocks |
@@ -1,6 +1,6 @@ | |||||
#include "../../test/IZ_test.h" | |||||
#include <bdd-for-c.h> | |||||
#include "../../common/IZ_common.h" | #include "../../common/IZ_common.h" | ||||
#include "../../../../__mocks__/dependencies/SDL2/SDL_stdinc.mock.h" | |||||
#include "../../../../__mocks__/src/packages/stdinc/IZ_stdlib.mock.h" | |||||
#include "IZ_list.h" | #include "IZ_list.h" | ||||
bool NodeExists(IZ_ListNode** node, u64 _index, IZ_List* list) { | bool NodeExists(IZ_ListNode** node, u64 _index, IZ_List* list) { | ||||
@@ -46,15 +46,15 @@ spec("data") { | |||||
} | } | ||||
after_each() { | after_each() { | ||||
mock_reset(SDL_free); | |||||
mock_reset(IZ_free); | |||||
} | } | ||||
it("removes all nodes from the list") { | it("removes all nodes from the list") { | ||||
mock_set_expected_calls(SDL_free, 3); | |||||
mock_set_expected_calls(IZ_free, 3); | |||||
IZ_ListTeardown(&list); | IZ_ListTeardown(&list); | ||||
check( | check( | ||||
mock_get_expected_calls(SDL_free) == mock_get_actual_calls(SDL_free), | |||||
mock_get_expected_calls(IZ_free) == mock_get_actual_calls(IZ_free), | |||||
"Deallocator function call count mismatch." | "Deallocator function call count mismatch." | ||||
); | ); | ||||
} | } | ||||
@@ -80,7 +80,7 @@ spec("data") { | |||||
} | } | ||||
after_each() { | after_each() { | ||||
mock_reset(SDL_malloc); | |||||
mock_reset(IZ_malloc); | |||||
} | } | ||||
after_each() { | after_each() { | ||||
@@ -97,7 +97,7 @@ spec("data") { | |||||
check(*((u64*) list.root->value) == 69420u, "Node not properly appended."); | check(*((u64*) list.root->value) == 69420u, "Node not properly appended."); | ||||
check( | check( | ||||
mock_is_called(SDL_malloc), | |||||
mock_is_called(IZ_malloc), | |||||
"Allocator function not called." | "Allocator function not called." | ||||
); | ); | ||||
check(list.length == 1, "Length mismatch."); | check(list.length == 1, "Length mismatch."); | ||||
@@ -110,7 +110,7 @@ spec("data") { | |||||
check(*((u64*) list2.root->next->value) == 42069u, "Node not properly appended."); | check(*((u64*) list2.root->next->value) == 42069u, "Node not properly appended."); | ||||
check( | check( | ||||
mock_is_called(SDL_malloc), | |||||
mock_is_called(IZ_malloc), | |||||
"Allocator function not called." | "Allocator function not called." | ||||
); | ); | ||||
check(list2.length == 2, "Length mismatch."); | check(list2.length == 2, "Length mismatch."); | ||||
@@ -160,14 +160,14 @@ spec("data") { | |||||
} | } | ||||
after_each() { | after_each() { | ||||
mock_reset(SDL_free); | |||||
mock_reset(IZ_free); | |||||
} | } | ||||
it("removes first node satisfying the filter condition") { | it("removes first node satisfying the filter condition") { | ||||
IZ_ListDeleteFirstNode(&list, NodeExists); | IZ_ListDeleteFirstNode(&list, NodeExists); | ||||
check( | check( | ||||
mock_is_called(SDL_free), | |||||
mock_is_called(IZ_free), | |||||
"Deallocator function not called." | "Deallocator function not called." | ||||
); | ); | ||||
@@ -1,4 +1,4 @@ | |||||
#include "../../test/IZ_test.h" | |||||
#include <bdd-for-c.h> | |||||
#include "IZ_vector2d.h" | #include "IZ_vector2d.h" | ||||
#include "IZ_rect.h" | #include "IZ_rect.h" | ||||
@@ -1,28 +0,0 @@ | |||||
#ifndef IZ_MOCK_H | |||||
#define IZ_MOCK_H | |||||
#define mock_call_count_t unsigned char | |||||
#define mock(X) static mock_call_count_t actual_##X = 0; | |||||
#define mock_mode_t unsigned char | |||||
#define mock_modes(X) static mock_mode_t current_mock_mode_##X = 0; enum mock_modes_##X | |||||
#define mock_mode(X, Y) current_mock_mode_##X = Y | |||||
#define mock_mode_if(X, Y) if (current_mock_mode_##X == Y) | |||||
#define mock_return(X) actual_##X += 1; return | |||||
#define mock_reset(X) actual_##X = 0 | |||||
#define mock_get_actual_calls(X) (mock_call_count_t) actual_##X | |||||
#define mock_set_expected_calls(X, Y) static const mock_call_count_t expected_##X = Y | |||||
#define mock_get_expected_calls(X) (mock_call_count_t) expected_##X | |||||
#define mock_is_called(X) mock_get_actual_calls(X) > 0 | |||||
#endif |
@@ -1,8 +0,0 @@ | |||||
#ifndef IZ_TEST_H | |||||
#define IZ_TEST_H | |||||
#include <bdd-for-c.h> | |||||
#include "IZ_mock.h" | |||||
#endif |
@@ -1,126 +0,0 @@ | |||||
# bdd-for-c-mocks | |||||
## Usage | |||||
Suppose you have a library `lib` and an application `app` that uses `lib`. You want to test `app` and you want to mock | |||||
`lib`'s functions. You can do this by creating a mock header file for `lib` and including it in `app`'s test file. | |||||
### `lib.h` | |||||
This is a reference header file for `lib`. The implementation should be abstracted from us, and we want to be able to | |||||
mock its behavior. | |||||
```c | |||||
#ifndef LIB_H | |||||
#define LIB_H | |||||
int add(int a, int b); | |||||
void alert(); | |||||
#endif | |||||
``` | |||||
### `lib.mock.h` | |||||
We define mocked behavior for `lib`. `bdd-for-c-mocks` offers a capability to force mock behavior through modes. Note | |||||
that all mode behaviors should be implemented already. | |||||
```c | |||||
#ifndef LIB_MOCK_H | |||||
#define LIB_MOCK_H | |||||
#include <bdd-for-c-mocks.h> | |||||
mock_modes(add) { | |||||
ADD_RETURNS_SUM = 0, | |||||
ADD_RETURNS_CONSTANT_VALUE, | |||||
}; | |||||
mock(add) int add(int a, int b) { | |||||
mock_mode_if(add, ADD_RETURNS_SUM) { | |||||
// suppose we want to test normal behavior | |||||
mock_return(add) a + b; | |||||
} else mock_mode_if(add, ADD_RETURNS_CONSTANT_VALUE) { | |||||
// maybe an edge case? | |||||
mock_return(add) 5; | |||||
} | |||||
} | |||||
mock(alert) void alert() { | |||||
mock_return(alert); | |||||
} | |||||
#endif | |||||
``` | |||||
### `app.h` | |||||
```c | |||||
#ifndef APP_H | |||||
#define APP_H | |||||
void math(); | |||||
#endif | |||||
``` | |||||
### `app.c` | |||||
This is a reference implementation of `app`. We want to test the invocations done inside the `math()` function. | |||||
```c | |||||
#include "lib.h" | |||||
#include "app.h" | |||||
void math() { | |||||
int result_a = add(1, 2); | |||||
int result_b = add(3, 4); | |||||
if (result_a == result_b) { | |||||
// this is the edge case! | |||||
// alert() should be called if the add values are the same | |||||
alert(); | |||||
} | |||||
} | |||||
``` | |||||
### `app.test.c` | |||||
This is the test file for `app`. It includes `lib.mock.h` instead of `lib.c`. `lib.h` should still be linked because we | |||||
are sharing the original function declarations. | |||||
```c | |||||
#include <bdd-for-c.h> | |||||
#include "app.h" | |||||
spec("app") { | |||||
describe("math") { | |||||
after_each() { | |||||
mock_reset(add); | |||||
} | |||||
after_each() { | |||||
mock_reset(alert); | |||||
} | |||||
it("calls add") { | |||||
mock_mode(add, ADD_RETURNS_SUM); | |||||
mock_set_excepted_calls(math, 2); | |||||
math(); | |||||
check( | |||||
mock_get_expected_calls(math) == mock_get_actual_calls(math), | |||||
"add was not called." | |||||
); | |||||
} | |||||
it("calls alert when calls from add return the same values") { | |||||
mock_mode(add, ADD_RETURNS_CONSTANT_VALUE); | |||||
math(); | |||||
check(mock_is_called(alert), "alert was not called."); | |||||
} | |||||
} | |||||
} | |||||
``` |