use assert_cmd::Command;
use predicates::prelude::*;
use predicates::str::contains;
use std::fs;
#[test]
fn help_is_generic_about_targets() {
Command::cargo_bin("hypothalamus")
.expect("binary should build")
.arg("--help")
.assert()
.success()
.stdout(contains("Hypothalamus - Brainfuck AOT compiler"))
.stdout(contains("--target <TARGET>"))
.stdout(contains("--list-targets"))
.stdout(contains("tools doctor"))
.stdout(contains("built-in runner"))
.stdout(contains("--gba-gcc").not());
}
#[test]
fn version_prints_package_version() {
Command::cargo_bin("hypothalamus")
.expect("binary should build")
.arg("--version")
.assert()
.success()
.stdout(contains(format!(
"hypothalamus {}",
env!("CARGO_PKG_VERSION")
)));
}
#[test]
fn list_targets_includes_current_presets() {
Command::cargo_bin("hypothalamus")
.expect("binary should build")
.arg("--list-targets")
.assert()
.success()
.stdout(contains("native"))
.stdout(contains("x86_64-none"))
.stdout(contains("i386-none"))
.stdout(contains("nds-arm9"))
.stdout(contains("gba"));
}
#[test]
fn tools_doctor_reports_local_capabilities() {
Command::cargo_bin("hypothalamus")
.expect("binary should build")
.args([
"tools",
"doctor",
"--cc",
"/definitely/missing/clang",
"--lli",
"/definitely/missing/lli",
])
.assert()
.success()
.stdout(contains("Hypothalamus tool doctor"))
.stdout(contains("Execution:"))
.stdout(contains("Tools:"))
.stdout(contains("Targets:"))
.stdout(contains("run: ok"))
.stdout(contains("clang: missing"))
.stdout(contains("lli: missing"))
.stdout(contains("nds-arm9"))
.stdout(contains("gba"));
}
#[test]
fn emits_llvm_ir_to_stdout() {
Command::cargo_bin("hypothalamus")
.expect("binary should build")
.args(["--emit", "llvm-ir", "-o", "-", "examples/hello.bf"])
.assert()
.success()
.stdout(contains("; Generated by hypothalamus."))
.stdout(contains("define i32 @main()"))
.stdout(contains("@putchar"));
}
#[test]
fn writes_llvm_ir_to_output_file() {
let temp_dir = tempfile::tempdir().expect("create temp dir");
let output = temp_dir.path().join("hello.ll");
Command::cargo_bin("hypothalamus")
.expect("binary should build")
.args(["--emit", "llvm-ir", "examples/hello.bf", "-o"])
.arg(&output)
.assert()
.success();
let ir = fs::read_to_string(output).expect("read generated LLVM IR");
assert!(ir.contains("; Generated by hypothalamus."));
assert!(ir.contains("define i32 @main()"));
}
#[test]
fn rejects_stdout_output_for_non_llvm_ir_modes() {
for args in [
["--emit", "obj", "-o", "-", "examples/hello.bf"],
["--emit", "asm", "-o", "-", "examples/hello.bf"],
["--target", "gba", "-o", "-", "examples/hello.bf"],
] {
Command::cargo_bin("hypothalamus")
.expect("binary should build")
.args(args)
.assert()
.code(1)
.stderr(contains("--emit llvm-ir"));
}
}
#[test]
fn run_uses_builtin_runner_without_lli() {
Command::cargo_bin("hypothalamus")
.expect("binary should build")
.args([
"--run",
"--lli",
"/definitely/missing/lli",
"examples/hello.bf",
])
.assert()
.success()
.stdout(contains("Hello World!"));
}
#[test]
fn llvm_jit_uses_lli() {
Command::cargo_bin("hypothalamus")
.expect("binary should build")
.args([
"--emit",
"llvm-jit",
"--lli",
"/definitely/missing/lli",
"examples/hello.bf",
])
.assert()
.failure()
.stderr(contains("failed to run"))
.stderr(contains("/definitely/missing/lli"));
}
#[test]
fn run_reads_stdin() {
let temp_dir = tempfile::tempdir().expect("create temp dir");
let source = temp_dir.path().join("input.bf");
fs::write(&source, ",+.").expect("write input program");
Command::cargo_bin("hypothalamus")
.expect("binary should build")
.args(["--run"])
.arg(source)
.write_stdin("A")
.assert()
.success()
.stdout("B");
}
#[test]
fn run_reports_pointer_bounds_errors() {
let temp_dir = tempfile::tempdir().expect("create temp dir");
let source = temp_dir.path().join("underflow.bf");
fs::write(&source, "<").expect("write underflow program");
Command::cargo_bin("hypothalamus")
.expect("binary should build")
.args(["--run"])
.arg(source)
.assert()
.failure()
.stderr(contains("runtime error"))
.stderr(contains("out of bounds"));
}
#[test]
fn emits_custom_freestanding_symbols_to_stdout() {
Command::cargo_bin("hypothalamus")
.expect("binary should build")
.args([
"--freestanding",
"--entry",
"kernel_bf_main",
"--putchar-symbol",
"serial_write_byte",
"--getchar-symbol",
"serial_read_byte",
"--emit",
"llvm-ir",
"-o",
"-",
"examples/hello.bf",
])
.assert()
.success()
.stdout(contains("define void @kernel_bf_main()"))
.stdout(contains("declare void @serial_write_byte(i8)"))
.stdout(contains("declare i32 @serial_read_byte()"))
.stdout(contains("define i32 @main()").not());
}
#[test]
fn nds_arm9_target_emits_freestanding_llvm_ir() {
Command::cargo_bin("hypothalamus")
.expect("binary should build")
.args([
"--target",
"nds-arm9",
"--emit",
"llvm-ir",
"-o",
"-",
"examples/hello.bf",
])
.assert()
.success()
.stdout(contains("target triple = \"armv5te-none-eabi\""))
.stdout(contains("define void @bf_main()"))
.stdout(contains("declare void @bf_putchar(i8)"))
.stdout(contains("define i32 @main()").not());
}