#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <assert.h>
#include "../../include/synta.h"
static int test_count = 0;
static int pass_count = 0;
#define TEST(name) \
do { \
test_count++; \
printf("Test %d: %s ... ", test_count, name);
#define END_TEST() \
pass_count++; \
printf("PASS\n"); \
} while(0)
void test_decoder_cleanup(void) {
TEST("Decoder cleanup");
const uint8_t data[] = {0x02, 0x01, 0x2A};
for (int i = 0; i < 1000; i++) {
SyntaDecoder* decoder = synta_decoder_new(data, sizeof(data), SyntaEncoding_Der);
assert(decoder != NULL);
synta_decoder_free(decoder);
}
END_TEST();
}
void test_encoder_cleanup(void) {
TEST("Encoder cleanup");
for (int i = 0; i < 1000; i++) {
SyntaEncoder* encoder = synta_encoder_new(SyntaEncoding_Der);
assert(encoder != NULL);
assert(synta_encode_integer_i64(encoder, 42) == SyntaErrorCode_Success);
SyntaByteArray output = {0};
assert(synta_encoder_finish(encoder, &output) == SyntaErrorCode_Success);
synta_byte_array_free(&output);
}
END_TEST();
}
void test_integer_cleanup(void) {
TEST("Integer cleanup");
for (int i = 0; i < 1000; i++) {
SyntaInteger* integer = synta_integer_new_i64(123456789);
assert(integer != NULL);
synta_integer_free(integer);
}
END_TEST();
}
void test_oid_cleanup(void) {
TEST("OID cleanup");
for (int i = 0; i < 1000; i++) {
SyntaObjectIdentifier* oid = synta_oid_from_string("1.2.840.113549.1.1.1");
assert(oid != NULL);
synta_oid_free(oid);
}
END_TEST();
}
void test_octet_string_cleanup(void) {
TEST("OctetString cleanup");
const uint8_t data[] = {0x01, 0x02, 0x03, 0x04, 0x05};
for (int i = 0; i < 1000; i++) {
SyntaOctetString* os = synta_octet_string_new(data, sizeof(data));
assert(os != NULL);
synta_octet_string_free(os);
}
END_TEST();
}
void test_byte_array_cleanup(void) {
TEST("ByteArray cleanup");
const uint8_t data[] = {0x01, 0x02, 0x03, 0x04, 0x05};
for (int i = 0; i < 1000; i++) {
SyntaByteArray array = {0};
array.data = data;
array.len = sizeof(data);
array.owned = false;
SyntaByteArray cloned = synta_byte_array_clone(&array);
assert(cloned.data != NULL);
assert(cloned.len == array.len);
assert(cloned.owned == true);
synta_byte_array_free(&cloned);
}
END_TEST();
}
void test_nested_sequence_cleanup(void) {
TEST("Nested sequence cleanup");
for (int i = 0; i < 100; i++) {
SyntaEncoder* encoder = synta_encoder_new(SyntaEncoding_Der);
assert(encoder != NULL);
SyntaEncoder* outer_seq = NULL;
assert(synta_encoder_start_sequence(encoder, &outer_seq) == SyntaErrorCode_Success);
SyntaEncoder* inner_seq = NULL;
assert(synta_encoder_start_sequence(outer_seq, &inner_seq) == SyntaErrorCode_Success);
assert(synta_encode_integer_i64(inner_seq, 42) == SyntaErrorCode_Success);
assert(synta_encoder_end_constructed(inner_seq) == SyntaErrorCode_Success);
assert(synta_encode_boolean(outer_seq, true) == SyntaErrorCode_Success);
assert(synta_encoder_end_constructed(outer_seq) == SyntaErrorCode_Success);
SyntaByteArray output = {0};
assert(synta_encoder_finish(encoder, &output) == SyntaErrorCode_Success);
SyntaDecoder* decoder = synta_decoder_new(output.data, output.len, SyntaEncoding_Der);
assert(decoder != NULL);
SyntaDecoder* outer_dec = NULL;
assert(synta_decoder_enter_sequence(decoder, &outer_dec) == SyntaErrorCode_Success);
SyntaDecoder* inner_dec = NULL;
assert(synta_decoder_enter_sequence(outer_dec, &inner_dec) == SyntaErrorCode_Success);
SyntaInteger* integer = NULL;
assert(synta_decode_integer(inner_dec, &integer) == SyntaErrorCode_Success);
synta_integer_free(integer);
synta_decoder_free(inner_dec);
bool value = false;
assert(synta_decode_boolean(outer_dec, &value) == SyntaErrorCode_Success);
synta_decoder_free(outer_dec);
synta_decoder_free(decoder);
synta_byte_array_free(&output);
}
END_TEST();
}
void test_large_allocation(void) {
TEST("Large data allocation");
size_t large_size = 1024 * 1024; uint8_t* large_data = (uint8_t*)malloc(large_size);
assert(large_data != NULL);
memset(large_data, 0x42, large_size);
SyntaEncoder* encoder = synta_encoder_new(SyntaEncoding_Der);
assert(encoder != NULL);
assert(synta_encode_octet_string(encoder, large_data, large_size) == SyntaErrorCode_Success);
SyntaByteArray output = {0};
assert(synta_encoder_finish(encoder, &output) == SyntaErrorCode_Success);
SyntaDecoder* decoder = synta_decoder_new(output.data, output.len, SyntaEncoding_Der);
assert(decoder != NULL);
SyntaOctetString* os = NULL;
assert(synta_decode_octet_string(decoder, &os) == SyntaErrorCode_Success);
assert(synta_octet_string_len(os) == large_size);
synta_octet_string_free(os);
synta_decoder_free(decoder);
synta_byte_array_free(&output);
free(large_data);
END_TEST();
}
void test_error_path_cleanup(void) {
TEST("Error path cleanup");
const uint8_t invalid_data[] = {0x02, 0x05, 0x01};
for (int i = 0; i < 100; i++) {
SyntaDecoder* decoder = synta_decoder_new(invalid_data, sizeof(invalid_data), SyntaEncoding_Der);
assert(decoder != NULL);
SyntaInteger* integer = NULL;
SyntaErrorCode err = synta_decode_integer(decoder, &integer);
assert(err != SyntaErrorCode_Success);
assert(integer == NULL);
synta_decoder_free(decoder);
}
END_TEST();
}
int main(void) {
printf("=== Memory Management Integration Tests ===\n");
printf("Run with: valgrind --leak-check=full ./test_memory\n\n");
test_decoder_cleanup();
test_encoder_cleanup();
test_integer_cleanup();
test_oid_cleanup();
test_octet_string_cleanup();
test_byte_array_cleanup();
test_nested_sequence_cleanup();
test_large_allocation();
test_error_path_cleanup();
printf("\n=== Summary ===\n");
printf("Passed: %d/%d\n", pass_count, test_count);
printf("\nCheck Valgrind output above for memory leaks.\n");
synta_clear_last_error();
return (pass_count == test_count) ? 0 : 1;
}