@@ -60,6 +60,131 @@ mod tests {
60
60
Ok ( ( ) )
61
61
}
62
62
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
+
63
188
async fn file_write_read ( ) -> Result < ( ) > {
64
189
let path = "test.txt" ;
65
190
let contents = "Mock content" ;
0 commit comments