Rust · 2492 bytes Raw Blame History
1 //! Sprint 10 integration gate: minimal executable/dylib outputs are accepted
2 //! by the platform inspection tools.
3
4 use std::fs;
5 use std::path::{Path, PathBuf};
6 use std::process::Command;
7
8 use afs_ld::layout::Layout;
9 use afs_ld::macho::writer;
10 use afs_ld::{LinkOptions, OutputKind};
11
12 fn have_xcrun_tool(tool: &str) -> bool {
13 Command::new("xcrun")
14 .arg("-f")
15 .arg(tool)
16 .output()
17 .map(|o| o.status.success())
18 .unwrap_or(false)
19 }
20
21 fn have_file() -> bool {
22 Command::new("file")
23 .arg("--version")
24 .output()
25 .map(|o| o.status.success())
26 .unwrap_or(false)
27 }
28
29 fn scratch(name: &str) -> PathBuf {
30 std::env::temp_dir().join(format!("afs-ld-sprint10-{}-{name}", std::process::id()))
31 }
32
33 fn write_image(path: &Path, kind: OutputKind) {
34 let mut bytes = Vec::new();
35 let opts = LinkOptions {
36 output: Some(path.to_path_buf()),
37 kind,
38 ..LinkOptions::default()
39 };
40 writer::write(&Layout::empty(kind, 0), kind, &opts, &mut bytes).unwrap();
41 fs::write(path, bytes).unwrap();
42 }
43
44 #[test]
45 fn minimal_outputs_pass_otool_and_file() {
46 if !have_xcrun_tool("otool") || !have_file() {
47 eprintln!("skipping: xcrun otool or file unavailable");
48 return;
49 }
50
51 let exe = scratch("tiny");
52 let dylib = scratch("libtiny.dylib");
53 write_image(&exe, OutputKind::Executable);
54 write_image(&dylib, OutputKind::Dylib);
55
56 for (path, expected) in [
57 (&exe, "Mach-O 64-bit executable arm64"),
58 (
59 &dylib,
60 "Mach-O 64-bit dynamically linked shared library arm64",
61 ),
62 ] {
63 let otool = Command::new("xcrun")
64 .args(["otool", "-lV"])
65 .arg(path)
66 .output()
67 .unwrap();
68 assert!(
69 otool.status.success(),
70 "otool failed for {}:\nstdout:\n{}\nstderr:\n{}",
71 path.display(),
72 String::from_utf8_lossy(&otool.stdout),
73 String::from_utf8_lossy(&otool.stderr)
74 );
75
76 let file = Command::new("file").arg(path).output().unwrap();
77 assert!(file.status.success(), "file failed for {}", path.display());
78 let text = String::from_utf8_lossy(&file.stdout);
79 assert!(
80 text.contains(expected),
81 "expected `{expected}` in file output for {} but got:\n{text}",
82 path.display()
83 );
84 }
85
86 let _ = fs::remove_file(exe);
87 let _ = fs::remove_file(dylib);
88 }
89