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