feat: hectic C: debug string constructor init

This commit is contained in:
2025-04-11 10:33:20 +00:00
parent de08900297
commit 80eac39b90
10 changed files with 407 additions and 244 deletions

View File

@@ -40,7 +40,7 @@ ColorMode color_mode = COLOR_MODE_AUTO;
// Global logging variables // Global logging variables
LogLevel current_log_level = LOG_LEVEL_INFO; LogLevel current_log_level = LOG_LEVEL_INFO;
LogRule *log_rules = NULL; // Linked list of log rules LogRule *log_rules = NULL;
const char* color_mode_to_string(ColorMode mode) { const char* color_mode_to_string(ColorMode mode) {
switch (mode) { switch (mode) {
@@ -64,6 +64,8 @@ void set_output_color_mode(ColorMode mode) {
#define POSITION_INFO_DECLARATION const char *file, const char *func, int line #define POSITION_INFO_DECLARATION const char *file, const char *func, int line
#define POSITION_INFO file, func, line #define POSITION_INFO file, func, line
#define COLORING_DECLARATION POSITION_INFO_DECLARATION Arena *arena
// ------------ // ------------
// -- Logger -- // -- Logger --
@@ -127,7 +129,6 @@ void logger_level(LogLevel level) {
} }
void init_logger(void) { void init_logger(void) {
// Read log level or rules from environment
const char* env_level = getenv("LOG_LEVEL"); const char* env_level = getenv("LOG_LEVEL");
if (env_level) { if (env_level) {
@@ -194,9 +195,13 @@ char* raise_message(
} }
// ----------- // -----------
// -- arena -- // -- debug --
// ----------- // -----------
// ------------
// -- arena --
// ------------
Arena arena_init__(POSITION_INFO_DECLARATION, size_t size) { Arena arena_init__(POSITION_INFO_DECLARATION, size_t size) {
// Function entry logging // Function entry logging
raise_message(LOG_LEVEL_DEBUG, POSITION_INFO, raise_message(LOG_LEVEL_DEBUG, POSITION_INFO,
@@ -354,6 +359,9 @@ void arena_free__(POSITION_INFO_DECLARATION, Arena *arena) {
arena->capacity = 0; arena->capacity = 0;
} }
/*
* Duplicates a string and returns a pointer to the new string.
*/
char* arena_strdup__(POSITION_INFO_DECLARATION, Arena *arena, const char *s) { char* arena_strdup__(POSITION_INFO_DECLARATION, Arena *arena, const char *s) {
// Function entry logging // Function entry logging
raise_message(LOG_LEVEL_TRACE, POSITION_INFO, raise_message(LOG_LEVEL_TRACE, POSITION_INFO,
@@ -384,6 +392,26 @@ char* arena_strdup__(POSITION_INFO_DECLARATION, Arena *arena, const char *s) {
return result; return result;
} }
/*
* Duplicates a string and returns a pointer to the new string.
* The string is formatted using the provided format string and arguments.
*/
char* arena_strdup_fmt__(POSITION_INFO_DECLARATION, Arena *arena, const char *fmt, ...) {
va_list args;
va_start(args, fmt);
int len = vsnprintf(NULL, 0, fmt, args);
va_end(args);
if (len < 0) return NULL;
char *temp = arena_alloc__(POSITION_INFO, DISPOSABLE_ARENA, len + 1);
va_start(args, fmt);
vsnprintf(temp, len + 1, fmt, args);
va_end(args);
return arena_strdup__(POSITION_INFO, arena, temp);
}
char* arena_strncpy__(POSITION_INFO_DECLARATION, Arena *arena, const char *start, size_t len) { char* arena_strncpy__(POSITION_INFO_DECLARATION, Arena *arena, const char *start, size_t len) {
// Function entry logging // Function entry logging
raise_message(LOG_LEVEL_TRACE, POSITION_INFO, raise_message(LOG_LEVEL_TRACE, POSITION_INFO,
@@ -417,6 +445,9 @@ char* arena_strncpy__(POSITION_INFO_DECLARATION, Arena *arena, const char *start
return result; return result;
} }
/*
* Replaces a substring in a string with a new string.
*/
char* arena_repstr__(POSITION_INFO_DECLARATION, Arena *arena, char* arena_repstr__(POSITION_INFO_DECLARATION, Arena *arena,
const char *src, size_t start, size_t len, const char *rep) { const char *src, size_t start, size_t len, const char *rep) {
// Function entry logging // Function entry logging
@@ -1117,70 +1148,6 @@ Json *json_get_object_item__(POSITION_INFO_DECLARATION, const Json * const objec
return NULL; return NULL;
} }
// -----------
// -- slice --
// -----------
// Create a slice from an array with boundary check.
Slice slice_create__(POSITION_INFO_DECLARATION, size_t isize, void *array, size_t array_len, size_t start, size_t len) {
// Function entry logging
raise_message(LOG_LEVEL_TRACE, POSITION_INFO,
"SLICE: Creating slice (source: %p, array_length: %zu, start: %zu, length: %zu, item_size: %zu)",
array, array_len, start, len, isize);
// Boundary check
if (start + len > array_len) {
raise_message(LOG_LEVEL_WARN, POSITION_INFO,
"SLICE: Slice boundaries exceed array length (start: %zu, length: %zu, array_length: %zu)",
start, len, array_len);
return (Slice){NULL, 0, isize};
}
// Create valid slice
Slice result = (Slice){ (char *)array + start * isize, len, isize };
// Success logging
raise_message(LOG_LEVEL_TRACE, POSITION_INFO,
"SLICE: Slice created successfully (data: %p, length: %zu, item_size: %zu)",
result.data, result.len, result.isize);
return result;
}
// Return a subslice from an existing slice.
Slice slice_subslice__(POSITION_INFO_DECLARATION, Slice s, size_t start, size_t len) {
// Function entry logging
raise_message(LOG_LEVEL_TRACE, POSITION_INFO,
"SLICE: Creating subslice (source: %p, source_length: %zu, start: %zu, length: %zu)",
s.data, s.len, start, len);
// Boundary check
if (start + len > s.len) {
raise_message(LOG_LEVEL_WARN, POSITION_INFO,
"SLICE: Subslice boundaries exceed source slice length (start: %zu, length: %zu, source_length: %zu)",
start, len, s.len);
return (Slice){NULL, 0, s.isize};
}
// Create valid subslice
Slice result = (Slice){(char*)s.data + start * s.isize, len, s.isize};
// Success logging
raise_message(LOG_LEVEL_TRACE, POSITION_INFO,
"SLICE: Subslice created successfully (data: %p, length: %zu, item_size: %zu)",
result.data, result.len, result.isize);
return result;
}
int* arena_slice_copy__(POSITION_INFO_DECLARATION, Arena *arena, Slice s) {
raise_message(LOG_LEVEL_TRACE, POSITION_INFO, "arena_slice_copy(<optimized>, <optimized>)");
int *copy = (void*) arena_alloc__(POSITION_INFO, arena, s.len * sizeof(int));
if (copy)
memcpy(copy, s.data, s.len * s.isize);
return copy;
}
char* json_to_debug_str__(POSITION_INFO_DECLARATION, Arena *arena, Json json) { char* json_to_debug_str__(POSITION_INFO_DECLARATION, Arena *arena, Json json) {
raise_message(LOG_LEVEL_TRACE, POSITION_INFO, "json_to_debug_str(<optimized>, <optimized>)"); raise_message(LOG_LEVEL_TRACE, POSITION_INFO, "json_to_debug_str(<optimized>, <optimized>)");
@@ -1253,6 +1220,139 @@ char* json_to_debug_str__(POSITION_INFO_DECLARATION, Arena *arena, Json json) {
return result; return result;
} }
// -----------
// -- slice --
// -----------
// Create a slice from an array with boundary check.
Slice slice_create__(POSITION_INFO_DECLARATION, size_t isize, void *array, size_t array_len, size_t start, size_t len) {
// Function entry logging
raise_message(LOG_LEVEL_TRACE, POSITION_INFO,
"SLICE: Creating slice (source: %p, array_length: %zu, start: %zu, length: %zu, item_size: %zu)",
array, array_len, start, len, isize);
// Boundary check
if (start + len > array_len) {
raise_message(LOG_LEVEL_WARN, POSITION_INFO,
"SLICE: Slice boundaries exceed array length (start: %zu, length: %zu, array_length: %zu)",
start, len, array_len);
return (Slice){NULL, 0, isize};
}
// Create valid slice
Slice result = (Slice){ (char *)array + start * isize, len, isize };
// Success logging
raise_message(LOG_LEVEL_TRACE, POSITION_INFO,
"SLICE: Slice created successfully (data: %p, length: %zu, item_size: %zu)",
result.data, result.len, result.isize);
return result;
}
// Return a subslice from an existing slice.
Slice slice_subslice__(POSITION_INFO_DECLARATION, Slice s, size_t start, size_t len) {
// Function entry logging
raise_message(LOG_LEVEL_TRACE, POSITION_INFO,
"SLICE: Creating subslice (source: %p, source_length: %zu, start: %zu, length: %zu)",
s.data, s.len, start, len);
// Boundary check
if (start + len > s.len) {
raise_message(LOG_LEVEL_WARN, POSITION_INFO,
"SLICE: Subslice boundaries exceed source slice length (start: %zu, length: %zu, source_length: %zu)",
start, len, s.len);
return (Slice){NULL, 0, s.isize};
}
// Create valid subslice
Slice result = (Slice){(char*)s.data + start * s.isize, len, s.isize};
// Success logging
raise_message(LOG_LEVEL_TRACE, POSITION_INFO,
"SLICE: Subslice created successfully (data: %p, length: %zu, item_size: %zu)",
result.data, result.len, result.isize);
return result;
}
int* arena_slice_copy__(POSITION_INFO_DECLARATION, Arena *arena, Slice s) {
raise_message(LOG_LEVEL_TRACE, POSITION_INFO, "arena_slice_copy(<optimized>, <optimized>)");
int *copy = (void*) arena_alloc__(POSITION_INFO, arena, s.len * sizeof(int));
if (copy)
memcpy(copy, s.data, s.len * s.isize);
return copy;
}
char* slice_to_debug_str__(POSITION_INFO_DECLARATION, Arena *arena, Slice slice) {
// Create complete information about the Slice structure
char buffer_meta[128];
snprintf(buffer_meta, sizeof(buffer_meta), "Slice{addr=%p, data=%p, len=%zu, isize=%zu, content=",
(void*)&slice, slice.data, slice.len, slice.isize);
size_t meta_len = strlen(buffer_meta);
// For NULL data, output a simple message
if (!slice.data) {
char* result = arena_alloc(arena, meta_len + 6);
strcpy(result, buffer_meta);
strcat(result, "NULL}");
return result;
}
// Allocate buffer with space for quotes, metadata and null terminator
size_t buffer_size = meta_len + slice.len * 4 + 20; // Extra space for escaping and closing brace
char* buffer = arena_alloc(arena, buffer_size);
// Copy metadata
strcpy(buffer, buffer_meta);
char* pos = buffer + meta_len;
*pos++ = '"';
// Copy slice data with escaping
for (size_t i = 0; i < slice.len; i++) {
char c = ((char*)slice.data)[i];
if (c == '\0') {
*pos++ = '\\';
*pos++ = '0';
} else if (c == '\n') {
*pos++ = '\\';
*pos++ = 'n';
} else if (c == '\r') {
*pos++ = '\\';
*pos++ = 'r';
} else if (c == '\t') {
*pos++ = '\\';
*pos++ = 't';
} else if (c == '"') {
*pos++ = '\\';
*pos++ = '"';
} else if (c == '\\') {
*pos++ = '\\';
*pos++ = '\\';
} else if (c < 32 || c > 126) {
// Non-printable characters as hex
pos += sprintf(pos, "\\x%02x", (unsigned char)c);
} else {
*pos++ = c;
}
}
*pos++ = '"';
*pos++ = '}'; // Closing brace for the structure
*pos = '\0';
raise_message(LOG_LEVEL_TRACE, POSITION_INFO, "slice_to_debug_str: %s", buffer);
return buffer;
}
// ------------------
// -- logger rules --
// ------------------
// Clean up existing log rules // Clean up existing log rules
void free_log_rules() { void free_log_rules() {
LogRule *rule = log_rules; LogRule *rule = log_rules;
@@ -1536,71 +1636,6 @@ char* logger_rules_to_string(Arena *arena) {
return buffer; return buffer;
} }
char* slice_to_debug_str__(POSITION_INFO_DECLARATION, Arena *arena, Slice slice) {
// Create complete information about the Slice structure
char buffer_meta[128];
snprintf(buffer_meta, sizeof(buffer_meta), "Slice{addr=%p, data=%p, len=%zu, isize=%zu, content=",
(void*)&slice, slice.data, slice.len, slice.isize);
size_t meta_len = strlen(buffer_meta);
// For NULL data, output a simple message
if (!slice.data) {
char* result = arena_alloc(arena, meta_len + 6);
strcpy(result, buffer_meta);
strcat(result, "NULL}");
return result;
}
// Allocate buffer with space for quotes, metadata and null terminator
size_t buffer_size = meta_len + slice.len * 4 + 20; // Extra space for escaping and closing brace
char* buffer = arena_alloc(arena, buffer_size);
// Copy metadata
strcpy(buffer, buffer_meta);
char* pos = buffer + meta_len;
*pos++ = '"';
// Copy slice data with escaping
for (size_t i = 0; i < slice.len; i++) {
char c = ((char*)slice.data)[i];
if (c == '\0') {
*pos++ = '\\';
*pos++ = '0';
} else if (c == '\n') {
*pos++ = '\\';
*pos++ = 'n';
} else if (c == '\r') {
*pos++ = '\\';
*pos++ = 'r';
} else if (c == '\t') {
*pos++ = '\\';
*pos++ = 't';
} else if (c == '"') {
*pos++ = '\\';
*pos++ = '"';
} else if (c == '\\') {
*pos++ = '\\';
*pos++ = '\\';
} else if (c < 32 || c > 126) {
// Non-printable characters as hex
pos += sprintf(pos, "\\x%02x", (unsigned char)c);
} else {
*pos++ = c;
}
}
*pos++ = '"';
*pos++ = '}'; // Closing brace for the structure
*pos = '\0';
raise_message(LOG_LEVEL_TRACE, POSITION_INFO, "slice_to_debug_str: %s", buffer);
return buffer;
}
// --------------- // ---------------
// -- Templater -- // -- Templater --
// --------------- // ---------------

View File

@@ -285,6 +285,7 @@ void arena_reset__(const char *file, const char *func, int line, Arena *arena);
void arena_free__(const char *file, const char *func, int line, Arena *arena); void arena_free__(const char *file, const char *func, int line, Arena *arena);
char* arena_strdup__(const char *file, const char *func, int line, Arena *arena, const char *s); char* arena_strdup__(const char *file, const char *func, int line, Arena *arena, const char *s);
char* arena_strdup_fmt__(const char *file, const char *func, int line, Arena *arena, const char *fmt, ...);
char* arena_repstr__(const char *file, const char *func, int line, Arena *arena, char* arena_repstr__(const char *file, const char *func, int line, Arena *arena,
const char *src, size_t start, size_t len, const char *rep); const char *src, size_t start, size_t len, const char *rep);
@@ -314,6 +315,9 @@ char* arena_strncpy__(const char *file, const char *func, int line, Arena *arena
#define arena_strdup(arena, s) \ #define arena_strdup(arena, s) \
arena_strdup__(__FILE__, __func__, __LINE__, arena, s) arena_strdup__(__FILE__, __func__, __LINE__, arena, s)
#define arena_strdup_fmt(arena, ...) \
arena_strdup_fmt__(__FILE__, __func__, __LINE__, arena, ##__VA_ARGS__)
#define arena_repstr(arena, src, start, len, rep) \ #define arena_repstr(arena, src, start, len, rep) \
arena_repstr__(__FILE__, __func__, __LINE__, arena, src, start, len, rep) arena_repstr__(__FILE__, __func__, __LINE__, arena, src, start, len, rep)

View File

@@ -1,5 +1,5 @@
#!/bin/sh #!/bin/sh
# Usage: make.sh [build|check] [--norun] [--debug] [--color] # Usage: make.sh [build|check[test1 test2 ...]] [--norun] [--debug] [--color]
# Options: # Options:
# build Build the library and app (default if no mode is provided). # build Build the library and app (default if no mode is provided).
# watch Build the library and app and watch for changes. # watch Build the library and app and watch for changes.
@@ -8,6 +8,7 @@
# --debug Build with -O0 (debug mode). # --debug Build with -O0 (debug mode).
# --color Pass -fdiagnostics-color=always to compiler. # --color Pass -fdiagnostics-color=always to compiler.
# help, --help Show this help message. # help, --help Show this help message.
# test1 test2 (check only) Run specific tests by name (without .c extension)
check_dependencies() { check_dependencies() {
for dep in cc ar; do for dep in cc ar; do
@@ -29,13 +30,14 @@ check_dependencies
print_help() { print_help() {
cat <<EOF cat <<EOF
Usage: $0 [build|check] [--norun] [--debug] [--color] Usage: $0 [build|check[test1 test2 ...]] [--norun] [--debug] [--color]
build Build the library and app (default). build Build the library and app (default).
watch Build the library and app and watch for changes. watch Build the library and app and watch for changes.
check Build tests; runs them unless --norun is specified. check Build tests; runs them unless --norun is specified.
--norun (check only) Build tests but do not run them. --norun (check only) Build tests but do not run them.
--debug Build with debug flags (-O0). --debug Build with debug flags (-O0).
--color Force colored compiler diagnostics. --color Force colored compiler diagnostics.
test1 test2 (check only) Run specific tests by name (without .c extension)
help, --help Display this help message. help, --help Display this help message.
EOF EOF
} }
@@ -51,15 +53,12 @@ esac
# Default flags # Default flags
RUN_TESTS=1 RUN_TESTS=1
OPTFLAGS="-O2" OPTFLAGS="-O2"
CFLAGS="-Wall -Wextra -Werror -pedantic -fsanitize=address " CFLAGS="-Wall -Wextra -Werror -pedantic -fsanitize=address -fanalyzer"
LDFLAGS="-lhectic" LDFLAGS="-lhectic"
STD_FLAGS="-std=c99" STD_FLAGS="-std=c99"
COLOR_FLAG="" COLOR_FLAG=""
DEBUG=0 DEBUG=0
MODE="${1:-build}"
shift
# Process options # Process options
while [ $# -gt 0 ]; do while [ $# -gt 0 ]; do
case "$1" in case "$1" in
@@ -76,17 +75,17 @@ while [ $# -gt 0 ]; do
;; ;;
--color) --color)
COLOR_FLAG="-fdiagnostics-color=always" COLOR_FLAG="-fdiagnostics-color=always"
;; ;;
*) *)
echo "Unknown option: $1" break
print_help
exit 1
;; ;;
esac esac
shift shift
done done
MODE="${1:-build}"
shift
if [ -n "$COLOR_FLAG" ]; then if [ -n "$COLOR_FLAG" ]; then
CFLAGS="$CFLAGS $COLOR_FLAG" CFLAGS="$CFLAGS $COLOR_FLAG"
fi fi
@@ -104,9 +103,36 @@ case "$MODE" in
;; ;;
check) check)
mkdir -p target/test mkdir -p target/test
export LOG_LEVEL=TRACE
# Get list of tests to run
TESTS_TO_RUN=()
while [ $# -gt 0 ]; do
case "$1" in
--norun|--debug|--color)
shift
;;
*)
TESTS_TO_RUN+=("$1")
shift
;;
esac
done
# If no specific tests provided, run all
if [ ${#TESTS_TO_RUN[@]} -eq 0 ]; then
TESTS_TO_RUN=("all")
fi
for test_file in test/*.c; do for test_file in test/*.c; do
exe="target/test/$(basename "${test_file%.c}")" test_name=$(basename "${test_file%.c}")
# Skip if specific tests are requested and this isn't one of them
if [ "${TESTS_TO_RUN[0]}" != "all" ] && ! [[ " ${TESTS_TO_RUN[*]} " =~ " ${test_name} " ]]; then
continue
fi
exe="target/test/$test_name"
echo "Building test: $test_name"
# shellcheck disable=SC2086 # shellcheck disable=SC2086
cc $CFLAGS $OPTFLAGS -I. "$test_file" -Ltarget -lhectic $LDFLAGS -o "$exe" cc $CFLAGS $OPTFLAGS -I. "$test_file" -Ltarget -lhectic $LDFLAGS -o "$exe"
if [ "$?" -ne 0 ]; then if [ "$?" -ne 0 ]; then
@@ -114,9 +140,9 @@ case "$MODE" in
fi fi
if [ "$RUN_TESTS" -eq 1 ]; then if [ "$RUN_TESTS" -eq 1 ]; then
if [ "$DEBUG" -eq 1 ]; then if [ "$DEBUG" -eq 1 ]; then
gdb -tui "$exe" env LOG_LEVEL="$LOG_LEVEL" gdb -tui "$exe"
fi fi
"$exe" env LOG_LEVEL="$LOG_LEVEL" "$exe"
fi fi
done done
;; ;;

View File

@@ -26,7 +26,7 @@
} while(0) } while(0)
int main(void) { int main(void) {
logger_level(LOG_LEVEL_DEBUG); printf("Running %s\n", __FILE__);
TEST_RAISE_GENERIC(raise_debug, LOG_LEVEL_DEBUG, "DEBUG"); TEST_RAISE_GENERIC(raise_debug, LOG_LEVEL_DEBUG, "DEBUG");
TEST_RAISE_GENERIC(raise_log, LOG_LEVEL_LOG, "LOG"); TEST_RAISE_GENERIC(raise_log, LOG_LEVEL_LOG, "LOG");

View File

@@ -0,0 +1,98 @@
#include "hectic.h"
typedef struct TestStruct TestStruct;
struct TestStruct {
int a;
int b;
char *c;
TestStruct *next;
};
typedef struct TestStruct2 TestStruct2;
struct TestStruct2 {
int a;
char *c;
float f;
TestStruct2 *left;
TestStruct *other;
};
typedef struct PtrSet {
void **data;
size_t size;
size_t capacity;
} PtrSet;
static bool debug_ptrset_contains(PtrSet *set, void *ptr) {
for (size_t i = 0; i < set->size; i++) {
if (set->data[i] == ptr)
return true;
}
return false;
}
static void debug_ptrset_add(PtrSet *set, void *ptr) {
if (set->size == set->capacity) {
set->capacity = set->capacity ? set->capacity * 2 : 4;
set->data = realloc(set->data, set->capacity * sizeof(void*));
}
set->data[set->size++] = ptr;
}
#define STRING_TO_DEBUG_STR(arena, name, string) \
arena_strdup_fmt__(__FILE__, __func__, __LINE__, arena, "%s = %p \"%s\"", name, string, string)
#define NUMBER_TO_DEBUG_STR(arena, name, number) \
arena_strdup_fmt__(__FILE__, __func__, __LINE__, arena, "%s = %d", name, number)
#define STRUCT_TO_DEBUG_STR(arena, type, name, ptr, ...) __extension__ ({ \
char *result; \
if ((ptr) == NULL) { \
result = arena_strdup_fmt__(__FILE__, __func__, __LINE__, arena, "%s %s = NULL", #type, name); \
} else { \
char* fields = arena_strdup_fmt__(__FILE__, __func__, __LINE__, arena, "%s, %s, %s", __VA_ARGS__); \
result = arena_strdup_fmt__(__FILE__, __func__, __LINE__, arena, "%s %s = {%s} %p", #type, name, fields, ptr); \
} \
result; \
})
#define test_struct_to_debug_str(arena, name, self) test_struct_to_debug_str__(arena, name, self)
char *test_struct_to_debug_str__(Arena *arena, char *name, TestStruct *self) {
if (name == NULL) {
name = "$1";
}
char *result = STRUCT_TO_DEBUG_STR(arena, TestStruct, name, self,
NUMBER_TO_DEBUG_STR(arena, "a", self->a),
NUMBER_TO_DEBUG_STR(arena, "b", self->b),
test_struct_to_debug_str__(arena, "next", self->next)
);
return result;
}
//char *test_struct_to_debug_str__(Arena *arena, char *name, char *type, TestStruct *self) {
// char *result = arena_strdup_fmt(arena, "%s %s{", name, type);
//
// result = arena_strdup_fmt(arena, "%s%s", result, NUMBER_TO_DEBUG_STR(arena, "a", self->a));
// result = arena_strdup_fmt(arena, "%s%s", result, NUMBER_TO_DEBUG_STR(arena, "b", self->b));
// result = arena_strdup_fmt(arena, "%s%s", result, test_struct_to_debug_str__(arena, "next", TestStruct, self->next));
//
// result = arena_strdup_fmt(arena, "%s} (%p)", result, self);
// return result;
//}
int main(void) {
printf("%sRunning %s%s%s\n", OPTIONAL_COLOR(COLOR_GREEN), OPTIONAL_COLOR(COLOR_CYAN), __FILE__, OPTIONAL_COLOR(COLOR_RESET));
init_logger();
TestStruct test_struct = {.a = 1, .b = 2, .next = NULL};
raise_notice("%s", test_struct_to_debug_str(DISPOSABLE_ARENA, "test_struct", &test_struct));
printf("%sAll tests passed %s%s%s\n", OPTIONAL_COLOR(COLOR_GREEN), OPTIONAL_COLOR(COLOR_CYAN), __FILE__, OPTIONAL_COLOR(COLOR_RESET));
return 0;
}

View File

@@ -91,7 +91,7 @@ void test_arena_overwrite_detection() {
} }
int main() { int main() {
logger_level(LOG_LEVEL_DEBUG); init_logger();
test_arena_init(); test_arena_init();
test_arena_alloc(); test_arena_alloc();

View File

@@ -124,7 +124,7 @@ static void test_arena_reset_reuse(void) {
} }
int main(void) { int main(void) {
logger_level(LOG_LEVEL_DEBUG); init_logger();
test_parse_json_object(); test_parse_json_object();
test_parse_json_number(); test_parse_json_number();

View File

@@ -1,92 +0,0 @@
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "hectic.h"
#define ARENA_SIZE 1024 * 1024
static char *remove_all_spaces(char *s) {
char *new_s = NULL;
while (*s) {
if (*s != ' ' && *s != '\t' && *s != '\n') {
new_s = s;
}
s++;
}
return new_s;
}
static void test_template_node_to_debug_str(Arena *arena) {
TemplateNode *root = arena_alloc(arena, sizeof(TemplateNode));
root->type = TEMPLATE_NODE_TEXT;
root->value.text.content = arena_strncpy(arena, "Hello", 5);
root->next = arena_alloc(arena, sizeof(TemplateNode));
root->next->type = TEMPLATE_NODE_INTERPOLATE;
root->next->value.interpolate.key = arena_strncpy(arena, "name", 4);
root->next->next = arena_alloc(arena, sizeof(TemplateNode));
root->next->next->type = TEMPLATE_NODE_TEXT;
root->next->next->value.text.content = arena_strncpy(arena, "!", 1);
char *debug_str = template_node_to_debug_str(arena, root);
raise_notice("debug_str: %s", debug_str);
assert(strcmp(
remove_all_spaces(debug_str),
remove_all_spaces("" \
"[" \
" {" \
" \"type\":\"TEXT\"," \
" \"content\":{" \
" \"content\":\"Hello\"" \
" }" \
" }," \
" {" \
" \"type\":\"INTERPOLATE\"," \
" \"content\":{" \
" \"key\":\"name\"" \
" }" \
" }," \
" {" \
" \"type\":\"TEXT\"," \
" \"content\":{" \
" \"content\":\"!\"" \
" }" \
" }" \
"]")) == 0);
}
static void test_template_parse(Arena *arena, TemplateConfig *config) {
const char *template = "Hello {% name %}!";
TemplateResult *result = template_parse(arena, &template, config);
Arena *debug_arena = DISPOSABLE_ARENA;
const char *debug_str = template_node_to_debug_str(debug_arena, &result->Result.node);
raise_notice("debug_str: %s", debug_str);
raise_notice("result: %s", json_to_pretty_str(debug_arena, json_parse(debug_arena, &debug_str)));
assert(result->type == TEMPLATE_RESULT_NODE);
}
int main(void) {
init_logger();
Arena arena = arena_init(ARENA_SIZE);
TemplateConfig config = template_default_config();
printf("%sRunning template parser tests...%s\n", OPTIONAL_COLOR(COLOR_GREEN), OPTIONAL_COLOR(COLOR_RESET));
test_template_node_to_debug_str(&arena);
printf("%sTest 0: template_node_to_debug_str passed%s\n", OPTIONAL_COLOR(COLOR_GREEN), OPTIONAL_COLOR(COLOR_RESET));
arena_reset(&arena);
test_template_parse(&arena, &config);
printf("%sTest 1: template_parse passed%s\n", OPTIONAL_COLOR(COLOR_GREEN), OPTIONAL_COLOR(COLOR_RESET));
arena_reset(&arena);
arena_free(&arena);
printf("%s%s all tests passed.%s\n", OPTIONAL_COLOR(COLOR_GREEN), __FILE__, OPTIONAL_COLOR(COLOR_RESET));
return 0;
}

View File

@@ -83,7 +83,7 @@ void test_slice_string() {
} }
int main() { int main() {
logger_level(LOG_LEVEL_DEBUG); init_logger();
test_slice_create(); test_slice_create();
test_slice_subslice(); test_slice_subslice();

View File

@@ -0,0 +1,92 @@
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "hectic.h"
#define ARENA_SIZE 1024 * 1024
//static char *remove_all_spaces(char *s) {
// char *new_s = NULL;
// while (*s) {
// if (*s != ' ' && *s != '\t' && *s != '\n') {
// new_s = s;
// }
// s++;
// }
// return new_s;
//}
static void test_template_node_to_debug_str(Arena *arena) {
TemplateNode *root = arena_alloc(arena, sizeof(TemplateNode));
root->type = TEMPLATE_NODE_TEXT;
root->value.text.content = arena_strncpy(arena, "Hello", 5);
root->next = arena_alloc(arena, sizeof(TemplateNode));
root->next->type = TEMPLATE_NODE_INTERPOLATE;
root->next->value.interpolate.key = arena_strncpy(arena, "name", 4);
root->next->next = arena_alloc(arena, sizeof(TemplateNode));
root->next->next->type = TEMPLATE_NODE_TEXT;
root->next->next->value.text.content = arena_strncpy(arena, "!", 1);
char *debug_str = template_node_to_debug_str(arena, root);
raise_notice("debug_str: %s", debug_str);
//assert(strcmp(
// remove_all_spaces(debug_str),
// remove_all_spaces(""
// "["
// " {"
// " \"type\":\"TEXT\","
// " \"content\":{"
// " \"content\":\"Hello\""
// " }"
// " },"
// " {"
// " \"type\":\"INTERPOLATE\","
// " \"content\":{"
// " \"key\":\"name\""
// " }"
// " },"
// " {"
// " \"type\":\"TEXT\","
// " \"content\":{"
// " \"content\":\"!\""
// " }"
// " }"
// "]")) == 0);
}
//static void test_template_parse(Arena *arena, TemplateConfig *config) {
// const char *template = "Hello {% name %}!";
// TemplateResult *result = template_parse(arena, &template, config);
//
// Arena *debug_arena = DISPOSABLE_ARENA;
// const char *debug_str = template_node_to_debug_str(debug_arena, &result->Result.node);
// raise_notice("debug_str: %s", debug_str);
// raise_notice("result: %s", json_to_pretty_str(debug_arena, json_parse(debug_arena, &debug_str)));
// assert(result->type == TEMPLATE_RESULT_NODE);
//}
int main(void) {
init_logger();
Arena arena = arena_init(ARENA_SIZE);
//TemplateConfig config = template_default_config();
printf("%sRunning template parser tests...%s\n", OPTIONAL_COLOR(COLOR_GREEN), OPTIONAL_COLOR(COLOR_RESET));
test_template_node_to_debug_str(&arena);
printf("%sTest 0: template_node_to_debug_str passed%s\n", OPTIONAL_COLOR(COLOR_GREEN), OPTIONAL_COLOR(COLOR_RESET));
arena_reset(&arena);
//test_template_parse(&arena, &config);
//printf("%sTest 1: template_parse passed%s\n", OPTIONAL_COLOR(COLOR_GREEN), OPTIONAL_COLOR(COLOR_RESET));
//arena_reset(&arena);
arena_free(&arena);
printf("%s%s all tests passed.%s\n", OPTIONAL_COLOR(COLOR_GREEN), __FILE__, OPTIONAL_COLOR(COLOR_RESET));
return 0;
}