Skip to content

Commit

Permalink
Allow NaN (#94)
Browse files Browse the repository at this point in the history
* Test encoding and decoding NaN

* Encode NaN
  • Loading branch information
ninevra authored Feb 11, 2021
1 parent 2a5e19d commit e2788d0
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 18 deletions.
4 changes: 1 addition & 3 deletions lib/encoder.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,11 @@

var Buffer = require('safe-buffer').Buffer
var bl = require('bl')
var isNaN = require('./helpers.js').isNaN
var isFloat = require('./helpers.js').isFloat

module.exports = function buildEncode (encodingTypes, options) {
function encode (obj) {
if (obj === undefined) throw new Error('undefined is not encodable in msgpack!')
if (isNaN(obj)) throw new Error('NaN is not encodable in msgpack!')

if (obj === null) return Buffer.from([ 0xc0 ])
if (obj === true) return Buffer.from([ 0xc3 ])
Expand Down Expand Up @@ -133,7 +131,7 @@ const fround = Math.fround
function encodeFloat (obj, forceFloat64) {
var buf

if (forceFloat64 || !fround || fround(obj) !== obj) {
if (forceFloat64 || !fround || !Object.is(fround(obj), obj)) {
buf = Buffer.allocUnsafe(9)
buf[0] = 0xcb
buf.writeDoubleBE(obj, 1)
Expand Down
6 changes: 0 additions & 6 deletions lib/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,3 @@ util.inherits(IncompleteBufferError, Error)
exports.isFloat = function isFloat (n) {
return n % 1 !== 0
}

exports.isNaN = function isNaN (n) {
/* eslint-disable no-self-compare */
return n !== n && typeof n === 'number'
/* eslint-enable no-self-compare */
}
16 changes: 12 additions & 4 deletions test/15-elements-maps.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,21 @@ test('do not encode undefined in a map', function (t) {
t.end()
})

test('throw error on NaN in a map', function (t) {
test('encode NaN in a map', function (t) {
var instance = msgpack()
var toEncode = { a: NaN, hello: 'world' }

t.throws(function () {
instance.encode(toEncode)
}, Error, 'must throw Error')
const buf = instance.encode(toEncode)

t.assert(Object.is(instance.decode(buf).a, NaN))

const expected = {...toEncode}
delete toEncode.a
const actual = instance.decode(buf)
delete buf.a

t.deepEqual(actual, expected)

t.end()
})

Expand Down
48 changes: 43 additions & 5 deletions test/NaN.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,50 @@
var test = require('tape').test
var msgpack = require('../')

test('encode NaN', function (t) {
var encoder = msgpack()
test('encode NaN as 32-bit float', function (t) {
const encoder = msgpack()

t.throws(function () {
encoder.encode(NaN)
}, Error, 'must throw Error')
const buf = encoder.encode(NaN)
t.equal(buf[0], 0xca)
t.equal(buf.byteLength, 5)

t.end()
})

test('encode NaN as 64-bit float with forceFloat64', function (t) {
const encoder = msgpack({forceFloat64: true})

const buf = encoder.encode(NaN)

t.equal(buf[0], 0xcb)
t.equal(buf.byteLength, 9)

t.end()
})

test('round-trip 32-bit NaN', function (t) {
const encoder = msgpack()

t.assert(Object.is(encoder.decode(encoder.encode(NaN)), NaN))

t.end()
})

test('round-trip 64-bit NaN with forceFloat64', function (t) {
const encoder = msgpack({forceFloat64: true})

t.assert(Object.is(encoder.decode(encoder.encode(NaN)), NaN))

t.end()
})

test('decode 64-bit NaN', function (t) {
const encoder = msgpack()
const buf = Buffer.alloc(9)
buf.writeUInt8(0xcb, 0)
buf.writeDoubleBE(NaN, 1)

t.assert(Object.is(encoder.decode(buf), NaN))

t.end()
})

0 comments on commit e2788d0

Please sign in to comment.