#[cfg(test)]
mod tests {
#[test]
fn test_malloc_single_value() {
let c_code = r#"
int* p = malloc(sizeof(int));
*p = 42;
free(p);
"#;
let rust_expected = r#"
let mut p = Box::new(0i32);
*p = 42;
// Automatic drop
"#;
assert!(c_code.contains("malloc(sizeof(int))"));
assert!(rust_expected.contains("Box::new(0i32)"));
}
#[test]
fn test_malloc_array() {
let c_code = r#"
int n = 100;
int* arr = malloc(n * sizeof(int));
free(arr);
"#;
let rust_expected = r#"
let n = 100;
let mut arr = Vec::with_capacity(n);
// Automatic drop
"#;
assert!(c_code.contains("malloc(n * sizeof(int))"));
assert!(rust_expected.contains("Vec::with_capacity(n)"));
}
#[test]
fn test_calloc_zero_init() {
let c_code = r#"
int* arr = calloc(10, sizeof(int));
free(arr);
"#;
let rust_expected = r#"
let arr = vec![0i32; 10];
// Automatic drop
"#;
assert!(c_code.contains("calloc(10, sizeof(int))"));
assert!(rust_expected.contains("vec![0i32; 10]"));
}
#[test]
fn test_calloc_variable_size() {
let c_code = r#"
int n = get_size();
double* values = calloc(n, sizeof(double));
free(values);
"#;
let rust_expected = r#"
let n = get_size();
let values = vec![0.0f64; n];
// Automatic drop
"#;
assert!(c_code.contains("calloc(n, sizeof(double))"));
assert!(rust_expected.contains("vec![0.0f64; n]"));
}
#[test]
fn test_realloc_grow() {
let c_code = r#"
int* arr = malloc(10 * sizeof(int));
arr = realloc(arr, 20 * sizeof(int));
free(arr);
"#;
let rust_expected = r#"
let mut arr = vec![0i32; 10];
arr.resize(20, 0);
// Automatic drop
"#;
assert!(c_code.contains("realloc(arr, 20"));
assert!(rust_expected.contains("arr.resize(20, 0)"));
}
#[test]
fn test_realloc_shrink() {
let c_code = r#"
int* arr = malloc(100 * sizeof(int));
arr = realloc(arr, 50 * sizeof(int));
free(arr);
"#;
let rust_expected = r#"
let mut arr = vec![0i32; 100];
arr.resize(50, 0);
// Automatic drop
"#;
assert!(c_code.contains("realloc(arr, 50"));
assert!(rust_expected.contains("arr.resize(50, 0)"));
}
#[test]
fn test_realloc_zero_size() {
let c_code = r#"
int* arr = malloc(10 * sizeof(int));
arr = realloc(arr, 0); // Equivalent to free
"#;
let rust_expected = r#"
let mut arr = vec![0i32; 10];
arr.clear(); // Or just drop
"#;
assert!(c_code.contains("realloc(arr, 0)"));
assert!(rust_expected.contains("arr.clear()"));
}
#[test]
fn test_realloc_null_pointer() {
let c_code = r#"
int* arr = NULL;
arr = realloc(arr, 10 * sizeof(int)); // Equivalent to malloc
free(arr);
"#;
let rust_expected = r#"
let arr = vec![0i32; 10];
// Automatic drop
"#;
assert!(c_code.contains("realloc(arr"));
assert!(rust_expected.contains("vec![0i32; 10]"));
}
#[test]
fn test_malloc_null_check() {
let c_code = r#"
int* p = malloc(sizeof(int));
if (p == NULL) {
return -1;
}
*p = 42;
free(p);
"#;
let rust_expected = r#"
let mut p = Box::new(0i32);
// Panics if OOM (rare)
*p = 42;
// Automatic drop
"#;
assert!(c_code.contains("if (p == NULL)"));
assert!(rust_expected.contains("Box::new"));
}
#[test]
fn test_scope_based_lifetime() {
let c_code = r#"
{
int* p = malloc(sizeof(int));
*p = 10;
free(p);
}
"#;
let rust_expected = r#"
{
let mut p = Box::new(0i32);
*p = 10;
// Automatic drop at end of scope
}
"#;
assert!(c_code.contains("free(p)"));
assert!(rust_expected.contains("// Automatic drop"));
}
#[test]
fn test_malloc_struct() {
let c_code = r#"
struct Point { int x; int y; };
struct Point* p = malloc(sizeof(struct Point));
p->x = 10;
p->y = 20;
free(p);
"#;
let rust_expected = r#"
struct Point { x: i32, y: i32 }
let mut p = Box::new(Point { x: 0, y: 0 });
p.x = 10;
p.y = 20;
// Automatic drop
"#;
assert!(c_code.contains("malloc(sizeof(struct Point))"));
assert!(rust_expected.contains("Box::new(Point"));
}
#[test]
fn test_calloc_struct_array() {
let c_code = r#"
struct Point points[10];
struct Point* arr = calloc(10, sizeof(struct Point));
free(arr);
"#;
let rust_expected = r#"
let arr = vec![Point::default(); 10];
// Automatic drop
"#;
assert!(c_code.contains("calloc(10, sizeof(struct Point))"));
assert!(rust_expected.contains("vec![Point::default(); 10]"));
}
#[test]
fn test_memory_leak_prevention() {
let c_note = r#"
// C: Easy to leak memory
int* p = malloc(sizeof(int));
if (error) {
return; // LEAK! Forgot to free
}
free(p);
"#;
let rust_code = r#"
// Rust: Impossible to leak (without unsafe)
let p = Box::new(0i32);
if error {
return; // OK: p automatically dropped
}
// p dropped here too
"#;
assert!(c_note.contains("LEAK"));
assert!(rust_code.contains("automatically dropped"));
}
#[test]
fn test_double_free_prevention() {
let c_note = r#"
// C: Double free is undefined behavior
int* p = malloc(sizeof(int));
free(p);
free(p); // CRASH or corruption
"#;
let rust_code = r#"
// Rust: Impossible to double free
let p = Box::new(0i32);
drop(p);
// drop(p); // COMPILE ERROR: use of moved value
"#;
assert!(c_note.contains("Double free"));
assert!(rust_code.contains("COMPILE ERROR"));
}
#[test]
fn test_use_after_free_prevention() {
let c_note = r#"
// C: Use after free is undefined behavior
int* p = malloc(sizeof(int));
free(p);
*p = 5; // UNDEFINED BEHAVIOR
"#;
let rust_code = r#"
// Rust: Impossible to use after free
let mut p = Box::new(0i32);
drop(p);
// *p = 5; // COMPILE ERROR: use of moved value
"#;
assert!(c_note.contains("Use after free"));
assert!(rust_code.contains("COMPILE ERROR"));
}
#[test]
fn test_malloc_with_cast() {
let c_code = r#"
int* p = (int*)malloc(sizeof(int));
free(p);
"#;
let rust_expected = r#"
let p = Box::new(0i32);
// Automatic drop
"#;
assert!(c_code.contains("(int*)malloc"));
assert!(rust_expected.contains("Box::new(0i32)"));
}
#[test]
fn test_memory_allocation_transformation_summary() {
let c_code = r#"
// Rule 1: malloc single → Box::new
int* p = malloc(sizeof(int));
free(p);
// Rule 2: malloc array → Vec::with_capacity
int* arr1 = malloc(n * sizeof(int));
free(arr1);
// Rule 3: calloc → vec![0; n]
int* arr2 = calloc(n, sizeof(int));
free(arr2);
// Rule 4: realloc → vec.resize
arr2 = realloc(arr2, new_size);
// Rule 5: NULL check → panic/Result
if (p == NULL) return -1;
// Rule 6: Scope-based free
{ int* tmp = malloc(10); free(tmp); }
"#;
let rust_expected = r#"
// Rule 1: Heap-allocated value
let p = Box::new(0i32);
// Rule 2: Uninitialized capacity
let mut arr1 = Vec::with_capacity(n);
// Rule 3: Zero-initialized
let arr2 = vec![0i32; n];
// Rule 4: Resize (grow/shrink)
arr2.resize(new_size, 0);
// Rule 5: Panics on OOM
// No NULL check needed
// Rule 6: Automatic Drop
{ let _tmp = vec![0; 10]; }
"#;
assert!(c_code.contains("malloc(sizeof(int))"));
assert!(rust_expected.contains("Box::new(0i32)"));
assert!(c_code.contains("malloc(n * sizeof(int))"));
assert!(rust_expected.contains("Vec::with_capacity(n)"));
assert!(c_code.contains("calloc(n, sizeof(int))"));
assert!(rust_expected.contains("vec![0i32; n]"));
assert!(c_code.contains("realloc"));
assert!(rust_expected.contains("resize"));
}
}