diff options
Diffstat (limited to 'cli/tests/unit/timers_test.ts')
-rw-r--r-- | cli/tests/unit/timers_test.ts | 763 |
1 files changed, 0 insertions, 763 deletions
diff --git a/cli/tests/unit/timers_test.ts b/cli/tests/unit/timers_test.ts deleted file mode 100644 index 17b137231..000000000 --- a/cli/tests/unit/timers_test.ts +++ /dev/null @@ -1,763 +0,0 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -import { - assert, - assertEquals, - assertNotEquals, - delay, - execCode, - unreachable, -} from "./test_util.ts"; - -Deno.test(async function functionParameterBindingSuccess() { - const { promise, resolve } = Promise.withResolvers<void>(); - let count = 0; - - const nullProto = (newCount: number) => { - count = newCount; - resolve(); - }; - - Reflect.setPrototypeOf(nullProto, null); - - setTimeout(nullProto, 500, 1); - await promise; - // count should be reassigned - assertEquals(count, 1); -}); - -Deno.test(async function stringifyAndEvalNonFunctions() { - // eval can only access global scope - const global = globalThis as unknown as { - globalPromise: ReturnType<typeof Promise.withResolvers<void>>; - globalCount: number; - }; - - global.globalPromise = Promise.withResolvers<void>(); - global.globalCount = 0; - - const notAFunction = - "globalThis.globalCount++; globalThis.globalPromise.resolve();" as unknown as () => - void; - - setTimeout(notAFunction, 500); - - await global.globalPromise.promise; - - // count should be incremented - assertEquals(global.globalCount, 1); - - Reflect.deleteProperty(global, "globalPromise"); - Reflect.deleteProperty(global, "globalCount"); -}); - -Deno.test(async function timeoutSuccess() { - const { promise, resolve } = Promise.withResolvers<void>(); - let count = 0; - setTimeout(() => { - count++; - resolve(); - }, 500); - await promise; - // count should increment - assertEquals(count, 1); -}); - -Deno.test(async function timeoutEvalNoScopeLeak() { - // eval can only access global scope - const global = globalThis as unknown as { - globalPromise: ReturnType<typeof Promise.withResolvers<Error>>; - }; - global.globalPromise = Promise.withResolvers(); - setTimeout( - ` - try { - console.log(core); - globalThis.globalPromise.reject(new Error("Didn't throw.")); - } catch (error) { - globalThis.globalPromise.resolve(error); - }` as unknown as () => void, - 0, - ); - const error = await global.globalPromise.promise; - assertEquals(error.name, "ReferenceError"); - Reflect.deleteProperty(global, "globalPromise"); -}); - -Deno.test(async function evalPrimordial() { - const global = globalThis as unknown as { - globalPromise: ReturnType<typeof Promise.withResolvers<void>>; - }; - global.globalPromise = Promise.withResolvers<void>(); - const originalEval = globalThis.eval; - let wasCalled = false; - globalThis.eval = (argument) => { - wasCalled = true; - return originalEval(argument); - }; - setTimeout( - "globalThis.globalPromise.resolve();" as unknown as () => void, - 0, - ); - await global.globalPromise.promise; - assert(!wasCalled); - Reflect.deleteProperty(global, "globalPromise"); - globalThis.eval = originalEval; -}); - -Deno.test(async function timeoutArgs() { - const { promise, resolve } = Promise.withResolvers<void>(); - const arg = 1; - let capturedArgs: unknown[] = []; - setTimeout( - function () { - capturedArgs = [...arguments]; - resolve(); - }, - 10, - arg, - arg.toString(), - [arg], - ); - await promise; - assertEquals(capturedArgs, [ - arg, - arg.toString(), - [arg], - ]); -}); - -Deno.test(async function timeoutCancelSuccess() { - let count = 0; - const id = setTimeout(() => { - count++; - }, 1); - // Cancelled, count should not increment - clearTimeout(id); - await delay(600); - assertEquals(count, 0); -}); - -Deno.test(async function timeoutCancelMultiple() { - function uncalled(): never { - throw new Error("This function should not be called."); - } - - // Set timers and cancel them in the same order. - const t1 = setTimeout(uncalled, 10); - const t2 = setTimeout(uncalled, 10); - const t3 = setTimeout(uncalled, 10); - clearTimeout(t1); - clearTimeout(t2); - clearTimeout(t3); - - // Set timers and cancel them in reverse order. - const t4 = setTimeout(uncalled, 20); - const t5 = setTimeout(uncalled, 20); - const t6 = setTimeout(uncalled, 20); - clearTimeout(t6); - clearTimeout(t5); - clearTimeout(t4); - - // Sleep until we're certain that the cancelled timers aren't gonna fire. - await delay(50); -}); - -Deno.test(async function timeoutCancelInvalidSilentFail() { - // Expect no panic - const { promise, resolve } = Promise.withResolvers<void>(); - let count = 0; - const id = setTimeout(() => { - count++; - // Should have no effect - clearTimeout(id); - resolve(); - }, 500); - await promise; - assertEquals(count, 1); - - // Should silently fail (no panic) - clearTimeout(2147483647); -}); - -Deno.test(async function intervalSuccess() { - const { promise, resolve } = Promise.withResolvers<void>(); - let count = 0; - const id = setInterval(() => { - count++; - clearInterval(id); - resolve(); - }, 100); - await promise; - // Clear interval - clearInterval(id); - // count should increment twice - assertEquals(count, 1); - // Similar false async leaking alarm. - // Force next round of polling. - await delay(0); -}); - -Deno.test(async function intervalCancelSuccess() { - let count = 0; - const id = setInterval(() => { - count++; - }, 1); - clearInterval(id); - await delay(500); - assertEquals(count, 0); -}); - -Deno.test(async function intervalOrdering() { - const timers: number[] = []; - let timeouts = 0; - function onTimeout() { - ++timeouts; - for (let i = 1; i < timers.length; i++) { - clearTimeout(timers[i]); - } - } - for (let i = 0; i < 10; i++) { - timers[i] = setTimeout(onTimeout, 1); - } - await delay(500); - assertEquals(timeouts, 1); -}); - -Deno.test(function intervalCancelInvalidSilentFail() { - // Should silently fail (no panic) - clearInterval(2147483647); -}); - -Deno.test(async function callbackTakesLongerThanInterval() { - const { promise, resolve } = Promise.withResolvers<void>(); - - let timeEndOfFirstCallback: number | undefined; - const interval = setInterval(() => { - if (timeEndOfFirstCallback === undefined) { - // First callback - Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 300); - timeEndOfFirstCallback = Date.now(); - } else { - // Second callback - assert(Date.now() - 100 >= timeEndOfFirstCallback); - clearInterval(interval); - resolve(); - } - }, 100); - - await promise; -}); - -// https://github.com/denoland/deno/issues/11398 -Deno.test(async function clearTimeoutAfterNextTimerIsDue1() { - const { promise, resolve } = Promise.withResolvers<void>(); - - setTimeout(() => { - resolve(); - }, 300); - - const interval = setInterval(() => { - Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 400); - // Both the interval and the timeout's due times are now in the past. - clearInterval(interval); - }, 100); - - await promise; -}); - -// https://github.com/denoland/deno/issues/11398 -Deno.test(async function clearTimeoutAfterNextTimerIsDue2() { - const { promise, resolve } = Promise.withResolvers<void>(); - - const timeout1 = setTimeout(unreachable, 100); - - setTimeout(() => { - resolve(); - }, 200); - - Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 300); - // Both of the timeouts' due times are now in the past. - clearTimeout(timeout1); - - await promise; -}); - -Deno.test(async function fireCallbackImmediatelyWhenDelayOverMaxValue() { - let count = 0; - setTimeout(() => { - count++; - }, 2 ** 31); - await delay(1); - assertEquals(count, 1); -}); - -Deno.test(async function timeoutCallbackThis() { - const { promise, resolve } = Promise.withResolvers<void>(); - let capturedThis: unknown; - const obj = { - foo() { - capturedThis = this; - resolve(); - }, - }; - setTimeout(obj.foo, 1); - await promise; - assertEquals(capturedThis, window); -}); - -Deno.test(async function timeoutBindThis() { - const thisCheckPassed = [null, undefined, window, globalThis]; - - const thisCheckFailed = [ - 0, - "", - true, - false, - {}, - [], - "foo", - () => {}, - Object.prototype, - ]; - - for (const thisArg of thisCheckPassed) { - const { promise, resolve } = Promise.withResolvers<void>(); - let hasThrown = 0; - try { - setTimeout.call(thisArg, () => resolve(), 1); - hasThrown = 1; - } catch (err) { - if (err instanceof TypeError) { - hasThrown = 2; - } else { - hasThrown = 3; - } - } - await promise; - assertEquals(hasThrown, 1); - } - - for (const thisArg of thisCheckFailed) { - let hasThrown = 0; - try { - setTimeout.call(thisArg, () => {}, 1); - hasThrown = 1; - } catch (err) { - if (err instanceof TypeError) { - hasThrown = 2; - } else { - hasThrown = 3; - } - } - assertEquals(hasThrown, 2); - } -}); - -Deno.test(function clearTimeoutShouldConvertToNumber() { - let called = false; - const obj = { - valueOf(): number { - called = true; - return 1; - }, - }; - clearTimeout((obj as unknown) as number); - assert(called); -}); - -Deno.test(function setTimeoutShouldThrowWithBigint() { - let hasThrown = 0; - try { - setTimeout(() => {}, (1n as unknown) as number); - hasThrown = 1; - } catch (err) { - if (err instanceof TypeError) { - hasThrown = 2; - } else { - hasThrown = 3; - } - } - assertEquals(hasThrown, 2); -}); - -Deno.test(function clearTimeoutShouldThrowWithBigint() { - let hasThrown = 0; - try { - clearTimeout((1n as unknown) as number); - hasThrown = 1; - } catch (err) { - if (err instanceof TypeError) { - hasThrown = 2; - } else { - hasThrown = 3; - } - } - assertEquals(hasThrown, 2); -}); - -Deno.test(function testFunctionName() { - assertEquals(clearTimeout.name, "clearTimeout"); - assertEquals(clearInterval.name, "clearInterval"); -}); - -Deno.test(function testFunctionParamsLength() { - assertEquals(setTimeout.length, 1); - assertEquals(setInterval.length, 1); - assertEquals(clearTimeout.length, 0); - assertEquals(clearInterval.length, 0); -}); - -Deno.test(function clearTimeoutAndClearIntervalNotBeEquals() { - assertNotEquals(clearTimeout, clearInterval); -}); - -Deno.test(async function timerOrdering() { - const array: number[] = []; - const { promise: donePromise, resolve } = Promise.withResolvers<void>(); - - function push(n: number) { - array.push(n); - if (array.length === 6) { - resolve(); - } - } - - setTimeout(() => { - push(1); - setTimeout(() => push(4)); - }, 0); - setTimeout(() => { - push(2); - setTimeout(() => push(5)); - }, 0); - setTimeout(() => { - push(3); - setTimeout(() => push(6)); - }, 0); - - await donePromise; - - assertEquals(array, [1, 2, 3, 4, 5, 6]); -}); - -Deno.test(async function timerBasicMicrotaskOrdering() { - let s = ""; - let count = 0; - const { promise, resolve } = Promise.withResolvers<void>(); - setTimeout(() => { - Promise.resolve().then(() => { - count++; - s += "de"; - if (count === 2) { - resolve(); - } - }); - }); - setTimeout(() => { - count++; - s += "no"; - if (count === 2) { - resolve(); - } - }); - await promise; - assertEquals(s, "deno"); -}); - -Deno.test(async function timerNestedMicrotaskOrdering() { - let s = ""; - const { promise, resolve } = Promise.withResolvers<void>(); - s += "0"; - setTimeout(() => { - s += "4"; - setTimeout(() => (s += "A")); - Promise.resolve() - .then(() => { - setTimeout(() => { - s += "B"; - resolve(); - }); - }) - .then(() => { - s += "5"; - }); - }); - setTimeout(() => (s += "6")); - Promise.resolve().then(() => (s += "2")); - Promise.resolve().then(() => - setTimeout(() => { - s += "7"; - Promise.resolve() - .then(() => (s += "8")) - .then(() => { - s += "9"; - }); - }) - ); - Promise.resolve().then(() => Promise.resolve().then(() => (s += "3"))); - s += "1"; - await promise; - assertEquals(s, "0123456789AB"); -}); - -Deno.test(function testQueueMicrotask() { - assertEquals(typeof queueMicrotask, "function"); -}); - -Deno.test(async function timerIgnoresDateOverride() { - const OriginalDate = Date; - const { promise, resolve, reject } = Promise.withResolvers<void>(); - let hasThrown = 0; - try { - const overrideCalled: () => number = () => { - reject("global Date override used over original Date object"); - return 0; - }; - const DateOverride = () => { - overrideCalled(); - }; - globalThis.Date = DateOverride as DateConstructor; - globalThis.Date.now = overrideCalled; - globalThis.Date.UTC = overrideCalled; - globalThis.Date.parse = overrideCalled; - queueMicrotask(() => { - resolve(); - }); - await promise; - hasThrown = 1; - } catch (err) { - if (typeof err === "string") { - assertEquals(err, "global Date override used over original Date object"); - hasThrown = 2; - } else if (err instanceof TypeError) { - hasThrown = 3; - } else { - hasThrown = 4; - } - } finally { - globalThis.Date = OriginalDate; - } - assertEquals(hasThrown, 1); -}); - -Deno.test({ - name: "unrefTimer", - permissions: { run: true, read: true }, - fn: async () => { - const [statusCode, output] = await execCode(` - const timer = setTimeout(() => console.log("1"), 1); - Deno.unrefTimer(timer); - `); - assertEquals(statusCode, 0); - assertEquals(output, ""); - }, -}); - -Deno.test({ - name: "unrefTimer - mix ref and unref 1", - permissions: { run: true, read: true }, - fn: async () => { - const [statusCode, output] = await execCode(` - const timer1 = setTimeout(() => console.log("1"), 200); - const timer2 = setTimeout(() => console.log("2"), 400); - const timer3 = setTimeout(() => console.log("3"), 600); - Deno.unrefTimer(timer3); - `); - assertEquals(statusCode, 0); - assertEquals(output, "1\n2\n"); - }, -}); - -Deno.test({ - name: "unrefTimer - mix ref and unref 2", - permissions: { run: true, read: true }, - fn: async () => { - const [statusCode, output] = await execCode(` - const timer1 = setTimeout(() => console.log("1"), 200); - const timer2 = setTimeout(() => console.log("2"), 400); - const timer3 = setTimeout(() => console.log("3"), 600); - Deno.unrefTimer(timer1); - Deno.unrefTimer(timer2); - `); - assertEquals(statusCode, 0); - assertEquals(output, "1\n2\n3\n"); - }, -}); - -Deno.test({ - name: "unrefTimer - unref interval", - permissions: { run: true, read: true }, - fn: async () => { - const [statusCode, output] = await execCode(` - let i = 0; - const timer1 = setInterval(() => { - console.log("1"); - i++; - if (i === 5) { - Deno.unrefTimer(timer1); - } - }, 10); - `); - assertEquals(statusCode, 0); - assertEquals(output, "1\n1\n1\n1\n1\n"); - }, -}); - -Deno.test({ - name: "unrefTimer - unref then ref 1", - permissions: { run: true, read: true }, - fn: async () => { - const [statusCode, output] = await execCode(` - const timer1 = setTimeout(() => console.log("1"), 10); - Deno.unrefTimer(timer1); - Deno.refTimer(timer1); - `); - assertEquals(statusCode, 0); - assertEquals(output, "1\n"); - }, -}); - -Deno.test({ - name: "unrefTimer - unref then ref", - permissions: { run: true, read: true }, - fn: async () => { - const [statusCode, output] = await execCode(` - const timer1 = setTimeout(() => { - console.log("1"); - Deno.refTimer(timer2); - }, 10); - const timer2 = setTimeout(() => console.log("2"), 20); - Deno.unrefTimer(timer2); - `); - assertEquals(statusCode, 0); - assertEquals(output, "1\n2\n"); - }, -}); - -Deno.test({ - name: "unrefTimer - invalid calls do nothing", - fn: () => { - Deno.unrefTimer(NaN); - Deno.refTimer(NaN); - }, -}); - -Deno.test({ - name: "AbortSignal.timeout() with no listeners", - permissions: { run: true, read: true }, - fn: async () => { - const [statusCode, output] = await execCode(` - const signal = AbortSignal.timeout(2000); - - // This unref timer expires before the signal, and if it does expire, then - // it means the signal has kept the event loop alive. - const timer = setTimeout(() => console.log("Unexpected!"), 1500); - Deno.unrefTimer(timer); - `); - assertEquals(statusCode, 0); - assertEquals(output, ""); - }, -}); - -Deno.test({ - name: "AbortSignal.timeout() with listeners", - permissions: { run: true, read: true }, - fn: async () => { - const [statusCode, output] = await execCode(` - const signal = AbortSignal.timeout(1000); - signal.addEventListener("abort", () => console.log("Event fired!")); - `); - assertEquals(statusCode, 0); - assertEquals(output, "Event fired!\n"); - }, -}); - -Deno.test({ - name: "AbortSignal.timeout() with removed listeners", - permissions: { run: true, read: true }, - fn: async () => { - const [statusCode, output] = await execCode(` - const signal = AbortSignal.timeout(2000); - - const callback = () => console.log("Unexpected: Event fired"); - signal.addEventListener("abort", callback); - - setTimeout(() => { - console.log("Removing the listener."); - signal.removeEventListener("abort", callback); - }, 500); - - Deno.unrefTimer( - setTimeout(() => console.log("Unexpected: Unref timer"), 1500) - ); - `); - assertEquals(statusCode, 0); - assertEquals(output, "Removing the listener.\n"); - }, -}); - -Deno.test({ - name: "AbortSignal.timeout() with listener for a non-abort event", - permissions: { run: true, read: true }, - fn: async () => { - const [statusCode, output] = await execCode(` - const signal = AbortSignal.timeout(2000); - - signal.addEventListener("someOtherEvent", () => { - console.log("Unexpected: someOtherEvent called"); - }); - - Deno.unrefTimer( - setTimeout(() => console.log("Unexpected: Unref timer"), 1500) - ); - `); - assertEquals(statusCode, 0); - assertEquals(output, ""); - }, -}); - -// Regression test for https://github.com/denoland/deno/issues/19866 -Deno.test({ - name: "regression for #19866", - fn: async () => { - const timeoutsFired = []; - - // deno-lint-ignore require-await - async function start(n: number) { - let i = 0; - const intervalId = setInterval(() => { - i++; - if (i > 2) { - clearInterval(intervalId!); - } - timeoutsFired.push(n); - }, 20); - } - - for (let n = 0; n < 100; n++) { - start(n); - } - - // 3s should be plenty of time for all the intervals to fire - // but it might still be flaky on CI. - await new Promise((resolve) => setTimeout(resolve, 3000)); - assertEquals(timeoutsFired.length, 300); - }, -}); - -// Regression test for https://github.com/denoland/deno/issues/20367 -Deno.test({ - name: "regression for #20367", - fn: async () => { - const { promise, resolve } = Promise.withResolvers<number>(); - const start = performance.now(); - setTimeout(() => { - const end = performance.now(); - resolve(end - start); - }, 1000); - clearTimeout(setTimeout(() => {}, 1000)); - - const result = await promise; - assert(result >= 1000); - }, -}); |