diff options
Diffstat (limited to 'src/bun.js')
-rw-r--r-- | src/bun.js/bindings/bindings.cpp | 25 | ||||
-rw-r--r-- | src/bun.js/bindings/bindings.zig | 10 | ||||
-rw-r--r-- | src/bun.js/bindings/headers-cpp.h | 2 | ||||
-rw-r--r-- | src/bun.js/bindings/headers.h | 4 | ||||
-rw-r--r-- | src/bun.js/bindings/headers.zig | 2 | ||||
-rw-r--r-- | src/bun.js/test/jest.zig | 77 |
6 files changed, 112 insertions, 8 deletions
diff --git a/src/bun.js/bindings/bindings.cpp b/src/bun.js/bindings/bindings.cpp index f273bca46..3b0137c28 100644 --- a/src/bun.js/bindings/bindings.cpp +++ b/src/bun.js/bindings/bindings.cpp @@ -2845,6 +2845,31 @@ JSC__JSString* JSC__JSValue__toStringOrNull(JSC__JSValue JSValue0, JSC__JSGlobal return value.toStringOrNull(arg1); } +bool JSC__JSValue__toMatch(JSC__JSValue regexValue, JSC__JSGlobalObject* global, JSC__JSValue value) { + JSC::JSValue regex = JSC::JSValue::decode(regexValue); + JSC::JSValue str = JSC::JSValue::decode(value); + if (regex.asCell()->type() != RegExpObjectType || !str.isString()) { + return false; + } + JSC::RegExpObject* regexObject = jsDynamicCast<JSC::RegExpObject*>(regex); + + return !!regexObject->match(global, JSC::asString(str)); +} + +bool JSC__JSValue__stringIncludes(JSC__JSValue value, JSC__JSGlobalObject* globalObject, JSC__JSValue other) +{ + VM& vm = globalObject->vm(); + auto scope = DECLARE_CATCH_SCOPE(vm); + + WTF::String stringToSearchIn = JSC::JSValue::decode(value).toWTFString(globalObject); + RETURN_IF_EXCEPTION(scope, false); + + WTF::String searchString = JSC::JSValue::decode(other).toWTFString(globalObject); + RETURN_IF_EXCEPTION(scope, false); + + return stringToSearchIn.find(searchString, 0) != WTF::notFound; +} + static void populateStackFrameMetadata(JSC::VM& vm, const JSC::StackFrame* stackFrame, ZigStackFrame* frame) { frame->source_url = Zig::toZigString(stackFrame->sourceURL(vm)); diff --git a/src/bun.js/bindings/bindings.zig b/src/bun.js/bindings/bindings.zig index 3059ba09f..1ac1fc5ca 100644 --- a/src/bun.js/bindings/bindings.zig +++ b/src/bun.js/bindings/bindings.zig @@ -3651,6 +3651,10 @@ pub const JSValue = enum(JSValueReprInt) { return cppFn("toZigString", .{ this, out, global }); } + pub fn toMatch(this: JSValue, global: *JSGlobalObject, other: JSValue) bool { + return cppFn("toMatch", .{ this, global, other }); + } + pub fn asArrayBuffer_(this: JSValue, global: *JSGlobalObject, out: *ArrayBuffer) bool { return cppFn("asArrayBuffer_", .{ this, global, out }); } @@ -3983,6 +3987,10 @@ pub const JSValue = enum(JSValueReprInt) { }); } + pub fn stringIncludes(this: JSValue, globalObject: *JSGlobalObject, other: JSValue) bool { + return cppFn("stringIncludes", .{ this, globalObject, other }); + } + pub inline fn asRef(this: JSValue) C_API.JSValueRef { return @intToPtr(C_API.JSValueRef, @bitCast(usize, @enumToInt(this))); } @@ -4121,8 +4129,10 @@ pub const JSValue = enum(JSValueReprInt) { "toWTFString", "toZigException", "toZigString", + "toMatch", "isConstructor", "isInstanceOf", + "stringIncludes", }; }; diff --git a/src/bun.js/bindings/headers-cpp.h b/src/bun.js/bindings/headers-cpp.h index 243ae3706..49391bb42 100644 --- a/src/bun.js/bindings/headers-cpp.h +++ b/src/bun.js/bindings/headers-cpp.h @@ -1,4 +1,4 @@ -//-- AUTOGENERATED FILE -- 1678855956 +//-- AUTOGENERATED FILE -- 1679048516 // clang-format off #pragma once diff --git a/src/bun.js/bindings/headers.h b/src/bun.js/bindings/headers.h index 35050c4e8..e631721f7 100644 --- a/src/bun.js/bindings/headers.h +++ b/src/bun.js/bindings/headers.h @@ -1,5 +1,5 @@ // clang-format off -//-- AUTOGENERATED FILE -- 1678855956 +//-- AUTOGENERATED FILE -- 1679048516 #pragma once #include <stddef.h> @@ -353,6 +353,7 @@ CPP_DECL void JSC__JSValue__put(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1 CPP_DECL void JSC__JSValue__putIndex(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1, uint32_t arg2, JSC__JSValue JSValue3); CPP_DECL void JSC__JSValue__putRecord(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1, ZigString* arg2, ZigString* arg3, size_t arg4); CPP_DECL bool JSC__JSValue__strictDeepEquals(JSC__JSValue JSValue0, JSC__JSValue JSValue1, JSC__JSGlobalObject* arg2); +CPP_DECL bool JSC__JSValue__stringIncludes(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1, JSC__JSValue JSValue2); CPP_DECL JSC__JSValue JSC__JSValue__symbolFor(JSC__JSGlobalObject* arg0, ZigString* arg1); CPP_DECL bool JSC__JSValue__symbolKeyFor(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1, ZigString* arg2); CPP_DECL bool JSC__JSValue__toBoolean(JSC__JSValue JSValue0); @@ -360,6 +361,7 @@ CPP_DECL bool JSC__JSValue__toBooleanSlow(JSC__JSValue JSValue0, JSC__JSGlobalOb CPP_DECL JSC__JSValue JSC__JSValue__toError_(JSC__JSValue JSValue0); CPP_DECL int32_t JSC__JSValue__toInt32(JSC__JSValue JSValue0); CPP_DECL int64_t JSC__JSValue__toInt64(JSC__JSValue JSValue0); +CPP_DECL bool JSC__JSValue__toMatch(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1, JSC__JSValue JSValue2); CPP_DECL JSC__JSObject* JSC__JSValue__toObject(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1); CPP_DECL JSC__JSString* JSC__JSValue__toString(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1); CPP_DECL JSC__JSString* JSC__JSValue__toStringOrNull(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1); diff --git a/src/bun.js/bindings/headers.zig b/src/bun.js/bindings/headers.zig index 1e3530d22..eff9a1b81 100644 --- a/src/bun.js/bindings/headers.zig +++ b/src/bun.js/bindings/headers.zig @@ -266,6 +266,7 @@ pub extern fn JSC__JSValue__put(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobal pub extern fn JSC__JSValue__putIndex(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject, arg2: u32, JSValue3: JSC__JSValue) void; pub extern fn JSC__JSValue__putRecord(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject, arg2: [*c]ZigString, arg3: [*c]ZigString, arg4: usize) void; pub extern fn JSC__JSValue__strictDeepEquals(JSValue0: JSC__JSValue, JSValue1: JSC__JSValue, arg2: *bindings.JSGlobalObject) bool; +pub extern fn JSC__JSValue__stringIncludes(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject, JSValue2: JSC__JSValue) bool; pub extern fn JSC__JSValue__symbolFor(arg0: *bindings.JSGlobalObject, arg1: [*c]ZigString) JSC__JSValue; pub extern fn JSC__JSValue__symbolKeyFor(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject, arg2: [*c]ZigString) bool; pub extern fn JSC__JSValue__toBoolean(JSValue0: JSC__JSValue) bool; @@ -273,6 +274,7 @@ pub extern fn JSC__JSValue__toBooleanSlow(JSValue0: JSC__JSValue, arg1: *binding pub extern fn JSC__JSValue__toError_(JSValue0: JSC__JSValue) JSC__JSValue; pub extern fn JSC__JSValue__toInt32(JSValue0: JSC__JSValue) i32; pub extern fn JSC__JSValue__toInt64(JSValue0: JSC__JSValue) i64; +pub extern fn JSC__JSValue__toMatch(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject, JSValue2: JSC__JSValue) bool; pub extern fn JSC__JSValue__toObject(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject) [*c]bindings.JSObject; pub extern fn JSC__JSValue__toString(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject) [*c]bindings.JSString; pub extern fn JSC__JSValue__toStringOrNull(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject) [*c]bindings.JSString; diff --git a/src/bun.js/test/jest.zig b/src/bun.js/test/jest.zig index 33e7d8269..883a3a48d 100644 --- a/src/bun.js/test/jest.zig +++ b/src/bun.js/test/jest.zig @@ -2759,7 +2759,7 @@ pub const Expect = struct { if (not) { const expected_line = "Expected constructor: not <green>{any}<r>\n"; const received_line = "Received value: <red>{any}<r>\n"; - const fmt = comptime getSignature("toBeInstanceOf", "", true) ++ "\n\n" ++ expected_line ++ received_line; + const fmt = comptime getSignature("toBeInstanceOf", "<green>expected<r>", true) ++ "\n\n" ++ expected_line ++ received_line; if (Output.enable_ansi_colors) { globalObject.throw(Output.prettyFmt(fmt, true), .{ expected_fmt, value_fmt }); return .zero; @@ -2771,13 +2771,79 @@ pub const Expect = struct { const expected_line = "Expected constructor: <green>{any}<r>\n"; const received_line = "Received value: <red>{any}<r>\n"; - const fmt = comptime getSignature("toBeInstanceOf", "", false) ++ "\n\n" ++ expected_line ++ received_line; - if (Output.enable_ansi_colors) { - globalObject.throw(Output.prettyFmt(fmt, true), .{ expected_fmt, value_fmt }); + const fmt = comptime getSignature("toBeInstanceOf", "<green>expected<r>", false) ++ "\n\n" ++ expected_line ++ received_line; + globalObject.throwPretty(fmt, .{ expected_fmt, value_fmt }); + return .zero; + } + + pub fn toMatch(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("toMatch() requires 1 argument", .{}); return .zero; } - globalObject.throw(Output.prettyFmt(fmt, false), .{ expected_fmt, value_fmt }); + if (this.scope.tests.items.len <= this.test_id) { + globalObject.throw("toMatch() must be called in a test", .{}); + return .zero; + } + + active_test_expectation_counter.actual += 1; + + var formatter = JSC.ZigConsoleClient.Formatter{ .globalThis = globalObject, .quote_strings = true }; + + const expected_value = arguments[0]; + if (!expected_value.isString() and !expected_value.isRegExp()) { + globalObject.throw("Expected value must be a string or regular expression: {any}", .{expected_value.toFmt(globalObject, &formatter)}); + return .zero; + } + expected_value.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.isString()) { + globalObject.throw("Received value must be a string: {any}", .{value.toFmt(globalObject, &formatter)}); + return .zero; + } + + const not = this.op.contains(.not); + var pass: bool = brk: { + if (expected_value.isString()) { + break :brk value.stringIncludes(globalObject, expected_value); + } else if (expected_value.isRegExp()) { + break :brk expected_value.toMatch(globalObject, value); + } + unreachable; + }; + + if (not) pass = !pass; + if (pass) return thisValue; + + // handle failure + const expected_fmt = expected_value.toFmt(globalObject, &formatter); + const value_fmt = value.toFmt(globalObject, &formatter); + + if (not) { + const expected_line = "Expected substring or pattern: not <green>{any}<r>\n"; + const received_line = "Received: <red>{any}<r>\n"; + const fmt = comptime getSignature("toMatch", "<green>expected<r>", true) ++ "\n\n" ++ expected_line ++ received_line; + globalObject.throwPretty(fmt, .{ expected_fmt, value_fmt }); + return .zero; + } + + const expected_line = "Expected substring or pattern: <green>{any}<r>\n"; + const received_line = "Received: <red>{any}<r>\n"; + const fmt = comptime getSignature("toMatch", "<green>expected<r>", false) ++ "\n\n" ++ expected_line ++ received_line; + globalObject.throwPretty(fmt, .{ expected_fmt, value_fmt }); return .zero; } @@ -2791,7 +2857,6 @@ pub const Expect = struct { pub const toHaveNthReturnedWith = notImplementedJSCFn; pub const toBeCloseTo = notImplementedJSCFn; pub const toContainEqual = notImplementedJSCFn; - pub const toMatch = notImplementedJSCFn; pub const toMatchObject = notImplementedJSCFn; pub const toMatchInlineSnapshot = notImplementedJSCFn; pub const toThrowErrorMatchingSnapshot = notImplementedJSCFn; |