Browse Source

Implement int test

Add tests for int config items.
master
TheoryOfNekomata 1 year ago
parent
commit
f3eb15d59c
12 changed files with 258 additions and 103 deletions
  1. +0
    -1
      .gitignore
  2. +36
    -9
      CMakeLists.txt
  3. +10
    -1
      README.md
  4. +29
    -0
      fixtures/test-int.ini
  5. +0
    -23
      ini-config.c
  6. +73
    -0
      source/ini-config.c
  7. +31
    -18
      source/ini-config.h
  8. +0
    -0
      source/types/int.c
  9. +1
    -0
      source/types/int.h
  10. +0
    -51
      source/types/string.c
  11. +1
    -0
      source/types/string.h
  12. +77
    -0
      tests/test-int.c

+ 0
- 1
.gitignore View File

@@ -1,3 +1,2 @@
.idea/
cmake-build-*/
build/

+ 36
- 9
CMakeLists.txt View File

@@ -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"
$<TARGET_FILE_DIR:test-int>
)

+ 10
- 1
README.md View File

@@ -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
```

+ 29
- 0
fixtures/test-int.ini View File

@@ -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

+ 0
- 23
ini-config.c View File

@@ -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;
}

+ 73
- 0
source/ini-config.c View File

@@ -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;
}

ini-config.h → source/ini-config.h View File

@@ -5,7 +5,6 @@
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include <minIni.h>

#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, \

types/int.c → source/types/int.c View File


types/int.h → source/types/int.h View File

@@ -1,6 +1,7 @@
#ifndef INI_CONFIG_TYPES_INT_H
#define INI_CONFIG_TYPES_INT_H

#include <minIni.h>
#include "../ini-config.h"

INI_CONFIG_DECLARE_TYPE(U8);

types/string.c → source/types/string.c View File

@@ -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;
}

types/string.h → source/types/string.h View File

@@ -1,6 +1,7 @@
#ifndef INI_CONFIG_TYPES_STRING_H
#define INI_CONFIG_TYPES_STRING_H

#include <minIni.h>
#include "../ini-config.h"

INI_CONFIG_DECLARE_TYPE(String);

+ 77
- 0
tests/test-int.c View File

@@ -0,0 +1,77 @@
#include <assert.h>
#include <stdio.h>
#include <stdint.h>
#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;
}

Loading…
Cancel
Save