From ea60b344eb76b7fdc9569f32b09d0c378fa09cf0 Mon Sep 17 00:00:00 2001 From: Linus Groh Date: Wed, 14 Apr 2021 10:02:51 +0200 Subject: [PATCH] LibJS: Add name and message properties to NativeError prototypes Otherwise these will get their name/default message from the Error prototype, and as a result would always just say "Error" in error messages, not the specific type. Something I missed in da177c6, now with tests. :^) --- .../LibJS/Runtime/ErrorPrototype.cpp | 9 +++++++ .../Libraries/LibJS/Runtime/ErrorPrototype.h | 2 +- .../builtins/Error/Error.prototype.message.js | 26 +++++++++++++++++++ .../builtins/Error/Error.prototype.name.js | 24 +++++++++++------ 4 files changed, 52 insertions(+), 9 deletions(-) create mode 100644 Userland/Libraries/LibJS/Tests/builtins/Error/Error.prototype.message.js diff --git a/Userland/Libraries/LibJS/Runtime/ErrorPrototype.cpp b/Userland/Libraries/LibJS/Runtime/ErrorPrototype.cpp index 9b8883eac35..ae79693a2fb 100644 --- a/Userland/Libraries/LibJS/Runtime/ErrorPrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/ErrorPrototype.cpp @@ -90,6 +90,15 @@ JS_DEFINE_NATIVE_FUNCTION(ErrorPrototype::to_string) PrototypeName::PrototypeName(GlobalObject& global_object) \ : Object(*global_object.error_prototype()) \ { \ + } \ + \ + void PrototypeName::initialize(GlobalObject& global_object) \ + { \ + auto& vm = this->vm(); \ + Object::initialize(global_object); \ + u8 attr = Attribute::Writable | Attribute::Configurable; \ + define_property(vm.names.name, js_string(vm, #ClassName), attr); \ + define_property(vm.names.message, js_string(vm, ""), attr); \ } JS_ENUMERATE_ERROR_SUBCLASSES diff --git a/Userland/Libraries/LibJS/Runtime/ErrorPrototype.h b/Userland/Libraries/LibJS/Runtime/ErrorPrototype.h index 3a996f5db76..317b5373f23 100644 --- a/Userland/Libraries/LibJS/Runtime/ErrorPrototype.h +++ b/Userland/Libraries/LibJS/Runtime/ErrorPrototype.h @@ -48,7 +48,7 @@ private: \ public: \ explicit PrototypeName(GlobalObject&); \ - virtual void initialize(GlobalObject&) override { } \ + virtual void initialize(GlobalObject&) override; \ virtual ~PrototypeName() override = default; \ }; diff --git a/Userland/Libraries/LibJS/Tests/builtins/Error/Error.prototype.message.js b/Userland/Libraries/LibJS/Tests/builtins/Error/Error.prototype.message.js new file mode 100644 index 00000000000..6aceafcb474 --- /dev/null +++ b/Userland/Libraries/LibJS/Tests/builtins/Error/Error.prototype.message.js @@ -0,0 +1,26 @@ +describe("normal behavior", () => { + test("initial message value is empty string", () => { + expect(Error.prototype.message).toBe(""); + expect(EvalError.prototype.message).toBe(""); + expect(RangeError.prototype.message).toBe(""); + expect(ReferenceError.prototype.message).toBe(""); + expect(SyntaxError.prototype.message).toBe(""); + expect(TypeError.prototype.message).toBe(""); + }); + + test("Error gets message via prototype by default", () => { + const error = new Error(); + expect(error.hasOwnProperty("message")).toBeFalse(); + expect(error.message).toBe(""); + Error.prototype.message = "Well hello friends"; + expect(error.message).toBe("Well hello friends"); + }); + + test("Error gets message via object if given to constructor", () => { + const error = new Error("Custom error message"); + expect(error.hasOwnProperty("message")).toBeTrue(); + expect(error.message).toBe("Custom error message"); + Error.prototype.message = "Well hello friends"; + expect(error.message).toBe("Custom error message"); + }); +}); diff --git a/Userland/Libraries/LibJS/Tests/builtins/Error/Error.prototype.name.js b/Userland/Libraries/LibJS/Tests/builtins/Error/Error.prototype.name.js index acfcb039fb1..4de3e935a8e 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/Error/Error.prototype.name.js +++ b/Userland/Libraries/LibJS/Tests/builtins/Error/Error.prototype.name.js @@ -1,10 +1,18 @@ -test("basic functionality", () => { - expect(Error.prototype).not.toHaveProperty("length"); +describe("normal behavior", () => { + test("initial name value is type name", () => { + expect(Error.prototype.name).toBe("Error"); + expect(EvalError.prototype.name).toBe("EvalError"); + expect(RangeError.prototype.name).toBe("RangeError"); + expect(ReferenceError.prototype.name).toBe("ReferenceError"); + expect(SyntaxError.prototype.name).toBe("SyntaxError"); + expect(TypeError.prototype.name).toBe("TypeError"); + }); - var changedInstance = new Error(""); - changedInstance.name = "NewCustomError"; - expect(changedInstance.name).toBe("NewCustomError"); - - var normalInstance = new Error(""); - expect(normalInstance.name).toBe("Error"); + test("Error gets name via prototype", () => { + const error = new Error(); + expect(error.hasOwnProperty("name")).toBeFalse(); + expect(error.name).toBe("Error"); + Error.prototype.name = "Foo"; + expect(error.name).toBe("Foo"); + }); });