#[cfg(test)]
mod tests {
#[test]
fn test_malloc_array_to_vec_basic() {
let c_code = r#"
int* arr = malloc(n * sizeof(int));
for (int i = 0; i < n; i++) {
arr[i] = i;
}
free(arr);
"#;
let rust_expected = r#"
let mut arr = vec![0i32; n];
for i in 0..n {
arr[i] = i;
}
// Automatic deallocation when arr goes out of scope
"#;
assert!(c_code.contains("malloc(n * sizeof(int))"));
assert!(c_code.contains("free(arr)"));
assert!(rust_expected.contains("vec![0i32; n]"));
assert!(rust_expected.contains("Automatic deallocation"));
}
#[test]
fn test_calloc_to_vec() {
let c_code = r#"
int* arr = calloc(n, sizeof(int));
free(arr);
"#;
let rust_expected = r#"
let arr = vec![0i32; n]; // Already zero-initialized
// Automatic deallocation
"#;
assert!(c_code.contains("calloc(n, sizeof(int))"));
assert!(rust_expected.contains("vec![0i32; n]"));
assert!(rust_expected.contains("zero-initialized"));
}
#[test]
fn test_malloc_array_null_check_to_vec() {
let c_code = r#"
int* arr = malloc(n * sizeof(int));
if (arr == NULL) {
return -1;
}
free(arr);
"#;
let rust_expected = r#"
let arr = vec![0i32; n]; // Panics on OOM (idiomatic)
// Automatic deallocation
"#;
assert!(c_code.contains("if (arr == NULL)"));
assert!(rust_expected.contains("vec![0i32; n]"));
assert!(rust_expected.contains("Panics on OOM"));
}
#[test]
fn test_malloc_array_struct_field_to_vec() {
let c_code = r#"
struct Array {
int* data;
size_t len;
};
struct Array a;
a.data = malloc(n * sizeof(int));
a.len = n;
free(a.data);
"#;
let rust_expected = r#"
struct Array {
data: Vec<i32>, // Length built-in (.len())
}
let a = Array { data: vec![0; n] };
// Automatic deallocation when a goes out of scope
"#;
assert!(c_code.contains("int* data"));
assert!(c_code.contains("size_t len"));
assert!(rust_expected.contains("data: Vec<i32>"));
assert!(rust_expected.contains("Length built-in"));
}
#[test]
fn test_malloc_array_return_to_vec() {
let c_code = r#"
int* create_array(size_t n) {
int* arr = malloc(n * sizeof(int));
for (size_t i = 0; i < n; i++) {
arr[i] = i;
}
return arr;
}
"#;
let rust_expected = r#"
fn create_array(n: usize) -> Vec<i32> {
let mut arr = vec![0i32; n];
for i in 0..n {
arr[i] = i as i32;
}
arr // Return ownership
}
"#;
assert!(c_code.contains("int* create_array"));
assert!(rust_expected.contains("-> Vec<i32>"));
assert!(rust_expected.contains("Return ownership"));
}
#[test]
fn test_malloc_array_with_capacity() {
let c_code = r#"
int* arr = malloc(10 * sizeof(int));
int count = 0;
// Fill arr dynamically
for (int i = 0; i < n && count < 10; i++) {
arr[count++] = i;
}
free(arr);
"#;
let rust_expected = r#"
let mut arr = Vec::with_capacity(10);
// Fill arr dynamically
for i in 0..n {
if arr.len() < 10 {
arr.push(i);
}
}
// Automatic deallocation
"#;
assert!(c_code.contains("malloc(10 * sizeof(int))"));
assert!(rust_expected.contains("Vec::with_capacity(10)"));
assert!(rust_expected.contains("arr.push"));
}
#[test]
fn test_malloc_struct_array_to_vec() {
let c_code = r#"
struct Point { int x; int y; };
struct Point* points = malloc(n * sizeof(struct Point));
for (int i = 0; i < n; i++) {
points[i].x = i;
points[i].y = i * 2;
}
free(points);
"#;
let rust_expected = r#"
struct Point { x: i32, y: i32 }
let mut points = vec![Point { x: 0, y: 0 }; n];
for i in 0..n {
points[i].x = i as i32;
points[i].y = (i * 2) as i32;
}
// Automatic deallocation
"#;
assert!(c_code.contains("struct Point*"));
assert!(c_code.contains("malloc(n * sizeof(struct Point))"));
assert!(rust_expected.contains("Vec<Point>") || rust_expected.contains("vec![Point"));
}
#[test]
fn test_realloc_to_vec_growth() {
let c_code = r#"
int* arr = malloc(10 * sizeof(int));
size_t capacity = 10;
// Later: need more space
arr = realloc(arr, 20 * sizeof(int));
capacity = 20;
free(arr);
"#;
let rust_expected = r#"
let mut arr = Vec::with_capacity(10);
// Later: need more space
arr.reserve(10); // Reserve additional 10 elements
// Automatic deallocation
"#;
assert!(c_code.contains("realloc(arr, 20 * sizeof(int))"));
assert!(rust_expected.contains("arr.reserve(10)"));
}
#[test]
fn test_malloc_2d_array_to_vec_vec() {
let c_code = r#"
int** matrix = malloc(rows * sizeof(int*));
for (int i = 0; i < rows; i++) {
matrix[i] = malloc(cols * sizeof(int));
}
// Use matrix...
for (int i = 0; i < rows; i++) {
free(matrix[i]);
}
free(matrix);
"#;
let rust_expected = r#"
let mut matrix = vec![vec![0i32; cols]; rows];
// Use matrix...
// Automatic deallocation (all rows and outer vec)
"#;
assert!(c_code.contains("int** matrix"));
assert!(c_code.contains("matrix[i] = malloc"));
assert!(rust_expected.contains("vec![vec![0i32; cols]; rows]"));
}
#[test]
fn test_malloc_array_assignment_to_vec() {
let c_code = r#"
int* arr1 = malloc(n * sizeof(int));
int* arr2 = arr1; // Both point to same memory
free(arr1); // arr2 is now dangling
"#;
let rust_expected = r#"
let arr1 = vec![0i32; n];
let arr2 = arr1; // arr1 moved, can't use arr1 anymore
// Or: let arr2 = arr1.clone(); to keep both
// Automatic deallocation when arr2 goes out of scope
"#;
assert!(c_code.contains("int* arr2 = arr1"));
assert!(rust_expected.contains("arr1 moved"));
assert!(rust_expected.contains("clone()"));
}
#[test]
fn test_malloc_array_parameter_to_slice() {
let c_code = r#"
void process_array(int* arr, size_t len) {
for (size_t i = 0; i < len; i++) {
arr[i] *= 2;
}
}
int* arr = malloc(n * sizeof(int));
process_array(arr, n);
free(arr);
"#;
let rust_expected = r#"
fn process_array(arr: &mut [i32]) {
for i in 0..arr.len() {
arr[i] *= 2;
}
}
let mut arr = vec![0i32; n];
process_array(&mut arr);
// Automatic deallocation
"#;
assert!(c_code.contains("void process_array(int* arr, size_t len)"));
assert!(rust_expected.contains("&mut [i32]"));
assert!(rust_expected.contains("arr.len()"));
}
#[test]
fn test_malloc_array_dynamic_growth() {
let c_code = r#"
int* arr = malloc(initial_capacity * sizeof(int));
size_t len = 0;
size_t capacity = initial_capacity;
for (int i = 0; i < n; i++) {
if (len >= capacity) {
capacity *= 2;
arr = realloc(arr, capacity * sizeof(int));
}
arr[len++] = i;
}
free(arr);
"#;
let rust_expected = r#"
let mut arr = Vec::with_capacity(initial_capacity);
for i in 0..n {
arr.push(i); // Automatically grows if needed
}
// Automatic deallocation
"#;
assert!(c_code.contains("realloc(arr, capacity * sizeof(int))"));
assert!(rust_expected.contains("arr.push(i)"));
assert!(rust_expected.contains("Automatically grows"));
}
#[test]
fn test_malloc_array_explicit_init() {
let c_code = r#"
int* arr = malloc(n * sizeof(int));
for (int i = 0; i < n; i++) {
arr[i] = 42;
}
free(arr);
"#;
let rust_expected = r#"
let arr = vec![42i32; n]; // Initialize all to 42
// Automatic deallocation
"#;
assert!(c_code.contains("arr[i] = 42"));
assert!(rust_expected.contains("vec![42i32; n]"));
}
#[test]
fn test_conditional_malloc_array_to_option_vec() {
let c_code = r#"
int* arr = NULL;
size_t len = 0;
if (condition) {
arr = malloc(n * sizeof(int));
len = n;
}
if (arr != NULL) {
free(arr);
}
"#;
let rust_expected = r#"
let arr: Option<Vec<i32>> = if condition {
Some(vec![0; n])
} else {
None
};
// Automatic deallocation if Some
"#;
assert!(c_code.contains("if (condition)"));
assert!(c_code.contains("if (arr != NULL)"));
assert!(rust_expected.contains("Option<Vec<i32>>"));
}
#[test]
fn test_malloc_pointer_array_to_vec_box() {
let c_code = r#"
int** ptrs = malloc(n * sizeof(int*));
for (int i = 0; i < n; i++) {
ptrs[i] = malloc(sizeof(int));
*ptrs[i] = i;
}
for (int i = 0; i < n; i++) {
free(ptrs[i]);
}
free(ptrs);
"#;
let rust_expected = r#"
let mut ptrs: Vec<Box<i32>> = Vec::with_capacity(n);
for i in 0..n {
let mut b = Box::new(0);
*b = i as i32;
ptrs.push(b);
}
// Automatic deallocation (all Boxes and Vec)
"#;
assert!(c_code.contains("int** ptrs"));
assert!(c_code.contains("ptrs[i] = malloc"));
assert!(rust_expected.contains("Vec<Box<i32>>"));
}
#[test]
fn test_malloc_buffer_to_vec() {
let c_code = r#"
char* buffer = malloc(BUFFER_SIZE);
read_data(buffer, BUFFER_SIZE);
free(buffer);
"#;
let rust_expected = r#"
let mut buffer = vec![0u8; BUFFER_SIZE];
read_data(&mut buffer);
// Automatic deallocation
"#;
assert!(c_code.contains("char* buffer = malloc(BUFFER_SIZE)"));
assert!(rust_expected.contains("vec![0u8; BUFFER_SIZE]"));
}
#[test]
fn test_malloc_array_transformation_summary() {
let c_code = r#"
// Rule 1: Basic malloc array → vec![]
int* arr = malloc(n * sizeof(int));
free(arr);
// Rule 2: calloc → vec![0; n]
calloc(n, sizeof(int));
// Rule 3: NULL check removed (Rust panics on OOM)
if (arr == NULL) { return -1; }
// Rule 4: Struct field → Vec field (no separate len)
struct Array { int* data; size_t len; };
// Rule 5: Return value → Vec<T>
int* create() { return malloc(n * sizeof(int)); }
// Rule 6: realloc → Vec::reserve or Vec::push
arr = realloc(arr, new_size);
// Rule 7: 2D array → Vec<Vec<T>>
int** matrix = malloc(rows * sizeof(int*));
// Rule 8: Assignment → move or clone
int* arr2 = arr1;
// Rule 9: Parameter → &[T] or &mut [T]
void process(int* arr, size_t len) { }
// Rule 10: Dynamic growth → Vec::push
arr[len++] = val;
"#;
let rust_expected = r#"
// Rule 1: Safe allocation
let arr = vec![0i32; n];
// Rule 2: Explicit zero-init
vec![0i32; n]
// Rule 3: Idiomatic error handling
// vec![] panics on OOM
// Rule 4: Built-in length
struct Array { data: Vec<i32> }
// Rule 5: Ownership transfer
fn create() -> Vec<i32> { vec![0; n] }
// Rule 6: Automatic resizing
arr.reserve(additional);
// Rule 7: Nested vectors
vec![vec![0; cols]; rows]
// Rule 8: Move or deep copy
let arr2 = arr1; // move
let arr2 = arr1.clone(); // copy
// Rule 9: Slice borrowing
fn process(arr: &[i32]) { }
// Rule 10: Automatic growth
arr.push(val)
"#;
assert!(c_code.contains("malloc(n * sizeof(int))"));
assert!(c_code.contains("free(arr)"));
assert!(c_code.contains("calloc"));
assert!(c_code.contains("realloc"));
assert!(rust_expected.contains("vec![0i32; n]"));
assert!(rust_expected.contains("arr.push"));
assert!(rust_expected.contains("clone()"));
assert!(rust_expected.contains("&[i32]"));
}
}