Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/crates/test-programs/src/preview1.rs
1693 views
1
use std::{sync::OnceLock, time::Duration};
2
3
pub fn config() -> &'static TestConfig {
4
static TESTCONFIG: OnceLock<TestConfig> = OnceLock::new();
5
TESTCONFIG.get_or_init(TestConfig::from_env)
6
}
7
8
// The `wasi` crate version 0.9.0 and beyond, doesn't
9
// seem to define these constants, so we do it ourselves.
10
pub const STDIN_FD: wasip1::Fd = 0x0;
11
pub const STDOUT_FD: wasip1::Fd = 0x1;
12
pub const STDERR_FD: wasip1::Fd = 0x2;
13
14
/// Opens a fresh file descriptor for `path` where `path` should be a preopened
15
/// directory.
16
pub fn open_scratch_directory(path: &str) -> Result<wasip1::Fd, String> {
17
unsafe {
18
for i in 3.. {
19
let stat = match wasip1::fd_prestat_get(i) {
20
Ok(s) => s,
21
Err(_) => break,
22
};
23
if stat.tag != wasip1::PREOPENTYPE_DIR.raw() {
24
continue;
25
}
26
let mut dst = Vec::with_capacity(stat.u.dir.pr_name_len);
27
if wasip1::fd_prestat_dir_name(i, dst.as_mut_ptr(), dst.capacity()).is_err() {
28
continue;
29
}
30
dst.set_len(stat.u.dir.pr_name_len);
31
if dst == path.as_bytes() {
32
return Ok(
33
wasip1::path_open(i, 0, ".", wasip1::OFLAGS_DIRECTORY, 0, 0, 0)
34
.expect("failed to open dir"),
35
);
36
}
37
}
38
39
Err(format!("failed to find scratch dir"))
40
}
41
}
42
43
pub unsafe fn create_file(dir_fd: wasip1::Fd, filename: &str) {
44
unsafe {
45
let file_fd = wasip1::path_open(dir_fd, 0, filename, wasip1::OFLAGS_CREAT, 0, 0, 0)
46
.expect("creating a file");
47
assert!(file_fd > STDERR_FD, "file descriptor range check",);
48
wasip1::fd_close(file_fd).expect("closing a file");
49
}
50
}
51
52
// Small workaround to get the crate's macros, through the
53
// `#[macro_export]` attribute below, also available from this module.
54
pub use crate::{assert_errno, assert_fs_time_eq};
55
56
#[macro_export]
57
macro_rules! assert_errno {
58
($s:expr, windows => $i:expr, $( $rest:tt )+) => {
59
let e = $s;
60
if $crate::preview1::config().errno_expect_windows() {
61
assert_errno!(e, $i);
62
} else {
63
assert_errno!(e, $($rest)+, $i);
64
}
65
};
66
($s:expr, macos => $i:expr, $( $rest:tt )+) => {
67
let e = $s;
68
if $crate::preview1::config().errno_expect_macos() {
69
assert_errno!(e, $i);
70
} else {
71
assert_errno!(e, $($rest)+, $i);
72
}
73
};
74
($s:expr, unix => $i:expr, $( $rest:tt )+) => {
75
let e = $s;
76
if $crate::preview1::config().errno_expect_unix() {
77
assert_errno!(e, $i);
78
} else {
79
assert_errno!(e, $($rest)+, $i);
80
}
81
};
82
($s:expr, $( $i:expr ),+) => {
83
let e = $s;
84
{
85
// Pretty printing infrastructure
86
struct Alt<'a>(&'a [&'static str]);
87
impl<'a> std::fmt::Display for Alt<'a> {
88
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
89
let l = self.0.len();
90
if l == 0 {
91
unreachable!()
92
} else if l == 1 {
93
f.write_str(self.0[0])
94
} else if l == 2 {
95
f.write_str(self.0[0])?;
96
f.write_str(" or ")?;
97
f.write_str(self.0[1])
98
} else {
99
for (ix, s) in self.0.iter().enumerate() {
100
if ix == l - 1 {
101
f.write_str("or ")?;
102
f.write_str(s)?;
103
} else {
104
f.write_str(s)?;
105
f.write_str(", ")?;
106
}
107
}
108
Ok(())
109
}
110
}
111
}
112
assert!( $( e == $i || )+ false,
113
"expected errno {}; got {}",
114
Alt(&[ $( $i.name() ),+ ]),
115
e.name()
116
)
117
}
118
};
119
}
120
121
#[macro_export]
122
macro_rules! assert_fs_time_eq {
123
($l:expr, $r:expr, $n:literal) => {
124
let diff = if $l > $r { $l - $r } else { $r - $l };
125
assert!(diff < $crate::preview1::config().fs_time_precision(), $n);
126
};
127
}
128
129
pub struct TestConfig {
130
errno_mode: ErrnoMode,
131
fs_time_precision: u64,
132
no_dangling_filesystem: bool,
133
no_rename_dir_to_empty_dir: bool,
134
rename_dir_onto_file: bool,
135
}
136
137
enum ErrnoMode {
138
Unix,
139
MacOS,
140
Windows,
141
Permissive,
142
}
143
144
impl TestConfig {
145
pub fn from_env() -> Self {
146
let errno_mode = if std::env::var("ERRNO_MODE_UNIX").is_ok() {
147
ErrnoMode::Unix
148
} else if std::env::var("ERRNO_MODE_MACOS").is_ok() {
149
ErrnoMode::MacOS
150
} else if std::env::var("ERRNO_MODE_WINDOWS").is_ok() {
151
ErrnoMode::Windows
152
} else {
153
ErrnoMode::Permissive
154
};
155
let fs_time_precision = match std::env::var("FS_TIME_PRECISION") {
156
Ok(p) => p.parse().unwrap(),
157
Err(_) => 100,
158
};
159
let no_dangling_filesystem = std::env::var("NO_DANGLING_FILESYSTEM").is_ok();
160
let no_rename_dir_to_empty_dir = std::env::var("NO_RENAME_DIR_TO_EMPTY_DIR").is_ok();
161
TestConfig {
162
errno_mode,
163
fs_time_precision,
164
no_dangling_filesystem,
165
no_rename_dir_to_empty_dir,
166
rename_dir_onto_file: std::env::var("RENAME_DIR_ONTO_FILE").is_ok(),
167
}
168
}
169
pub fn errno_expect_unix(&self) -> bool {
170
match self.errno_mode {
171
ErrnoMode::Unix | ErrnoMode::MacOS => true,
172
_ => false,
173
}
174
}
175
pub fn errno_expect_macos(&self) -> bool {
176
match self.errno_mode {
177
ErrnoMode::MacOS => true,
178
_ => false,
179
}
180
}
181
pub fn errno_expect_windows(&self) -> bool {
182
match self.errno_mode {
183
ErrnoMode::Windows => true,
184
_ => false,
185
}
186
}
187
pub fn fs_time_precision(&self) -> Duration {
188
Duration::from_nanos(self.fs_time_precision)
189
}
190
pub fn support_dangling_filesystem(&self) -> bool {
191
!self.no_dangling_filesystem
192
}
193
pub fn support_rename_dir_to_empty_dir(&self) -> bool {
194
!self.no_rename_dir_to_empty_dir
195
}
196
pub fn support_rename_dir_onto_file(&self) -> bool {
197
self.rename_dir_onto_file
198
}
199
}
200
201