/* Copyright 2013 Daniel Wirtz Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ var ByteBuffer = require("../dist/bytebuffer-node.js"); var ByteBufferNode = ByteBuffer; var ByteBufferBrowser = require("../dist/bytebuffer.min.js"); var ByteBufferBrowser_DataView = require("../dist/bytebuffer-dataview.min.js"); var pkg = require("../package.json"); /** * Constructs a new Sandbox for module loaders and shim testing. * @param {Object.} properties Additional properties to set * @constructor */ var Sandbox = function(properties) { this.Int8Array = function() {}; this.Uint8Array = function() {}; this.Int16Array = function() {}; this.Uint16Array = function() {}; this.Int32Array = function() {}; this.Uint32Array = function() {}; this.Float32Array = function() {}; this.Float64Array = function() {}; this.DataView = function() {}; for (var i in properties) { this[i] = properties[i]; } this.console = { log: function(s) { console.log(s); } }; }; function makeSuite(ByteBuffer) { var type = ByteBuffer.type(), // Buffer or ArrayBuffer accessor = ByteBuffer.accessor(), Long = ByteBuffer.Long; var suite = {}; suite.init = function(test) { test.ok(require("../index.js")); if (ByteBuffer == ByteBufferNode) test.log("\n\n --- ByteBufferNB ---\n".bold.white), test.log("[optional] node-memcpy is "+(ByteBuffer.memcpy ? "present" : "not present")); else if (ByteBuffer == ByteBufferBrowser) test.log("\n\n --- ByteBufferAB ---\n".bold.white); else if (ByteBuffer == ByteBufferBrowser_DataView) test.log("\n\n --- ByteBufferAB_DataView ---\n".bold.white); test.ok(type === Buffer || type === ArrayBuffer); test.ok(typeof ByteBuffer == "function"); test.strictEqual(pkg.version, ByteBuffer.VERSION); test.done(); }; suite.base = {}; suite.base.allocate = function(test) { var bb = new ByteBuffer(); test.ok(bb.buffer instanceof type); test.equal(bb.offset, 0); test.equal(bb.limit, ByteBuffer.DEFAULT_CAPACITY); test.equal(bb.littleEndian, ByteBuffer.DEFAULT_ENDIAN); test.equal(bb.noAssert, ByteBuffer.DEFAULT_NOASSERT); if (type === Buffer) test.equal(bb.buffer.length, bb.capacity()); else test.equal(bb.buffer.byteLength, bb.capacity()); test.equal(bb.capacity(), ByteBuffer.DEFAULT_CAPACITY); bb = ByteBuffer.allocate(undefined, !ByteBuffer.DEFAULT_ENDIAN, !ByteBuffer.DEFAULT_NOASSERT); test.equal(bb.capacity(), ByteBuffer.DEFAULT_CAPACITY); test.equal(bb.littleEndian, !ByteBuffer.DEFAULT_ENDIAN); test.equal(bb.noAssert, !ByteBuffer.DEFAULT_NOASSERT); // __isByteBuffer__ test.strictEqual(bb.__isByteBuffer__, true); bb.__isByteBuffer__ = false; test.strictEqual(bb.__isByteBuffer__, true); test.equal(ByteBuffer.isByteBuffer(bb), true); // Fixed set of properties for (var i in bb) if (bb.hasOwnProperty(i) && ["offset", "markedOffset", "limit", "littleEndian", "noAssert", "buffer", "view"].indexOf(i) < 0) test.fail("Illegal enumerable property: "+i); test.done(); }; suite.base.clone = function(test) { var bb = new ByteBuffer(1, true, false); var bb2 = bb.clone(); test.strictEqual(bb.buffer, bb2.buffer); test.equal(bb.offset, bb2.offset); test.equal(bb.limit, bb2.limit); test.equal(bb.markedOffset, bb2.markedOffset); test.equal(bb.littleEndian, bb2.littleEndian); test.equal(bb.noAssert, bb2.noAssert); test.notStrictEqual(bb, bb2); test.done(); }; suite.base.assert = function(test) { var bb = new ByteBuffer(); test.strictEqual(bb.noAssert, false); test.strictEqual(bb.assert(false), bb); test.strictEqual(bb.noAssert, true); test.strictEqual(bb.assert(true), bb); test.strictEqual(bb.noAssert, false); test.done(); }; suite.wrap = {}; if (type === Buffer) { suite.wrap.Buffer = function(test) { var buf = new Buffer(1); buf[0] = 0x01; var bb = ByteBuffer.wrap(buf); test.strictEqual(bb.capacity(), 1); test.strictEqual(bb.buffer, buf); test.strictEqual(bb.toDebug(), "<01>"); test.done(); }; } suite.wrap.ArrayBuffer = function(test) { var buf = new ArrayBuffer(1); var bb = ByteBuffer.wrap(buf); test.strictEqual(bb.capacity(), 1); if (type === ArrayBuffer) test.strictEqual(bb.buffer, buf); else test.ok(bb.buffer instanceof Buffer); test.equal(bb.offset, 0); test.equal(bb.limit, 1); test.done(); }; suite.wrap.Uint8Array = function(test) { // Full view var buf = new Uint8Array(1); buf[0] = 0x01; var bb = ByteBuffer.wrap(buf); test.strictEqual(bb.capacity(), 1); if (type === ArrayBuffer) test.strictEqual(bb.buffer, buf.buffer); else test.ok(bb.buffer instanceof Buffer); test.strictEqual(bb.toDebug(), "<01>"); // Partial view (not on node, node copies) if (type === ArrayBuffer) { buf = new Uint8Array(3); buf[0] = 0x01; buf[1] = 0x02; buf[2] = 0x03; buf = new Uint8Array(buf.buffer, 1, 1); bb = ByteBuffer.wrap(buf); test.strictEqual(bb.capacity(), 3); test.strictEqual(bb.toDebug(), "01<02>03"); } test.done(); }; suite.wrap.Array = function(test) { var arr = [1,255,-1]; var bb = ByteBuffer.wrap(arr); test.strictEqual(bb.capacity(), 3); test.strictEqual(bb.toDebug(), "<01 FF FF>"); test.done(); }; suite.wrap.ByteBuffer = function(test) { var bb2 = ByteBuffer.wrap("\x12\x34\x56\x78", "binary"); bb2.offset = 1; var bb = ByteBuffer.wrap(bb2); test.strictEqual(bb2.offset, bb.offset); test.strictEqual(bb2.limit, bb.limit); test.strictEqual(bb2.capacity(), bb.capacity()); test.strictEqual(bb2.toString("debug"), bb.toString("debug")); test.done(); }; suite.wrap.string = function(test) { var bb = ByteBuffer.wrap("\u0061\u0062"); test.equal(bb.toDebug(), "<61 62>"); test.done(); }; suite.encodings = {}; suite.encodings.UTF8 = function(test) { ["aäöü߀b", ""].forEach(function(str) { var bb = ByteBuffer.wrap(str, "utf8"); // Calls ByteBuffer#fromUTF8 test.strictEqual(bb.toUTF8(), str); if (str.length > 2) { bb.offset = 1; bb.limit = bb.capacity()-1; test.strictEqual(bb.toUTF8(), str.substring(1, str.length-1)); } }); test.done(); }; suite.encodings.debug = function(test) { ["60<61 62]63", "<60 61 62 63]", "|", "|61", "<61>", "!12"].forEach(function(str) { var bb = ByteBuffer.wrap(str, "debug"); // Calls ByteBuffer#fromDebug test.equal(bb.toDebug(), str); }); test.done(); }; suite.encodings.binary = function(test) { ["\x61\x62\x63\x64", "", " "].forEach(function(str) { var bb = ByteBuffer.wrap(str, "binary"); // Calls ByteBuffer#fromBinary test.strictEqual(bb.toBinary(), str); if (str.length > 2) { bb.offset = 1; bb.limit = bb.capacity()-1; test.strictEqual(bb.toBinary(), str.substring(1, str.length-1)); } }); test.done(); }; suite.encodings.hex = function(test) { ["61626364", "61", ""].forEach(function(str) { var bb = ByteBuffer.wrap(str, "hex"); // Calls ByteBuffer#fromHex test.strictEqual(bb.toHex(), str); if (str.length > 2) { bb.offset = 1; bb.limit = bb.capacity()-1; test.strictEqual(bb.toHex(), str.substring(2, str.length-2)); } }); test.done(); }; suite.encodings.base64 = function(test) { ["", "YWI=", "YWJjZGVmZw==", "YWJjZGVmZ2g=", "YWJjZGVmZ2hp"].forEach(function(str) { var bb = ByteBuffer.wrap(str, "base64"); // Calls ByteBuffer#fromBase64 test.strictEqual(bb.toBase64(), str); if (str.length > 8) { bb.offset = 3; bb.limit = bb.offset + 3; test.strictEqual(bb.toBase64(), str.substr(4, 4)); } }); test.done(); }; suite.methods = {}; suite.methods.concat = function(test) { var bbs = [ new ArrayBuffer(1), ByteBuffer.fromDebug('00<01 02>'), ByteBuffer.fromDebug('00 01 02<03>00'), ByteBuffer.fromDebug('00|'), ByteBuffer.fromDebug('<04>'), type === Buffer ? new Buffer(0) : new ArrayBuffer(0), new Uint8Array(0), '05' ]; var bb = ByteBuffer.concat(bbs, 'hex', !ByteBuffer.DEFAULT_ENDIAN, !ByteBuffer.DEFAULT_NOASSERT); test.strictEqual(bb.littleEndian, !ByteBuffer.DEFAULT_ENDIAN); test.strictEqual(bb.noAssert, !ByteBuffer.DEFAULT_NOASSERT); test.equal(bb.toDebug(), '<00 01 02 03 04 05>'); bb = ByteBuffer.concat([]); test.strictEqual(bb.buffer, new ByteBuffer(0).buffer); // EMPTY_BUFFER test.done(); }; suite.methods.resize = function(test) { var bb = new ByteBuffer(1); bb.offset = 1; bb.resize(2); bb.fill(0, 0, 2); test.equal(bb.capacity(), 2); test.equal(bb.toDebug(), "00|00"); test.done(); }; suite.methods.ensureCapacity = function(test) { var bb = new ByteBuffer(5); test.equal(bb.capacity(), 5); bb.ensureCapacity(6); // Doubles test.equal(bb.capacity(), 10); bb.ensureCapacity(21); // Uses 21 test.equal(bb.capacity(), 21); test.done(); }; suite.methods.slice = function(test) { var bb = new ByteBuffer.wrap("\x12\x34\x56"), bb2 = bb.slice(1,2); test.strictEqual(bb.buffer, bb2.buffer); test.equal(bb.offset, 0); test.equal(bb.limit, 3); test.equal(bb2.offset, 1); test.equal(bb2.limit, 2); test.done(); }; suite.methods.flip = function(test) { var bb = ByteBuffer.wrap('\x12\x34\x56\x78'); bb.offset = 4; test.equal(bb.offset, 4); test.equal(bb.limit, 4); bb.flip(); test.equal(bb.offset, 0); test.equal(bb.limit, 4); test.done(); }; suite.methods.mark = function(test) { var bb = ByteBuffer.wrap('\x12\x34\x56\x78'); test.equal(bb.offset, 0); test.equal(bb.limit, 4); test.equal(bb.markedOffset, -1); bb.mark(); test.equal(bb.markedOffset, 0); test.done(); }; suite.methods.reset = function(test) { var bb = ByteBuffer.wrap('\x12\x34\x56\x78'); bb.reset(); test.equal(bb.offset, 0); test.equal(bb.limit, 4); bb.offset = 1; bb.mark(); test.equal(bb.markedOffset, 1); bb.reset(); test.equal(bb.offset, 1); test.equal(bb.markedOffset, -1); test.done(); }; suite.methods.copy = function(test) { var bb = ByteBuffer.wrap("\x01", !ByteBuffer.DEFAULT_ENDIAN), bb2 = bb.copy(); test.equal(bb.offset, 0); test.notStrictEqual(bb, bb2); test.notStrictEqual(bb.buffer, bb2.buffer); test.equal(bb2.offset, bb.offset); test.equal(bb2.limit, bb.limit); test.equal(bb2.markedOffset, bb.markedOffset); test.equal(bb2.littleEndian, bb.littleEndian); test.equal(bb2.noAssert, bb.noAssert); test.done(); }; suite.methods.copyTo = function(test) { var bb = ByteBuffer.wrap("\x01"), bb2 = new ByteBuffer(2).fill(0).flip(); test.equal(bb.toDebug(), "<01>"); // Modifies source and target offsets bb.copyTo(bb2 /* all offsets omitted */); test.equal(bb.toDebug(), "01|"); // Read 1 byte test.equal(bb2.toDebug(), "01<00>"); // Written 1 byte bb.reset(); test.equal(bb.toDebug(), "<01>"); // Again, but with bb2.offset=1 bb.copyTo(bb2 /* all offsets omitted */); test.equal(bb.toDebug(), "01|"); // Read 1 byte test.equal(bb2.toDebug(), "01 01|"); // Written 1 byte at 2 bb.reset(); bb2.clear().fill(0).flip(); // Modifies source offsets only bb.copyTo(bb2, 0 /* source offsets omitted */); test.equal(bb.toDebug(), "01|"); // Read 1 byte test.equal(bb2.toDebug(), "<01 00>"); // Written 1 byte (no change) // Modifies no offsets at all bb.reset(); bb2.fill(0).flip(); bb.copyTo(bb2, 1, 0, bb.capacity() /* no offsets omitted */); test.equal(bb.toDebug(), "<01>"); // Read 1 byte (no change) test.equal(bb2.toDebug(), "<00 01>"); // Written 1 byte (no change) test.done(); }; suite.methods.compact = function(test) { var bb = ByteBuffer.wrap("\x01\x02"); bb.limit = 1; bb.markedOffset = 2; var prevBuffer = bb.buffer, prevView = bb.view; bb.compact(); test.notStrictEqual(bb.buffer, prevBuffer); if (type === ArrayBuffer) { test.notStrictEqual(bb.buffer, prevView); } test.equal(bb.capacity(), 1); test.equal(bb.offset, 0); test.equal(bb.limit, 1); test.equal(bb.markedOffset, 2); // Actually out of bounds // Empty region bb.offset = 1; prevBuffer = bb.buffer; bb.compact(); test.notStrictEqual(bb.buffer, prevBuffer); test.strictEqual(bb.buffer, new ByteBuffer(0).buffer); // EMPTY_BUFFER if (type === ArrayBuffer) { test.strictEqual(bb.view, null); } test.equal(bb.capacity(), 0); test.equal(bb.offset, 0); test.equal(bb.limit, 0); test.done(); }; suite.methods.reverse = function(test) { var bb = ByteBuffer.wrap("\x12\x34\x56\x78"); bb.reverse(1, 3); test.equal(bb.toString("debug"), "<12 56 34 78>"); bb.reverse(); test.equal(bb.toString("debug"), "<78 34 56 12>"); bb.offset = 1; bb.limit = 3; bb.reverse(); test.equal(bb.toString("debug"), "78<56 34>12"); bb.reverse(0, 4).clear(); test.equal(bb.toString("debug"), "<12 34 56 78>"); test.done(); }; suite.methods.append = function(test) { var bb = ByteBuffer.wrap("\x12\x34"); var bb2 = ByteBuffer.wrap("\x56\x78"); bb.offset = 2; bb.append(bb2); // Modifies offsets of both test.equal(bb.toString("debug"), "12 34>56 78<"); test.equal(bb2.toString("debug"), "56 78|"); bb2.reset(); bb.append(bb2, 1); // Modifies offsets of bb2 only test.equal(bb.toString("debug"), "12 56>78 78<"); test.equal(bb2.toString("debug"), "56 78|"); test.done(); }; suite.methods.prepend = function(test) { var bb = ByteBuffer.wrap("\x12\x34"), bb2 = ByteBuffer.wrap("\x56\x78"); test.strictEqual(bb.prepend(bb2), bb); // Relative prepend at 0, 2 bytes (2 overflow) test.equal(bb.toDebug(), "<56 78 12 34>"); test.equal(bb2.toDebug(), "56 78|"); bb.offset = 4; bb2.offset = 1; bb.prepend(bb2, 3); // Absolute prepend at 3, 1 byte test.equal(bb.toDebug(), "56 78 78 34|"); test.equal(bb2.toDebug(), "56 78|"); bb2.offset = 0; bb.prepend(bb2); // Relative prepend at 4, 2 bytes test.equal(bb.toDebug(), "56 78<56 78>"); test.equal(bb2.toDebug(), "56 78|"); bb.offset = 3; bb2.offset = 0; test.throws(function() { bb.prepend(bb2, 6); // Absolute out of bounds }, RangeError); bb.prepend("abcde", "utf8"); // Relative prepend at 3, 5 bytes (1 overflow) test.equal(bb.toDebug(), "<61 62 63 64 65 78>"); test.done(); }; suite.methods.prependTo = function(test) { var bb = ByteBuffer.wrap("\x12\x34"), bb2 = ByteBuffer.wrap("\x56\x78"); test.strictEqual(bb2.prependTo(bb), bb2); test.equal(bb.toDebug(), "<56 78 12 34>"); test.equal(bb2.toDebug(), "56 78|"); test.done(); }; suite.methods.remaining = function(test) { var bb = ByteBuffer.wrap("\x12\x34"); test.strictEqual(bb.remaining(), 2); bb.offset = 2; test.strictEqual(bb.remaining(), 0); bb.offset = 3; test.strictEqual(bb.remaining(), -1); test.done(); }; suite.methods.skip = function(test) { var bb = ByteBuffer.wrap("\x12\x34\x56"); test.strictEqual(bb.offset, 0); bb.skip(3); test.strictEqual(bb.offset, 3); test.strictEqual(bb.noAssert, false); test.throws(function() { bb.skip(1); }); test.strictEqual(bb.offset, 3); bb.noAssert = true; test.doesNotThrow(function() { bb.skip(1); }); test.strictEqual(bb.offset, 4); test.done(); }; suite.methods.order = function(test) { test.strictEqual(ByteBuffer.LITTLE_ENDIAN, true); test.strictEqual(ByteBuffer.BIG_ENDIAN, false); var bb = new ByteBuffer(2); test.strictEqual(bb.littleEndian, false); bb.writeInt32(0x12345678); bb.flip(); test.strictEqual(bb.toHex(), "12345678"); bb.clear(); test.strictEqual(bb.LE(), bb); test.strictEqual(bb.littleEndian, true); bb.writeInt32(0x12345678); bb.flip(); test.strictEqual(bb.toHex(), "78563412"); test.strictEqual(bb.BE(), bb); test.strictEqual(bb.littleEndian, false); test.strictEqual(bb.order(ByteBuffer.LITTLE_ENDIAN), bb); test.strictEqual(bb.littleEndian, true); test.strictEqual(bb.order(ByteBuffer.BIG_ENDIAN), bb); test.strictEqual(bb.littleEndian, false); test.done(); }; var types = [ // name | alias | size | input | output | BE representation ["Int8" , "Byte" , 1 , 0xFE , -2 , "fe" ], ["Uint8" , null , 1 , -2 , 0xFE , "fe" ], ["Int16" , "Short" , 2 , 0xFFFE , -2 , "fffe" ], ["Uint16" , null , 2 , -2 , 0xFFFE , "fffe" ], ["Int32" , "Int" , 4 , 0xFFFFFFFE , -2 , "fffffffe" ], ["Uint32" , null , 4 , -2 , 0xFFFFFFFE , "fffffffe" ], ["Float32" , "Float" , 4 , 0.5 , 0.5 , "3f000000" ], ["Float64" , "Double", 8 , 0.1 , 0.1 , "3fb999999999999a" ], ["Int64" , "Long" , 8 , new Long(0xFFFFFFFE, 0xFFFFFFFF, true) , new Long(0xFFFFFFFE, 0xFFFFFFFF, false) , "fffffffffffffffe" ], ["Uint64" , null , 8 , new Long(0xFFFFFFFE, 0xFFFFFFFF, false) , new Long(0xFFFFFFFE, 0xFFFFFFFF, true) , "fffffffffffffffe" ], // name | alias | size | input | output | representation ["Varint32" , null , 5 , 0xFFFFFFFE , -2 , "feffffff0f" ], ["Varint32ZigZag", null , 1 , -1 , -1 , "01" ], ["Varint64" , null , 10 , new Long(0xFFFFFFFE, 0xFFFFFFFF, true) , new Long(0xFFFFFFFE, 0xFFFFFFFF, false) , "feffffffffffffffff01"], ["Varint64ZigZag", null , 1 , Long.fromNumber(-1) , Long.fromNumber(-1) , "01" ] ]; suite.types = {}; types.forEach(function(type) { var name = type[0], varint = name.indexOf("Varint") >= 0, alias = type[1], size = type[2], input = type[3], output = type[4], be = type[5], le = ""; for (var i=be.length; i>0; i-=2) { le += be.substr(i-2, 2); } suite.types[name.toLowerCase()] = function(test) { var bb = new ByteBuffer(size); // Relative BE (always LE for varints) test.strictEqual(bb["write"+name](input), bb); bb.flip(); var val = bb["read"+name](); if (output instanceof Long) { test.deepEqual(val, output); } else { test.strictEqual(val, output); } bb.flip(); test.strictEqual(bb.toHex(), be); if (!varint) { // Relative LE bb.LE(); bb["write"+name](input); bb.flip(); val = bb["read"+name](); if (output instanceof Long) { test.deepEqual(val, output); } else { test.strictEqual(val, output); } bb.flip(); test.strictEqual(bb.toHex(), le); } test.throws(function() { // OOB bb.offset = bb.capacity() - size + 1; bb["read"+name](input); }); test.doesNotThrow(function() { // OOB, automatic resizing * 2 bb["write"+name](input); }); test.strictEqual(bb.capacity(), size * 2); // Absolute bb.clear(); if (!varint) test.strictEqual(bb["write"+name](input, 1), bb); else test.strictEqual(bb["write"+name](input, 1), size); val = bb["read"+name](1); if (output instanceof Long) { if (!varint) test.deepEqual(val, output); else test.deepEqual(val, {value: output, length: size}); } else { if (!varint) test.strictEqual(val, output); else test.deepEqual(val, {value: output, length: size}); } // Alias if (alias) { test.strictEqual(bb["write"+name], bb["write"+alias]); test.strictEqual(bb["read"+name], bb["read"+alias]); } test.done(); }; }); suite.types.bitset = function(test) { var bb = new ByteBuffer(2), arr; function run(data) { bb.reset(); bb.writeBitSet(data); bb.reset(); test.deepEqual(bb.readBitSet(),data); }; run([]); run([true]); run([false]); run([false,true]); run([false,false,false,false,false,false,false,false]); run([true,false,true,false,true,false,true,false]); run([true,true,true,true,true,true,true,true]); run([true,false,true,false,true,false,true,false]); run([true,false,true,false,true,false,true,false,true]); bb.reset(); bb.writeBitSet([,null,"",0,42,"hello world",new Date(0),{},[]]); bb.reset(); test.deepEqual(bb.readBitSet(),[false,false,false,false,true,true,true,true,true]); test.done(); }; suite.types.calculateVarint = function(test) { test.equal(ByteBuffer.MAX_VARINT32_BYTES, 5); test.equal(ByteBuffer.MAX_VARINT64_BYTES, 10); var values = [ [0, 1], [-1, 5, 10], [1<<7, 2], [1<<14, 3], [1<<21, 4], [1<<28, 5], [0x7FFFFFFF | 0, 5], [0xFFFFFFFF, 5], [0xFFFFFFFF | 0, 5, 10] ]; for (var i=0; i 2 ? values[i][2] : values[i][1]); } var Long = ByteBuffer.Long; values = [ [Long.fromNumber(1).shiftLeft(35), 6], [Long.fromNumber(1).shiftLeft(42), 7], [Long.fromNumber(1).shiftLeft(49), 8], [Long.fromNumber(1).shiftLeft(56), 9], [Long.fromNumber(1).shiftLeft(63), 10], [Long.fromNumber(1, true).shiftLeft(63), 10] ]; for (i=0; i"); test.deepEqual(bb.readIString(0), {"string": "ab", "length": 6}); test.strictEqual(bb.readIString(), "ab"); bb.reset(); test.equal(bb.toString("debug"), "<00 00 00 02 61 62>"); test.strictEqual(bb.readIString(), "ab"); test.equal(bb.toString("debug"), "00 00 00 02 61 62|"); test.done(); }; suite.types.vstring = function(test) { var bb = new ByteBuffer(2); bb.writeVString("ab"); // resizes to 2*2=4 test.strictEqual(bb.capacity(), 4); test.strictEqual(bb.offset, 3); test.strictEqual(bb.limit, 2); bb.flip(); test.equal(bb.toString("debug").substr(0, 10), "<02 61 62>"); test.deepEqual(bb.readVString(0), {"string": "ab", "length": 3}); test.equal(bb.toString("debug").substr(0, 10), "<02 61 62>"); test.equal(bb.readVString(), "ab"); test.equal(bb.toString("debug").substr(0, 9), "02 61 62|"); test.done(); }; suite.types.cstring = function(test) { var bb = new ByteBuffer(2); bb.writeCString("a"); test.equal(bb.capacity(), 2); test.equal(bb.offset, 2); test.equal(bb.limit, 2); bb.offset = 1; bb.writeCString("b"); // resizes to 4 test.equal(bb.capacity(), 4); test.equal(bb.offset, 3); test.equal(bb.limit, 2); bb.flip(); test.equal(bb.toString("debug").substr(0, 10), "<61 62 00>"); test.deepEqual(bb.readCString(0), {"string": "ab", "length": 3}); test.equal(bb.toString("debug").substr(0, 10), "<61 62 00>"); test.equal(bb.readCString(), "ab"); test.equal(bb.toString("debug").substr(0, 9), "61 62 00|"); test.done(); }; suite.convert = {}; suite.convert.toHex = function(test) { var bb = new ByteBuffer(4); bb.writeUint16(0x1234); bb.writeUint8(0x56); bb.flip(); test.equal(bb.toHex(), "123456"); test.strictEqual(bb.offset, 0); test.equal(bb.toHex(1), "3456"); test.equal(bb.toHex(1,2), "34"); test.equal(bb.toHex(1,1), ""); test.throws(function() { bb.toHex(1,0); }); test.done(); }; suite.convert.toBase64 = function(test) { var bb = new ByteBuffer(8); bb.writeUTF8String("abcdefg"); // 7 chars bb.flip(); test.equal(bb.toBase64(), "YWJjZGVmZw=="); test.strictEqual(bb.offset, 0); test.equal(bb.toBase64(3), "ZGVmZw=="); test.equal(bb.toBase64(3,6), "ZGVm"); test.equal(bb.toBase64(3,3), ""); test.throws(function() { bb.toBase64(1,0); }); test.done(); }; suite.convert.toBinary = function(test) { var bb = new ByteBuffer(5); bb.writeUint32(0x001234FF); bb.flip(); test.strictEqual(bb.toBinary(), "\x00\x12\x34\xFF"); test.strictEqual(bb.offset, 0); test.done(); }; suite.convert.toString = function(test) { var bb = new ByteBuffer(3); bb.writeUint16(0x6162).flip(); test.equal(bb.toString("hex"), "6162"); test.equal(bb.toString("base64"), "YWI="); test.equal(bb.toString("utf8"), "ab"); test.equal(bb.toString("debug").substr(0,7), "<61 62>"); test.equal(bb.toString(), (type === ArrayBuffer ? (accessor === DataView ? "ByteBufferAB_DataView" : "ByteBufferAB") : "ByteBufferNB")+"(offset=0,markedOffset=-1,limit=2,capacity=3)"); test.strictEqual(bb.offset, 0); test.done(); }; suite.convert.toBuffer = function(test) { var bb = new ByteBuffer(2); bb.writeUint16(0x1234).flip(); var buf = bb.toBuffer(); test.strictEqual(buf, bb.buffer); if (type === ArrayBuffer) { test.ok(buf instanceof ArrayBuffer); test.strictEqual(buf.byteLength, 2); } else { test.ok(buf instanceof Buffer); test.strictEqual(buf.length, 2); } bb.limit = 1; buf = bb.toBuffer(); test.notStrictEqual(buf, bb.buffer); if (type === ArrayBuffer) { test.ok(buf instanceof ArrayBuffer); test.strictEqual(buf.byteLength, 1); } else { test.ok(buf instanceof Buffer); test.strictEqual(buf.length, 1); } test.done(); }; suite.convert.toArrayBuffer = function(test) { var bb = new ByteBuffer(3); if (type === ArrayBuffer) { test.strictEqual(bb.toArrayBuffer, bb.toBuffer); } else { test.ok(bb.buffer instanceof Buffer); bb.writeUint16(0x1234); bb.flip(); bb.offset = 1; var ab = bb.toArrayBuffer(); test.ok(ab instanceof ArrayBuffer); test.strictEqual(ab.byteLength, 1); } test.done(); }; suite.misc = {}; suite.misc.pbjsi19 = function(test) { // test that this issue is fixed: https://github.com/dcodeIO/ProtoBuf.js/issues/19 var bb = new ByteBuffer(9); // Trigger resize to 18 in writeVarint64 bb.writeVarint32(16); bb.writeVarint32(2); bb.writeVarint32(24); bb.writeVarint32(0); bb.writeVarint32(32); bb.writeVarint64(ByteBuffer.Long.fromString("1368057600000")); bb.writeVarint32(40); bb.writeVarint64(ByteBuffer.Long.fromString("1235455123")); bb.flip(); test.equal(bb.toString("debug").substr(0,52), "<10 02 18 00 20 80 B0 D9 B4 E8 27 28 93 99 8E CD 04>"); test.done(); }; suite.misc.NaN = function(test) { var bb = new ByteBuffer(4); test.ok(isNaN(bb.writeFloat(NaN).flip().readFloat(0))); test.strictEqual(bb.writeFloat(+Infinity).flip().readFloat(0), +Infinity); test.strictEqual(bb.writeFloat(-Infinity).flip().readFloat(0), -Infinity); bb.resize(8); test.ok(isNaN(bb.writeDouble(NaN).flip().readDouble(0))); test.strictEqual(bb.writeDouble(+Infinity).flip().readDouble(0), +Infinity); test.strictEqual(bb.writeDouble(-Infinity).flip().readDouble(0), -Infinity); // Varints, however, always need a cast, which results in the following: test.strictEqual(NaN >>> 0, 0); test.strictEqual(NaN | 0, 0); test.strictEqual(Infinity >>> 0, 0); test.strictEqual(Infinity | 0, 0); test.strictEqual(-Infinity >>> 0, 0); test.strictEqual(-Infinity | 0, 0); test.done(); }; suite.debug = {}; suite.debug.printDebug = function(test) { var bb = new ByteBuffer(3); function callMe() { callMe.called = true; } bb.printDebug(callMe); test.ok(callMe.called); test.done(); }; if (type === ArrayBuffer) { suite.debug.printDebugVisual = function(test) { var bb = ByteBuffer.wrap("Hello world! from byteBuffer.js. This is just a last visual test of ByteBuffer#printDebug."); console.log(""); bb.printDebug(console.log); test.done(); }; } return suite; } module.exports = { "info": function(test) { test.log("Version "+ByteBuffer.VERSION+", "+new Date().toISOString()+"\n"); test.done(); }, "node": makeSuite(ByteBufferNode), "browser": makeSuite(ByteBufferBrowser), "dataview": makeSuite(ByteBufferBrowser_DataView) };