use decy_core::transpile;
#[test]
fn test_strlen_transpilation() {
let c_code = r#"
#include <string.h>
int get_length(const char* str) {
return strlen(str);
}
int main() {
const char* message = "Hello, World!";
int len = get_length(message);
return len;
}
"#;
let result = transpile(c_code).expect("Transpilation should succeed");
assert!(
!result.contains("unsafe"),
"String length should be safe (use .len())"
);
assert!(
result.contains(".len()"),
"Should use safe Rust .len() method"
);
assert!(result.contains("fn get_length"), "Should generate function");
assert!(result.contains("fn main"), "Should generate main");
}
#[test]
fn test_strcpy_transpilation_to_string_copy() {
let c_code = r#"
#include <string.h>
void copy_string(char* dest, const char* src) {
strcpy(dest, src);
}
int main() {
char buffer[100];
copy_string(buffer, "Safe in Rust!");
return 0;
}
"#;
let result = transpile(c_code).expect("Transpilation should succeed");
let unsafe_count = result.matches("unsafe").count();
assert!(
unsafe_count <= 2,
"strcpy should minimize unsafe (found {})",
unsafe_count
);
assert!(
result.contains("fn copy_string"),
"Should generate function"
);
}
#[test]
fn test_strcat_transpilation_to_string_concatenation() {
let c_code = r#"
#include <string.h>
void append_string(char* dest, const char* src) {
strcat(dest, src);
}
int main() {
char buffer[200];
strcpy(buffer, "Hello, ");
append_string(buffer, "Rust!");
return 0;
}
"#;
let result = transpile(c_code).expect("Transpilation should succeed");
let unsafe_count = result.matches("unsafe").count();
assert!(
unsafe_count <= 3,
"strcat should minimize unsafe (found {})",
unsafe_count
);
assert!(
result.contains("fn append_string"),
"Should generate function"
);
}
#[test]
fn test_string_literal_transpilation() {
let c_code = r#"
int main() {
const char* greeting = "Hello, World!";
const char* farewell = "Goodbye!";
return 0;
}
"#;
let result = transpile(c_code).expect("Transpilation should succeed");
assert!(
!result.contains("unsafe") || result.matches("unsafe").count() <= 1,
"String literals should be mostly safe"
);
assert!(
result.contains("Hello, World!"),
"Should preserve string literal"
);
assert!(
result.contains("Goodbye!"),
"Should preserve string literal"
);
}
#[test]
fn test_strcmp_transpilation_to_eq() {
let c_code = r#"
#include <string.h>
int are_equal(const char* s1, const char* s2) {
return strcmp(s1, s2) == 0;
}
int main() {
const char* a = "test";
const char* b = "test";
int equal = are_equal(a, b);
return equal;
}
"#;
let result = transpile(c_code).expect("Transpilation should succeed");
assert!(result.contains("fn are_equal"), "Should generate function");
let unsafe_count = result.matches("unsafe").count();
assert!(
unsafe_count <= 2,
"String comparison should minimize unsafe (found {})",
unsafe_count
);
}
#[test]
fn test_null_string_handling() {
let c_code = r#"
#include <string.h>
int check_null(const char* str) {
if (str == 0) {
return 0;
}
return strlen(str);
}
int main() {
const char* valid_str = "test";
int len = check_null(valid_str);
return len;
}
"#;
let result = transpile(c_code).expect("Transpilation should succeed");
assert!(result.contains("fn check_null"), "Should generate function");
assert!(result.contains("fn main"), "Should generate main");
}
#[test]
fn test_empty_string_handling() {
let c_code = r#"
#include <string.h>
int main() {
const char* empty = "";
int len = strlen(empty);
return len;
}
"#;
let result = transpile(c_code).expect("Transpilation should succeed");
assert!(!result.is_empty(), "Should generate code");
assert!(result.contains("fn main"), "Should generate main");
}
#[test]
fn test_unsafe_block_count_target() {
let c_code = r#"
#include <string.h>
int main() {
const char* str1 = "Hello";
const char* str2 = "World";
int len1 = strlen(str1);
int len2 = strlen(str2);
return len1 + len2;
}
"#;
let result = transpile(c_code).expect("Transpilation should succeed");
let unsafe_count = result.matches("unsafe").count();
let lines_of_code = result.lines().count();
let unsafe_per_1000 = if lines_of_code > 0 {
(unsafe_count as f64 / lines_of_code as f64) * 1000.0
} else {
0.0
};
assert!(
unsafe_per_1000 < 5.0,
"Unsafe blocks per 1000 LOC should be <5 (got {:.2})",
unsafe_per_1000
);
}
#[test]
fn test_transpiled_rust_compiles() {
let c_code = r#"
#include <string.h>
int main() {
const char* message = "Decy transpiler";
int length = strlen(message);
return length;
}
"#;
let result = transpile(c_code).expect("Transpilation should succeed");
assert!(!result.is_empty(), "Should generate non-empty code");
assert!(result.contains("fn main"), "Should have main function");
assert!(
!result.contains("}}}}"),
"Should not have excessive closing braces"
);
assert!(
!result.contains(";;;;"),
"Should not have excessive semicolons"
);
}
#[test]
fn test_string_safety_documentation() {
let c_code = r#"
#include <string.h>
char* get_string() {
static char buffer[100] = "Static string";
return buffer;
}
int main() {
char* str = get_string();
int len = strlen(str);
return len;
}
"#;
let result = transpile(c_code).expect("Transpilation should succeed");
if result.contains("unsafe") {
assert!(result.contains("fn get_string"), "Should generate function");
}
}