diff options
author | Idan Horowitz <idan.horowitz@gmail.com> | 2021-06-12 05:37:09 +0300 |
---|---|---|
committer | Linus Groh <mail@linusgroh.de> | 2021-06-12 10:44:28 +0100 |
commit | 77c2db41835294d60d01396865f0c9c81e7378c3 (patch) | |
tree | dd095964c7b992bf7bbc91cf56e58b0eb55725da /Userland/Libraries | |
parent | 39554f3787eae7e52094cab16a966e62f00dea22 (diff) | |
download | serenity-77c2db41835294d60d01396865f0c9c81e7378c3.zip |
LibJS: Add all of the WeakMap.prototype methods (delete, get, has, set)
Diffstat (limited to 'Userland/Libraries')
8 files changed, 169 insertions, 0 deletions
diff --git a/Userland/Libraries/LibJS/Runtime/WeakMapPrototype.cpp b/Userland/Libraries/LibJS/Runtime/WeakMapPrototype.cpp index 892b1c14b6..6b63c47115 100644 --- a/Userland/Libraries/LibJS/Runtime/WeakMapPrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/WeakMapPrototype.cpp @@ -18,6 +18,12 @@ void WeakMapPrototype::initialize(GlobalObject& global_object) { auto& vm = this->vm(); Object::initialize(global_object); + u8 attr = Attribute::Writable | Attribute::Configurable; + + define_native_function(vm.names.delete_, delete_, 1, attr); + define_native_function(vm.names.get, get, 1, attr); + define_native_function(vm.names.has, has, 1, attr); + define_native_function(vm.names.set, set, 2, attr); define_property(vm.well_known_symbol_to_string_tag(), js_string(global_object.heap(), vm.names.WeakMap), Attribute::Configurable); } @@ -38,4 +44,56 @@ WeakMap* WeakMapPrototype::typed_this(VM& vm, GlobalObject& global_object) return static_cast<WeakMap*>(this_object); } +JS_DEFINE_NATIVE_FUNCTION(WeakMapPrototype::delete_) +{ + auto* weak_map = typed_this(vm, global_object); + if (!weak_map) + return {}; + auto value = vm.argument(0); + if (!value.is_object()) + return Value(false); + return Value(weak_map->values().remove(&value.as_object())); +} + +JS_DEFINE_NATIVE_FUNCTION(WeakMapPrototype::get) +{ + auto* weak_map = typed_this(vm, global_object); + if (!weak_map) + return {}; + auto value = vm.argument(0); + if (!value.is_object()) + return js_undefined(); + auto& values = weak_map->values(); + auto result = values.find(&value.as_object()); + if (result == values.end()) + return js_undefined(); + return result->value; +} + +JS_DEFINE_NATIVE_FUNCTION(WeakMapPrototype::has) +{ + auto* weak_map = typed_this(vm, global_object); + if (!weak_map) + return {}; + auto value = vm.argument(0); + if (!value.is_object()) + return Value(false); + auto& values = weak_map->values(); + return Value(values.find(&value.as_object()) != values.end()); +} + +JS_DEFINE_NATIVE_FUNCTION(WeakMapPrototype::set) +{ + auto* weak_map = typed_this(vm, global_object); + if (!weak_map) + return {}; + auto value = vm.argument(0); + if (!value.is_object()) { + vm.throw_exception<TypeError>(global_object, ErrorType::NotAnObject, value.to_string_without_side_effects()); + return {}; + } + weak_map->values().set(&value.as_object(), vm.argument(1)); + return weak_map; +} + } diff --git a/Userland/Libraries/LibJS/Runtime/WeakMapPrototype.h b/Userland/Libraries/LibJS/Runtime/WeakMapPrototype.h index 267ddeb689..f662f62eb2 100644 --- a/Userland/Libraries/LibJS/Runtime/WeakMapPrototype.h +++ b/Userland/Libraries/LibJS/Runtime/WeakMapPrototype.h @@ -20,6 +20,11 @@ public: private: static WeakMap* typed_this(VM&, GlobalObject&); + + JS_DECLARE_NATIVE_FUNCTION(delete_); + JS_DECLARE_NATIVE_FUNCTION(get); + JS_DECLARE_NATIVE_FUNCTION(has); + JS_DECLARE_NATIVE_FUNCTION(set); }; } diff --git a/Userland/Libraries/LibJS/Tests/builtins/WeakMap/WeakMap.js b/Userland/Libraries/LibJS/Tests/builtins/WeakMap/WeakMap.js new file mode 100644 index 0000000000..9dcbe59fb9 --- /dev/null +++ b/Userland/Libraries/LibJS/Tests/builtins/WeakMap/WeakMap.js @@ -0,0 +1,34 @@ +test("constructor properties", () => { + expect(WeakMap).toHaveLength(0); + expect(WeakMap.name).toBe("WeakMap"); +}); + +describe("errors", () => { + test("invalid array iterators", () => { + [-100, Infinity, NaN, {}, 152n].forEach(value => { + expect(() => { + new WeakMap(value); + }).toThrowWithMessage(TypeError, "is not iterable"); + }); + }); + test("called without new", () => { + expect(() => { + WeakMap(); + }).toThrowWithMessage(TypeError, "WeakMap constructor must be called with 'new'"); + }); +}); + +describe("normal behavior", () => { + test("typeof", () => { + expect(typeof new WeakMap()).toBe("object"); + }); + + test("constructor with single array of entries argument", () => { + var a = new WeakMap([ + [{ a: 1 }, 1], + [{ a: 2 }, 2], + [{ a: 3 }, 3], + ]); + expect(a instanceof WeakMap).toBeTrue(); + }); +}); diff --git a/Userland/Libraries/LibJS/Tests/builtins/WeakMap/WeakMap.prototype.delete.js b/Userland/Libraries/LibJS/Tests/builtins/WeakMap/WeakMap.prototype.delete.js new file mode 100644 index 0000000000..dd12bd8b1a --- /dev/null +++ b/Userland/Libraries/LibJS/Tests/builtins/WeakMap/WeakMap.prototype.delete.js @@ -0,0 +1,13 @@ +test("basic functionality", () => { + expect(WeakMap.prototype.delete).toHaveLength(1); + + var original = [ + [{ a: 1 }, 1], + [{ a: 2 }, 2], + [{ a: 3 }, 3], + ]; + const weakMap = new WeakMap(original); + expect(weakMap.delete(original[0][0])).toBeTrue(); + expect(weakMap.delete(original[0][0])).toBeFalse(); + expect(weakMap.delete(null)).toBeFalse(); +}); diff --git a/Userland/Libraries/LibJS/Tests/builtins/WeakMap/WeakMap.prototype.get.js b/Userland/Libraries/LibJS/Tests/builtins/WeakMap/WeakMap.prototype.get.js new file mode 100644 index 0000000000..09cd06c970 --- /dev/null +++ b/Userland/Libraries/LibJS/Tests/builtins/WeakMap/WeakMap.prototype.get.js @@ -0,0 +1,12 @@ +test("basic functionality", () => { + expect(WeakMap.prototype.get).toHaveLength(1); + + var original = [ + [{ a: 1 }, 1], + [{ a: 2 }, 2], + [{ a: 3 }, 3], + ]; + const weakMap = new WeakMap(original); + expect(weakMap.get(original[0][0])).toBe(original[0][1]); + expect(weakMap.get(null)).toBe(undefined); +}); diff --git a/Userland/Libraries/LibJS/Tests/builtins/WeakMap/WeakMap.prototype.has.js b/Userland/Libraries/LibJS/Tests/builtins/WeakMap/WeakMap.prototype.has.js new file mode 100644 index 0000000000..b0d67baa54 --- /dev/null +++ b/Userland/Libraries/LibJS/Tests/builtins/WeakMap/WeakMap.prototype.has.js @@ -0,0 +1,16 @@ +test("length is 1", () => { + expect(WeakMap.prototype.has).toHaveLength(1); +}); + +test("basic functionality", () => { + var original = [ + [{ a: 1 }, 1], + [{ a: 2 }, 2], + [{ a: 3 }, 3], + ]; + var weakMap = new WeakMap(original); + + expect(new WeakMap().has()).toBeFalse(); + expect(weakMap.has(original[0][0])).toBeTrue(); + expect(weakMap.has({ a: 1 })).toBeFalse(); +}); diff --git a/Userland/Libraries/LibJS/Tests/builtins/WeakMap/WeakMap.prototype.set.js b/Userland/Libraries/LibJS/Tests/builtins/WeakMap/WeakMap.prototype.set.js new file mode 100644 index 0000000000..f7e422da8e --- /dev/null +++ b/Userland/Libraries/LibJS/Tests/builtins/WeakMap/WeakMap.prototype.set.js @@ -0,0 +1,30 @@ +test("basic functionality", () => { + expect(WeakMap.prototype.set).toHaveLength(2); + + const weakMap = new WeakMap([ + [{ a: 1 }, 1], + [{ a: 2 }, 2], + [{ a: 3 }, 3], + ]); + expect(weakMap.set({ a: 4 }, 4)).toBe(weakMap); + expect(weakMap.set({ a: 1 }, 2)).toBe(weakMap); +}); + +test("invalid values", () => { + const weakMap = new WeakMap(); + [-100, Infinity, NaN, "hello", 152n].forEach(value => { + expect(() => { + weakMap.set(value, value); + }).toThrowWithMessage(TypeError, "is not an object"); + }); +}); + +test("automatic removal of garbage-collected values", () => { + const weakMap = new WeakMap(); + { + expect(weakMap.set({ a: 1 }, 1)).toBe(weakMap); + expect(getWeakMapSize(weakMap)).toBe(1); + } + gc(); + expect(getWeakMapSize(weakMap)).toBe(0); +}); diff --git a/Userland/Libraries/LibTest/JavaScriptTestRunner.h b/Userland/Libraries/LibTest/JavaScriptTestRunner.h index 57ce930e3b..a810cee517 100644 --- a/Userland/Libraries/LibTest/JavaScriptTestRunner.h +++ b/Userland/Libraries/LibTest/JavaScriptTestRunner.h @@ -27,6 +27,7 @@ #include <LibJS/Runtime/GlobalObject.h> #include <LibJS/Runtime/JSONObject.h> #include <LibJS/Runtime/TypedArray.h> +#include <LibJS/Runtime/WeakMap.h> #include <LibJS/Runtime/WeakSet.h> #include <LibTest/Results.h> #include <fcntl.h> |