From 746e9f5f795dd16bed8ffce595d056d501d6f448 Mon Sep 17 00:00:00 2001 From: FineArchs Date: Tue, 22 Oct 2024 18:45:14 +0900 Subject: [PATCH] test wip --- src/interpreter/index.ts | 15 ++++- test/interpreter.ts | 117 ++++++++++++++++++++++++++++----------- 2 files changed, 97 insertions(+), 35 deletions(-) diff --git a/src/interpreter/index.ts b/src/interpreter/index.ts index d97ff1b0..d7519968 100644 --- a/src/interpreter/index.ts +++ b/src/interpreter/index.ts @@ -72,12 +72,23 @@ export class Interpreter { } }; - if (this.opts.irqRate < 0) throw new AiScriptHostsideError('IRQ rate must not be negative value'); + if (!((this.opts.irqRate ?? 300) >= 0)) { + throw new AiScriptHostsideError(`Invalid IRQ rate (${this.opts.irqRate}): must be non-negative number`); + } this.irqRate = this.opts.irqRate ?? 300; + + const sleep = (time: number) => ( + (): Promise => new Promise(resolve => setTimeout(resolve, time)) + ); + if (typeof this.opts.irqSleep === 'function') { this.irqSleep = this.opts.irqSleep; + } else if (this.opts.irqSleep === undefined) { + this.irqSleep = sleep(5); + } else if (this.opts.irqSleep >= 0) { + this.irqSleep = sleep(this.opts.irqSleep); } else { - this.irqSleep = (): Promise => new Promise(resolve => setTimeout(resolve, (this.opts.irqSleep ?? 5) as number)); + throw new AiScriptHostsideError('irqSleep must be a function or a positive number.'); } } diff --git a/test/interpreter.ts b/test/interpreter.ts index 17bd0341..dd2127fc 100644 --- a/test/interpreter.ts +++ b/test/interpreter.ts @@ -1,5 +1,5 @@ import * as assert from 'assert'; -import { describe, expect, test } from 'vitest'; +import { describe, expect, test, vi, beforeEach, afterEach } from 'vitest'; import { Parser, Interpreter, values, errors, utils, Ast } from '../src'; let { FN_NATIVE } = values; @@ -116,40 +116,91 @@ describe('error location', () => { }); describe('IRQ', () => { - async function countSleeps(irqRate: number): Promise { - let count = 0; - const interpreter = new Interpreter({}, { - irqRate, - // It's safe only when no massive loop occurs - irqSleep: async () => count++, + describe('irqSleep is function', () => { + async function countSleeps(irqRate: number): Promise { + let count = 0; + const interpreter = new Interpreter({}, { + irqRate, + // It's safe only when no massive loop occurs + irqSleep: async () => count++, + }); + await interpreter.exec(Parser.parse(` + 'Ai-chan kawaii' + 'Ai-chan kawaii' + 'Ai-chan kawaii' + 'Ai-chan kawaii' + 'Ai-chan kawaii' + 'Ai-chan kawaii' + 'Ai-chan kawaii' + 'Ai-chan kawaii' + 'Ai-chan kawaii' + 'Ai-chan kawaii'`)); + return count; + } + + test.concurrent.each([ + [0, 0], + [1, 10], + [2, 5], + [10, 1], + [Infinity, 0], + ])('rate = %d', async (rate, count) => { + return expect(countSleeps(rate)).resolves.toEqual(count); + }); + + test.concurrent.each( + [-1, NaN], + )('rate = %d', async (rate, count) => { + return expect(countSleeps(rate)).rejects.toThrow(AiScriptHostsideError); }); - await interpreter.exec(Parser.parse(` - 'Ai-chan kawaii' - 'Ai-chan kawaii' - 'Ai-chan kawaii' - 'Ai-chan kawaii' - 'Ai-chan kawaii' - 'Ai-chan kawaii' - 'Ai-chan kawaii' - 'Ai-chan kawaii' - 'Ai-chan kawaii' - 'Ai-chan kawaii'`)); - return count; - } - - test.concurrent.each([ - [0, 0], - [1, 10], - [2, 5], - [10, 1], - [Infinity, 0], - ])('rate = %d', async (rate, count) => { - return expect(countSleeps(rate)).resolves.toEqual(count); }); - test.concurrent.each([ - [-1, NaN], - ])('rate = %d', async (rate, count) => { - return expect(countSleeps(rate)).rejects.toThrow(AiScriptHostsideError); + describe('irqSleep is number', () => { + // This function does IRQ 10 times so takes 10 * irqSleep milliseconds in sum when executed. + async function countSleeps(irqSleep: number): Promise { + const interpreter = new Interpreter({}, { + irqRate: 1, + irqSleep, + }); + await interpreter.exec(Parser.parse(` + 'Ai-chan kawaii' + 'Ai-chan kawaii' + 'Ai-chan kawaii' + 'Ai-chan kawaii' + 'Ai-chan kawaii' + 'Ai-chan kawaii' + 'Ai-chan kawaii' + 'Ai-chan kawaii' + 'Ai-chan kawaii' + 'Ai-chan kawaii'`)); + } + + beforeEach(() => { + vi.useFakeTimers(); + }) + + afterEach(() => { + vi.restoreAllMocks(); + }) + + test.concurrent('It ends', async () => { + const countSleepsSpy = vi.fn(countSleeps); + const promise = countSleepsSpy(100); + vi.advanceTimersByTime(1000); + return expect(countSleepsSpy).toHaveResolved(); + }); + + test.concurrent('It takes time', () => { + const countSleepsSpy = vi.fn(countSleeps); + const promise = countSleepsSpy(100); + vi.advanceTimersByTime(900); + return expect(countSleepsSpy).not.toHaveResolved(); + }); + + test.concurrent.each( + [-1, NaN] + )('Invalid number: %d', (time) => { + return expect(countSleeps(time)).rejects.toThrow(AiScriptHostsideError); + }); }); });