Repository navigation
Expand file tree
/
Copy pathoutput_publication.rs
More file actions
84 lines (79 loc) · 3.24 KB
/
Copy pathoutput_publication.rs
File metadata and controls
84 lines (79 loc) · 3.24 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
use std::{fs, path::Path, process::Command};
fn run(mode: &str, input: &Path, output: &Path) -> std::process::Output {
let mut command = Command::new(env!("CARGO_BIN_EXE_whale"));
match mode {
"asm" => {
command.args(["asm", "--amd64"]);
},
"ir" => {
command.args(["ir", "lower"]);
},
_ => {
command.arg("object");
},
}
command.arg(input).arg("-o").arg(output).output().unwrap()
}
fn cases() -> Vec<(&'static str, &'static [u8])> {
#[allow(unused_mut)]
let mut cases: Vec<(&str, &[u8])> = vec![("asm", b"section .text\nret\n"), ("object", b"\xc3")];
#[cfg(feature = "socket-cli")]
cases.push(("ir", br#"{"format_version":2,"semantics_version":1,"features":[],"program":{"declarations":[],"globals":[],"functions":[]}}"#));
cases
}
#[test]
fn every_writer_rejects_source_aliases_and_preserves_source_bytes() {
let scratch = tempfile::tempdir().unwrap();
for (mode, source) in cases() {
let input = scratch.path().join(format!("{mode} source.o"));
fs::write(&input, source).unwrap();
let hard = scratch.path().join(format!("{mode} hardlink.o"));
fs::hard_link(&input, &hard).unwrap();
#[allow(unused_mut)]
let mut outputs = vec![input.clone(), hard];
#[cfg(unix)]
{
let link = scratch.path().join(format!("{mode} symlink.o"));
std::os::unix::fs::symlink(&input, &link).unwrap();
outputs.push(link);
}
for output in outputs {
let result = run(mode, &input, &output);
assert!(!result.status.success(), "{mode}: accepted source alias");
assert!(String::from_utf8_lossy(&result.stderr).contains("same file"), "{result:?}");
assert_eq!(fs::read(&input).unwrap(), source);
assert_eq!(fs::read(&output).unwrap(), source);
}
}
}
#[test]
fn every_writer_replaces_outputs_with_spaces_and_cleans_temporary_files() {
let scratch = tempfile::tempdir().unwrap();
for (mode, source) in cases() {
let input = scratch.path().join("input file");
let output = scratch.path().join("output file.o");
fs::write(&input, source).unwrap();
fs::write(&output, b"prior output").unwrap();
let result = run(mode, &input, &output);
assert!(result.status.success(), "{result:?}");
let bytes = fs::read(&output).unwrap();
assert!(bytes.starts_with(if mode == "ir" { b"module" } else { b"\x7fELF" }));
assert_eq!(fs::read(&input).unwrap(), source);
assert_eq!(fs::read_dir(scratch.path()).unwrap().count(), 2);
}
}
#[test]
fn output_errors_are_diagnostics_without_panics_or_leftovers() {
let scratch = tempfile::tempdir().unwrap();
let input = scratch.path().join("input");
let output = scratch.path().join("directory.o");
fs::create_dir(&output).unwrap();
for (mode, source) in cases() {
fs::write(&input, source).unwrap();
let result = run(mode, &input, &output);
assert!(!result.status.success());
assert!(!String::from_utf8_lossy(&result.stderr).contains("panicked"));
assert!(output.is_dir());
assert_eq!(fs::read_dir(scratch.path()).unwrap().count(), 2);
}
}