'use strict'; const { test } = require('node:test'); const assert = require('node:assert'); const SC = require('./stats-core'); const at = (y, m, d, h = 12) => new Date(y, m - 1, d, h); const songA = { id: 'aaaaaaaaaaa', title: 'Goodness of God', channel: 'Bethel Music - Topic' }; const songB = { id: 'bbbbbbbbbbb', title: 'Build My Life', channel: 'Housefires' }; test('record accumulates seconds and plays per local day', () => { let s = SC.empty(); s = SC.record(s, songA, 100, true, at(2026, 9, 18)); s = SC.record(s, songA, 50, false, at(2026, 9, 18)); s = SC.record(s, songB, 30, true, at(2026, 9, 19)); assert.deepStrictEqual(s.days['2026-09-18'], { s: 150, p: 1, songs: { aaaaaaaaaaa: 1 } }); assert.strictEqual(s.days['2026-09-19'].p, 1); assert.strictEqual(s.meta.aaaaaaaaaaa.t, 'Goodness of God'); }); test('old days are pruned', () => { let s = SC.empty(); s = SC.record(s, songA, 10, true, at(2024, 1, 1)); s = SC.record(s, songA, 10, true, at(2026, 9, 18)); assert.deepStrictEqual(Object.keys(s.days), ['2026-09-18']); }); test('streak counts consecutive 5-minute days, allowing today to be pending', () => { let s = SC.empty(); for (const d of [10, 11, 12, 15, 16, 17]) s = SC.record(s, songA, 400, true, at(2026, 9, d)); s = SC.record(s, songA, 60, true, at(2026, 9, 18)); // today, under 5 min so far const st = SC.streaks(s, at(2026, 9, 18)); assert.strictEqual(st.current, 3); // 15,16,17 assert.strictEqual(st.best, 3); s = SC.record(s, songA, 400, true, at(2026, 9, 18)); assert.strictEqual(SC.streaks(s, at(2026, 9, 18)).current, 4); }); test('summary: month totals, top artists (Topic stripped), top songs with sparkline, heatmap', () => { let s = SC.empty(); s = SC.record(s, songA, 3600, true, at(2026, 8, 20)); // last month s = SC.record(s, songA, 1800, true, at(2026, 9, 14)); // this month (Mon) s = SC.record(s, songA, 1800, true, at(2026, 9, 17)); s = SC.record(s, songB, 600, true, at(2026, 9, 17)); const sum = SC.summarize(s, at(2026, 9, 18)); assert.strictEqual(sum.thisMonthSec, 4200); assert.strictEqual(sum.lastMonthSec, 3600); assert.strictEqual(sum.totalPlays, 4); assert.strictEqual(sum.songsPlayed, 2); assert.deepStrictEqual(sum.topArtists, [{ name: 'Bethel Music', plays: 2 }, { name: 'Housefires', plays: 1 }]); assert.strictEqual(sum.topSongs[0].title, 'Goodness of God'); assert.strictEqual(sum.topSongs[0].plays, 3); assert.strictEqual(sum.topSongs[0].spark.length, 30); assert.strictEqual(sum.topSongs[0].spark.at(-2), 1); // Sep 17 assert.strictEqual(sum.heat.length, 16); const cur = sum.heat[15]; assert.strictEqual(cur[0].date, '2026-09-14'); // Monday of this week assert.strictEqual(cur[0].minutes, 30); assert.strictEqual(cur[6].future, true); // Sunday Sep 20 hasn't happened assert.strictEqual(sum.peak.day, 'Thursday'); // Sep 17 had 40 min }); test('fmtHours and artistOf', () => { assert.strictEqual(SC.fmtHours(152280), '42h 18m'); assert.strictEqual(SC.fmtHours(600), '10m'); assert.strictEqual(SC.artistOf('BethelVEVO'), 'Bethel'); assert.strictEqual(SC.artistOf(''), 'Unknown'); });