diff --git a/src/string.js b/src/string.js index c2066d7..3e90ade 100644 --- a/src/string.js +++ b/src/string.js @@ -2,6 +2,7 @@ import { Int } from "./int"; import { UnsignedInt } from "./unsigned-int"; import {calculatePadding, slicePadding} from "./util"; import isString from "lodash/isString"; +import isArray from "lodash/isArray"; import includeIoMixin from './io-mixin'; export class String { @@ -21,7 +22,11 @@ export class String { let padding = calculatePadding(length); let result = io.slice(length); slicePadding(io, padding); - return result.buffer().toString('utf8'); + return result.buffer(); + } + + readString(io) { + return this.read(io).toString('utf8'); } write(value, io) { @@ -31,20 +36,26 @@ export class String { `max allows is ${this._maxLength}`); } - if(!isString(value)) { - throw new Error(`XDR Write Error: ${value} is not a string,`); + let buffer; + if (isString(value)) { + buffer = Buffer.from(value, 'utf8'); + } else { + buffer = Buffer.from(value); } - let buffer = Buffer.from(value, 'utf8'); Int.write(buffer.length, io); io.writeBufferPadded(buffer); } isValid(value) { - if (!isString(value)) { + let buffer; + if (isString(value)) { + buffer = Buffer.from(value, 'utf8'); + } else if (isArray(value) || Buffer.isBuffer(value)) { + buffer = Buffer.from(value); + } else { return false; } - let buffer = Buffer.from(value, 'utf8'); return buffer.length <= this._maxLength; } } diff --git a/test/unit/string_test.js b/test/unit/string_test.js index dc50f93..2f23c2d 100644 --- a/test/unit/string_test.js +++ b/test/unit/string_test.js @@ -6,12 +6,24 @@ let subject = new XDR.String(4); describe('String#read', function() { it('decodes correctly', function() { - expect(read([0x00,0x00,0x00,0x00])).to.eql(""); - expect(read([0x00,0x00,0x00,0x01,0x41,0x00,0x00,0x00])).to.eql("A"); - expect(read([0x00,0x00,0x00,0x03,0xe4,0xb8,0x89,0x00])).to.eql("三"); - expect(read([0x00,0x00,0x00,0x02,0x41,0x41,0x00,0x00])).to.eql("AA"); + expect(read([0x00,0x00,0x00,0x00]).toString('utf8')).to.eql(""); + expect(read([0x00,0x00,0x00,0x01,0x41,0x00,0x00,0x00]).toString('utf8')).to.eql("A"); + expect(read([0x00,0x00,0x00,0x03,0xe4,0xb8,0x89,0x00]).toString('utf8')).to.eql("三"); + expect(read([0x00,0x00,0x00,0x02,0x41,0x41,0x00,0x00]).toString('utf8')).to.eql("AA"); }); + it('decodes correctly to string', function() { + expect(readString([0x00,0x00,0x00,0x00])).to.eql(""); + expect(readString([0x00,0x00,0x00,0x01,0x41,0x00,0x00,0x00])).to.eql("A"); + expect(readString([0x00,0x00,0x00,0x03,0xe4,0xb8,0x89,0x00])).to.eql("三"); + expect(readString([0x00,0x00,0x00,0x02,0x41,0x41,0x00,0x00])).to.eql("AA"); + }); + + it('decodes non-utf-8 correctly', function() { + let val = read([0x00,0x00,0x00,0x01,0xd1,0x00,0x00,0x00]) + expect(val[0]).to.eql(0xd1); + }) + it("throws a read error when the encoded length is greater than the allowed max", function() { expect(() => read([0x00,0x00,0x00,0x05,0x41,0x41,0x41,0x41,0x41])).to.throw(/read error/i); }); @@ -26,17 +38,30 @@ describe('String#read', function() { let io = new Cursor(bytes); return subject.read(io); } + + function readString(bytes) { + let io = new Cursor(bytes); + return subject.readString(io); + } }); describe('String#write', function() { - it('encodes correctly', function() { + it('encodes string correctly', function() { expect(write("")).to.eql([0x00,0x00,0x00,0x00]); expect(write("三")).to.eql([0x00,0x00,0x00,0x03,0xe4,0xb8,0x89,0x00]); expect(write("A")).to.eql([0x00,0x00,0x00,0x01,0x41,0x00,0x00,0x00]); expect(write("AA")).to.eql([0x00,0x00,0x00,0x02,0x41,0x41,0x00,0x00]); }); + it('encodes non-utf-8 correctly', function() { + expect(write([0xd1])).to.eql([0x00,0x00,0x00,0x01,0xd1,0x00,0x00,0x00]); + }); + + it('encodes non-utf-8 correctly (buffer)', function() { + expect(write(Buffer.from([0xd1]))).to.eql([0x00,0x00,0x00,0x01,0xd1,0x00,0x00,0x00]); + }); + function write(value) { let io = new Cursor(8); subject.write(value, io); @@ -51,15 +76,30 @@ describe('String#isValid', function() { expect(subject.isValid("aa")).to.be.true; }); + it('returns true for arrays of the correct length', function() { + expect(subject.isValid([0x01])).to.be.true; + }); + + it('returns true for buffers of the correct length', function() { + expect(subject.isValid(Buffer.from([0x01]))).to.be.true; + }); + it('returns false for strings that are too large', function() { expect(subject.isValid("aaaaa")).to.be.false; }); - it('returns false for non string', function() { + it('returns false for arrays that are too large', function() { + expect(subject.isValid([0x01, 0x01, 0x01, 0x01, 0x01])).to.be.false; + }); + + it('returns false for buffers that are too large', function() { + expect(subject.isValid(Buffer.from([0x01, 0x01, 0x01, 0x01, 0x01]))).to.be.false; + }); + + it('returns false for non string/array/buffer', function() { expect(subject.isValid(true)).to.be.false; expect(subject.isValid(null)).to.be.false; expect(subject.isValid(3)).to.be.false; - expect(subject.isValid([0])).to.be.false; }); });