#[cfg(test)]
mod tests {
#[test]
fn test_simple_const_variable() {
let c_code = r#"
const int x = 5;
"#;
let rust_expected = r#"
let x: i32 = 5;
"#;
assert!(c_code.contains("const int x"));
assert!(rust_expected.contains("let x: i32"));
}
#[test]
fn test_compile_time_const() {
let c_code = r#"
const int MAX = 100;
"#;
let rust_expected = r#"
const MAX: i32 = 100;
"#;
assert!(c_code.contains("const int MAX"));
assert!(rust_expected.contains("const MAX: i32"));
}
#[test]
fn test_pointer_to_const() {
let c_code = r#"
const int* p;
"#;
let rust_expected = r#"
let p: &i32;
"#;
assert!(c_code.contains("const int* p"));
assert!(rust_expected.contains("&i32"));
}
#[test]
fn test_const_pointer() {
let c_code = r#"
int* const p = &x;
"#;
let rust_expected = r#"
let p: &mut i32 = &mut x;
"#;
assert!(c_code.contains("int* const p"));
assert!(rust_expected.contains("let p: &mut i32"));
}
#[test]
fn test_const_pointer_to_const() {
let c_code = r#"
const int* const p;
"#;
let rust_expected = r#"
let p: &i32;
"#;
assert!(c_code.contains("const int* const p"));
assert!(rust_expected.contains("&i32"));
}
#[test]
fn test_const_parameter() {
let c_code = r#"
void process(const int* data);
"#;
let rust_expected = r#"
fn process(data: &i32);
"#;
assert!(c_code.contains("const int* data"));
assert!(rust_expected.contains("data: &i32"));
}
#[test]
fn test_const_return() {
let c_code = r#"
const int* get_data(void);
"#;
let rust_expected = r#"
fn get_data() -> &i32;
"#;
assert!(c_code.contains("const int* get_data"));
assert!(rust_expected.contains("-> &i32"));
}
#[test]
fn test_const_array() {
let c_code = r#"
const int arr[5] = {1, 2, 3, 4, 5};
"#;
let rust_expected = r#"
let arr: [i32; 5] = [1, 2, 3, 4, 5];
"#;
assert!(c_code.contains("const int arr[5]"));
assert!(rust_expected.contains("let arr: [i32; 5]"));
}
#[test]
fn test_const_struct() {
let c_code = r#"
const struct Point p = {10, 20};
"#;
let rust_expected = r#"
let p: Point = Point { x: 10, y: 20 };
"#;
assert!(c_code.contains("const struct Point p"));
assert!(rust_expected.contains("let p: Point"));
}
#[test]
fn test_const_with_expression() {
let c_code = r#"
const int result = a + b * 2;
"#;
let rust_expected = r#"
let result: i32 = a + b * 2;
"#;
assert!(c_code.contains("const int result = a + b * 2"));
assert!(rust_expected.contains("let result: i32 = a + b * 2"));
}
#[test]
fn test_const_local_variable() {
let c_code = r#"
void func(void) {
const int limit = 100;
}
"#;
let rust_expected = r#"
fn func() {
let limit: i32 = 100;
}
"#;
assert!(c_code.contains("const int limit"));
assert!(rust_expected.contains("let limit: i32"));
}
#[test]
fn test_const_char_pointer() {
let c_code = r#"
const char* str = "hello";
"#;
let rust_expected = r#"
let str: &str = "hello";
"#;
assert!(c_code.contains("const char* str"));
assert!(rust_expected.contains("&str"));
}
#[test]
fn test_array_of_const_pointers() {
let c_code = r#"
const int* arr[3];
"#;
let rust_expected = r#"
let arr: [&i32; 3];
"#;
assert!(c_code.contains("const int* arr[3]"));
assert!(rust_expected.contains("[&i32; 3]"));
}
#[test]
fn test_const_vs_define() {
let c_code = r#"
#define MAX 100
// Or: const int MAX = 100;
"#;
let rust_expected = r#"
const MAX: i32 = 100;
"#;
assert!(c_code.contains("#define MAX 100"));
assert!(rust_expected.contains("const MAX: i32"));
}
#[test]
fn test_const_volatile() {
let c_code = r#"
const volatile int* reg;
"#;
let rust_expected = r#"
let reg: *const i32; // Raw pointer, volatile via ptr::read_volatile
"#;
assert!(c_code.contains("const volatile int*"));
assert!(rust_expected.contains("*const i32"));
}
#[test]
fn test_const_qualifier_transformation_summary() {
let c_code = r#"
// Rule 1: const variable → let (immutable by default)
const int x = 5;
// Rule 2: Compile-time const → const
const int MAX = 100;
// Rule 3: Pointer to const → &T
const int* p1;
// Rule 4: Const pointer → let binding (cannot rebind)
int* const p2 = &x;
// Rule 5: Const pointer to const → &T
const int* const p3;
// Rule 6: const parameter → &T
void process(const int* data);
// Rule 7: const return → &T
const int* get_data(void);
// Rule 8: const array → let array
const int arr[5] = {1, 2, 3, 4, 5};
// Rule 9: const struct → let struct
const struct Point p = {10, 20};
// Rule 10: const with expression
const int result = a + b;
// Rule 11: const char* (string) → &str
const char* str = "hello";
// Rule 12: Array of const pointers
const int* ptrs[3];
// Rule 13: #define → const
#define LIMIT 100
// Rule 14: const volatile → *const T
const volatile int* reg;
"#;
let rust_expected = r#"
// Rule 1: Immutable by default (let)
let x: i32 = 5;
// Rule 2: Compile-time constant (const)
const MAX: i32 = 100;
// Rule 3: Immutable reference
let p1: &i32;
// Rule 4: Cannot rebind (let, no mut)
let p2: &mut i32 = &mut x;
// Rule 5: Both immutable
let p3: &i32;
// Rule 6: Immutable reference parameter
fn process(data: &i32);
// Rule 7: Immutable reference return
fn get_data() -> &i32;
// Rule 8: Immutable array
let arr: [i32; 5] = [1, 2, 3, 4, 5];
// Rule 9: Immutable struct
let p: Point = Point { x: 10, y: 20 };
// Rule 10: Let with expression
let result: i32 = a + b;
// Rule 11: String slice
let str: &str = "hello";
// Rule 12: Array of references
let ptrs: [&i32; 3];
// Rule 13: Type-safe constant
const LIMIT: i32 = 100;
// Rule 14: Raw pointer (volatile via methods)
let reg: *const i32;
"#;
assert!(c_code.contains("const int x = 5"));
assert!(rust_expected.contains("let x: i32 = 5"));
assert!(c_code.contains("const int MAX = 100"));
assert!(rust_expected.contains("const MAX: i32 = 100"));
assert!(c_code.contains("const int* p1"));
assert!(rust_expected.contains("&i32"));
assert!(c_code.contains("int* const p2"));
assert!(rust_expected.contains("let p2: &mut i32"));
assert!(c_code.contains("const char* str"));
assert!(rust_expected.contains("&str"));
assert!(c_code.contains("#define LIMIT 100"));
assert!(rust_expected.contains("const LIMIT: i32"));
}
}