#![allow(clippy::unwrap_used)]
#![allow(clippy::expect_used)]
use super::makefile::emit_makefile;
use crate::ast::restricted::{Function, Literal, Type};
use crate::ast::{Expr, RestrictedAst, Stmt};
fn make_ast(stmts: Vec<Stmt>) -> RestrictedAst {
RestrictedAst {
functions: vec![Function {
name: "main".to_string(),
params: vec![],
return_type: Type::Void,
body: stmts,
}],
entry_point: "main".to_string(),
}
}
#[test]
fn test_MCOV_001_analyze_phony_line() {
let ast = make_ast(vec![Stmt::Expr(Expr::FunctionCall {
name: "rash_println".to_string(),
args: vec![Expr::Literal(Literal::Str(".PHONY: clean all".to_string()))],
})]);
let result = emit_makefile(&ast).unwrap();
assert!(result.contains(".PHONY"));
}
#[test]
fn test_MCOV_002_analyze_tab_prefixed_line() {
let ast = make_ast(vec![Stmt::Expr(Expr::FunctionCall {
name: "rash_println".to_string(),
args: vec![Expr::Literal(Literal::Str(
"\tgcc -o build main.c".to_string(),
))],
})]);
let result = emit_makefile(&ast).unwrap();
assert!(result.contains("gcc -o build main.c"));
}
#[test]
fn test_MCOV_003_analyze_simple_assignment() {
let ast = make_ast(vec![Stmt::Expr(Expr::FunctionCall {
name: "exec".to_string(),
args: vec![Expr::Literal(Literal::Str("CC := gcc".to_string()))],
})]);
let result = emit_makefile(&ast).unwrap();
assert!(result.contains("CC") && result.contains("gcc"));
}
#[test]
fn test_MCOV_004_analyze_target_line() {
let ast = make_ast(vec![Stmt::Expr(Expr::FunctionCall {
name: "exec".to_string(),
args: vec![Expr::Literal(Literal::Str("build: main.o".to_string()))],
})]);
let result = emit_makefile(&ast).unwrap();
assert!(result.contains("build"));
}
#[test]
fn test_MCOV_005_analyze_recursive_assignment() {
let ast = make_ast(vec![Stmt::Expr(Expr::FunctionCall {
name: "exec".to_string(),
args: vec![Expr::Literal(Literal::Str("CFLAGS = -O2".to_string()))],
})]);
let result = emit_makefile(&ast).unwrap();
assert!(result.contains("CFLAGS") || result.contains("-O2"));
}
#[test]
fn test_MCOV_006_analyze_comment_line() {
let ast = make_ast(vec![Stmt::Expr(Expr::FunctionCall {
name: "exec".to_string(),
args: vec![Expr::Literal(Literal::Str(
"just a comment line".to_string(),
))],
})]);
let result = emit_makefile(&ast).unwrap();
assert!(result.contains("just a comment line"));
}
#[test]
fn test_MCOV_007_target_with_empty_deps_via_exec() {
let ast = make_ast(vec![Stmt::Expr(Expr::FunctionCall {
name: "exec".to_string(),
args: vec![Expr::Literal(Literal::Str("all:".to_string()))],
})]);
let result = emit_makefile(&ast).unwrap();
assert!(result.contains("all"));
}
#[test]
fn test_MCOV_008_resolve_concat_i32_literal() {
let ast = make_ast(vec![Stmt::Expr(Expr::FunctionCall {
name: "rash_println".to_string(),
args: vec![Expr::Literal(Literal::I32(42))],
})]);
let result = emit_makefile(&ast).unwrap();
assert!(result.contains("42"));
}
#[test]
fn test_MCOV_009_resolve_concat_u16_literal() {
let ast = make_ast(vec![Stmt::Expr(Expr::FunctionCall {
name: "rash_println".to_string(),
args: vec![Expr::Literal(Literal::U16(8080))],
})]);
let result = emit_makefile(&ast).unwrap();
assert!(result.contains("8080"));
}
#[test]
fn test_MCOV_010_resolve_concat_u32_literal() {
let ast = make_ast(vec![Stmt::Expr(Expr::FunctionCall {
name: "rash_println".to_string(),
args: vec![Expr::Literal(Literal::U32(65536))],
})]);
let result = emit_makefile(&ast).unwrap();
assert!(result.contains("65536"));
}
#[test]
fn test_MCOV_011_resolve_concat_bool_literal() {
let ast = make_ast(vec![Stmt::Expr(Expr::FunctionCall {
name: "rash_println".to_string(),
args: vec![Expr::Literal(Literal::Bool(true))],
})]);
let result = emit_makefile(&ast).unwrap();
assert!(result.contains("true"));
}
#[test]
fn test_MCOV_012_resolve_concat_variable_without_binding() {
let ast = make_ast(vec![Stmt::Expr(Expr::FunctionCall {
name: "rash_println".to_string(),
args: vec![Expr::Variable("compiler".to_string())],
})]);
let result = emit_makefile(&ast).unwrap();
assert!(result.contains("$(COMPILER)"));
}
#[test]
fn test_MCOV_013_resolve_concat_variable_with_binding() {
let ast = make_ast(vec![
Stmt::Let {
name: "compiler".to_string(),
value: Expr::Literal(Literal::Str("clang".to_string())),
declaration: true,
},
Stmt::Expr(Expr::FunctionCall {
name: "rash_println".to_string(),
args: vec![Expr::Variable("compiler".to_string())],
}),
]);
let result = emit_makefile(&ast).unwrap();
assert!(result.contains("clang") || result.contains("COMPILER"));
}
#[test]
fn test_MCOV_014_resolve_concat_format_concat_call() {
let ast = make_ast(vec![Stmt::Expr(Expr::FunctionCall {
name: "rash_println".to_string(),
args: vec![Expr::FunctionCall {
name: "__format_concat".to_string(),
args: vec![
Expr::Literal(Literal::Str("hello".to_string())),
Expr::Literal(Literal::Str(" world".to_string())),
],
}],
})]);
let result = emit_makefile(&ast).unwrap();
assert!(result.contains("hello world"));
}
#[test]
fn test_MCOV_015_resolve_concat_unknown_expr_is_empty() {
let ast = make_ast(vec![Stmt::Expr(Expr::FunctionCall {
name: "rash_println".to_string(),
args: vec![Expr::Array(vec![])],
})]);
let result = emit_makefile(&ast);
assert!(result.is_ok());
}
#[test]
fn test_MCOV_016_expr_to_string_array_becomes_space_joined() {
let ast = make_ast(vec![Stmt::Let {
name: "files".to_string(),
value: Expr::Array(vec![
Expr::Literal(Literal::Str("a.c".to_string())),
Expr::Literal(Literal::Str("b.c".to_string())),
]),
declaration: true,
}]);
let result = emit_makefile(&ast).unwrap();
assert!(result.contains("a.c b.c") || result.contains("a.c") && result.contains("b.c"));
}
#[test]
fn test_MCOV_017_expr_to_string_binary_add() {
use crate::ast::restricted::BinaryOp;
let ast = make_ast(vec![Stmt::Let {
name: "result".to_string(),
value: Expr::Binary {
left: Box::new(Expr::Literal(Literal::I32(1))),
op: BinaryOp::Add,
right: Box::new(Expr::Literal(Literal::I32(2))),
},
declaration: true,
}]);
let result = emit_makefile(&ast).unwrap();
assert!(result.contains("shell echo") || result.contains("RESULT"));
}
#[test]
fn test_MCOV_018_expr_to_string_binary_sub() {
use crate::ast::restricted::BinaryOp;
let ast = make_ast(vec![Stmt::Let {
name: "diff".to_string(),
value: Expr::Binary {
left: Box::new(Expr::Literal(Literal::I32(10))),
op: BinaryOp::Sub,
right: Box::new(Expr::Literal(Literal::I32(3))),
},
declaration: true,
}]);
let result = emit_makefile(&ast).unwrap();
assert!(result.contains("DIFF") || result.contains("10"));
}
#[test]
fn test_MCOV_019_expr_to_string_binary_mul() {
use crate::ast::restricted::BinaryOp;
let ast = make_ast(vec![Stmt::Let {
name: "product".to_string(),
value: Expr::Binary {
left: Box::new(Expr::Literal(Literal::I32(4))),
op: BinaryOp::Mul,
right: Box::new(Expr::Literal(Literal::I32(5))),
},
declaration: true,
}]);
let result = emit_makefile(&ast).unwrap();
assert!(result.contains("PRODUCT") || result.contains("4"));
}
#[test]
fn test_MCOV_020_expr_to_string_binary_div() {
use crate::ast::restricted::BinaryOp;
let ast = make_ast(vec![Stmt::Let {
name: "quot".to_string(),
value: Expr::Binary {
left: Box::new(Expr::Literal(Literal::I32(20))),
op: BinaryOp::Div,
right: Box::new(Expr::Literal(Literal::I32(4))),
},
declaration: true,
}]);
let result = emit_makefile(&ast).unwrap();
assert!(result.contains("QUOT") || result.contains("20"));
}
#[test]
fn test_MCOV_021_expr_to_string_binary_other_op() {
use crate::ast::restricted::BinaryOp;
let ast = make_ast(vec![Stmt::Let {
name: "cmp".to_string(),
value: Expr::Binary {
left: Box::new(Expr::Literal(Literal::I32(1))),
op: BinaryOp::Eq,
right: Box::new(Expr::Literal(Literal::I32(1))),
},
declaration: true,
}]);
let result = emit_makefile(&ast).unwrap();
assert!(result.contains("CMP") || result.contains("1"));
}
#[test]
fn test_MCOV_022_expr_to_string_index_expr() {
let ast = make_ast(vec![Stmt::Let {
name: "item".to_string(),
value: Expr::Index {
object: Box::new(Expr::Variable("items".to_string())),
index: Box::new(Expr::Literal(Literal::I32(0))),
},
declaration: true,
}]);
let result = emit_makefile(&ast).unwrap();
assert!(result.contains("ITEM") || result.contains("word"));
}
#[test]
fn test_MCOV_023_rash_print_no_newline() {
let ast = make_ast(vec![Stmt::Expr(Expr::FunctionCall {
name: "rash_print".to_string(),
args: vec![Expr::Literal(Literal::Str("no newline".to_string()))],
})]);
let result = emit_makefile(&ast).unwrap();
assert!(result.contains("no newline"));
}
#[test]
include!("makefile_coverage_tests_tests_MCOV.rs");