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