use decy_codegen::CodeGenerator;
use decy_hir::{HirFunction, HirParameter, HirStatement, HirType};
use decy_ownership::dataflow::DataflowAnalyzer;
fn create_array_param_function(name: &str, param_name: &str, len_param_name: &str) -> HirFunction {
let params = vec![
HirParameter::new(
param_name.to_string(),
HirType::Pointer(Box::new(HirType::Int)),
),
HirParameter::new(len_param_name.to_string(), HirType::Int),
];
HirFunction::new(name.to_string(), HirType::Void, params)
}
#[test]
fn test_int_array_parameter_transformed_to_slice() {
let func = create_array_param_function("process", "arr", "len");
let codegen = CodeGenerator::new();
let rust_code = codegen.generate_function(&func);
assert!(
rust_code.contains("arr: &[i32]") || rust_code.contains("arr: &mut [i32]"),
"Expected slice parameter, got: {}",
rust_code
);
assert!(
!rust_code.contains("*mut i32") && !rust_code.contains("*const i32"),
"Should not use raw pointers for array parameters, got: {}",
rust_code
);
assert!(
!rust_code.contains("len: i32"),
"Should not include redundant length parameter, got: {}",
rust_code
);
}
#[test]
fn test_char_buffer_parameter_transformed_to_u8_slice() {
let params = vec![
HirParameter::new("buf".to_string(), HirType::Pointer(Box::new(HirType::Char))),
HirParameter::new("size".to_string(), HirType::Int),
];
let func = HirFunction::new("read_buffer".to_string(), HirType::Void, params);
let codegen = CodeGenerator::new();
let rust_code = codegen.generate_function(&func);
assert!(
rust_code.contains("buf: &[u8]") || rust_code.contains("buf: &mut [u8]"),
"Expected u8 slice parameter, got: {}",
rust_code
);
assert!(
!rust_code.contains("size: i32"),
"Should not include redundant size parameter, got: {}",
rust_code
);
}
#[test]
fn test_mutable_array_parameter_uses_mut_slice() {
use decy_hir::HirExpression;
let params = vec![
HirParameter::new("arr".to_string(), HirType::Pointer(Box::new(HirType::Int))),
HirParameter::new("len".to_string(), HirType::Int),
];
let body = vec![HirStatement::ArrayIndexAssignment {
array: Box::new(HirExpression::Variable("arr".to_string())),
index: Box::new(HirExpression::IntLiteral(0)),
value: HirExpression::IntLiteral(42),
}];
let func = HirFunction::new_with_body("modify_array".to_string(), HirType::Void, params, body);
let codegen = CodeGenerator::new();
let rust_code = codegen.generate_function(&func);
assert!(
rust_code.contains("arr: &mut [i32]"),
"Expected mutable slice for modified array, got: {}",
rust_code
);
}
#[test]
fn test_array_length_usage_transformed_to_len_method() {
use decy_hir::HirExpression;
let params = vec![
HirParameter::new("arr".to_string(), HirType::Pointer(Box::new(HirType::Int))),
HirParameter::new("len".to_string(), HirType::Int),
];
let body = vec![HirStatement::Return(Some(HirExpression::Variable(
"len".to_string(),
)))];
let func = HirFunction::new_with_body("get_length".to_string(), HirType::Int, params, body);
let codegen = CodeGenerator::new();
let rust_code = codegen.generate_function(&func);
assert!(
rust_code.contains("arr.len()"),
"Expected arr.len() call, got: {}",
rust_code
);
assert!(
!rust_code.contains("len") || rust_code.contains(".len()"),
"Should not use len parameter, got: {}",
rust_code
);
}
#[test]
fn test_pointer_without_length_not_transformed() {
let params = vec![HirParameter::new(
"ptr".to_string(),
HirType::Pointer(Box::new(HirType::Int)),
)];
let func = HirFunction::new("process".to_string(), HirType::Void, params);
let codegen = CodeGenerator::new();
let rust_code = codegen.generate_function(&func);
assert!(
!rust_code.contains("&[i32]") && !rust_code.contains("&mut [i32]"),
"Should not transform pointer without length to slice, got: {}",
rust_code
);
}
#[test]
fn test_array_parameter_detection_by_name_pattern() {
let params = vec![
HirParameter::new(
"array".to_string(),
HirType::Pointer(Box::new(HirType::Int)),
),
HirParameter::new("count".to_string(), HirType::Int),
];
let func = HirFunction::new("sum_array".to_string(), HirType::Int, params);
let codegen = CodeGenerator::new();
let rust_code = codegen.generate_function(&func);
assert!(
rust_code.contains("array: &[i32]") || rust_code.contains("array: &mut [i32]"),
"Expected slice parameter for 'array' name, got: {}",
rust_code
);
}
#[test]
fn test_buffer_parameter_detection_by_name_pattern() {
let params = vec![
HirParameter::new(
"buffer".to_string(),
HirType::Pointer(Box::new(HirType::Char)),
),
HirParameter::new("length".to_string(), HirType::Int),
];
let func = HirFunction::new("process_buffer".to_string(), HirType::Void, params);
let codegen = CodeGenerator::new();
let rust_code = codegen.generate_function(&func);
assert!(
rust_code.contains("buffer: &[u8]") || rust_code.contains("buffer: &mut [u8]"),
"Expected slice parameter for 'buffer' name, got: {}",
rust_code
);
}
#[test]
fn test_dataflow_analysis_detects_array_parameters() {
let params = vec![
HirParameter::new("data".to_string(), HirType::Pointer(Box::new(HirType::Int))),
HirParameter::new("size".to_string(), HirType::Int),
];
let func = HirFunction::new("process_data".to_string(), HirType::Void, params);
let analyzer = DataflowAnalyzer::new();
let graph = analyzer.analyze(&func);
let is_array = graph.is_array_parameter("data");
assert_eq!(
is_array,
Some(true),
"DataflowAnalyzer should detect 'data' as array parameter"
);
}
#[test]
fn test_multiple_array_parameters_all_transformed() {
let params = vec![
HirParameter::new("a".to_string(), HirType::Pointer(Box::new(HirType::Int))),
HirParameter::new("len_a".to_string(), HirType::Int),
HirParameter::new("b".to_string(), HirType::Pointer(Box::new(HirType::Int))),
HirParameter::new("len_b".to_string(), HirType::Int),
];
let func = HirFunction::new("merge".to_string(), HirType::Void, params);
let codegen = CodeGenerator::new();
let rust_code = codegen.generate_function(&func);
assert!(
rust_code.contains("a: &[i32]") || rust_code.contains("a: &mut [i32]"),
"Expected 'a' to be slice, got: {}",
rust_code
);
assert!(
rust_code.contains("b: &[i32]") || rust_code.contains("b: &mut [i32]"),
"Expected 'b' to be slice, got: {}",
rust_code
);
assert!(
!rust_code.contains("len_a") && !rust_code.contains("len_b"),
"Should not have length parameters, got: {}",
rust_code
);
}
#[test]
fn test_float_array_parameter_transformed() {
let params = vec![
HirParameter::new(
"values".to_string(),
HirType::Pointer(Box::new(HirType::Float)),
),
HirParameter::new("num_values".to_string(), HirType::Int),
];
let func = HirFunction::new("process_floats".to_string(), HirType::Void, params);
let codegen = CodeGenerator::new();
let rust_code = codegen.generate_function(&func);
assert!(
rust_code.contains("values: &[f32]") || rust_code.contains("values: &mut [f32]"),
"Expected f32 slice parameter, got: {}",
rust_code
);
}