From f3eb15d59ce81fb92a16375189f1d4755e2b7574 Mon Sep 17 00:00:00 2001 From: TheoryOfNekomata Date: Fri, 3 Mar 2023 19:36:23 +0800 Subject: [PATCH] Implement int test Add tests for int config items. --- .gitignore | 1 - CMakeLists.txt | 45 +++++++++++++---- README.md | 11 ++++- fixtures/test-int.ini | 29 +++++++++++ ini-config.c | 23 --------- source/ini-config.c | 73 +++++++++++++++++++++++++++ ini-config.h => source/ini-config.h | 49 +++++++++++------- {types => source/types}/int.c | 0 {types => source/types}/int.h | 1 + {types => source/types}/string.c | 51 ------------------- {types => source/types}/string.h | 1 + tests/test-int.c | 77 +++++++++++++++++++++++++++++ 12 files changed, 258 insertions(+), 103 deletions(-) create mode 100644 fixtures/test-int.ini delete mode 100644 ini-config.c create mode 100644 source/ini-config.c rename ini-config.h => source/ini-config.h (80%) rename {types => source/types}/int.c (100%) rename {types => source/types}/int.h (98%) rename {types => source/types}/string.c (52%) rename {types => source/types}/string.h (94%) create mode 100644 tests/test-int.c diff --git a/.gitignore b/.gitignore index f69d6e9..41f7f34 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,2 @@ .idea/ -cmake-build-*/ build/ diff --git a/CMakeLists.txt b/CMakeLists.txt index 93694f0..15902b4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,18 +1,45 @@ cmake_minimum_required(VERSION 3.24) -project(ini_config C) - +project(ini-config C) set(CMAKE_C_STANDARD 11) +include(CTest) + include_directories( "${CMAKE_HOME_DIRECTORY}/subprojects/minIni/dev" ) add_library( - ini_config STATIC - ini-config.c - ini-config.h - types/int.c - types/int.h - types/string.c - types/string.h + ini-config STATIC + source/ini-config.c + source/ini-config.h + source/types/int.c + source/types/int.h + source/types/string.c + source/types/string.h +) + +add_executable( + test-int + subprojects/minIni/dev/minIni.h + subprojects/minIni/dev/minIni.c + tests/test-int.c + source/ini-config.c + source/ini-config.h + source/types/int.c + source/types/int.h +) + +set_target_properties (test-int PROPERTIES RUNTIME_OUTPUT_DIRECTORY tests) + +add_test( + NAME test-int + COMMAND test-int + WORKING_DIRECTORY tests +) + +add_custom_command( + TARGET test-int POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different + "${CMAKE_HOME_DIRECTORY}/fixtures/test-int.ini" + $ ) diff --git a/README.md b/README.md index 8e14e4f..f5628a9 100644 --- a/README.md +++ b/README.md @@ -5,5 +5,14 @@ ```shell mkdir build cmake "-DCMAKE_MT=%CMAKE_MT%" -G Ninja -S . -B build -cmake --build build -t ini_config +cmake --build build -t ini-config +``` + +## Testing + +```shell +cmake --build build -t test-int +cmake --build build -t test-string +cd build +ctest ``` diff --git a/fixtures/test-int.ini b/fixtures/test-int.ini new file mode 100644 index 0000000..8932bc7 --- /dev/null +++ b/fixtures/test-int.ini @@ -0,0 +1,29 @@ +[Int] +Int8_0=0 +Int8_1=127 +Int8_2=-128 +Int8_3=128 +Int8_4=-129 + +Int16_0=0 +Int16_1=32767 +Int16_2=-32768 +Int16_3=32768 +Int16_4=-32769 + +Int32_0=0 +Int32_1=2147483647 +Int32_2=-2147483648 +Int32_3=2147483648 +Int32_4=-2147483649 + +[Uint] +Uint8_0=0 +Uint8_1=255 +Uint8_2=-1 +Uint8_3=256 + +Uint16_0=0 +Uint16_1=65535 +Uint16_2=-1 +Uint16_3=65536 diff --git a/ini-config.c b/ini-config.c deleted file mode 100644 index cc85f81..0000000 --- a/ini-config.c +++ /dev/null @@ -1,23 +0,0 @@ -#include "ini-config.h" - -const char* INI_ConfigGetCommandlineOption(uint8_t argc, const char* argv[], const char* val) { - size_t n = strlen(val); - int c = argc; - - while (--c > 0) { - if (!strncmp(argv[c], val, n)) { - if (!*(argv[c] + n) && c < argc - 1) { - /* coverity treats unchecked argv as "tainted" */ - if (!argv[c + 1] || strlen(argv[c + 1]) > 1024) - return NULL; - return argv[c + 1]; - } - - if (argv[c][n] == '=') - return &argv[c][n + 1]; - return argv[c] + n; - } - } - - return NULL; -} diff --git a/source/ini-config.c b/source/ini-config.c new file mode 100644 index 0000000..7558eb4 --- /dev/null +++ b/source/ini-config.c @@ -0,0 +1,73 @@ +#include "ini-config.h" + +const char* INI_ConfigGetCommandlineOption(uint8_t argc, const char* argv[], const char* val) { + size_t n = strlen(val); + int c = argc; + + while (--c > 0) { + if (!strncmp(argv[c], val, n)) { + if (!*(argv[c] + n) && c < argc - 1) { + /* coverity treats unchecked argv as "tainted" */ + if (!argv[c + 1] || strlen(argv[c + 1]) > 1024) + return NULL; + return argv[c + 1]; + } + + if (argv[c][n] == '=') + return &argv[c][n + 1]; + return argv[c] + n; + } + } + + return NULL; +} + +void INI_ConfigLoad(INI_ConfigItem item[], const char* config_path) { + uint8_t i; + for (i = 0; item[i].type.size > 0; i += 1) { + if (!item[i].type.load) { + continue; + } + item[i].type.load(&item[i], config_path); + } +} + +INI_ConfigSaveResult INI_ConfigSave(INI_ConfigItem item[], const char* config_path) { + uint8_t i; + int32_t problems = 0; + for (i = 0; item[i].type.size > 0; i += 1) { + int32_t result = item[i].type.save ? item[i].type.save(&item[i], config_path) : 0; + + if (result < 0) { + problems |= (1 << (int32_t) i); + } + } + + return -problems; +} + +void INI_ConfigOverride(INI_ConfigItem item[], uint8_t argc, const char* argv[]) { + uint8_t i; + for (i = 0; item[i].type.size > 0; i += 1) { + if (!item[i].type.override) { + continue; + } + + item[i].type.override(&item[i], argc, argv); + // TODO specify command-line arg external from config item? + + } +} + +INI_ConfigInitializeResult INI_ConfigInitialize(INI_ConfigItem item[], const char* config_path, uint8_t argc, const char* argv[]) { + INI_ConfigLoad(item, config_path); + INI_ConfigSaveResult save_result = INI_ConfigSave(item, config_path); + if (save_result < 0) { + return INI_CONFIG_INITIALIZE_RESULT_ERROR; + } + INI_ConfigOverride(item, argc, argv); + if (save_result > 0) { + return INI_CONFIG_INITIALIZE_RESULT_WARNING; + } + return INI_CONFIG_INITIALIZE_RESULT_OK; +} diff --git a/ini-config.h b/source/ini-config.h similarity index 80% rename from ini-config.h rename to source/ini-config.h index a852246..aae3e73 100644 --- a/ini-config.h +++ b/source/ini-config.h @@ -5,7 +5,6 @@ #include #include #include -#include #ifdef __cplusplus extern "C" { @@ -18,11 +17,11 @@ typedef struct { /** * Function that formats the value from memory to a value that is write-friendly to the config file. */ - void *serialize; + void* serialize; /** * Function that formats the value from file to a value that is read-friendly to memory. */ - void *deserialize; + void* deserialize; } INI_ConfigTransformer; // TODO: should we unify this with INI_ConfigType? struct INI_ConfigItem; @@ -30,7 +29,7 @@ struct INI_ConfigItem; /** * Function for loading a config item value from file to memory. */ -typedef void INI_ConfigTypeLoad(struct INI_ConfigItem *, const char *); +typedef void INI_ConfigTypeLoad(struct INI_ConfigItem*, const char*); /** * Result enum for saving config items. @@ -50,12 +49,12 @@ typedef enum { /** * Function for saving a config item value from memory to file. */ -typedef INI_ConfigSaveItemResult INI_ConfigTypeSave(struct INI_ConfigItem *, const char *); +typedef INI_ConfigSaveItemResult INI_ConfigTypeSave(struct INI_ConfigItem*, const char*); /** * Function for retrieving a config item value from the command-line to memory. */ -typedef void INI_ConfigTypeOverride(struct INI_ConfigItem *, uint8_t, const char *[]); +typedef void INI_ConfigTypeOverride(struct INI_ConfigItem*, uint8_t, const char* []); /** * Struct for the config item type. @@ -69,17 +68,17 @@ typedef struct { * Load function. * @see INI_ConfigTypeLoad */ - INI_ConfigTypeLoad *load; + INI_ConfigTypeLoad* load; /** * Save function. * @see INI_ConfigTypeSave */ - INI_ConfigTypeSave *save; + INI_ConfigTypeSave* save; /** * Override function. * @see INI_ConfigTypeOverride */ - INI_ConfigTypeOverride *override; + INI_ConfigTypeOverride* override; } INI_ConfigType; /** @@ -93,23 +92,23 @@ typedef struct INI_ConfigItem { /** * Section where this config item can be found. */ - const char *section; + const char* section; /** * Key where this config item value is serialized and stored. */ - const char *key; + const char* key; /** * Command-line option for overriding this config item's value. */ - const char *cmdline_option; // TODO: should we extract commandline parsing logic? + const char* cmdline_option; // TODO: should we extract commandline parsing logic? /** * Default value of the config item, when the value could not be read from the config file. */ - const void *default_value; + const void* default_value; /** * Validator function for the config item's value. */ - void *validator; + void* validator; /** * Transformer functions. * @see INI_ConfigTransformer @@ -119,14 +118,14 @@ typedef struct INI_ConfigItem { * The memory address where the config item value will reside. This property should allow storing the amount of butes * specified under `type.size`. */ - void *dest; + void* dest; } INI_ConfigItem; /** * Retrieves the value from a command-line option. * @return The string value from the command-line option. */ -const char *INI_ConfigGetCommandlineOption(uint8_t, const char *[], const char *); +const char* INI_ConfigGetCommandlineOption(uint8_t, const char*[], const char*); /** * Result enum for initializing config items. @@ -146,11 +145,19 @@ typedef enum { INI_CONFIG_INITIALIZE_RESULT_WARNING } INI_ConfigInitializeResult; -INI_ConfigInitializeResult INI_ConfigInitialize(INI_ConfigItem[], const char *, uint8_t, const char *[]); +/** + * Syncs the config file to memory. This includes the loading of the items from the config file. + * @return Result of the initialization. + */ +INI_ConfigInitializeResult INI_ConfigInitialize(INI_ConfigItem[], const char*, uint8_t, const char*[]); typedef int32_t INI_ConfigSaveResult; -INI_ConfigSaveResult INI_ConfigSave(INI_ConfigItem[], const char *); +/** + * Saves the contents of the memory to the config file. + * @return + */ +INI_ConfigSaveResult INI_ConfigSave(INI_ConfigItem[], const char*); #ifdef __cplusplus }; @@ -161,11 +168,17 @@ INI_ConfigTypeLoad INI_ConfigLoad##ID; \ INI_ConfigTypeSave INI_ConfigSave##ID; \ INI_ConfigTypeOverride INI_ConfigOverride##ID +/** + * Null transformer. + */ #define INI_CONFIG_TRANSFORMER_NONE (INI_ConfigTransformer) { \ .serialize = NULL, \ .deserialize = NULL, \ } +/** + * Null item. Use this to signify the end of the config item list. + */ #define INI_CONFIG_ITEM_NULL (INI_ConfigItem) { \ (INI_ConfigType) { \ .size = 0, \ diff --git a/types/int.c b/source/types/int.c similarity index 100% rename from types/int.c rename to source/types/int.c diff --git a/types/int.h b/source/types/int.h similarity index 98% rename from types/int.h rename to source/types/int.h index 05eea65..01bbb06 100644 --- a/types/int.h +++ b/source/types/int.h @@ -1,6 +1,7 @@ #ifndef INI_CONFIG_TYPES_INT_H #define INI_CONFIG_TYPES_INT_H +#include #include "../ini-config.h" INI_CONFIG_DECLARE_TYPE(U8); diff --git a/types/string.c b/source/types/string.c similarity index 52% rename from types/string.c rename to source/types/string.c index 31166b4..36a36c8 100644 --- a/types/string.c +++ b/source/types/string.c @@ -1,6 +1,5 @@ #include "string.h" - typedef bool INI_ConfigLoadParamsStringValidator(const char*); void INI_ConfigEnsureValidString(INI_ConfigItem* item, const char* buffer) { @@ -47,53 +46,3 @@ void INI_ConfigOverrideString(INI_ConfigItem* item, uint8_t argc, const char* ar INI_ConfigEnsureValidString(item, cmdline_buffer); } } - -void INI_ConfigLoad(INI_ConfigItem item[], const char* config_path) { - uint8_t i; - for (i = 0; item[i].type.size > 0; i += 1) { - if (!item[i].type.load) { - continue; - } - item[i].type.load(&item[i], config_path); - } -} - -INI_ConfigSaveResult INI_ConfigSave(INI_ConfigItem item[], const char* config_path) { - uint8_t i; - int32_t problems = 0; - for (i = 0; item[i].type.size > 0; i += 1) { - int32_t result = item[i].type.save ? item[i].type.save(&item[i], config_path) : 0; - - if (result < 0) { - problems |= (1 << (int32_t) i); - } - } - - return -problems; -} - -void INI_ConfigOverride(INI_ConfigItem item[], uint8_t argc, const char* argv[]) { - uint8_t i; - for (i = 0; item[i].type.size > 0; i += 1) { - if (!item[i].type.override) { - continue; - } - - item[i].type.override(&item[i], argc, argv); - // TODO specify command-line arg external from config item? - - } -} - -INI_ConfigInitializeResult INI_ConfigInitialize(INI_ConfigItem item[], const char* config_path, uint8_t argc, const char* argv[]) { - INI_ConfigLoad(item, config_path); - INI_ConfigSaveResult save_result = INI_ConfigSave(item, config_path); - if (save_result < 0) { - return INI_CONFIG_INITIALIZE_RESULT_ERROR; - } - INI_ConfigOverride(item, argc, argv); - if (save_result > 0) { - return INI_CONFIG_INITIALIZE_RESULT_WARNING; - } - return INI_CONFIG_INITIALIZE_RESULT_OK; -} diff --git a/types/string.h b/source/types/string.h similarity index 94% rename from types/string.h rename to source/types/string.h index 7147317..8a9a2c9 100644 --- a/types/string.h +++ b/source/types/string.h @@ -1,6 +1,7 @@ #ifndef INI_CONFIG_TYPES_STRING_H #define INI_CONFIG_TYPES_STRING_H +#include #include "../ini-config.h" INI_CONFIG_DECLARE_TYPE(String); diff --git a/tests/test-int.c b/tests/test-int.c new file mode 100644 index 0000000..4d7f4b9 --- /dev/null +++ b/tests/test-int.c @@ -0,0 +1,77 @@ +#include +#include +#include +#include "../source/ini-config.h" +#include "../source/types/int.h" + +static int8_t default_int8_value = 0; + +static int8_t read_int8_values[] = { 0, 0, 0, 0, 0 }; +static int8_t expected_int8_values[] = { 0, 127, -128, -128, 127 }; + +static INI_ConfigItem items[] = { + { + .section = "Int", + .key = "Int8_0", + .type = INI_CONFIG_TYPE_I8, + .default_value = &default_int8_value, + .transformer = INI_CONFIG_TRANSFORMER_NONE, + .validator = NULL, + .cmdline_option = NULL, + .dest = &read_int8_values[0], + }, + { + .section = "Int", + .key = "Int8_1", + .type = INI_CONFIG_TYPE_I8, + .default_value = &default_int8_value, + .transformer = INI_CONFIG_TRANSFORMER_NONE, + .validator = NULL, + .cmdline_option = NULL, + .dest = &read_int8_values[1], + }, + { + .section = "Int", + .key = "Int8_2", + .type = INI_CONFIG_TYPE_I8, + .default_value = &default_int8_value, + .transformer = INI_CONFIG_TRANSFORMER_NONE, + .validator = NULL, + .cmdline_option = NULL, + .dest = &read_int8_values[2], + }, + { + .section = "Int", + .key = "Int8_3", + .type = INI_CONFIG_TYPE_I8, + .default_value = &default_int8_value, + .transformer = INI_CONFIG_TRANSFORMER_NONE, + .validator = NULL, + .cmdline_option = NULL, + .dest = &read_int8_values[3], + }, + { + .section = "Int", + .key = "Int8_4", + .type = INI_CONFIG_TYPE_I8, + .default_value = &default_int8_value, + .transformer = INI_CONFIG_TRANSFORMER_NONE, + .validator = NULL, + .cmdline_option = NULL, + .dest = &read_int8_values[4], + }, + INI_CONFIG_ITEM_NULL +}; + +int main() { + printf("Fixture file exists? "); + const char* argv[] = { }; + int argc = 0; + assert(INI_ConfigInitialize(items, "test-int.ini", argc, argv) == 0); + printf("Yes.\n"); + for (uint8_t i = 0; i < 5; i += 1) { + printf("read: %d, expected: %d\n", read_int8_values[i], expected_int8_values[i]); + assert(read_int8_values[i] == expected_int8_values[i]); + } + return 0; +}