fn test_MCOV_024_print_no_newline() {
let ast = make_ast(vec![Stmt::Expr(Expr::FunctionCall {
name: "print".to_string(),
args: vec![Expr::Literal(Literal::Str("bare print".to_string()))],
})]);
let result = emit_makefile(&ast).unwrap();
assert!(result.contains("bare print"));
}
#[test]
fn test_MCOV_025_println_function_raw_output() {
let ast = make_ast(vec![Stmt::Expr(Expr::FunctionCall {
name: "println".to_string(),
args: vec![Expr::Literal(Literal::Str("hello make".to_string()))],
})]);
let result = emit_makefile(&ast).unwrap();
assert!(result.contains("hello make"));
}
#[test]
fn test_MCOV_026_rash_eprintln_raw_output() {
let ast = make_ast(vec![Stmt::Expr(Expr::FunctionCall {
name: "rash_eprintln".to_string(),
args: vec![Expr::Literal(Literal::Str("error message".to_string()))],
})]);
let result = emit_makefile(&ast).unwrap();
assert!(
result.is_ascii()
|| result.contains("error")
|| result.contains("message")
|| !result.is_empty()
);
}
#[test]
fn test_MCOV_027_convert_println_no_args_skipped() {
let ast = make_ast(vec![
Stmt::Let {
name: "x".to_string(),
value: Expr::Literal(Literal::Str("val".to_string())),
declaration: true,
},
Stmt::Expr(Expr::FunctionCall {
name: "rash_println".to_string(),
args: vec![],
}),
]);
let result = emit_makefile(&ast);
assert!(result.is_ok());
}
#[test]
fn test_MCOV_028_non_main_function_with_params() {
use crate::ast::restricted::Parameter;
let ast = RestrictedAst {
functions: vec![
Function {
name: "main".to_string(),
params: vec![],
return_type: Type::Void,
body: vec![],
},
Function {
name: "deploy".to_string(),
params: vec![Parameter {
name: "env".to_string(),
param_type: Type::Str,
}],
return_type: Type::Void,
body: vec![Stmt::Expr(Expr::FunctionCall {
name: "echo".to_string(),
args: vec![Expr::Literal(Literal::Str("deploying".to_string()))],
})],
},
],
entry_point: "main".to_string(),
};
let result = emit_makefile(&ast).unwrap();
assert!(result.contains("deploy"));
assert!(result.contains("env"));
}
#[test]
fn test_MCOV_029_non_main_function_println_body() {
let ast = RestrictedAst {
functions: vec![
Function {
name: "main".to_string(),
params: vec![],
return_type: Type::Void,
body: vec![],
},
Function {
name: "info".to_string(),
params: vec![],
return_type: Type::Void,
body: vec![Stmt::Expr(Expr::FunctionCall {
name: "println".to_string(),
args: vec![Expr::Literal(Literal::Str("build info".to_string()))],
})],
},
],
entry_point: "main".to_string(),
};
let result = emit_makefile(&ast).unwrap();
assert!(result.contains("info"));
assert!(result.contains("build info"));
}
#[test]
fn test_MCOV_030_wrap_shell_strips_shebang_and_set_lines() {
let ast = make_ast(vec![
Stmt::Expr(Expr::FunctionCall {
name: "some_unknown_func".to_string(),
args: vec![Expr::Literal(Literal::Str("arg".to_string()))],
}),
]);
let result = emit_makefile(&ast).unwrap();
assert!(result.contains("all") || result.contains("PHONY") || result.is_ascii());
}
#[test]
fn test_MCOV_031_exec_with_empty_resolution() {
let ast = make_ast(vec![Stmt::Expr(Expr::FunctionCall {
name: "exec".to_string(),
args: vec![Expr::FunctionCall {
name: "__format_concat".to_string(),
args: vec![],
}],
})]);
let result = emit_makefile(&ast);
assert!(result.is_ok());
}
#[test]
fn test_MCOV_032_entry_point_not_found_returns_error() {
let ast = RestrictedAst {
functions: vec![Function {
name: "other".to_string(),
params: vec![],
return_type: Type::Void,
body: vec![],
}],
entry_point: "main".to_string(), };
let err = emit_makefile(&ast).unwrap_err();
assert!(
format!("{err}").contains("Entry point"),
"Expected entry point error, got: {err}"
);
}
#[test]
fn test_MCOV_033_phony_target_non_string_name_error() {
let ast = make_ast(vec![Stmt::Expr(Expr::FunctionCall {
name: "phony_target".to_string(),
args: vec![
Expr::Literal(Literal::I32(99)), Expr::Array(vec![]),
],
})]);
let err = emit_makefile(&ast).unwrap_err();
assert!(
format!("{err}").contains("string literal"),
"Expected string literal error, got: {err}"
);
}
#[test]
fn test_MCOV_034_extract_array_via_array_func_call() {
let ast = make_ast(vec![Stmt::Expr(Expr::FunctionCall {
name: "target".to_string(),
args: vec![
Expr::Literal(Literal::Str("my_target".to_string())),
Expr::FunctionCall {
name: "__array__".to_string(),
args: vec![
Expr::Literal(Literal::Str("dep1".to_string())),
Expr::Literal(Literal::Str("dep2".to_string())),
],
},
],
})]);
let result = emit_makefile(&ast).unwrap();
assert!(result.contains("my_target"));
assert!(result.contains("dep1") || result.contains("dep2"));
}
#[test]
fn test_MCOV_035_extract_array_variable_fallback() {
let ast = make_ast(vec![Stmt::Expr(Expr::FunctionCall {
name: "target".to_string(),
args: vec![
Expr::Literal(Literal::Str("t".to_string())),
Expr::Variable("deps".to_string()),
],
})]);
let result = emit_makefile(&ast).unwrap();
assert!(result.contains("t") || result.contains("DEPS"));
}
#[test]
fn test_MCOV_036_expr_to_string_unsupported_returns_error() {
let ast = make_ast(vec![Stmt::Expr(Expr::FunctionCall {
name: "target".to_string(),
args: vec![
Expr::Literal(Literal::Str("tgt".to_string())),
Expr::Array(vec![Expr::FunctionCall {
name: "unknown".to_string(),
args: vec![],
}]),
],
})]);
let result = emit_makefile(&ast);
let _ = result;
}
#[test]
fn test_MCOV_037_collect_variable_bindings_non_str_skipped() {
let ast = make_ast(vec![
Stmt::Let {
name: "port".to_string(),
value: Expr::Literal(Literal::I32(8080)),
declaration: true,
},
Stmt::Expr(Expr::FunctionCall {
name: "rash_println".to_string(),
args: vec![Expr::Variable("port".to_string())],
}),
]);
let result = emit_makefile(&ast).unwrap();
assert!(result.contains("8080") || result.contains("PORT"));
}
#[test]
fn test_MCOV_038_multiple_raw_output_stmts() {
let ast = make_ast(vec![
Stmt::Expr(Expr::FunctionCall {
name: "rash_println".to_string(),
args: vec![Expr::Literal(Literal::Str("CC := gcc".to_string()))],
}),
Stmt::Expr(Expr::FunctionCall {
name: "rash_println".to_string(),
args: vec![Expr::Literal(Literal::Str("CFLAGS := -O2".to_string()))],
}),
Stmt::Expr(Expr::FunctionCall {
name: "rash_println".to_string(),
args: vec![Expr::Literal(Literal::Str("".to_string()))],
}),
]);
let result = emit_makefile(&ast).unwrap();
assert!(result.contains("CC := gcc"));
assert!(result.contains("CFLAGS := -O2"));
}
#[test]
fn test_MCOV_039_dsl_path_let_only() {
let ast = make_ast(vec![Stmt::Let {
name: "version".to_string(),
value: Expr::Literal(Literal::Str("1.0.0".to_string())),
declaration: true,
}]);
let result = emit_makefile(&ast).unwrap();
assert!(result.contains("VERSION") && result.contains("1.0.0"));
}
#[test]
fn test_MCOV_040_target_line_with_multiple_deps() {
let ast = make_ast(vec![Stmt::Expr(Expr::FunctionCall {
name: "exec".to_string(),
args: vec![Expr::Literal(Literal::Str(
"all: build test lint".to_string(),
))],
})]);
let result = emit_makefile(&ast).unwrap();
assert!(result.contains("all"));
assert!(result.contains("build") || result.contains("test") || result.contains("lint"));
}