buffer: clean up copy() asserts and tests
Argument checks were simplified by setting all undefined/NaN or out of bounds values equal to their defaults. Also copy() tests had a flaw that each buffer had the same bit pattern at the same offset. So even if the copy failed, the bit-by-bit comparison would have still been true. This was fixed by filling each buffer with a unique value before copy operations.
This commit is contained in:
parent
16bbeccd40
commit
49175e6ae2
@ -239,6 +239,9 @@ Does copy between buffers. The source and target regions can be overlapped.
|
||||
`targetStart` and `sourceStart` default to `0`.
|
||||
`sourceEnd` defaults to `buffer.length`.
|
||||
|
||||
All values passed that are `undefined`/`NaN` or are out of bounds are set equal
|
||||
to their respective defaults.
|
||||
|
||||
Example: build two Buffers, then copy `buf1` from byte 16 through byte 19
|
||||
into `buf2`, starting at the 8th byte in `buf2`.
|
||||
|
||||
|
@ -541,37 +541,26 @@ Buffer.concat = function(list, length) {
|
||||
|
||||
// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length)
|
||||
Buffer.prototype.copy = function(target, target_start, start, end) {
|
||||
var source = this;
|
||||
start || (start = 0);
|
||||
end || (end = this.length);
|
||||
target_start || (target_start = 0);
|
||||
|
||||
if (end < start) throw new Error('sourceEnd < sourceStart');
|
||||
// set undefined/NaN or out of bounds values equal to their default
|
||||
if (!(target_start >= 0)) target_start = 0;
|
||||
if (!(start >= 0)) start = 0;
|
||||
if (!(end < this.length)) end = this.length;
|
||||
|
||||
// Copy 0 bytes; we're done
|
||||
if (end === start) return 0;
|
||||
if (target.length == 0 || source.length == 0) return 0;
|
||||
if (end === start ||
|
||||
target.length === 0 ||
|
||||
this.length === 0 ||
|
||||
start > this.length)
|
||||
return 0;
|
||||
|
||||
if (target_start < 0 || target_start >= target.length) {
|
||||
throw new Error('targetStart out of bounds');
|
||||
}
|
||||
if (end < start)
|
||||
throw new RangeError('sourceEnd < sourceStart');
|
||||
|
||||
if (start < 0 || start >= source.length) {
|
||||
throw new Error('sourceStart out of bounds');
|
||||
}
|
||||
if (target_start >= target.length)
|
||||
throw new RangeError('targetStart out of bounds');
|
||||
|
||||
if (end < 0 || end > source.length) {
|
||||
throw new Error('sourceEnd out of bounds');
|
||||
}
|
||||
|
||||
// Are we oob?
|
||||
if (end > this.length) {
|
||||
end = this.length;
|
||||
}
|
||||
|
||||
if (target.length - target_start < end - start) {
|
||||
if (target.length - target_start < end - start)
|
||||
end = target.length - target_start + start;
|
||||
}
|
||||
|
||||
return this.parent.copy(target.parent || target,
|
||||
target_start + (target.offset || 0),
|
||||
|
@ -25,6 +25,9 @@ var assert = require('assert');
|
||||
var SlowBuffer = require('buffer').SlowBuffer;
|
||||
var Buffer = require('buffer').Buffer;
|
||||
|
||||
// counter to ensure unique value is always copied
|
||||
var cntr = 0;
|
||||
|
||||
// Regression test for segfault introduced in commit e501ce4.
|
||||
['base64','binary','ucs2','utf8','ascii'].forEach(function(encoding) {
|
||||
var buf = new SlowBuffer(0);
|
||||
@ -33,18 +36,18 @@ var Buffer = require('buffer').Buffer;
|
||||
|
||||
var b = Buffer(1024); // safe constructor
|
||||
|
||||
console.log('b.length == ' + b.length);
|
||||
console.log('b.length == %d', b.length);
|
||||
assert.strictEqual(1024, b.length);
|
||||
|
||||
b[0] = -1;
|
||||
assert.equal(b[0], 255);
|
||||
assert.strictEqual(b[0], 255);
|
||||
|
||||
for (var i = 0; i < 1024; i++) {
|
||||
b[i] = i % 256;
|
||||
}
|
||||
|
||||
for (var i = 0; i < 1024; i++) {
|
||||
assert.equal(i % 256, b[i]);
|
||||
assert.strictEqual(i % 256, b[i]);
|
||||
}
|
||||
|
||||
var c = new Buffer(512);
|
||||
@ -52,93 +55,134 @@ console.log('c.length == %d', c.length);
|
||||
assert.strictEqual(512, c.length);
|
||||
|
||||
// copy 512 bytes, from 0 to 512.
|
||||
b.fill(++cntr);
|
||||
c.fill(++cntr);
|
||||
var copied = b.copy(c, 0, 0, 512);
|
||||
console.log('copied ' + copied + ' bytes from b into c');
|
||||
assert.equal(512, copied);
|
||||
for (var i = 0; i < c.length; i++) {
|
||||
common.print('.');
|
||||
assert.equal(i % 256, c[i]);
|
||||
}
|
||||
console.log('');
|
||||
|
||||
// try to copy 513 bytes, and hope we don't overrun c, which is only 512 long
|
||||
var copied = b.copy(c, 0, 0, 513);
|
||||
console.log('copied ' + copied + ' bytes from b into c');
|
||||
console.log('copied %d bytes from b into c', copied);
|
||||
assert.strictEqual(512, copied);
|
||||
for (var i = 0; i < c.length; i++) {
|
||||
assert.equal(i % 256, c[i]);
|
||||
assert.strictEqual(b[i], c[i]);
|
||||
}
|
||||
|
||||
// copy all of c back into b, without specifying sourceEnd
|
||||
// copy c into b, without specifying sourceEnd
|
||||
b.fill(++cntr);
|
||||
c.fill(++cntr);
|
||||
var copied = c.copy(b, 0, 0);
|
||||
console.log('copied ' + copied + ' bytes from c back into b');
|
||||
assert.strictEqual(512, copied);
|
||||
for (var i = 0; i < b.length; i++) {
|
||||
assert.equal(i % 256, b[i]);
|
||||
console.log('copied %d bytes from c into b w/o sourceEnd', copied);
|
||||
assert.strictEqual(c.length, copied);
|
||||
for (var i = 0; i < c.length; i++) {
|
||||
assert.strictEqual(c[i], b[i]);
|
||||
}
|
||||
|
||||
// copy c into b, without specifying sourceStart
|
||||
b.fill(++cntr);
|
||||
c.fill(++cntr);
|
||||
var copied = c.copy(b, 0);
|
||||
console.log('copied %d bytes from c into b w/o sourceStart', copied);
|
||||
assert.strictEqual(c.length, copied);
|
||||
for (var i = 0; i < c.length; i++) {
|
||||
assert.strictEqual(c[i], b[i]);
|
||||
}
|
||||
|
||||
// copy longer buffer b to shorter c without targetStart
|
||||
b.fill(++cntr);
|
||||
c.fill(++cntr);
|
||||
var copied = b.copy(c);
|
||||
console.log('copied %d bytes from b into c w/o targetStart', copied);
|
||||
assert.strictEqual(c.length, copied);
|
||||
for (var i = 0; i < c.length; i++) {
|
||||
assert.strictEqual(b[i], c[i]);
|
||||
}
|
||||
|
||||
// copy starting near end of b to c
|
||||
b.fill(++cntr);
|
||||
c.fill(++cntr);
|
||||
var copied = b.copy(c, 0, b.length - Math.floor(c.length / 2));
|
||||
console.log('copied %d bytes from end of b into beginning of c', copied);
|
||||
assert.strictEqual(Math.floor(c.length / 2), copied);
|
||||
for (var i = 0; i < Math.floor(c.length / 2); i++) {
|
||||
assert.strictEqual(b[b.length - Math.floor(c.length / 2) + i], c[i]);
|
||||
}
|
||||
for (var i = Math.floor(c.length /2) + 1; i < c.length; i++) {
|
||||
assert.strictEqual(c[c.length-1], c[i]);
|
||||
}
|
||||
|
||||
// try to copy 513 bytes, and check we don't overrun c
|
||||
b.fill(++cntr);
|
||||
c.fill(++cntr);
|
||||
var copied = b.copy(c, 0, 0, 513);
|
||||
console.log('copied %d bytes from b trying to overrun c', copied);
|
||||
assert.strictEqual(c.length, copied);
|
||||
for (var i = 0; i < c.length; i++) {
|
||||
assert.strictEqual(b[i], c[i]);
|
||||
}
|
||||
|
||||
// copy 768 bytes from b into b
|
||||
b.fill(++cntr);
|
||||
b.fill(++cntr, 256);
|
||||
var copied = b.copy(b, 0, 256, 1024);
|
||||
console.log('copied ' + copied + ' bytes from b into c');
|
||||
console.log('copied %d bytes from b into b', copied);
|
||||
assert.strictEqual(768, copied);
|
||||
for (var i = 0; i < b.length; i++) {
|
||||
assert.strictEqual(cntr, b[i]);
|
||||
}
|
||||
|
||||
// copy from b to c with negative targetStart
|
||||
b.fill(++cntr);
|
||||
c.fill(++cntr);
|
||||
var copied = b.copy(c, -1);
|
||||
console.log('copied %d bytes from b into c w/ negative targetStart', copied);
|
||||
assert.strictEqual(c.length, copied);
|
||||
for (var i = 0; i < c.length; i++) {
|
||||
assert.equal(i % 256, c[i]);
|
||||
assert.strictEqual(b[i], c[i]);
|
||||
}
|
||||
|
||||
// copy from fast to slow buffer
|
||||
// copy from b to c with negative sourceStart
|
||||
b.fill(++cntr);
|
||||
c.fill(++cntr);
|
||||
var copied = b.copy(c, 0, -1);
|
||||
assert.strictEqual(c.length, copied);
|
||||
console.log('copied %d bytes from b into c w/ negative sourceStart', copied);
|
||||
for (var i = 0; i < c.length; i++) {
|
||||
assert.strictEqual(b[i], c[i]);
|
||||
}
|
||||
|
||||
// check sourceEnd resets to targetEnd if former is greater than the latter
|
||||
b.fill(++cntr);
|
||||
c.fill(++cntr);
|
||||
var copied = b.copy(c, 0, 0, 1025);
|
||||
console.log('copied %d bytes from b into c', copied);
|
||||
for (var i = 0; i < c.length; i++) {
|
||||
assert.strictEqual(b[i], c[i]);
|
||||
}
|
||||
|
||||
// copy from fast buffer to slow buffer without parameters
|
||||
var sb = new SlowBuffer(b.length);
|
||||
sb.fill(++cntr, 0, sb.length);
|
||||
b.fill(++cntr);
|
||||
var copied = b.copy(sb);
|
||||
console.log('copied %d bytes from b into sb');
|
||||
for (var i = 0; i < sb.length; i++) {
|
||||
assert.strictEqual(sb[i], b[i]);
|
||||
console.log('copied %d bytes from fast buffer to slow buffer', copied);
|
||||
for (var i = 0 ; i < b.length; i++) {
|
||||
assert.strictEqual(b[i], sb[i]);
|
||||
}
|
||||
|
||||
var caught_error = null;
|
||||
// throw with negative sourceEnd
|
||||
console.log('test copy at negative sourceEnd');
|
||||
assert.throws(function() {
|
||||
b.copy(c, 0, 0, -1);
|
||||
}, RangeError);
|
||||
|
||||
// try to copy from before the beginning of b
|
||||
caught_error = null;
|
||||
try {
|
||||
var copied = b.copy(c, 0, 100, 10);
|
||||
} catch (err) {
|
||||
caught_error = err;
|
||||
}
|
||||
assert.strictEqual('sourceEnd < sourceStart', caught_error.message);
|
||||
// throw when sourceStart is greater than sourceEnd
|
||||
assert.throws(function() {
|
||||
b.copy(c, 0, 100, 10);
|
||||
}, RangeError);
|
||||
|
||||
// try to copy to before the beginning of c
|
||||
caught_error = null;
|
||||
try {
|
||||
var copied = b.copy(c, -1, 0, 10);
|
||||
} catch (err) {
|
||||
caught_error = err;
|
||||
}
|
||||
assert.strictEqual('targetStart out of bounds', caught_error.message);
|
||||
// throw attempting to copy after end of c
|
||||
assert.throws(function() {
|
||||
b.copy(c, 512, 0, 10);
|
||||
}, RangeError);
|
||||
|
||||
// try to copy to after the end of c
|
||||
caught_error = null;
|
||||
try {
|
||||
var copied = b.copy(c, 512, 0, 10);
|
||||
} catch (err) {
|
||||
caught_error = err;
|
||||
}
|
||||
assert.strictEqual('targetStart out of bounds', caught_error.message);
|
||||
|
||||
// try to copy starting before the beginning of b
|
||||
caught_error = null;
|
||||
try {
|
||||
var copied = b.copy(c, 0, -1, 1);
|
||||
} catch (err) {
|
||||
caught_error = err;
|
||||
}
|
||||
assert.strictEqual('sourceStart out of bounds', caught_error.message);
|
||||
|
||||
// try to copy starting after the end of b
|
||||
caught_error = null;
|
||||
try {
|
||||
var copied = b.copy(c, 0, 1024, 1025);
|
||||
} catch (err) {
|
||||
caught_error = err;
|
||||
}
|
||||
assert.strictEqual('sourceStart out of bounds', caught_error.message);
|
||||
var caught_error;
|
||||
|
||||
// invalid encoding for Buffer.toString
|
||||
caught_error = null;
|
||||
@ -158,16 +202,6 @@ try {
|
||||
}
|
||||
assert.strictEqual('Unknown encoding: invalid', caught_error.message);
|
||||
|
||||
// a too-low sourceEnd will get caught by earlier checks
|
||||
|
||||
// try to copy ending after the end of b
|
||||
try {
|
||||
var copied = b.copy(c, 0, 1023, 1025);
|
||||
} catch (err) {
|
||||
caught_error = err;
|
||||
}
|
||||
assert.strictEqual('sourceEnd out of bounds', caught_error.message);
|
||||
|
||||
// try to create 0-length buffers
|
||||
new Buffer('');
|
||||
new Buffer('', 'ascii');
|
||||
|
Loading…
x
Reference in New Issue
Block a user