Skip to content

Commit

Permalink
Fixes'n'tests.
Browse files Browse the repository at this point in the history
  • Loading branch information
DirtyHairy committed Sep 2, 2022
1 parent 413dfd6 commit 40e917f
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 5 deletions.
5 changes: 4 additions & 1 deletion src/Semaphore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,12 @@ class Semaphore implements SemaphoreInterface {
if (!queueEntry) continue;

This comment has been minimized.

Copy link
@AkatQuas

AkatQuas Sep 19, 2022

Contributor

Brilliant design.

Would you mind explaining the implementation _dispatch and the weight / _value calculation in line 73/74 ?


const previousValue = this._value;
const previousWeight = weight;

this._value -= weight;
weight = this._value + 1;

queueEntry.resolve([previousValue, this._newReleaser(weight)]);
queueEntry.resolve([previousValue, this._newReleaser(previousWeight)]);
}

this._drainUnlockWaiters();
Expand Down
4 changes: 2 additions & 2 deletions src/withTimeout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@ export function withTimeout(sync: MutexInterface | SemaphoreInterface, timeout:
}
},

release(): void {
sync.release();
release(weight?: number): void {
sync.release(weight);
},

cancel(): void {
Expand Down
71 changes: 70 additions & 1 deletion test/semaphore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,27 @@ export const semaphoreSuite = (factory: (maxConcurrency: number, err?: Error) =>
assert.strictEqual(value, 2);
});

test('release is idempotent', async () => {
test('a semaphore can be initialized to negative values', async () => {
semaphore = factory(-2);

let value: number | undefined = undefined;
semaphore.acquire().then(([x]) => {
value = x;
});

await clock.tickAsync(0);
assert.strictEqual(value, undefined);

semaphore.release(2);
await clock.tickAsync(0);
assert.strictEqual(value, undefined);

semaphore.release(2);
await clock.tickAsync(0);
assert.strictEqual(value, 2);
});

test('the releaser is idempotent', async () => {
const values: Array<number> = [];

semaphore.acquire().then(([value, release]) => {
Expand Down Expand Up @@ -115,6 +135,20 @@ export const semaphoreSuite = (factory: (maxConcurrency: number, err?: Error) =>
assert.deepStrictEqual(values.sort(), [1, 1, 1, 2]);
});

test('the releaser increments by the correct weight', async () => {
await semaphore.acquire(2);
assert.strictEqual(semaphore.getValue(), 0);

semaphore.release(2);
assert.strictEqual(semaphore.getValue(), 2);

await semaphore.acquire();
assert.strictEqual(semaphore.getValue(), 1);

semaphore.release();
assert.strictEqual(semaphore.getValue(), 2);
});

test('runExclusive passes semaphore value', async () => {
let value = -1;

Expand Down Expand Up @@ -191,6 +225,14 @@ export const semaphoreSuite = (factory: (maxConcurrency: number, err?: Error) =>
assert(flag);
});

test('runExclusive passes the correct weight', async () => {
semaphore.runExclusive(() => undefined, 2);
assert.strictEqual(semaphore.getValue(), 0);

await clock.runAllAsync();
assert.strictEqual(semaphore.getValue(), 2);
});

test('new semaphore is unlocked', () => {
assert(!semaphore.isLocked());
});
Expand Down Expand Up @@ -220,6 +262,33 @@ export const semaphoreSuite = (factory: (maxConcurrency: number, err?: Error) =>
assert(!semaphore.isLocked());
});

test("getValue returns the Semaphore's value", () => {
assert.strictEqual(semaphore.getValue(), 2);
semaphore.acquire();

assert.strictEqual(semaphore.getValue(), 1);
});

test('setValue sets the semaphore value and runs all applicable waiters', async () => {
semaphore = factory(0);

let flag1 = false;
let flag2 = false;
let flag3 = false;

semaphore.acquire(1).then(() => (flag1 = true));
semaphore.acquire(2).then(() => (flag2 = true));
semaphore.acquire(4).then(() => (flag3 = true));

semaphore.setValue(3);

await clock.runAllAsync();

assert.strictEqual(flag1, true);
assert.strictEqual(flag2, true);
assert.strictEqual(flag3, false);
});

test('the release method releases a locked semaphore', async () => {
semaphore = factory(1);

Expand Down
2 changes: 1 addition & 1 deletion test/withTimeout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { mutexSuite } from './mutex';
import { semaphoreSuite } from './semaphore';
import { withTimeout } from '../src/withTimeout';

suite('waitFor', () => {
suite('withTimeout', () => {
suite('Mutex', () => {
suite('timeout behavior', () => {
let clock: InstalledClock;
Expand Down

0 comments on commit 40e917f

Please sign in to comment.