repositories / dotfiles
dotfiles
bugabingas dorkfiles
owned by admin
quickshell/nuguland/caldav.test.js
Rawconst assert = require('assert');
const C = require('./caldav.js');
// --- unescapeText: single-pass, must survive adjacent backslashes ---
assert.strictEqual(C.unescapeText('a\\,b'), 'a,b');
assert.strictEqual(C.unescapeText('a\\;b'), 'a;b');
assert.strictEqual(C.unescapeText('line1\\nline2'), 'line1\nline2');
assert.strictEqual(C.unescapeText('back\\\\slash'), 'back\\slash');
assert.strictEqual(C.unescapeText('lit\\\\nslash'), 'lit\\nslash'); // \\ then n => backslash + 'n', NOT newline
// --- decodeXmlEntities ---
assert.strictEqual(C.decodeXmlEntities('a"b&c '), 'a"b&c\r');
// --- unfold: CRLF or LF, strip exactly one WS, keep further spaces ---
assert.deepStrictEqual(C.unfold('AB\r\n CD\r\nEF'), ['ABCD', 'EF']);
assert.deepStrictEqual(C.unfold('AB\n\tCD'), ['ABCD']);
assert.deepStrictEqual(C.unfold('A\r\n B'), ['A B']); // two leading spaces -> one kept
// --- splitLine: first unquoted colon ---
let p = C.splitLine('DTSTART;TZID="A:B":20260101T000000');
assert.strictEqual(p.name, 'DTSTART');
assert.strictEqual(p.value, '20260101T000000');
// --- parseIcs: timed UTC event ---
const timedXml = '@@CAL /p/\t#5b8cff\tVEVENT\n<c:calendar-data>BEGIN:VEVENT\r\nUID:u1\r\nSUMMARY:Picnic\r\nDTSTART:20260622T152500Z\r\nDTEND:20260622T171500Z\r\nEND:VEVENT</c:calendar-data>';
let ev = C.parseIcs(timedXml)[0];
assert.strictEqual(ev.summary, 'Picnic');
assert.strictEqual(ev.cal, '/p/');
assert.strictEqual(ev.color, '#5b8cff');
assert.strictEqual(ev.allDay, false);
assert.strictEqual(ev.startMs, Date.UTC(2026, 5, 22, 15, 25, 0));
assert.strictEqual(ev.endMs, Date.UTC(2026, 5, 22, 17, 15, 0));
// --- parseIcs: all-day event, exclusive DTEND ---
const allDayXml = '@@CAL /p/\t#43c08a\tVEVENT\n<c:calendar-data>BEGIN:VEVENT\nUID:u2\nSUMMARY:Office\nDTSTART;VALUE=DATE:20260602\nDTEND;VALUE=DATE:20260603\nEND:VEVENT</c:calendar-data>';
let ad = C.parseIcs(allDayXml)[0];
assert.strictEqual(ad.allDay, true);
assert.strictEqual(ad.date, '2026-06-02');
assert.strictEqual(ad.endDate, '2026-06-03');
assert.strictEqual(ad.startMs, null);
// --- parseIcs: VTODO task ---
const todoXml = '@@CAL /r/\t#e0a93c\tVTODO\n<c:calendar-data>BEGIN:VTODO\nUID:t1\nSUMMARY:Pay rent\nDUE;VALUE=DATE:20260628\nSTATUS:NEEDS-ACTION\nEND:VTODO</c:calendar-data>';
let td = C.parseIcs(todoXml)[0];
assert.strictEqual(td.kind, 'task');
assert.strictEqual(td.date, '2026-06-28');
assert.strictEqual(td.done, false);
// --- parseIcs: folded SUMMARY + entity + escape end to end ---
const foldXml = '@@CAL /p/\t#fff\tVEVENT\n<c:calendar-data>BEGIN:VEVENT\r\nUID:u3\r\nSUMMARY:Team "sync"\\, part\r\n 2\r\nDTSTART:20260601T090000Z\r\nEND:VEVENT</c:calendar-data>'; // folded: " 2" -> strip one fold-space -> " 2"
let fe = C.parseIcs(foldXml)[0];
assert.strictEqual(fe.summary, 'Team "sync", part 2');
// --- parseIcs: defensive, never throws on garbage ---
assert.deepStrictEqual(C.parseIcs('not xml at all'), []);
assert.deepStrictEqual(C.parseIcs(''), []);
// --- coveredDates: all-day exclusive end spans start..end-1 ---
assert.deepStrictEqual(
C.coveredDates({ allDay: true, date: '2026-06-10', endDate: '2026-06-13' }),
['2026-06-10', '2026-06-11', '2026-06-12']);
// single all-day (no endDate)
assert.deepStrictEqual(C.coveredDates({ allDay: true, date: '2026-06-02', endDate: null }), ['2026-06-02']);
// pathological spans are capped, not allowed to loop forever
assert.strictEqual(C.coveredDates({ allDay: true, date: '2026-01-01', endDate: '2028-01-01' }).length, C.MAX_EVENT_DAYS);
// timed single-day
assert.deepStrictEqual(
C.coveredDates({ allDay: false, startMs: Date.UTC(2026,5,22,15,0), endMs: Date.UTC(2026,5,22,17,0) }).length, 1);
assert.strictEqual(C.isMultiDay({ allDay: true, date: '2026-06-10', endDate: '2026-06-13' }), true);
assert.strictEqual(C.isMultiDay({ allDay: true, date: '2026-06-02', endDate: '2026-06-03' }), false);
// --- buildSegments: a Wed..Fri band in week 0 (grid starts Mon 2026-06-08) ---
const segOut = C.buildSegments(
[{ allDay: true, date: '2026-06-10', endDate: '2026-06-13', color: '#5b8cff', summary: 'Urlaub' }],
'2026-06-08'); // Mon of week containing the 10th
assert.strictEqual(segOut.laneCount, 1);
assert.strictEqual(segOut.segments.length, 1);
let s = segOut.segments[0];
assert.strictEqual(s.row, 0);
assert.strictEqual(s.colStart, 2); // Wed
assert.strictEqual(s.colEnd, 4); // Fri (covers 10,11,12)
assert.strictEqual(s.lane, 0);
assert.strictEqual(s.roundLeft, true);
assert.strictEqual(s.roundRight, true);
// --- buildSegments: week wrap Fri..Mon -> two segments, both inner ends square ---
const wrap = C.buildSegments(
[{ allDay: true, date: '2026-06-12', endDate: '2026-06-16', color: '#e06b9a', summary: 'Messe' }],
'2026-06-08'); // covers 12,13,14,15 -> Fri,Sat,Sun (row0) + Mon (row1)
assert.strictEqual(wrap.segments.length, 2);
const r0 = wrap.segments.find(x => x.row === 0), r1 = wrap.segments.find(x => x.row === 1);
assert.strictEqual(r0.colStart, 4); assert.strictEqual(r0.colEnd, 6);
assert.strictEqual(r0.roundLeft, true); assert.strictEqual(r0.roundRight, false);
assert.strictEqual(r1.colStart, 0); assert.strictEqual(r1.colEnd, 0);
assert.strictEqual(r1.roundLeft, false); assert.strictEqual(r1.roundRight, true);
// --- buildSegments: two overlapping events get distinct lanes ---
const lanes = C.buildSegments([
{ allDay: true, date: '2026-06-09', endDate: '2026-06-12', color: '#aaa', summary: 'A' },
{ allDay: true, date: '2026-06-10', endDate: '2026-06-13', color: '#bbb', summary: 'B' }
], '2026-06-08');
assert.strictEqual(lanes.laneCount, 2);
console.log('caldav.test.js: ALL PASS');