Skip to content

Commit 385cb01

Browse files
sunfishcodeloganek
authored andcommitted
Port more tests from Wasmtime's testsuite
Following up on ac32f57, port several more tests from Wasmtime's testsuite to wasi-testsuite. It is likely that at least some of these tests are testing behavior which differs between Wasm engine implementations. The intent here is not to instate these as authoritative, but to help surface these differences so that we can discuss whether it's best to change the test, or add documentation to the spec. Other Wasm engines are welcome to submit their tests to wasi-testsuite as well.
1 parent ad174d5 commit 385cb01

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

59 files changed

+2756
-25
lines changed

tests/rust/src/bin/dangling_fd.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ unsafe fn test_dangling_fd(dir_fd: wasi::Fd) {
1717
wasi::path_unlink_file(dir_fd, FILE_NAME).expect("failed to unlink");
1818
let fd = wasi::path_open(dir_fd, 0, FILE_NAME, wasi::OFLAGS_CREAT, 0, 0, 0).unwrap();
1919
wasi::fd_close(fd).unwrap();
20+
wasi::path_unlink_file(dir_fd, FILE_NAME).expect("failed to unlink");
2021

2122
// Now, repeat the same process but for a directory
2223
wasi::path_create_directory(dir_fd, DIR_NAME).expect("failed to create dir");

tests/rust/src/bin/fd_readdir.rs

Lines changed: 1 addition & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use std::{env, mem, process, slice, str};
2-
use wasi::path_create_directory;
3-
use wasi_tests::open_scratch_directory;
2+
use wasi_tests::{create_tmp_dir, open_scratch_directory};
43

54
const BUF_LEN: usize = 256;
65

@@ -53,28 +52,6 @@ impl<'a> Iterator for ReadDir<'a> {
5352
}
5453
}
5554

56-
unsafe fn create_tmp_dir(dir_fd: wasi::Fd, name: &str) -> wasi::Fd {
57-
path_create_directory(dir_fd, name).expect("failed to create dir");
58-
wasi::path_open(
59-
dir_fd,
60-
0,
61-
name,
62-
wasi::OFLAGS_DIRECTORY,
63-
wasi::RIGHTS_FD_FILESTAT_GET
64-
| wasi::RIGHTS_FD_READDIR
65-
| wasi::RIGHTS_PATH_CREATE_FILE
66-
| wasi::RIGHTS_PATH_OPEN
67-
| wasi::RIGHTS_PATH_UNLINK_FILE,
68-
wasi::RIGHTS_FD_READ
69-
| wasi::RIGHTS_FD_WRITE
70-
| wasi::RIGHTS_FD_READDIR
71-
| wasi::RIGHTS_FD_FILESTAT_GET
72-
| wasi::RIGHTS_FD_SEEK,
73-
0,
74-
)
75-
.expect("failed to open dir")
76-
}
77-
7855
/// Return the entries plus a bool indicating EOF.
7956
unsafe fn exec_fd_readdir(fd: wasi::Fd, cookie: wasi::Dircookie) -> (Vec<DirEntry>, bool) {
8057
let mut buf: [u8; BUF_LEN] = [0; BUF_LEN];

tests/rust/src/bin/file_allocate.rs

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
use std::{env, process};
2+
use wasi_tests::{create_tmp_dir, open_scratch_directory, TESTCONFIG};
3+
4+
unsafe fn test_file_allocate(dir_fd: wasi::Fd) {
5+
// Create a file in the scratch directory.
6+
let file_fd = wasi::path_open(
7+
dir_fd,
8+
0,
9+
"file",
10+
wasi::OFLAGS_CREAT,
11+
wasi::RIGHTS_FD_READ
12+
| wasi::RIGHTS_FD_WRITE
13+
| wasi::RIGHTS_FD_ALLOCATE
14+
| wasi::RIGHTS_FD_FILESTAT_GET,
15+
0,
16+
0,
17+
)
18+
.expect("opening a file");
19+
assert!(
20+
file_fd > libc::STDERR_FILENO as wasi::Fd,
21+
"file descriptor range check",
22+
);
23+
24+
// Check file size
25+
let mut stat = wasi::fd_filestat_get(file_fd).expect("reading file stats");
26+
assert_eq!(stat.size, 0, "file size should be 0");
27+
28+
if TESTCONFIG.support_fd_allocate() {
29+
// Allocate some size
30+
wasi::fd_allocate(file_fd, 0, 100).expect("allocating size");
31+
stat = wasi::fd_filestat_get(file_fd).expect("reading file stats");
32+
assert_eq!(stat.size, 100, "file size should be 100");
33+
34+
// Allocate should not modify if less than current size
35+
wasi::fd_allocate(file_fd, 10, 10).expect("allocating size less than current size");
36+
stat = wasi::fd_filestat_get(file_fd).expect("reading file stats");
37+
assert_eq!(stat.size, 100, "file size should remain unchanged at 100");
38+
39+
// Allocate should modify if offset+len > current_len
40+
wasi::fd_allocate(file_fd, 90, 20).expect("allocating size larger than current size");
41+
stat = wasi::fd_filestat_get(file_fd).expect("reading file stats");
42+
assert_eq!(stat.size, 110, "file size should increase from 100 to 110");
43+
}
44+
wasi::fd_close(file_fd).expect("closing a file");
45+
wasi::path_unlink_file(dir_fd, "file").expect("removing a file");
46+
}
47+
48+
fn main() {
49+
let mut args = env::args();
50+
let prog = args.next().unwrap();
51+
let arg = if let Some(arg) = args.next() {
52+
arg
53+
} else {
54+
eprintln!("usage: {} <scratch directory>", prog);
55+
process::exit(1);
56+
};
57+
58+
// Open scratch directory
59+
let base_dir_fd = match open_scratch_directory(&arg) {
60+
Ok(dir_fd) => dir_fd,
61+
Err(err) => {
62+
eprintln!("{}", err);
63+
process::exit(1)
64+
}
65+
};
66+
67+
const DIR_NAME: &str = "file_allocate_dir.cleanup";
68+
let dir_fd;
69+
unsafe {
70+
dir_fd = create_tmp_dir(base_dir_fd, DIR_NAME);
71+
}
72+
73+
// Run the tests.
74+
unsafe { test_file_allocate(dir_fd) }
75+
76+
unsafe { wasi::path_remove_directory(base_dir_fd, DIR_NAME).expect("failed to remove dir") }
77+
}
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
use std::convert::TryInto;
2+
use std::{env, process};
3+
use wasi_tests::{create_tmp_dir, open_scratch_directory};
4+
5+
unsafe fn test_file_pread_pwrite(dir_fd: wasi::Fd) {
6+
// Create a file in the scratch directory.
7+
let file_fd = wasi::path_open(
8+
dir_fd,
9+
0,
10+
"file",
11+
wasi::OFLAGS_CREAT,
12+
wasi::RIGHTS_FD_READ | wasi::RIGHTS_FD_SEEK | wasi::RIGHTS_FD_WRITE,
13+
0,
14+
0,
15+
)
16+
.expect("opening a file");
17+
assert!(
18+
file_fd > libc::STDERR_FILENO as wasi::Fd,
19+
"file descriptor range check",
20+
);
21+
22+
let contents = &[0u8, 1, 2, 3];
23+
let ciovec = wasi::Ciovec {
24+
buf: contents.as_ptr() as *const _,
25+
buf_len: contents.len(),
26+
};
27+
let mut nwritten =
28+
wasi::fd_pwrite(file_fd, &mut [ciovec], 0).expect("writing bytes at offset 0");
29+
assert_eq!(nwritten, 4, "nwritten bytes check");
30+
31+
let contents = &mut [0u8; 4];
32+
let iovec = wasi::Iovec {
33+
buf: contents.as_mut_ptr() as *mut _,
34+
buf_len: contents.len(),
35+
};
36+
let mut nread = wasi::fd_pread(file_fd, &[iovec], 0).expect("reading bytes at offset 0");
37+
assert_eq!(nread, 4, "nread bytes check");
38+
assert_eq!(contents, &[0u8, 1, 2, 3], "written bytes equal read bytes");
39+
40+
// Write all the data through multiple iovecs.
41+
//
42+
// Note that this needs to be done with a loop, because some
43+
// platforms do not support writing multiple iovecs at once.
44+
// See https://github.com/rust-lang/rust/issues/74825.
45+
let contents = &[0u8, 1, 2, 3];
46+
let mut offset = 0usize;
47+
loop {
48+
let mut ciovecs: Vec<wasi::Ciovec> = Vec::new();
49+
let mut remaining = contents.len() - offset;
50+
if remaining > 2 {
51+
ciovecs.push(wasi::Ciovec {
52+
buf: contents[offset..].as_ptr() as *const _,
53+
buf_len: 2,
54+
});
55+
remaining -= 2;
56+
}
57+
ciovecs.push(wasi::Ciovec {
58+
buf: contents[contents.len() - remaining..].as_ptr() as *const _,
59+
buf_len: remaining,
60+
});
61+
62+
nwritten = wasi::fd_pwrite(file_fd, ciovecs.as_slice(), offset.try_into().unwrap())
63+
.expect("writing bytes at offset 0");
64+
65+
offset += nwritten;
66+
if offset == contents.len() {
67+
break;
68+
}
69+
}
70+
assert_eq!(offset, 4, "nread bytes check");
71+
72+
// Read all the data through multiple iovecs.
73+
//
74+
// Note that this needs to be done with a loop, because some
75+
// platforms do not support reading multiple iovecs at once.
76+
// See https://github.com/rust-lang/rust/issues/74825.
77+
let contents = &mut [0u8; 4];
78+
let mut offset = 0usize;
79+
loop {
80+
let buffer = &mut [0u8; 4];
81+
let iovecs = &[
82+
wasi::Iovec {
83+
buf: buffer.as_mut_ptr() as *mut _,
84+
buf_len: 2,
85+
},
86+
wasi::Iovec {
87+
buf: buffer[2..].as_mut_ptr() as *mut _,
88+
buf_len: 2,
89+
},
90+
];
91+
nread = wasi::fd_pread(file_fd, iovecs, offset as _).expect("reading bytes at offset 0");
92+
if nread == 0 {
93+
break;
94+
}
95+
contents[offset..offset + nread].copy_from_slice(&buffer[0..nread]);
96+
offset += nread;
97+
}
98+
assert_eq!(offset, 4, "nread bytes check");
99+
assert_eq!(contents, &[0u8, 1, 2, 3], "file cursor was overwritten");
100+
101+
let contents = &mut [0u8; 4];
102+
let iovec = wasi::Iovec {
103+
buf: contents.as_mut_ptr() as *mut _,
104+
buf_len: contents.len(),
105+
};
106+
nread = wasi::fd_pread(file_fd, &[iovec], 2).expect("reading bytes at offset 2");
107+
assert_eq!(nread, 2, "nread bytes check");
108+
assert_eq!(contents, &[2u8, 3, 0, 0], "file cursor was overwritten");
109+
110+
let contents = &[1u8, 0];
111+
let ciovec = wasi::Ciovec {
112+
buf: contents.as_ptr() as *const _,
113+
buf_len: contents.len(),
114+
};
115+
nwritten = wasi::fd_pwrite(file_fd, &mut [ciovec], 2).expect("writing bytes at offset 2");
116+
assert_eq!(nwritten, 2, "nwritten bytes check");
117+
118+
let contents = &mut [0u8; 4];
119+
let iovec = wasi::Iovec {
120+
buf: contents.as_mut_ptr() as *mut _,
121+
buf_len: contents.len(),
122+
};
123+
nread = wasi::fd_pread(file_fd, &[iovec], 0).expect("reading bytes at offset 0");
124+
assert_eq!(nread, 4, "nread bytes check");
125+
assert_eq!(contents, &[0u8, 1, 1, 0], "file cursor was overwritten");
126+
127+
wasi::fd_close(file_fd).expect("closing a file");
128+
wasi::path_unlink_file(dir_fd, "file").expect("removing a file");
129+
}
130+
131+
fn main() {
132+
let mut args = env::args();
133+
let prog = args.next().unwrap();
134+
let arg = if let Some(arg) = args.next() {
135+
arg
136+
} else {
137+
eprintln!("usage: {} <scratch directory>", prog);
138+
process::exit(1);
139+
};
140+
141+
// Open scratch directory
142+
let base_dir_fd = match open_scratch_directory(&arg) {
143+
Ok(dir_fd) => dir_fd,
144+
Err(err) => {
145+
eprintln!("{}", err);
146+
process::exit(1)
147+
}
148+
};
149+
150+
const DIR_NAME: &str = "file_pread_pwrite_dir.cleanup";
151+
let dir_fd;
152+
unsafe {
153+
dir_fd = create_tmp_dir(base_dir_fd, DIR_NAME);
154+
}
155+
156+
// Run the tests.
157+
unsafe { test_file_pread_pwrite(dir_fd) }
158+
159+
unsafe { wasi::path_remove_directory(base_dir_fd, DIR_NAME).expect("failed to remove dir") }
160+
}

tests/rust/src/bin/file_seek_tell.rs

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
use std::{env, process};
2+
use wasi_tests::{assert_errno, create_tmp_dir, open_scratch_directory};
3+
4+
unsafe fn test_file_seek_tell(dir_fd: wasi::Fd) {
5+
// Create a file in the scratch directory.
6+
let file_fd = wasi::path_open(
7+
dir_fd,
8+
0,
9+
"file",
10+
wasi::OFLAGS_CREAT,
11+
wasi::RIGHTS_FD_READ | wasi::RIGHTS_FD_WRITE | wasi::RIGHTS_FD_SEEK | wasi::RIGHTS_FD_TELL,
12+
0,
13+
0,
14+
)
15+
.expect("opening a file");
16+
assert!(
17+
file_fd > libc::STDERR_FILENO as wasi::Fd,
18+
"file descriptor range check",
19+
);
20+
21+
// Check current offset
22+
let mut offset = wasi::fd_tell(file_fd).expect("getting initial file offset");
23+
assert_eq!(offset, 0, "current offset should be 0");
24+
25+
// Write to file
26+
let data = &[0u8; 100];
27+
let iov = wasi::Ciovec {
28+
buf: data.as_ptr() as *const _,
29+
buf_len: data.len(),
30+
};
31+
let nwritten = wasi::fd_write(file_fd, &[iov]).expect("writing to a file");
32+
assert_eq!(nwritten, 100, "should write 100 bytes to file");
33+
34+
// Check current offset
35+
offset = wasi::fd_tell(file_fd).expect("getting file offset after writing");
36+
assert_eq!(offset, 100, "offset after writing should be 100");
37+
38+
// Seek to middle of the file
39+
let mut newoffset =
40+
wasi::fd_seek(file_fd, -50, wasi::WHENCE_CUR).expect("seeking to the middle of a file");
41+
assert_eq!(
42+
newoffset, 50,
43+
"offset after seeking to the middle should be at 50"
44+
);
45+
46+
// Seek to the beginning of the file
47+
newoffset =
48+
wasi::fd_seek(file_fd, 0, wasi::WHENCE_SET).expect("seeking to the beginning of the file");
49+
assert_eq!(
50+
newoffset, 0,
51+
"offset after seeking to the beginning of the file should be at 0"
52+
);
53+
54+
// Seek beyond the file should be possible
55+
wasi::fd_seek(file_fd, 1000, wasi::WHENCE_CUR).expect("seeking beyond the end of the file");
56+
57+
// Seek before byte 0 is an error though
58+
assert_errno!(
59+
wasi::fd_seek(file_fd, -2000, wasi::WHENCE_CUR)
60+
.expect_err("seeking before byte 0 should be an error"),
61+
wasi::ERRNO_INVAL
62+
);
63+
64+
// Check that fd_read properly updates the file offset
65+
wasi::fd_seek(file_fd, 0, wasi::WHENCE_SET)
66+
.expect("seeking to the beginning of the file again");
67+
68+
let buffer = &mut [0u8; 100];
69+
let iovec = wasi::Iovec {
70+
buf: buffer.as_mut_ptr(),
71+
buf_len: buffer.len(),
72+
};
73+
let nread = wasi::fd_read(file_fd, &[iovec]).expect("reading file");
74+
assert_eq!(nread, buffer.len(), "should read {} bytes", buffer.len());
75+
76+
offset = wasi::fd_tell(file_fd).expect("getting file offset after reading");
77+
assert_eq!(offset, 100, "offset after reading should be 100");
78+
79+
wasi::fd_close(file_fd).expect("closing a file");
80+
wasi::path_unlink_file(dir_fd, "file").expect("deleting a file");
81+
}
82+
fn main() {
83+
let mut args = env::args();
84+
let prog = args.next().unwrap();
85+
let arg = if let Some(arg) = args.next() {
86+
arg
87+
} else {
88+
eprintln!("usage: {} <scratch directory>", prog);
89+
process::exit(1);
90+
};
91+
92+
// Open scratch directory
93+
let base_dir_fd = match open_scratch_directory(&arg) {
94+
Ok(dir_fd) => dir_fd,
95+
Err(err) => {
96+
eprintln!("{}", err);
97+
process::exit(1)
98+
}
99+
};
100+
101+
const DIR_NAME: &str = "file_seek_tell_dir.cleanup";
102+
let dir_fd;
103+
unsafe {
104+
dir_fd = create_tmp_dir(base_dir_fd, DIR_NAME);
105+
}
106+
107+
// Run the tests.
108+
unsafe { test_file_seek_tell(dir_fd) }
109+
110+
unsafe { wasi::path_remove_directory(base_dir_fd, DIR_NAME).expect("failed to remove dir") }
111+
}

0 commit comments

Comments
 (0)