From 61a8c195566f1f68a250e5132a37f4600909eccb Mon Sep 17 00:00:00 2001 From: Luke Date: Fri, 18 Jun 2021 03:57:53 +0100 Subject: [PATCH] LibJS: Add %TypedArray%.prototype.find --- .../LibJS/Runtime/TypedArrayPrototype.cpp | 15 +++ .../LibJS/Runtime/TypedArrayPrototype.h | 1 + .../TypedArray/TypedArray.prototype.find.js | 108 ++++++++++++++++++ 3 files changed, 124 insertions(+) create mode 100644 Userland/Libraries/LibJS/Tests/builtins/TypedArray/TypedArray.prototype.find.js diff --git a/Userland/Libraries/LibJS/Runtime/TypedArrayPrototype.cpp b/Userland/Libraries/LibJS/Runtime/TypedArrayPrototype.cpp index 598339b1ec..123b79447b 100644 --- a/Userland/Libraries/LibJS/Runtime/TypedArrayPrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/TypedArrayPrototype.cpp @@ -27,6 +27,7 @@ void TypedArrayPrototype::initialize(GlobalObject& object) define_native_accessor(vm.names.byteOffset, byte_offset_getter, nullptr, Attribute::Configurable); define_native_function(vm.names.at, at, 1, attr); define_native_function(vm.names.every, every, 1, attr); + define_native_function(vm.names.find, find, 1, attr); } TypedArrayPrototype::~TypedArrayPrototype() @@ -139,6 +140,20 @@ JS_DEFINE_NATIVE_FUNCTION(TypedArrayPrototype::every) return Value(result); } +// 23.2.3.10 %TypedArray%.prototype.find ( predicate [ , thisArg ] ), https://tc39.es/ecma262/#sec-%typedarray%.prototype.find +JS_DEFINE_NATIVE_FUNCTION(TypedArrayPrototype::find) +{ + auto result = js_undefined(); + for_each_item(vm, global_object, "find", [&](auto, auto value, auto callback_result) { + if (callback_result.to_boolean()) { + result = value; + return IterationDecision::Break; + } + return IterationDecision::Continue; + }); + return result; +} + // 23.2.3.1 get %TypedArray%.prototype.buffer, https://tc39.es/ecma262/#sec-get-%typedarray%.prototype.buffer JS_DEFINE_NATIVE_GETTER(TypedArrayPrototype::buffer_getter) { diff --git a/Userland/Libraries/LibJS/Runtime/TypedArrayPrototype.h b/Userland/Libraries/LibJS/Runtime/TypedArrayPrototype.h index f0e225077f..be4c44d8b8 100644 --- a/Userland/Libraries/LibJS/Runtime/TypedArrayPrototype.h +++ b/Userland/Libraries/LibJS/Runtime/TypedArrayPrototype.h @@ -26,6 +26,7 @@ private: JS_DECLARE_NATIVE_FUNCTION(at); JS_DECLARE_NATIVE_FUNCTION(every); + JS_DECLARE_NATIVE_FUNCTION(find); }; } diff --git a/Userland/Libraries/LibJS/Tests/builtins/TypedArray/TypedArray.prototype.find.js b/Userland/Libraries/LibJS/Tests/builtins/TypedArray/TypedArray.prototype.find.js new file mode 100644 index 0000000000..5eb85af952 --- /dev/null +++ b/Userland/Libraries/LibJS/Tests/builtins/TypedArray/TypedArray.prototype.find.js @@ -0,0 +1,108 @@ +const TYPED_ARRAYS = [ + Uint8Array, + Uint16Array, + Uint32Array, + Int8Array, + Int16Array, + Int32Array, + Float32Array, + Float64Array, +]; + +const BIGINT_TYPED_ARRAYS = [BigUint64Array, BigInt64Array]; + +test("length is 1", () => { + TYPED_ARRAYS.forEach(T => { + expect(T.prototype.find).toHaveLength(1); + }); + + BIGINT_TYPED_ARRAYS.forEach(T => { + expect(T.prototype.find).toHaveLength(1); + }); +}); + +describe("errors", () => { + function errorTests(T) { + test(`requires at least one argument (${T.name})`, () => { + expect(() => { + new T().find(); + }).toThrowWithMessage( + TypeError, + "TypedArray.prototype.find() requires at least one argument" + ); + }); + + test(`callback must be a function (${T.name})`, () => { + expect(() => { + new T().find(undefined); + }).toThrowWithMessage(TypeError, "undefined is not a function"); + }); + } + + TYPED_ARRAYS.forEach(T => errorTests(T)); + BIGINT_TYPED_ARRAYS.forEach(T => errorTests(T)); +}); + +describe("normal behaviour", () => { + test("basic functionality", () => { + TYPED_ARRAYS.forEach(T => { + const typedArray = new T([1, 2, 3]); + + expect(typedArray.find(value => value === 1)).toBe(1); + expect(typedArray.find(value => value === 2)).toBe(2); + expect(typedArray.find(value => value === 3)).toBe(3); + expect(typedArray.find((value, index) => index === 1)).toBe(2); + expect(typedArray.find(value => value == "1")).toBe(1); + expect(typedArray.find(value => value === 10)).toBeUndefined(); + }); + + BIGINT_TYPED_ARRAYS.forEach(T => { + const typedArray = new T([1n, 2n, 3n]); + + expect(typedArray.find(value => value === 1n)).toBe(1n); + expect(typedArray.find(value => value === 2n)).toBe(2n); + expect(typedArray.find(value => value === 3n)).toBe(3n); + expect(typedArray.find((value, index) => index === 1)).toBe(2n); + expect(typedArray.find(value => value == 1)).toBe(1n); + expect(typedArray.find(value => value == "1")).toBe(1n); + expect(typedArray.find(value => value === 1)).toBeUndefined(); + }); + }); + + test("never calls callback with empty array", () => { + function emptyTest(T) { + var callbackCalled = 0; + expect( + new T().find(() => { + callbackCalled++; + }) + ).toBeUndefined(); + expect(callbackCalled).toBe(0); + } + + TYPED_ARRAYS.forEach(T => emptyTest(T)); + BIGINT_TYPED_ARRAYS.forEach(T => emptyTest(T)); + }); + + test("calls callback once for every item", () => { + TYPED_ARRAYS.forEach(T => { + var callbackCalled = 0; + expect( + new T([1, 2, 3]).find(() => { + callbackCalled++; + }) + ).toBeUndefined(); + expect(callbackCalled).toBe(3); + }); + + BIGINT_TYPED_ARRAYS.forEach(T => { + var callbackCalled = 0; + expect( + new T([1n, 2n, 3n]).find(() => { + callbackCalled++; + }) + ).toBeUndefined(); + expect(callbackCalled).toBe(3); + }); + }); +});