UNPKG

react-native-archives

Version:
1,608 lines (1,462 loc) 48.8 kB
import React, {useState, useRef, useEffect} from 'react'; import { View, Text, ScrollView, TouchableOpacity, ActivityIndicator, PermissionsAndroid, } from 'react-native'; import { fs, dirs, utils, status, external, BlobPlus, fetchPlus, RequestPlus, ResponsePlus, HttpService } from "./../index"; const IsAndroid = Platform.OS === 'android'; const RemotePng = 'https://home.baidu.com/Public/img/logo.png'; const RemoteDoc = "https://dev-4h9.pages.dev/hello.docx"; const RemoteJpg = "https://dev-4h9.pages.dev/brige.jpeg"; const RemoteTxt = "https://dev-4h9.pages.dev/str.txt"; const RemoteZip = "https://dev-4h9.pages.dev/file.zip"; function unicode(text) { text = text ? text.replace(/&#x(\w+);/g, (s, icon) => { return String.fromCharCode(parseInt(icon, 16)) }) : text; return text; } function TestButton({ android, ios, title, startLog, endLog, errLog, onPress, children, ...props }){ if (android && !IsAndroid) { return null; } if (ios && IsAndroid) { return null; } const [disable, setDisable] = useState(false); const isMounted = useRef(false); useEffect(() => { isMounted.current = true; return () => isMounted.current = false; }, []); const callPress = async () => { startLog(title); setDisable(true); try { await onPress(); } catch(e) { errLog(e) } if (isMounted.current) { setDisable(false); endLog(); } }; return <TouchableOpacity activeOpacity={.8} {...props} disabled={disable} onPress={callPress} style={{ height:32, flexDirection:"row", justifyContent:"center", alignItems:"center", borderRadius: 4, minWidth: "48%", marginVertical:3, marginHorizontal:"1%", backgroundColor: "rgb(33, 150, 243)", opacity: disable ? .8 : null, }} > {disable ? <ActivityIndicator color="#fff" size="small" /> : null} <Text style={{color:"#fff"}}>{title}</Text> {children} </TouchableOpacity> } class TestService extends HttpService{ withToken(request, token){ return request.header('x-token', token); } test(){ return this.request().payload({t:'test'}).json(); } } class ArchivesTest extends React.PureComponent { constructor(props) { super(props); this.state = { remoteFont: 0, localFont: 0, }; } createButton(props) { return <TestButton startLog={this.startLog} endLog={this.endLog} errLog={this.errLog} {...props} /> } startLog(title) { console.log('========================' + title + '========================'); } endLog() { } errLog(e) { if (__DEV__) { console.error(e); } else { console.error(e.message); } } prtLog() { const args = Array.prototype.slice.call(arguments); if (!args.length) { return; } console.log(...args) } showLog() { const args = Array.prototype.slice.call(arguments); if (!args.length) { return; } if (args.length < 2) { console.log(args[0]) return; } const tit = args.shift(); const equal = args.pop(); args.unshift(tit+':'); args.unshift('【'+(equal ? '✓' : '×')+'】'); console[equal ? 'log' : 'error'](...args) } utilsFunc = async () => { const self = this; let test, buffer, u8, u8int; test = 'test'; buffer = utils.textToArrayBuffer(test); u8 = new Uint8Array(buffer); u8int = []; for (let i=0; i<u8.length; i++) { u8int.push(u8[i]) } self.showLog('textToArrayBuffer()', test, buffer, u8int.join('') === [116, 101, 115, 116].join('')); let txt = utils.arrayBufferToText(buffer); self.showLog('arrayBufferToText()', test, txt, txt === test); let b64 = utils.arrayBufferToBase64(buffer), base64 = 'dGVzdA=='; self.showLog('arrayBufferToBase64()', base64, b64, b64 === base64); buffer = utils.base64ToArrayBuffer(base64); txt = utils.arrayBufferToText(buffer); self.showLog('base64ToArrayBuffer()', test, buffer, test === txt); //getNumber let expected, actual; self.showLog( 'getNumber()', expected = 3, actual = utils.getNumber(3), expected === actual ); self.showLog( 'getNumber()', expected = 1, actual = utils.getNumber('1.2'), expected === actual ); self.showLog( 'getNumber()', expected = undefined, actual = utils.getNumber('x'), expected === actual ); self.showLog( 'getNumber()', expected = null, actual = utils.getNumber('v', null), expected === actual ); //normalizeMethod self.showLog( 'normalizeMethod()', expected = 'GET', actual = utils.normalizeMethod('get'), expected === actual ); self.showLog( 'normalizeMethod()', expected = 'none', actual = utils.normalizeMethod('none'), expected === actual ); //ltrim self.showLog( 'ltrim()', expected = 'str ', actual = utils.ltrim(' str '), expected === actual ); self.showLog( 'ltrim()', expected = 'str~', actual = utils.ltrim('~~~str~', '~'), expected === actual ); //rtrim self.showLog( 'rtrim()', expected = ' str', actual = utils.rtrim(' str '), expected === actual ); self.showLog( 'rtrim()', expected = '~str', actual = utils.rtrim('~str~~~', '~'), expected === actual ); //parseQuery let expected2={ foo:['f', 'o'], bar:"bar" }; let actual2 = utils.parseQuery('foo[]=f&foo[]=o&bar=bar'); self.showLog('parseQuery()', expected2, actual2, JSON.stringify(expected2) === JSON.stringify(actual2) ); //parseCookie let expected3={ foo:['f', 'o'], bar:"bar" }; let actual3 = utils.parseCookie('foo[]=f; foo[]=o; bar=bar'); self.showLog('parseCookie()', expected3, actual3, JSON.stringify(expected3) === JSON.stringify(actual3) ); //parseHeader u8 = { Connection: "keep-alive", Pragma: "no-cache", }; u8int = []; let expected4={}; for (let k in u8) { u8int.push(k+':'+u8[k]); expected4[k.toLocaleLowerCase()] = u8[k]; } let actual4 = {}; let header = utils.parseHeader(u8int.join("\n")); for (let k of header.entries()) { actual4[k[0]] = k[1]; } self.showLog('parseHeader()', expected4, actual4, JSON.stringify(expected4) === JSON.stringify(actual4) ); //makeParam u8 = { key:"key", arr:["a", "中"], 哈:"t" }; actual = utils.makeParam(u8); expected='key=key&arr[]=a&arr[]=%E4%B8%AD&%E5%93%88=t'; self.showLog('makeParams()', expected, actual, expected === actual); //makeUrl self.showLog( 'makeUrl()', expected = 'http://d.com', actual = utils.makeUrl(expected), expected === actual ); self.showLog( 'makeUrl()', '', actual = utils.makeUrl('http://d.com', 'path'), 'http://d.com/path' === actual ); self.showLog( 'makeUrl()', '', actual = utils.makeUrl('http://d.com', 'path', {foo:"foo"}), 'http://d.com/path?foo=foo' === actual ); } blobPlus = async () => { const self = this; let actual, str = 'abcdeft', blob = new BlobPlus([str], {type: 'text/plain'}); self.prtLog(blob); actual = await blob.text(); self.showLog('blob text()', str, actual, actual === str); actual = await blob.arrayBuffer(); self.showLog('blob arrayBuffer()', str, actual, utils.arrayBufferToText(actual) === str); actual = await blob.base64(); self.showLog( 'blob base64()', str, actual, utils.arrayBufferToText( utils.base64ToArrayBuffer(actual) ) === str ); actual = await blob.dataUrl(); self.showLog( 'blob dataUrl()', str, actual, actual === 'data:text/plain;base64,' + utils.arrayBufferToBase64( utils.textToArrayBuffer(str) ) ); const blobSlice =blob.slice(2, 5); actual = await blobSlice.text(); self.showLog('blob slice()', 'cde', actual, 'cde' === actual); actual = await blob.text(); self.showLog('blob text()', str, actual, actual === str); actual = await (new BlobPlus([blob])).text(); self.showLog('blob->blobPlus', str, actual, actual === str); blob.close(); } requestPlus_Props = async () => { const self = this; // RequestPlus 除 body 外的基本属性测试 const url = "https://postman-echo.com/post"; const controller = new AbortController(); const info = { credentials:"omit", method:"GET", mode:"cors", signal:controller.signal, referrer:"https://postman-echo.com", headers:{ "user-agent": "Mozilla/5.0", "content-type": "image/jpeg" }, }; const callback=()=>{}; const extend = { timeout:2, saveTo:"path", keepBlob:true, resText:true, onHeader:callback, onUpload:callback, onDownload:callback, } const options = {...info, ...extend}; const fullInfo = {...options, url}; const getHeaderAll = (header) => { const obj = {}; for (var pair of header.entries()) { obj[pair[0]] = pair[1]; } return obj; } const checkInfo = (title, req) => { self.prtLog(req) let same=true, actual, expected; for (let k in fullInfo) { actual = req[k]; expected = fullInfo[k]; if ('headers' === k) { if (JSON.stringify(expected) != JSON.stringify(getHeaderAll(actual))) { same=false; self.showLog(k, expected, actual, false); } } else if (actual !== expected) { same=false; self.showLog(k, expected, actual, false); } } if (same) { self.showLog('check ' + title, true); } else { self.showLog('check ' + title, false); } }; // check method let req, ex, ac; req = new RequestPlus('/'); self.showLog('req method', ex = null, ac = req.method, ex === ac); req = new RequestPlus('/', {body:'a'}); self.showLog('req method', ex = null, ac = req.method, ex === ac); req = new RequestPlus('/', {body:'a', method:'POST'}); self.showLog('req method', ex = 'POST', ac = req.method, ex === ac); req = new RequestPlus('/', {method:'GET'}); self.showLog('req method', ex = 'GET', ac = req.method, ex === ac); // check instance checkInfo('req(url, options)', new RequestPlus(url, options)); checkInfo('req(options)', new RequestPlus(fullInfo)); const basicReq = new RequestPlus(url, info); checkInfo('req(req, options)', new RequestPlus(basicReq, extend)); const orgReq = new Request(url, info); for (let ek in extend) { orgReq[ek] = extend[ek]; } // 原始 Request 不支持 referrer orgReq.referrer = info.referrer; checkInfo('request+extend', orgReq); } _checkPlusBody = async (isRequest) => { const self = this; // request/response body 功能同, 所以这里合并测试 const create = (body) => { if (isRequest) { return new RequestPlus({ method:'POST', body }) } return new ResponsePlus(body); }; const checkBody = async (body, str) => { let res, payload, temp; self.prtLog('✸✸ init body ✸✸:', body); res = create(body); payload = await res.text(); self.showLog('text()', str, payload, str === payload); res = create(body); payload = await res.formData(); self.showLog('formData()', str, payload, payload instanceof FormData); res = create(body); payload = await res.blob(); temp = payload instanceof BlobPlus ? await payload.text() : null; self.showLog('blob()', str, payload, str === temp); res = create(body); payload = await res.arrayBuffer(); temp = payload instanceof ArrayBuffer ? utils.arrayBufferToText(payload) : null; self.showLog('arrayBuffer()', str, payload, str === temp); try { res = create(body); payload = await res.json(); self.showLog('json()', str, payload, str === JSON.stringify(payload)); } catch(e) { self.showLog('not support json()', str, e.message, true); } } const obj = {foo: "foo"}; // string const payload = JSON.stringify(obj); await checkBody(payload, payload); // obj await checkBody(obj, payload); // URLSearchParams const us = new URLSearchParams(); us.append('foo', 'foo'); us.append('bar', 'bar'); await checkBody(us, 'foo=foo&bar=bar'); // blob const blob = new Blob([payload]); await checkBody(blob, payload); // ArrayBuffer const buff = utils.textToArrayBuffer(payload); await checkBody(buff, payload); // DataView const dataView = new DataView(utils.textToArrayBuffer(payload)); await checkBody(dataView, payload); } requestPlus_Body = async () => { await this._checkPlusBody(true); } responsePlus = async () => { await this._checkPlusBody(); } fetchPlus = async () => { const self = this; let json; const postFetch = async (body, headers, props) => { headers = headers||{}; const res = await fetchPlus('https://postman-echo.com/post', { resText: true, headers, body, ...props }); return await res.json(); }; // header / referrer / string body let hd = 'custom', reurl = 'http://www.react.com'; json = await postFetch('payload', {'x-custome': hd, referrer: reurl}); self.prtLog('✸✸ post string ✸✸', json); self.showLog('res header', hd, json.headers['x-custome'], json.headers['x-custome'] === hd); self.showLog('res referrer', reurl, json.headers['referrer'], json.headers['referrer'] === reurl); self.showLog('res body', 'payload', json.data, json.data === 'payload'); // object const obj = {foo:"bar", bar:['b', 'z']}; json = await postFetch(obj); self.prtLog('✸✸ post object ✸✸', json); self.showLog('res json', obj, json.json, JSON.stringify(json.json) === JSON.stringify(obj)); // Blob const blob = new Blob(['blob'], {type: 'text/html'}) json = await postFetch(blob); self.prtLog('✸✸ post Blob ✸✸', blob); self.showLog('res header', 'text/html', json.headers['content-type'], json.headers['content-type'] === 'text/html'); self.showLog('res body', 'blob', json.data, json.data === 'blob'); // ArrayBuffer/DataView const checkBuffer = async (buffer, d) => { json = await postFetch(buffer); self.prtLog('✸✸ post '+(d ? 'DataView' : 'ArrayBuffer')+' ✸✸', json); let resData = 'object' === typeof json.data && 'data' in json.data ? json.data.data : null; if (resData) { resData = utils.arrayBufferToText(new Uint8Array(json.data.data)); } self.showLog('res body', 'buffer', resData, resData === 'buffer'); } const buffer = utils.textToArrayBuffer('buffer'); await checkBuffer(buffer); await checkBuffer(new DataView(buffer), true); // URLSearchParams const foobar = {foo:"foo", 'bar[]':['b', 'r']}; const us = new URLSearchParams(); us.append('foo', 'foo'); us.append('bar[]', 'b'); us.append('bar[]', 'r'); json = await postFetch(us); self.prtLog('✸✸ post URLSearchParams ✸✸', json); self.showLog('res form', foobar, json.form, JSON.stringify(json.form) === JSON.stringify(foobar)); // FormData const form = new FormData(); form.append('foo', 'foo'); form.append('bar[]', 'b'); form.append('bar[]', 'r'); form.append('logo', { uri: RemotePng, type: 'image/png', name: 'logo.jpg', }); let trigger = {header:false, upload:false, download:false}, props = {}; props.onHeader = () => { trigger.header = true; }; props.onUpload = () => { trigger.upload = true; }; props.onDownload = () => { trigger.download = true; }; json = await postFetch(form, {}, props); self.prtLog('✸✸ post FormData ✸✸', form); self.showLog('res form', foobar, json.form, JSON.stringify(json.form) === JSON.stringify(foobar)); self.showLog('res file', 'logo.jpg', Object.keys(json.files), 'logo.jpg' in json.files); self.showLog('res onHeader trigged', trigger.header); self.showLog('res onUpload trigged', trigger.upload); self.showLog('res onDownload trigged', trigger.download); } httpRequest_Props = async () => { const self = this; const service = new TestService('https://postman-echo.com'); self.prtLog('✸✸ check request prop init ✸✸'); const req = service.request(); const check = (method, stand) => { let v,obj,val; v = 'val'; obj = req.init(method, v); val = req.init(method); self.showLog('init '+method, v, val, v === val && obj === req); if (stand) { v = 'val2'; obj = req[method](v); val = req[method](); self.showLog(method+'()', v, val, v === val && obj === req); } }; for (let m of [ 'url', 'method', 'timeout', 'credentials', 'referrer', 'payload', 'onHeader', 'onUpload', 'onDownload', 'saveTo', 'keepBlob', 'resBlob', 'signal' ]) { check(m, true); } for (let m of ['mode', 'diy']) { check(m); } let v, obj, val; obj = req.auth(v = 'auth'); val = req.header('Authorization'); self.showLog('auth()', v, val, v === val && obj === req); self.prtLog('✸✸ check request original ✸✸'); const init = { url:'/ttt', mode:'a', method:'POST', timeout:2, credentials:'ab', referrer:'ccc', }; const org = service.request(init); for (let k in init) { self.showLog(k, init[k], org.init(k), org.init(k) === init[k]); } } httpRequest_Method = async () => { const self = this; const service = new TestService(); const logRequest = (tit, req, method, expected, obj) => { const data = req[method](); const actual = {...data}; const eq = JSON.stringify(expected) === JSON.stringify(actual) && (!obj || req === obj); self.showLog(tit, expected, actual, eq); }; const checkRequestData = (method) => { let obj, val; const req = service.request(); const log = (tit, expected) => { logRequest(tit, req, method, expected, obj); } const Foo = 'header' === method ? 'Foo' : 'foo'; self.prtLog('✸✸ check request data ✸✸', method); // get all log('all', {}); // set obj = req[method](Foo, 'foo'); log('set string', {foo:'foo'}); obj = req[method]('bar', ['b', 'a']); log('set array', {foo:'foo', bar:['b', 'a']}); obj = req[method](Foo, 'foo2', true); log('set string append', {foo:['foo', 'foo2'], bar:['b', 'a']}); // set batch val = {baz:'baz'}; val[Foo] = 'foo'; obj = req[method](val); log('set batch', {foo:'foo', bar:['b', 'a'], baz:'baz'}); val = {que:'q'}; val[Foo] = 'f'; obj = req[method](val, true); log( 'set batch append', {foo:['foo', 'f'], bar:['b', 'a'], baz:'baz', que:'q'} ); val = {}; val[Foo] = 'f'; val.bar = 'b'; obj = req[method](val, false); log('set batch overwrite', {foo:'f', bar:'b'}); obj = req[method](null); log('clear', {}); // get all let all, expected, actual; req[method](all = {foo:'f', bar:'a', baz:['b', 'z']}); actual = req[method](); self.showLog( 'get all', all, actual = {...actual}, JSON.stringify(all) === JSON.stringify(actual) ); // get one self.showLog('get string', expected='f', actual = req[method](Foo), expected === actual); self.showLog( 'get array', expected=['b', 'z'], actual = req[method]('baz'), JSON.stringify(expected) === JSON.stringify(actual) ); // get batch self.showLog( 'get batch', expected={foo:'f', baz:['b', 'z']}, actual = req[method]([Foo,'baz']), JSON.stringify(expected) === JSON.stringify(actual) ); }; checkRequestData('header'); checkRequestData('cookie'); checkRequestData('query'); checkRequestData('param'); checkRequestData('file'); } httpService = async () => { const self = this; const isContains = (tit, sub, actual, eq) => { let contains = true, index = 0; for (let k in sub) { if (!actual.hasOwnProperty(k) || actual[k] !== sub[k]) { contains = false; break; } index++; } if (contains && eq && Object.keys(actual).length !== index) { contains = false; } self.showLog(tit+' contains', sub, actual, contains); } let send, res; const getServer = 'https://postman-echo.com/get' const service = new TestService('https://postman-echo.com/post'); // header+query let header, query; send = await service.request(getServer) .withToken('tt') .header(header = {x:"x", y:"y"}) .query(query = {foo:"foo", bar:"bar"}) .send(); self.showLog('response', send, ResponsePlus.prototype.isPrototypeOf(send)); res = await send.json(); header['x-token'] = 'tt'; isContains('header', header, res.headers); isContains('query', query, res.args); // cookie res = await service.request(getServer).json(); self.showLog('cookie contains', 'cookie', res.headers, 'cookie' in res.headers); res = await service.request(getServer).credentials(false).json(); self.showLog('cookie not contains', 'cookie', res.headers, !('cookie' in res.headers)); res = await service.request(getServer).cookie('z', 'z').json(); self.showLog('cookie contains custom', 'cookie', res.headers, res.headers.cookie === 'z=z'); res = await service.request(getServer).credentials(true).cookie('z', 'z').json(); self.showLog('cookie not contains custom', 'cookie', res.headers, 'cookie' in res.headers && res.headers.cookie !== 'z=z'); // param/file let params,files; res = await service.request().param(params = {foo:'f', bar:'b'}).json(); isContains('params', params, res.form, true); res = await service.request() .param(params) .file({img:RemotePng}) .json(); isContains('params', params, res.form, true); self.showLog( 'files contains', files = Object.keys(res.files), JSON.stringify(files) === JSON.stringify(['logo.png']) ); // payload 优先 let payload; res = await service.request() .param(params) .file({img:RemotePng}) .payload(payload = 'str') .json(); self.showLog('payload priority', payload, res.data, res.data === payload); // service 内部函数 let rjson = {t:"test"}; res = await service.test(); self.showLog( 'service func', rjson, res.json, JSON.stringify(rjson) === JSON.stringify(res.json) ); } showVars = async () => { this.prtLog('dirs', dirs); this.prtLog('status', status); this.prtLog('external', external); } rmkDir = async () => { const self = this; const dir = dirs.Caches + '/_arch_rmk_test_967_'; let exist, rm, crt, subdir; exist = await fs.isDir(dir); self.showLog('isDir', dir, exist, true); if (false === exist) { self.showLog('test dir is a file, jump test', false) return; } if (exist) { rm = await fs.rmDir(dir, true); self.showLog('rmDir', dir, rm, null === rm); exist = await fs.isDir(dir); self.showLog('isDir', dir, exist, null === exist); } crt = await fs.mkDir(dir); self.showLog('mkDir', dir, crt, null === crt); exist = await fs.isDir(dir); self.showLog('isDir', dir, exist, exist); subdir = dir + '/a/b'; try { crt = await fs.mkDir(subdir, false); self.showLog('mkSubDir should failed', dir, false); } catch(e) { self.showLog('mkSubDir should failed', dir, true); } crt = await fs.mkDir(subdir); self.showLog('mkSubDir', dir, crt, null === crt); exist = await fs.isDir(subdir); self.showLog('isSubDir', dir, exist, exist); try { rm = await fs.rmDir(dir); self.showLog('rm recursive should failed', dir, false); } catch(e) { self.showLog('rm recursive should failed', dir, true); } rm = await fs.rmDir(dir, true); self.showLog('rmDir', dir, rm, null === rm); exist = await fs.isDir(dir); self.showLog('isDir', dir, exist, null === exist); } _makeTmpDir = async (clear) => { const dir = dirs.Caches + '/_arch_tmp_test_967_'; if (clear) { await fs.rmDir(dir, true); } else { await fs.mkDir(dir); await fs.writeFile(dir + '/x.txt', 'abc'); } return dir; } _testPaths = null; _getTestPaths = async (read) => { const self = this; const tmpDir = await this._makeTmpDir(); if (read || null === this._testPaths) { const files = []; const directs = [dirs.Document]; if (IsAndroid) { // android 特殊目录 const contentPath = await fs.getContentUri('images'); directs.push('drawable://', 'asset://', 'raw://', contentPath); } else { // ios 特殊目录 } let lists, file, hasFile, hasDir, err; for (let [index, d] of [tmpDir, ...directs].entries()) { err = null; try { lists = await fs.readDir(d); } catch(e) { lists = []; err = e; } // readDir 测试 if (read) { if (err) { self.showLog(d, err.message, false); } else { self.showLog(d + ':', lists, true); } continue; } // 非 readDir 测试 if (index === 0) { continue; } hasFile = hasDir = false; for (file of lists) { if (!('isDir' in file)) { continue; } if (file.isDir && !hasDir) { hasDir = true; directs.push(file.path); } else if(!file.isDir && !hasFile) { hasFile = true; files.push(file.path) } if (hasFile && hasDir) { break; } } } this._testPaths = { dirs: directs, files }; } // 添加临时创建文件 return { dirs: this._testPaths.dirs.concat([tmpDir]), files: this._testPaths.files.concat([tmpDir + '/x.txt']) }; } readDir = async () => { if (IsAndroid) { await PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE); } await this._getTestPaths(true); await this._makeTmpDir(true); } isDir = async () => { const self = this; const temp = await this._getTestPaths(); const existDirs = temp.dirs; const existFiles = temp.files; let path, rs, err; for (path of existDirs) { err = null; try { rs = await fs.isDir(path); } catch (e) { rs = null; err = e; } if (err) { self.showLog(path, err.message, false); } else { self.showLog(path, rs === true); } } for (path of existFiles) { err = null; try { rs = await fs.isDir(path); } catch (e) { rs = null; err = e; } if (err) { self.showLog(path, err.message, false); } else { self.showLog(path, rs === false); } } await this._makeTmpDir(true); // not exist const nonePahts = [ dirs.Document + '/_test_none_' ]; if (IsAndroid) { // android 特殊目录 nonePahts.push( 'drawable://none', 'raw://none', 'asset://_none_', 'content://_none_' ); } else { // ios 特殊目录 } for (path of nonePahts) { rs = await fs.isDir(path); self.showLog(path, rs === null); } } writeFile = async () => { const self = this; const file = dirs.Caches + '/_test_.txt'; const getWriteContent = (type) => { let contents = [ ['overwrite', 'abcd', 'abcd'], // 覆盖写 ['overwrite', '123', '123'], // 覆盖写 ['write append', '456', '123456', true], // 追加写 ['write offset', 'abc', '12abc6', 2], // 在指定位置写(从开头数) ['write -offset', 'xyz', '12abxyz', -2], // 在指定位置写(从结尾数) ]; if ('arr' === type || 'base64' === type) { let rs = [], isBase = 'base64' === type; contents.forEach(([tit, c, e, flag]) => { c = utils.textToArrayBuffer(c); if (isBase) { c = [utils.arrayBufferToBase64(c)]; } rs.push([tit, c, e, flag]); }); return rs; } if ('blob' === type) { let rs = []; const qblob = new Blob(['abcd']); const sblob = qblob.slice(0, 3); contents.forEach(([tit, c, e, flag], index) => { if (0 === index) { c = qblob; } else if (3 === index) { c = sblob; } else { c = new Blob([c]); } rs.push([tit, c, e, flag]); }); return rs; } return contents; }; const checkWrite = async (type) => { self.prtLog('✸✸ write file '+type+' ✸✸'); const arr = getWriteContent(type); let item, tit, str, expected, flag, writeRs, content; for (item of arr) { [tit, str, expected, flag] = item; writeRs = await fs.writeFile(file, str, flag); self.showLog(tit, writeRs, null === writeRs); content = await fs.readFile(file); self.showLog('content', expected, content, expected === content); } }; await checkWrite('str'); await checkWrite('arr'); await checkWrite('base64'); await checkWrite('blob'); let writeRs, content, expected; if (IsAndroid) { // android 特殊路径 self.prtLog('✸✸ write access content:// file ✸✸'); const uri = await fs.getShareUri(file); writeRs = await fs.writeFile(uri, expected = 'content_test'); self.showLog('write cotent uri', writeRs, null === writeRs); content = await fs.readFile(file); self.showLog('content', expected, content, expected === content); } else { // iOS 特殊路径 } const rm = await fs.unlink(file); self.showLog('unlink file', rm, null === rm); } readFile = async () => { const self = this; // test speical file self.prtLog('✸✸ read speical file ✸✸'); const temp = await this._getTestPaths(); for (let path of temp.files) { await fs.readFile(path, 0, 1); self.showLog('read file', path, true); } await this._makeTmpDir(true); // test read method const expected = 'abcdefg'; const checkRead = async (file) => { let base64, middle, content, excpt; content = await fs.readFile(file); self.showLog('read string', expected, content, expected === content); content = await fs.readFile(file, 'text', 3); self.showLog('read string offset', excpt = 'defg', content, excpt === content); content = await fs.readFile(file, 'text', 3, 2); self.showLog('read string offset+len', excpt = 'de', content, excpt === content); content = await fs.readFile(file, 'text', -5); self.showLog('read string -offset', excpt = 'cdefg', content, excpt === content); content = await fs.readFile(file, 'text', -5, 3); self.showLog('read string -offset+len', excpt = 'cde', content, excpt === content); base64 = await fs.readFile(file, 'base64'); content = utils.arrayBufferToText(utils.base64ToArrayBuffer(base64)); self.showLog('read base64', expected, base64, expected === content); content = await fs.readFile(file, 'uri'); self.showLog('read uri', excpt = 'data:text/plain;base64,' + base64, content, excpt === content); base64 = await fs.readFile(file, 'base64', 3); content = utils.arrayBufferToText(utils.base64ToArrayBuffer(base64)); self.showLog('read base64 offset', excpt = 'defg', base64, excpt === content); content = await fs.readFile(file, 'uri', 3); self.showLog('read uri offset', excpt = 'data:text/plain;base64,' + base64, content, excpt === content); middle = await fs.readFile(file, 'blob'); content = await middle.text(); self.showLog('read blob', expected, middle, expected === content); middle = await fs.readFile(file, 'blob', 3); content = await middle.text(); self.showLog('read blob offset', excpt = 'defg', middle, excpt === content); middle = await fs.readFile(file, 'buffer'); content = utils.arrayBufferToText(middle); self.showLog('read buffer', expected, middle, expected === content); middle = await fs.readFile(file, 'buffer', 3); content = utils.arrayBufferToText(middle); self.showLog('read buffer offset', excpt = 'defg', middle, excpt === content); }; // remote file self.prtLog('✸✸ read file ✸✸'); await checkRead(require('./str.html')); // file self.prtLog('✸✸ read local file ✸✸'); const file = dirs.Caches + '/_test_.txt'; await fs.writeFile(file, expected); await checkRead(file); const rm = await fs.unlink(file); self.showLog('unlink file', rm, '', null === rm); // remote file self.prtLog('✸✸ read remote file ✸✸'); await checkRead(RemoteTxt); } copyFile = async () => { const self = this; self.prtLog('✸✸ check copy special file ✸✸'); const temp = await this._getTestPaths(); const destPath = dirs.Caches + '/_special_dest_file_'; let checkPath; for (let path of temp.files) { await fs.copyFile(path, destPath); checkPath = await fs.isDir(destPath); self.showLog('copy '+path, false === checkPath); await fs.unlink(destPath); } await this._makeTmpDir(true); // copy 方法 self.prtLog('✸✸ check copy method ✸✸'); let excpt, exist, exist2, rm, cp, content, excon, excon2; const file = dirs.Caches + '/_test_.txt'; const file2 = dirs.Caches + '/_test_2.txt'; // 确认文件 exist = await fs.isDir(file); self.prtLog('source file exist:', exist === false); exist2 = await fs.isDir(file2); self.prtLog('dest file exist:', exist === false); if (null !== exist2) { rm = await fs.unlink(file2); self.showLog('unlink dest file', excpt = null, rm, excpt === rm); } excon = '*&^'; await fs.writeFile(file, excon); // 复制(不存在) cp = await fs.copyFile(file, file2); self.showLog('copy file', excpt = null, cp, excpt === cp); content = await fs.readFile(file2); self.showLog('check copy', excon, content, excon === content); // 复制(不覆盖) excon2 = '@#$'; await fs.writeFile(file, excon2); try { await fs.copyFile(file, file2, false); self.showLog('copy overwrite should failed', false) } catch(e) { self.showLog('copy overwrite should failed', true) } content = await fs.readFile(file2); self.showLog('check copy', excon, content, excon === content); // 复制(覆盖) await fs.copyFile(file, file2); self.showLog('copy overwrite', true); content = await fs.readFile(file2); self.showLog('check copy', excon2, content, excon2 === content); // 删除临时文件 await fs.unlink(file); await fs.unlink(file2); } moveFile = async () => { const self = this; let excpt, exist, exist2, rm, cp, content, excon, excon2; const file = dirs.Caches + '/_test_.txt'; const file2 = dirs.Caches + '/_test_2.txt'; // 确认文件 exist = await fs.isDir(file); self.showLog('file isDir', exist, '', true); exist2 = await fs.isDir(file2); self.showLog('file2 isDir', exist2, '', true); if (null !== exist2) { rm = await fs.unlink(file2); self.showLog('unlink file2', rm, '', null === rm); } excon = '*&^'; await fs.writeFile(file, excon); // 移动(不存在) cp = await fs.moveFile(file, file2); self.showLog('moveFile', excpt = null, cp, excpt === cp); content = await fs.readFile(file2); self.showLog('check move', excon, content, excon === content); exist = await fs.isDir(file); self.showLog('old file exist', exist, '', exist === null); // 移动(不覆盖) excon2 = '@#$'; await fs.writeFile(file, excon2); try { await fs.moveFile(file, file2, false); self.showLog('move overwrite should failed', false) } catch(e) { self.showLog('move overwrite should failed', true) } content = await fs.readFile(file2); self.showLog('check move', excon, content, excon === content); // 移动(覆盖) await fs.moveFile(file, file2); self.showLog('move overwrite:', true); content = await fs.readFile(file2); self.showLog('check move', excon2, content, excon2 === content); exist = await fs.isDir(file); self.showLog('old file exist', exist, '', exist === null); // 删除临时文件 await fs.unlink(file2); } unlink = async () => { const self = this; let exist; const file = dirs.Caches + '/_arch_test_unlink_687_.txt'; exist = await fs.isDir(file); self.prtLog('file exist:', exist === false); if (true === exist) { self.showLog('test file is dir', false); return; } if (null === exist) { await fs.writeFile(file, ''); self.showLog('create file', true); } exist = await fs.isDir(file); self.showLog('file exist', exist === false); await fs.unlink(file); exist = await fs.isDir(file); self.showLog('unlink->file', exist === null); } openFile = async () => { const self = this; const file = dirs.Caches + '/_arch_test_addown_.jpeg'; const test = await fs.isDir(file); if (false !== test) { await fetchPlus({ url:RemoteJpg, saveTo: file }) } await fs.openFile(file, { title: "Test File", onClose:() => { self.prtLog('open file closed') fs.unlink(file); } }); self.prtLog('open file success') } openFile2 = async () => { const self = this; const file = dirs.Caches + '/_arch_test_addown_'; const test = await fs.isDir(file); if (false !== test) { await fetchPlus({ url:RemoteJpg, saveTo: file }) } await fs.openFile(file, { mime: "image/jpeg", title: "Test File", onClose:() => { self.prtLog('open file closed') fs.unlink(file); } }); self.prtLog('open file success') } getMime = async () => { const self = this; let mime, except; mime = await fs.getMime('foo.txt'); self.showLog('getMime', except = 'text/plain', mime, except === mime); mime = await fs.getMime(['path/foo.txt', 'foo.png']); self.showLog( 'getMime', except = ['text/plain', 'image/png'], mime, JSON.stringify(except) === JSON.stringify(mime) ); } getExt = async () => { const self = this; let ext, except; ext = await fs.getExt('text/plain'); self.showLog('getExt', except = 'txt', ext, except === ext); ext = await fs.getExt(['text/plain;utf-8', 'image/png']); self.showLog( 'getExt', except = ['txt', 'png'], ext, JSON.stringify(except) === JSON.stringify(ext) ); } getHash = async () => { const self = this; self.prtLog('✸✸ check get special file hash ✸✸'); const temp = await this._getTestPaths(); let path, shash; if (!__DEV__) { path = './str.html'; shash = await fs.getHash(require('./str.html')); self.showLog(path, shash, true); } for (path of temp.files) { shash = await fs.getHash(path); self.showLog(path, shash, true); } await this._makeTmpDir(true); self.prtLog('✸✸ check hash value ✸✸'); let file, hash, except; file = dirs.Caches + '/_test_.txt'; await fs.writeFile(file, 'abc'); const hashs = { md5: "900150983cd24fb0d6963f7d28e17f72", sha1: "a9993e364706816aba3e25717850c26c9cd0d89d", sha224: "23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7", sha256: "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", sha384: "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7", sha512: "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f", }; for (let k in hashs) { except = hashs[k]; hash = await fs.getHash(file, k); self.showLog(k, except, hash, except === hash); } await fs.unlink(file); if (IsAndroid) { file = 'drawable://notify_panel_notification_icon_bg' hash = await fs.getHash(file); except = 'e5e0e446cc8c3c56990cd94799d65598'; self.showLog('drawable file hash', except, hash, except === hash); } } remoteFont = async () => { const self = this; const font = this.state.remoteFont; if (font) { self.showLog('font has loaded', true); return; } const file = dirs.Caches + '/remotefont.ttf'; const url = "https://at.alicdn.com/t/font_3415031_w5ulq8d500h.ttf?t=1652968984755"; await fetchPlus(url, {saveTo: file}) await fs.loadFont('remotefont', file); this.setState({remoteFont: 1}, () => { self.showLog('load remoteFont success', true); }); } localFont = async () => { const self = this; const font = this.state.localFont; if (font) { self.showLog('font has loaded', true); return; } await fs.loadFont('localFont', require('./localFont.ttf')); this.setState({localFont: 1}, () => { self.showLog('load localFont success', true); }); } unzip = async () => { const self = this; const dir = dirs.Caches + '/_unzip_test_'; const tmpFile = dirs.Caches + '/_unzip_test_.zip'; const zipFile = RemoteZip; await fetchPlus({ url: zipFile, saveTo: tmpFile }); await fs.unzip(tmpFile, dir); // 普通解压 let files; let actual={}; let except = { "foo.txt": false, "sub": true, }; files = await fs.readDir(dir); for (let f of files) { actual[f.name] = f.isDir; } self.showLog('check list', except, actual, JSON.stringify(except) === JSON.stringify(actual)); actual={}; except = { "bar.txt": false, }; files = await fs.readDir(dir+'/sub'); for (let f of files) { actual[f.name] = f.isDir; } self.showLog('check deep list', except, actual, JSON.stringify(except) === JSON.stringify(actual)); actual = await fs.readFile(dir+'/foo.txt'); self.showLog('check file', except = 'foo', actual, except === actual); actual = await fs.readFile(dir+'/sub/bar.txt'); self.showLog('check deep file', except = 'bar', actual, except === actual); // 移除解压文件夹 await fs.rmDir(dir, true); let isDir = await fs.isDir(dir); self.showLog('rm unzip dir', isDir, null === isDir); // 校验 md5 并解压 try { await fs.unzip(tmpFile, dir, '13d36a40f4a77225b7a9f41fd1b9b9dd'); self.showLog('unzip by error md5 shold exception', false); } catch(e) { isDir = await fs.isDir(dir); self.showLog('unzip by error md5 shold exception', isDir, null === isDir); } await fs.unzip(tmpFile, dir, '13d36a40f4a77225b7a9f41fd1b9b9e9'); isDir = await fs.isDir(dir); self.showLog('unzip by correct md5', isDir, true === isDir); // 移除临时文件 await fs.rmDir(dir, true); await fs.unlink(tmpFile); } reload = async () => { const rs = await fs.reload(); this.prtLog('reload', rs) } getContentUri = async () => { let paths = [ 'images', 'video', 'audio', 'files', 'downloads', 'audio.artists', 'audio.albums', 'audio.genres', 'audio.playlists' ], type, uri; for (type of paths) { uri = await fs.getContentUri(type); this.prtLog(type+':', uri) } type = 'images'; uri = await fs.getContentUri(type, 'internal'); this.prtLog(type+' internal:', uri) } getShareUri = async () => { let file, uri; file = dirs.Caches + '/_arch_test_667_.txt'; await fs.writeFile(file, 'abc'); uri = await fs.getShareUri(file); this.prtLog('share uri:', uri); await fs.unlink(file); } download = async () => { const self = this; await fs.download({ url:RemoteJpg, title:'test download', description:'download desc', onProgress:e => { self.showLog('onProcess', e, true); }, onComplete:e => { self.showLog('onComplete', e, true); }, onError:e => { self.showLog('onError', e, true); } }); self.showLog('onStart', true); } addDownload = async () => { const file = 'file://' + external.AppCaches + '/_arch_test_addown_.docx'; const test = await fs.isDir(file); if (false !== test) { await fetchPlus({ url:RemoteDoc, saveTo: file }) } await fs.addDownload({ file, title: 'test title', description: 'test desc', }) } restartAndroid = async () => { const rs = await fs.restartAndroid(); this.prtLog('restart', rs) } render() { const MyButton = this.createButton.bind(this); return <ScrollView style={{flex:1}}> <View style={{ flexDirection:"row", flexWrap:"wrap", paddingTop:8, }}> <MyButton title="utilsFunc" onPress={this.utilsFunc} /> <MyButton title="BlobPlus" onPress={this.blobPlus} /> <MyButton title="RequestPlus.props" onPress={this.requestPlus_Props} /> <MyButton title="RequestPlus.body" onPress={this.requestPlus_Body} /> <MyButton title="ResponsePlus" onPress={this.responsePlus} /> <MyButton title="fetchPlus" onPress={this.fetchPlus} /> <MyButton title="HttpRequest.props" onPress={this.httpRequest_Props} /> <MyButton title="HttpRequest.method" onPress={this.httpRequest_Method} /> <MyButton title="HttpService" onPress={this.httpService} /> <MyButton title="获取变量" onPress={this.showVars} /> <MyButton title="fs.rmkDir" onPress={this.rmkDir}/> <MyButton title="fs.readDir" onPress={this.readDir}/> <MyButton title="fs.isDir" onPress={this.isDir}/> <MyButton title="fs.writeFile" onPress={this.writeFile}/> <MyButton title="fs.readFile" onPress={this.readFile}/> <MyButton title="fs.copyFile" onPress={this.copyFile}/> <MyButton title="fs.moveFile" onPress={this.moveFile}/> <MyButton title="fs.unlink" onPress={this.unlink}/> <MyButton title="fs.openFile" onPress={this.openFile}/> <MyButton title="fs.openFile2" onPress={this.openFile2}/> <MyButton title="fs.getMime" onPress={this.getMime}/> <MyButton title="fs.getExt" onPress={this.getExt}/> <MyButton title="fs.getHash" onPress={this.getHash}/> <MyButton title="fs.unzip" onPress={this.unzip}/> <MyButton title="fs.remoteFont" onPress={this.remoteFont}> {this.state.remoteFont ? <Text style={{ fontFamily:'remotefont', color: 'white' }}>{unicode('&#xe8b9;')}</Text> : null} </MyButton> <MyButton title="fs.localFont" onPress={this.localFont}> {this.state.localFont ? <Text style={{ fontFamily:'localFont', color: 'white' }}>{unicode('&#xe8c9;')}</Text> : null} </MyButton> <MyButton title="fs.reload" onPress={this.reload}/> <MyButton title="fs.getContentUri" android={true} onPress={this.getContentUri}/> <MyButton title="fs.getShareUri" android={true} onPress={this.getShareUri}/> <MyButton title="fs.download" android={true} onPress={this.download}/> <MyButton title="fs.addDownload" android={true} onPress={this.addDownload}/> <MyButton title="fs.restartAndroid" android={true} onPress={this.restartAndroid}/> </View> </ScrollView> } } export default ArchivesTest;