mirror of
https://github.com/dexoron/dcr.git
synced 2026-10-21 13:48:29 +00:00
370 lines
12 KiB
Rust
370 lines
12 KiB
Rust
mod common;
|
|
use common::*;
|
|
|
|
#[test]
|
|
fn init_and_clean_remove_target() {
|
|
let dir = unique_sandbox_dir("init");
|
|
let out = run_dcr(&["init"], &dir);
|
|
assert!(out.status.success(), "dcr init should succeed");
|
|
|
|
let target_debug = dir.join("target").join("debug");
|
|
std::fs::create_dir_all(&target_debug).expect("failed to create target/debug");
|
|
std::fs::write(target_debug.join("dummy.o"), "x").expect("failed to write dummy file");
|
|
|
|
let out = run_dcr(&["clean"], &dir);
|
|
assert!(out.status.success(), "dcr clean should succeed");
|
|
assert!(!dir.join("target").exists(), "target should be removed");
|
|
}
|
|
|
|
#[test]
|
|
fn add_preserves_run_and_untyped_keys() {
|
|
// Regression: `dcr add` used to drop the [run] section and non-whitelisted
|
|
// [build] keys (filename/extension/include) when re-serializing dcr.toml.
|
|
let dir = unique_sandbox_dir("preserve_add");
|
|
let out = run_dcr(&["init"], &dir);
|
|
assert!(out.status.success(), "dcr init should succeed");
|
|
|
|
let toml_path = dir.join("dcr.toml");
|
|
let toml = std::fs::read_to_string(&toml_path).expect("failed to read dcr.toml");
|
|
let updated = toml.replace(
|
|
"[build]",
|
|
"[build]\nfilename = \"KERNEL\"\nextension = \"ELF\"\ninclude = [\"src/include\"]",
|
|
) + "\n[run]\ncmd = \"qemu-system-aarch64 -kernel KERNEL\"\n";
|
|
std::fs::write(&toml_path, updated).expect("failed to write dcr.toml");
|
|
|
|
let out = run_dcr(&["add", "zlib", "path:../zlib"], &dir);
|
|
assert!(out.status.success(), "dcr add should succeed");
|
|
|
|
let saved = std::fs::read_to_string(&toml_path).expect("failed to read dcr.toml");
|
|
assert!(
|
|
saved.contains("filename = \"KERNEL\""),
|
|
"build.filename lost:\n{saved}"
|
|
);
|
|
assert!(
|
|
saved.contains("extension = \"ELF\""),
|
|
"build.extension lost:\n{saved}"
|
|
);
|
|
assert!(
|
|
saved.contains("include = [\"src/include\"]"),
|
|
"build.include lost:\n{saved}"
|
|
);
|
|
assert!(
|
|
saved.contains("[run]") && saved.contains("qemu-system-aarch64"),
|
|
"[run] section lost:\n{saved}"
|
|
);
|
|
assert!(
|
|
saved.contains("zlib = { path = \"../zlib\" }"),
|
|
"dependency not added as inline table:\n{saved}"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn build_run_clean_flags_normal_project() {
|
|
let Some(compiler) = available_compiler() else {
|
|
eprintln!("no compiler found; skipping build/run test");
|
|
return;
|
|
};
|
|
|
|
let dir = unique_sandbox_dir("normal");
|
|
let out = run_dcr(&["init"], &dir);
|
|
assert!(out.status.success(), "dcr init should succeed");
|
|
|
|
let envs = [("DCR_COMPILER", compiler)];
|
|
let out = run_dcr_env(&["build"], &dir, &envs);
|
|
assert!(out.status.success(), "dcr build should succeed");
|
|
|
|
let out = run_dcr_env(&["build", "--release"], &dir, &envs);
|
|
assert!(out.status.success(), "dcr build --release should succeed");
|
|
|
|
let out = run_dcr_env(&["run"], &dir, &envs);
|
|
let combined = format!(
|
|
"{}{}",
|
|
String::from_utf8_lossy(&out.stdout),
|
|
String::from_utf8_lossy(&out.stderr)
|
|
);
|
|
assert!(
|
|
combined.contains("run") || combined.contains("Running"),
|
|
"dcr run should start"
|
|
);
|
|
|
|
std::fs::write(
|
|
dir.join("src/main.c"),
|
|
r#"#include <stdio.h>
|
|
int main(int argc, char **argv) {
|
|
for (int i = 1; i < argc; i++) {
|
|
printf("ARG:%s\n", argv[i]);
|
|
}
|
|
return 0;
|
|
}
|
|
"#,
|
|
)
|
|
.expect("rewrite main.c");
|
|
let out = run_dcr_env(&["run", "--force", "--", "--test_help", "foo"], &dir, &envs);
|
|
let combined = format!(
|
|
"{}{}",
|
|
String::from_utf8_lossy(&out.stdout),
|
|
String::from_utf8_lossy(&out.stderr)
|
|
);
|
|
assert!(
|
|
out.status.success(),
|
|
"dcr run -- <args> should succeed:\n{combined}"
|
|
);
|
|
assert!(
|
|
combined.contains("ARG:--test_help") && combined.contains("ARG:foo"),
|
|
"binary should receive args after `--`:\n{combined}"
|
|
);
|
|
|
|
let out = run_dcr_env(&["clean", "--release"], &dir, &envs);
|
|
assert!(out.status.success(), "dcr clean --release should succeed");
|
|
let release_dir = host_profile_dir(&dir, "release");
|
|
let debug_dir = host_profile_dir(&dir, "debug");
|
|
assert!(
|
|
!release_dir.exists(),
|
|
"release profile dir should be removed: {}",
|
|
release_dir.display()
|
|
);
|
|
assert!(
|
|
debug_dir.is_dir(),
|
|
"debug profile dir should remain: {}",
|
|
debug_dir.display()
|
|
);
|
|
|
|
let out = run_dcr_env(&["clean"], &dir, &envs);
|
|
assert!(out.status.success(), "dcr clean should succeed");
|
|
assert!(!dir.join("target").exists(), "target should be removed");
|
|
}
|
|
|
|
#[test]
|
|
fn build_with_target_config() {
|
|
let Some(compiler) = available_compiler() else {
|
|
eprintln!("no compiler found; skipping target config test");
|
|
return;
|
|
};
|
|
|
|
let dir = unique_sandbox_dir("target_cfg");
|
|
let out = run_dcr(&["init"], &dir);
|
|
assert!(out.status.success(), "dcr init should succeed");
|
|
|
|
let toml_path = dir.join("dcr.toml");
|
|
let toml = std::fs::read_to_string(&toml_path).expect("failed to read dcr.toml");
|
|
let project_name = parse_project_name(&toml);
|
|
let updated = toml.replace("[build]", "[build]\ntarget = \"linux\"");
|
|
std::fs::write(&toml_path, updated).expect("failed to write dcr.toml");
|
|
|
|
let envs = [("DCR_COMPILER", compiler)];
|
|
let out = run_dcr_env(&["build"], &dir, &envs);
|
|
if !out.status.success() {
|
|
eprintln!("stdout: {}", String::from_utf8_lossy(&out.stdout));
|
|
eprintln!("stderr: {}", String::from_utf8_lossy(&out.stderr));
|
|
if cfg!(windows) {
|
|
eprintln!("skipping linux-target path assert: build failed (no linux cross toolchain)");
|
|
return;
|
|
}
|
|
}
|
|
assert!(
|
|
out.status.success(),
|
|
"dcr build with target = \"linux\" should succeed"
|
|
);
|
|
|
|
let out_dir = dir
|
|
.join("target")
|
|
.join("x86_64-unknown-linux-gnu")
|
|
.join("debug");
|
|
assert_artifact_in(
|
|
&out_dir,
|
|
&project_name,
|
|
"build.target=linux should place artifact under target/x86_64-unknown-linux-gnu/debug",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn build_with_out_dir() {
|
|
let Some(compiler) = available_compiler() else {
|
|
eprintln!("no compiler found; skipping out_dir test");
|
|
return;
|
|
};
|
|
|
|
let dir = unique_sandbox_dir("out_dir");
|
|
let out = run_dcr(&["init"], &dir);
|
|
assert!(out.status.success(), "dcr init should succeed");
|
|
|
|
let toml_path = dir.join("dcr.toml");
|
|
let toml = std::fs::read_to_string(&toml_path).expect("failed to read dcr.toml");
|
|
let project_name = parse_project_name(&toml);
|
|
let updated = toml.replace("[build]", "[build]\nout_dir = \"./_BUILD\"");
|
|
std::fs::write(&toml_path, updated).expect("failed to write dcr.toml");
|
|
|
|
let envs = [("DCR_COMPILER", compiler)];
|
|
let out = run_dcr_env(&["build"], &dir, &envs);
|
|
if !out.status.success() {
|
|
eprintln!("stdout: {}", String::from_utf8_lossy(&out.stdout));
|
|
eprintln!("stderr: {}", String::from_utf8_lossy(&out.stderr));
|
|
}
|
|
assert!(
|
|
out.status.success(),
|
|
"dcr build with out_dir should succeed"
|
|
);
|
|
|
|
assert_artifact_in(
|
|
&dir.join("_BUILD"),
|
|
&project_name,
|
|
"artifact should be under custom out_dir _BUILD",
|
|
);
|
|
|
|
let default_path = default_artifact_path(&dir, &project_name);
|
|
assert!(
|
|
!default_path.exists(),
|
|
"artifact should NOT be at default path when out_dir is set"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn flat_bin_nasm_build() {
|
|
let nasm_ok = std::process::Command::new("nasm")
|
|
.arg("-v")
|
|
.output()
|
|
.map(|o| o.status.success())
|
|
.unwrap_or(false);
|
|
if !nasm_ok {
|
|
eprintln!("nasm not found; skipping flat-bin test");
|
|
return;
|
|
}
|
|
|
|
let dir = unique_sandbox_dir("flat_bin");
|
|
let out = run_dcr(&["init"], &dir);
|
|
assert!(out.status.success(), "dcr init should succeed");
|
|
|
|
std::fs::write(
|
|
dir.join("dcr.toml"),
|
|
r#"[package]
|
|
name = "flatdemo"
|
|
version = "0.1.0"
|
|
|
|
[build]
|
|
language = "asm"
|
|
compiler = "nasm"
|
|
kind = "flat-bin"
|
|
extension = "bin"
|
|
roots = ["src"]
|
|
"#,
|
|
)
|
|
.expect("write dcr.toml");
|
|
|
|
std::fs::create_dir_all(dir.join("src")).expect("src");
|
|
std::fs::write(
|
|
dir.join("src/boot.asm"),
|
|
"bits 16\norg 0x7c00\ncli\nhlt\ntimes 510-($-$$) db 0\ndw 0xaa55\n",
|
|
)
|
|
.expect("write boot.asm");
|
|
|
|
let out = run_dcr(&["build"], &dir);
|
|
if !out.status.success() {
|
|
eprintln!("stdout: {}", String::from_utf8_lossy(&out.stdout));
|
|
eprintln!("stderr: {}", String::from_utf8_lossy(&out.stderr));
|
|
}
|
|
assert!(out.status.success(), "flat-bin nasm build should succeed");
|
|
|
|
let candidates = [
|
|
host_profile_dir(&dir, "debug").join("boot.bin"),
|
|
dir.join("target/debug/boot.bin"),
|
|
];
|
|
assert!(
|
|
candidates.iter().any(|p| p.is_file()),
|
|
"expected boot.bin under host profile dir, candidates: {candidates:?}"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn package_build_target_used_without_cli_flag() {
|
|
let Some(compiler) = available_compiler() else {
|
|
eprintln!("no compiler found; skipping package target test");
|
|
return;
|
|
};
|
|
|
|
let dir = unique_sandbox_dir("pkg_target");
|
|
let out = run_dcr(&["init"], &dir);
|
|
assert!(out.status.success());
|
|
|
|
let toml_path = dir.join("dcr.toml");
|
|
let toml = std::fs::read_to_string(&toml_path).unwrap();
|
|
let project_name = parse_project_name(&toml);
|
|
let updated = toml.replace("[build]", "[build]\ntarget = \"x86_64-unknown-linux-gnu\"");
|
|
std::fs::write(&toml_path, updated).unwrap();
|
|
|
|
let envs = [("DCR_COMPILER", compiler)];
|
|
let out = run_dcr_env(&["build"], &dir, &envs);
|
|
if !out.status.success() {
|
|
eprintln!("stdout: {}", String::from_utf8_lossy(&out.stdout));
|
|
eprintln!("stderr: {}", String::from_utf8_lossy(&out.stderr));
|
|
if cfg!(windows) {
|
|
eprintln!("skipping linux-target path assert: build failed (no linux cross toolchain)");
|
|
return;
|
|
}
|
|
}
|
|
assert!(out.status.success(), "build should use package target");
|
|
|
|
let out_dir = dir
|
|
.join("target")
|
|
.join("x86_64-unknown-linux-gnu")
|
|
.join("debug");
|
|
assert_artifact_in(
|
|
&out_dir,
|
|
&project_name,
|
|
"artifact should be under package build.target path",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn host_target_section_ldflags_apply_without_cli_target() {
|
|
let Some(compiler) = available_compiler() else {
|
|
eprintln!("no compiler found; skipping host target ldflags test");
|
|
return;
|
|
};
|
|
|
|
let dir = unique_sandbox_dir("host_ldflags");
|
|
let out = run_dcr(&["init"], &dir);
|
|
assert!(out.status.success(), "dcr init should succeed");
|
|
|
|
let host = if cfg!(target_os = "linux") {
|
|
let arch = std::env::consts::ARCH;
|
|
let env = if cfg!(target_env = "musl") {
|
|
"musl"
|
|
} else {
|
|
"gnu"
|
|
};
|
|
format!("{arch}-unknown-linux-{env}")
|
|
} else if cfg!(target_os = "macos") {
|
|
format!("{}-apple-darwin", std::env::consts::ARCH)
|
|
} else if cfg!(target_os = "windows") {
|
|
let env = if cfg!(target_env = "gnu") {
|
|
"gnu"
|
|
} else {
|
|
"msvc"
|
|
};
|
|
format!("{}-pc-windows-{env}", std::env::consts::ARCH)
|
|
} else {
|
|
eprintln!("unsupported host for host_target_section test; skipping");
|
|
return;
|
|
};
|
|
|
|
let toml_path = dir.join("dcr.toml");
|
|
let toml = std::fs::read_to_string(&toml_path).expect("read dcr.toml");
|
|
let updated = format!(
|
|
"{toml}\n[build.{host}]\nldflags = [\"-Wl,-rpath,/nonexistent-dcr-host-ldflags\"]\n"
|
|
);
|
|
std::fs::write(&toml_path, updated).expect("write dcr.toml");
|
|
|
|
let envs = [("DCR_COMPILER", compiler), ("DCR_DEBUG", "1")];
|
|
let out = run_dcr_env(&["build", "--force"], &dir, &envs);
|
|
let combined = format!(
|
|
"{}{}",
|
|
String::from_utf8_lossy(&out.stdout),
|
|
String::from_utf8_lossy(&out.stderr)
|
|
);
|
|
assert!(
|
|
combined.contains("-Wl,-rpath,/nonexistent-dcr-host-ldflags")
|
|
|| combined.contains("rpath,/nonexistent-dcr-host-ldflags"),
|
|
"host target section ldflags must be applied on native build:\n{combined}"
|
|
);
|
|
}
|