-
-
Notifications
You must be signed in to change notification settings - Fork 234
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix issues surrounding type checking for Uint8Arrays and Buffers #346
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,179 @@ | ||
'use strict' | ||
|
||
const Buffer = require('../').Buffer | ||
const test = require('tape') | ||
const vm = require('vm') | ||
|
||
// Get a Uint8Array and Buffer constructor from another context. | ||
const code = ` | ||
'use strict' | ||
function Buffer (...args) { | ||
const buf = new Uint8Array(...args) | ||
Object.setPrototypeOf(buf, Buffer.prototype) | ||
return buf | ||
} | ||
Object.setPrototypeOf(Buffer.prototype, Uint8Array.prototype) | ||
Object.setPrototypeOf(Buffer, Uint8Array) | ||
Buffer.prototype._isBuffer = true | ||
exports.Uint8Array = Uint8Array | ||
exports.Buffer = Buffer | ||
` | ||
|
||
const context = {} | ||
|
||
// Should work in browserify. | ||
vm.runInNewContext(code, { exports: context }) | ||
|
||
const arrays = [context.Uint8Array, context.Buffer] | ||
|
||
// Extracted from the index.js code for testing purposes. | ||
function isInstance (obj, type) { | ||
return (obj instanceof type) || | ||
(obj != null && | ||
obj.constructor != null && | ||
obj.constructor.name != null && | ||
obj.constructor.name === type.name) || | ||
(type === Uint8Array && Buffer.isBuffer(obj)) | ||
} | ||
dcousens marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
test('Uint8Arrays and Buffers from other contexts', (t) => { | ||
// Our buffer is considered a view. | ||
t.ok(ArrayBuffer.isView(Buffer.alloc(0))) | ||
|
||
for (const ForeignArray of arrays) { | ||
const buf = new ForeignArray(1) | ||
|
||
buf[0] = 1 | ||
|
||
// Prove that ArrayBuffer.isView and isInstance | ||
// return true for objects from other contexts. | ||
t.ok(!(buf instanceof Object)) | ||
t.ok(!(buf instanceof Uint8Array)) | ||
t.ok(!(buf instanceof Buffer)) | ||
t.ok(ArrayBuffer.isView(buf)) | ||
|
||
// Now returns true even for Buffers from other contexts: | ||
t.ok(isInstance(buf, Uint8Array)) | ||
|
||
if (ForeignArray === context.Uint8Array) { | ||
t.ok(!Buffer.isBuffer(buf)) | ||
} else { | ||
t.ok(Buffer.isBuffer(buf)) | ||
} | ||
|
||
// They even behave the same! | ||
const copy = new Uint8Array(buf) | ||
|
||
t.ok(copy instanceof Object) | ||
t.ok(copy instanceof Uint8Array) | ||
t.ok(ArrayBuffer.isView(copy)) | ||
t.equal(copy[0], 1) | ||
} | ||
|
||
t.end() | ||
}) | ||
|
||
test('should instantiate from foreign arrays', (t) => { | ||
for (const ForeignArray of arrays) { | ||
const arr = new ForeignArray(2) | ||
|
||
arr[0] = 1 | ||
arr[1] = 2 | ||
|
||
const buf = Buffer.from(arr) | ||
|
||
t.equal(buf.toString('hex'), '0102') | ||
} | ||
|
||
t.end() | ||
}) | ||
|
||
test('should do comparisons with foreign arrays', (t) => { | ||
const a = Buffer.from([1, 2, 3]) | ||
const b = new context.Uint8Array(a) | ||
const c = new context.Buffer(a) | ||
|
||
t.equal(Buffer.byteLength(a), 3) | ||
t.equal(Buffer.byteLength(b), 3) | ||
t.equal(Buffer.byteLength(c), 3) | ||
t.equal(b[0], 1) | ||
t.equal(c[0], 1) | ||
|
||
t.ok(a.equals(b)) | ||
t.ok(a.equals(c)) | ||
t.ok(a.compare(b) === 0) | ||
t.ok(a.compare(c) === 0) | ||
t.ok(Buffer.compare(a, b) === 0) | ||
t.ok(Buffer.compare(a, c) === 0) | ||
t.ok(Buffer.compare(b, c) === 0) | ||
t.ok(Buffer.compare(c, b) === 0) | ||
|
||
a[0] = 0 | ||
|
||
t.ok(!a.equals(b)) | ||
t.ok(!a.equals(c)) | ||
t.ok(a.compare(b) < 0) | ||
t.ok(a.compare(c) < 0) | ||
t.ok(Buffer.compare(a, b) < 0) | ||
t.ok(Buffer.compare(a, c) < 0) | ||
|
||
b[0] = 0 | ||
|
||
t.ok(Buffer.compare(b, c) < 0) | ||
t.ok(Buffer.compare(c, b) > 0) | ||
|
||
t.end() | ||
}) | ||
|
||
test('should fill with foreign arrays', (t) => { | ||
for (const ForeignArray of arrays) { | ||
const buf = Buffer.alloc(4) | ||
const arr = new ForeignArray(2) | ||
|
||
arr[0] = 1 | ||
arr[1] = 2 | ||
|
||
buf.fill(arr) | ||
|
||
t.equal(buf.toString('hex'), '01020102') | ||
} | ||
|
||
t.end() | ||
}) | ||
|
||
test('should do concatenation with foreign arrays', (t) => { | ||
for (const ForeignArray of arrays) { | ||
const a = new ForeignArray(2) | ||
|
||
a[0] = 1 | ||
a[1] = 2 | ||
|
||
const b = new ForeignArray(a) | ||
|
||
{ | ||
const buf = Buffer.concat([a, b]) | ||
t.equal(buf.toString('hex'), '01020102') | ||
} | ||
|
||
{ | ||
const buf = Buffer.concat([a, b], 3) | ||
t.equal(buf.toString('hex'), '010201') | ||
} | ||
} | ||
|
||
t.end() | ||
}) | ||
|
||
test('should copy on to foreign arrays', (t) => { | ||
for (const ForeignArray of arrays) { | ||
const a = Buffer.from([1, 2]) | ||
const b = new ForeignArray(2) | ||
|
||
a.copy(b) | ||
|
||
t.equal(b[0], 1) | ||
t.equal(b[1], 2) | ||
} | ||
|
||
t.end() | ||
}) |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What isn't necessary about this now?
(citation?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because
ArrayBuffer.isView
returns true forUint8Array
subclasses likeBuffer
. So this case will actually be handled earlier, inBuffer.from
:I left the
Buffer.isBuffer(obj)
check in there because I was concerned that maybe non-v8 javascript engines'ArrayBuffer.isView
does not returntrue
forUint8Array
subclasses (from the same context or another).Because
ArrayByffer.isView
is so magic in v8, I actually wanted to test it in FF and Safari to make sure they had the same behavior, but I didn't get around to it, so leaving the check in is just me being cautious.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should add comments like ^ into your code 💙
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, it's something I need to work on.