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