chore(release): prepare public source release

This commit is contained in:
MercuryToolbox Release
2026-07-18 15:41:59 +08:00
commit e365e5df4d
508 changed files with 163373 additions and 0 deletions
+260
View File
@@ -0,0 +1,260 @@
//! Integration tests for the LLVM COFF helper commands.
use std::env;
use std::fs;
use std::path::{Path, PathBuf};
use assert_cmd::Command;
use predicates::prelude::*;
use serde_json::Value;
use tempfile::{TempDir, tempdir};
#[derive(Clone, Copy)]
struct ToolCase {
binary: &'static str,
backend: &'static str,
}
const LLVM_TOOL_CASES: &[ToolCase] = &[
ToolCase {
binary: "llvmreadobj",
backend: "llvm-readobj",
},
ToolCase {
binary: "llvmobjdump",
backend: "llvm-objdump",
},
ToolCase {
binary: "llvmnm",
backend: "llvm-nm",
},
];
fn llvm_command(binary: &str) -> Command {
Command::cargo_bin(binary).expect("binary")
}
#[test]
fn help_mentions_examples_backend_and_shared_output_flags() {
for case in LLVM_TOOL_CASES {
let mut command = llvm_command(case.binary);
command
.arg("--help")
.assert()
.success()
.stdout(predicate::str::contains("Examples"))
.stdout(predicate::str::contains("--llvm-bin-dir"))
.stdout(predicate::str::contains("--llvm-arg"))
.stdout(predicate::str::contains("--json"))
.stdout(predicate::str::contains("--toon"));
}
}
#[test]
fn json_output_exposes_common_top_level_contract() {
for case in LLVM_TOOL_CASES {
let backend_dir = fake_backend_dir(LLVM_TOOL_CASES);
let input_dir = tempdir().expect("input tempdir");
let object = write_coff_placeholder(input_dir.path(), case.binary);
let mut command = llvm_command(case.binary);
add_fake_backend(&mut command, backend_dir.path());
let output = command
.arg("--json")
.arg(&object)
.assert()
.success()
.get_output()
.stdout
.clone();
let json = serde_json::from_slice::<Value>(&output).expect("json output");
assert_common_json_contract(case.binary, &json);
assert!(
json["files"]
.as_array()
.is_some_and(|files| !files.is_empty()),
"{}: expected at least one file entry in {json}",
case.binary
);
}
}
#[test]
fn stdin_lines_feed_multiple_files() {
for case in LLVM_TOOL_CASES {
let backend_dir = fake_backend_dir(LLVM_TOOL_CASES);
let input_dir = tempdir().expect("input tempdir");
let first = write_coff_placeholder(input_dir.path(), &format!("{}-first", case.binary));
let second = write_coff_placeholder(input_dir.path(), &format!("{}-second", case.binary));
let stdin = format!("{}\n{}\n", first.display(), second.display());
let mut command = llvm_command(case.binary);
add_fake_backend(&mut command, backend_dir.path());
let output = command
.arg("--json")
.write_stdin(stdin)
.assert()
.success()
.get_output()
.stdout
.clone();
let json = serde_json::from_slice::<Value>(&output).expect("json output");
assert_common_json_contract(case.binary, &json);
let files = json["files"].as_array().expect("files array");
assert_eq!(
files.len(),
2,
"{}: expected stdin line input to produce two file entries in {json}",
case.binary
);
}
}
#[test]
fn objdump_symbol_and_address_flags_are_recorded_in_backend_argv() {
let backend_dir = fake_backend_dir(LLVM_TOOL_CASES);
let input_dir = tempdir().expect("input tempdir");
let object = write_coff_placeholder(input_dir.path(), "objdump-argv");
let mut command = llvm_command("llvmobjdump");
add_fake_backend(&mut command, backend_dir.path());
let output = command
.arg("--symbol")
.arg("main")
.arg("--start-address")
.arg("0x0")
.arg("--stop-address")
.arg("0x20")
.arg("--json")
.arg(&object)
.assert()
.success()
.get_output()
.stdout
.clone();
let json = serde_json::from_slice::<Value>(&output).expect("json output");
let argv = json["backend"]["argv"]
.as_array()
.expect("backend argv")
.iter()
.filter_map(Value::as_str)
.collect::<Vec<_>>();
assert!(argv.contains(&"--disassemble-symbols=main"));
assert!(argv.contains(&"--start-address=0x0"));
assert!(argv.contains(&"--stop-address=0x20"));
}
#[test]
fn missing_backend_fails_with_actionable_message() {
for case in LLVM_TOOL_CASES {
let empty_backend_dir = tempdir().expect("backend tempdir");
let input_dir = tempdir().expect("input tempdir");
let object = write_coff_placeholder(input_dir.path(), case.binary);
let mut command = llvm_command(case.binary);
command
.arg("--llvm-bin-dir")
.arg(empty_backend_dir.path())
.arg(&object)
.assert()
.failure()
.stderr(predicate::str::contains(case.backend))
.stderr(predicate::str::contains("--llvm-bin-dir"))
.stderr(
predicate::str::contains("backend")
.or(predicate::str::contains("LLVM"))
.or(predicate::str::contains("not found")),
);
}
}
fn assert_common_json_contract(binary: &str, json: &Value) {
assert!(
json.get("backend").is_some(),
"{binary}: missing top-level backend in {json}"
);
assert!(
json.get("summary").is_some(),
"{binary}: missing top-level summary in {json}"
);
assert!(
json.get("files").and_then(Value::as_array).is_some(),
"{binary}: missing top-level files array in {json}"
);
assert!(
json.get("parse_warnings")
.and_then(Value::as_array)
.is_some(),
"{binary}: missing top-level parse_warnings array in {json}"
);
}
fn add_fake_backend(command: &mut Command, backend_dir: &Path) {
command.arg("--llvm-bin-dir").arg(backend_dir);
for arg in fake_backend_args() {
command.arg("--llvm-arg").arg(arg);
}
}
fn fake_backend_dir(cases: &[ToolCase]) -> TempDir {
let dir = tempdir().expect("backend tempdir");
let shell = host_shell();
for case in cases {
for file_name in backend_file_names(case.backend) {
let destination = dir.path().join(file_name);
fs::copy(&shell, &destination).expect("copy fake backend executable");
make_executable(&destination);
}
}
dir
}
fn host_shell() -> PathBuf {
if cfg!(windows) {
env::var_os("COMSPEC").map_or_else(
|| PathBuf::from(r"C:\Windows\System32\cmd.exe"),
PathBuf::from,
)
} else {
PathBuf::from("/bin/sh")
}
}
fn backend_file_names(backend: &str) -> Vec<String> {
if cfg!(windows) {
vec![backend.to_owned(), format!("{backend}.exe")]
} else {
vec![backend.to_owned()]
}
}
fn fake_backend_args() -> Vec<&'static str> {
if cfg!(windows) {
vec!["/D", "/S", "/C", "echo fake llvm coff output"]
} else {
vec!["-c", "printf 'fake llvm coff output\\n'"]
}
}
fn write_coff_placeholder(dir: &Path, stem: &str) -> PathBuf {
let path = dir.join(format!("{stem}.obj"));
fs::write(&path, b"MZ fake COFF placeholder\n").expect("write object placeholder");
path
}
#[cfg(unix)]
fn make_executable(path: &Path) {
use std::os::unix::fs::PermissionsExt as _;
let mut permissions = fs::metadata(path)
.expect("fake backend metadata")
.permissions();
permissions.set_mode(0o755);
fs::set_permissions(path, permissions).expect("fake backend permissions");
}
#[cfg(not(unix))]
const fn make_executable(_path: &Path) {}