From 3bca6c62f7d6d90aa8db1c8e1cacc5035e8fad0c Mon Sep 17 00:00:00 2001 From: Guy Bedford Date: Tue, 14 May 2024 15:32:34 -0700 Subject: [PATCH 1/2] fix: performance builtin and tests --- builtins/web/fetch/fetch_event.cpp | 3 + builtins/web/performance.cpp | 8 +- tests/integration/handlers.js | 1 + tests/integration/performance/performance.js | 283 ++++++++++++++++++ tests/integration/tests/performance.js | 285 +++++++++++++++++++ tests/tests.cmake | 1 + 6 files changed, 580 insertions(+), 1 deletion(-) create mode 100644 tests/integration/performance/performance.js create mode 100644 tests/integration/tests/performance.js diff --git a/builtins/web/fetch/fetch_event.cpp b/builtins/web/fetch/fetch_event.cpp index 33406ea..8772464 100644 --- a/builtins/web/fetch/fetch_event.cpp +++ b/builtins/web/fetch/fetch_event.cpp @@ -1,4 +1,5 @@ #include "fetch_event.h" +#include "../performance.h" #include "../url.h" #include "../worker-location.h" #include "encode.h" @@ -74,6 +75,8 @@ JSObject *FetchEvent::prepare_downstream_request(JSContext *cx) { bool FetchEvent::init_incoming_request(JSContext *cx, JS::HandleObject self, host_api::HttpIncomingRequest *req) { + builtins::web::performance::Performance::timeOrigin.emplace( + std::chrono::high_resolution_clock::now()); JS::RootedObject request( cx, &JS::GetReservedSlot(self, static_cast(Slots::Request)).toObject()); diff --git a/builtins/web/performance.cpp b/builtins/web/performance.cpp index 17b895a..315ef65 100644 --- a/builtins/web/performance.cpp +++ b/builtins/web/performance.cpp @@ -67,7 +67,13 @@ bool Performance::init_class(JSContext *cx, JS::HandleObject global) { } bool install(api::Engine *engine) { - return Performance::init_class(engine->cx(), engine->global()); + if (!Performance::init_class(engine->cx(), engine->global())) { + return false; + } + if (!Performance::create(engine->cx(), engine->global())) { + return false; + } + return true; } } // namespace performance diff --git a/tests/integration/handlers.js b/tests/integration/handlers.js index c087ab3..2eada8e 100644 --- a/tests/integration/handlers.js +++ b/tests/integration/handlers.js @@ -1,2 +1,3 @@ export { handler as btoa } from './btoa/btoa.js'; +export { handler as performance } from './performance/performance.js'; export { handler as timers } from './timers/timers.js'; diff --git a/tests/integration/performance/performance.js b/tests/integration/performance/performance.js new file mode 100644 index 0000000..44a462e --- /dev/null +++ b/tests/integration/performance/performance.js @@ -0,0 +1,283 @@ +import { serveTest } from "../test-server.js"; +import { assert, deepStrictEqual, strictEqual } from "../assert.js"; + +export const handler = serveTest(async (t) => { + t.test("Performance-interface", () => { + { + let actual = Reflect.ownKeys(Performance); + let expected = ["prototype", "length", "name"]; + deepStrictEqual(actual, expected, `Reflect.ownKeys(Performance)`); + } + + // Check the prototype descriptors are correct + { + let actual = Reflect.getOwnPropertyDescriptor(Performance, "prototype"); + let expected = { + value: Performance.prototype, + writable: false, + enumerable: false, + configurable: false, + }; + deepStrictEqual( + actual, + expected, + `Reflect.getOwnPropertyDescriptor(Performance, 'prototype')` + ); + } + + // Check the constructor function's defined parameter length is correct + { + let actual = Reflect.getOwnPropertyDescriptor(Performance, "length"); + let expected = { + value: 0, + writable: false, + enumerable: false, + configurable: true, + }; + deepStrictEqual( + actual, + expected, + `Reflect.getOwnPropertyDescriptor(Performance, 'length')` + ); + } + + // Check the constructor function's name is correct + { + let actual = Reflect.getOwnPropertyDescriptor(Performance, "name"); + let expected = { + value: "Performance", + writable: false, + enumerable: false, + configurable: true, + }; + deepStrictEqual( + actual, + expected, + `Reflect.getOwnPropertyDescriptor(Performance, 'name')` + ); + } + + // Check the prototype has the correct keys + { + let actual = Reflect.ownKeys(Performance.prototype); + let expected = ["constructor", "timeOrigin", "now", Symbol.toStringTag]; + deepStrictEqual( + actual, + expected, + `Reflect.ownKeys(Performance.prototype)` + ); + } + + // Check the constructor on the prototype is correct + { + let actual = Reflect.getOwnPropertyDescriptor( + Performance.prototype, + "constructor" + ); + let expected = { + writable: true, + enumerable: false, + configurable: true, + value: Performance.prototype.constructor, + }; + deepStrictEqual( + actual, + expected, + `Reflect.getOwnPropertyDescriptor(Performance.prototype, 'constructor')` + ); + + strictEqual( + typeof Performance.prototype.constructor, + "function", + `typeof Performance.prototype.constructor` + ); + } + + { + let actual = Reflect.getOwnPropertyDescriptor( + Performance.prototype.constructor, + "length" + ); + let expected = { + value: 0, + writable: false, + enumerable: false, + configurable: true, + }; + assert( + actual, + expected, + `Reflect.getOwnPropertyDescriptor(Performance.prototype.constructor, 'length')` + ); + } + + { + let actual = Reflect.getOwnPropertyDescriptor( + Performance.prototype.constructor, + "name" + ); + let expected = { + value: "Performance", + writable: false, + enumerable: false, + configurable: true, + }; + assert( + actual, + expected, + `Reflect.getOwnPropertyDescriptor(Performance.prototype.constructor, 'name')` + ); + } + + // Check the Symbol.toStringTag on the prototype is correct + { + let actual = Reflect.getOwnPropertyDescriptor( + Performance.prototype, + Symbol.toStringTag + ); + let expected = { + value: "performance", + writable: false, + enumerable: false, + configurable: true, + }; + assert( + actual, + expected, + `Reflect.getOwnPropertyDescriptor(Performance.prototype, [Symbol.toStringTag])` + ); + + assert( + typeof Performance.prototype[Symbol.toStringTag], + "string", + `typeof Performance.prototype[Symbol.toStringTag]` + ); + } + + // Check the timeOrigin property is correct + { + let descriptors = Reflect.getOwnPropertyDescriptor( + Performance.prototype, + "timeOrigin" + ); + let expected = { enumerable: true, configurable: true }; + assert( + descriptors.enumerable, + true, + `Reflect.getOwnPropertyDescriptor(Performance, 'timeOrigin').enumerable` + ); + assert( + descriptors.configurable, + true, + `Reflect.getOwnPropertyDescriptor(Performance, 'timeOrigin').configurable` + ); + assert( + descriptors.value, + undefined, + `Reflect.getOwnPropertyDescriptor(Performance, 'timeOrigin').value` + ); + assert( + descriptors.set, + undefined, + `Reflect.getOwnPropertyDescriptor(Performance, 'timeOrigin').set` + ); + assert( + typeof descriptors.get, + "function", + `typeof Reflect.getOwnPropertyDescriptor(Performance, 'timeOrigin').get` + ); + + assert( + typeof Performance.prototype.timeOrigin, + "number", + `typeof Performance.prototype.timeOrigin` + ); + } + + // Check the now property is correct + { + let actual = Reflect.getOwnPropertyDescriptor( + Performance.prototype, + "now" + ); + let expected = { + writable: true, + enumerable: true, + configurable: true, + value: Performance.prototype.now, + }; + assert( + actual, + expected, + `Reflect.getOwnPropertyDescriptor(Performance, 'now')` + ); + + assert( + typeof Performance.prototype.now, + "function", + `typeof Performance.prototype.now` + ); + } + + { + let actual = Reflect.getOwnPropertyDescriptor( + Performance.prototype.now, + "length" + ); + let expected = { + value: 0, + writable: false, + enumerable: false, + configurable: true, + }; + assert( + actual, + expected, + `Reflect.getOwnPropertyDescriptor(Performance.prototype.now, 'length')` + ); + } + + { + let actual = Reflect.getOwnPropertyDescriptor( + Performance.prototype.now, + "name" + ); + let expected = { + value: "now", + writable: false, + enumerable: false, + configurable: true, + }; + assert( + actual, + expected, + `Reflect.getOwnPropertyDescriptor(Performance.prototype.now, 'name')` + ); + } + }); + + t.test("globalThis.performance", () => { + assert( + globalThis.performance instanceof Performance, + true, + `globalThis.performance instanceof Performance` + ); + }); + + t.test("globalThis.performance.now", () => { + throws(() => new performance.now()); + assert(typeof performance.now(), "number"); + assert(performance.now() > 0, true); + assert(Number.isNaN(performance.now()), false); + assert(Number.isFinite(performance.now()), true); + assert(performance.now() < Date.now(), true); + }); + + t.test("globalThis.performance.timeOrigin", () => { + assert(typeof performance.timeOrigin, "number"); + assert(performance.timeOrigin > 0, true); + assert(Number.isNaN(performance.timeOrigin), false); + assert(Number.isFinite(performance.timeOrigin), true); + assert(performance.timeOrigin < Date.now(), true); + }); +}); diff --git a/tests/integration/tests/performance.js b/tests/integration/tests/performance.js new file mode 100644 index 0000000..2356e89 --- /dev/null +++ b/tests/integration/tests/performance.js @@ -0,0 +1,285 @@ +import { serveTest } from "../test-server.js"; +import { deepStrictEqual, strictEqual, throws } from "../assert.js"; + +throw new Error('wat'); + +export const handler = serveTest(async (t) => { + t.test("Performance-interface", () => { + { + let actual = Reflect.ownKeys(Performance); + let expected = ["prototype", "length", "name"]; + deepStrictEqual(actual, expected, `Reflect.ownKeys(Performance)`); + } + + // Check the prototype descriptors are correct + { + let actual = Reflect.getOwnPropertyDescriptor(Performance, "prototype"); + let expected = { + value: Performance.prototype, + writable: false, + enumerable: false, + configurable: false, + }; + deepStrictEqual( + actual, + expected, + `Reflect.getOwnPropertyDescriptor(Performance, 'prototype')` + ); + } + + // Check the constructor function's defined parameter length is correct + { + let actual = Reflect.getOwnPropertyDescriptor(Performance, "length"); + let expected = { + value: 0, + writable: false, + enumerable: false, + configurable: true, + }; + deepStrictEqual( + actual, + expected, + `Reflect.getOwnPropertyDescriptor(Performance, 'length')` + ); + } + + // Check the constructor function's name is correct + { + let actual = Reflect.getOwnPropertyDescriptor(Performance, "name"); + let expected = { + value: "Performance", + writable: false, + enumerable: false, + configurable: true, + }; + deepStrictEqual( + actual, + expected, + `Reflect.getOwnPropertyDescriptor(Performance, 'name')` + ); + } + + // Check the prototype has the correct keys + { + let actual = Reflect.ownKeys(Performance.prototype); + let expected = ["constructor", "timeOrigin", "now", Symbol.toStringTag]; + deepStrictEqual( + actual, + expected, + `Reflect.ownKeys(Performance.prototype)` + ); + } + + // Check the constructor on the prototype is correct + { + let actual = Reflect.getOwnPropertyDescriptor( + Performance.prototype, + "constructor" + ); + let expected = { + writable: true, + enumerable: false, + configurable: true, + value: Performance.prototype.constructor, + }; + deepStrictEqual( + actual, + expected, + `Reflect.getOwnPropertyDescriptor(Performance.prototype, 'constructor')` + ); + + strictEqual( + typeof Performance.prototype.constructor, + "function", + `typeof Performance.prototype.constructor` + ); + } + + { + let actual = Reflect.getOwnPropertyDescriptor( + Performance.prototype.constructor, + "length" + ); + let expected = { + value: 0, + writable: false, + enumerable: false, + configurable: true, + }; + strictEqual( + actual, + expected, + `Reflect.getOwnPropertyDescriptor(Performance.prototype.constructor, 'length')` + ); + } + + { + let actual = Reflect.getOwnPropertyDescriptor( + Performance.prototype.constructor, + "name" + ); + let expected = { + value: "Performance", + writable: false, + enumerable: false, + configurable: true, + }; + strictEqual( + actual, + expected, + `Reflect.getOwnPropertyDescriptor(Performance.prototype.constructor, 'name')` + ); + } + + // Check the Symbol.toStringTag on the prototype is correct + { + let actual = Reflect.getOwnPropertyDescriptor( + Performance.prototype, + Symbol.toStringTag + ); + let expected = { + value: "performance", + writable: false, + enumerable: false, + configurable: true, + }; + strictEqual( + actual, + expected, + `Reflect.getOwnPropertyDescriptor(Performance.prototype, [Symbol.toStringTag])` + ); + + strictEqual( + typeof Performance.prototype[Symbol.toStringTag], + "string", + `typeof Performance.prototype[Symbol.toStringTag]` + ); + } + + // Check the timeOrigin property is correct + { + let descriptors = Reflect.getOwnPropertyDescriptor( + Performance.prototype, + "timeOrigin" + ); + let expected = { enumerable: true, configurable: true }; + strictEqual( + descriptors.enumerable, + true, + `Reflect.getOwnPropertyDescriptor(Performance, 'timeOrigin').enumerable` + ); + strictEqual( + descriptors.configurable, + true, + `Reflect.getOwnPropertyDescriptor(Performance, 'timeOrigin').configurable` + ); + strictEqual( + descriptors.value, + undefined, + `Reflect.getOwnPropertyDescriptor(Performance, 'timeOrigin').value` + ); + strictEqual( + descriptors.set, + undefined, + `Reflect.getOwnPropertyDescriptor(Performance, 'timeOrigin').set` + ); + strictEqual( + typeof descriptors.get, + "function", + `typeof Reflect.getOwnPropertyDescriptor(Performance, 'timeOrigin').get` + ); + + strictEqual( + typeof Performance.prototype.timeOrigin, + "number", + `typeof Performance.prototype.timeOrigin` + ); + } + + // Check the now property is correct + { + let actual = Reflect.getOwnPropertyDescriptor( + Performance.prototype, + "now" + ); + let expected = { + writable: true, + enumerable: true, + configurable: true, + value: Performance.prototype.now, + }; + strictEqual( + actual, + expected, + `Reflect.getOwnPropertyDescriptor(Performance, 'now')` + ); + + strictEqual( + typeof Performance.prototype.now, + "function", + `typeof Performance.prototype.now` + ); + } + + { + let actual = Reflect.getOwnPropertyDescriptor( + Performance.prototype.now, + "length" + ); + let expected = { + value: 0, + writable: false, + enumerable: false, + configurable: true, + }; + strictEqual( + actual, + expected, + `Reflect.getOwnPropertyDescriptor(Performance.prototype.now, 'length')` + ); + } + + { + let actual = Reflect.getOwnPropertyDescriptor( + Performance.prototype.now, + "name" + ); + let expected = { + value: "now", + writable: false, + enumerable: false, + configurable: true, + }; + strictEqual( + actual, + expected, + `Reflect.getOwnPropertyDescriptor(Performance.prototype.now, 'name')` + ); + } + }); + + t.test("globalThis.performance", () => { + strictEqual( + globalThis.performance instanceof Performance, + true, + `globalThis.performance instanceof Performance` + ); + }); + + t.test("globalThis.performance.now", () => { + throws(() => new performance.now()); + strictEqual(typeof performance.now(), "number"); + strictEqual(performance.now() > 0, true); + strictEqual(Number.isNaN(performance.now()), false); + strictEqual(Number.isFinite(performance.now()), true); + strictEqual(performance.now() < Date.now(), true); + }); + + t.test("globalThis.performance.timeOrigin", () => { + strictEqual(typeof performance.timeOrigin, "number"); + strictEqual(performance.timeOrigin > 0, true); + strictEqual(Number.isNaN(performance.timeOrigin), false); + strictEqual(Number.isFinite(performance.timeOrigin), true); + strictEqual(performance.timeOrigin < Date.now(), true); + }); +}); diff --git a/tests/tests.cmake b/tests/tests.cmake index d2ee82a..b483788 100644 --- a/tests/tests.cmake +++ b/tests/tests.cmake @@ -36,4 +36,5 @@ test_e2e(tla-err) test_e2e(tla-runtime-resolve) test_integration(btoa) +test_integration(performance) test_integration(timers) From 230822649c68ccfbda57d99c0650bdfd36f07de8 Mon Sep 17 00:00:00 2001 From: Guy Bedford Date: Tue, 14 May 2024 15:38:54 -0700 Subject: [PATCH 2/2] fix tests --- tests/integration/performance/performance.js | 53 ++++++++++---------- 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/tests/integration/performance/performance.js b/tests/integration/performance/performance.js index 44a462e..705a68e 100644 --- a/tests/integration/performance/performance.js +++ b/tests/integration/performance/performance.js @@ -1,5 +1,5 @@ import { serveTest } from "../test-server.js"; -import { assert, deepStrictEqual, strictEqual } from "../assert.js"; +import { deepStrictEqual, strictEqual, throws } from "../assert.js"; export const handler = serveTest(async (t) => { t.test("Performance-interface", () => { @@ -104,7 +104,7 @@ export const handler = serveTest(async (t) => { enumerable: false, configurable: true, }; - assert( + deepStrictEqual( actual, expected, `Reflect.getOwnPropertyDescriptor(Performance.prototype.constructor, 'length')` @@ -122,7 +122,7 @@ export const handler = serveTest(async (t) => { enumerable: false, configurable: true, }; - assert( + deepStrictEqual( actual, expected, `Reflect.getOwnPropertyDescriptor(Performance.prototype.constructor, 'name')` @@ -141,13 +141,13 @@ export const handler = serveTest(async (t) => { enumerable: false, configurable: true, }; - assert( + deepStrictEqual( actual, expected, `Reflect.getOwnPropertyDescriptor(Performance.prototype, [Symbol.toStringTag])` ); - assert( + strictEqual( typeof Performance.prototype[Symbol.toStringTag], "string", `typeof Performance.prototype[Symbol.toStringTag]` @@ -160,34 +160,33 @@ export const handler = serveTest(async (t) => { Performance.prototype, "timeOrigin" ); - let expected = { enumerable: true, configurable: true }; - assert( + strictEqual( descriptors.enumerable, true, `Reflect.getOwnPropertyDescriptor(Performance, 'timeOrigin').enumerable` ); - assert( + strictEqual( descriptors.configurable, true, `Reflect.getOwnPropertyDescriptor(Performance, 'timeOrigin').configurable` ); - assert( + strictEqual( descriptors.value, undefined, `Reflect.getOwnPropertyDescriptor(Performance, 'timeOrigin').value` ); - assert( + strictEqual( descriptors.set, undefined, `Reflect.getOwnPropertyDescriptor(Performance, 'timeOrigin').set` ); - assert( + strictEqual( typeof descriptors.get, "function", `typeof Reflect.getOwnPropertyDescriptor(Performance, 'timeOrigin').get` ); - assert( + strictEqual( typeof Performance.prototype.timeOrigin, "number", `typeof Performance.prototype.timeOrigin` @@ -206,13 +205,13 @@ export const handler = serveTest(async (t) => { configurable: true, value: Performance.prototype.now, }; - assert( + deepStrictEqual( actual, expected, `Reflect.getOwnPropertyDescriptor(Performance, 'now')` ); - assert( + strictEqual( typeof Performance.prototype.now, "function", `typeof Performance.prototype.now` @@ -230,7 +229,7 @@ export const handler = serveTest(async (t) => { enumerable: false, configurable: true, }; - assert( + deepStrictEqual( actual, expected, `Reflect.getOwnPropertyDescriptor(Performance.prototype.now, 'length')` @@ -248,7 +247,7 @@ export const handler = serveTest(async (t) => { enumerable: false, configurable: true, }; - assert( + deepStrictEqual( actual, expected, `Reflect.getOwnPropertyDescriptor(Performance.prototype.now, 'name')` @@ -257,7 +256,7 @@ export const handler = serveTest(async (t) => { }); t.test("globalThis.performance", () => { - assert( + strictEqual( globalThis.performance instanceof Performance, true, `globalThis.performance instanceof Performance` @@ -266,18 +265,18 @@ export const handler = serveTest(async (t) => { t.test("globalThis.performance.now", () => { throws(() => new performance.now()); - assert(typeof performance.now(), "number"); - assert(performance.now() > 0, true); - assert(Number.isNaN(performance.now()), false); - assert(Number.isFinite(performance.now()), true); - assert(performance.now() < Date.now(), true); + strictEqual(typeof performance.now(), "number"); + strictEqual(performance.now() > 0, true); + strictEqual(Number.isNaN(performance.now()), false); + strictEqual(Number.isFinite(performance.now()), true); + strictEqual(performance.now() < Date.now(), true); }); t.test("globalThis.performance.timeOrigin", () => { - assert(typeof performance.timeOrigin, "number"); - assert(performance.timeOrigin > 0, true); - assert(Number.isNaN(performance.timeOrigin), false); - assert(Number.isFinite(performance.timeOrigin), true); - assert(performance.timeOrigin < Date.now(), true); + strictEqual(typeof performance.timeOrigin, "number"); + strictEqual(performance.timeOrigin > 0, true); + strictEqual(Number.isNaN(performance.timeOrigin), false); + strictEqual(Number.isFinite(performance.timeOrigin), true); + strictEqual(performance.timeOrigin < Date.now(), true); }); });