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 { 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 21 fn main() { 22 unreachable!() 23 } 24 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