SnowLuma v2.4.2 source snapshot
Dev Build / cleanup (push) Waiting to run
Dev Build / typecheck (push) Waiting to run
Publish MCP to npm / Build, test, and publish MCP (push) Waiting to run
Publish SDK to npm / Build, test, and publish SDK (push) Waiting to run
Sync action catalog to docs / sync (push) Waiting to run
Publish UI to npm / Build and publish UI (push) Waiting to run
Build and Release / preflight (push) Waiting to run
Dev Build / cleanup (push) Waiting to run
Dev Build / typecheck (push) Waiting to run
Publish MCP to npm / Build, test, and publish MCP (push) Waiting to run
Publish SDK to npm / Build, test, and publish SDK (push) Waiting to run
Sync action catalog to docs / sync (push) Waiting to run
Publish UI to npm / Build and publish UI (push) Waiting to run
Build and Release / preflight (push) Waiting to run
This commit is contained in:
commit
fa9c73363d
1367 files changed
+355735
No files matched your search
@@ -0,0 +1,110 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import {
|
||||
buildStatusText,
|
||||
formatUptime,
|
||||
matchesStatusCommand,
|
||||
statusCooldownElapsed,
|
||||
} from '../src/modules/status-command';
|
||||
import type { JsonValue } from '../src/types';
|
||||
|
||||
function textSeg(text: string): JsonValue {
|
||||
return [{ type: 'text', data: { text } }] as unknown as JsonValue;
|
||||
}
|
||||
|
||||
const ANY_TRIGGER = '#sl';
|
||||
|
||||
describe('matchesStatusCommand', () => {
|
||||
it('matches a single text segment equal to the trigger', () => {
|
||||
expect(matchesStatusCommand(textSeg('#sl'), ANY_TRIGGER)).toBe(true);
|
||||
});
|
||||
|
||||
it('is case-insensitive and trims surrounding whitespace', () => {
|
||||
expect(matchesStatusCommand(textSeg('#SL'), ANY_TRIGGER)).toBe(true);
|
||||
expect(matchesStatusCommand(textSeg(' #Sl '), ANY_TRIGGER)).toBe(true);
|
||||
});
|
||||
|
||||
it('matches a bare string (string-format adapters)', () => {
|
||||
expect(matchesStatusCommand('#sl' as unknown as JsonValue, ANY_TRIGGER)).toBe(true);
|
||||
expect(matchesStatusCommand(' #SL ' as unknown as JsonValue, ANY_TRIGGER)).toBe(true);
|
||||
});
|
||||
|
||||
it('does NOT match as a prefix — only exact', () => {
|
||||
expect(matchesStatusCommand(textSeg('#slogan'), ANY_TRIGGER)).toBe(false);
|
||||
expect(matchesStatusCommand(textSeg('#sl help'), ANY_TRIGGER)).toBe(false);
|
||||
});
|
||||
|
||||
it('rejects mixed-segment messages', () => {
|
||||
const mixed = [
|
||||
{ type: 'text', data: { text: '#sl' } },
|
||||
{ type: 'image', data: { file: 'x.png' } },
|
||||
] as unknown as JsonValue;
|
||||
expect(matchesStatusCommand(mixed, ANY_TRIGGER)).toBe(false);
|
||||
});
|
||||
|
||||
it('rejects non-text leading segments and empty/garbage input', () => {
|
||||
expect(
|
||||
matchesStatusCommand(
|
||||
[{ type: 'at', data: { qq: '1' } }] as unknown as JsonValue,
|
||||
ANY_TRIGGER,
|
||||
),
|
||||
).toBe(false);
|
||||
expect(matchesStatusCommand([] as unknown as JsonValue, ANY_TRIGGER)).toBe(false);
|
||||
expect(matchesStatusCommand(undefined, ANY_TRIGGER)).toBe(false);
|
||||
expect(matchesStatusCommand(123 as unknown as JsonValue, ANY_TRIGGER)).toBe(false);
|
||||
});
|
||||
|
||||
it('works with custom trigger words', () => {
|
||||
expect(matchesStatusCommand(textSeg('/status'), '/status')).toBe(true);
|
||||
expect(matchesStatusCommand(textSeg('.ping'), '.ping')).toBe(true);
|
||||
expect(matchesStatusCommand(textSeg('/status'), '#sl')).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('statusCooldownElapsed', () => {
|
||||
it('allows the first reply (no prior timestamp)', () => {
|
||||
expect(statusCooldownElapsed(undefined, 1_000, 5)).toBe(true);
|
||||
});
|
||||
|
||||
it('ignores the cooldown when set to 0 or negative', () => {
|
||||
expect(statusCooldownElapsed(1_000, 1_500, 0)).toBe(true);
|
||||
expect(statusCooldownElapsed(1_000, 1_000, -1)).toBe(true);
|
||||
});
|
||||
|
||||
it('blocks within the window and allows once elapsed', () => {
|
||||
const last = 10_000;
|
||||
expect(statusCooldownElapsed(last, last + 4_999, 5)).toBe(false);
|
||||
expect(statusCooldownElapsed(last, last + 5_000, 5)).toBe(true);
|
||||
expect(statusCooldownElapsed(last, last + 9_999, 5)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('formatUptime', () => {
|
||||
it('drops leading zero units', () => {
|
||||
expect(formatUptime(0)).toBe('0秒');
|
||||
expect(formatUptime(45_000)).toBe('45秒');
|
||||
expect(formatUptime(90_000)).toBe('1分钟 30秒');
|
||||
expect(formatUptime(3_600_000)).toBe('1小时 0分钟');
|
||||
expect(formatUptime((26 * 3600 + 12 * 60) * 1000)).toBe('1天 2小时 12分钟');
|
||||
});
|
||||
|
||||
it('never goes negative', () => {
|
||||
expect(formatUptime(-5_000)).toBe('0秒');
|
||||
});
|
||||
});
|
||||
|
||||
describe('buildStatusText', () => {
|
||||
it('renders version / platform / uptime, no leaked uin or topology', () => {
|
||||
const text = buildStatusText({
|
||||
version: '1.9.3-node',
|
||||
platform: 'linux',
|
||||
arch: 'x64',
|
||||
uptimeMs: 90_000,
|
||||
});
|
||||
expect(text).toContain('SnowLuma');
|
||||
expect(text).toContain('版本: 1.9.3-node');
|
||||
expect(text).toContain('平台: linux-x64');
|
||||
expect(text).toContain('运行时长: 1分钟 30秒');
|
||||
// public-safe: must not echo a uin or connection count
|
||||
expect(text).not.toMatch(/uin|连接|adapter/i);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user