import test from "node:test"; import assert from "node:assert/strict"; import { readFileSync } from "node:fs"; import { parseDocx } from "../server/parser.js"; import { parseWeeksDocx, parseBellsDocx } from "../server/calendar.js"; import { parseWeekRanges, parseTextDates, lessonWeeks, lessonDates, dateInWeek, weekIndexOf, todayIso, } from "../shared/weeks.js"; const fixture = (name) => readFileSync(new URL(`./fixtures/${name}.docx`, import.meta.url)); const calendar = { weeks: parseWeeksDocx(fixture("weeks")), bells: parseBellsDocx(fixture("bells")), }; const fef = () => parseDocx(fixture("fef-23-ba"), { name: "23-ЛГ_23-БА.docx" }).lessons.filter( (l) => l.groups.includes("23-БА"), ); test("Таблица недель: 18 недель, нечётные белые, неделя 1 со вторника", () => { const { weeks } = calendar; assert.equal(weeks.length, 18); assert.deepEqual(weeks[0], { n: 1, start: "2026-09-01", end: "2026-09-06", color: "white", }); assert.deepEqual(weeks.at(-1), { n: 18, start: "2026-12-28", end: "2027-01-03", color: "green", }); assert.ok(weeks.every((w) => (w.n % 2 ? "white" : "green") === w.color)); assert.equal(dateInWeek(weeks[0], 1), null); assert.equal(dateInWeek(weeks[0], 2), "2026-09-01"); assert.equal(weekIndexOf(calendar, "2026-10-16"), 6); assert.equal(weekIndexOf(calendar, "2027-02-01"), -1); assert.equal(todayIso(new Date("2026-10-15T22:30:00Z")), "2026-10-16"); }); test("Звонки: восемь пар с половинами", () => { assert.equal(calendar.bells.length, 8); assert.deepEqual(calendar.bells[1], { pair: 2, start: "10:05", end: "11:30", halves: [ ["10:05", "10:45"], ["10:50", "11:30"], ], }); }); test("Пометки недель: диапазоны, «с N», опечатки остаются для сверки", () => { assert.deepEqual(parseWeekRanges("1-4,6-11н."), [ [1, 4], [6, 11], ]); assert.deepEqual(parseWeekRanges("со 2 нед."), [[2, null]]); assert.deepEqual(parseWeekRanges("1-4н.;6-12н."), [[1, 4], [6, 12]]); assert.deepEqual(parseWeekRanges("1-6н , 13-18н"), [[1, 6], [13, 18]]); assert.deepEqual(parseWeekRanges("с 4-16н"), [[4, 16]]); assert.deepEqual(parseWeekRanges("1-8,10-17"), [ [1, 8], [10, 17], ]); assert.equal(parseWeekRanges("2,6-12-16н"), null); assert.equal(parseWeekRanges("26.10"), null); assert.equal(parseWeekRanges(""), null); }); test("Цвет строки ограничивает диапазон чётностью недели", () => { const white = { day: 2, date: null, condition: "13-17н", variant: "upper" }; const green = { day: 4, date: null, condition: "4-12н", variant: "lower" }; const every = { day: 5, date: null, condition: "6-13н", variant: "all" }; const plain = { day: 1, date: null, condition: "", variant: "lower" }; assert.deepEqual(lessonWeeks(white, 18), [13, 15, 17]); assert.deepEqual(lessonWeeks(green, 18), [4, 6, 8, 10, 12]); assert.deepEqual(lessonWeeks(every, 18), [6, 7, 8, 9, 10, 11, 12, 13]); assert.deepEqual(lessonWeeks(plain, 18), [2, 4, 6, 8, 10, 12, 14, 16, 18]); assert.equal( lessonWeeks({ ...white, condition: "2,6-12-16н" }, 18), null, ); assert.deepEqual(lessonDates(every, calendar).slice(0, 2), [ "2026-10-09", "2026-10-16", ]); }); test("Парсер: 23-БА получает номера недель и даты дня информирования", () => { const lessons = fef(); const friday = lessons.filter((l) => l.day === 5 && l.start === "10:05"); assert.deepEqual( friday.map((l) => l.weekRanges), [[[1, 4], [6, 11]], [[12, 15]], [[16, 16]]], ); const week7 = friday.filter((l) => lessonWeeks(l, 18).includes(7)); assert.deepEqual( week7.map((l) => l.subject), ["PR-менеджмент"], ); const info = lessons.find((l) => l.subject.startsWith("Единый день информирования"), ); assert.deepEqual(info.dates, [ "2026-09-10", "2026-10-15", "2026-11-19", "2026-12-17", ]); assert.deepEqual(parseTextDates("17 декабря и 14 января", 2026), [ "2026-12-17", "2027-01-14", ]); // Every coloured-row mark in the real document agrees with the week table. for (const l of lessons.filter((l) => l.variant !== "all" && l.weekRanges)) for (const [a, b] of l.weekRanges) for (const n of [a, b ?? a]) assert.equal(n % 2, l.variant === "upper" ? 1 : 0, l.raw); }); test("Даты числами: «10.09;15.10;19.11;17.12», но не время пары", () => { // ИСФ пишет дни информирования списком дат, как в 23-АРХ. assert.deepEqual(parseTextDates("Единый день информирования 10.09;15.10;19.11;17.12", 2026), [ "2026-09-10", "2026-10-15", "2026-11-19", "2026-12-17", ]); assert.deepEqual(parseTextDates("03.10, 17.10. Физика", 2026), ["2026-10-03", "2026-10-17"]); assert.deepEqual(parseTextDates("12.01.2027; 19.01.2027 Экзамен", 2026), ["2027-01-12", "2027-01-19"]); // One number pair alone or a time range is a time, not a date. for (const time of ["10.05 Лекция", "10.05-11.30", "16.50 Информационный час", "09.11 по 06.12 практика"]) assert.deepEqual(parseTextDates(time, 2026), [], time); });