From 6c53475143691196b52134b2a57b8f3151102523 Mon Sep 17 00:00:00 2001 From: Timothy Flynn Date: Wed, 7 Jul 2021 13:05:47 -0400 Subject: [PATCH] LibJS: Implement RegExp.prototype.test with RegExpExec abstraction --- .../LibJS/Runtime/RegExpPrototype.cpp | 24 ++----------- .../builtins/RegExp/RegExp.prototype.test.js | 35 +++++++++++++++++++ 2 files changed, 38 insertions(+), 21 deletions(-) diff --git a/Userland/Libraries/LibJS/Runtime/RegExpPrototype.cpp b/Userland/Libraries/LibJS/Runtime/RegExpPrototype.cpp index eb72cabdb5..b728e85ec6 100644 --- a/Userland/Libraries/LibJS/Runtime/RegExpPrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/RegExpPrototype.cpp @@ -260,9 +260,7 @@ JS_DEFINE_NATIVE_FUNCTION(RegExpPrototype::exec) // 22.2.5.15 RegExp.prototype.test ( S ), https://tc39.es/ecma262/#sec-regexp.prototype.test JS_DEFINE_NATIVE_FUNCTION(RegExpPrototype::test) { - // FIXME: This should try using dynamic properties for 'exec' first, - // before falling back to builtin_exec. - auto regexp_object = regexp_object_from(vm, global_object); + auto* regexp_object = regexp_object_from(vm, global_object); if (!regexp_object) return {}; @@ -270,27 +268,11 @@ JS_DEFINE_NATIVE_FUNCTION(RegExpPrototype::test) if (vm.exception()) return {}; - // RegExps without "global" and "sticky" always start at offset 0. - if (!regexp_object->regex().options().has_flag_set((ECMAScriptFlags)regex::AllFlags::Internal_Stateful)) { - regexp_object->set(vm.names.lastIndex, Value(0), true); - if (vm.exception()) - return {}; - } - - auto last_index = regexp_object->get(vm.names.lastIndex); - if (vm.exception()) - return {}; - regexp_object->regex().start_offset = last_index.to_length(global_object); + auto match = regexp_exec(global_object, *regexp_object, str); if (vm.exception()) return {}; - auto result = do_match(regexp_object->regex(), str); - - regexp_object->set(vm.names.lastIndex, Value(regexp_object->regex().start_offset), true); - if (vm.exception()) - return {}; - - return Value(result.success); + return Value(!match.is_null()); } // 22.2.5.16 RegExp.prototype.toString ( ), https://tc39.es/ecma262/#sec-regexp.prototype.tostring diff --git a/Userland/Libraries/LibJS/Tests/builtins/RegExp/RegExp.prototype.test.js b/Userland/Libraries/LibJS/Tests/builtins/RegExp/RegExp.prototype.test.js index 561716a7c7..2c5bbcf853 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/RegExp/RegExp.prototype.test.js +++ b/Userland/Libraries/LibJS/Tests/builtins/RegExp/RegExp.prototype.test.js @@ -56,3 +56,38 @@ test("flag and options", () => { Function("/foo/x"); }).toThrowWithMessage(SyntaxError, "Invalid RegExp flag 'x'"); }); + +test("override exec with function", () => { + let calls = 0; + + let re = /test/; + let oldExec = re.exec.bind(re); + re.exec = function (...args) { + ++calls; + return oldExec(...args); + }; + + expect(re.test("test")).toBe(true); + expect(calls).toBe(1); +}); + +test("override exec with bad function", () => { + let calls = 0; + + let re = /test/; + re.exec = function (...args) { + ++calls; + return 4; + }; + + expect(() => { + re.test("test"); + }).toThrow(TypeError); + expect(calls).toBe(1); +}); + +test("override exec with non-function", () => { + let re = /test/; + re.exec = 3; + expect(re.test("test")).toBe(true); +});