import assert from 'node:assert/strict' import { test } from 'node:test' import type { TgUpdateRaw } from './telegram.ts' import { classifyInbound, mayHide, toTgMessage } from './telegram.ts' const BOT = { id: 42, username: 'will_bot' } function msg( partial: Partial[0]>, ): Parameters[0] { return { updateId: 1, messageId: 10, chatId: -100, date: 1700000000, ...partial, } } test('mention of the bot wakes', () => { const m = msg({ text: 'hey @will_bot look at this', entities: [{ type: 'mention', offset: 4, length: 9 }], }) assert.deepEqual(classifyInbound(m, BOT.id, BOT.username), { wake: true, reason: 'mention' }) }) test('reply to the bot wakes', () => { const m = msg({ text: 'nice', replyToSenderId: BOT.id, replyToMessageId: 9 }) assert.equal(classifyInbound(m, BOT.id, BOT.username).reason, 'reply') }) test('ordinary chatter never wakes', () => { const m = msg({ text: 'just talking among friends' }) assert.deepEqual(classifyInbound(m, BOT.id, BOT.username), { wake: false, reason: 'none' }) }) test('mention inside a reply of someone else does not wake', () => { const m = msg({ text: 'someone else @other_bot', entities: [{ type: 'mention', offset: 14, length: 10 }], replyToSenderId: 7, }) assert.equal(classifyInbound(m, BOT.id, BOT.username).wake, false) }) test('/hide via reply is deterministic, never wakes the model', () => { const m = msg({ text: '/hide', replyToMessageId: 55 }) const c = classifyInbound(m, BOT.id, BOT.username) assert.equal(c.wake, false) assert.deepEqual(c.hide, { targetMessageId: 55 }) }) test('/hide with explicit id targets that id', () => { const m = msg({ text: '/hide 123' }) assert.deepEqual(classifyInbound(m, BOT.id, BOT.username).hide, { targetMessageId: 123 }) }) test('other commands wake', () => { const m = msg({ text: '/status' }) assert.deepEqual(classifyInbound(m, BOT.id, BOT.username), { wake: true, reason: 'command' }) }) test('caption mention on media wakes', () => { const m = msg({ caption: '@will_bot what is this', media: [{ kind: 'photo', fileId: 'f1' }], entities: [{ type: 'mention', offset: 0, length: 9 }], }) assert.equal(classifyInbound(m, BOT.id, BOT.username).reason, 'mention') }) test('sender of the target or oliver may hide', () => { assert.equal(mayHide({ targetSenderId: '7', requesterId: '7', oliverId: '1' }), true) assert.equal(mayHide({ targetSenderId: '7', requesterId: '8', oliverId: '1' }), false) assert.equal(mayHide({ targetSenderId: '7', requesterId: '1', oliverId: '1' }), true) }) test('toTgMessage extracts largest photo and documents', () => { const raw: TgUpdateRaw = { update_id: 5, message: { message_id: 11, date: 1, chat: { id: -100 }, from: { id: 9, username: 'friend' }, photo: [ { file_id: 'small', width: 1, height: 1 }, { file_id: 'big', width: 2, height: 2 }, ], caption: 'pic', }, } const m = toTgMessage(raw) assert.ok(m) assert.equal(m.media?.length, 1) assert.equal(m.media?.[0]?.fileId, 'big') assert.equal(m.senderName, 'friend') })