diff --git a/test/node/bson_test.js b/test/node/bson_test.js index d7edc17f..99693649 100644 --- a/test/node/bson_test.js +++ b/test/node/bson_test.js @@ -298,80 +298,6 @@ describe('BSON', function () { done(); }); - /** - * @ignore - */ - it('Should correctly ignore undefined values in arrays', function (done) { - var doc = { doc: { notdefined: undefined } }; - var serialized_data = BSON.serialize(doc, { - ignoreUndefined: true - }); - var serialized_data2 = Buffer.alloc( - BSON.calculateObjectSize(doc, { - ignoreUndefined: true - }) - ); - BSON.serializeWithBufferAndIndex(doc, serialized_data2, { - ignoreUndefined: true - }); - - assertBuffersEqual(done, serialized_data, serialized_data2, 0); - var doc1 = BSON.deserialize(serialized_data); - - expect(undefined).to.deep.equal(doc1.doc.notdefined); - done(); - }); - - it('Should correctly serialize undefined array entries as null values', function (done) { - var doc = { doc: { notdefined: undefined }, a: [1, 2, undefined, 3] }; - var serialized_data = BSON.serialize(doc, { - ignoreUndefined: true - }); - var serialized_data2 = Buffer.alloc( - BSON.calculateObjectSize(doc, { - ignoreUndefined: true - }) - ); - BSON.serializeWithBufferAndIndex(doc, serialized_data2, { - ignoreUndefined: true - }); - assertBuffersEqual(done, serialized_data, serialized_data2, 0); - var doc1 = BSON.deserialize(serialized_data); - expect(undefined).to.deep.equal(doc1.doc.notdefined); - expect(null).to.equal(doc1.a[2]); - done(); - }); - - it('Should correctly serialize undefined array entries as undefined values', function (done) { - var doc = { doc: { notdefined: undefined }, a: [1, 2, undefined, 3] }; - var serialized_data = BSON.serialize(doc, { - ignoreUndefined: false - }); - var serialized_data2 = Buffer.alloc( - BSON.calculateObjectSize(doc, { - ignoreUndefined: false - }) - ); - BSON.serializeWithBufferAndIndex(doc, serialized_data2, { - ignoreUndefined: false - }); - - // console.log("======================================== 0") - // console.log(serialized_data.toString('hex')) - // console.log(serialized_data2.toString('hex')) - - assertBuffersEqual(done, serialized_data, serialized_data2, 0); - var doc1 = BSON.deserialize(serialized_data); - var doc2 = BSON.deserialize(serialized_data2); - // console.log("======================================== 0") - // console.dir(doc1) - // console.dir(doc2) - - expect(null).to.deep.equal(doc1.doc.notdefined); - expect(null).to.deep.equal(doc2.doc.notdefined); - done(); - }); - /** * @ignore */ diff --git a/test/node/bson_undefined.test.ts b/test/node/bson_undefined.test.ts new file mode 100644 index 00000000..b902450c --- /dev/null +++ b/test/node/bson_undefined.test.ts @@ -0,0 +1,108 @@ +import { expect } from 'chai'; +import { bufferFromHexArray } from './tools/utils'; +import { BSON } from '../register-bson'; +import { BSON_DATA_NULL } from '../../src/constants'; + +describe('BSON undefined', () => { + const KEY_A = '6100'; + const KEY_0 = '3000'; + const KEY_1 = '3100'; + const KEY_2 = '3200'; + + describe('when deserialize is given BSON bytes with undefined value', function () { + it('returns a javascript undefined value', () => { + const bsonDocWithUndefined = bufferFromHexArray([ + '06', // BSON undefined + KEY_A + ]); + const doc = BSON.deserialize(bsonDocWithUndefined); + expect(doc).to.have.own.property('a').that.is.undefined; + }); + }); + + describe('when serialize is given a javascript object that contains undefined', () => { + describe('when ignoreUndefined is set to false', function () { + it('serializes to document with a set to BSON null (type=10)', () => { + const jsObject = { a: undefined }; + const bytes = BSON.serialize(jsObject, { ignoreUndefined: false }); + expect(bytes).to.have.lengthOf(8); + const elements = BSON.onDemand.parseToElements(bytes); + expect(elements).to.have.lengthOf(1); + expect(elements[0][0]).to.deep.equal(BSON_DATA_NULL); + }); + }); + + describe('when ignoreUndefined is set to true', function () { + it('serializes to empty document', () => { + const jsObject = { a: undefined }; + const bytes = BSON.serialize(jsObject, { ignoreUndefined: true }); + expect(bytes).to.deep.equal(Uint8Array.of(5, 0, 0, 0, 0)); + }); + }); + + describe('when ignoreUndefined is unset', function () { + it('serializes to empty document', () => { + const jsObject = { a: undefined }; + const bytes = BSON.serialize(jsObject); + expect(bytes).to.deep.equal(Uint8Array.of(5, 0, 0, 0, 0)); + }); + }); + }); + + describe('when undefined appears inside an array', function () { + describe('when ignoreUndefined is set to true', function () { + it('serializes undefined values as null', function () { + // because this would change the size of the array + const doc = { a: [1, undefined, 3] }; + const bytes = BSON.serialize(doc, { ignoreUndefined: true }); + expect(bytes).to.deep.equal( + bufferFromHexArray([ + '04', // array + KEY_A, + bufferFromHexArray([ + ...['10', KEY_0, '01000000'], // int "0" = 1 + ...['0A', KEY_1], // null "1" + ...['10', KEY_2, '03000000'] // int "2" = 3 + ]).toString('hex') + ]) + ); + }); + }); + + describe('when ignoreUndefined is set to false', function () { + it('serializes undefined values as null', function () { + const doc = { a: [1, undefined, 3] }; + const bytes = BSON.serialize(doc, { ignoreUndefined: false }); + expect(bytes).to.deep.equal( + bufferFromHexArray([ + '04', // array + KEY_A, + bufferFromHexArray([ + ...['10', KEY_0, '01000000'], // int "0" = 1 + ...['0A', KEY_1], // null "1" + ...['10', KEY_2, '03000000'] // int "2" = 3 + ]).toString('hex') + ]) + ); + }); + }); + + describe('when ignoreUndefined is unset', function () { + it('serializes undefined values as null', function () { + const doc = { a: [1, undefined, 3] }; + const bytes = BSON.serialize(doc); + expect(bytes).to.deep.equal( + bufferFromHexArray([ + '04', // array + KEY_A, + bufferFromHexArray([ + ...['10', KEY_0, '01000000'], // int "0" = 1 + ...['0A', KEY_1], // null "1" + ...['10', KEY_2, '03000000'] // int "2" = 3 + ]).toString('hex') + ]) + ); + }); + }); + }); +}); diff --git a/test/node/parser/serializer.test.ts b/test/node/parser/serializer.test.ts index c06161cc..6af3f27a 100644 --- a/test/node/parser/serializer.test.ts +++ b/test/node/parser/serializer.test.ts @@ -26,6 +26,7 @@ describe('serialize()', () => { }); it('does not turn nested nulls into empty documents', () => { + // In JS typeof null is 'object' so it is possible it could be misinterpreted as an object with no keys const nestedNull = bufferFromHexArray([ '0A', // null type '6100', // 'a\x00'