aboutsummaryrefslogtreecommitdiff
path: root/src/bun.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/bun.js')
-rw-r--r--src/bun.js/bindings/JSBufferList.cpp58
-rw-r--r--src/bun.js/test/jest.zig82
2 files changed, 106 insertions, 34 deletions
diff --git a/src/bun.js/bindings/JSBufferList.cpp b/src/bun.js/bindings/JSBufferList.cpp
index e16c8cf88..e54b433e5 100644
--- a/src/bun.js/bindings/JSBufferList.cpp
+++ b/src/bun.js/bindings/JSBufferList.cpp
@@ -2,7 +2,6 @@
#include "JSBuffer.h"
#include "JavaScriptCore/Lookup.h"
#include "JavaScriptCore/ObjectConstructor.h"
-#include "JavaScriptCore/JSGenericTypedArrayViewInlines.h"
#include "ZigGlobalObject.h"
#include "JSDOMOperation.h"
#include "headers.h"
@@ -48,6 +47,9 @@ JSC::JSValue JSBufferList::concat(JSC::VM& vm, JSC::JSGlobalObject* lexicalGloba
if (UNLIKELY(!array)) {
return throwTypeError(lexicalGlobalObject, throwScope, "concat can only be called when all buffers are Uint8Array"_s);
}
+ if (UNLIKELY(array->byteLength() > n)) {
+ return throwRangeError(lexicalGlobalObject, throwScope, "specified size too small to fit all buffers"_s);
+ }
RELEASE_AND_RETURN(throwScope, array);
}
// Buffer.allocUnsafe(n >>> 0)
@@ -106,10 +108,10 @@ JSC::JSValue JSBufferList::consume(JSC::VM& vm, JSC::JSGlobalObject* lexicalGlob
return _getBuffer(vm, lexicalGlobalObject, n);
}
-JSC::JSValue JSBufferList::_getString(JSC::VM& vm, JSC::JSGlobalObject* lexicalGlobalObject, int32_t n)
+JSC::JSValue JSBufferList::_getString(JSC::VM& vm, JSC::JSGlobalObject* lexicalGlobalObject, int32_t total)
{
auto throwScope = DECLARE_THROW_SCOPE(vm);
- if (n == 0 || length() == 0) {
+ if (total <= 0 || length() == 0) {
RELEASE_AND_RETURN(throwScope, JSC::jsEmptyString(vm));
}
@@ -118,7 +120,8 @@ JSC::JSValue JSBufferList::_getString(JSC::VM& vm, JSC::JSGlobalObject* lexicalG
if (UNLIKELY(!str)) {
return throwTypeError(lexicalGlobalObject, throwScope, "_getString can only be called when all buffers are string"_s);
}
- size_t len = str->length();
+ const size_t len = str->length();
+ size_t n = total;
if (n == len) {
m_deque.removeFirst();
@@ -131,32 +134,33 @@ JSC::JSValue JSBufferList::_getString(JSC::VM& vm, JSC::JSGlobalObject* lexicalG
}
JSRopeString::RopeBuilder<RecordOverflow> ropeBuilder(vm);
- for (const auto end = m_deque.end(); iter != end && n > 0; ++iter) {
+ for (const auto end = m_deque.end(); iter != end; ++iter) {
JSC::JSString* str = JSC::jsDynamicCast<JSC::JSString*>(iter->get());
if (UNLIKELY(!str)) {
return throwTypeError(lexicalGlobalObject, throwScope, "_getString can only be called when all buffers are string"_s);
}
- size_t len = str->length();
+ const size_t len = str->length();
if (n < len) {
JSString* firstHalf = JSC::jsSubstring(lexicalGlobalObject, str, 0, n);
if (!ropeBuilder.append(firstHalf))
return throwOutOfMemoryError(lexicalGlobalObject, throwScope);
iter->set(vm, this, JSC::jsSubstring(lexicalGlobalObject, str, n, len - n));
- } else {
- if (!ropeBuilder.append(str))
- return throwOutOfMemoryError(lexicalGlobalObject, throwScope);
- m_deque.removeFirst();
+ break;
}
- n -= static_cast<int32_t>(len);
+ if (!ropeBuilder.append(str))
+ return throwOutOfMemoryError(lexicalGlobalObject, throwScope);
+ m_deque.removeFirst();
+ if (n == len) break;
+ n -= len;
}
RELEASE_AND_RETURN(throwScope, ropeBuilder.release());
}
-JSC::JSValue JSBufferList::_getBuffer(JSC::VM& vm, JSC::JSGlobalObject* lexicalGlobalObject, int32_t n)
+JSC::JSValue JSBufferList::_getBuffer(JSC::VM& vm, JSC::JSGlobalObject* lexicalGlobalObject, int32_t total)
{
auto throwScope = DECLARE_THROW_SCOPE(vm);
auto* subclassStructure = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject)->JSBufferSubclassStructure();
- if (n == 0 || length() == 0) {
+ if (total <= 0 || length() == 0) {
// Buffer.alloc(0)
RELEASE_AND_RETURN(throwScope, JSC::JSUint8Array::create(lexicalGlobalObject, subclassStructure, 0));
}
@@ -166,13 +170,15 @@ JSC::JSValue JSBufferList::_getBuffer(JSC::VM& vm, JSC::JSGlobalObject* lexicalG
if (UNLIKELY(!array)) {
return throwTypeError(lexicalGlobalObject, throwScope, "_getBuffer can only be called when all buffers are Uint8Array"_s);
}
- size_t len = array->byteLength();
+ const size_t len = array->byteLength();
+ size_t n = total;
if (n == len) {
+ m_deque.removeFirst();
RELEASE_AND_RETURN(throwScope, array);
}
if (n < len) {
- auto buffer = array->existingBuffer();
+ auto buffer = array->possiblySharedBuffer();
JSC::JSUint8Array* retArray = JSC::JSUint8Array::create(lexicalGlobalObject, subclassStructure, buffer, 0, n);
JSC::JSUint8Array* newArray = JSC::JSUint8Array::create(lexicalGlobalObject, subclassStructure, buffer, n, len - n);
iter->set(vm, this, newArray);
@@ -182,29 +188,31 @@ JSC::JSValue JSBufferList::_getBuffer(JSC::VM& vm, JSC::JSGlobalObject* lexicalG
// Buffer.allocUnsafe(n >>> 0)
auto arrayBuffer = JSC::ArrayBuffer::tryCreateUninitialized(n, 1);
if (UNLIKELY(!arrayBuffer)) {
- return throwTypeError(lexicalGlobalObject, throwScope);
+ return throwOutOfMemoryError(lexicalGlobalObject, throwScope);
}
JSC::JSUint8Array* uint8Array = JSC::JSUint8Array::create(lexicalGlobalObject, subclassStructure, WTFMove(arrayBuffer), 0, n);
size_t offset = 0;
- for (const auto end = m_deque.end(); iter != end && n > 0; ++iter) {
+ for (const auto end = m_deque.end(); iter != end; ++iter) {
JSC::JSUint8Array* array = JSC::jsDynamicCast<JSC::JSUint8Array*>(iter->get());
if (UNLIKELY(!array)) {
return throwTypeError(lexicalGlobalObject, throwScope, "_getBuffer can only be called when all buffers are Uint8Array"_s);
}
- size_t len = array->byteLength();
+ const size_t len = array->byteLength();
if (n < len) {
if (UNLIKELY(!uint8Array->setFromTypedArray(lexicalGlobalObject, offset, array, 0, n, JSC::CopyType::Unobservable))) {
return throwOutOfMemoryError(lexicalGlobalObject, throwScope);
}
- JSC::JSUint8Array* newArray = JSC::JSUint8Array::create(lexicalGlobalObject, subclassStructure, array->existingBuffer(), n, len - n);
+ auto buffer = array->possiblySharedBuffer();
+ JSC::JSUint8Array* newArray = JSC::JSUint8Array::create(lexicalGlobalObject, subclassStructure, buffer, n, len - n);
iter->set(vm, this, newArray);
- } else {
- if (UNLIKELY(!uint8Array->setFromTypedArray(lexicalGlobalObject, offset, array, 0, len, JSC::CopyType::Unobservable))) {
- return throwOutOfMemoryError(lexicalGlobalObject, throwScope);
- }
- m_deque.removeFirst();
+ break;
+ }
+ if (UNLIKELY(!uint8Array->setFromTypedArray(lexicalGlobalObject, offset, array, 0, len, JSC::CopyType::Unobservable))) {
+ return throwOutOfMemoryError(lexicalGlobalObject, throwScope);
}
- n -= static_cast<int32_t>(len);
+ m_deque.removeFirst();
+ if (n == len) break;
+ n -= len;
offset += len;
}
RELEASE_AND_RETURN(throwScope, uint8Array);
diff --git a/src/bun.js/test/jest.zig b/src/bun.js/test/jest.zig
index 24c1bd0e1..ba9234c6d 100644
--- a/src/bun.js/test/jest.zig
+++ b/src/bun.js/test/jest.zig
@@ -535,7 +535,7 @@ pub const Expect = struct {
defer this.postMatch(globalObject);
const thisValue = callFrame.this();
const value: JSValue = Expect.capturedValueGetCached(thisValue) orelse {
- globalObject.throw("Interal consistency error: the expect(value) was garbage collected but it should not have been!", .{});
+ globalObject.throw("Internal consistency error: the expect(value) was garbage collected but it should not have been!", .{});
return .zero;
};
value.ensureStillAlive();
@@ -564,7 +564,7 @@ pub const Expect = struct {
const thisValue = callFrame.this();
const value: JSValue = Expect.capturedValueGetCached(thisValue) orelse {
- globalObject.throw("Interal consistency error: the expect(value) was garbage collected but it should not have been!", .{});
+ globalObject.throw("Internal consistency error: the expect(value) was garbage collected but it should not have been!", .{});
return .zero;
};
value.ensureStillAlive();
@@ -596,7 +596,7 @@ pub const Expect = struct {
const thisValue = callFrame.this();
const value: JSValue = Expect.capturedValueGetCached(thisValue) orelse {
- globalObject.throw("Interal consistency error: the expect(value) was garbage collected but it should not have been!", .{});
+ globalObject.throw("Internal consistency error: the expect(value) was garbage collected but it should not have been!", .{});
return .zero;
};
value.ensureStillAlive();
@@ -623,7 +623,7 @@ pub const Expect = struct {
const thisValue = callFrame.this();
const value: JSValue = Expect.capturedValueGetCached(thisValue) orelse {
- globalObject.throw("Interal consistency error: the expect(value) was garbage collected but it should not have been!", .{});
+ globalObject.throw("Internal consistency error: the expect(value) was garbage collected but it should not have been!", .{});
return .zero;
};
value.ensureStillAlive();
@@ -851,7 +851,7 @@ pub const Expect = struct {
other_value.ensureStillAlive();
const value = Expect.capturedValueGetCached(thisValue) orelse {
- globalObject.throw("Internal consistency error: thie expect(value) was garbage collected but it should not have been!", .{});
+ globalObject.throw("Internal consistency error: the expect(value) was garbage collected but it should not have been!", .{});
return .zero;
};
value.ensureStillAlive();
@@ -914,7 +914,7 @@ pub const Expect = struct {
other_value.ensureStillAlive();
const value = Expect.capturedValueGetCached(thisValue) orelse {
- globalObject.throw("Internal consistency error: thie expect(value) was garbage collected but it should not have been!", .{});
+ globalObject.throw("Internal consistency error: the expect(value) was garbage collected but it should not have been!", .{});
return .zero;
};
value.ensureStillAlive();
@@ -977,7 +977,7 @@ pub const Expect = struct {
other_value.ensureStillAlive();
const value = Expect.capturedValueGetCached(thisValue) orelse {
- globalObject.throw("Internal consistency error: thie expect(value) was garbage collected but it should not have been!", .{});
+ globalObject.throw("Internal consistency error: the expect(value) was garbage collected but it should not have been!", .{});
return .zero;
};
value.ensureStillAlive();
@@ -1040,7 +1040,7 @@ pub const Expect = struct {
other_value.ensureStillAlive();
const value = Expect.capturedValueGetCached(thisValue) orelse {
- globalObject.throw("Internal consistency error: thie expect(value) was garbage collected but it should not have been!", .{});
+ globalObject.throw("Internal consistency error: the expect(value) was garbage collected but it should not have been!", .{});
return .zero;
};
value.ensureStillAlive();
@@ -1080,6 +1080,71 @@ pub const Expect = struct {
return .zero;
}
+ pub fn toThrow(this: *Expect, globalObject: *JSC.JSGlobalObject, callFrame: *JSC.CallFrame) callconv(.C) JSValue {
+ defer this.postMatch(globalObject);
+
+ const thisValue = callFrame.this();
+ const _arguments = callFrame.arguments(1);
+ const arguments: []const JSValue = _arguments.ptr[0.._arguments.len];
+
+ if (arguments.len < 1) {
+ globalObject.throwInvalidArguments("toThrow() requires 1 argument", .{});
+ return .zero;
+ }
+
+ if (this.scope.tests.items.len <= this.test_id) {
+ globalObject.throw("toThrow() must be called in a test", .{});
+ return .zero;
+ }
+
+ active_test_expectation_counter.actual += 1;
+
+ const expected = arguments[0];
+ expected.ensureStillAlive();
+
+ const value = Expect.capturedValueGetCached(thisValue) orelse {
+ globalObject.throw("Internal consistency error: the expect(value) was garbage collected but it should not have been!", .{});
+ return .zero;
+ };
+ value.ensureStillAlive();
+
+ if ((!value.jsType().isFunction())) {
+ globalObject.throw("Expected value must be a function", .{});
+ return .zero;
+ }
+
+ const not = this.op.contains(.not);
+ const result = value.call(globalObject, &.{}).toError(globalObject);
+ if (result.isUndefined()) {
+ if (not) return thisValue;
+ globalObject.throw("Expected function to throw", .{});
+ return .zero;
+ } else if(not) {
+ globalObject.throw("Expected function not to throw", .{});
+ return .zero;
+ }
+
+ if (expected.isString()) {
+ const message = result.get(globalObject, "message");
+ // TODO support partial match
+ const pass = if (message) |actual| expected.isSameValue(actual, globalObject) else false;
+
+ if (pass) return thisValue;
+ globalObject.throw("\n\tExpected: {s}\n\tReceived: {s}", .{
+ expected.getZigString(globalObject),
+ if (message) |actual| actual.getZigString(globalObject) else ZigString.init("undefined"),
+ });
+ return .zero;
+ }
+
+ if (result.isInstanceOf(globalObject, expected)) return thisValue;
+ globalObject.throw("\n\tExpected type: {s}\n\tReceived type: {s}", .{
+ expected.getName(globalObject),
+ if (result.get(globalObject, "name")) |name| name.getZigString(globalObject) else ZigString.init("<UnknownError>"),
+ });
+ return .zero;
+ }
+
pub const toHaveBeenCalledTimes = notImplementedJSCFn;
pub const toHaveBeenCalledWith = notImplementedJSCFn;
pub const toHaveBeenLastCalledWith = notImplementedJSCFn;
@@ -1095,7 +1160,6 @@ pub const Expect = struct {
pub const toMatchObject = notImplementedJSCFn;
pub const toMatchSnapshot = notImplementedJSCFn;
pub const toMatchInlineSnapshot = notImplementedJSCFn;
- pub const toThrow = notImplementedJSCFn;
pub const toThrowErrorMatchingSnapshot = notImplementedJSCFn;
pub const toThrowErrorMatchingInlineSnapshot = notImplementedJSCFn;