diff --git a/src/ensure_buffer.ts b/src/ensure_buffer.ts index d2b97832..8b82a085 100644 --- a/src/ensure_buffer.ts +++ b/src/ensure_buffer.ts @@ -8,7 +8,7 @@ import { isAnyArrayBuffer } from './parser/utils'; * @param potentialBuffer - The potential buffer * @returns Buffer the input if potentialBuffer is a buffer, or a buffer that * wraps a passed in Uint8Array - * @throws TypeError If anything other than a Buffer or Uint8Array is passed in + * @throws BSONTypeError If anything other than a Buffer or Uint8Array is passed in */ export function ensureBuffer(potentialBuffer: Buffer | ArrayBufferView | ArrayBuffer): Buffer { if (ArrayBuffer.isView(potentialBuffer)) { diff --git a/src/error.ts b/src/error.ts index b9071d57..8f1a4173 100644 --- a/src/error.ts +++ b/src/error.ts @@ -1,5 +1,10 @@ /** @public */ export class BSONError extends Error { + constructor(message: string) { + super(message); + Object.setPrototypeOf(this, BSONError.prototype); + } + get name(): string { return 'BSONError'; } @@ -7,6 +12,11 @@ export class BSONError extends Error { /** @public */ export class BSONTypeError extends TypeError { + constructor(message: string) { + super(message); + Object.setPrototypeOf(this, BSONTypeError.prototype); + } + get name(): string { return 'BSONTypeError'; } diff --git a/test/binary_parser.js b/test/binary_parser.js index dde662b3..76df24fa 100644 --- a/test/binary_parser.js +++ b/test/binary_parser.js @@ -1,4 +1,8 @@ 'use strict'; + +const BSON = require('./register-bson'); +const BSONError = BSON.BSONError; + /** * Binary Parser. * Jonas Raoni Soares Silva @@ -20,7 +24,7 @@ function BinaryParser(bigEndian, allowExceptions) { BinaryParser.warn = function warn(msg) { if (this.allowExceptions) { - throw new Error(msg); + throw new BSONError(msg); } return 1; @@ -419,7 +423,7 @@ BinaryParserBuffer.prototype.hasNeededBits = function hasNeededBits(neededBits) BinaryParserBuffer.prototype.checkBuffer = function checkBuffer(neededBits) { if (!this.hasNeededBits(neededBits)) { - throw new Error('checkBuffer::missing bytes'); + throw new BSONError('checkBuffer::missing bytes'); } }; diff --git a/test/node/bigint_tests.js b/test/node/bigint_tests.js index 32262c79..efdb82ac 100644 --- a/test/node/bigint_tests.js +++ b/test/node/bigint_tests.js @@ -2,6 +2,7 @@ 'use strict'; const BSON = require('../register-bson'); +const BSONTypeError = BSON.BSONTypeError; describe('BSON BigInt Support', function () { before(function () { @@ -13,7 +14,7 @@ describe('BSON BigInt Support', function () { }); it('Should serialize an int that fits in int32', function () { const testDoc = { b: BigInt(32) }; - expect(() => BSON.serialize(testDoc)).to.throw(TypeError); + expect(() => BSON.serialize(testDoc)).to.throw(BSONTypeError); // const serializedDoc = BSON.serialize(testDoc); // // prettier-ignore @@ -25,7 +26,7 @@ describe('BSON BigInt Support', function () { it('Should serialize an int that fits in int64', function () { const testDoc = { b: BigInt(0x1ffffffff) }; - expect(() => BSON.serialize(testDoc)).to.throw(TypeError); + expect(() => BSON.serialize(testDoc)).to.throw(BSONTypeError); // const serializedDoc = BSON.serialize(testDoc); // // prettier-ignore @@ -37,7 +38,7 @@ describe('BSON BigInt Support', function () { it('Should serialize an int that fits in decimal128', function () { const testDoc = { b: BigInt('9223372036854776001') }; // int64 max + 1 - expect(() => BSON.serialize(testDoc)).to.throw(TypeError); + expect(() => BSON.serialize(testDoc)).to.throw(BSONTypeError); // const serializedDoc = BSON.serialize(testDoc); // // prettier-ignore @@ -52,7 +53,7 @@ describe('BSON BigInt Support', function () { const testDoc = { b: BigInt('9'.repeat(35)) }; // decimal 128 can only encode 34 digits of precision - expect(() => BSON.serialize(testDoc)).to.throw(TypeError); + expect(() => BSON.serialize(testDoc)).to.throw(BSONTypeError); // expect(() => BSON.serialize(testDoc)).to.throw(); }); diff --git a/test/node/bson_corpus_tests.js b/test/node/bson_corpus_tests.js index 5973b5af..83f39d54 100644 --- a/test/node/bson_corpus_tests.js +++ b/test/node/bson_corpus_tests.js @@ -3,6 +3,7 @@ const Buffer = require('buffer').Buffer; const BSON = require('../register-bson'); +const BSONError = BSON.BSONError; const EJSON = BSON.EJSON; const deserializeOptions = { @@ -89,19 +90,19 @@ const parseErrorForRootDocument = scenario => { } if (/Null/.test(parseError.description)) { - expect(caughtError).to.be.instanceOf(Error); + expect(caughtError).to.be.instanceOf(BSONError); expect(caughtError.message).to.match(/null bytes/); } else if (/Bad/.test(parseError.description)) { // There is a number of failing tests that start with 'Bad' // so this check is essentially making the test optional for now - // This should assert that e is an Error and something about the message + // This should assert that e is a BSONError and something about the message // TODO(NODE-3637): remove special logic and use expect().to.throw() and add errors to lib expect(caughtError).to.satisfy(e => { - if (e instanceof Error) return true; + if (e instanceof BSONError) return true; else this.skip(); }); } else { - expect(caughtError).to.be.instanceOf(Error); + expect(caughtError).to.be.instanceOf(BSONError); } }); } diff --git a/test/node/bson_test.js b/test/node/bson_test.js index c37461ab..85b6d718 100644 --- a/test/node/bson_test.js +++ b/test/node/bson_test.js @@ -16,6 +16,7 @@ const Int32 = BSON.Int32; const Double = BSON.Double; const MinKey = BSON.MinKey; const MaxKey = BSON.MaxKey; +const BSONError = BSON.BSONError; const { BinaryParser } = require('../binary_parser'); const vm = require('vm'); const { assertBuffersEqual } = require('./tools/utils'); @@ -33,7 +34,7 @@ var ISODate = function (string) { const match = string.match(ISO_REGEX); if (!match) { - throw new Error(`Invalid ISO 8601 date given: ${string}`); + throw new BSONError(`Invalid ISO 8601 date given: ${string}`); } var date = new Date(); diff --git a/test/node/ensure_buffer_test.js b/test/node/ensure_buffer_test.js index fe271138..a4648128 100644 --- a/test/node/ensure_buffer_test.js +++ b/test/node/ensure_buffer_test.js @@ -3,6 +3,8 @@ const { Buffer } = require('buffer'); const { ensureBuffer } = require('../register-bson'); +const BSON = require('../register-bson'); +const BSONTypeError = BSON.BSONTypeError; describe('ensureBuffer tests', function () { it('should be a function', function () { @@ -15,7 +17,7 @@ describe('ensureBuffer tests', function () { expect(function () { bufferOut = ensureBuffer(bufferIn); - }).to.not.throw(Error); + }).to.not.throw(BSONTypeError); expect(bufferOut).to.be.an.instanceOf(Buffer); expect(bufferOut.buffer).to.equal(bufferIn.buffer); @@ -29,7 +31,7 @@ describe('ensureBuffer tests', function () { expect(function () { bufferOut = ensureBuffer(arrayIn); - }).to.not.throw(Error); + }).to.not.throw(BSONTypeError); expect(bufferOut).to.be.an.instanceOf(Buffer); expect(bufferOut.buffer).to.equal(arrayIn.buffer); @@ -41,7 +43,7 @@ describe('ensureBuffer tests', function () { expect(function () { bufferOut = ensureBuffer(arrayBufferIn); - }).to.not.throw(Error); + }).to.not.throw(BSONTypeError); expect(bufferOut).to.be.an.instanceOf(Buffer); expect(bufferOut.buffer).to.equal(arrayBufferIn); @@ -57,7 +59,7 @@ describe('ensureBuffer tests', function () { expect(function () { bufferOut = ensureBuffer(arrayBufferIn); - }).to.not.throw(Error); + }).to.not.throw(BSONTypeError); expect(bufferOut).to.be.an.instanceOf(Buffer); expect(bufferOut.buffer).to.equal(arrayBufferIn); @@ -69,7 +71,7 @@ describe('ensureBuffer tests', function () { expect(function () { bufferOut = ensureBuffer(input); - }).to.not.throw(Error); + }).to.not.throw(BSONTypeError); expect(bufferOut).to.be.an.instanceOf(Buffer); expect(bufferOut.byteLength).to.equal(3); @@ -80,7 +82,7 @@ describe('ensureBuffer tests', function () { it(`should throw if input is ${typeof item}: ${item}`, function () { expect(function () { ensureBuffer(item); - }).to.throw(TypeError); + }).to.throw(BSONTypeError); }); }); diff --git a/test/node/error_test.js b/test/node/error_test.js new file mode 100644 index 00000000..60f09397 --- /dev/null +++ b/test/node/error_test.js @@ -0,0 +1,37 @@ +'use strict'; + +const BSON = require('../register-bson'); +const BSONTypeError = BSON.BSONTypeError; +const BSONError = BSON.BSONError; + +describe('BSONTypeError', function () { + it('should evaluate true on instanceof BSONTypeError and TypeError', function () { + const bsonTypeErr = new BSONTypeError(); + expect(bsonTypeErr instanceof BSONTypeError).to.be.true; + expect(bsonTypeErr instanceof TypeError).to.be.true; + expect(bsonTypeErr).to.be.instanceOf(BSONTypeError); + expect(bsonTypeErr).to.be.instanceOf(TypeError); + }); + + it('should correctly set BSONTypeError name and message properties', function () { + const bsonTypeErr = new BSONTypeError('This is a BSONTypeError message'); + expect(bsonTypeErr.name).equals('BSONTypeError'); + expect(bsonTypeErr.message).equals('This is a BSONTypeError message'); + }); +}); + +describe('BSONError', function () { + it('should evaluate true on instanceof BSONError and Error', function () { + const bsonErr = new BSONError(); + expect(bsonErr instanceof BSONError).to.be.true; + expect(bsonErr instanceof Error).to.be.true; + expect(bsonErr).to.be.instanceOf(BSONError); + expect(bsonErr).to.be.instanceOf(Error); + }); + + it('should correctly set BSONError name and message properties', function () { + const bsonErr = new BSONError('This is a BSONError message'); + expect(bsonErr.name).equals('BSONError'); + expect(bsonErr.message).equals('This is a BSONError message'); + }); +}); diff --git a/test/node/object_id_tests.js b/test/node/object_id_tests.js index 4d18b69f..f59a0040 100644 --- a/test/node/object_id_tests.js +++ b/test/node/object_id_tests.js @@ -2,6 +2,7 @@ const Buffer = require('buffer').Buffer; const BSON = require('../register-bson'); +const BSONTypeError = BSON.BSONTypeError; const util = require('util'); const ObjectId = BSON.ObjectId; @@ -33,7 +34,7 @@ describe('ObjectId', function () { for (const { input, description } of invalidInputs) { it(`should throw error if ${description} is passed in`, function () { - expect(() => new ObjectId(input)).to.throw(TypeError); + expect(() => new ObjectId(input)).to.throw(BSONTypeError); }); } @@ -44,8 +45,7 @@ describe('ObjectId', function () { return noArgObjID.toHexString(); } }; - - expect(() => new ObjectId(objectIdLike)).to.throw(TypeError); + expect(() => new ObjectId(objectIdLike)).to.throw(BSONTypeError); }); it('should correctly create ObjectId from object with valid string id', function () { @@ -117,15 +117,15 @@ describe('ObjectId', function () { const objectNullId = { id: null }; - expect(() => new ObjectId(objectNumId)).to.throw(TypeError); - expect(() => new ObjectId(objectNullId)).to.throw(TypeError); + expect(() => new ObjectId(objectNumId)).to.throw(BSONTypeError); + expect(() => new ObjectId(objectNullId)).to.throw(BSONTypeError); }); it('should throw an error if object with invalid string id is passed in', function () { const objectInvalid24HexStr = { id: 'FFFFFFFFFFFFFFFFFFFFFFFG' }; - expect(() => new ObjectId(objectInvalid24HexStr)).to.throw(TypeError); + expect(() => new ObjectId(objectInvalid24HexStr)).to.throw(BSONTypeError); }); it('should correctly create ObjectId from object with invalid string id and toHexString method', function () { @@ -144,7 +144,7 @@ describe('ObjectId', function () { const objectInvalidBuffer = { id: Buffer.from([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]) }; - expect(() => new ObjectId(objectInvalidBuffer)).to.throw(TypeError); + expect(() => new ObjectId(objectInvalidBuffer)).to.throw(BSONTypeError); }); it('should correctly create ObjectId from object with invalid Buffer id and toHexString method', function () { @@ -185,11 +185,11 @@ describe('ObjectId', function () { }); it('should throw error if non-12 byte non-24 hex string passed in', function () { - expect(() => new ObjectId('FFFFFFFFFFFFFFFFFFFFFFFG')).to.throw(TypeError); - expect(() => new ObjectId('thisstringisdefinitelytoolong')).to.throw(TypeError); - expect(() => new ObjectId('tooshort')).to.throw(TypeError); - expect(() => new ObjectId('101010')).to.throw(TypeError); - expect(() => new ObjectId('')).to.throw(TypeError); + expect(() => new ObjectId('FFFFFFFFFFFFFFFFFFFFFFFG')).to.throw(BSONTypeError); + expect(() => new ObjectId('thisstringisdefinitelytoolong')).to.throw(BSONTypeError); + expect(() => new ObjectId('tooshort')).to.throw(BSONTypeError); + expect(() => new ObjectId('101010')).to.throw(BSONTypeError); + expect(() => new ObjectId('')).to.throw(BSONTypeError); }); it('should correctly create ObjectId from 24 hex string', function () { @@ -234,7 +234,7 @@ describe('ObjectId', function () { it('should throw an error if invalid Buffer passed in', function () { const a = Buffer.from([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]); - expect(() => new ObjectId(a)).to.throw(TypeError); + expect(() => new ObjectId(a)).to.throw(BSONTypeError); }); it('should correctly allow for node.js inspect to work with ObjectId', function (done) { @@ -260,11 +260,11 @@ describe('ObjectId', function () { const characterCodesLargerThan256 = 'abcdefŽhijkl'; const length12Not12Bytes = '🐶🐶🐶🐶🐶🐶'; expect(() => new ObjectId(characterCodesLargerThan256).toHexString()).to.throw( - TypeError, + BSONTypeError, 'Argument passed in must be a string of 12 bytes' ); expect(() => new ObjectId(length12Not12Bytes).id).to.throw( - TypeError, + BSONTypeError, 'Argument passed in must be a string of 12 bytes' ); }); diff --git a/test/node/uuid_tests.js b/test/node/uuid_tests.js index 6598abbe..0ff69b17 100644 --- a/test/node/uuid_tests.js +++ b/test/node/uuid_tests.js @@ -4,6 +4,8 @@ const { Buffer } = require('buffer'); const { Binary, UUID } = require('../register-bson'); const { inspect } = require('util'); const { validate: uuidStringValidate, version: uuidStringVersion } = require('uuid'); +const BSON = require('../register-bson'); +const BSONTypeError = BSON.BSONTypeError; // Test values const UPPERCASE_DASH_SEPARATED_UUID_STRING = 'AAAAAAAA-AAAA-4AAA-AAAA-AAAAAAAAAAAA'; @@ -76,7 +78,7 @@ describe('UUID', () => { */ it('should throw if passed invalid 36-char uuid hex string', () => { expect(() => new UUID(LOWERCASE_DASH_SEPARATED_UUID_STRING)).to.not.throw(); - expect(() => new UUID('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa')).to.throw(TypeError); + expect(() => new UUID('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa')).to.throw(BSONTypeError); // Note: The version is missing here ^ }); @@ -85,7 +87,7 @@ describe('UUID', () => { */ it('should throw if passed unsupported argument', () => { expect(() => new UUID(LOWERCASE_DASH_SEPARATED_UUID_STRING)).to.not.throw(); - expect(() => new UUID({})).to.throw(TypeError); + expect(() => new UUID({})).to.throw(BSONTypeError); }); /** diff --git a/test/register-bson.js b/test/register-bson.js index 4061d2a3..a8240154 100644 --- a/test/register-bson.js +++ b/test/register-bson.js @@ -14,25 +14,4 @@ require('object.entries/auto'); const BSON = require('../lib/bson'); const { ensureBuffer } = require('../lib/ensure_buffer'); BSON.ensureBuffer = ensureBuffer; - -const { Assertion, util } = require('chai'); -Assertion.overwriteMethod('throw', function (original) { - return function assertThrow(...args) { - if (args.length === 0 || args.includes(BSON.BSONError) || args.includes(BSON.BSONTypeError)) { - // By default, lets check for BSONError or BSONTypeError - // Since we compile to es5 instanceof is broken??? - const assertion = original.apply(this, args); - const object = util.flag(assertion, 'object'); - return this.assert( - object && /BSONError|BSONTypeError/.test(object.stack), - 'expected #{this} to be a BSONError or a BSONTypeError but got #{act}', - 'expected #{this} to not be a BSONError nor a BSONTypeError but got #{act}', - (object && object.stack) || '' - ); - } else { - return original.apply(this, args); - } - }; -}); - module.exports = BSON;