#[test]
fn test_REPRODUCIBLE_003_detect_random() {
let makefile = r#"
SESSION_ID := session-$$RANDOM
test:
echo "Session: $(SESSION_ID)"
"#;
let ast = crate::make_parser::parser::parse_makefile(makefile).unwrap();
let result = purify_makefile(&ast);
assert!(
result.report.iter().any(|r| r.contains("RANDOM")
|| r.contains("random")
|| r.contains("non-deterministic")),
"Should detect non-deterministic $RANDOM variable"
);
}
#[test]
fn test_REPRODUCIBLE_004_detect_process_id() {
let makefile = r#"
TMP_FILE := /tmp/build-$$$$
build:
touch $(TMP_FILE)
gcc -o app main.c
rm $(TMP_FILE)
"#;
let ast = crate::make_parser::parser::parse_makefile(makefile).unwrap();
let result = purify_makefile(&ast);
assert!(
result
.report
.iter()
.any(|r| r.contains("process") || r.contains("$$") || r.contains("PID")),
"Should detect non-deterministic process ID $$"
);
}
#[test]
fn test_REPRODUCIBLE_005_suggest_source_date_epoch() {
let makefile = r#"
BUILD_DATE := $(shell date)
package:
echo "Built on: $(BUILD_DATE)" > version.txt
"#;
let ast = crate::make_parser::parser::parse_makefile(makefile).unwrap();
let result = purify_makefile(&ast);
assert!(
result
.report
.iter()
.any(|r| r.contains("SOURCE_DATE_EPOCH")),
"Should suggest using SOURCE_DATE_EPOCH for reproducibility"
);
}
#[test]
fn test_REPRODUCIBLE_006_detect_command_substitution() {
let makefile = r#"
HOSTNAME := $(shell hostname)
config:
echo "Host: $(HOSTNAME)" > config.txt
"#;
let ast = crate::make_parser::parser::parse_makefile(makefile).unwrap();
let result = purify_makefile(&ast);
assert!(
result.report.iter().any(|r| r.contains("hostname")
|| r.contains("environment")
|| r.contains("deterministic")),
"Should detect environment-dependent hostname"
);
}
#[test]
fn test_REPRODUCIBLE_007_preserve_deterministic() {
let makefile = r#"
BUILD_DATE := $(SOURCE_DATE_EPOCH)
build:
echo "Build: $(BUILD_DATE)"
"#;
let ast = crate::make_parser::parser::parse_makefile(makefile).unwrap();
let result = purify_makefile(&ast);
let _ = result.transformations_applied; }
#[test]
fn test_REPRODUCIBLE_008_detect_git_timestamp() {
let makefile = r#"
GIT_DATE := $(shell git log -1 --format=%cd)
version:
echo "Git date: $(GIT_DATE)" > version.txt
"#;
let ast = crate::make_parser::parser::parse_makefile(makefile).unwrap();
let result = purify_makefile(&ast);
assert!(
result
.report
.iter()
.any(|r| r.contains("git") || r.contains("timestamp") || r.contains("deterministic")),
"Should detect git commit timestamp"
);
}
#[test]
fn test_REPRODUCIBLE_009_detect_mktemp() {
let makefile = r#"
build:
TMP=$$(mktemp); \
gcc -o $$TMP main.c; \
cp $$TMP app
"#;
let ast = crate::make_parser::parser::parse_makefile(makefile).unwrap();
let result = purify_makefile(&ast);
assert!(
result
.report
.iter()
.any(|r| r.contains("mktemp") || r.contains("temp") || r.contains("deterministic")),
"Should detect non-deterministic mktemp usage"
);
}
#[test]
fn test_REPRODUCIBLE_010_comprehensive_check() {
let makefile = r#"
VERSION := $(shell date +%Y%m%d)
SESSION := $$RANDOM
BUILD_HOST := $(shell hostname)
all: build
build:
echo "Version: $(VERSION)" > version.txt
echo "Session: $(SESSION)" >> version.txt
echo "Host: $(BUILD_HOST)" >> version.txt
gcc -o app main.c
"#;
let ast = crate::make_parser::parser::parse_makefile(makefile).unwrap();
let result = purify_makefile(&ast);
assert!(
result.transformations_applied >= 3,
"Should detect at least 3 reproducibility issues (date, RANDOM, hostname)"
);
}
#[test]
fn test_PERFORMANCE_001_detect_multiple_shell_invocations() {
let makefile = r#"
build:
mkdir -p bin
gcc -c main.c -o bin/main.o
gcc -c util.c -o bin/util.o
gcc bin/main.o bin/util.o -o bin/app
"#;
let ast = crate::make_parser::parser::parse_makefile(makefile).unwrap();
let result = purify_makefile(&ast);
assert!(
result
.report
.iter()
.any(|r| r.contains("combine") || r.contains("shell") || r.contains("performance")),
"Should detect multiple shell invocations that could be combined"
);
}
#[test]
fn test_PERFORMANCE_002_suggest_simple_expansion() {
let makefile = r#"
CC = gcc
CFLAGS = -Wall -O2
LDFLAGS = -lm
build:
$(CC) $(CFLAGS) main.c $(LDFLAGS) -o app
"#;
let ast = crate::make_parser::parser::parse_makefile(makefile).unwrap();
let result = purify_makefile(&ast);
assert!(
result
.report
.iter()
.any(|r| r.contains(":=") || r.contains("simple") || r.contains("expansion")),
"Should suggest using := instead of = for simple variables"
);
}
#[test]
fn test_PERFORMANCE_003_detect_missing_suffixes() {
let makefile = r#"
VERSION = $(shell git describe)
all: app
app: main.o
gcc main.o -o app
main.o: main.c
gcc -c main.c
"#;
let ast = crate::make_parser::parser::parse_makefile(makefile).unwrap();
let result = purify_makefile(&ast);
assert!(
result
.report
.iter()
.any(|r| r.contains(".SUFFIXES") || r.contains("builtin") || r.contains("performance")),
"Should recommend adding .SUFFIXES: when performance issues detected"
);
}
#[test]
fn test_PERFORMANCE_004_detect_inefficient_expansion() {
let makefile = r#"
VERSION = $(shell git describe --tags)
build:
echo "Building $(VERSION)"
tar -czf myapp-$(VERSION).tar.gz src/
echo "Created myapp-$(VERSION).tar.gz"
"#;
let ast = crate::make_parser::parser::parse_makefile(makefile).unwrap();
let result = purify_makefile(&ast);
assert!(
result
.report
.iter()
.any(|r| r.contains(":=") || r.contains("expansion") || r.contains("shell")),
"Should suggest := to avoid re-expanding $(shell) multiple times"
);
}
#[test]
fn test_PERFORMANCE_005_preserve_existing_suffixes() {
let makefile = r#"
.SUFFIXES:
all: app
app: main.c
gcc main.c -o app
"#;
let ast = crate::make_parser::parser::parse_makefile(makefile).unwrap();
let result = purify_makefile(&ast);
let _ = result.transformations_applied; }
#[test]
fn test_PERFORMANCE_006_detect_sequential_recipes() {
let makefile = r#"
install:
mkdir -p /usr/local/bin
cp app /usr/local/bin/
chmod +x /usr/local/bin/app
mkdir -p /usr/local/share/doc/app
cp README.md /usr/local/share/doc/app/
"#;
let ast = crate::make_parser::parser::parse_makefile(makefile).unwrap();
let result = purify_makefile(&ast);
assert!(
result
.report
.iter()
.any(|r| r.contains("combine") || r.contains("&&") || r.contains("performance")),
"Should suggest combining sequential recipe lines"
);
}
include!("tests_tests_performance_.rs");