Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BREAKING(testing): replace TimeError exception in favor of built-in error classes in some cases #5550

Merged
merged 11 commits into from
Jul 29, 2024
55 changes: 21 additions & 34 deletions testing/time.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,30 +43,6 @@ import { _internals } from "./_time.ts";

export type { DelayOptions };

/**
* An error related to faking time.
*
* @example Usage
* ```ts
* import { FakeTime, TimeError } from "@std/testing/time";
* import { assertThrows } from "@std/assert";
*
* assertThrows(() => {
* new FakeTime(NaN);
* }, TimeError);
* ```
*/
export class TimeError extends Error {
/** Construct TimeError.
*
* @param message The error message
*/
constructor(message: string) {
super(message);
this.name = "TimeError";
}
}

function FakeTimeNow() {
return time?.now ?? _internals.Date.now();
}
Expand Down Expand Up @@ -131,12 +107,12 @@ function fakeSetTimeout(
// deno-lint-ignore no-explicit-any
...args: any[]
): number {
if (!time) throw new TimeError("Time is not faked");
if (!time) throw new ReferenceError("Time is not faked");
iuioiua marked this conversation as resolved.
Show resolved Hide resolved
return setTimer(callback, delay, args, false);
}

function fakeClearTimeout(id?: unknown) {
if (!time) throw new TimeError("Time is not faked");
if (!time) throw new ReferenceError("Time is not faked");
if (typeof id === "number" && dueNodes.has(id)) {
dueNodes.delete(id);
}
Expand All @@ -149,12 +125,12 @@ function fakeSetInterval(
// deno-lint-ignore no-explicit-any
...args: any[]
): number {
if (!time) throw new TimeError("Time is not faked");
if (!time) throw new ReferenceError("Time is not faked");
return setTimer(callback, delay, args, true);
}

function fakeClearInterval(id?: unknown) {
if (!time) throw new TimeError("Time is not faked");
if (!time) throw new ReferenceError("Time is not faked");
if (typeof id === "number" && dueNodes.has(id)) {
dueNodes.delete(id);
}
Expand Down Expand Up @@ -283,12 +259,15 @@ export class FakeTime {
*
* @param start The time to simulate. The default is the current time..
* @param options The options
*
* @throws {TypeError} If time is already faked
* @throws {TypeError} If the start is invalid
*/
constructor(
start?: number | string | Date | null,
options?: FakeTimeOptions,
) {
if (time) throw new TimeError("Time is already faked");
if (time) throw new TypeError("Time is already faked");
iuioiua marked this conversation as resolved.
Show resolved Hide resolved
initializedAt = _internals.Date.now();
startedAt = start instanceof Date
? start.valueOf()
Expand All @@ -297,7 +276,7 @@ export class FakeTime {
: typeof start === "string"
? (new Date(start)).valueOf()
: initializedAt;
if (Number.isNaN(startedAt)) throw new TimeError("Invalid start");
if (Number.isNaN(startedAt)) throw new TypeError("Invalid start");
now = startedAt;

timerId = timerIdGen();
Expand Down Expand Up @@ -356,6 +335,8 @@ export class FakeTime {
/**
* Restores real time.
*
* @throws {TypeError} If time is already restored
*
* @example Usage
* ```ts
* import { FakeTime } from "@std/testing/time";
Expand All @@ -373,13 +354,15 @@ export class FakeTime {
* ```
*/
static restore() {
if (!time) throw new TimeError("Time is already restored");
if (!time) throw new TypeError("Time is already restored");
iuioiua marked this conversation as resolved.
Show resolved Hide resolved
time.restore();
}

/**
* Restores real time temporarily until callback returns and resolves.
*
* @throws {ReferenceError} If time is not faked
*
* @example Usage
* ```ts
* import { FakeTime } from "@std/testing/time";
Expand Down Expand Up @@ -407,7 +390,7 @@ export class FakeTime {
// deno-lint-ignore no-explicit-any
...args: any[]
): Promise<T> {
if (!time) return Promise.reject(new TimeError("Time is not faked"));
if (!time) return Promise.reject(new ReferenceError("Time is not faked"));
restoreGlobals();
try {
const result = callback.apply(null, args);
Expand Down Expand Up @@ -449,6 +432,8 @@ export class FakeTime {
* Set the current time. It will call any functions waiting to be called between the current and new fake time.
* If the timer callback throws, time will stop advancing forward beyond that timer.
*
* @throws {RangeError} If the time goes backwards
*
* @example Usage
* ```ts
* import { FakeTime } from "@std/testing/time";
Expand All @@ -466,7 +451,7 @@ export class FakeTime {
* @param value The current time (in milliseconds)
*/
set now(value: number) {
if (value < now) throw new Error("time cannot go backwards");
if (value < now) throw new RangeError("Time cannot go backwards");
let dueNode: DueNode | null = dueTree.min();
while (dueNode && dueNode.due <= value) {
const timer: Timer | undefined = dueNode.timers.shift();
Expand Down Expand Up @@ -774,6 +759,8 @@ export class FakeTime {
/**
* Restores time related global functions to their original state.
*
* @throws {TypeError} If time is already restored
*
* @example Usage
* ```ts
* import { FakeTime } from "@std/testing/time";
Expand All @@ -791,7 +778,7 @@ export class FakeTime {
* ```
*/
restore() {
if (!time) throw new TimeError("Time is already restored");
if (!time) throw new TypeError("Time is already restored");
time = undefined;
restoreGlobals();
if (advanceIntervalId) clearInterval(advanceIntervalId);
Expand Down
24 changes: 12 additions & 12 deletions testing/time_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
assertStrictEquals,
assertThrows,
} from "@std/assert";
import { FakeTime, TimeError } from "./time.ts";
import { FakeTime } from "./time.ts";
import { _internals } from "./_time.ts";
import { assertSpyCall, spy, type SpyCall } from "./mock.ts";
import { deadline, delay } from "@std/async";
Expand Down Expand Up @@ -335,10 +335,10 @@ Deno.test("FakeTime.restoreFor() returns promise that rejected to error in callb
);
});

Deno.test("FakeTime.restoreFor() returns promise that rejected to TimeError if FakeTime is uninitialized", async () => {
Deno.test("FakeTime.restoreFor() returns promise that rejected to ReferenceError if FakeTime is uninitialized", async () => {
await assertRejects(
() => FakeTime.restoreFor(() => {}),
TimeError,
ReferenceError,
"Time is not faked",
);
});
Expand Down Expand Up @@ -661,16 +661,16 @@ Deno.test("Faked timer functions throws when called after FakeTime is restored",
}
assertThrows(
() => fakeSetTimeout(() => {}, 0),
TimeError,
ReferenceError,
"Time is not faked",
);
assertThrows(() => fakeClearTimeout(0), TimeError, "Time is not faked");
assertThrows(() => fakeClearTimeout(0), ReferenceError, "Time is not faked");
assertThrows(
() => fakeSetInterval(() => {}, 0),
TimeError,
ReferenceError,
"Time is not faked",
);
assertThrows(() => fakeClearInterval(0), TimeError, "Time is not faked");
assertThrows(() => fakeClearInterval(0), ReferenceError, "Time is not faked");
});

Deno.test("Faked Date.now returns real time after FakeTime is restored", () => {
Expand Down Expand Up @@ -700,19 +700,19 @@ Deno.test("FakeTime can be constructed with number, Date, or string", () => {
});

Deno.test("FakeTime throws when NaN is provided", () => {
assertThrows(() => new FakeTime(NaN), TimeError, "Invalid start");
assertThrows(() => new FakeTime(NaN), TypeError, "Invalid start");
});

Deno.test("FakeTime.restore() throws when the time is already restored", () => {
const _time = new FakeTime();
FakeTime.restore();
assertThrows(() => FakeTime.restore(), TimeError, "Time is already restored");
assertThrows(() => FakeTime.restore(), TypeError, "Time is already restored");
});

Deno.test("time.restore() throws when the time is already restored", () => {
const time = new FakeTime();
time.restore();
assertThrows(() => time.restore(), TimeError, "Time is already restored");
assertThrows(() => time.restore(), TypeError, "Time is already restored");
});

Deno.test("time.now = N throws when N < time.now", () => {
Expand All @@ -721,8 +721,8 @@ Deno.test("time.now = N throws when N < time.now", () => {
() => {
time.now = 999;
},
Error,
"time cannot go backwards",
RangeError,
"Time cannot go backwards",
);
});

Expand Down