Camel/examples/units.c

365 lines
14 KiB
C
Raw Normal View History

2025-03-31 14:56:58 +00:00
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define CYAML_IMPLEMENTATION
#include "../include/cyaml.h" // Adjust this path as needed
/* ANSI color definitions for pretty terminal output */
#define COLOR_RED "\033[31m"
#define COLOR_GREEN "\033[32m"
#define COLOR_YELLOW "\033[33m"
#define COLOR_RESET "\033[0m"
/* Global counters for tests */
static int tests_passed = 0;
static int tests_run = 0;
/* Test assertion macro */
#define TEST_ASSERT(cond, msg) do { \
tests_run++; \
if (!(cond)) { \
printf(COLOR_RED "[FAIL]" COLOR_RESET " %s\n", msg); \
} else { \
tests_passed++; \
printf(COLOR_GREEN "[PASS]" COLOR_RESET " %s\n", msg); \
} \
} while(0)
/*---------------------------------------------------------
* Utility Functions to Clean Up Manually Created Nodes
* (These are needed because our cyaml library currently
* only auto-frees scalar nodes from cyaml_load_* functions.)
*---------------------------------------------------------*/
static void free_mapping_node(cyaml_node_t *node) {
if (node->keys) {
for (size_t i = 0; i < node->mapping_size; i++) {
free(node->keys[i]);
}
free(node->keys);
}
if (node->values) {
for (size_t i = 0; i < node->mapping_size; i++) {
if (node->values[i]) {
if (node->values[i]->scalar)
free(node->values[i]->scalar);
free(node->values[i]);
}
}
free(node->values);
}
free(node);
}
static void free_sequence_node(cyaml_node_t *node) {
if (node->sequence) {
for (size_t i = 0; i < node->sequence_size; i++) {
if (node->sequence[i]) {
if (node->sequence[i]->scalar)
free(node->sequence[i]->scalar);
free(node->sequence[i]);
}
}
free(node->sequence);
}
free(node);
}
/*---------------------------------------------------------
* Test 1: Load YAML String (Scalar)
*---------------------------------------------------------*/
void test_load_string() {
const char *yaml = "Hello, cyaml!";
cyaml_document_t *doc = cyaml_load_string(yaml);
TEST_ASSERT(doc != NULL, "cyaml_load_string should not return NULL");
if (doc) {
const cyaml_node_t *root = cyaml_document_get_root(doc);
TEST_ASSERT(root != NULL, "Root node should not be NULL");
if (root) {
const char *str = cyaml_node_as_string(root);
TEST_ASSERT(str != NULL, "Root node should be a scalar string");
if (str) {
TEST_ASSERT(strcmp(str, yaml) == 0, "Scalar value should match input string");
}
}
cyaml_document_destroy(doc);
}
}
/*---------------------------------------------------------
* Test 2: Emitter for Scalar YAML
*---------------------------------------------------------*/
void test_emitter_scalar() {
const char *yaml = "Emitter Test!";
cyaml_document_t *doc = cyaml_load_string(yaml);
TEST_ASSERT(doc != NULL, "cyaml_load_string for emitter test should not return NULL");
if (doc) {
cyaml_emitter_t *emitter = cyaml_emitter_create();
TEST_ASSERT(emitter != NULL, "cyaml_emitter_create should not return NULL");
if (emitter) {
int emit_result = cyaml_emitter_emit(emitter, doc);
TEST_ASSERT(emit_result == 0, "cyaml_emitter_emit should succeed");
char *emitted_str = cyaml_emitter_to_string(emitter);
TEST_ASSERT(emitted_str != NULL, "cyaml_emitter_to_string should not return NULL");
if (emitted_str) {
TEST_ASSERT(strcmp(emitted_str, yaml) == 0, "Emitted YAML should match original scalar");
free(emitted_str);
}
cyaml_emitter_destroy(emitter);
}
cyaml_document_destroy(doc);
}
}
/*---------------------------------------------------------
* Test 3: Load YAML from a File (Scalar)
*---------------------------------------------------------*/
void test_load_file() {
const char *filename = "test.yaml";
const char *yaml = "File Test!";
/* Create a temporary file with YAML content */
FILE *file = fopen(filename, "w");
if (!file) {
printf(COLOR_YELLOW "Warning: Could not create temporary test file.\n" COLOR_RESET);
return;
}
fputs(yaml, file);
fclose(file);
cyaml_document_t *doc = cyaml_load_file(filename);
TEST_ASSERT(doc != NULL, "cyaml_load_file should not return NULL");
if (doc) {
const cyaml_node_t *root = cyaml_document_get_root(doc);
TEST_ASSERT(root != NULL, "Root node from file should not be NULL");
if (root) {
const char *str = cyaml_node_as_string(root);
TEST_ASSERT(str != NULL, "Root node from file should be a scalar string");
if (str) {
TEST_ASSERT(strcmp(str, yaml) == 0, "File content should match expected YAML");
}
}
cyaml_document_destroy(doc);
}
/* Remove the temporary file */
remove(filename);
}
/*---------------------------------------------------------
* Test 4: Numeric Conversions
*---------------------------------------------------------*/
void test_numeric_conversion() {
// Integer conversion test
const char *int_str = "12345";
cyaml_document_t *doc_int = cyaml_load_string(int_str);
TEST_ASSERT(doc_int != NULL, "Load integer string for conversion");
if (doc_int) {
const cyaml_node_t *node = cyaml_document_get_root(doc_int);
int value = cyaml_node_as_int(node);
TEST_ASSERT(value == 12345, "Integer conversion: value should be 12345");
cyaml_document_destroy(doc_int);
}
// Double conversion test
const char *double_str = "3.14159";
cyaml_document_t *doc_double = cyaml_load_string(double_str);
TEST_ASSERT(doc_double != NULL, "Load double string for conversion");
if (doc_double) {
const cyaml_node_t *node = cyaml_document_get_root(doc_double);
double dvalue = cyaml_node_as_double(node);
TEST_ASSERT(dvalue > 3.14158 && dvalue < 3.14160, "Double conversion: value should be approx 3.14159");
cyaml_document_destroy(doc_double);
}
}
/*---------------------------------------------------------
* Test 5: Mapping Node Functionality
*---------------------------------------------------------*/
void test_mapping_node() {
// Manually create a mapping node document
cyaml_document_t *doc = (cyaml_document_t*)malloc(sizeof(cyaml_document_t));
doc->root = (cyaml_node_t*)malloc(sizeof(cyaml_node_t));
cyaml_node_t *map = doc->root;
map->type = CYAML_NODE_MAPPING;
map->mapping_size = 3;
map->keys = (char**)malloc(sizeof(char*) * 3);
map->values = (cyaml_node_t**)malloc(sizeof(cyaml_node_t*) * 3);
// Key-value pair 1: "name": "cyaml"
map->keys[0] = strdup("name");
map->values[0] = (cyaml_node_t*)malloc(sizeof(cyaml_node_t));
map->values[0]->type = CYAML_NODE_SCALAR;
map->values[0]->scalar = strdup("cyaml");
// Key-value pair 2: "version": "1.0"
map->keys[1] = strdup("version");
map->values[1] = (cyaml_node_t*)malloc(sizeof(cyaml_node_t));
map->values[1]->type = CYAML_NODE_SCALAR;
map->values[1]->scalar = strdup("1.0");
// Key-value pair 3: "count": "42"
map->keys[2] = strdup("count");
map->values[2] = (cyaml_node_t*)malloc(sizeof(cyaml_node_t));
map->values[2]->type = CYAML_NODE_SCALAR;
map->values[2]->scalar = strdup("42");
TEST_ASSERT(cyaml_node_size(map) == 3, "Mapping node size should be 3");
const cyaml_node_t *node_name = cyaml_node_get(map, "name");
TEST_ASSERT(node_name != NULL, "Mapping node: key 'name' should exist");
if (node_name) {
TEST_ASSERT(strcmp(cyaml_node_as_string(node_name), "cyaml") == 0, "Mapping node: 'name' value should be 'cyaml'");
}
const cyaml_node_t *node_version = cyaml_node_get(map, "version");
TEST_ASSERT(node_version != NULL, "Mapping node: key 'version' should exist");
if (node_version) {
TEST_ASSERT(strcmp(cyaml_node_as_string(node_version), "1.0") == 0, "Mapping node: 'version' value should be '1.0'");
}
const cyaml_node_t *node_count = cyaml_node_get(map, "count");
TEST_ASSERT(node_count != NULL, "Mapping node: key 'count' should exist");
if (node_count) {
int count = cyaml_node_as_int(node_count);
TEST_ASSERT(count == 42, "Mapping node: 'count' value should be 42");
}
// Clean up manually created mapping node
free_mapping_node(map);
free(doc);
}
/*---------------------------------------------------------
* Test 6: Sequence Node Functionality
*---------------------------------------------------------*/
void test_sequence_node() {
// Manually create a sequence node document
cyaml_document_t *doc = (cyaml_document_t*)malloc(sizeof(cyaml_document_t));
doc->root = (cyaml_node_t*)malloc(sizeof(cyaml_node_t));
cyaml_node_t *seq = doc->root;
seq->type = CYAML_NODE_SEQUENCE;
seq->sequence_size = 4;
seq->sequence = (cyaml_node_t**)malloc(sizeof(cyaml_node_t*) * 4);
const char *items[] = { "one", "two", "three", "four" };
for (size_t i = 0; i < 4; i++) {
seq->sequence[i] = (cyaml_node_t*)malloc(sizeof(cyaml_node_t));
seq->sequence[i]->type = CYAML_NODE_SCALAR;
seq->sequence[i]->scalar = strdup(items[i]);
}
TEST_ASSERT(cyaml_node_size(seq) == 4, "Sequence node size should be 4");
for (size_t i = 0; i < 4; i++) {
const cyaml_node_t *item = cyaml_node_index(seq, i);
char msg[128];
snprintf(msg, sizeof(msg), "Sequence node: item %zu should not be NULL", i);
TEST_ASSERT(item != NULL, msg);
if (item) {
snprintf(msg, sizeof(msg), "Sequence node: item %zu should equal '%s'", i, items[i]);
TEST_ASSERT(strcmp(cyaml_node_as_string(item), items[i]) == 0, msg);
}
}
// Clean up manually created sequence node
free_sequence_node(seq);
free(doc);
}
/*---------------------------------------------------------
* Test 7: Bulk YAML String Loading (100 iterations)
*---------------------------------------------------------*/
void test_bulk_load_string() {
for (int i = 0; i < 100; i++) {
char buffer[64];
snprintf(buffer, sizeof(buffer), "Bulk test %d", i);
cyaml_document_t *doc = cyaml_load_string(buffer);
char test_msg[128];
snprintf(test_msg, sizeof(test_msg), "Bulk load string test %d: document should not be NULL", i);
TEST_ASSERT(doc != NULL, test_msg);
if (doc) {
const cyaml_node_t *root = cyaml_document_get_root(doc);
snprintf(test_msg, sizeof(test_msg), "Bulk load string test %d: root should not be NULL", i);
TEST_ASSERT(root != NULL, test_msg);
if (root) {
snprintf(test_msg, sizeof(test_msg), "Bulk load string test %d: value should match", i);
TEST_ASSERT(strcmp(cyaml_node_as_string(root), buffer) == 0, test_msg);
}
cyaml_document_destroy(doc);
}
}
}
/*---------------------------------------------------------
* Test 8: Bulk File Read/Write (20 iterations)
*---------------------------------------------------------*/
void test_bulk_file_rw() {
for (int i = 0; i < 20; i++) {
char filename[64];
char content[64];
snprintf(filename, sizeof(filename), "temp_test_%d.yaml", i);
snprintf(content, sizeof(content), "File bulk test %d", i);
/* Write to file */
FILE *file = fopen(filename, "w");
if (!file) {
printf(COLOR_YELLOW "Warning: Could not create temporary file %s.\n" COLOR_RESET, filename);
continue;
}
fputs(content, file);
fclose(file);
/* Read file and validate */
cyaml_document_t *doc = cyaml_load_file(filename);
char test_msg[128];
snprintf(test_msg, sizeof(test_msg), "Bulk file test %d: document should not be NULL", i);
TEST_ASSERT(doc != NULL, test_msg);
if (doc) {
const cyaml_node_t *root = cyaml_document_get_root(doc);
snprintf(test_msg, sizeof(test_msg), "Bulk file test %d: root should not be NULL", i);
TEST_ASSERT(root != NULL, test_msg);
if (root) {
snprintf(test_msg, sizeof(test_msg), "Bulk file test %d: content should match", i);
TEST_ASSERT(strcmp(cyaml_node_as_string(root), content) == 0, test_msg);
}
cyaml_document_destroy(doc);
}
/* Remove the temporary file */
remove(filename);
}
}
/*---------------------------------------------------------
* Main Function: Run All Tests and Display Summary
*---------------------------------------------------------*/
int main(void) {
printf("========================================\n");
printf(" " COLOR_YELLOW "cyaml Unit Test Suite" COLOR_RESET "\n");
printf("========================================\n\n");
test_load_string();
test_emitter_scalar();
test_load_file();
test_numeric_conversion();
test_mapping_node();
test_sequence_node();
test_bulk_load_string();
test_bulk_file_rw();
printf("\n========================================\n");
printf("Test Summary:\n");
printf("Total tests run: %d\n", tests_run);
printf(COLOR_GREEN "Passed: %d" COLOR_RESET "\n", tests_passed);
printf(COLOR_RED "Failed: %d" COLOR_RESET "\n", tests_run - tests_passed);
printf("========================================\n");
return (tests_run - tests_passed) == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
}