feat: hectic C: debug to json parser

This commit is contained in:
2025-04-14 19:43:57 +00:00
parent 1dcb165abf
commit d45307336a
4 changed files with 319 additions and 60 deletions

View File

@@ -325,7 +325,7 @@ char *string_to_debug_str__(CTX_DECLARATION, const char *name, const char *strin
// Check if the pointer is readable. // Check if the pointer is readable.
if (!is_readable(string)) if (!is_readable(string))
return arena_strdup_fmt__(CTX(arena), "%s = unreadable", name); return arena_strdup_fmt__(CTX(arena), "%s = <memory unreadable>", name);
return arena_strdup_fmt__(CTX(arena), "%s = %s%p%s \"%s\"", return arena_strdup_fmt__(CTX(arena), "%s = %s%p%s \"%s\"",
name, DEBUG_COLOR(COLOR_CYAN), string, name, DEBUG_COLOR(COLOR_CYAN), string,
@@ -385,14 +385,14 @@ char *union_to_debug_str__(POSITION_INFO_DECLARATION, Arena *arena, const char *
if (!variant_exists) { if (!variant_exists) {
return arena_strdup_fmt__(file, func, line, arena, return arena_strdup_fmt__(file, func, line, arena,
"%sunion%s %s %s = {invalid variant %d} %s%p%s", "%sunion%s %s %s = <invalid variant %d> %s%p%s",
DEBUG_COLOR(COLOR_GREEN), DEBUG_COLOR(COLOR_RESET), DEBUG_COLOR(COLOR_GREEN), DEBUG_COLOR(COLOR_RESET),
type, name, active_variant, DEBUG_COLOR(COLOR_CYAN), ptr, DEBUG_COLOR(COLOR_RESET)); type, name, active_variant, DEBUG_COLOR(COLOR_CYAN), ptr, DEBUG_COLOR(COLOR_RESET));
} }
if (!value) { if (!value) {
return arena_strdup_fmt__(file, func, line, arena, return arena_strdup_fmt__(file, func, line, arena,
"%sunion%s %s %s = {unknown variant} %s%p%s", "%sunion%s %s %s = <unknown variant> %s%p%s",
DEBUG_COLOR(COLOR_GREEN), DEBUG_COLOR(COLOR_RESET), DEBUG_COLOR(COLOR_GREEN), DEBUG_COLOR(COLOR_RESET),
type, name, DEBUG_COLOR(COLOR_CYAN), ptr, DEBUG_COLOR(COLOR_RESET)); type, name, DEBUG_COLOR(COLOR_CYAN), ptr, DEBUG_COLOR(COLOR_RESET));
} }
@@ -1473,12 +1473,254 @@ char* json_to_debug_str__(POSITION_INFO_DECLARATION, Arena *arena, Json json) {
return result; return result;
} }
JsonResult debug_str_to_json__(POSITION_INFO_DECLARATION, Arena *arena, const char **s) {
raise_message(LOG_LEVEL_TRACE, POSITION_INFO, "DEBUG STR TO JSON: debug_str: %s", *s);
// Remove the unused 'start' variable
Json *json = arena_alloc__(POSITION_INFO, arena, sizeof(Json));
memset(json, 0, sizeof(Json));
// Extract the name/key
const char *equal_sign = strstr(*s, "=");
if (!equal_sign) {
raise_message(LOG_LEVEL_EXCEPTION, POSITION_INFO, "DEBUG STR TO JSON: no equal sign found");
return RESULT_ERROR(JsonResult, DEBUG_TO_JSON_PARSE_NO_EQUAL_SIGN_ERROR, "No equal sign found");
}
Slice full_name = slice_create__(POSITION_INFO, 1, *s, strlen(*s), 0, equal_sign - *s);
if (full_name.len == 0) {
raise_message(LOG_LEVEL_EXCEPTION, POSITION_INFO, "DEBUG STR TO JSON: no name found");
return RESULT_ERROR(JsonResult, DEBUG_TO_JSON_PARSE_LEFT_OPERAND_ERROR, "No left operand found");
}
// Move past the equal sign
*s = skip_whitespace(equal_sign + 1);
// Check for struct, union, enum, or other types
const char *name_str = full_name.data;
name_str = skip_whitespace(name_str);
if (strncmp(name_str, "struct ", 7) == 0) {
// Handle struct
json->type = JSON_OBJECT;
// Extract struct type and name
name_str += 7; // Skip "struct "
const char *space = strchr(name_str, ' ');
if (!space) {
raise_message(LOG_LEVEL_EXCEPTION, POSITION_INFO, "DEBUG STR TO JSON: missing struct name");
return RESULT_ERROR(JsonResult, DEBUG_TO_JSON_PARSE_NO_STRUCT_NAME_ERROR, "Struct without name");
}
// Extract type (between "struct " and space)
// Extract name (after space, before any other character)
name_str = skip_whitespace(space + 1);
const char *name_end = name_str;
while (*name_end && !isspace(*name_end) && *name_end != '{') name_end++;
if (name_end == name_str) {
raise_message(LOG_LEVEL_EXCEPTION, POSITION_INFO, "DEBUG STR TO JSON: missing struct variable name");
return RESULT_ERROR(JsonResult, DEBUG_TO_JSON_PARSE_NO_STRUCT_NAME_ERROR, "Struct without variable name");
}
size_t name_len = name_end - name_str;
json->key = arena_strncpy__(POSITION_INFO, arena, name_str, name_len);
// Find struct body
const char *body_start = strchr(name_end, '{');
if (!body_start) {
raise_message(LOG_LEVEL_EXCEPTION, POSITION_INFO, "DEBUG STR TO JSON: no start found for struct");
return RESULT_ERROR(JsonResult, DEBUG_TO_JSON_PARSE_NO_START_ERROR, "Struct without start");
}
const char *body_end = strrchr(body_start, '}');
if (!body_end) {
raise_message(LOG_LEVEL_EXCEPTION, POSITION_INFO, "DEBUG STR TO JSON: no end found for struct");
return RESULT_ERROR(JsonResult, DEBUG_TO_JSON_PARSE_NO_END_ERROR, "Struct without end");
}
// Move pointer past the struct
*s = body_end + 1;
// TODO: Parse struct fields
// For now, we're just creating an empty object
}
else if (strncmp(name_str, "union ", 6) == 0) {
// Handle union
json->type = JSON_OBJECT;
// Extract union name
name_str += 6; // Skip "union "
const char *space = strchr(name_str, ' ');
if (!space) {
raise_message(LOG_LEVEL_EXCEPTION, POSITION_INFO, "DEBUG STR TO JSON: missing union name");
return RESULT_ERROR(JsonResult, DEBUG_TO_JSON_PARSE_NO_STRUCT_NAME_ERROR, "Union without name");
}
// Extract type (between "union " and space)
// Extract name (after space, before any other character)
name_str = skip_whitespace(space + 1);
const char *name_end = name_str;
while (*name_end && !isspace(*name_end) && *name_end != '{') name_end++;
size_t name_len = name_end - name_str;
json->key = arena_strncpy__(POSITION_INFO, arena, name_str, name_len);
// Find body
const char *body_start = strchr(name_end, '{');
if (!body_start) {
raise_message(LOG_LEVEL_EXCEPTION, POSITION_INFO, "DEBUG STR TO JSON: no start found for union");
return RESULT_ERROR(JsonResult, DEBUG_TO_JSON_PARSE_NO_START_ERROR, "Union without start");
}
const char *body_end = strrchr(body_start, '}');
if (!body_end) {
raise_message(LOG_LEVEL_EXCEPTION, POSITION_INFO, "DEBUG STR TO JSON: no end found for union");
return RESULT_ERROR(JsonResult, DEBUG_TO_JSON_PARSE_NO_END_ERROR, "Union without end");
}
// Move pointer past the union
*s = body_end + 1;
// TODO: Parse union variant
// For now, we're just creating an empty object
}
else if (strncmp(name_str, "enum ", 5) == 0) {
// Handle enum
json->type = JSON_STRING;
// Find enum value (typically at the end)
const char *value_start = strrchr(*s, ' ');
if (!value_start) {
raise_message(LOG_LEVEL_EXCEPTION, POSITION_INFO, "DEBUG STR TO JSON: missing enum value");
return RESULT_ERROR(JsonResult, DEBUG_TO_JSON_PARSE_LEFT_OPERAND_ERROR, "Invalid enum format");
}
// Extract name
name_str += 5; // Skip "enum "
const char *space = strchr(name_str, ' ');
if (space) {
size_t name_len = space - name_str;
json->key = arena_strncpy__(POSITION_INFO, arena, name_str, name_len);
}
// Extract value as string
value_start = skip_whitespace(value_start + 1);
json->JsonValue.string = arena_strdup__(POSITION_INFO, arena, value_start);
// Move pointer to the end
*s += strlen(*s);
}
else if (strchr(name_str, '[') && strchr(name_str, ']')) {
// Handle array
json->type = JSON_ARRAY;
// Extract array name
const char *bracket = strchr(name_str, '[');
if (bracket > name_str) {
const char *name_end = bracket;
while (name_end > name_str && isspace(*(name_end-1))) name_end--;
size_t name_len = name_end - name_str;
json->key = arena_strncpy__(POSITION_INFO, arena, name_str, name_len);
}
// Find array body
const char *body_start = strchr(*s, '[');
if (!body_start) {
raise_message(LOG_LEVEL_EXCEPTION, POSITION_INFO, "DEBUG STR TO JSON: no start found for array");
return RESULT_ERROR(JsonResult, DEBUG_TO_JSON_PARSE_NO_START_ERROR, "Array without start");
}
const char *body_end = strrchr(body_start, ']');
if (!body_end) {
raise_message(LOG_LEVEL_EXCEPTION, POSITION_INFO, "DEBUG STR TO JSON: no end found for array");
return RESULT_ERROR(JsonResult, DEBUG_TO_JSON_PARSE_NO_END_ERROR, "Array without end");
}
// Move pointer past the array
*s = body_end + 1;
// TODO: Parse array elements
// For now, we're just creating an empty array
}
else {
// Try to determine value type (string, number, bool, null)
const char *value = *s;
if (strncmp(value, "NULL", 4) == 0 || strncmp(value, "null", 4) == 0) {
json->type = JSON_NULL;
*s += 4;
}
else if (strncmp(value, "true", 4) == 0) {
json->type = JSON_BOOL;
json->JsonValue.boolean = true;
*s += 4;
}
else if (strncmp(value, "false", 5) == 0) {
json->type = JSON_BOOL;
json->JsonValue.boolean = false;
*s += 5;
}
else if (*value == '"') {
// String value
json->type = JSON_STRING;
value++; // Skip opening quote
const char *end_quote = strchr(value, '"');
if (!end_quote) {
raise_message(LOG_LEVEL_EXCEPTION, POSITION_INFO, "DEBUG STR TO JSON: unterminated string");
return RESULT_ERROR(JsonResult, DEBUG_TO_JSON_PARSE_LEFT_OPERAND_ERROR, "Unterminated string");
}
size_t str_len = end_quote - value;
json->JsonValue.string = arena_strncpy__(POSITION_INFO, arena, value, str_len);
*s = end_quote + 1;
}
else if (isdigit(*value) || *value == '-' || *value == '+') {
// Numeric value
json->type = JSON_NUMBER;
// Use strtod to parse the number
char *end;
json->JsonValue.number = strtod(value, &end);
*s = end;
}
else {
// Default to string for unknown types
json->type = JSON_STRING;
// Find the end of the value (space, comma, etc.)
const char *end = value;
while (*end && !isspace(*end) && *end != ',' && *end != '}' && *end != ']') end++;
size_t str_len = end - value;
json->JsonValue.string = arena_strncpy__(POSITION_INFO, arena, value, str_len);
*s = end;
}
// Extract name for simple types
const char *name_end = name_str;
while (*name_end && !isspace(*name_end) && *name_end != '=') name_end++;
size_t name_len = name_end - name_str;
json->key = arena_strncpy__(POSITION_INFO, arena, name_str, name_len);
}
return RESULT_SOME(JsonResult, *json);
}
// ----------- // -----------
// -- slice -- // -- slice --
// ----------- // -----------
// Create a slice from an array with boundary check. // 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) { Slice slice_create__(POSITION_INFO_DECLARATION, size_t isize, const void *array, size_t array_len, size_t start, size_t len) {
// Function entry logging // Function entry logging
raise_message(LOG_LEVEL_TRACE, POSITION_INFO, raise_message(LOG_LEVEL_TRACE, POSITION_INFO,
"SLICE: Creating slice (source: %p, array_length: %zu, start: %zu, length: %zu, item_size: %zu)", "SLICE: Creating slice (source: %p, array_length: %zu, start: %zu, length: %zu, item_size: %zu)",

View File

@@ -85,6 +85,11 @@ typedef enum {
TEMPLATE_ERROR_OUT_OF_MEMORY = 985575, TEMPLATE_ERROR_OUT_OF_MEMORY = 985575,
LOGGER_ERROR_INVALID_RULES_STRING = 985576, LOGGER_ERROR_INVALID_RULES_STRING = 985576,
LOGGER_ERROR_OUT_OF_MEMORY = 985577, LOGGER_ERROR_OUT_OF_MEMORY = 985577,
DEBUG_TO_JSON_PARSE_NO_EQUAL_SIGN_ERROR = 985578,
DEBUG_TO_JSON_PARSE_NO_STRUCT_NAME_ERROR = 985579,
DEBUG_TO_JSON_PARSE_LEFT_OPERAND_ERROR = 985580,
DEBUG_TO_JSON_PARSE_NO_START_ERROR = 985581,
DEBUG_TO_JSON_PARSE_NO_END_ERROR = 985582,
} HecticErrorCode; } HecticErrorCode;
// Define color macros based on output type // Define color macros based on output type
@@ -464,7 +469,7 @@ bool debug_ptrset_contains(PtrSet *set, void *ptr);
name = "$1"; \ name = "$1"; \
\ \
if (debug_ptrset_contains__(visited, ptr, #type, name)) \ if (debug_ptrset_contains__(visited, ptr, #type, name)) \
return arena_strdup_fmt__(__FILE__, __func__, __LINE__, arena, "%sunion%s %s %s = {cycle detected} %s%p%s", DEBUG_COLOR(COLOR_GREEN), DEBUG_COLOR(COLOR_RESET), #type, name, DEBUG_COLOR(COLOR_CYAN), ptr, DEBUG_COLOR(COLOR_RESET)); \ return arena_strdup_fmt__(__FILE__, __func__, __LINE__, arena, "%sunion%s %s %s = <cycle detected> %s%p%s", DEBUG_COLOR(COLOR_GREEN), DEBUG_COLOR(COLOR_RESET), #type, name, DEBUG_COLOR(COLOR_CYAN), ptr, DEBUG_COLOR(COLOR_RESET)); \
\ \
if (!ptr) \ if (!ptr) \
return arena_strdup_fmt__(__FILE__, __func__, __LINE__, arena, "%sunion%s %s %s = NULL", DEBUG_COLOR(COLOR_GREEN), DEBUG_COLOR(COLOR_RESET), #type, name); \ return arena_strdup_fmt__(__FILE__, __func__, __LINE__, arena, "%sunion%s %s %s = NULL", DEBUG_COLOR(COLOR_GREEN), DEBUG_COLOR(COLOR_RESET), #type, name); \
@@ -504,7 +509,7 @@ bool debug_ptrset_contains(PtrSet *set, void *ptr);
name = "$1"; \ name = "$1"; \
\ \
if (debug_ptrset_contains__(visited, ptr, #type, name)) \ if (debug_ptrset_contains__(visited, ptr, #type, name)) \
return arena_strdup_fmt__(__FILE__, __func__, __LINE__, arena, "%sstruct%s %s %s = {cycle detected} %s%p%s", DEBUG_COLOR(COLOR_GREEN), DEBUG_COLOR(COLOR_RESET), #type, name, DEBUG_COLOR(COLOR_CYAN), ptr, DEBUG_COLOR(COLOR_RESET)); \ return arena_strdup_fmt__(__FILE__, __func__, __LINE__, arena, "%sstruct%s %s %s = <cycle detected> %s%p%s", DEBUG_COLOR(COLOR_GREEN), DEBUG_COLOR(COLOR_RESET), #type, name, DEBUG_COLOR(COLOR_CYAN), ptr, DEBUG_COLOR(COLOR_RESET)); \
\ \
if (!ptr) \ if (!ptr) \
return arena_strdup_fmt__(__FILE__, __func__, __LINE__, arena, "%sstruct%s %s %s = NULL", DEBUG_COLOR(COLOR_GREEN), DEBUG_COLOR(COLOR_RESET), #type, name); \ return arena_strdup_fmt__(__FILE__, __func__, __LINE__, arena, "%sstruct%s %s %s = NULL", DEBUG_COLOR(COLOR_GREEN), DEBUG_COLOR(COLOR_RESET), #type, name); \
@@ -588,6 +593,8 @@ typedef struct Json {
} JsonValue; } JsonValue;
} Json; } Json;
RESULT(Json, Json);
#define json_parse(arena, s) json_parse__(__FILE__, __func__, __LINE__, arena, s) #define json_parse(arena, s) json_parse__(__FILE__, __func__, __LINE__, arena, s)
Json *json_parse__(const char* file, const char* func, int line, Arena *arena, const char **s); Json *json_parse__(const char* file, const char* func, int line, Arena *arena, const char **s);
@@ -608,8 +615,12 @@ char* json_to_debug_str__(const char* file, const char* func, int line, Arena *a
char *json_to_pretty_str__(const char* file, const char* func, int line, Arena *arena, const Json * const item, int indent_level); char *json_to_pretty_str__(const char* file, const char* func, int line, Arena *arena, const Json * const item, int indent_level);
JsonResult debug_str_to_json__(const char* file, const char* func, int line, Arena *arena, const char **s);
#define json_to_pretty_str(arena, json) json_to_pretty_str__(__FILE__, __func__, __LINE__, arena, json, 0) #define json_to_pretty_str(arena, json) json_to_pretty_str__(__FILE__, __func__, __LINE__, arena, json, 0)
#define DEBUG_STR_TO_JSON(arena, debug_ptr) debug_str_to_json__(__FILE__, __func__, __LINE__, arena, debug_ptr)
// ----------- // -----------
// -- Slice -- // -- Slice --
// ----------- // -----------
@@ -625,7 +636,7 @@ typedef struct {
// printf("Content: %d\n", SLICE_ARGS(slice, int)); // printf("Content: %d\n", SLICE_ARGS(slice, int));
#define SLICE_ARGS(slice, type) ((int)((slice).len / sizeof(type))), ((type*)((slice).data)) #define SLICE_ARGS(slice, type) ((int)((slice).len / sizeof(type))), ((type*)((slice).data))
Slice slice_create__(const char *file, const char *func, int line, size_t isize, void *array, size_t array_len, size_t start, size_t len); Slice slice_create__(const char *file, const char *func, int line, size_t isize, const void *array, size_t array_len, size_t start, size_t len);
Slice slice_subslice__(const char *file, const char *func, int line, Slice s, size_t start, size_t len); Slice slice_subslice__(const char *file, const char *func, int line, Slice s, size_t start, size_t len);

View File

@@ -8,91 +8,76 @@
#define ARENA_SIZE 1024 * 1024 #define ARENA_SIZE 1024 * 1024
// Test 1: Parse JSON object with a string value. // Test 1: Parse JSON object with a string value.
static void test_parse_json_object(void) { static void test_parse_json_object(Arena *arena) {
Arena arena = arena_init(ARENA_SIZE);
const char *json = "{\"key\":\"value\"}"; const char *json = "{\"key\":\"value\"}";
Json *root = json_parse(&arena, &json); Json *root = json_parse(arena, &json);
assert(root->type == JSON_OBJECT); assert(root->type == JSON_OBJECT);
Json *child = root->child; Json *child = root->child;
assert(child && strcmp(child->key, "key") == 0); assert(child && strcmp(child->key, "key") == 0);
assert(child->type == JSON_STRING); assert(child->type == JSON_STRING);
assert(strcmp(child->JsonValue.string, "value") == 0); assert(strcmp(child->JsonValue.string, "value") == 0);
arena_free(&arena);
} }
// Test 2: Parse JSON number. // Test 2: Parse JSON number.
static void test_parse_json_number(void) { static void test_parse_json_number(Arena *arena) {
Arena arena = arena_init(ARENA_SIZE);
const char *json = "42"; const char *json = "42";
Json *root = json_parse(&arena, &json); Json *root = json_parse(arena, &json);
assert(root->type == JSON_NUMBER); assert(root->type == JSON_NUMBER);
assert(root->JsonValue.number == 42); assert(root->JsonValue.number == 42);
arena_free(&arena);
} }
// Test 3: Parse JSON string. // Test 3: Parse JSON string.
static void test_parse_json_string(void) { static void test_parse_json_string(Arena *arena) {
Arena arena = {0};
const char *json = "\"hello\""; const char *json = "\"hello\"";
Json *root = json_parse(&arena, &json); Json *root = json_parse(arena, &json);
assert(root->type == JSON_STRING); assert(root->type == JSON_STRING);
assert(strcmp(root->JsonValue.string, "hello") == 0); assert(strcmp(root->JsonValue.string, "hello") == 0);
arena_free(&arena);
} }
// Test 4: Get object items by key. // Test 4: Get object items by key.
static void test_get_object_items(void) { static void test_get_object_items(Arena *arena) {
Arena arena = arena_init(ARENA_SIZE);
const char *json = "{\"a\":\"1\", \"b\":2}"; const char *json = "{\"a\":\"1\", \"b\":2}";
Json *root = json_parse(&arena, &json); Json *root = json_parse(arena, &json);
Json *item_a = json_get_object_item(root, "a"); Json *item_a = json_get_object_item(root, "a");
assert(item_a && item_a->type == JSON_STRING); assert(item_a && item_a->type == JSON_STRING);
assert(strcmp(item_a->JsonValue.string, "1") == 0); assert(strcmp(item_a->JsonValue.string, "1") == 0);
Json *item_b = json_get_object_item(root, "b"); Json *item_b = json_get_object_item(root, "b");
assert(item_b && item_b->type == JSON_NUMBER); assert(item_b && item_b->type == JSON_NUMBER);
assert(item_b->JsonValue.number == 2); assert(item_b->JsonValue.number == 2);
arena_free(&arena);
} }
// Test 5: Print JSON object. // Test 5: Print JSON object.
static void test_print_json_object(void) { static void test_print_json_object(Arena *arena) {
Arena arena = arena_init(ARENA_SIZE);
const char *json = "{\"key\":\"value\", \"num\":3.14}"; const char *json = "{\"key\":\"value\", \"num\":3.14}";
Json *root = json_parse(&arena, &json); Json *root = json_parse(arena, &json);
char *printed = json_to_string(&arena, root); char *printed = json_to_string(arena, root);
assert(strstr(printed, "\"key\":") != NULL); assert(strstr(printed, "\"key\":") != NULL);
assert(strstr(printed, "\"value\"") != NULL); assert(strstr(printed, "\"value\"") != NULL);
assert(strstr(printed, "\"num\":") != NULL); assert(strstr(printed, "\"num\":") != NULL);
assert(strstr(printed, "3.14") != NULL); assert(strstr(printed, "3.14") != NULL);
arena_free(&arena);
} }
// Test 6: Print JSON number. // Test 6: Print JSON number.
static void test_print_json_number(void) { static void test_print_json_number(Arena *arena) {
Arena arena = arena_init(ARENA_SIZE);
const char *json = "123.456"; const char *json = "123.456";
Json *root = json_parse(&arena, &json); Json *root = json_parse(arena, &json);
char *printed = json_to_string(&arena, root); char *printed = json_to_string(arena, root);
double val = atof(printed); double val = atof(printed);
assert(val == 123.456); assert(val == 123.456);
arena_free(&arena);
} }
// Test 7: Print JSON string. // Test 7: Print JSON string.
static void test_print_json_string(void) { static void test_print_json_string(Arena *arena) {
Arena arena = arena_init(ARENA_SIZE);
const char *json = "\"test string\""; const char *json = "\"test string\"";
Json *root = json_parse(&arena, &json); Json *root = json_parse(arena, &json);
char *printed = json_to_string(&arena, root); char *printed = json_to_string(arena, root);
assert(strcmp(printed, "\"test string\"") == 0); assert(strcmp(printed, "\"test string\"") == 0);
arena_free(&arena);
} }
// Test 8: Nested JSON object. // Test 8: Nested JSON object.
static void test_nested_json_object(void) { static void test_nested_json_object(Arena *arena) {
Arena arena = arena_init(1024 * 1024);
const char *json = "{\"outer\":{\"inner\":100}}"; const char *json = "{\"outer\":{\"inner\":100}}";
Json *root = json_parse(&arena, &json); Json *root = json_parse(arena, &json);
assert(root != NULL); assert(root != NULL);
assert(root->type == JSON_OBJECT); assert(root->type == JSON_OBJECT);
@@ -105,38 +90,59 @@ static void test_nested_json_object(void) {
assert(inner->type == JSON_NUMBER); assert(inner->type == JSON_NUMBER);
assert(inner->JsonValue.number == 100); assert(inner->JsonValue.number == 100);
arena_free(&arena);
} }
// Test 9: Arena reset and reuse. // Test 9: Arena reset and reuse.
static void test_arena_reset_reuse(void) { static void test_arena_reset_reuse(Arena *arena) {
Arena arena = arena_init(ARENA_SIZE);
const char *json1 = "{\"key\":\"value\"}"; const char *json1 = "{\"key\":\"value\"}";
Json *root1 = json_parse(&arena, &json1); Json *root1 = json_parse(arena, &json1);
char *printed1 = json_to_string(&arena, root1); char *printed1 = json_to_string(arena, root1);
assert(strcmp(printed1, "{\"key\":\"value\"}") == 0); assert(strcmp(printed1, "{\"key\":\"value\"}") == 0);
arena_reset(&arena); arena_reset(arena);
const char *json2 = "\"another test\""; const char *json2 = "\"another test\"";
Json *root2 = json_parse(&arena, &json2); Json *root2 = json_parse(arena, &json2);
char *printed2 = json_to_string(&arena, root2); char *printed2 = json_to_string(arena, root2);
assert(strcmp(printed2, "\"another test\"") == 0); assert(strcmp(printed2, "\"another test\"") == 0);
arena_free(&arena); }
static void test_debug_str_to_json(Arena *arena) {
const char *debug_str = "struct SomeStruct struct_name = { name = \"value\", next = NULL, value = 123 }";
JsonResult result = DEBUG_STR_TO_JSON(arena, &debug_str);
if (IS_RESULT_ERROR(result)) {
raise_exception("DEBUG_STR_TO_JSON: %s", &RESULT_ERROR_MESSAGE(result));
return;
}
raise_notice("result: %s", json_to_string(arena, &RESULT_SOME_VALUE(result)));
assert(RESULT_SOME_VALUE(result).type == JSON_OBJECT);
} }
int main(void) { int main(void) {
printf("%sRunning %s%s%s\n", OPTIONAL_COLOR(COLOR_GREEN), OPTIONAL_COLOR(COLOR_CYAN), __FILE__, OPTIONAL_COLOR(COLOR_RESET)); printf("%sRunning %s%s%s\n", OPTIONAL_COLOR(COLOR_GREEN), OPTIONAL_COLOR(COLOR_CYAN), __FILE__, OPTIONAL_COLOR(COLOR_RESET));
logger_init(); logger_init();
test_parse_json_object(); Arena arena = arena_init(ARENA_SIZE);
test_parse_json_number();
test_parse_json_string();
test_get_object_items();
test_print_json_object();
test_print_json_number();
test_print_json_string();
test_nested_json_object();
test_arena_reset_reuse();
test_parse_json_object(&arena);
arena_reset(&arena);
test_parse_json_number(&arena);
arena_reset(&arena);
test_parse_json_string(&arena);
arena_reset(&arena);
test_get_object_items(&arena);
arena_reset(&arena);
test_print_json_object(&arena);
arena_reset(&arena);
test_print_json_number(&arena);
arena_reset(&arena);
test_print_json_string(&arena);
arena_reset(&arena);
test_nested_json_object(&arena);
arena_reset(&arena);
test_arena_reset_reuse(&arena);
arena_reset(&arena);
test_debug_str_to_json(&arena);
arena_free(&arena);
logger_free(); logger_free();
printf("%sall tests passed.%s%s%s\n", OPTIONAL_COLOR(COLOR_GREEN), OPTIONAL_COLOR(COLOR_CYAN), __FILE__, OPTIONAL_COLOR(COLOR_RESET)); printf("%sall tests passed.%s%s%s\n", OPTIONAL_COLOR(COLOR_GREEN), OPTIONAL_COLOR(COLOR_CYAN), __FILE__, OPTIONAL_COLOR(COLOR_RESET));
return 0; return 0;

View File

@@ -89,6 +89,6 @@ int main(void) {
logger_free(); logger_free();
arena_free(&arena); arena_free(&arena);
printf("%sall tests passed.%s%s%s\n", OPTIONAL_COLOR(COLOR_GREEN), OPTIONAL_COLOR(COLOR_CYAN), __FILE__, OPTIONAL_COLOR(COLOR_RESET)); printf("%sall tests passed %s%s%s\n", OPTIONAL_COLOR(COLOR_GREEN), OPTIONAL_COLOR(COLOR_CYAN), __FILE__, OPTIONAL_COLOR(COLOR_RESET));
return 0; return 0;
} }