import { test } from 'node:test'; import assert from 'node:assert/strict'; import fs from 'node:fs'; import os from 'node:os'; import path from 'node:path'; import type { ChatMessage } from '#shared/events.ts'; import { migrate } from './index.ts'; import { repos } from './repos.ts'; import { DatabaseSync } from 'node:sqlite'; function freshDb() { const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'abdulive-test-')); const db = new DatabaseSync(path.join(dir, 't.db')); db.exec('PRAGMA foreign_keys = ON'); migrate(db); return { db, repo: repos(db), dir }; } function msg(over: Partial = {}): ChatMessage { return { id: `m-${Math.random().toString(36).slice(2)}`, ts: '2026-09-09T20:00:00.000Z', userId: '42', login: 'maxi_2k', displayName: 'maxi_2k', text: 'moin', emotes: [], isFirst: false, isReturning: false, isCommand: false, isMod: false, isSub: false, isBroadcaster: false, bits: 0, color: null, ...over, }; } test('legt Nutzer an und zaehlt Nachrichten', () => { const { db, repo } = freshDb(); repo.openStream('s1', '2026-09-09T19:00:00.000Z'); repo.recordMessage(msg(), 's1'); repo.recordMessage(msg({ text: 'zweite' }), 's1'); const user = db.prepare('SELECT * FROM users WHERE id = ?').get('42') as { message_count: number; login: string; first_seen_at: string }; assert.equal(user.message_count, 2); assert.equal(user.login, 'maxi_2k'); const n = db.prepare('SELECT COUNT(*) AS n FROM chat_messages').get() as { n: number }; assert.equal(n.n, 2); }); test('Namenswechsel erhaelt die Historie', () => { const { db, repo } = freshDb(); repo.openStream('s1', '2026-09-09T19:00:00.000Z'); repo.recordMessage(msg(), 's1'); // Gleiche user-id, neuer Login - so sieht eine Twitch-Namensaenderung aus repo.recordMessage(msg({ login: 'maxi_neu', displayName: 'Maxi_Neu' }), 's1'); const rows = db.prepare('SELECT * FROM users').all() as Array<{ login: string; message_count: number }>; assert.equal(rows.length, 1, 'darf keinen zweiten Nutzer angelegt haben'); assert.equal(rows[0]!.login, 'maxi_neu'); assert.equal(rows[0]!.message_count, 2); }); test('zaehlt Streams, an denen jemand geschrieben hat', () => { const { repo } = freshDb(); repo.openStream('s1', '2026-09-09T19:00:00.000Z'); repo.openStream('s2', '2026-09-10T19:00:00.000Z'); assert.equal(repo.recordMessage(msg(), 's1').streamsChatted, 1); assert.equal(repo.recordMessage(msg(), 's1').streamsChatted, 1); assert.equal(repo.recordMessage(msg(), 's2').streamsChatted, 2); }); test('doppelte Nachrichten-IDs werden nicht zweimal gespeichert', () => { const { db, repo } = freshDb(); repo.openStream('s1', '2026-09-09T19:00:00.000Z'); const m = msg({ id: 'immer-gleich' }); repo.recordMessage(m, 's1'); repo.recordMessage(m, 's1'); const n = db.prepare('SELECT COUNT(*) AS n FROM chat_messages').get() as { n: number }; assert.equal(n.n, 1); }); test('Zuschauerzahlen setzen den Hoechststand', () => { const { repo } = freshDb(); repo.openStream('s1', '2026-09-09T19:00:00.000Z'); repo.sample('s1', '2026-09-09T19:01:00.000Z', 8); repo.sample('s1', '2026-09-09T19:02:00.000Z', 17); repo.sample('s1', '2026-09-09T19:03:00.000Z', 11); assert.equal(repo.getStream('s1')?.peak_viewers, 17); }); test('offene Sitzung wird gefunden und geschlossen', () => { const { repo } = freshDb(); repo.openStream('s1', '2026-09-09T19:00:00.000Z'); assert.equal(repo.latestOpenStream()?.id, 's1'); repo.closeStream('s1', '2026-09-09T22:00:00.000Z'); assert.equal(repo.latestOpenStream(), undefined); }); test('erneutes openStream ueberschreibt eine laufende Sitzung nicht', () => { const { repo } = freshDb(); repo.openStream('s1', '2026-09-09T19:00:00.000Z'); repo.openStream('s1', '2026-09-09T21:00:00.000Z'); assert.equal(repo.getStream('s1')?.started_at, '2026-09-09T19:00:00.000Z'); }); test('Nachrichten ohne laufenden Stream gehen trotzdem nicht verloren', () => { const { db, repo } = freshDb(); repo.recordMessage(msg(), null); const row = db.prepare('SELECT stream_id FROM chat_messages').get() as { stream_id: string | null }; assert.equal(row.stream_id, null); }); test('unique_chatters zaehlt Personen, nicht Nachrichten', () => { const { repo } = freshDb(); repo.openStream('s1', '2026-09-09T19:00:00.000Z'); repo.recordMessage(msg({ userId: '1', login: 'a' }), 's1'); repo.recordMessage(msg({ userId: '1', login: 'a' }), 's1'); repo.recordMessage(msg({ userId: '2', login: 'b' }), 's1'); assert.equal(repo.getStream('s1')?.unique_chatters, 2); });