diff options
author | Idan Horowitz <idan.horowitz@gmail.com> | 2021-06-09 00:14:08 +0300 |
---|---|---|
committer | Linus Groh <mail@linusgroh.de> | 2021-06-09 11:48:04 +0100 |
commit | 0b0f1eda059615bd8d16daa9261239463a1554ec (patch) | |
tree | 01ba201a90ba5a73b0cfe2c282cc3b5bc6c3378b /Userland/Libraries | |
parent | 670be04c816b978e6308e18e8b18a0f784bf577c (diff) | |
download | serenity-0b0f1eda059615bd8d16daa9261239463a1554ec.zip |
LibJS: Add most of the Set.prototype methods
Specifically all aside from "values" and "entries" which require an
implementation of the SetIterator object.
Diffstat (limited to 'Userland/Libraries')
9 files changed, 164 insertions, 0 deletions
diff --git a/Userland/Libraries/LibJS/Runtime/CommonPropertyNames.h b/Userland/Libraries/LibJS/Runtime/CommonPropertyNames.h index 06a3e77015..52dc0ef420 100644 --- a/Userland/Libraries/LibJS/Runtime/CommonPropertyNames.h +++ b/Userland/Libraries/LibJS/Runtime/CommonPropertyNames.h @@ -44,6 +44,7 @@ namespace JS { P(abs) \ P(acos) \ P(acosh) \ + P(add) \ P(all) \ P(allSettled) \ P(anchor) \ @@ -290,6 +291,7 @@ namespace JS { struct CommonPropertyNames { FlyString catch_ { "catch" }; + FlyString delete_ { "delete" }; FlyString for_ { "for" }; #define __ENUMERATE(x) FlyString x { #x }; ENUMERATE_STANDARD_PROPERTY_NAMES(__ENUMERATE) diff --git a/Userland/Libraries/LibJS/Runtime/SetPrototype.cpp b/Userland/Libraries/LibJS/Runtime/SetPrototype.cpp index e2cc0c7a5d..bfd842c1fe 100644 --- a/Userland/Libraries/LibJS/Runtime/SetPrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/SetPrototype.cpp @@ -20,6 +20,12 @@ void SetPrototype::initialize(GlobalObject& global_object) Set::initialize(global_object); u8 attr = Attribute::Writable | Attribute::Configurable; + define_native_function(vm.names.add, add, 1, attr); + define_native_function(vm.names.clear, clear, 0, attr); + define_native_function(vm.names.delete_, delete_, 1, attr); + define_native_function(vm.names.forEach, for_each, 1, attr); + define_native_function(vm.names.has, has, 1, attr); + define_native_property(vm.names.size, size_getter, {}, attr); define_property(vm.well_known_symbol_to_string_tag(), js_string(global_object.heap(), vm.names.Set), Attribute::Configurable); @@ -29,6 +35,62 @@ SetPrototype::~SetPrototype() { } +JS_DEFINE_NATIVE_FUNCTION(SetPrototype::add) +{ + auto* set = typed_this(vm, global_object); + if (!set) + return {}; + auto value = vm.argument(0); + if (value.is_negative_zero()) + value = Value(0); + set->values().set(value, AK::HashSetExistingEntryBehavior::Keep); + return set; +} + +JS_DEFINE_NATIVE_FUNCTION(SetPrototype::clear) +{ + auto* set = typed_this(vm, global_object); + if (!set) + return {}; + set->values().clear(); + return js_undefined(); +} + +JS_DEFINE_NATIVE_FUNCTION(SetPrototype::delete_) +{ + auto* set = typed_this(vm, global_object); + if (!set) + return {}; + return Value(set->values().remove(vm.argument(0))); +} + +JS_DEFINE_NATIVE_FUNCTION(SetPrototype::for_each) +{ + auto* set = typed_this(vm, global_object); + if (!set) + return {}; + if (!vm.argument(0).is_function()) { + vm.throw_exception<TypeError>(global_object, ErrorType::NotAFunction, vm.argument(0).to_string_without_side_effects()); + return {}; + } + auto this_value = vm.this_value(global_object); + for (auto& value : set->values()) { + (void)vm.call(vm.argument(0).as_function(), vm.argument(1), value, value, this_value); + if (vm.exception()) + return {}; + } + return js_undefined(); +} + +JS_DEFINE_NATIVE_FUNCTION(SetPrototype::has) +{ + auto* set = typed_this(vm, global_object); + if (!set) + return {}; + auto& values = set->values(); + return Value(values.find(vm.argument(0)) != values.end()); +} + JS_DEFINE_NATIVE_GETTER(SetPrototype::size_getter) { auto* set = typed_this(vm, global_object); diff --git a/Userland/Libraries/LibJS/Runtime/SetPrototype.h b/Userland/Libraries/LibJS/Runtime/SetPrototype.h index 55e7e88035..a7908c2317 100644 --- a/Userland/Libraries/LibJS/Runtime/SetPrototype.h +++ b/Userland/Libraries/LibJS/Runtime/SetPrototype.h @@ -19,6 +19,12 @@ public: virtual ~SetPrototype() override; private: + JS_DECLARE_NATIVE_FUNCTION(add); + JS_DECLARE_NATIVE_FUNCTION(clear); + JS_DECLARE_NATIVE_FUNCTION(delete_); + JS_DECLARE_NATIVE_FUNCTION(for_each); + JS_DECLARE_NATIVE_FUNCTION(has); + JS_DECLARE_NATIVE_GETTER(size_getter); }; diff --git a/Userland/Libraries/LibJS/Tests/builtins/Set/Set.js b/Userland/Libraries/LibJS/Tests/builtins/Set/Set.js index 2216354feb..034f1bfe17 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/Set/Set.js +++ b/Userland/Libraries/LibJS/Tests/builtins/Set/Set.js @@ -27,5 +27,10 @@ describe("normal behavior", () => { var a = new Set([0, 1, 2]); expect(a instanceof Set).toBeTrue(); expect(a).toHaveSize(3); + var seen = [false, false, false]; + a.forEach(x => { + seen[x] = true; + }); + expect(seen[0] && seen[1] && seen[2]); }); }); diff --git a/Userland/Libraries/LibJS/Tests/builtins/Set/Set.prototype.add.js b/Userland/Libraries/LibJS/Tests/builtins/Set/Set.prototype.add.js new file mode 100644 index 0000000000..e4dbb3dc72 --- /dev/null +++ b/Userland/Libraries/LibJS/Tests/builtins/Set/Set.prototype.add.js @@ -0,0 +1,10 @@ +test("basic functionality", () => { + expect(Set.prototype.add).toHaveLength(1); + + const set = new Set(["a", "b", "c"]); + expect(set).toHaveSize(3); + expect(set.add("d")).toBe(set); + expect(set).toHaveSize(4); + expect(set.add("a")).toBe(set); + expect(set).toHaveSize(4); +}); diff --git a/Userland/Libraries/LibJS/Tests/builtins/Set/Set.prototype.clear.js b/Userland/Libraries/LibJS/Tests/builtins/Set/Set.prototype.clear.js new file mode 100644 index 0000000000..956acc50fc --- /dev/null +++ b/Userland/Libraries/LibJS/Tests/builtins/Set/Set.prototype.clear.js @@ -0,0 +1,8 @@ +test("basic functionality", () => { + expect(Set.prototype.clear).toHaveLength(0); + + const set = new Set(["a", "b", "c"]); + expect(set).toHaveSize(3); + set.clear(); + expect(set).toHaveSize(0); +}); diff --git a/Userland/Libraries/LibJS/Tests/builtins/Set/Set.prototype.delete.js b/Userland/Libraries/LibJS/Tests/builtins/Set/Set.prototype.delete.js new file mode 100644 index 0000000000..d1775c9d73 --- /dev/null +++ b/Userland/Libraries/LibJS/Tests/builtins/Set/Set.prototype.delete.js @@ -0,0 +1,10 @@ +test("basic functionality", () => { + expect(Set.prototype.delete).toHaveLength(1); + + const set = new Set(["a", "b", "c"]); + expect(set).toHaveSize(3); + expect(set.delete("b")).toBeTrue(); + expect(set).toHaveSize(2); + expect(set.delete("b")).toBeFalse(); + expect(set).toHaveSize(2); +}); diff --git a/Userland/Libraries/LibJS/Tests/builtins/Set/Set.prototype.forEach.js b/Userland/Libraries/LibJS/Tests/builtins/Set/Set.prototype.forEach.js new file mode 100644 index 0000000000..ab677dcd2a --- /dev/null +++ b/Userland/Libraries/LibJS/Tests/builtins/Set/Set.prototype.forEach.js @@ -0,0 +1,48 @@ +test("length is 1", () => { + expect(Set.prototype.forEach).toHaveLength(1); +}); + +describe("errors", () => { + test("requires at least one argument", () => { + expect(() => { + new Set().forEach(); + }).toThrowWithMessage(TypeError, "undefined is not a function"); + }); + + test("callback must be a function", () => { + expect(() => { + new Set().forEach(undefined); + }).toThrowWithMessage(TypeError, "undefined is not a function"); + }); +}); + +describe("normal behavior", () => { + test("never calls callback with empty set", () => { + var callbackCalled = 0; + expect( + new Set().forEach(() => { + callbackCalled++; + }) + ).toBeUndefined(); + expect(callbackCalled).toBe(0); + }); + + test("calls callback once for every item", () => { + var callbackCalled = 0; + expect( + new Set([1, 2, 3]).forEach(() => { + callbackCalled++; + }) + ).toBeUndefined(); + expect(callbackCalled).toBe(3); + }); + + test("callback receives value twice and set", () => { + var a = new Set([1, 2, 3]); + a.forEach((value1, value2, set) => { + expect(a.has(value1)).toBeTrue(); + expect(value1).toBe(value2); + expect(set).toBe(a); + }); + }); +}); diff --git a/Userland/Libraries/LibJS/Tests/builtins/Set/Set.prototype.has.js b/Userland/Libraries/LibJS/Tests/builtins/Set/Set.prototype.has.js new file mode 100644 index 0000000000..3a797d025d --- /dev/null +++ b/Userland/Libraries/LibJS/Tests/builtins/Set/Set.prototype.has.js @@ -0,0 +1,13 @@ +test("length is 1", () => { + expect(Set.prototype.has).toHaveLength(1); +}); + +test("basic functionality", () => { + var set = new Set(["hello", "friends", 1, 2, false]); + + expect(new Set().has()).toBeFalse(); + expect(new Set([undefined]).has()).toBeTrue(); + expect(set.has("hello")).toBeTrue(); + expect(set.has(1)).toBeTrue(); + expect(set.has("serenity")).toBeFalse(); +}); |