diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 00000000..44cd99d9 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,45 @@ +module.exports = { + extends: [ + // https://eslint.org/docs/rules/ + "eslint:recommended", + // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/src/configs/recommended.json + "plugin:@typescript-eslint/recommended", + // https://prettier.io/docs/en/eslint.html + "plugin:prettier/recommended", + ], + // https://reactjs.org/docs/hooks-rules.html + plugins: [], + parser: "@typescript-eslint/parser", + parserOptions: { + project: "./tsconfig.json", + }, + settings: {}, + rules: { + "no-undef": "off", // useless in TypeScript + "no-constant-condition": ["warn", { checkLoops: false }], + "no-useless-escape": "warn", + "no-console": "warn", + + "@typescript-eslint/no-unused-vars": ["warn", { argsIgnorePattern: "^_|^intl$" }], + "@typescript-eslint/array-type": ["error", "generic"], + "@typescript-eslint/camelcase": "warn", + "@typescript-eslint/class-name-casing": "warn", // to allow the initial underscore + "@typescript-eslint/no-non-null-assertion": "warn", // NOTE: pay attention to it because it may cause unexpected behavior + "@typescript-eslint/prefer-for-of": "warn", + "@typescript-eslint/prefer-includes": "warn", + "@typescript-eslint/prefer-string-starts-ends-with": "warn", + "@typescript-eslint/no-use-before-define": "warn", + + "@typescript-eslint/indent": "off", + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/explicit-function-return-type": "off", + "@typescript-eslint/explicit-member-accessibility": "off", + "@typescript-eslint/no-object-literal-type-assertion": "off", + "@typescript-eslint/no-empty-interface": "off", + "@typescript-eslint/no-parameter-properties": "off", + "@typescript-eslint/no-var-requires": "off", // not a part of ECMA-262 + "@typescript-eslint/prefer-interface": "off", + + "prettier/prettier": "warn", + }, +}; diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..a97a0d2a --- /dev/null +++ b/.gitignore @@ -0,0 +1,12 @@ +node_modules/ +dist/ +build/ +package-lock.json +.nyc_output/ +coverage/ + +# v8 profiler logs +isolate-*.log + +# flamebearer +flamegraph.html diff --git a/.nycrc.json b/.nycrc.json new file mode 100644 index 00000000..a3f0859d --- /dev/null +++ b/.nycrc.json @@ -0,0 +1,7 @@ +{ + "include": ["src/**/*.ts"], + "extension": [".ts"], + "reporter": ["text-summary", "html"], + "sourceMap": true, + "instrument": true +} diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..ae804356 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,5 @@ +language: node_js +node_js: + - "10" + - "12" +cache: npm diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..3662b370 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "typescript.tsdk": "node_modules/typescript/lib" +} \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..f0e7f3e7 --- /dev/null +++ b/LICENSE @@ -0,0 +1,5 @@ +Copyright 2019 The MessagePack Community. + +Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/README b/README deleted file mode 100644 index e69de29b..00000000 diff --git a/README.md b/README.md new file mode 100644 index 00000000..06c606c7 --- /dev/null +++ b/README.md @@ -0,0 +1,25 @@ +# MessagePack for JavaScript [![Build Status](https://travis-ci.org/msgpack/msgpack-javascript.svg?branch=master)](https://travis-ci.org/msgpack/msgpack-javascript) + +This is the pure-JavaScript implementation of MessagePack: + +https://msgpack.org/ + +## Usage + +TBD + +## Install + +```shell +npm install @msgpack/msgpack +``` + +## License + +Copyright 2019 The MessagePack Community. + +This software is licensed under the ISC license: + +https://opensource.org/licenses/ISC + +See [LICENSE](./LICENSE) for details. diff --git a/benchmark/benchmark-from-msgpack-lite-data.json b/benchmark/benchmark-from-msgpack-lite-data.json new file mode 100644 index 00000000..874f3b8b --- /dev/null +++ b/benchmark/benchmark-from-msgpack-lite-data.json @@ -0,0 +1,52 @@ +{ + "int0": 0, + "int1": 1, + "int1-": -1, + "int8": 255, + "int8-": -255, + "int16": 256, + "int16-": -256, + "int32": 65536, + "int32-": -65536, + "nil": null, + "true": true, + "false": false, + "float": 0.5, + "float-": -0.5, + "string0": "", + "string1": "A", + "string4": "foobarbaz", + "string8": "Omnes viae Romam ducunt.", + "string16": "L’homme n’est qu’un roseau, le plus faible de la nature ; mais c’est un roseau pensant. Il ne faut pas que l’univers entier s’arme pour l’écraser : une vapeur, une goutte d’eau, suffit pour le tuer. Mais, quand l’univers l’écraserait, l’homme serait encore plus noble que ce qui le tue, puisqu’il sait qu’il meurt, et l’avantage que l’univers a sur lui, l’univers n’en sait rien. Toute notre dignité consiste donc en la pensée. C’est de là qu’il faut nous relever et non de l’espace et de la durée, que nous ne saurions remplir. Travaillons donc à bien penser : voilà le principe de la morale.", + "array0": [], + "array1": [ + "foo" + ], + "array8": [ + 1, + 2, + 4, + 8, + 16, + 32, + 64, + 128, + 256, + 512, + 1024, + 2048, + 4096, + 8192, + 16384, + 32768, + 65536, + 131072, + 262144, + 524288, + 1048576 + ], + "map0": {}, + "map1": { + "foo": "bar" + } +} \ No newline at end of file diff --git a/benchmark/benchmark-from-msgpack-lite.ts b/benchmark/benchmark-from-msgpack-lite.ts new file mode 100644 index 00000000..61fb3a80 --- /dev/null +++ b/benchmark/benchmark-from-msgpack-lite.ts @@ -0,0 +1,156 @@ +// original: https://raw.githubusercontent.com/kawanet/msgpack-lite/master/lib/benchmark.js + +// automatically use the dist version if available +var msgpack_msgpack = try_require("..") || require("../src"); + +var msgpack_node = try_require("msgpack"); +var msgpack_lite = try_require("msgpack-lite"); +var msgpack_js = try_require("msgpack-js"); +var msgpack_js_v5 = try_require("msgpack-js-v5"); +var msgpack5 = try_require("msgpack5"); +var msgpack_unpack = try_require("msgpack-unpack"); +var notepack = try_require("notepack"); + +msgpack5 = msgpack5 && msgpack5(); + +var pkg = require("../package.json"); +var data = require("./benchmark-from-msgpack-lite-data.json"); +var packed = msgpack_lite.encode(data); +var expected = JSON.stringify(data); + +var argv = Array.prototype.slice.call(process.argv, 2); + +if (argv[0] === "-v") { + console.warn(pkg.name + " " + pkg.version); + process.exit(0); +} + +var limit = 5; +if (argv[0] - 0) limit = argv.shift() - 0; +limit *= 1000; + +var COL1 = 65; +var COL2 = 7; +var COL3 = 5; +var COL4 = 7; + +console.log(`Benchmark on NodeJS/${process.version}\n`) +console.log(rpad("operation", COL1), "|", " op ", "|", " ms ", "|", " op/s "); +console.log(rpad("", COL1, "-"), "|", lpad(":", COL2, "-"), "|", lpad(":", COL3, "-"), "|", lpad(":", COL4, "-")); + +var buf, obj; + +if (JSON) { + buf = bench('buf = Buffer.from(JSON.stringify(obj));', JSON_stringify, data); + buf = bench('buf = JSON.stringify(obj);', JSON.stringify, data); + obj = bench('obj = JSON.parse(buf);', JSON.parse, buf); + runTest(obj); +} + +if (msgpack_lite) { + buf = bench('buf = require("msgpack-lite").encode(obj);', msgpack_lite.encode, data); + obj = bench('obj = require("msgpack-lite").decode(buf);', msgpack_lite.decode, packed); + runTest(obj); +} + +if (msgpack_node) { + buf = bench('buf = require("msgpack").pack(obj);', msgpack_node.pack, data); + obj = bench('obj = require("msgpack").unpack(buf);', msgpack_node.unpack, buf); + runTest(obj); +} + +if (msgpack_msgpack) { + buf = bench('buf = require("@msgpack/msgpack").encode(obj);', msgpack_msgpack.encode, data); + buf = bench('buf = Buffer.from(require("@msgpack/msgpack").encode(obj));', msgpack_msgpack_encode, data); + obj = bench('obj = require("@msgpack/msgpack").decode(buf);', msgpack_msgpack.decode, buf); + runTest(obj); +} + +if (msgpack_js_v5) { + buf = bench('buf = require("msgpack-js-v5").encode(obj);', msgpack_js_v5.encode, data); + obj = bench('obj = require("msgpack-js-v5").decode(buf);', msgpack_js_v5.decode, buf); + runTest(obj); +} + +if (msgpack_js) { + buf = bench('buf = require("msgpack-js").encode(obj);', msgpack_js.encode, data); + obj = bench('obj = require("msgpack-js").decode(buf);', msgpack_js.decode, buf); + runTest(obj); +} + +if (msgpack5) { + buf = bench('buf = require("msgpack5")().encode(obj);', msgpack5.encode, data); + obj = bench('obj = require("msgpack5")().decode(buf);', msgpack5.decode, buf); + runTest(obj); +} + +if (notepack) { + buf = bench('buf = require("notepack").encode(obj);', notepack.encode, data); + obj = bench('obj = require("notepack").decode(buf);', notepack.decode, buf); + runTest(obj); +} + +if (msgpack_unpack) { + obj = bench('obj = require("msgpack-unpack").decode(buf);', msgpack_unpack, packed); + runTest(obj); +} + +function JSON_stringify(src: any) { + return Buffer.from(JSON.stringify(src)); +} + +function msgpack_msgpack_encode(data: any) { + return Buffer.from(msgpack_msgpack.encode(data)); +} + +function bench(name: string, func: (...args: any[]) => any, src: any) { + if (argv.length) { + var match = argv.filter(function(grep) { + return (name.indexOf(grep) > -1); + }); + if (!match.length) return SKIP; + } + // warm up + func(src); + + var ret, duration: number; + var start = Date.now(); + var count = 0; + while (1) { + var end = Date.now(); + duration = end - start; + if (duration >= limit) break; + while ((++count) % 100) ret = func(src); + } + name = rpad(name, COL1); + var score = Math.floor(count / duration! * 1000); + console.log(name, "|", lpad(`${count}`, COL2), "|", lpad(`${duration}`, COL3), "|", lpad(`${score}`, COL4)); + return ret; +} + +function rpad(str: string, len: number, chr = " ") { + return str.padEnd(len, chr); +} + +function lpad(str: string, len: number, chr = " ") { + return str.padStart(len, chr); +} + +function runTest(actual: any) { + if (actual === SKIP) return; + actual = JSON.stringify(actual); + if (actual === expected) return; + console.warn("expected: " + expected); + console.warn("actual: " + actual); +} + +function SKIP() { +} + +function try_require(name: string) { + try { + return require(name); + } catch (e) { + // ignore + } +} diff --git a/benchmark/profile-decode.ts b/benchmark/profile-decode.ts new file mode 100644 index 00000000..58e38e6a --- /dev/null +++ b/benchmark/profile-decode.ts @@ -0,0 +1,16 @@ +import { encode, decode } from "../src"; + +const data = require("./benchmark-from-msgpack-lite-data.json"); +const encoded = encode(data); + +console.time("decode #1"); +for (let i = 0; i < 10000; i++) { + decode(encoded); +} +console.timeEnd("decode #1"); + +console.time("decode #2"); +for (let i = 0; i < 10000; i++) { + decode(encoded); +} +console.timeEnd("decode #2"); diff --git a/benchmark/profile-encode.ts b/benchmark/profile-encode.ts new file mode 100644 index 00000000..53e5716d --- /dev/null +++ b/benchmark/profile-encode.ts @@ -0,0 +1,15 @@ +import { encode } from "../src"; + +const data = require("./benchmark-from-msgpack-lite-data.json"); + +console.time("encode #1"); +for (let i = 0; i < 10000; i++) { + encode(data); +} +console.timeEnd("encode #1"); + +console.time("encode #2"); +for (let i = 0; i < 10000; i++) { + encode(data); +} +console.timeEnd("encode #2"); diff --git a/msgpack.base.js b/msgpack.base.js deleted file mode 100644 index d8f027b5..00000000 --- a/msgpack.base.js +++ /dev/null @@ -1,597 +0,0 @@ - -// === msgpack === -// MessagePack -> http://msgpack.sourceforge.net/ - -this.msgpack || (function(globalScope) { - -globalScope.msgpack = { - pack: msgpackpack, // msgpack.pack(data:Mix):ByteArray - unpack: msgpackunpack, // msgpack.unpack(data:BinaryString/ByteArray):Mix - worker: "msgpack.js", // msgpack.worker - WebWorkers script filename - upload: msgpackupload, // msgpack.upload(url:String, option:Hash, callback:Function) - download: msgpackdownload // msgpack.download(url:String, option:Hash, callback:Function) -}; - -var _ie = /MSIE/.test(navigator.userAgent), - _bit2num = {}, // BitStringToNumber { "00000000": 0, ... "11111111": 255 } - _bin2num = {}, // BinaryStringToNumber { "\00": 0, ... "\ff": 255 } - _num2bin = {}, // NumberToBinaryString { 0: "\00", ... 255: "\ff" } - _num2b64 = ("ABCDEFGHIJKLMNOPQRSTUVWXYZ" + - "abcdefghijklmnopqrstuvwxyz0123456789+/").split(""), - _sign = { 8: 0x80, 16: 0x8000, 32: 0x80000000 }, - _split8char = /.{8}/g; - -// for WebWorkers Code Block -self.importScripts && (onmessage = function(event) { - if (event.data.method === "pack") { - postMessage(base64encode(msgpackpack(event.data.data))); - } else { - postMessage(msgpackunpack(event.data.data)); - } -}); - -// msgpack.pack -function msgpackpack(data) { // @param Mix: - // @return ByteArray: - return encode([], data); -} - -// msgpack.unpack -function msgpackunpack(data) { // @param BinaryString/ByteArray: - // @return Mix: - return { data: typeof data === "string" ? toByteArray(data) - : data, - index: -1, decode: decode }.decode(); -} - -// inner - encoder -function encode(rv, // @param ByteArray: result - mix) { // @param Mix: source data - var size = 0, i = 0, iz, c, ary, hash, - high, low, i64 = 0, sign, exp, frac; - - if (mix == null) { // null or undefined - rv.push(0xc0); - } else { - switch (typeof mix) { - case "boolean": - rv.push(mix ? 0xc3 : 0xc2); - break; - case "number": - if (mix !== mix) { // isNaN - rv.push(0xcb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff); // quiet NaN - } else if (mix === Infinity) { - rv.push(0xcb, 0x7f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); // positive infinity - } else if (Math.floor(mix) === mix) { - if (mix < 0) { // int - if (mix >= -32) { // negative fixnum - rv.push(0xe0 + mix + 32); - } else if (mix > -0x80) { - rv.push(0xd0, mix + 0x100); - } else if (mix > -0x8000) { - mix += 0x10000; - rv.push(0xd1, mix >> 8, mix & 0xff); - } else if (mix > -0x80000000) { - mix += 0x100000000; - rv.push(0xd2, mix >>> 24, (mix >> 16) & 0xff, - (mix >> 8) & 0xff, mix & 0xff); - } else { - ++i64; - } - } else { // uint - if (mix < 0x80) { - rv.push(mix); // positive fixnum - } else if (mix < 0x100) { // uint 8 - rv.push(0xcc, mix); - } else if (mix < 0x10000) { // uint 16 - rv.push(0xcd, mix >> 8, mix & 0xff); - } else if (mix < 0x100000000) { // uint 32 - rv.push(0xce, mix >>> 24, (mix >> 16) & 0xff, - (mix >> 8) & 0xff, mix & 0xff); - } else { - ++i64; - } - } - if (i64) { - high = Math.floor(mix / 0x100000000); - low = mix & (0x100000000 - 1); - rv.push(mix < 0 ? 0xd3 : 0xcf, - (high >> 24) & 0xff, (high >> 16) & 0xff, - (high >> 8) & 0xff, high & 0xff, - (low >> 24) & 0xff, (low >> 16) & 0xff, - (low >> 8) & 0xff, low & 0xff); - } - } else { // double - // THX! edvakf - // http://javascript.g.hatena.ne.jp/edvakf/20100614/1276503044 - hash = _bit2num; - sign = mix < 0; - sign && (mix *= -1); - - // add offset 1023 to ensure positive - exp = Math.log(mix) / Math.LN2 + 1023 | 0; - - // shift 52 - (exp - 1023) bits to make integer part exactly 53 bits, - // then throw away trash less than decimal point - frac = (Math.floor(mix * Math.pow(2, 52 + 1023 - exp))). - toString(2).slice(1); - - // exp is between 1 and 2047. make it 11 bits - exp = ("000000000" + exp.toString(2)).slice(-11); - - ary = (+sign + exp + frac).match(_split8char); - rv.push(0xcb, hash[ary[0]], hash[ary[1]], - hash[ary[2]], hash[ary[3]], - hash[ary[4]], hash[ary[5]], - hash[ary[6]], hash[ary[7]]); - } - break; - case "string": - // utf8.encode - for (ary = [], iz = mix.length, i = 0; i < iz; ++i) { - c = mix.charCodeAt(i); - if (c < 0x80) { // ASCII(0x00 ~ 0x7f) - ary.push(c & 0x7f); - } else if (c < 0x0800) { - ary.push(((c >>> 6) & 0x1f) | 0xc0, (c & 0x3f) | 0x80); - } else if (c < 0x10000) { - ary.push(((c >>> 12) & 0x0f) | 0xe0, - ((c >>> 6) & 0x3f) | 0x80, (c & 0x3f) | 0x80); - } - } - setType(rv, 32, ary.length, [0xa0, 0xda, 0xdb]); - Array.prototype.push.apply(rv, ary); - break; - default: // array or hash - if (Object.prototype.toString.call(mix) === "[object Array]") { // array - size = mix.length; - setType(rv, 16, size, [0x90, 0xdc, 0xdd]); - for (; i < size; ++i) { - encode(rv, mix[i]); - } - } else { // hash - if (Object.keys) { - size = Object.keys(mix).length; - } else { - for (i in mix) { - mix.hasOwnProperty(i) && ++size; - } - } - setType(rv, 16, size, [0x80, 0xde, 0xdf]); - for (i in mix) { - encode(rv, i); - encode(rv, mix[i]); - } - } - } - } - return rv; -} - -// inner - decoder -function decode() { // @return Mix: - var rv, undef, size, i = 0, iz, msb = 0, c, sign, exp, frac, key, - that = this, - data = that.data, - type = data[++that.index]; - - if (type >= 0xe0) { // Negative FixNum (111x xxxx) (-32 ~ -1) - return type - 0x100; - } - if (type < 0x80) { // Positive FixNum (0xxx xxxx) (0 ~ 127) - return type; - } - if (type < 0x90) { // FixMap (1000 xxxx) - size = type - 0x80; - type = 0x80; - } else if (type < 0xa0) { // FixArray (1001 xxxx) - size = type - 0x90; - type = 0x90; - } else if (type < 0xc0) { // FixRaw (101x xxxx) - size = type - 0xa0; - type = 0xa0; - } - switch (type) { - case 0xc0: return null; - case 0xc2: return false; - case 0xc3: return true; - case 0xca: rv = readByte(that, 4); // float - sign = rv & _sign[32]; // 1bit - exp = (rv >> 23) & 0xff; // 8bits - frac = rv & 0x7fffff; // 23bits - if (!rv || rv === 0x80000000) { // 0.0 or -0.0 - return 0; - } - if (exp === 0xff) { // NaN or Infinity - return frac ? NaN : Infinity; - } - return (sign ? -1 : 1) * - (frac | 0x800000) * Math.pow(2, exp - 127 - 23); // 127: bias - case 0xcb: rv = readByte(that, 4); // double - sign = rv & _sign[32]; // 1bit - exp = (rv >> 20) & 0x7ff; // 11bits - frac = rv & 0xfffff; // 52bits - 32bits (high word) - if (!rv || rv === 0x80000000) { // 0.0 or -0.0 - return 0; - } - if (exp === 0x7ff) { // NaN or Infinity - readByte(that, 4); // seek index - return frac ? NaN : Infinity; - } - return (sign ? -1 : 1) * - ((frac | 0x100000) * Math.pow(2, exp - 1023 - 20) // 1023: bias - + readByte(that, 4) * Math.pow(2, exp - 1023 - 52)); - case 0xcf: return readByte(that, 4) * Math.pow(2, 32) + - readByte(that, 4); // uint 64 - case 0xce: return readByte(that, 4); // uint 32 - case 0xcd: return readByte(that, 2); // uint 16 - case 0xcc: return readByte(that, 1); // uint 8 - case 0xd3: return decodeInt64(that); // int 64 - case 0xd2: rv = readByte(that, 4); // int 32 - case 0xd1: rv === undef && (rv = readByte(that, 2)); // int 16 - case 0xd0: rv === undef && (rv = readByte(that, 1)); // int 8 - msb = 4 << ((type & 0x3) + 1); // 8, 16, 32 - return rv < _sign[msb] ? rv : rv - _sign[msb] * 2; - case 0xdb: size = readByte(that, 4); // raw 32 - case 0xda: size === undef && (size = readByte(that, 2)); // raw 16 - case 0xa0: i = that.index + 1; // raw - that.index += size; - // utf8.decode - for (rv = [], ri = -1, iz = i + size; i < iz; ++i) { - c = data[i]; // first byte - if (c < 0x80) { // ASCII(0x00 ~ 0x7f) - rv[++ri] = c; - } else if (c < 0xe0) { - rv[++ri] = (c & 0x1f) << 6 | (data[++i] & 0x3f); - } else if (c < 0xf0) { - rv[++ri] = (c & 0x0f) << 12 | (data[++i] & 0x3f) << 6 - | (data[++i] & 0x3f); - } - } - return String.fromCharCode.apply(null, rv); - case 0xdf: size = readByte(that, 4); // map 32 - case 0xde: size === undef && (size = readByte(that, 2)); // map 16 - case 0x80: for (rv = {}; i < size; ++i) { // map - key = that.decode(); - rv[key] = that.decode(); // key/value pair - } - return rv; - case 0xdd: size = readByte(that, 4); // array 32 - case 0xdc: size === undef && (size = readByte(that, 2)); // array 16 - case 0x90: for (rv = []; i < size; ++i) { // array - rv.push(that.decode()); - } - } - return rv; -} - -// inner - read byte -function readByte(that, // @param Object: - size) { // @param Number: - // @return Number: - var rv = 0, data = that.data, i = that.index; - - switch (size) { - case 4: rv += data[++i] * 0x1000000 + (data[++i] << 16); - case 2: rv += data[++i] << 8; - case 1: rv += data[++i]; - } - that.index = i; - return rv; -} - -// inner - decode int64 -function decodeInt64(that) { // @param Object: - // @return Number: - var rv, overflow = 0, - bytes = that.data.slice(that.index + 1, that.index + 9); - - that.index += 8; - - // avoid overflow - if (bytes[0] & 0x80) { - - ++overflow; - bytes[0] ^= 0xff; - bytes[1] ^= 0xff; - bytes[2] ^= 0xff; - bytes[3] ^= 0xff; - bytes[4] ^= 0xff; - bytes[5] ^= 0xff; - bytes[6] ^= 0xff; - bytes[7] ^= 0xff; - } - rv = bytes[0] * 0x100000000000000 - + bytes[1] * 0x1000000000000 - + bytes[2] * 0x10000000000 - + bytes[3] * 0x100000000 - + bytes[4] * 0x1000000 - + bytes[5] * 0x10000 - + bytes[6] * 0x100 - + bytes[7]; - return overflow ? (rv + 1) * -1 : rv; -} - -// inner - set type and fixed size -function setType(rv, // @param ByteArray: result - fixSize, // @param Number: fix size. 16 or 32 - size, // @param Number: size - types) { // @param ByteArray: type formats. eg: [0x90, 0xdc, 0xdd] - if (size < fixSize) { - rv.push(types[0] + size); - } else if (size < 0x10000) { // 16 - rv.push(types[1], size >> 8, size & 0xff); - } else if (size < 0x100000000) { // 32 - rv.push(types[2], size >>> 24, (size >> 16) & 0xff, - (size >> 8) & 0xff, size & 0xff); - } -} - -// msgpack.download - load from server -function msgpackdownload(url, // @param String: - option, // @param Hash: { worker, timeout, before, after } - // option.worker - Boolean(= false): true is use WebWorkers - // option.timeout - Number(= 10): timeout sec - // option.before - Function: before(xhr, option) - // option.after - Function: after(xhr, option, { status, ok }) - callback) { // @param Function: callback(data, option, { status, ok }) - // data - Mix/null: - // option - Hash: - // status - Number: HTTP status code - // ok - Boolean: - option.method = "GET"; - option.binary = true; - ajax(url, option, callback); -} - -// msgpack.upload - save to server -function msgpackupload(url, // @param String: - option, // @param Hash: { data, worker, timeout, before, after } - // option.data - Mix: - // option.worker - Boolean(= false): true is use WebWorkers - // option.timeout - Number(= 10): timeout sec - // option.before - Function: before(xhr, option) - // option.after - Function: after(xhr, option, { status, ok }) - callback) { // @param Function: callback(data, option, { status, ok }) - // data - String: responseText - // option - Hash: - // status - Number: HTTP status code - // ok - Boolean: - option.method = "PUT"; - option.binary = true; - - if (option.worker && globalScope.Worker) { - var worker = new Worker(msgpack.worker); - - worker.onmessage = function(event) { - option.data = event.data; - ajax(url, option, callback); - }; - worker.postMessage({ method: "pack", data: option.data }); - } else { - // pack and base64 encode - option.data = base64encode(msgpackpack(option.data)); - ajax(url, option, callback); - } -} - -// inner - -function ajax(url, // @param String: - option, // @param Hash: { data, ifmod, method, timeout, - // header, binary, before, after, worker } - // option.data - Mix: upload data - // option.ifmod - Boolean: true is "If-Modified-Since" header - // option.method - String: "GET", "POST", "PUT" - // option.timeout - Number(= 10): timeout sec - // option.header - Hash(= {}): { key: "value", ... } - // option.binary - Boolean(= false): true is binary data - // option.before - Function: before(xhr, option) - // option.after - Function: after(xhr, option, { status, ok }) - // option.worker - Boolean(= false): true is use WebWorkers - callback) { // @param Function: callback(data, option, { status, ok }) - // data - String/Mix/null: - // option - Hash: - // status - Number: HTTP status code - // ok - Boolean: - function readyStateChange() { - if (xhr.readyState === 4) { - var data, status = xhr.status, worker, byteArray, - rv = { status: status, ok: status >= 200 && status < 300 }; - - if (!run++) { - if (method === "PUT") { - data = rv.ok ? xhr.responseText : ""; - } else { - if (rv.ok) { - if (option.worker && globalScope.Worker) { - worker = new Worker(msgpack.worker); - worker.onmessage = function(event) { - callback(event.data, option, rv); - }; - worker.postMessage({ method: "unpack", - data: xhr.responseText }); - gc(); - return; - } else { - byteArray = _ie ? toByteArrayIE(xhr) - : toByteArray(xhr.responseText); - data = msgpackunpack(byteArray); - } - } - } - after && after(xhr, option, rv); - callback(data, option, rv); - gc(); - } - } - } - - function ng(abort, status) { - if (!run++) { - var rv = { status: status || 400, ok: false }; - - after && after(xhr, option, rv); - callback(null, option, rv); - gc(abort); - } - } - - function gc(abort) { - abort && xhr && xhr.abort && xhr.abort(); - watchdog && (clearTimeout(watchdog), watchdog = 0); - xhr = null; - globalScope.addEventListener && - globalScope.removeEventListener("beforeunload", ng, false); - } - - var watchdog = 0, - method = option.method || "GET", - header = option.header || {}, - before = option.before, - after = option.after, - data = option.data || null, - xhr = globalScope.XMLHttpRequest ? new XMLHttpRequest() : - globalScope.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP") : - null, - run = 0, i, - overrideMimeType = "overrideMimeType", - setRequestHeader = "setRequestHeader", - getbinary = method === "GET" && option.binary; - - try { - xhr.onreadystatechange = readyStateChange; - xhr.open(method, url, true); // ASync - - before && before(xhr, option); - - getbinary && xhr[overrideMimeType] && - xhr[overrideMimeType]("text/plain; charset=x-user-defined"); - data && - xhr[setRequestHeader]("Content-Type", - "application/x-www-form-urlencoded"); - - for (i in header) { - xhr[setRequestHeader](i, header[i]); - } - - globalScope.addEventListener && - globalScope.addEventListener("beforeunload", ng, false); // 400: Bad Request - - xhr.send(data); - watchdog = setTimeout(function() { - ng(1, 408); // 408: Request Time-out - }, (option.timeout || 10) * 1000); - } catch (err) { - ng(0, 400); // 400: Bad Request - } -} - -// inner - BinaryString To ByteArray -function toByteArray(data) { // @param BinaryString: "\00\01" - // @return ByteArray: [0x00, 0x01] - var rv = [], bin2num = _bin2num, remain, - ary = data.split(""), - i = -1, iz; - - iz = ary.length; - remain = iz % 8; - - while (remain--) { - ++i; - rv[i] = bin2num[ary[i]]; - } - remain = iz >> 3; - while (remain--) { - rv.push(bin2num[ary[++i]], bin2num[ary[++i]], - bin2num[ary[++i]], bin2num[ary[++i]], - bin2num[ary[++i]], bin2num[ary[++i]], - bin2num[ary[++i]], bin2num[ary[++i]]); - } - return rv; -} - -// inner - BinaryString to ByteArray -function toByteArrayIE(xhr) { - var rv = [], data, remain, - charCodeAt = "charCodeAt", - loop, v0, v1, v2, v3, v4, v5, v6, v7, - i = -1, iz; - - iz = vblen(xhr); - data = vbstr(xhr); - loop = Math.ceil(iz / 2); - remain = loop % 8; - - while (remain--) { - v0 = data[charCodeAt](++i); // 0x00,0x01 -> 0x0100 - rv.push(v0 & 0xff, v0 >> 8); - } - remain = loop >> 3; - while (remain--) { - v0 = data[charCodeAt](++i); - v1 = data[charCodeAt](++i); - v2 = data[charCodeAt](++i); - v3 = data[charCodeAt](++i); - v4 = data[charCodeAt](++i); - v5 = data[charCodeAt](++i); - v6 = data[charCodeAt](++i); - v7 = data[charCodeAt](++i); - rv.push(v0 & 0xff, v0 >> 8, v1 & 0xff, v1 >> 8, - v2 & 0xff, v2 >> 8, v3 & 0xff, v3 >> 8, - v4 & 0xff, v4 >> 8, v5 & 0xff, v5 >> 8, - v6 & 0xff, v6 >> 8, v7 & 0xff, v7 >> 8); - } - iz % 2 && rv.pop(); - - return rv; -} - -// inner - base64.encode -function base64encode(data) { // @param ByteArray: - // @return Base64String: - var rv = [], - c = 0, i = -1, iz = data.length, - pad = [0, 2, 1][data.length % 3], - num2bin = _num2bin, - num2b64 = _num2b64; - - if (globalScope.btoa) { - while (i < iz) { - rv.push(num2bin[data[++i]]); - } - return btoa(rv.join("")); - } - --iz; - while (i < iz) { - c = (data[++i] << 16) | (data[++i] << 8) | (data[++i]); // 24bit - rv.push(num2b64[(c >> 18) & 0x3f], - num2b64[(c >> 12) & 0x3f], - num2b64[(c >> 6) & 0x3f], - num2b64[ c & 0x3f]); - } - pad > 1 && (rv[rv.length - 2] = "="); - pad > 0 && (rv[rv.length - 1] = "="); - return rv.join(""); -} - -// --- init --- -(function() { - var i = 0, v; - - for (; i < 0x100; ++i) { - v = String.fromCharCode(i); - _bit2num[("0000000" + i.toString(2)).slice(-8)] = i; - _bin2num[v] = i; // "\00" -> 0x00 - _num2bin[i] = v; // 0 -> "\00" - } - // http://twitter.com/edvakf/statuses/15576483807 - for (i = 0x80; i < 0x100; ++i) { // [Webkit][Gecko] - _bin2num[String.fromCharCode(0xf700 + i)] = i; // "\f780" -> 0x80 - } -})(); - -_ie && document.write(' diff --git a/test/ajax.htm b/test/ajax.htm deleted file mode 100644 index c5d5bda9..00000000 --- a/test/ajax.htm +++ /dev/null @@ -1,179 +0,0 @@ - - - -msgpack ajax demo - - - - - -

msgpack.download(), msgpack.upload()

-
-
- Last downloaded data length: 0 bytes -
-
- add decode log - -
- - -
- - - - - - - - - - - - - - - - -
Test1 (without WebWorkers)
Choose Download dataUpload Last dataDownload Last data
- - - - - -> - - -> - -
- - -
- - - - - - - - - - - - - - - - -
Test2 (with WebWorkers)
Choose Download dataUpload Last dataDownload Last data
- - - - - -> - - -> - -
- - - - diff --git a/test/bench.htm b/test/bench.htm deleted file mode 100644 index 6f85dbd7..00000000 --- a/test/bench.htm +++ /dev/null @@ -1,177 +0,0 @@ - - -benchmark msgpack vs json - - - - - - - - - - - - - - - - - - -
Prepare DataBench !
- - - -
- - - -
- -> - - -
- -
- - - - - - - - - - - diff --git a/test/bench.ie.htm b/test/bench.ie.htm deleted file mode 100644 index 730ed6d0..00000000 --- a/test/bench.ie.htm +++ /dev/null @@ -1,176 +0,0 @@ - - -benchmark msgpack vs json - - - - - - - - - - - - - - - - - -
Prepare DataBench !
- - - -
- - - -
- -> - - -
- -
- - - - - - - - - - - diff --git a/test/byteArray.js b/test/byteArray.js deleted file mode 100644 index 6edd82b6..00000000 --- a/test/byteArray.js +++ /dev/null @@ -1,53 +0,0 @@ - -// === uu.byteArray === -//#include uupaa.js - -uu.byteArray || (function(uu) { - -uu.byteArray = uubyteArray; // uu.byteArray(source:HexString):ByteArray -uu.byteArray.toHexString = uubyteArraytoHexString; // uu.byteArray.toHexString(source:ByteArray, - // verbose:Boolean = false):HexString - -// uu.byteArray - HexString to ByteArray -function uubyteArray(source) { // @param String: "00010203" - // @return ByteArray: [0, 1, 2, 3] - // @throws Error("BAD_DATA") - var rv = [], ri = -1, v, i = 0, iz = source.length, - hh2num = uu.hash.hh2num; - - if (iz % 2) { - throw new Error("BAD_DATA"); - } - - v = source.split(""); - - for (; i < iz; i += 2) { - rv[++ri] = hh2num[v[i] + v[i + 1]]; - } - return rv; -} - -// uu.byteArray.toHexString - array to HexString -function uubyteArraytoHexString(source, // @param ByteArray: [0, 1, 2, 3] - verbose) { // @param Boolean(= false): - // @return HexString: verbose = false "00010203" - // or verbose = true "0x00, 0x01, 0x02, 0x03" - var rv = [], ri = -1, v, i = 0, iz = source.length, - num2hh = uu.hash.num2hh; - - if (verbose) { - for (; i < iz; ++i) { - v = source[i]; - rv[++ri] = "0x" + num2hh[v * (v < 0 ? -1 : 1)]; - } - return rv.join(", "); - } - for (; i < iz; ++i) { - v = source[i]; - rv[++ri] = num2hh[v * (v < 0 ? -1 : 1)]; - } - return rv.join(""); -} - -})(uu); - diff --git a/test/codec-float.test.ts b/test/codec-float.test.ts new file mode 100644 index 00000000..87e4f3e1 --- /dev/null +++ b/test/codec-float.test.ts @@ -0,0 +1,76 @@ +import * as ieee754 from "ieee754"; +import assert from "assert"; +import { decode } from "../src"; + +const FLOAT32_TYPE = 0xca; +const FLOAT64_TYPE = 0xcb; + +const SPECS = { + POSITIVE_ZERO: +0.0, + NEGATIVE_ZERO: -0.0, + POSITIVE_INFINITY: Number.POSITIVE_INFINITY, + NEGATIVE_INFINITY: Number.NEGATIVE_INFINITY, + + POSITIVE_VALUE_1: +0.1, + POSITIVE_VALUE_2: +42, + POSITIVE_VALUE_3: +Math.PI, + POSITIVE_VALUE_4: +Math.E, + NEGATIVE_VALUE_1: -0.1, + NEGATIVE_VALUE_2: -42, + NEGATIVE_VALUE_3: -Math.PI, + NEGATIVE_VALUE_4: -Math.E, + + MAX_SAFE_INTEGER: Number.MAX_SAFE_INTEGER, + MIN_SAFE_INTEGER: Number.MIN_SAFE_INTEGER, + + MAX_VALUE: Number.MAX_VALUE, + MIN_VALUE: Number.MIN_VALUE, +} as Record; + +describe("codec: float 32/64", () => { + context("float 32", () => { + for (const name of Object.keys(SPECS)) { + const value = SPECS[name]; + + it(`decodes ${name} (${value})`, () => { + const buf: Array = []; + ieee754.write(buf, value, 0, false, 23, 4); + const expected = ieee754.read(buf, 0, false, 23, 4); + + assert.deepStrictEqual(decode([FLOAT32_TYPE, ...buf]), expected, "matched sign"); + assert.notDeepStrictEqual(decode([FLOAT32_TYPE, ...buf]), -expected, "unmatched sign"); + }); + } + + it(`decodes NaN`, () => { + const buf: Array = []; + ieee754.write(buf, NaN, 0, false, 23, 4); + const expected = ieee754.read(buf, 0, false, 23, 4); + + assert.deepStrictEqual(decode([FLOAT32_TYPE, ...buf]), expected, "matched sign"); + }); + }); + + context("float 64", () => { + for (const name of Object.keys(SPECS)) { + const value = SPECS[name]; + + it(`decodes ${name} (${value})`, () => { + const buf: Array = []; + ieee754.write(buf, value, 0, false, 52, 8); + const expected = ieee754.read(buf, 0, false, 52, 8); + + assert.deepStrictEqual(decode([FLOAT64_TYPE, ...buf]), expected, "matched sign"); + assert.notDeepStrictEqual(decode([FLOAT64_TYPE, ...buf]), -expected, "unmatched sign"); + }); + } + + it(`decodes NaN`, () => { + const buf: Array = []; + ieee754.write(buf, NaN, 0, false, 52, 8); + const expected = ieee754.read(buf, 0, false, 52, 8); + + assert.deepStrictEqual(decode([FLOAT64_TYPE, ...buf]), expected, "matched sign"); + }); + }); +}); diff --git a/test/codec-int.test.ts b/test/codec-int.test.ts new file mode 100644 index 00000000..78e02954 --- /dev/null +++ b/test/codec-int.test.ts @@ -0,0 +1,44 @@ +import assert from "assert"; +import { encodeInt64, decodeInt64, encodeInt32, decodeInt32 } from "../src/utils/int"; + +const INT32SPECS = { + ZERO: 0, + ONE: 1, + MINUS_ONE: -1, + X_FF: 0xff, + MINUS_X_FF: -0xff, + INT32_MAX: 0x7fffffff, + INT32_MIN: -0x7fffffff - 1, +} as Record; + +const INT64SPECS = { + ...INT32SPECS, + MAX_SAFE_INTEGER: Number.MAX_SAFE_INTEGER, + MIN_SAFE_INTEGER: Number.MIN_SAFE_INTEGER, +} as Record; + +describe("codec: encode and decode int 32/64", () => { + context("int 32", () => { + for (const name of Object.keys(INT32SPECS)) { + const value = INT32SPECS[name]; + + it(`${value} (${value < 0 ? "-" : ""}0x${Math.abs(value).toString(16)})`, () => { + const b: Array = []; + encodeInt32(b, value); + assert.deepStrictEqual(decodeInt32(b[0], b[1], b[2], b[3]), value); + }); + } + }); + + context("int 64", () => { + for (const name of Object.keys(INT64SPECS)) { + const value = INT64SPECS[name]; + + it(`${value} (${value < 0 ? "-" : ""}0x${Math.abs(value).toString(16)})`, () => { + const b: Array = []; + encodeInt64(b, value); + assert.deepStrictEqual(decodeInt64(b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]), value); + }); + } + }); +}); diff --git a/test/codec-timestamp.test.ts b/test/codec-timestamp.test.ts new file mode 100644 index 00000000..0f126a97 --- /dev/null +++ b/test/codec-timestamp.test.ts @@ -0,0 +1,27 @@ +import assert from "assert"; +import util from "util"; +import { encode, decode } from "../src"; + +const TIME = 1556636810389; + +const SPECS = { + ZERO: new Date(0), + TIME_BEFORE_EPOCH_NS: new Date(-1), + TIME_BEFORE_EPOCH_SEC: new Date(-1000), + TIME_BEFORE_EPOCH_SEC_AND_NS: new Date(-1002), + TIMESTAMP32: new Date(Math.floor(TIME / 1000) * 1000), + TIMESTAMP64: new Date(TIME), + TIMESTAMP96_SEC_OVER_UINT32: new Date(0x400000000 * 1000), + TIMESTAMP96_SEC_OVER_UINT32_WITH_NS: new Date(0x400000000 * 1000 + 2), +} as Record; + +describe("codec: timestamp 32/64/96", () => { + for (const name of Object.keys(SPECS)) { + const value = SPECS[name]; + + it(`encodes and decodes ${name} (${value.toISOString()})`, () => { + const encoded = encode(value); + assert.deepStrictEqual(decode(encoded), value, `encoded: ${util.inspect(encoded)}`); + }); + } +}); diff --git a/test/codec.htm b/test/codec.htm deleted file mode 100644 index d424d986..00000000 --- a/test/codec.htm +++ /dev/null @@ -1,1316 +0,0 @@ - - - -msgpack codec test - - - - - diff --git a/test/encode-edge-cases.test.ts b/test/encode-edge-cases.test.ts new file mode 100644 index 00000000..aaef1915 --- /dev/null +++ b/test/encode-edge-cases.test.ts @@ -0,0 +1,32 @@ +import assert from "assert"; +import { encode, decode } from "../src"; + +describe("edge cases", () => { + context("try to encode trycyclic refs", () => { + it("throws errors", () => { + const cyclicRefs: Array = []; + cyclicRefs.push(cyclicRefs); + assert.throws(() => { + encode(cyclicRefs); + }, /too deep/i); + }); + }); + + context("try to encode non-encodable objects", () => { + it("throws errors", () => { + assert.throws(() => { + encode(Symbol("this is a symbol!")); + }, /unrecognized object/i); + }); + }); + + context("try to decode invlid MessagePack binary", () => { + it("throws errors", () => { + const TYPE_NEVER_USED = 0xc1; + + assert.throws(() => { + decode([TYPE_NEVER_USED]); + }, /unrecognized type byte/i); + }); + }); +}); diff --git a/test/last.bin b/test/last.bin deleted file mode 100644 index f14e69b3..00000000 --- a/test/last.bin +++ /dev/null @@ -1 +0,0 @@ -ab?|hr˿\( \ No newline at end of file diff --git a/test/last.php b/test/last.php deleted file mode 100644 index 1a892e47..00000000 --- a/test/last.php +++ /dev/null @@ -1,8 +0,0 @@ - diff --git a/test/mocha.opts b/test/mocha.opts new file mode 100644 index 00000000..23e391a1 --- /dev/null +++ b/test/mocha.opts @@ -0,0 +1 @@ +--require ts-node/register diff --git a/test/msgpack-test-suite.test.ts b/test/msgpack-test-suite.test.ts new file mode 100644 index 00000000..7e05779d --- /dev/null +++ b/test/msgpack-test-suite.test.ts @@ -0,0 +1,120 @@ +import assert from "assert"; +import util from "util"; +import { Exam } from "msgpack-test-js"; +import { MsgTimestamp } from "msg-timestamp"; +import { encode as _encode, decode as _decode } from "../src"; +import { ExtensionCodec, EXT_TIMESTAMP, encodeTimestampFromTimeSpec } from "../src/ExtensionCodec"; +import { BufferType } from "../src/BufferType"; + +const { encode, decode }: { encode: typeof _encode; decode: typeof _decode } = (() => { + if (process.env.TEST_DIST) { + console.log("# TEST_DIST is set"); + return require(".."); + } else { + return { + encode: _encode, + decode: _decode, + }; + } +})(); + +const extensionCodec = new ExtensionCodec(); +extensionCodec.register({ + type: EXT_TIMESTAMP, + encode: (input) => { + if (input instanceof MsgTimestamp) { + return encodeTimestampFromTimeSpec({ + sec: input.getTime(), + nsec: input.getNano(), + }); + } else { + return null; + } + }, + decode: (_type: number, data: BufferType) => { + return MsgTimestamp.parse(Buffer.from(data as any)); + }, +}); + +const TEST_TYPES = { + array: 1, + bignum: 0, // TODO + binary: 1, + bool: 1, + map: 1, + nil: 1, + number: 1, + string: 1, + timestamp: 1, +}; + +describe("msgpack-test-suite", () => { + Exam.getExams(TEST_TYPES).forEach((exam) => { + const types = exam.getTypes(TEST_TYPES); + const first = types[0]; + const title = first + ": " + exam.stringify(first); + it(`encodes ${title}`, () => { + types.forEach((type) => { + const value = exam.getValue(type); + const buffer = Buffer.from(encode(value, { extensionCodec })); + + if (exam.matchMsgpack(buffer)) { + assert(true, exam.stringify(type)); + } else { + const msg = `encode(${util.inspect(value)}): expect ${util.inspect(buffer)} to be one of ${util.inspect( + exam.getMsgpacks(), + )}`; + assert(false, msg); + } + }); + }); + + it(`decodes ${title}`, () => { + const msgpacks = exam.getMsgpacks(); + msgpacks.forEach((encoded, idx) => { + const value = decode(encoded, { extensionCodec }); + if (exam.matchValue(value)) { + assert(true, exam.stringify(idx)); + } else { + const values = exam.getTypes().map((type) => exam.getValue(type)); + const msg = `decode(${util.inspect(encoded)}): expect ${util.inspect(value)} to be one of ${util.inspect( + values, + )}`; + assert(false, msg); + } + }); + }); + }); + + context("specs not covered by msgpack-test-js", () => { + // by detecting test coverage + const SPECS = { + FLOAT64_POSITIVE_INF: Number.POSITIVE_INFINITY, + FLOAT64_NEGATIVE_INF: Number.NEGATIVE_INFINITY, + FLOAT64_NAN: Number.NaN, + STR16: "x".repeat(0x100), + STR32: "x".repeat(0x10000), + BIN16: new Uint8Array(0x100).fill(0xff), + BIN32: new Uint8Array(0x10000).fill(0xff), + ARRAY16: new Array(0x100).fill(true), + ARRAY32: new Array(0x10000).fill(true), + MAP16: new Array(0x100).fill(null).reduce>((acc, _val, i) => { + acc[`k${i}`] = i; + return acc; + }, {}), + MAP32: new Array(0x10000).fill(null).reduce>((acc, _val, i) => { + acc[`k${i}`] = i; + return acc; + }, {}), + } as Record; + + for (const name of Object.keys(SPECS)) { + const value = SPECS[name]; + + it(`encodes and decodes ${name}`, () => { + const encoded = encode(value); + assert.deepStrictEqual(decode(new Uint8Array(encoded)), value); + }); + } + }); +}); diff --git a/test/put.bin b/test/put.bin deleted file mode 100644 index f14e69b3..00000000 --- a/test/put.bin +++ /dev/null @@ -1 +0,0 @@ -ab?|hr˿\( \ No newline at end of file diff --git a/test/types/ieee754.d.ts b/test/types/ieee754.d.ts new file mode 100644 index 00000000..c68455f4 --- /dev/null +++ b/test/types/ieee754.d.ts @@ -0,0 +1,11 @@ +declare module "ieee754" { + function read(buf: ArrayLike, offset: number, isLE: boolean, mLen: number, nBytes: number): number; + function write( + buf: ArrayLike, + value: number, + index: number, + isLE: boolean, + mLen: number, + nBytes: number, + ): void; +} diff --git a/test/upload.php b/test/upload.php deleted file mode 100644 index 7c672a3c..00000000 --- a/test/upload.php +++ /dev/null @@ -1,13 +0,0 @@ - diff --git a/test/uupaa.js b/test/uupaa.js deleted file mode 100644 index 81f41612..00000000 --- a/test/uupaa.js +++ /dev/null @@ -1,9126 +0,0 @@ -/*!{id:"uupaa.js",ver:0.8,license:"MIT",author:"uupaa.js@gmail.com"}*/ - -// Firefox 3.5(end of 2010-08) -//