1*0686c3d9SAlex Crichton use futures::join;
2*0686c3d9SAlex Crichton use test_programs::p3::wasi::filesystem::types::{
3*0686c3d9SAlex Crichton Descriptor, DescriptorFlags, ErrorCode, OpenFlags, PathFlags,
4*0686c3d9SAlex Crichton };
5*0686c3d9SAlex Crichton use test_programs::p3::{wasi, wit_stream};
6*0686c3d9SAlex Crichton
7*0686c3d9SAlex Crichton struct Component;
8*0686c3d9SAlex Crichton
9*0686c3d9SAlex Crichton test_programs::p3::export!(Component);
10*0686c3d9SAlex Crichton
11*0686c3d9SAlex Crichton impl test_programs::p3::exports::wasi::cli::run::Guest for Component {
run() -> Result<(), ()>12*0686c3d9SAlex Crichton async fn run() -> Result<(), ()> {
13*0686c3d9SAlex Crichton let preopens = wasi::filesystem::preopens::get_directories();
14*0686c3d9SAlex Crichton let (dir, _) = &preopens[0];
15*0686c3d9SAlex Crichton
16*0686c3d9SAlex Crichton test_file_long_write(dir, "long_write.txt").await;
17*0686c3d9SAlex Crichton Ok(())
18*0686c3d9SAlex Crichton }
19*0686c3d9SAlex Crichton }
20*0686c3d9SAlex Crichton
main()21*0686c3d9SAlex Crichton fn main() {
22*0686c3d9SAlex Crichton unreachable!()
23*0686c3d9SAlex Crichton }
24*0686c3d9SAlex Crichton
test_file_long_write(dir: &Descriptor, filename: &str)25*0686c3d9SAlex Crichton async fn test_file_long_write(dir: &Descriptor, filename: &str) {
26*0686c3d9SAlex Crichton let mut content = Vec::new();
27*0686c3d9SAlex Crichton // 16 byte string, 4096 times, is 64k
28*0686c3d9SAlex Crichton for n in 0..4096 {
29*0686c3d9SAlex Crichton let chunk = format!("123456789 {n:05} ");
30*0686c3d9SAlex Crichton assert_eq!(chunk.as_str().as_bytes().len(), 16);
31*0686c3d9SAlex Crichton content.extend_from_slice(chunk.as_str().as_bytes());
32*0686c3d9SAlex Crichton }
33*0686c3d9SAlex Crichton
34*0686c3d9SAlex Crichton // Write to the file
35*0686c3d9SAlex Crichton let file = dir
36*0686c3d9SAlex Crichton .open_at(
37*0686c3d9SAlex Crichton PathFlags::empty(),
38*0686c3d9SAlex Crichton filename.to_string(),
39*0686c3d9SAlex Crichton OpenFlags::CREATE,
40*0686c3d9SAlex Crichton DescriptorFlags::WRITE,
41*0686c3d9SAlex Crichton )
42*0686c3d9SAlex Crichton .await
43*0686c3d9SAlex Crichton .expect("creating a file for writing");
44*0686c3d9SAlex Crichton let (mut tx, rx) = wit_stream::new();
45*0686c3d9SAlex Crichton join! {
46*0686c3d9SAlex Crichton async {
47*0686c3d9SAlex Crichton file.write_via_stream(rx, 0).await.unwrap();
48*0686c3d9SAlex Crichton },
49*0686c3d9SAlex Crichton async {
50*0686c3d9SAlex Crichton let result = tx.write_all(content.clone()).await;
51*0686c3d9SAlex Crichton drop(tx);
52*0686c3d9SAlex Crichton assert!(result.is_empty());
53*0686c3d9SAlex Crichton },
54*0686c3d9SAlex Crichton };
55*0686c3d9SAlex Crichton
56*0686c3d9SAlex Crichton // The file should be of the appropriate size via `stat` now.
57*0686c3d9SAlex Crichton let stat = file.stat().await.unwrap();
58*0686c3d9SAlex Crichton assert_eq!(
59*0686c3d9SAlex Crichton stat.size,
60*0686c3d9SAlex Crichton content.len() as u64,
61*0686c3d9SAlex Crichton "file should be size of content",
62*0686c3d9SAlex Crichton );
63*0686c3d9SAlex Crichton
64*0686c3d9SAlex Crichton drop(file);
65*0686c3d9SAlex Crichton
66*0686c3d9SAlex Crichton // Make sure the file can be read at various offsets.
67*0686c3d9SAlex Crichton let file = dir
68*0686c3d9SAlex Crichton .open_at(
69*0686c3d9SAlex Crichton PathFlags::empty(),
70*0686c3d9SAlex Crichton filename.to_string(),
71*0686c3d9SAlex Crichton OpenFlags::empty(),
72*0686c3d9SAlex Crichton DescriptorFlags::READ,
73*0686c3d9SAlex Crichton )
74*0686c3d9SAlex Crichton .await
75*0686c3d9SAlex Crichton .expect("creating a file for reading");
76*0686c3d9SAlex Crichton
77*0686c3d9SAlex Crichton let (read_contents, result) = file.read_via_stream(0);
78*0686c3d9SAlex Crichton let read_contents = read_contents.collect().await;
79*0686c3d9SAlex Crichton result.await.unwrap();
80*0686c3d9SAlex Crichton assert!(read_contents == content);
81*0686c3d9SAlex Crichton
82*0686c3d9SAlex Crichton let (read_contents, result) = file.read_via_stream((content.len() as u64) - 100);
83*0686c3d9SAlex Crichton let read_contents = read_contents.collect().await;
84*0686c3d9SAlex Crichton result.await.unwrap();
85*0686c3d9SAlex Crichton assert!(read_contents == &content[content.len() - 100..]);
86*0686c3d9SAlex Crichton drop(file);
87*0686c3d9SAlex Crichton
88*0686c3d9SAlex Crichton // Writing to a read-only handle should be an error.
89*0686c3d9SAlex Crichton let filename = "test-zero-write-fails.txt";
90*0686c3d9SAlex Crichton dir.open_at(
91*0686c3d9SAlex Crichton PathFlags::empty(),
92*0686c3d9SAlex Crichton filename.to_string(),
93*0686c3d9SAlex Crichton OpenFlags::CREATE,
94*0686c3d9SAlex Crichton DescriptorFlags::WRITE,
95*0686c3d9SAlex Crichton )
96*0686c3d9SAlex Crichton .await
97*0686c3d9SAlex Crichton .expect("creating a file for writing");
98*0686c3d9SAlex Crichton let file = dir
99*0686c3d9SAlex Crichton .open_at(
100*0686c3d9SAlex Crichton PathFlags::empty(),
101*0686c3d9SAlex Crichton filename.to_string(),
102*0686c3d9SAlex Crichton OpenFlags::empty(),
103*0686c3d9SAlex Crichton DescriptorFlags::READ,
104*0686c3d9SAlex Crichton )
105*0686c3d9SAlex Crichton .await
106*0686c3d9SAlex Crichton .expect("creating a file for writing");
107*0686c3d9SAlex Crichton
108*0686c3d9SAlex Crichton let (mut tx, rx) = wit_stream::new();
109*0686c3d9SAlex Crichton join! {
110*0686c3d9SAlex Crichton async {
111*0686c3d9SAlex Crichton let err = file.write_via_stream(rx, 0).await.unwrap_err();
112*0686c3d9SAlex Crichton assert!(
113*0686c3d9SAlex Crichton matches!(err, ErrorCode::Access | ErrorCode::BadDescriptor | ErrorCode::NotPermitted),
114*0686c3d9SAlex Crichton "bad error {err:?}",
115*0686c3d9SAlex Crichton );
116*0686c3d9SAlex Crichton },
117*0686c3d9SAlex Crichton async {
118*0686c3d9SAlex Crichton let result = tx.write_all(b"x".to_vec()).await;
119*0686c3d9SAlex Crichton drop(tx);
120*0686c3d9SAlex Crichton assert_eq!(result.len(), 1);
121*0686c3d9SAlex Crichton },
122*0686c3d9SAlex Crichton };
123*0686c3d9SAlex Crichton }
124