diff options
| author | Felix Morgner <felix.morgner@gmail.com> | 2026-02-19 13:30:45 +0100 |
|---|---|---|
| committer | Felix Morgner <felix.morgner@gmail.com> | 2026-02-19 13:30:45 +0100 |
| commit | e6d59a7b506f610b82340b62457f9dd9ad0cb53d (patch) | |
| tree | b83affc4789146822a9fdbda88402b87c5f0fa28 | |
| parent | e34239cf2bdb6bd810826b82c2a66873bd0881e2 (diff) | |
| download | snake.s-e6d59a7b506f610b82340b62457f9dd9ad0cb53d.tar.xz snake.s-e6d59a7b506f610b82340b62457f9dd9ad0cb53d.zip | |
feat: integrate basic CMocka tests
| -rw-r--r-- | .vscode/settings.json | 9 | ||||
| -rw-r--r-- | CMakeLists.txt | 20 | ||||
| -rw-r--r-- | CMakePresets.json | 3 | ||||
| -rw-r--r-- | libs/SDL/error.S | 6 | ||||
| -rw-r--r-- | libs/SDL/events.S | 6 | ||||
| -rw-r--r-- | libs/SDL/init.S | 6 | ||||
| -rw-r--r-- | libs/SDL/rect.S | 6 | ||||
| -rw-r--r-- | libs/SDL/render.S | 6 | ||||
| -rw-r--r-- | libs/SDL/video.S | 4 | ||||
| -rw-r--r-- | src/error.S | 3 | ||||
| -rw-r--r-- | src/helpers/function.S | 4 | ||||
| -rw-r--r-- | src/snake.S | 77 | ||||
| -rw-r--r-- | tests/CMakeLists.txt | 42 | ||||
| -rw-r--r-- | tests/main.c | 5 | ||||
| -rw-r--r-- | tests/snake.c | 65 | ||||
| -rw-r--r-- | tests/suites.h | 6 |
16 files changed, 259 insertions, 9 deletions
diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..e2ce90a --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,9 @@ +{ + "cSpell.words": [ + "ifndef", + "Lexit", + "offsetof", + "stdc", + "stddef" + ] +}
\ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 9e2baef..7f97d30 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,15 +6,29 @@ project("snake.s" LANGUAGES ASM ) +option(SNAKE_BUILD_TESTS "Build the snake.s tests" ON) + add_subdirectory("libs") -add_executable("snake.s" +add_library("snake.core" "src/error.S" - "src/main.S" + "src/snake.S" +) + +target_include_directories("snake.core" PUBLIC + "src" ) -target_link_libraries("snake.s" PRIVATE +target_link_libraries("snake.core" PUBLIC "bindings::SDL2" ) +add_executable("snake.s" "src/main.S") + +target_link_libraries("snake.s" PRIVATE "snake.core") + install(TARGETS "snake.s") + +if(SNAKE_BUILD_TESTS) + add_subdirectory("tests") +endif()
\ No newline at end of file diff --git a/CMakePresets.json b/CMakePresets.json index dc09fc2..e646f4a 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -7,7 +7,8 @@ "generator": "Ninja", "binaryDir": "${sourceDir}/build", "cacheVariables": { - "CMAKE_BUILD_TYPE": "Debug" + "CMAKE_BUILD_TYPE": "Debug", + "CMAKE_EXPORT_COMPILE_COMMANDS": true } } ], diff --git a/libs/SDL/error.S b/libs/SDL/error.S index 19efb5a..ea2d853 100644 --- a/libs/SDL/error.S +++ b/libs/SDL/error.S @@ -1,3 +1,5 @@ +#ifndef __STDC_VERSION__ + //! @file error.S //! //! Assembler bindings for SDL2 (SDL_error.h) @@ -5,4 +7,6 @@ //! @fn char const * SDL_GetError(void) //! @return the last error message .type SDL_GetError, @function -.extern SDL_GetError
\ No newline at end of file +.extern SDL_GetError + +#endif
\ No newline at end of file diff --git a/libs/SDL/events.S b/libs/SDL/events.S index b94b65c..ce3a767 100644 --- a/libs/SDL/events.S +++ b/libs/SDL/events.S @@ -1,3 +1,5 @@ +#ifndef __STDC_VERSION__ + //! @file events.S //! //! Assembler bindings for SDL2 (SDL_events.h) @@ -12,4 +14,6 @@ //! @param event the SDL_Event structure to be filled with the next event from the queue, or NULL. //! @return 1 if there is a pending event, or 0 if there isn't. .type SDL_PollEvent, @function -.extern SDL_PollEvent
\ No newline at end of file +.extern SDL_PollEvent + +#endif
\ No newline at end of file diff --git a/libs/SDL/init.S b/libs/SDL/init.S index a2880c8..7026d64 100644 --- a/libs/SDL/init.S +++ b/libs/SDL/init.S @@ -1,3 +1,5 @@ +#ifndef __STDC_VERSION__ + //! @file init.S //! //! Assembler bindings for SDL2 (SDL.h) @@ -28,4 +30,6 @@ //! @fn void SDL_Quit(void) .type SDL_Quit, @function -.extern SDL_Quit
\ No newline at end of file +.extern SDL_Quit + +#endif
\ No newline at end of file diff --git a/libs/SDL/rect.S b/libs/SDL/rect.S index f402324..a535f3b 100644 --- a/libs/SDL/rect.S +++ b/libs/SDL/rect.S @@ -1,3 +1,5 @@ +#ifndef __STDC_VERSION__ + //! @file rect.S //! //! Assembler bindings for SDL2 (SDL_rect.h) @@ -7,4 +9,6 @@ #define OFFSET_SDL_Rect_w 8 #define OFFSET_SDL_Rect_h 12 -#define SIZE_SDL_Rect 16
\ No newline at end of file +#define SIZE_SDL_Rect 16 + +#endif
\ No newline at end of file diff --git a/libs/SDL/render.S b/libs/SDL/render.S index 61c06e5..d256bff 100644 --- a/libs/SDL/render.S +++ b/libs/SDL/render.S @@ -1,3 +1,5 @@ +#ifndef __STDC_VERSION__ + //! @file render.S //! //! Assembler bindings for SDL2 (SDL_render.h) @@ -45,4 +47,6 @@ //! @param a the alpha value used to draw on the rendering target. //! @return 0 on success, or a negative value on error. .type SDL_SetRenderDrawColor, @function -.extern SDL_SetRenderDrawColor
\ No newline at end of file +.extern SDL_SetRenderDrawColor + +#endif
\ No newline at end of file diff --git a/libs/SDL/video.S b/libs/SDL/video.S index f91cc89..78623bd 100644 --- a/libs/SDL/video.S +++ b/libs/SDL/video.S @@ -1,3 +1,5 @@ +#ifndef __STDC_VERSION__ + //! @file video.S //! //! Assembler bindings for SDL2 (SDL_video.h) @@ -21,3 +23,5 @@ //! @param window the window to destroy .type SDL_DestroyWindow, @function .extern SDL_DestroyWindow + +#endif
\ No newline at end of file diff --git a/src/error.S b/src/error.S index 44be8b0..50597dd 100644 --- a/src/error.S +++ b/src/error.S @@ -1,6 +1,8 @@ #include "helpers/function.S" #include "SDL/error.S" +#ifndef __STDC_VERSION__ + .section .text //! @function _print_sdl_error(char const * format) @@ -19,3 +21,4 @@ function_end +#endif
\ No newline at end of file diff --git a/src/helpers/function.S b/src/helpers/function.S index af41905..eeada7c 100644 --- a/src/helpers/function.S +++ b/src/helpers/function.S @@ -1,3 +1,5 @@ +#ifndef __STDC_VERSION__ + .set .L_FUNCTION_IS_IN_FUNCTION_DEFINITION, 0 .set .L_FUNCTION_LOCALS_ALLOCATED, 0 @@ -122,3 +124,5 @@ .cfi_def_cfa_register %rbp .set .L\name\()_FRAME_OFFSET, 0 .endm + +#endif
\ No newline at end of file diff --git a/src/snake.S b/src/snake.S new file mode 100644 index 0000000..00d66e2 --- /dev/null +++ b/src/snake.S @@ -0,0 +1,77 @@ +//! @file snake.S +//! +//! Type definitions, sizes, and the interface for the snake. + +#include "helpers/function.S" + +#define OFFSET_snake_t_x 0 +#define SIZE_snake_t_x 4 + +#define OFFSET_snake_t_y OFFSET_snake_t_x + SIZE_snake_t_x +#define SIZE_snake_t_y 4 + +#define OFFSET_snake_t_length OFFSET_snake_t_y + SIZE_snake_t_y +#define SIZE_snake_t_length 4 + +#define OFFSET_snake_t_direction OFFSET_snake_t_length + SIZE_snake_t_length +#define SIZE_snake_t_direction 1 + +#define OFFSET_snake_t_padding OFFSET_snake_t_direction + SIZE_snake_t_direction +#define SIZE_snake_t_padding 3 + +#define SIZE_snake_t OFFSET_snake_t_padding + SIZE_snake_t_padding + +#ifndef __STDC_VERSION__ + +.section .text + + //! @fn void snake_init(snake_t * self, int x, int y, int length) + //! @param (%rdi) self the object to initialize + //! @param (%esi) x the x position of the head of the snake + //! @param (%edx) y the y position of the head of the snake + //! @param (%ecx) length the length of the snake + function_begin snake_init + + test %rdi, %rdi + jz .Lexit_snake_init + + mov %esi, OFFSET_snake_t_x(%rdi) + mov %edx, OFFSET_snake_t_y(%rdi) + mov %ecx, OFFSET_snake_t_length(%rdi) + xor %al, %al + mov %al, OFFSET_snake_t_direction(%rdi) + + function_end + +#else + +#include <stddef.h> + +typedef struct { + int x; + int y; + int length; + char direction; + char padding[3]; +} snake_t; + +static_assert(sizeof(snake_t) == SIZE_snake_t); + +static_assert(offsetof(snake_t, x) == OFFSET_snake_t_x); +static_assert(sizeof(((snake_t*)0)->x) == SIZE_snake_t_x); + +static_assert(offsetof(snake_t, y) == OFFSET_snake_t_y); +static_assert(sizeof(((snake_t*)0)->y) == SIZE_snake_t_y); + +static_assert(offsetof(snake_t, length) == OFFSET_snake_t_length); +static_assert(sizeof(((snake_t*)0)->length) == SIZE_snake_t_length); + +static_assert(offsetof(snake_t, direction) == OFFSET_snake_t_direction); +static_assert(sizeof(((snake_t*)0)->direction) == SIZE_snake_t_direction); + +static_assert(offsetof(snake_t, padding) == OFFSET_snake_t_padding); +static_assert(sizeof(((snake_t*)0)->padding) == SIZE_snake_t_padding); + +void snake_init(snake_t * self, int x, int y, int length); + +#endif
\ No newline at end of file diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 0000000..3ed41d4 --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,42 @@ +enable_language(C) + +set(CMAKE_C_STANDARD 23) +set(CMAKE_C_STANDARD_REQUIRED YES) +set(CMAKE_C_EXTENSIONS OFF) + +include("FetchContent") + +FetchContent_Declare("CMocka" + URL "https://gitlab.com/cmocka/cmocka/-/archive/cmocka-2.0.0/cmocka-cmocka-2.0.0.zip" + URL_HASH "SHA256=c2a53cc0a45e8be734f657e48daa687f077def759ea30adcd46bdb842a8fb269" +) + +set(BUILD_SHARED_LIBS OFF) +set(WITH_EXAMPLES OFF) + +FetchContent_MakeAvailable("CMocka") + +enable_testing() + +add_executable("snake.tests" + "main.c" + "snake.c" +) + +target_compile_features("snake.tests" PUBLIC + "c_std_23" +) + +target_compile_options("snake.tests" PUBLIC + "-Wall" + "-Wextra" + "-Werror" + "-pedantic-errors" +) + +target_link_libraries("snake.tests" PUBLIC + "snake.core" + "cmocka" +) + +add_test(NAME "snake.tests" COMMAND "snake.tests")
\ No newline at end of file diff --git a/tests/main.c b/tests/main.c new file mode 100644 index 0000000..e156b31 --- /dev/null +++ b/tests/main.c @@ -0,0 +1,5 @@ +#include "suites.h" + +#include <cmocka.h> + +int main() { return run_snake_tests(); }
\ No newline at end of file diff --git a/tests/snake.c b/tests/snake.c new file mode 100644 index 0000000..f4acc7e --- /dev/null +++ b/tests/snake.c @@ -0,0 +1,65 @@ +#include "suites.h" + +#include "snake.S" + +#include <cmocka.h> + + + +extern void snake_init(snake_t *self, int x, int y, int length); + +static void test_snake_init_sets_x([[maybe_unused]] void **state) { + // Arrange: + snake_t snake; + + // Act: + snake_init(&snake, 1, 2, 3); + + // Assert: + assert_int_equal(snake.x, 1); +} + +static void test_snake_init_sets_y([[maybe_unused]] void **state) { + // Arrange: + snake_t snake; + + // Act: + snake_init(&snake, 1, 2, 3); + + // Assert: + assert_int_equal(snake.y, 2); +} + +static void test_snake_init_sets_length([[maybe_unused]] void **state) { + // Arrange: + snake_t snake; + + // Act: + snake_init(&snake, 1, 2, 3); + + // Assert: + assert_int_equal(snake.length, 3); +} + +static void +test_snake_init_sets_direction_to_zero([[maybe_unused]] void **state) { + // Arrange: + snake_t snake; + + // Act: + snake_init(&snake, 1, 2, 3); + + // Assert: + assert_int_equal(snake.direction, 0); +} + +int run_snake_tests(void) { + struct CMUnitTest const tests[] = { + cmocka_unit_test(test_snake_init_sets_x), + cmocka_unit_test(test_snake_init_sets_y), + cmocka_unit_test(test_snake_init_sets_length), + cmocka_unit_test(test_snake_init_sets_direction_to_zero), + }; + + return cmocka_run_group_tests(tests, NULL, NULL); +} diff --git a/tests/suites.h b/tests/suites.h new file mode 100644 index 0000000..ea82ece --- /dev/null +++ b/tests/suites.h @@ -0,0 +1,6 @@ +#ifndef SNAKE_TESTS_SUITES_H +#define SNAKE_TESTS_SUITES_H + +int run_snake_tests(); + +#endif
\ No newline at end of file |
