@@ -60,6 +60,131 @@ mod tests {
6060 Ok ( ( ) )
6161 }
6262
63+ #[ tokio:: test]
64+ async fn poll_complete_after_write ( ) -> Result < ( ) > {
65+ use futures:: future:: poll_fn;
66+ use std:: pin:: Pin ;
67+ use tokio:: io:: { AsyncSeek , AsyncWriteExt } ;
68+
69+ let path = "pos_after_write.txt" ;
70+ let mut f = File :: create ( path) . await ?;
71+ f. write_all ( b"hello" ) . await ?; // 5 bytes
72+ f. flush ( ) . await ?; // wait for the write to finish
73+
74+ // Ask the file itself where it thinks the cursor is.
75+ let mut pinned = Pin :: new ( & mut f) ;
76+ let pos = poll_fn ( |cx| pinned. as_mut ( ) . poll_complete ( cx) ) . await ?;
77+
78+ // **BUG**: returns 0 with the current implementation
79+ assert_eq ! ( pos, 5 , "cursor should sit just past the 5 written bytes" ) ;
80+ Ok ( ( ) )
81+ }
82+
83+ #[ tokio:: test]
84+ async fn poll_complete_after_set_len ( ) -> Result < ( ) > {
85+ use futures:: future:: poll_fn;
86+ use std:: pin:: Pin ;
87+ use tokio:: io:: { AsyncSeek , AsyncSeekExt , AsyncWriteExt } ;
88+
89+ let path = "pos_after_set_len.txt" ;
90+ let mut f = File :: create ( path) . await ?;
91+ f. write_all ( b"abcdef" ) . await ?; // 6 bytes
92+ f. flush ( ) . await ?;
93+ f. seek ( std:: io:: SeekFrom :: Start ( 2 ) ) . await ?; // move to byte 2
94+
95+ f. set_len ( 100 ) . await ?; // extend – should *not* move the cursor
96+
97+ let mut pinned = Pin :: new ( & mut f) ;
98+ let pos = poll_fn ( |cx| pinned. as_mut ( ) . poll_complete ( cx) ) . await ?;
99+
100+ // **BUG**: current code reports 0 instead of 2
101+ assert_eq ! ( pos, 2 , "set_len must preserve the current offset" ) ;
102+ Ok ( ( ) )
103+ }
104+
105+ #[ tokio:: test]
106+ async fn poll_complete_after_read ( ) -> Result < ( ) > {
107+ use futures:: future:: poll_fn;
108+ use std:: pin:: Pin ;
109+ use tokio:: io:: { AsyncReadExt , AsyncSeek , AsyncWriteExt } ;
110+
111+ // Create a test file with some content
112+ let path = "pos_after_read.txt" ;
113+ let mut f = File :: create ( path) . await ?;
114+ f. write_all ( b"hello world" ) . await ?; // 11 bytes
115+ f. flush ( ) . await ?;
116+
117+ // Close and reopen the file for reading
118+ drop ( f) ;
119+ let mut f = File :: open ( path) . await ?;
120+
121+ // Read part of the content
122+ let mut buf = [ 0u8 ; 5 ] ; // Only read first 5 bytes
123+ f. read_exact ( & mut buf) . await ?;
124+ assert_eq ! ( & buf, b"hello" ) ;
125+
126+ // Ask the file where it thinks the cursor is
127+ let mut pinned = Pin :: new ( & mut f) ;
128+ let pos = poll_fn ( |cx| pinned. as_mut ( ) . poll_complete ( cx) ) . await ?;
129+
130+ // Verify the cursor has advanced by the number of bytes read
131+ assert_eq ! ( pos, 5 , "cursor should sit just past the 5 read bytes" ) ;
132+
133+ // Read more bytes and check position again
134+ f. read_exact ( & mut buf) . await ?; // Read next 5 bytes
135+ assert_eq ! ( & buf, b" worl" ) ;
136+
137+ let mut pinned = Pin :: new ( & mut f) ;
138+ let pos = poll_fn ( |cx| pinned. as_mut ( ) . poll_complete ( cx) ) . await ?;
139+
140+ // Verify cursor has advanced further
141+ assert_eq ! ( pos, 10 , "cursor should advance after additional reads" ) ;
142+
143+ Ok ( ( ) )
144+ }
145+
146+ #[ tokio:: test]
147+ async fn seek_after_pending_write ( ) -> Result < ( ) > {
148+ use tokio:: io:: { AsyncSeekExt , AsyncWriteExt } ;
149+
150+ let path = "seek_after_pending.txt" ;
151+ let mut f = File :: create ( path) . await ?;
152+ f. write_all ( b"xyz" ) . await ?; // leaves an in-flight write
153+
154+ // Try to find out where we are without an explicit flush.
155+ // Tokio’s real File lets this succeed; our version currently errors.
156+ let pos = f. seek ( std:: io:: SeekFrom :: Current ( 0 ) ) . await ;
157+
158+ // **BUG**: expect Ok(3), get Err(other operation is pending)
159+ assert_eq ! (
160+ pos. unwrap( ) ,
161+ 3 ,
162+ "seek should wait for the write to finish"
163+ ) ;
164+ Ok ( ( ) )
165+ }
166+
167+ #[ tokio:: test]
168+ async fn test_sync_all ( ) -> Result < ( ) > {
169+ let buf = [ 0u8 ; 1024 ] ;
170+ let path = "test_sync_all.txt" ;
171+ let tmp_path = "test_sync_all.txt.tmp" ;
172+ let mut f = OpenOptions :: new ( )
173+ . write ( true )
174+ . create ( true )
175+ . truncate ( true )
176+ . open ( & tmp_path)
177+ . await ?;
178+ f. write_all ( & buf) . await ?;
179+ f. sync_all ( ) . await ?;
180+ assert ! ( vfs:: try_exists( & tmp_path) . await ?) ;
181+ assert_eq ! ( vfs:: metadata( & tmp_path) . await ?. len( ) , buf. len( ) as u64 ) ;
182+ vfs:: rename ( tmp_path, path) . await ?;
183+ assert ! ( vfs:: try_exists( path) . await ?) ;
184+ assert_eq ! ( vfs:: metadata( path) . await ?. len( ) , buf. len( ) as u64 ) ;
185+ Ok ( ( ) )
186+ }
187+
63188 async fn file_write_read ( ) -> Result < ( ) > {
64189 let path = "test.txt" ;
65190 let contents = "Mock content" ;
0 commit comments