UNPKG

@ferrisk/bsonfy

Version:

Ultrafast BSON serializer/parser

360 lines (301 loc) 16.7 kB
/////////////////////////////////////////////////////////////////////////////// // \author (c) Marco Paland (marco@paland.com) // 2018, PALANDesign Hannover, Germany // // \license The MIT License (MIT) // // This file is part of the bysonfy library. // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // // \brief BSON test cases // /////////////////////////////////////////////////////////////////////////////// import { BSON } from '../../src/bson'; import { expect, assert } from 'chai'; import 'mocha'; describe('BSON', () => { class UnknownObj { _dummy: number = 123; test() { } } let serialize_vector = [ { obj: { "BSON": ["awesome", 5.05, 1986] }, bson: "310000000442534f4e002600000002300008000000617765736f6d65000131003333333333331440103200c20700000000", }, { obj: { int32: 10, int64: 1125899906842624, flo: 3.141592653, str: "Hello äöü", utc: new BSON.UTC("2011-10-10T14:48:00Z"), bool: true, date: new Date("2011-10-10T14:48:00Z") }, bson: "6400000010696e743332000a00000012696e74363400000000000000040001666c6f0038e92f54fb21094002737472000d00000048656c6c6f20c3a4c3b6c3bc00097574630000f94dee3201000008626f6f6c000109646174650000f94dee3201000000" }, { obj: { arr: ["foo", "bar", 100, 1000], ta: new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]), obj: { int32: 10, int64: 1125899906842624, flo: 3.141592653 } }, bson: "7500000004617272002900000002300004000000666f6f00023100040000006261720010320064000000103300e8030000000574610008000000000102030405060708036f626a002c00000010696e743332000a00000012696e74363400000000000000040001666c6f0038e92f54fb2109400000" }, { obj: { da: [[1, 2, 3], [4, 5, 6], [7, 8, 9]], uuid: new BSON.UUID(new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16])) }, bson: "80000000046461005c0000000430001a000000103000010000001031000200000010320003000000000431001a000000103000040000001031000500000010320006000000000432001a000000103000070000001031000800000010320009000000000005757569640010000000040102030405060708090a0b0c0d0e0f1000" }, { obj: { id: 123456, sk: new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]), pk: new Uint8Array([255, 254, 253, 252, 251, 250, 249, 248]) }, bson: "2f0000001069640040e2010005736b000800000000010203040506070805706b000800000000fffefdfcfbfaf9f800" }, { obj: { id: 10, obj: new UnknownObj(), str: "Test", n: null, b: true }, bson: "22000000106964000a00000002737472000500000054657374000a6e000862000100" } ]; let deserialize_vector = [ { obj: { "BSON": ["awesome", 5.05, 1986] }, bson: "310000000442534f4e002600000002300008000000617765736f6d65000131003333333333331440103200c20700000000", }, { obj: { int32: 10, int64: 1125899906842624, flo: 3.141592653, str: "Hello äöü", utc: new BSON.UTC("2011-10-10T14:48:00Z"), bool: true, date: new Uint8Array([1,2,3,4]), nu: null }, bson: "6900000010696e743332000a00000012696e74363400000000000000040001666c6f0038e92f54fb21094002737472000d00000048656c6c6f20c3a4c3b6c3bc00097574630000f94dee3201000008626f6f6c00010564617465000400000000010203040a6e750000" }, { obj: { arr: ["foo", "bar", 100, 1000], ta: new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]), obj: { int32: 10, int64: 1125899906842624, flo: 3.141592653 } }, bson: "7500000004617272002900000002300004000000666f6f00023100040000006261720010320064000000103300e8030000000574610008000000000102030405060708036f626a002c00000010696e743332000a00000012696e74363400000000000000040001666c6f0038e92f54fb2109400000" }, { obj: { da: [[1, 2, 3], [4, 5, 6], [7, 8, 9]], uuid: new BSON.UUID(new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16])) }, bson: "80000000046461005c0000000430001a000000103000010000001031000200000010320003000000000431001a000000103000040000001031000500000010320006000000000432001a000000103000070000001031000800000010320009000000000005757569640010000000040102030405060708090a0b0c0d0e0f1000" }, { obj: { id: 123456, sk: new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]), pk: new Uint8Array([255, 254, 253, 252, 251, 250, 249, 248]) }, bson: "2f0000001069640040e2010005736b000800000000010203040506070805706b000800000000fffefdfcfbfaf9f800" }, { obj: { id: 10, oid: new BSON.ObjectId(new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12])), str: "Test", n: null, b: true }, bson: "33000000106964000a000000076f6964000102030405060708090a0b0c02737472000500000054657374000a6e000862000100" } ]; describe("serialize", function () { it("checks empty/unknown object", function () { let bson = BSON.serialize(""); expect(bin2hex(bson)).to.deep.equal("0500000000"); bson = BSON.serialize({ obj: new UnknownObj() }); expect(bin2hex(bson)).to.deep.equal("0500000000"); }); it("checks int32", function () { let bson = BSON.serialize({ int: 0x1234 }); expect(bin2hex(bson)).to.deep.equal("0e00000010696e74003412000000"); }); it("checks negative int32", function () { let bson = BSON.serialize({ int: -10 }); expect(bin2hex(bson)).to.deep.equal("0e00000010696e7400f6ffffff00"); }); it("checks int64", function () { let bson = BSON.serialize({ int: 0x1234567890 }); expect(bin2hex(bson)).to.deep.equal("1200000012696e7400907856341200000000"); }); it("checks negative int64", function () { let bson = BSON.serialize({ int: -78187493520 }); expect(bin2hex(bson)).to.deep.equal("1200000012696e74007087a9cbedffffff00"); }); it("checks double (64-bit binary floating point)", function () { let bson = BSON.serialize({ flo: 3.1415926535 }); expect(bin2hex(bson)).to.deep.equal("1200000001666c6f0044174154fb21094000"); }); it("checks string", function () { let bson = BSON.serialize({ str: "Hello World" }); expect(bin2hex(bson)).to.deep.equal("1a00000002737472000c00000048656c6c6f20576f726c640000"); }); it("checks UTF-8 string", function () { let bson = BSON.serialize({ str: "\u00C4\u00D6\u00DC\u00DF" }); expect(bin2hex(bson)).to.deep.equal("17000000027374720009000000c384c396c39cc39f0000"); }); it("checks boolean", function () { let bson = BSON.serialize({ bool: false }); expect(bin2hex(bson)).to.deep.equal("0c00000008626f6f6c000000"); bson = BSON.serialize({ bool: true }); expect(bin2hex(bson)).to.deep.equal("0c00000008626f6f6c000100"); }); it("checks null", function () { let bson = BSON.serialize({ nul: null }); expect(bin2hex(bson)).to.deep.equal("0a0000000a6e756c0000"); }); it("checks binary", function () { let bson = BSON.serialize({ bin: new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 9, 0xFF]) }); expect(bin2hex(bson)).to.deep.equal("190000000562696e000a00000000010203040506070809ff00"); }); it("checks array", function () { let bson = BSON.serialize({ arr: [0xFA, 0xFB, 0xFC, 0xFD] }); expect(bin2hex(bson)).to.deep.equal("2b000000046172720021000000103000fa000000103100fb000000103200fc000000103300fd0000000000"); }); it("checks array in array", function () { let bson = BSON.serialize({ arr: [[0x10, 0x11, 0x12, 0x13], 0xFA, 0xFB, 0xFC, 0xFD] }); expect(bin2hex(bson)).to.deep.equal("4f000000046172720045000000043000210000001030001000000010310011000000103200120000001033001300000000103100fa000000103200fb000000103300fc000000103400fd0000000000"); }); it("checks object", function () { let bson = BSON.serialize({ obj: { int: 10, str: "" } }); expect(bin2hex(bson)).to.deep.equal("22000000036f626a001800000010696e74000a000000027374720001000000000000"); }); it("checks Date", function () { let bson = BSON.serialize({ dat: new Date("2016-06-25T14:48:11Z") }); expect(bin2hex(bson)).to.deep.equal("120000000964617400f84308885501000000"); }); it("checks UTC", function () { let bson = BSON.serialize({ utc1: new BSON.UTC("2016-06-25T14:48:11Z"), utc2: new BSON.UTC("2016-06-25T14:48:11+0200"), utc3: new BSON.UTC([0x3D, 0x53, 0xAE, 0x91, 0x55, 0x01, 0x00, 0x00]) }); expect(bin2hex(bson)).to.deep.equal("2f000000097574633100f843088855010000097574633200f8669a87550100000975746333003d53ae915501000000"); }); it("checks UUID", function () { let bson = BSON.serialize({ uuid: new BSON.UUID(new Uint8Array([0x43, 0xab, 0x2e, 0x98, 0x62, 0x3c, 0x03, 0xe8, 0x5f, 0x54, 0x1a, 0x17, 0x45, 0xe0, 0x1b, 0xda])) }); expect(bin2hex(bson)).to.deep.equal("20000000057575696400100000000443ab2e98623c03e85f541a1745e01bda00"); }); it("checks ObjectId", function () { let bson = BSON.serialize({ oid: new BSON.ObjectId([0xa8, 0x05, 0x57, 0xf0, 0x5c, 0x6d, 0x7a, 0xd0, 0x9f, 0xa7, 0x35, 0x70]) }); expect(bin2hex(bson)).to.deep.equal("16000000076f696400a80557f05c6d7ad09fa7357000"); }); it("checks complex objects", function () { for (let i = 0; i < serialize_vector.length; i++) { let bson = BSON.serialize(serialize_vector[i].obj); expect(bin2hex(bson)).to.deep.equal(serialize_vector[i].bson); } }); }); describe("deserialize", function () { it("checks empty/unknown object", function () { let obj = BSON.deserialize(hex2bin("0500000000")); expect(obj).to.deep.equal({ }); }); it("checks int32", function () { let obj = BSON.deserialize(hex2bin("0e00000010696e74003412000000")); expect(obj).to.deep.equal({ int: 0x1234 }); }); it("checks negative int32", function () { let obj = BSON.deserialize(hex2bin("0e00000010696e7400f6ffffff00")); expect(obj).to.deep.equal({ int: -10 }); }); it("checks int64", function () { let obj = BSON.deserialize(hex2bin("1200000012696e7400907856341200000000")); expect(obj).to.deep.equal({ int: 0x1234567890 }); }); it("checks int64 > 2^53", function () { let obj = BSON.deserialize(hex2bin("1200000012696e7400FFDEBC9A7856341200")); expect(obj).to.deep.equal({ int: 0x123456789ABCDEFF }); }); it("checks negative int64", function () { let obj = BSON.deserialize(hex2bin("1200000012696e74007087a9cbedffffff00")); expect(obj).to.deep.equal({ int: -78187493520 }); }); it("checks double (64-bit binary floating point)", function () { let obj = BSON.deserialize(hex2bin("1200000001666c6f0044174154fb21094000")); expect(obj).to.deep.equal({ flo: 3.1415926535 }); }); it("checks string", function () { let obj = BSON.deserialize(hex2bin("1a00000002737472000c00000048656c6c6f20576f726c640000")); expect(obj).to.deep.equal({ str: "Hello World" }); }); it("checks UTF-8 string", function () { let obj = BSON.deserialize(hex2bin("17000000027374720009000000c384c396c39cc39f0000")); expect(obj).to.deep.equal({ str: "\u00C4\u00D6\u00DC\u00DF" }); }); it("checks boolean", function () { let obj = BSON.deserialize(hex2bin("0c00000008626f6f6c000000")); expect(obj).to.deep.equal({ bool: false }); obj = BSON.deserialize(hex2bin("0c00000008626f6f6c000100")); expect(obj).to.deep.equal({ bool: true }); }); it("checks null", function () { let obj = BSON.deserialize(hex2bin("0a0000000a6e756c0000")); expect(obj).to.deep.equal({ nul: null }); }); it("checks binary", function () { let obj = BSON.deserialize(hex2bin("190000000562696e000a00000000010203040506070809ff00")); expect(obj).to.deep.equal({ bin: new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 9, 0xFF]) }); }); it("checks array", function () { let obj = BSON.deserialize(hex2bin("2b000000046172720021000000103000fa000000103100fb000000103200fc000000103300fd0000000000")); expect(obj).to.deep.equal({ arr: [0xFA, 0xFB, 0xFC, 0xFD] }); }); it("checks array in array", function () { let obj = BSON.deserialize(hex2bin("4f000000046172720045000000043000210000001030001000000010310011000000103200120000001033001300000000103100fa000000103200fb000000103300fc000000103400fd0000000000")); expect(obj).to.deep.equal({ arr: [[0x10, 0x11, 0x12, 0x13], 0xFA, 0xFB, 0xFC, 0xFD] }); }); it("checks object", function () { let obj = BSON.deserialize(hex2bin("22000000036f626a001800000010696e74000a000000027374720001000000000000")); expect(obj).to.deep.equal({ obj: { int: 10, str: "" } }); }); it("checks Date", function () { let obj = BSON.deserialize(hex2bin("120000000964617400f84308885501000000")); expect(obj).to.deep.equal({ dat: new Date("2016-06-25T14:48:11Z") }); }); it("checks UTC", function () { let obj = BSON.deserialize(hex2bin("2f000000097574633100f843088855010000097574633200f8669a87550100000975746333003d53ae915501000000"), true); expect(obj).to.deep.equal({ utc1: new BSON.UTC("2016-06-25T14:48:11Z"), utc2: new BSON.UTC("2016-06-25T14:48:11+0200"), utc3: new BSON.UTC([0x3D, 0x53, 0xAE, 0x91, 0x55, 0x01, 0x00, 0x00]) }); }); it("checks UUID", function () { let obj = BSON.deserialize(hex2bin("20000000057575696400100000000443ab2e98623c03e85f541a1745e01bda00")); expect(obj).to.deep.equal({ uuid: new BSON.UUID(new Uint8Array([0x43, 0xab, 0x2e, 0x98, 0x62, 0x3c, 0x03, 0xe8, 0x5f, 0x54, 0x1a, 0x17, 0x45, 0xe0, 0x1b, 0xda])) }); obj = BSON.deserialize(hex2bin("2100000005757569640011000000040143ab2e98623c03e85f541a1745e01bda00")); expect(obj).to.equal(undefined); }); it("checks ObjectId", function () { let obj = BSON.deserialize(hex2bin("16000000076f696400a80557f05c6d7ad09fa7357000")); expect(obj).to.deep.equal({ oid: new BSON.ObjectId([0xa8, 0x05, 0x57, 0xf0, 0x5c, 0x6d, 0x7a, 0xd0, 0x9f, 0xa7, 0x35, 0x70]) }); }); it("checks complex objects", function () { for (let i = 0; i < deserialize_vector.length; i++) { let bson = BSON.serialize(deserialize_vector[i].obj); let obj = BSON.deserialize(hex2bin(deserialize_vector[i].bson), true); expect(obj).to.deep.equal(deserialize_vector[i].obj); } }); it("checks document too small", function () { let obj = BSON.deserialize(hex2bin("04000000")); expect(obj).to.equal(undefined); }); it("checks document termination", function () { let obj = BSON.deserialize(hex2bin("0c00000008626f6f6c000001")); expect(obj).to.equal(undefined); obj = BSON.deserialize(hex2bin("0c00000008626f6f6c0000")); expect(obj).to.equal(undefined); }); it("checks document size mismatch", function () { let obj = BSON.deserialize(hex2bin("0d00000008626f6f6c000000")); expect(obj).to.equal(undefined); }); it("checks illegal keyname", function () { let obj = BSON.deserialize(hex2bin("0c00000008626f6f6c010100")); expect(obj).to.equal(undefined); }); it("checks unknown element", function () { let obj = BSON.deserialize(hex2bin("0c00000018626f6f6c000000")); expect(obj).to.equal(undefined); }); }); ///////////////////////////////////////////////////////////////////////////// function bin2hex(bin: Uint8Array, uppercase: boolean = false): string { let hex = uppercase ? "0123456789ABCDEF" : "0123456789abcdef"; let str = ""; for (let i = 0, len = bin.length; i < len; i++) { str += hex.charAt((bin[i] >>> 4) & 0x0f) + hex.charAt(bin[i] & 0x0f); } return str; } function hex2bin(hex: string): Uint8Array { let bin = new Uint8Array(hex.length >>> 1); for (let i = 0, len = hex.length >>> 1; i < len; i++) { bin[i] = parseInt(hex.substr(i << 1, 2), 16); } return bin; } });