From 8ed04423b07a5b66b65646931436d618ee0a167f Mon Sep 17 00:00:00 2001 From: Alisue Date: Tue, 13 Aug 2024 16:03:40 +0900 Subject: [PATCH] feat(semaphore): throw `RangeError` for invalid `size` --- semaphore.ts | 8 +++-- semaphore_test.ts | 78 +++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 81 insertions(+), 5 deletions(-) diff --git a/semaphore.ts b/semaphore.ts index 0c90f93..3aba954 100644 --- a/semaphore.ts +++ b/semaphore.ts @@ -23,11 +23,13 @@ export class Semaphore { * Creates a new semaphore with the specified limit. * * @param size The maximum number of times the semaphore can be acquired before blocking. - * @throws Error if the size is less than 1. + * @throws {RangeError} if the size is not a positive safe integer. */ constructor(size: number) { - if (size < 0) { - throw new Error("The size must be greater than 0"); + if (size <= 0 || !Number.isSafeInteger(size)) { + throw new RangeError( + `size must be a positive safe integer, got ${size}`, + ); } this.#rest = size + 1; } diff --git a/semaphore_test.ts b/semaphore_test.ts index 9b21457..85be7ce 100644 --- a/semaphore_test.ts +++ b/semaphore_test.ts @@ -1,9 +1,9 @@ -import { assertEquals } from "@std/assert"; +import { assertEquals, assertThrows } from "@std/assert"; import { Semaphore } from "./semaphore.ts"; Deno.test("Semaphore", async (t) => { await t.step( - "regulates the number of workers concurrently running", + "regulates the number of workers concurrently running (n=5)", async () => { let nworkers = 0; const results: number[] = []; @@ -32,4 +32,78 @@ Deno.test("Semaphore", async (t) => { ]); }, ); + + await t.step( + "regulates the number of workers concurrently running (n=1)", + async () => { + let nworkers = 0; + const results: number[] = []; + const sem = new Semaphore(1); + const worker = () => { + return sem.lock(async () => { + nworkers++; + results.push(nworkers); + await new Promise((resolve) => setTimeout(resolve, 10)); + nworkers--; + }); + }; + await Promise.all([...Array(10)].map(() => worker())); + assertEquals(nworkers, 0); + assertEquals(results, [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + ]); + }, + ); + + await t.step( + "regulates the number of workers concurrently running (n=10)", + async () => { + let nworkers = 0; + const results: number[] = []; + const sem = new Semaphore(10); + const worker = () => { + return sem.lock(async () => { + nworkers++; + results.push(nworkers); + await new Promise((resolve) => setTimeout(resolve, 10)); + nworkers--; + }); + }; + await Promise.all([...Array(10)].map(() => worker())); + assertEquals(nworkers, 0); + assertEquals(results, [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + ]); + }, + ); + + await t.step( + "throws RangeError if size is not a positive safe integer", + () => { + assertThrows(() => new Semaphore(NaN), RangeError); + assertThrows(() => new Semaphore(Infinity), RangeError); + assertThrows(() => new Semaphore(-Infinity), RangeError); + assertThrows(() => new Semaphore(-1), RangeError); + assertThrows(() => new Semaphore(1.1), RangeError); + assertThrows(() => new Semaphore(0), RangeError); + }, + ); });