143 lines
5.9 KiB
JavaScript
143 lines
5.9 KiB
JavaScript
import test from "node:test";
|
||
import assert from "node:assert/strict";
|
||
import { readFileSync } from "node:fs";
|
||
import { parseDocx, parseWord } from "../server/parser.js";
|
||
import { decodeListing, fileMetadata } from "../server/source.js";
|
||
const fixture = (name) =>
|
||
readFileSync(new URL(`./fixtures/${name}.docx`, import.meta.url));
|
||
const fef = () => parseDocx(fixture("fef-23-ba"), { name: "23-ЛГ_23-БА.docx" });
|
||
test("ФЭФ: 23-БА не получает дисциплины 23-ЛГ", () => {
|
||
const s = fef(),
|
||
ba = s.lessons.filter((l) => l.groups.includes("23-БА"));
|
||
assert.deepEqual(s.groups, ["23-ЛГ", "23-БА"]);
|
||
assert.equal(ba.length, 33);
|
||
assert.ok(ba.some((l) => l.subject === "Бизнес-анализ"));
|
||
assert.ok(
|
||
!ba.some((l) =>
|
||
/логистик|Экспедирование|Управление запасами/i.test(l.subject),
|
||
),
|
||
);
|
||
assert.ok(
|
||
s.lessons
|
||
.filter((l) => l.groups.includes("23-ЛГ"))
|
||
.some((l) => /Финансовая логистика/.test(l.subject)),
|
||
);
|
||
});
|
||
test("ФЭФ: общая ячейка принадлежит обеим группам", () => {
|
||
const shared = fef().lessons.filter((l) =>
|
||
l.subject.startsWith("Единый день информирования"),
|
||
);
|
||
assert.equal(shared.length, 1);
|
||
assert.deepEqual(shared[0].groups, ["23-ЛГ", "23-БА"]);
|
||
assert.match(shared[0].raw, /15 октября/);
|
||
assert.equal(shared[0].start, "13:40");
|
||
});
|
||
test("ФЭФ: варианты недель, цвет, преподаватель и аудитория сохранены", () => {
|
||
const s = fef();
|
||
const lessons = s.lessons.filter(
|
||
(l) =>
|
||
l.day === 4 &&
|
||
l.groups.includes("23-БА") &&
|
||
l.subject === "Бизнес-анализ",
|
||
);
|
||
assert.deepEqual(
|
||
lessons.map((l) => [l.condition, l.variant, l.room, l.teacher]),
|
||
[
|
||
["7,9,11н.", "upper", "430", "Войтенок Ж.Е."],
|
||
["4-12н", "lower", "430", "Войтенок Ж.Е."],
|
||
],
|
||
);
|
||
assert.equal(lessons[1].sourceColor, "CCFFCC");
|
||
assert.equal(lessons[0].start, "10:05");
|
||
assert.equal(lessons[0].end, "11:30");
|
||
const plan = s.lessons.find(
|
||
(l) =>
|
||
l.subject === "Бизнес-планирование" && l.start === "11:45" && l.day === 4,
|
||
);
|
||
assert.equal(plan.condition, "1-8,10-17");
|
||
assert.ok(s.warnings.length);
|
||
});
|
||
test("ФЭФ: кураторский час в 16.50 не становится невозможной датой", () => {
|
||
const l = fef().lessons.find(
|
||
(l) =>
|
||
l.groups.includes("23-БА") &&
|
||
l.day === 1 &&
|
||
l.subject.includes("кураторский"),
|
||
);
|
||
assert.equal(l.start, "16:50");
|
||
assert.equal(l.end, null);
|
||
assert.equal(l.date, null);
|
||
assert.equal(l.condition, "");
|
||
for (const lesson of fef().lessons)
|
||
if (lesson.date)
|
||
assert.ok(Number.isFinite(new Date(lesson.date).getTime()));
|
||
});
|
||
test("ФЭФ: объединённое занятие не дублируется на зелёной строке", () => {
|
||
const s = fef();
|
||
const l = s.lessons.filter(
|
||
(l) =>
|
||
l.day === 2 &&
|
||
l.groups.includes("23-БА") &&
|
||
l.subject === "Управление проектами" &&
|
||
l.start === "15:20",
|
||
);
|
||
assert.equal(l.length, 1);
|
||
assert.equal(l[0].variant, "all");
|
||
});
|
||
test("Дневные таблицы четырёх факультетов распознаются со своими группами", () => {
|
||
for (const [name, groups] of [
|
||
["fit-daily", ["24-ИТ-1", "24-ИТ-2"]],
|
||
["fkne-daily", ["24-КБ", "24-КФ"]],
|
||
["isf-daily", ["26-ПГС-1", "26-ПГС-2"]],
|
||
["gf-daily", ["25-РГФ-1", "25-РГФ-2"]],
|
||
]) {
|
||
const s = parseDocx(fixture(name), { name });
|
||
assert.deepEqual(s.groups, groups);
|
||
assert.ok(s.lessons.length > 20);
|
||
assert.ok(
|
||
s.lessons.every(
|
||
(l) => l.day >= 1 && l.day <= 7 && /^\d{2}:\d{2}$/.test(l.start),
|
||
),
|
||
);
|
||
assert.ok(
|
||
s.lessons.every((l) => l.groups.every((g) => groups.includes(g))),
|
||
);
|
||
}
|
||
});
|
||
test("Сессии: отдельные колонки времени, аудитории и преподавателя", () => {
|
||
const s = parseDocx(fixture("fit"), { name: "26-ИТзс.docx" }),
|
||
l = s.lessons[0];
|
||
assert.deepEqual(s.groups, ["26-ИТзс"]);
|
||
assert.equal(l.date, "2026-09-17");
|
||
assert.equal(l.start, "11:00");
|
||
assert.equal(l.end, "11:30");
|
||
assert.equal(l.teacher, "Петрович О.Н.");
|
||
assert.equal(l.room, "220Д");
|
||
assert.deepEqual(l.subgroups, []);
|
||
assert.match(l.raw, /Петрович/);
|
||
assert.equal(s.period, "Установочная сессия");
|
||
const f = parseDocx(fixture("fkne"), {});
|
||
assert.deepEqual(f.groups, ["26-ЭЭТзс"]);
|
||
assert.ok(f.lessons.every((l) => l.date));
|
||
});
|
||
test("Импорт отклоняет повреждённые и посторонние файлы", async () => {
|
||
assert.throws(() => parseDocx(Buffer.from("broken")), /повреждён/);
|
||
await assert.rejects(
|
||
() => parseWord(Buffer.from("not a word file")),
|
||
/настоящий файл Word/,
|
||
);
|
||
});
|
||
test("DAV: метаданные вложенных документов и только доверенный каталог", () => {
|
||
const xml = `<d:multistatus xmlns:d="DAV:"><d:response><d:href>/public.php/dav/files/no5zKbMrns6j5jQ/2026-2027/</d:href><d:propstat><d:prop><d:resourcetype><d:collection/></d:resourcetype></d:prop><d:status>HTTP/1.1 200 OK</d:status></d:propstat></d:response><d:response><d:href>https://evil.example/file.docx</d:href></d:response></d:multistatus>`;
|
||
const entries = decodeListing(xml);
|
||
assert.equal(entries.length, 1);
|
||
assert.equal(entries[0].folder, true);
|
||
const metadata = JSON.parse(
|
||
readFileSync(new URL("./fixtures/fef-23-ba.docx.json", import.meta.url)),
|
||
);
|
||
const file = fileMetadata(metadata);
|
||
assert.equal(file.faculty, "Финансово-экономический факультет");
|
||
assert.equal(file.course, "4 курс");
|
||
assert.equal(file.name, "23-ЛГ_23-БА.docx");
|
||
});
|