FileSystemWritableFileStream-write.js (13720B)
1 'use strict'; 2 3 directory_test(async (t, root) => { 4 const handle = await createEmptyFile('empty_blob', root); 5 const stream = await handle.createWritable(); 6 7 await stream.write(new Blob([])); 8 await stream.close(); 9 10 assert_equals(await getFileContents(handle), ''); 11 assert_equals(await getFileSize(handle), 0); 12 }, 'write() with an empty blob to an empty file'); 13 14 directory_test(async (t, root) => { 15 const handle = await createEmptyFile('valid_blob', root); 16 const stream = await handle.createWritable(); 17 18 await stream.write(new Blob(['1234567890'])); 19 await stream.close(); 20 21 assert_equals(await getFileContents(handle), '1234567890'); 22 assert_equals(await getFileSize(handle), 10); 23 }, 'write() a blob to an empty file'); 24 25 directory_test(async (t, root) => { 26 const handle = await createEmptyFile('write_param_empty', root); 27 const stream = await handle.createWritable(); 28 29 await stream.write({type: 'write', data: '1234567890'}); 30 await stream.close(); 31 32 assert_equals(await getFileContents(handle), '1234567890'); 33 assert_equals(await getFileSize(handle), 10); 34 }, 'write() with WriteParams without position to an empty file'); 35 36 directory_test(async (t, root) => { 37 const handle = await createEmptyFile('string_zero_offset', root); 38 const stream = await handle.createWritable(); 39 40 await stream.write({type: 'write', position: 0, data: '1234567890'}); 41 await stream.close(); 42 43 assert_equals(await getFileContents(handle), '1234567890'); 44 assert_equals(await getFileSize(handle), 10); 45 }, 'write() a string to an empty file with zero offset'); 46 47 directory_test(async (t, root) => { 48 const handle = await createEmptyFile('blob_zero_offset', root); 49 const stream = await handle.createWritable(); 50 51 await stream.write( 52 {type: 'write', position: 0, data: new Blob(['1234567890'])}); 53 await stream.close(); 54 55 assert_equals(await getFileContents(handle), '1234567890'); 56 assert_equals(await getFileSize(handle), 10); 57 }, 'write() a blob to an empty file with zero offset'); 58 59 directory_test(async (t, root) => { 60 const handle = await createEmptyFile('write_appends', root); 61 const stream = await handle.createWritable(); 62 63 await stream.write('12345'); 64 await stream.write('67890'); 65 await stream.close(); 66 67 assert_equals(await getFileContents(handle), '1234567890'); 68 assert_equals(await getFileSize(handle), 10); 69 }, 'write() called consecutively appends'); 70 71 directory_test(async (t, root) => { 72 const handle = await createEmptyFile('write_appends_object_string', root); 73 const stream = await handle.createWritable(); 74 75 await stream.write('12345'); 76 await stream.write({type: 'write', data: '67890'}); 77 await stream.close(); 78 79 assert_equals(await getFileContents(handle), '1234567890'); 80 assert_equals(await getFileSize(handle), 10); 81 }, 'write() WriteParams without position and string appends'); 82 83 directory_test(async (t, root) => { 84 const handle = await createEmptyFile('write_appends_object_blob', root); 85 const stream = await handle.createWritable(); 86 87 await stream.write('12345'); 88 await stream.write({type: 'write', data: new Blob(['67890'])}); 89 await stream.close(); 90 91 assert_equals(await getFileContents(handle), '1234567890'); 92 assert_equals(await getFileSize(handle), 10); 93 }, 'write() WriteParams without position and blob appends'); 94 95 directory_test(async (t, root) => { 96 const handle = await createEmptyFile('string_with_offset', root); 97 const stream = await handle.createWritable(); 98 99 await stream.write('1234567890'); 100 await stream.write({type: 'write', position: 4, data: 'abc'}); 101 await stream.close(); 102 103 assert_equals(await getFileContents(handle), '1234abc890'); 104 assert_equals(await getFileSize(handle), 10); 105 }, 'write() called with a string and a valid offset'); 106 107 directory_test(async (t, root) => { 108 const handle = 109 await createEmptyFile('write_string_with_offset_after_seek', root); 110 const stream = await handle.createWritable(); 111 112 await stream.write('1234567890'); 113 await stream.write({type: 'seek', position: 0}); 114 await stream.write({type: 'write', position: 4, data: 'abc'}); 115 await stream.close(); 116 117 assert_equals(await getFileContents(handle), '1234abc890'); 118 assert_equals(await getFileSize(handle), 10); 119 }, 'write() called with a string and a valid offset after seek'); 120 121 directory_test(async (t, root) => { 122 const handle = await createEmptyFile('blob_with_offset', root); 123 const stream = await handle.createWritable(); 124 125 await stream.write('1234567890'); 126 await stream.write({type: 'write', position: 4, data: new Blob(['abc'])}); 127 await stream.close(); 128 129 assert_equals(await getFileContents(handle), '1234abc890'); 130 assert_equals(await getFileSize(handle), 10); 131 }, 'write() called with a blob and a valid offset'); 132 133 directory_test(async (t, root) => { 134 const handle = await createEmptyFile('bad_offset', root); 135 const stream = await handle.createWritable(); 136 137 await stream.write({type: 'write', position: 4, data: new Blob(['abc'])}); 138 await stream.close(); 139 140 assert_equals(await getFileContents(handle), '\0\0\0\0abc'); 141 assert_equals(await getFileSize(handle), 7); 142 }, 'write() called with an offset beyond the end of the file'); 143 144 directory_test(async (t, root) => { 145 const handle = await createEmptyFile('empty_string', root); 146 const stream = await handle.createWritable(); 147 148 await stream.write(''); 149 await stream.close(); 150 assert_equals(await getFileContents(handle), ''); 151 assert_equals(await getFileSize(handle), 0); 152 }, 'write() with an empty string to an empty file'); 153 154 directory_test(async (t, root) => { 155 const handle = await createEmptyFile('valid_utf8_string', root); 156 const stream = await handle.createWritable(); 157 158 await stream.write('foo🤘'); 159 await stream.close(); 160 assert_equals(await getFileContents(handle), 'foo🤘'); 161 assert_equals(await getFileSize(handle), 7); 162 }, 'write() with a valid utf-8 string'); 163 164 directory_test(async (t, root) => { 165 const handle = await createEmptyFile('string_with_unix_line_ending', root); 166 const stream = await handle.createWritable(); 167 168 await stream.write('foo\n'); 169 await stream.close(); 170 assert_equals(await getFileContents(handle), 'foo\n'); 171 assert_equals(await getFileSize(handle), 4); 172 }, 'write() with a string with unix line ending preserved'); 173 174 directory_test(async (t, root) => { 175 const handle = await createEmptyFile('string_with_windows_line_ending', root); 176 const stream = await handle.createWritable(); 177 178 await stream.write('foo\r\n'); 179 await stream.close(); 180 assert_equals(await getFileContents(handle), 'foo\r\n'); 181 assert_equals(await getFileSize(handle), 5); 182 }, 'write() with a string with windows line ending preserved'); 183 184 directory_test(async (t, root) => { 185 const handle = await createEmptyFile('empty_array_buffer', root); 186 const stream = await handle.createWritable(); 187 188 const buf = new ArrayBuffer(0); 189 await stream.write(buf); 190 await stream.close(); 191 assert_equals(await getFileContents(handle), ''); 192 assert_equals(await getFileSize(handle), 0); 193 }, 'write() with an empty array buffer to an empty file'); 194 195 directory_test(async (t, root) => { 196 const handle = await createEmptyFile('valid_string_typed_byte_array', root); 197 const stream = await handle.createWritable(); 198 199 const buf = new ArrayBuffer(3); 200 const intView = new Uint8Array(buf); 201 intView[0] = 0x66; 202 intView[1] = 0x6f; 203 intView[2] = 0x6f; 204 await stream.write(buf); 205 await stream.close(); 206 assert_equals(await getFileContents(handle), 'foo'); 207 assert_equals(await getFileSize(handle), 3); 208 }, 'write() with a valid typed array buffer'); 209 210 directory_test(async (t, root) => { 211 const handle = await createEmptyFile('atomic_writes.txt', root); 212 const stream = await handle.createWritable(); 213 await stream.write('foox'); 214 215 const stream2 = await cleanup_writable(t, await handle.createWritable()); 216 await stream2.write('bar'); 217 218 assert_equals(await getFileSize(handle), 0); 219 220 await stream2.close(); 221 assert_equals(await getFileContents(handle), 'bar'); 222 assert_equals(await getFileSize(handle), 3); 223 224 await stream.close(); 225 assert_equals(await getFileContents(handle), 'foox'); 226 assert_equals(await getFileSize(handle), 4); 227 }, 'atomic writes: writable file streams make atomic changes on close'); 228 229 directory_test(async (t, root) => { 230 const handle = await createEmptyFile('atomic_write_after_close.txt', root); 231 const stream = await handle.createWritable(); 232 await stream.write('foo'); 233 234 await stream.close(); 235 assert_equals(await getFileContents(handle), 'foo'); 236 assert_equals(await getFileSize(handle), 3); 237 238 await promise_rejects_js(t, TypeError, stream.write('abc')); 239 }, 'atomic writes: write() after close() fails'); 240 241 directory_test(async (t, root) => { 242 const handle = await createEmptyFile('atomic_truncate_after_close.txt', root); 243 const stream = await handle.createWritable(); 244 await stream.write('foo'); 245 246 await stream.close(); 247 assert_equals(await getFileContents(handle), 'foo'); 248 assert_equals(await getFileSize(handle), 3); 249 250 await promise_rejects_js(t, TypeError, stream.truncate(0)); 251 }, 'atomic writes: truncate() after close() fails'); 252 253 directory_test(async (t, root) => { 254 const handle = await createEmptyFile('atomic_close_after_close.txt', root); 255 const stream = await handle.createWritable(); 256 await stream.write('foo'); 257 258 await stream.close(); 259 assert_equals(await getFileContents(handle), 'foo'); 260 assert_equals(await getFileSize(handle), 3); 261 262 await promise_rejects_js(t, TypeError, stream.close()); 263 }, 'atomic writes: close() after close() fails'); 264 265 directory_test(async (t, root) => { 266 const handle = await createEmptyFile('there_can_be_only_one.txt', root); 267 const stream = await handle.createWritable(); 268 await stream.write('foo'); 269 270 // This test might be flaky if there is a race condition allowing 271 // close() to be called multiple times. 272 const success_promises = 273 [...Array(100)].map(() => stream.close().then(() => 1).catch(() => 0)); 274 const close_attempts = await Promise.all(success_promises); 275 const success_count = close_attempts.reduce((x, y) => x + y); 276 assert_equals(success_count, 1); 277 }, 'atomic writes: only one close() operation may succeed'); 278 279 directory_test(async (t, root) => { 280 const handle = await createEmptyFile('writer_written', root); 281 const stream = await handle.createWritable(); 282 assert_false(stream.locked); 283 const writer = stream.getWriter(); 284 assert_true(stream.locked); 285 286 await writer.write('foo'); 287 await writer.write(new Blob(['bar'])); 288 await writer.write({type: 'seek', position: 0}); 289 await writer.write({type: 'write', data: 'baz'}); 290 await writer.close(); 291 292 assert_equals(await getFileContents(handle), 'bazbar'); 293 assert_equals(await getFileSize(handle), 6); 294 }, 'getWriter() can be used'); 295 296 directory_test(async (t, root) => { 297 const handle = 298 await createFileWithContents('content.txt', 'very long string', root); 299 const stream = await handle.createWritable(); 300 301 await promise_rejects_dom( 302 t, 'SyntaxError', stream.write({type: 'truncate'}), 303 'truncate without size'); 304 }, 'WriteParams: truncate missing size param'); 305 306 directory_test(async (t, root) => { 307 const handle = await createEmptyFile('content.txt', root); 308 const stream = await handle.createWritable(); 309 310 await promise_rejects_dom( 311 t, 'SyntaxError', stream.write({type: 'write'}), 'write without data'); 312 }, 'WriteParams: write missing data param'); 313 314 directory_test(async (t, root) => { 315 const handle = await createEmptyFile('content.txt', root); 316 const stream = await handle.createWritable(); 317 318 await promise_rejects_js( 319 t, TypeError, stream.write({type: 'write', data: null}), 320 'write with null data'); 321 }, 'WriteParams: write null data param'); 322 323 directory_test(async (t, root) => { 324 const handle = await createFileWithContents('content.txt', 'seekable', root); 325 const stream = await handle.createWritable(); 326 327 await promise_rejects_dom( 328 t, 'SyntaxError', stream.write({type: 'seek'}), 'seek without position'); 329 }, 'WriteParams: seek missing position param'); 330 331 directory_test(async (t, root) => { 332 const source_file = 333 await createFileWithContents('source_file', 'source data', root); 334 const source_blob = await source_file.getFile(); 335 await root.removeEntry(source_file.name); 336 337 const handle = await createEmptyFile('invalid_blob_test', root); 338 const stream = await handle.createWritable(); 339 await promise_rejects_dom(t, "NotFoundError", stream.write(source_blob)); 340 await promise_rejects_js(t, TypeError, stream.close()); 341 342 assert_equals(await getFileContents(handle), ''); 343 assert_equals(await getFileSize(handle), 0); 344 }, 'write() with an invalid blob to an empty file should reject'); 345 346 directory_test(async (t, root) => { 347 const handle = await createFileWithContents('file.txt', 'contents', root); 348 const stream = await handle.createWritable({mode: 'exclusive'}); 349 350 await stream.write('12345'); 351 await promise_rejects_js( 352 t, TypeError, stream.write({type: 'write', data: null}), 353 'write with null data'); 354 355 // The file contents should not have been changed. 356 assert_equals(await getFileContents(handle), 'contents'); 357 358 // The file's lock was released. 359 const newStream = await handle.createWritable({mode: 'exclusive'}); 360 await newStream.close(); 361 }, 'an errored writable stream releases its lock'); 362 363 directory_test(async (t, root) => { 364 const handle = await createFileWithContents('file.txt', 'contents', root); 365 const stream = await handle.createWritable({mode: 'exclusive'}); 366 367 const writer = stream.getWriter(); 368 369 await promise_rejects_js(t, TypeError, writer.write(null), 'write with null data'); 370 await promise_rejects_js(t, TypeError, writer.write("foo"), 'write with text data'); 371 }, 'an errored writable stream should reject the next write call');