This repository has been archived by the owner on Feb 4, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 27
/
Copy pathmod.rs
171 lines (156 loc) · 4.86 KB
/
mod.rs
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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
#![allow(dead_code)]
use std::path::{Path, PathBuf};
use std::process::{Command, Output};
extern crate env_logger;
extern crate log;
extern crate tempfile;
use log::info;
use saltwater::Error;
pub fn init() {
env_logger::builder().is_test(true).init();
}
pub fn cpp() -> std::process::Command {
let mut cpp = std::process::Command::new("cpp");
cpp.args(&[
"-P",
"-undef",
"-D__DBL_MAX__=1.797693134862315708e+308L",
"-D__DBL_MIN__=2.225073858507201383e-308L",
"-D__FLT_MAX__=3.402823466385288598e+38F",
"-D__FLT_MIN__=1.175494350822287507e-38F",
"-D__INTPTR_TYPE__=8",
"-D__INT32_TYPE__=4",
#[cfg(linux)]
"-D__linux__",
#[cfg(target_arch = "x86_64")]
"-D__x86_64__",
]);
cpp
}
pub fn compile_and_run(program: &str, path: PathBuf, args: &[&str]) -> Result<Output, Error> {
let output = compile(program, path, false)
.unwrap_or_else(|err| panic!("failed to compile program '{}': {}", program, err));
info!("running file {:?}", output);
run(&output, args).map_err(Error::IO)
}
pub fn compile(
program: &str,
filename: PathBuf,
no_link: bool,
) -> Result<tempfile::TempPath, Error> {
let opts = saltwater::Opt {
filename,
..Default::default()
};
let module = saltwater::initialize_aot_module(program.to_owned());
let module = saltwater::compile(module, program, opts).result?.finish();
let output = tempfile::NamedTempFile::new()
.expect("cannot create tempfile")
.into_temp_path();
info!("output is {:?}", output);
if !no_link {
let tmp_file = tempfile::NamedTempFile::new()
.expect("cannot create tempfile")
.into_temp_path();
info!("tmp_file is {:?}", tmp_file);
saltwater::assemble(module, &tmp_file)?;
saltwater::link(&tmp_file, &output)?;
} else {
saltwater::assemble(module, &output)?;
};
Ok(output)
}
pub fn run(program: &Path, args: &[&str]) -> Result<Output, std::io::Error> {
Command::new(program).args(args).output()
}
pub fn assert_compiles(program: &str, path: PathBuf) {
assert!(
compile(program, path, true).is_err(),
"{} failed to compile",
program
);
}
pub fn assert_compiles_no_main(fragment: &str, path: PathBuf) {
let program = format!("int main() {{}}\n{}", fragment);
assert!(
compile(&program, path, true).is_ok(),
"{} failed to compile",
fragment
);
}
pub fn assert_compile_error(program: &str, path: PathBuf) {
assert!(
match compile(program, path, true) {
Err(Error::Source(_)) => true,
_ => false,
},
"{} should fail to compile",
program
);
}
pub fn assert_crash(program: &str, path: PathBuf) {
let output = compile(program, path, false).expect("could not compile program");
log::debug!("running compiled program at {:?}", output);
let path: &Path = output.as_ref();
let mut handle = Command::new(path)
.spawn()
.expect("could not start compiled program");
#[cfg(unix)]
{
use std::os::unix::process::ExitStatusExt;
assert!(handle
.wait()
.expect("call to libc::wait should succeed")
.signal()
.is_some());
}
#[cfg(not(unix))]
{
use log::warn;
warn!("testing for segfaults is not supported on non-unix platforms, this just checks the return code is non-zero");
assert!(!handle.wait().unwrap().success());
}
}
pub fn assert_output(program: &str, path: PathBuf, output: &str) {
match compile_and_run(program, path, &[]) {
Err(_) => panic!("program failed to compile or run: {}", program),
Ok(actual) => assert_eq!(
actual.stdout,
output.as_bytes(),
"{} should have the output {} (got {})",
program,
output,
String::from_utf8_lossy(&actual.stdout),
),
}
}
pub fn assert_succeeds(program: &str, path: PathBuf) {
assert!(
match compile_and_run(program, path, &[]) {
Err(_) => false,
Ok(output) => output.status.success(),
},
"'{}' should exit successfully",
program
);
}
pub fn assert_code(program: &str, path: PathBuf, code: i32) {
assert!(
match compile_and_run(program, path, &[]) {
Err(_) => false,
Ok(output) => match output.status.code() {
Some(actual) => actual == code,
None => false,
},
},
"{} should exit with code {}",
program,
code
);
}
pub fn assert_num_errs<S: AsRef<str>>(program: S, path: PathBuf, n: usize) {
match compile(program.as_ref(), path, true) {
Err(Error::Source(errs)) => assert!(errs.len() == n),
_ => panic!("program should have an error"),
}
}