1'use strict'; 2 3import { FileSystem as FS, Asset } from 'expo'; 4 5export const name = 'FileSystem'; 6 7export function test(t) { 8 t.describe('FileSystem', () => { 9 const throws = async run => { 10 let error = null; 11 try { 12 await run(); 13 } catch (e) { 14 // Uncomment to log error message. 15 // const func = run.toString().match(/[A-Za-z]+\(/)[0].slice(0, -1); 16 // console.log(`${func}: ${e.message}`); 17 error = e; 18 } 19 t.expect(error).toBeTruthy(); 20 }; 21 22 /*t.it( 23 'delete(idempotent) -> !exists -> download(md5, uri) -> exists ' + '-> delete -> !exists', 24 async () => { 25 const localUri = FS.documentDirectory + 'download1.png'; 26 27 const assertExists = async expectedToExist => { 28 let { exists } = await FS.getInfoAsync(localUri); 29 if (expectedToExist) { 30 t.expect(exists).toBeTruthy(); 31 } else { 32 t.expect(exists).not.toBeTruthy(); 33 } 34 }; 35 36 await FS.deleteAsync(localUri, { idempotent: true }); 37 await assertExists(false); 38 39 const { 40 md5, 41 uri, 42 headers, 43 } = await FS.downloadAsync( 44 'https://s3-us-west-1.amazonaws.com/test-suite-data/avatar2.png', 45 localUri, 46 { md5: true } 47 ); 48 t.expect(md5).toBe('1e02045c10b8f1145edc7c8375998f87'); 49 await assertExists(true); 50 t.expect(headers['Content-Type']).toBe('image/png'); 51 52 await FS.deleteAsync(localUri); 53 await assertExists(false); 54 }, 55 9000 56 );*/ 57 58 t.it('Can read/write Base64', async () => { 59 const asset = await Asset.fromModule(require('../assets/icons/app.png')); 60 await asset.downloadAsync(); 61 62 for (let startingPosition = 0; startingPosition < 3; startingPosition++) { 63 const options = { 64 encoding: FS.EncodingTypes.Base64, 65 position: startingPosition, 66 length: startingPosition + 1, 67 }; 68 69 const b64 = await FS.readAsStringAsync(asset.localUri, options); 70 t.expect(b64).toBeDefined(); 71 t.expect(typeof b64).toBe('string'); 72 t.expect(b64.length % 4).toBe(0); 73 74 const localUri = FS.documentDirectory + 'b64.png'; 75 76 await FS.writeAsStringAsync(localUri, b64, { encoding: FS.EncodingTypes.Base64 }); 77 78 t.expect(await FS.readAsStringAsync(localUri, { encoding: FS.EncodingTypes.Base64 })).toBe( 79 b64 80 ); 81 } 82 }); 83 84 t.it('delete(idempotent) -> delete[error]', async () => { 85 const localUri = FS.documentDirectory + 'willDelete.png'; 86 87 await FS.deleteAsync(localUri, { idempotent: true }); 88 89 let error; 90 try { 91 await FS.deleteAsync(localUri); 92 } catch (e) { 93 error = e; 94 } 95 t.expect(error.message).toMatch(/not.*found/); 96 }); 97 98 /*t.it( 99 'download(md5, uri) -> read -> delete -> !exists -> read[error]', 100 async () => { 101 const localUri = FS.documentDirectory + 'download1.txt'; 102 103 const { 104 md5, 105 uri, 106 } = await FS.downloadAsync( 107 'https://s3-us-west-1.amazonaws.com/test-suite-data/text-file.txt', 108 localUri, 109 { md5: true } 110 ); 111 t.expect(md5).toBe('86d73d2f11e507365f7ea8e7ec3cc4cb'); 112 113 const string = await FS.readAsStringAsync(localUri); 114 t.expect(string).toBe('hello, world\nthis is a test file\n'); 115 116 await FS.deleteAsync(localUri, { idempotent: true }); 117 118 let error; 119 try { 120 await FS.readAsStringAsync(localUri); 121 } catch (e) { 122 error = e; 123 } 124 t.expect(error).toBeTruthy(); 125 }, 126 9000 127 );*/ 128 129 t.it('delete(idempotent) -> !exists -> write -> read -> write -> read', async () => { 130 const localUri = FS.documentDirectory + 'write1.txt'; 131 132 await FS.deleteAsync(localUri, { idempotent: true }); 133 134 const { exists } = await FS.getInfoAsync(localUri); 135 t.expect(exists).not.toBeTruthy(); 136 137 const writeAndVerify = async expected => { 138 await FS.writeAsStringAsync(localUri, expected); 139 const string = await FS.readAsStringAsync(localUri); 140 t.expect(string).toBe(expected); 141 }; 142 143 await writeAndVerify('hello, world'); 144 await writeAndVerify('hello, world!!!!!!'); 145 }); 146 147 t.it('delete(new) -> 2 * [write -> move -> !exists(orig) -> read(new)]', async () => { 148 const from = FS.documentDirectory + 'from.txt'; 149 const to = FS.documentDirectory + 'to.txt'; 150 const contents = ['contents 1', 'contents 2']; 151 152 await FS.deleteAsync(to, { idempotent: true }); 153 154 // Move twice to make sure we can overwrite 155 for (let i = 0; i < 2; ++i) { 156 await FS.writeAsStringAsync(from, contents[i]); 157 158 await FS.moveAsync({ from, to }); 159 160 const { exists } = await FS.getInfoAsync(from); 161 t.expect(exists).not.toBeTruthy(); 162 163 t.expect(await FS.readAsStringAsync(to)).toBe(contents[i]); 164 } 165 }); 166 167 t.it('delete(new) -> 2 * [write -> copy -> exists(orig) -> read(new)]', async () => { 168 const from = FS.documentDirectory + 'from.txt'; 169 const to = FS.documentDirectory + 'to.txt'; 170 const contents = ['contents 1', 'contents 2']; 171 172 await FS.deleteAsync(to, { idempotent: true }); 173 174 // Copy twice to make sure we can overwrite 175 for (let i = 0; i < 2; ++i) { 176 await FS.writeAsStringAsync(from, contents[i]); 177 178 await FS.copyAsync({ from, to }); 179 180 const { exists } = await FS.getInfoAsync(from); 181 t.expect(exists).toBeTruthy(); 182 183 t.expect(await FS.readAsStringAsync(to)).toBe(contents[i]); 184 } 185 }); 186 187 t.it( 188 'delete(dir) -> write(dir/file)[error] -> mkdir(dir) ->' + 189 'mkdir(dir)[error] -> write(dir/file) -> read', 190 async () => { 191 let error; 192 const path = FS.documentDirectory + 'dir/file'; 193 const dir = FS.documentDirectory + 'dir'; 194 const contents = 'hello, world'; 195 196 await FS.deleteAsync(dir, { idempotent: true }); 197 198 error = null; 199 try { 200 await FS.writeAsStringAsync(path, contents); 201 } catch (e) { 202 error = e; 203 } 204 t.expect(error).toBeTruthy(); 205 206 await FS.makeDirectoryAsync(dir); 207 208 error = null; 209 try { 210 await FS.makeDirectoryAsync(dir); 211 } catch (e) { 212 error = e; 213 } 214 t.expect(error).toBeTruthy(); 215 216 await FS.writeAsStringAsync(path, contents); 217 218 t.expect(await FS.readAsStringAsync(path)).toBe(contents); 219 } 220 ); 221 222 t.it( 223 'delete(dir) -> write(dir/dir2/file)[error] -> ' + 224 'mkdir(dir/dir2, intermediates) -> ' + 225 'mkdir(dir/dir2, intermediates) -> write(dir/dir2/file) -> read', 226 async () => { 227 let error; 228 const path = FS.documentDirectory + 'dir/dir2/file'; 229 const dir = FS.documentDirectory + 'dir/dir2'; 230 const contents = 'hello, world'; 231 232 await FS.deleteAsync(dir, { idempotent: true }); 233 234 error = null; 235 try { 236 await FS.writeAsStringAsync(path, contents); 237 } catch (e) { 238 error = e; 239 } 240 t.expect(error).toBeTruthy(); 241 242 await FS.makeDirectoryAsync(dir, { 243 intermediates: true, 244 }); 245 246 error = null; 247 try { 248 await FS.makeDirectoryAsync(dir); 249 } catch (e) { 250 error = e; 251 } 252 t.expect(error).toBeTruthy(); 253 254 error = null; 255 try { 256 await FS.makeDirectoryAsync(dir, { 257 intermediates: true, 258 }); 259 } catch (e) { 260 error = e; 261 } 262 t.expect(error).toBe(null); 263 264 await FS.writeAsStringAsync(path, contents); 265 266 t.expect(await FS.readAsStringAsync(path)).toBe(contents); 267 } 268 ); 269 270 t.it( 271 'delete(dir, idempotent) -> make tree -> check contents ' + 272 '-> check directory listings' + 273 '-> move -> check directory listings' + 274 '-> copy -> check directory listings', 275 async () => { 276 let error; 277 const dir = FS.documentDirectory + 'dir'; 278 279 await FS.deleteAsync(dir, { idempotent: true }); 280 281 await FS.makeDirectoryAsync(dir + '/child1', { 282 intermediates: true, 283 }); 284 await FS.makeDirectoryAsync(dir + '/child2', { 285 intermediates: true, 286 }); 287 288 await FS.writeAsStringAsync(dir + '/file1', 'contents1'); 289 await FS.writeAsStringAsync(dir + '/file2', 'contents2'); 290 291 await FS.writeAsStringAsync(dir + '/child1/file3', 'contents3'); 292 293 await FS.writeAsStringAsync(dir + '/child2/file4', 'contents4'); 294 await FS.writeAsStringAsync(dir + '/child2/file5', 'contents5'); 295 296 const checkContents = async (path, contents) => 297 t.expect(await FS.readAsStringAsync(path)).toBe(contents); 298 299 await checkContents(dir + '/file1', 'contents1'); 300 await checkContents(dir + '/file2', 'contents2'); 301 await checkContents(dir + '/child1/file3', 'contents3'); 302 await checkContents(dir + '/child2/file4', 'contents4'); 303 await checkContents(dir + '/child2/file5', 'contents5'); 304 305 const checkDirectory = async (path, expected) => { 306 const list = await FS.readDirectoryAsync(path); 307 t.expect(list.sort()).toEqual(expected.sort()); 308 }; 309 310 const checkRoot = async root => { 311 await checkDirectory(root, ['file1', 'file2', 'child1', 'child2']); 312 await checkDirectory(root + '/child1', ['file3']); 313 await checkDirectory(root + '/child2', ['file4', 'file5']); 314 315 error = null; 316 try { 317 await checkDirectory(root + '/file1', ['nope']); 318 } catch (e) { 319 error = e; 320 } 321 t.expect(error).toBeTruthy(); 322 }; 323 324 await checkRoot(dir); 325 326 await FS.deleteAsync(FS.documentDirectory + 'moved', { 327 idempotent: true, 328 }); 329 await FS.moveAsync({ from: dir, to: FS.documentDirectory + 'moved' }); 330 await checkRoot(FS.documentDirectory + 'moved'); 331 await FS.copyAsync({ 332 from: FS.documentDirectory + 'moved', 333 to: FS.documentDirectory + 'copied', 334 }); 335 await checkRoot(FS.documentDirectory + 'copied'); 336 } 337 ); 338 339 t.it( 340 'delete(idempotent) -> download(md5) -> getInfo(size)', 341 async () => { 342 const localUri = FS.documentDirectory + 'download1.png'; 343 344 await FS.deleteAsync(localUri, { idempotent: true }); 345 346 const { md5 } = await FS.downloadAsync( 347 'https://s3-us-west-1.amazonaws.com/test-suite-data/avatar2.png', 348 localUri, 349 { md5: true } 350 ); 351 t.expect(md5).toBe('1e02045c10b8f1145edc7c8375998f87'); 352 353 const { size, modificationTime } = await FS.getInfoAsync(localUri); 354 t.expect(size).toBe(3230); 355 const nowTime = 0.001 * new Date().getTime(); 356 t.expect(nowTime - modificationTime).toBeLessThan(3600); 357 358 await FS.deleteAsync(localUri); 359 }, 360 30000 361 ); 362 363 t.it('throws out-of-scope exceptions', async () => { 364 const p = FS.documentDirectory; 365 366 await throws(() => FS.getInfoAsync(p + '../hello/world')); 367 await throws(() => FS.readAsStringAsync(p + '../hello/world')); 368 await throws(() => FS.writeAsStringAsync(p + '../hello/world', '')); 369 await throws(() => FS.deleteAsync(p + '../hello/world')); 370 await throws(() => FS.deleteAsync(p)); 371 await throws(() => FS.deleteAsync(FS.cacheDirectory)); 372 await throws(() => FS.moveAsync({ from: p + '../a/b', to: 'c' })); 373 await throws(() => FS.moveAsync({ from: 'c', to: p + '../a/b' })); 374 await throws(() => FS.copyAsync({ from: p + '../a/b', to: 'c' })); 375 await throws(() => FS.copyAsync({ from: 'c', to: p + '../a/b' })); 376 await throws(() => FS.makeDirectoryAsync(p + '../hello/world')); 377 await throws(() => FS.readDirectoryAsync(p + '../hello/world')); 378 await throws(() => FS.downloadAsync('http://www.google.com', p + '../hello/world')); 379 await throws(() => FS.readDirectoryAsync(p + '../')); 380 await throws(() => FS.downloadAsync('http://www.google.com', p + '../hello/world')); 381 }); 382 383 t.it('missing parameters', async () => { 384 const p = FS.documentDirectory + 'test'; 385 386 await throws(() => FS.moveAsync({ from: p })); 387 await throws(() => FS.moveAsync({ to: p })); 388 await throws(() => FS.copyAsync({ from: p })); 389 await throws(() => FS.copyAsync({ to: p })); 390 }); 391 392 t.it('can read root directories', async () => { 393 await FS.readDirectoryAsync(FS.documentDirectory); 394 await FS.readDirectoryAsync(FS.cacheDirectory); 395 }); 396 397 /*t.it('can copy from `CameraRoll`, verify hash, other methods restricted', async () => { 398 await Promise.all( 399 (await CameraRoll.getPhotos({ 400 first: 1, 401 })).edges.map(async ({ node: { image: { uri: cameraRollUri } } }) => { 402 const destinationUri = FS.documentDirectory + 'photo.jpg'; 403 404 await throws(() => FS.readAsStringAsync(cameraRollUri)); 405 await throws(() => FS.writeAsStringAsync(cameraRollUri)); 406 await throws(() => FS.deleteAsync(cameraRollUri)); 407 await throws(() => FS.moveAsync({ from: cameraRollUri, to: destinationUri })); 408 await throws(() => FS.copyAsync({ from: destinationUri, to: cameraRollUri })); 409 await throws(() => FS.makeDirectoryAsync(cameraRollUri)); 410 await throws(() => FS.readDirectoryAsync(cameraRollUri)); 411 await throws(() => FS.downloadAsync('http://www.google.com', cameraRollUri)); 412 413 await FS.copyAsync({ from: cameraRollUri, to: destinationUri }); 414 415 const origInfo = await FS.getInfoAsync(cameraRollUri, { 416 size: true, 417 md5: true, 418 }); 419 const copyInfo = await FS.getInfoAsync(destinationUri, { 420 size: true, 421 md5: true, 422 }); 423 424 t.expect(origInfo.md5).toEqual(copyInfo.md5); 425 t.expect(origInfo.size).toEqual(copyInfo.size); 426 }) 427 ); 428 });*/ 429 430 t.it( 431 'download(network failure)', 432 async () => { 433 const localUri = FS.documentDirectory + 'download1.png'; 434 435 const assertExists = async expectedToExist => { 436 let { exists } = await FS.getInfoAsync(localUri); 437 if (expectedToExist) { 438 t.expect(exists).toBeTruthy(); 439 } else { 440 t.expect(exists).not.toBeTruthy(); 441 } 442 }; 443 444 await FS.deleteAsync(localUri, { idempotent: true }); 445 await assertExists(false); 446 447 let error; 448 try { 449 const { md5, uri } = await FS.downloadAsync( 450 'https://nonexistent-subdomain.expo.io', 451 localUri, 452 { md5: true } 453 ); 454 } catch (e) { 455 error = e; 456 } 457 t.expect(error).toBeTruthy(); 458 await assertExists(false); 459 await FS.deleteAsync(localUri, { idempotent: true }); 460 }, 461 30000 462 ); 463 464 t.it( 465 'download(404)', 466 async () => { 467 const localUri = FS.documentDirectory + 'download1.png'; 468 469 const assertExists = async expectedToExist => { 470 let { exists } = await FS.getInfoAsync(localUri); 471 if (expectedToExist) { 472 t.expect(exists).toBeTruthy(); 473 } else { 474 t.expect(exists).not.toBeTruthy(); 475 } 476 }; 477 478 await FS.deleteAsync(localUri, { idempotent: true }); 479 await assertExists(false); 480 481 const { md5, uri, status } = await FS.downloadAsync('https://expo.io/404', localUri, { 482 md5: true, 483 }); 484 await assertExists(true); 485 t.expect(status).toBe(404); 486 487 await FS.deleteAsync(localUri); 488 await assertExists(false); 489 }, 490 30000 491 ); 492 }); 493} 494