Переглянути джерело

Organize test fixtures

Add third-party mocks, specify mock files.

/? Do we need first-party mocks in their own files, or can we provide a
mock flag in the implementation files already?
feature/data-structs
TheoryOfNekomata 2 роки тому
джерело
коміт
d9cb1483d0
16 змінених файлів з 337 додано та 182 видалено
  1. +10
    -0
      .editorconfig
  2. +62
    -35
      CMakeLists.txt
  3. +14
    -0
      __mocks__/SDL_keyboard.mock.h
  4. +29
    -0
      __mocks__/minIni.mock.h
  5. +3
    -3
      src/packages/game/IZ_config.c
  6. +1
    -1
      src/packages/game/IZ_config.h
  7. +12
    -0
      src/packages/game/__mocks__/IZ_config.mock.h
  8. +2
    -2
      src/packages/game/input/IZ_joystick.c
  9. +2
    -3
      src/packages/game/input/IZ_keyboard.c
  10. +101
    -0
      src/packages/game/input/IZ_keyboard.test.c
  11. +0
    -126
      src/packages/game/output/IZ_config.test.c
  12. +14
    -6
      src/packages/game/output/IZ_video.c
  13. +2
    -1
      src/packages/game/output/IZ_video.h
  14. +66
    -0
      src/packages/game/output/IZ_video.test.c
  15. +11
    -5
      src/packages/test/IZ_mock.h
  16. +8
    -0
      src/packages/test/IZ_test.h

+ 10
- 0
.editorconfig Переглянути файл

@@ -0,0 +1,10 @@
root = true

[*]
charset = utf-8
end_of_line = lf
indent_size = tab
indent_style = tab
insert_final_newline = true
max_line_length = 120
tab_width = 2

+ 62
- 35
CMakeLists.txt Переглянути файл

@@ -6,54 +6,81 @@ project(izanagi C)
set(CMAKE_C_STANDARD 11)

include_directories(
"${PROJECT_SOURCE_DIR}/dependencies/SDL2/include"
"${PROJECT_SOURCE_DIR}/dependencies/minIni/dev"
"${PROJECT_SOURCE_DIR}/dependencies/bdd-for-c"
"${PROJECT_SOURCE_DIR}/dependencies/portmidi/pm_common"
"${PROJECT_SOURCE_DIR}/dependencies/SDL2/include"
"${PROJECT_SOURCE_DIR}/dependencies/minIni/dev"
"${PROJECT_SOURCE_DIR}/dependencies/bdd-for-c"
"${PROJECT_SOURCE_DIR}/dependencies/portmidi/pm_common"
)

if (WIN32)
if (CMAKE_SIZEOF_VOID_P EQUAL 8)
set(PROJECT_ARCH x64)
else ()
set(PROJECT_ARCH x86)
endif ()
if (CMAKE_SIZEOF_VOID_P EQUAL 8)
set(PROJECT_ARCH x64)
else ()
set(PROJECT_ARCH x86)
endif ()
endif ()

link_directories(
"${PROJECT_SOURCE_DIR}/dependencies/SDL2/lib/${PROJECT_ARCH}"
"${PROJECT_SOURCE_DIR}/dependencies/portmidi/Release"
"${PROJECT_SOURCE_DIR}/dependencies/SDL2/lib/${PROJECT_ARCH}"
"${PROJECT_SOURCE_DIR}/dependencies/portmidi/Release"
)

add_executable(
game
dependencies/minIni/dev/minIni.h
dependencies/minIni/dev/minIni.c
src/packages/game/output/IZ_video.h
src/packages/game/output/IZ_video.c
src/packages/game/IZ_common.h
src/packages/game/IZ_action.h
src/packages/game/IZ_app.h
src/packages/game/IZ_app.c
src/packages/game/main.c
src/packages/game/input/IZ_joystick.c src/packages/game/input/IZ_joystick.h src/packages/game/input/IZ_keyboard.c src/packages/game/input/IZ_keyboard.h src/packages/game/IZ_config.c src/packages/game/IZ_config.h)
game
dependencies/minIni/dev/minIni.h
dependencies/minIni/dev/minIni.c
src/packages/game/output/IZ_video.h
src/packages/game/output/IZ_video.c
src/packages/game/IZ_common.h
src/packages/game/IZ_action.h
src/packages/game/IZ_app.h
src/packages/game/IZ_app.c
src/packages/game/main.c
src/packages/game/input/IZ_joystick.c
src/packages/game/input/IZ_joystick.h
src/packages/game/input/IZ_keyboard.c
src/packages/game/input/IZ_keyboard.h
src/packages/game/IZ_config.c
src/packages/game/IZ_config.h
)
target_link_libraries(
game
SDL2main
SDL2
game
SDL2main
SDL2
)

add_executable(
game-test
dependencies/bdd-for-c/bdd-for-c.h
src/packages/game/output/IZ_video.h
src/packages/game/output/IZ_video.c
src/packages/game/output/IZ_config.test.c
src/packages/test/IZ_mock.h)
game-test-output
dependencies/bdd-for-c/bdd-for-c.h
src/packages/test/IZ_mock.h src/packages/test/IZ_test.h
__mocks__/minIni.mock.h

src/packages/game/IZ_config.h

src/packages/game/output/IZ_video.h
src/packages/game/output/IZ_video.c
src/packages/game/output/IZ_video.test.c
__mocks__/SDL_keyboard.mock.h src/packages/game/__mocks__/IZ_config.mock.h)

add_executable(
game-test-input
dependencies/bdd-for-c/bdd-for-c.h
src/packages/test/IZ_mock.h src/packages/test/IZ_test.h
__mocks__/minIni.mock.h

src/packages/game/IZ_config.h

src/packages/game/input/IZ_keyboard.h
src/packages/game/input/IZ_keyboard.c
src/packages/game/input/IZ_keyboard.test.c

# src/packages/game/input/IZ_joystick.h
# src/packages/game/input/IZ_joystick.c
__mocks__/SDL_keyboard.mock.h src/packages/game/__mocks__/IZ_config.mock.h)

if (WIN32)
add_custom_command(TARGET game POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different # which executes "cmake - E copy_if_different..."
"${PROJECT_SOURCE_DIR}/dependencies/SDL2/lib/${PROJECT_ARCH}/SDL2.dll" # <--this is in-file
$<TARGET_FILE_DIR:game>) # <--this is out-file path
add_custom_command(TARGET game POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different # which executes "cmake - E copy_if_different..."
"${PROJECT_SOURCE_DIR}/dependencies/SDL2/lib/${PROJECT_ARCH}/SDL2.dll" # <--this is in-file
$<TARGET_FILE_DIR:game>) # <--this is out-file path
endif ()

+ 14
- 0
__mocks__/SDL_keyboard.mock.h Переглянути файл

@@ -0,0 +1,14 @@
#ifndef SDL_KEYBOARD_MOCK_H
#define SDL_KEYBOARD_MOCK_H

#include "../src/packages/test/IZ_test.h"

mock(SDL_GetKeyName) const char* SDL_GetKeyName(int key) {
mock_return(SDL_GetKeyName) "";
}

mock(SDL_GetKeyFromName) int SDL_GetKeyFromName(const char *name) {
mock_return(SDL_GetKeyFromName) 0;
}

#endif

+ 29
- 0
__mocks__/minIni.mock.h Переглянути файл

@@ -0,0 +1,29 @@
#ifndef MININI_MOCK_H
#define MININI_MOCK_H

#include "../src/packages/test/IZ_test.h"

mock(ini_getl) long ini_getl(const TCHAR *Section, const TCHAR *Key, long DefValue, const TCHAR *Filename) {
mock_return(ini_getl) DefValue;
}

mock(ini_putl) int ini_putl(const TCHAR *Section, const TCHAR *Key, long Value, const TCHAR *Filename) {
mock_return(ini_putl) 1;
}

mock(ini_gets) int ini_gets(
const TCHAR *Section,
const TCHAR *Key,
const TCHAR *DefValue,
TCHAR *Buffer,
int BufferSize,
const TCHAR *Filename
) {
mock_return(ini_gets) 0;
}

mock(ini_puts) int ini_puts(const TCHAR *Section, const TCHAR *Key, const TCHAR *Value, const TCHAR *Filename) {
mock_return(ini_puts) 1;
}

#endif

+ 3
- 3
src/packages/game/IZ_config.c Переглянути файл

@@ -1,8 +1,8 @@
#include "IZ_config.h"

void IZ_GetConfigPath(char* config_path) {
void IZ_GetConfigPath(char* config_path, size_t string_size) {
//const char* config_path_dir = SDL_GetPrefPath("Modal Studios", APP_NAME);
const char* config_path_dir = SDL_GetBasePath();
memcpy_s(config_path, 128, config_path_dir, 128);
strcat_s(config_path, 128, "config.ini");
memcpy_s(config_path, string_size, config_path_dir, 128);
strcat_s(config_path, string_size, "config.ini");
}

+ 1
- 1
src/packages/game/IZ_config.h Переглянути файл

@@ -4,6 +4,6 @@
#include <SDL_filesystem.h>
#include <string.h>

void IZ_GetConfigPath(char* config_path);
void IZ_GetConfigPath(char*, size_t);

#endif

+ 12
- 0
src/packages/game/__mocks__/IZ_config.mock.h Переглянути файл

@@ -0,0 +1,12 @@
#ifndef IZ_CONFIG_MOCK_H
#define IZ_CONFIG_MOCK_H

#include "../../test/IZ_test.h"

mock(IZ_GetConfigPath) void IZ_GetConfigPath(char* config_path, size_t string_size) {
const char dummy_path[] = "test-config.ini";
memcpy_s(config_path, string_size, dummy_path, 128);
mock_return(IZ_GetConfigPath);
}

#endif

+ 2
- 2
src/packages/game/input/IZ_joystick.c Переглянути файл

@@ -74,7 +74,7 @@ void IZ_HandleJoystickEvents(SDL_Event e, IZ_JoystickState* state, IZ_Action* ac

void IZ_LoadJoystickConfig(IZ_JoystickConfig* config, uint8_t p) {
char config_path[128];
IZ_GetConfigPath(config_path);
IZ_GetConfigPath(config_path, 128);

char joystick_control_mapping_section_name[] = "Joystick.0.ControlMapping";
joystick_control_mapping_section_name[9] = (char) (48 + p);
@@ -89,7 +89,7 @@ void IZ_LoadJoystickConfig(IZ_JoystickConfig* config, uint8_t p) {

void IZ_SaveJoystickConfig(IZ_JoystickConfig* config, uint8_t p) {
char config_path[128];
IZ_GetConfigPath(config_path);
IZ_GetConfigPath(config_path, 128);

char joystick_control_mapping_section_name[] = "Joystick.0.ControlMapping";
joystick_control_mapping_section_name[9] = (char) (48 + p);


+ 2
- 3
src/packages/game/input/IZ_keyboard.c Переглянути файл

@@ -15,11 +15,10 @@ void IZ_HandleKeyboardEvents(SDL_Event e, IZ_KeyboardState* state, IZ_Action* ac

void IZ_SaveKeyboardConfig(IZ_KeyboardConfig* config, uint8_t p) {
char config_path[128];
IZ_GetConfigPath(config_path);
IZ_GetConfigPath(config_path, 128);

char keyboard_section_name[] = "Keyboard.0.ControlMapping";
keyboard_section_name[9] = (char) (48 + p);

for (uint8_t i = 0; i < CONTROLS; i += 1) {
ini_puts(keyboard_section_name, ACTION_NAMES[i], SDL_GetKeyName(config->control_mapping[i]), config_path);
}
@@ -27,7 +26,7 @@ void IZ_SaveKeyboardConfig(IZ_KeyboardConfig* config, uint8_t p) {

void IZ_LoadKeyboardConfig(IZ_KeyboardConfig* config, uint8_t p) {
char config_path[128];
IZ_GetConfigPath(config_path);
IZ_GetConfigPath(config_path, 128);

char buffer[128];
char keyboard_section_name[] = "Keyboard.0.ControlMapping";


+ 101
- 0
src/packages/game/input/IZ_keyboard.test.c Переглянути файл

@@ -0,0 +1,101 @@
#include "../../../__mocks__/SDL_keyboard.mock.h"
#include "../../../__mocks__/minIni.mock.h"
#include "../__mocks__/IZ_config.mock.h"
#include "IZ_keyboard.h"

spec("input/keyboard") {
describe("HandleKeyboardEvents") {
static SDL_Event e;
static IZ_KeyboardState state;
static IZ_Action action;

for (uint8_t i = 0; i < CONTROLS; i += 1) {
it("handles %s action activation", ACTION_NAMES[i]) {
e.type = SDL_KEYDOWN;
e.key.keysym.sym = IZ_DEFAULT_KEYBOARD_CONTROLS[0][i];
state.config.control_mapping[i] = IZ_DEFAULT_KEYBOARD_CONTROLS[0][i];
action = 0;

IZ_HandleKeyboardEvents(e, &state, &action);
check(
action == (0x1 << i),
"Action not set."
);
}

it("handles %s action deactivation", ACTION_NAMES[i]) {
e.type = SDL_KEYUP;
e.key.keysym.sym = IZ_DEFAULT_KEYBOARD_CONTROLS[0][i];
state.config.control_mapping[i] = IZ_DEFAULT_KEYBOARD_CONTROLS[0][i];
action = ~0;

IZ_HandleKeyboardEvents(e, &state, &action);
check(
!(action & (0x1 << i)),
"Action not unset."
);
}
}
}

describe("LoadKeyboardConfig") {
static IZ_KeyboardConfig config;

after_each() {
mock_reset(IZ_GetConfigPath);
}

after_each() {
mock_reset(ini_gets);
}

it("calls load method") {
mock_set_expected_calls(ini_gets, CONTROLS);

IZ_LoadKeyboardConfig(&config, 0);

check(
mock_is_called(IZ_GetConfigPath),
"SDL_GetBasePath() not called."
);

check(
mock_get_expected_calls(ini_gets) == mock_get_actual_calls(ini_gets),
"Call count mismatch for ini_gets() (expected %u, received %u).",
mock_get_expected_calls(ini_gets),
mock_get_actual_calls(ini_gets)
);
}
}

describe("SaveKeyboardConfig") {
static IZ_KeyboardConfig config;

after_each() {
mock_reset(IZ_GetConfigPath);
}

after_each() {
mock_reset(ini_puts);
}

before_each() {
for (uint8_t i = 0; i < CONTROLS; i += 1) {
config.control_mapping[i] = IZ_DEFAULT_KEYBOARD_CONTROLS[0][i];
}
}

it("calls save method") {
mock_set_expected_calls(ini_puts, CONTROLS);

IZ_SaveKeyboardConfig(&config, 0);

check(
mock_get_expected_calls(ini_puts) == mock_get_actual_calls(ini_puts),
"Call count mismatch for ini_puts() (expected %u, received %u).",
mock_get_expected_calls(ini_puts),
mock_get_actual_calls(ini_puts)
);
}
}
}

+ 0
- 126
src/packages/game/output/IZ_config.test.c Переглянути файл

@@ -1,126 +0,0 @@
#include <bdd-for-c.h>
#include "../../test/IZ_mock.h"
#include "IZ_video.h"

mock(SDL_GetBasePath) char* SDL_GetBasePath() {
mock_return(SDL_GetBasePath) "";
}

mock(SDL_GetKeyName) const char* SDL_GetKeyName (SDL_KeyCode code) {
mock_return(SDL_GetKeyName) "";
}

mock(SDL_GetKeyFromName) SDL_KeyCode SDL_GetKeyFromName(const char* name) {
mock_return(SDL_GetKeyFromName) 0;
}

mock(ini_gets) int ini_gets(
const TCHAR *Section,
const TCHAR *Key,
const TCHAR *DefValue,
char *Buffer,
int BufferSize,
const TCHAR *Filename
) {
mock_return(ini_gets) 0;
}

mock(ini_getl) long ini_getl(
const TCHAR *Section,
const TCHAR *Key,
long DefValue,
const TCHAR *Filename
) {
mock_return(ini_getl) DefValue;
}

spec("config") {
describe("LoadConfig") {
static IZ_Config config;

after_each() {
mock_reset(ini_getl);
}

after_each() {
mock_reset(ini_gets);
}

after_each() {
mock_reset(SDL_GetKeyFromName);
}

after_each() {
mock_reset(SDL_GetKeyName);
}

after_each() {
mock_reset(SDL_GetBasePath);
}

it("should load default config values") {
IZ_LoadVideoConfig(&config);

check(
mock_calls(SDL_GetBasePath) > 0,
"SDL_GetBasePath() not called."
);

static const mock_call_count_t expected_calls_ini_getl =
3 // video params
+ 1 // input params
+ (12 * PLAYERS); // joystick controls
check(
mock_calls(ini_getl) == expected_calls_ini_getl,
"Call count mismatch for ini_getl() (expected %u, received %u).",
expected_calls_ini_getl,
mock_calls(ini_getl)
);

check(
config.video.width == 640,
"Default value for Video.Width is not loaded."
);
check(
config.video.height == 480,
"Default value for Video.Height is not loaded."
);
check(
config.video.max_fps == 30,
"Default value for Video.MaxFps is not loaded."
);

check(
config.input.axis_threshold == 8000,
"Default value for Input.GamepadAxisThreshold is not loaded."
);

static const mock_call_count_t expected_calls_ini_gets =
(16 * PLAYERS); // keyboard controls
check(
mock_calls(ini_gets) == expected_calls_ini_gets,
"Call count mismatch for ini_gets() (expected %u, received %u).",
expected_calls_ini_gets,
mock_calls(ini_gets)
);

static const mock_call_count_t expected_calls_SDL_GetKeyFromName =
(16 * PLAYERS); // keyboard controls
check(
mock_calls(SDL_GetKeyFromName) == expected_calls_SDL_GetKeyFromName,
"Call count mismatch for SDL_GetKeyFromName() (expected %u, received %u).",
expected_calls_SDL_GetKeyFromName,
mock_calls(SDL_GetKeyFromName)
);

static const mock_call_count_t expected_calls_SDL_GetKeyName =
(16 * PLAYERS); // keyboard controls
check(
mock_calls(SDL_GetKeyName) == expected_calls_SDL_GetKeyName,
"Call count mismatch for SDL_GetKeyName() (expected %u, received %u).",
expected_calls_SDL_GetKeyName,
mock_calls(SDL_GetKeyName)
);
}
}
}

+ 14
- 6
src/packages/game/output/IZ_video.c Переглянути файл

@@ -1,17 +1,25 @@
#include "IZ_video.h"

void IZ_SaveVideoConfig(IZ_VideoConfig* config) {
IZ_ProcedureResult IZ_SaveVideoConfig(IZ_VideoConfig* config) {
char config_path[128];
IZ_GetConfigPath(config_path);
IZ_GetConfigPath(config_path, 128);

ini_putl("Video", "Width", config->width, config_path);
ini_putl("Video", "Height", config->height, config_path);
ini_putl("Video", "MaxFps", config->max_fps, config_path);
if (!ini_putl("Video", "Width", config->width, config_path)) {
return 1;
}
if (!ini_putl("Video", "Height", config->height, config_path)) {
return 1;
}
if (!ini_putl("Video", "MaxFps", config->max_fps, config_path)) {
return 1;
}

return 0;
}

void IZ_LoadVideoConfig(IZ_VideoConfig* config) {
char config_path[128];
IZ_GetConfigPath(config_path);
IZ_GetConfigPath(config_path, 128);

config->width = ini_getl("Video", "Width", 640l, config_path);
config->height = ini_getl("Video", "Height", 480l, config_path);


+ 2
- 1
src/packages/game/output/IZ_video.h Переглянути файл

@@ -3,6 +3,7 @@

#include <stdio.h>
#include <minIni.h>
#include "../IZ_common.h"
#include "../IZ_config.h"

typedef struct {
@@ -11,7 +12,7 @@ typedef struct {
uint8_t max_fps;
} IZ_VideoConfig;

void IZ_SaveVideoConfig(IZ_VideoConfig* config);
IZ_ProcedureResult IZ_SaveVideoConfig(IZ_VideoConfig* config);

void IZ_LoadVideoConfig(IZ_VideoConfig* config);



+ 66
- 0
src/packages/game/output/IZ_video.test.c Переглянути файл

@@ -0,0 +1,66 @@
#include "../../../__mocks__/minIni.mock.h"
#include "../__mocks__/IZ_config.mock.h"
#include "IZ_video.h"

spec("output/video") {
describe("LoadVideoConfig") {
static IZ_VideoConfig config;

after_each() {
mock_reset(IZ_GetConfigPath);
}

after_each() {
mock_reset(ini_getl);
}

it("calls load method") {
mock_set_expected_calls(ini_getl, 3);

IZ_LoadVideoConfig(&config);

check(
mock_is_called(IZ_GetConfigPath),
"SDL_GetBasePath() not called."
);

check(
mock_get_expected_calls(ini_getl) == mock_get_actual_calls(ini_getl),
"Call count mismatch for ini_getl() (expected %u, received %u).",
mock_get_expected_calls(ini_getl),
mock_get_actual_calls(ini_getl)
);
}
}

describe("SaveVideoConfig") {
static IZ_VideoConfig config;

after_each() {
mock_reset(IZ_GetConfigPath);
}

after_each() {
mock_reset(ini_putl);
}

before_each() {
config.width = 1337;
config.height = 420;
config.max_fps = 69;
}

it("calls save method") {
mock_set_expected_calls(ini_putl, 3);

IZ_SaveVideoConfig(&config);

check(
mock_get_expected_calls(ini_putl) == mock_get_actual_calls(ini_putl),
"Call count mismatch for ini_putl() (expected %u, received %u).",
mock_get_expected_calls(ini_putl),
mock_get_actual_calls(ini_putl)
);
}
}
}

+ 11
- 5
src/packages/test/IZ_mock.h Переглянути файл

@@ -1,14 +1,20 @@
#ifndef IZ_MOCK_H
#define IZ_MOCK_H

#define mock_call_count_t uint8_t
#define mock_call_count_t unsigned char

#define mock(X) static mock_call_count_t calls_##X = 0;
#define mock(X) static mock_call_count_t actual_##X = 0;

#define mock_return(X) calls_##X += 1; return
#define mock_return(X) actual_##X += 1; return

#define mock_reset(X) calls_##X = 0
#define mock_reset(X) actual_##X = 0

#define mock_calls(X) ((mock_call_count_t) (calls_##X))
#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

+ 8
- 0
src/packages/test/IZ_test.h Переглянути файл

@@ -0,0 +1,8 @@
#ifndef IZ_TEST_H
#define IZ_TEST_H

#include <bdd-for-c.h>

#include "IZ_mock.h"

#endif

Завантаження…
Відмінити
Зберегти