/** * Test: Memory leak detection * * This test should be run with valgrind or ASAN to detect memory leaks. * * Usage: * valgrind --leak-check=full --error-exitcode=1 ./test_memory * * Or compile with ASAN: * gcc -fsanitize=address -o test_memory test_memory.c -L../../../target/release -lentropyk_ffi * ./test_memory */ #include #include #include #include #include "entropyk.h" #define NUM_CYCLES 100 int main() { printf("Test: Memory leak detection\n"); printf(" Run with: valgrind --leak-check=full ./test_memory\n\n"); /* Test 1: System lifecycle */ printf(" Test 1: System create/free cycles (%d iterations)... ", NUM_CYCLES); for (int i = 0; i < NUM_CYCLES; i++) { EntropykSystem* sys = entropyk_system_create(); assert(sys != NULL); entropyk_system_free(sys); } printf("PASS\n"); /* Test 2: Component lifecycle (not added to system) */ printf(" Test 2: Component create/free cycles... "); for (int i = 0; i < NUM_CYCLES; i++) { double coeffs[10] = {0.85, 2.5, 500.0, 1500.0, -2.5, 1.8, 600.0, 1600.0, -3.0, 2.0}; EntropykComponent* comp = entropyk_compressor_create(coeffs, 10); EntropykComponent* cond = entropyk_condenser_create(5000.0); EntropykComponent* evap = entropyk_evaporator_create(3000.0); EntropykComponent* valve = entropyk_expansion_valve_create(); assert(comp && cond && evap && valve); entropyk_compressor_free(comp); entropyk_component_free(cond); entropyk_component_free(evap); entropyk_component_free(valve); } printf("PASS\n"); /* Test 3: Full system with components (ownership transfer) */ printf(" Test 3: Full system lifecycle... "); for (int i = 0; i < NUM_CYCLES; i++) { EntropykSystem* sys = entropyk_system_create(); assert(sys != NULL); double coeffs[10] = {0.85, 2.5, 500.0, 1500.0, -2.5, 1.8, 600.0, 1600.0, -3.0, 2.0}; EntropykComponent* comp = entropyk_compressor_create(coeffs, 10); EntropykComponent* cond = entropyk_condenser_create(5000.0); EntropykComponent* evap = entropyk_evaporator_create(3000.0); EntropykComponent* valve = entropyk_expansion_valve_create(); unsigned int comp_idx = entropyk_system_add_component(sys, comp); unsigned int cond_idx = entropyk_system_add_component(sys, cond); unsigned int evap_idx = entropyk_system_add_component(sys, evap); unsigned int valve_idx = entropyk_system_add_component(sys, valve); (void)comp_idx; (void)cond_idx; (void)evap_idx; (void)valve_idx; entropyk_system_free(sys); /* Note: Components are freed when system is freed (ownership transfer) */ } printf("PASS\n"); /* Test 4: Solver result lifecycle */ printf(" Test 4: Solver result lifecycle... "); for (int i = 0; i < NUM_CYCLES; i++) { EntropykSystem* sys = entropyk_system_create(); double coeffs[10] = {0.85, 2.5, 500.0, 1500.0, -2.5, 1.8, 600.0, 1600.0, -3.0, 2.0}; EntropykComponent* comp = entropyk_compressor_create(coeffs, 10); EntropykComponent* cond = entropyk_condenser_create(5000.0); EntropykComponent* evap = entropyk_evaporator_create(3000.0); EntropykComponent* valve = entropyk_expansion_valve_create(); entropyk_system_add_component(sys, comp); entropyk_system_add_component(sys, cond); entropyk_system_add_component(sys, evap); entropyk_system_add_component(sys, valve); entropyk_system_finalize(sys); EntropykFallbackConfig config = { .newton = {10, 1e-4, false, 100}, .picard = {20, 1e-3, 0.5} }; EntropykSolverResult* result = NULL; entropyk_solve_fallback(sys, &config, &result); if (result != NULL) { entropyk_result_free(result); } entropyk_system_free(sys); } printf("PASS\n"); /* Test 5: Null pointer handling (should not crash or leak) */ printf(" Test 5: Null pointer handling... "); entropyk_system_free(NULL); entropyk_compressor_free(NULL); entropyk_component_free(NULL); entropyk_result_free(NULL); printf("PASS\n"); /* Test 6: State vector retrieval */ printf(" Test 6: State vector allocation... "); EntropykSystem* sys = entropyk_system_create(); double coeffs[10] = {0.85, 2.5, 500.0, 1500.0, -2.5, 1.8, 600.0, 1600.0, -3.0, 2.0}; EntropykComponent* comp = entropyk_compressor_create(coeffs, 10); EntropykComponent* cond = entropyk_condenser_create(5000.0); EntropykComponent* evap = entropyk_evaporator_create(3000.0); EntropykComponent* valve = entropyk_expansion_valve_create(); entropyk_system_add_component(sys, comp); entropyk_system_add_component(sys, cond); entropyk_system_add_component(sys, evap); entropyk_system_add_component(sys, valve); entropyk_system_finalize(sys); EntropykFallbackConfig config = { .newton = {10, 1e-4, false, 100}, .picard = {20, 1e-3, 0.5} }; EntropykSolverResult* result = NULL; if (entropyk_solve_fallback(sys, &config, &result) == ENTROPYK_OK && result != NULL) { unsigned int len = 0; entropyk_result_get_state_vector(result, NULL, &len); if (len > 0) { double* state = (double*)malloc(len * sizeof(double)); entropyk_result_get_state_vector(result, state, &len); free(state); } entropyk_result_free(result); } entropyk_system_free(sys); printf("PASS\n"); printf("\nAll memory tests PASSED\n"); printf("If running under valgrind, check for 'ERROR SUMMARY: 0 errors'\n"); return 0; }