Skip to content

Commit 567bf61

Browse files
the-homeless-godMarat Zimnurov
authored andcommitted
Корпус сверки перестал зависеть от чужого домашнего каталога
Два теста ядра — core-json и core-parser — подхватывали модели из /home/m/projects/courses/static/fts/models/ по факту существования каталога. Охват молча менялся от машины к машине: 56 моделей здесь, 47 на чистом клоне, и в выводе теста это никак не отражалось. Из-за этого я публиковал «побайтовое совпадение на 56 моделях из 56» — утверждение, которое у читателя не воспроизводится. Внешний корпус теперь подключается только переменной FTS_MODEL_PATH, списком каталогов через разделитель PATH — как FTS_TOOLCHAIN_PATH рядом. Автоподхвата не осталось. Проверка переменной стоит на верхнем уровне модуля, а не внутри сборки корпуса, и это не стилистика: при ленивой проверке битый путь давал «прошло 38, упало 1» — половина сверки успевала отчитаться об успехе на урезанном корпусе, и ошибку снова было бы легко проглядеть. Теперь битая переменная роняет загрузку файла до объявления первого теста. Негодность переменной — падение с внятным текстом: нет каталога, файл вместо каталога, каталог без единой модели. Хвостовой разделитель ошибкой не считается. Охват виден в имени теста, а не в тихой диагностике: «47 моделей: только репозиторий, внешний корпус не подключён» против «56 моделей: репозиторий 47 + внешние 9 (FTS_MODEL_PATH)». Печатается и «моделей N из M файлов» — если каталог даст файлы, но не даст моделей, это будет видно. Числа в core/SPEC.md заменены с «56 из 56» на воспроизводимые «47 из 47» с оговоркой про переменную; FTS_MODEL_PATH описана в README рядом с остальными. Проверено в обоих режимах: 1267 тестов без внешнего корпуса, 1285 с ним, 0 падений. Разница ровно 18 = 2 × 9 моделей.
1 parent 5a4dedd commit 567bf61

4 files changed

Lines changed: 209 additions & 54 deletions

File tree

flang/core/SPEC.md

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -247,8 +247,11 @@
247247
произвольному значению и по вложенному утверждению убывает по полю варианта и
248248
элементу коллекции, то есть доказывается обычным правилом.
249249

250-
Дифференциальная сверка (раздел 5) на всех `.fts` репозитория и внешнего
251-
каталога моделей: 56 моделей, ноль расхождений с `JSON.stringify(compile(…))`.
250+
Дифференциальная сверка (раздел 5) на всех `.fts` репозитория: **47 моделей из
251+
47**, ноль расхождений с `JSON.stringify(compile(…))`. Это число воспроизводится
252+
на чистом клоне и ни от чего вне репозитория не зависит; подключение внешних
253+
каталогов моделей (`FTS_MODEL_PATH`, см. `flang/test/corpus.mjs`) охват
254+
увеличивает — фактический печатает сам тест, первой же строкой вывода.
252255
Проверка — `flang/test/core-json.test.mjs`.
253256

254257
Расхождения и отступления, оставленные сознательно:
@@ -391,8 +394,11 @@
391394
`totality.mjs`.
392395

393396
Сквозная сверка (раздел 5) — `текст → лексер → парсер → печать JSON` против
394-
`JSON.stringify(compile(…))`: **56 моделей из 56, ноль расхождений**, обе
395-
поверхности. Диагностики сверены отдельно: на 34 намеренно сломанных моделях
397+
`JSON.stringify(compile(…))`: **47 моделей из 47, ноль расхождений**, обе
398+
поверхности. Число — репозиторное, воспроизводимое на чистом клоне; внешние
399+
каталоги моделей подключаются переменной `FTS_MODEL_PATH` и охват увеличивают,
400+
а фактический охват прогона тест печатает сам.
401+
Диагностики сверены отдельно: на 34 намеренно сломанных моделях
396402
отступной поверхности и на 13 моделях скобочной совпадают и код, и текст
397403
сообщения. Проверка — `flang/test/core-parser.test.mjs`.
398404

flang/test/core-json.test.mjs

Lines changed: 21 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22
* Печать документа FTS в JSON на flang (`flang/core/json.flang`).
33
*
44
* Главная проверка здесь одна и она дифференциальная: для каждой модели `.fts`
5-
* репозитория (и внешнего каталога моделей, если он есть) документ, полученный
6-
* настоящим ядром на TypeScript (`compile` из `dist/`), печатается функцией
7-
* «Печать документа» — и обязан совпасть с `JSON.stringify` того же документа
8-
* **побайтово**. Не «эквивалентный JSON», а тот же байт: порядок ключей,
9-
* экранирование, запись чисел (flang/core/SPEC.md, раздел 5).
5+
* репозитория (и внешних каталогов, если они перечислены в `FTS_MODEL_PATH`)
6+
* документ, полученный настоящим ядром на TypeScript (`compile` из `dist/`),
7+
* печатается функцией «Печать документа» — и обязан совпасть с `JSON.stringify`
8+
* того же документа **побайтово**. Не «эквивалентный JSON», а тот же байт:
9+
* порядок ключей, экранирование, запись чисел (flang/core/SPEC.md, раздел 5).
1010
*
1111
* Документ ядра — это обычный JSON, а значения flang — записи и варианты сумм,
1212
* поэтому между ними стоит перевод (`документ` и его помощники ниже). Перевод
@@ -20,18 +20,16 @@
2020
* списки, вложенность. Оракул везде один и тот же — `JSON.stringify`.
2121
*/
2222
import assert from "node:assert/strict"
23-
import { existsSync, readFileSync } from "node:fs"
23+
import { readFileSync } from "node:fs"
2424
import test from "node:test"
25-
import { fileURLToPath } from "node:url"
2625

2726
import { valuesEqual } from "../src/builtins.mjs"
2827
import { evaluate } from "../src/interpret.mjs"
2928
import { parse } from "../src/parser.mjs"
3029
import { checkTotality } from "../src/totality.mjs"
3130
import { checkTypes } from "../src/types.mjs"
32-
import { globSync } from "./glob.mjs"
31+
import { строкиОхвата, текстМодели, файлыКорпуса } from "./corpus.mjs"
3332

34-
const root = fileURLToPath(new URL("../..", import.meta.url))
3533
const source = readFileSync(new URL("../core/json.flang", import.meta.url), "utf8")
3634
const program = parse(source, "json.flang")
3735
const types = checkTypes(program)
@@ -619,46 +617,42 @@ test("документ: кириллица и кавычки в именах н
619617
/* ─────────────────── дифференциальная сверка на моделях ─────────────────── */
620618

621619
/**
622-
* Корпус: все `.fts` репозитория плюс внешний каталог моделей, если он есть на
623-
* машине. Внешний каталог не обязателен — тест не имеет права зависеть от
624-
* чужого рабочего дерева, поэтому проверяется существование.
620+
* Корпус: все `.fts` репозитория плюс модели из каталогов, явно перечисленных
621+
* в `FTS_MODEL_PATH`. Состав корпуса и его источники печатаются ниже отдельным
622+
* тестом: охват сверки обязан быть виден в выводе, а не подразумеваться
623+
* (почему именно так — `flang/test/corpus.mjs`).
625624
*/
626625
function модели() {
627-
const пути = globSync("**/*.fts", { cwd: root, exclude: (path) => path.includes("node_modules") })
628-
.sort()
629-
.map((path) => ({ имя: path, путь: root + path }))
630-
const внешний = "/home/m/projects/courses/static/fts/models/"
631-
if (existsSync(внешний)) {
632-
for (const path of globSync("*.fts", { cwd: внешний }).sort()) {
633-
пути.push({ имя: `courses/${path}`, путь: внешний + path })
634-
}
635-
}
636-
637626
const найденные = []
638-
for (const { имя, путь } of пути) {
639-
const текст = readFileSync(путь, "utf8")
627+
for (const запись of файлы) {
628+
const текст = текстМодели(запись)
640629
let тело = текст
641630
try {
642631
/* Файлы `tools/**` начинаются с заголовка `модуль …`, которого ядро не
643632
знает; файлы-функторы документами FTS не являются вовсе. */
644-
const разобранный = parseModuleFile(текст, имя)
633+
const разобранный = parseModuleFile(текст, запись.имя)
645634
if (разобранный.kind !== "module") continue
646635
тело = разобранный.body
647636
} catch {
648637
continue
649638
}
650639
try {
651-
найденные.push({ имя, документ: core.compile(тело) })
640+
найденные.push({ имя: запись.имя, источник: запись.источник, документ: core.compile(тело) })
652641
} catch {
653642
/* Не документ ядра (другой диалект, намеренно сломанная модель). */
654643
}
655644
}
656645
return найденные
657646
}
658647

648+
const файлы = файлыКорпуса()
659649
const корпус = модели()
650+
const охват = строкиОхвата(корпус, файлы)
660651

661-
test("корпус моделей найден", () => {
652+
/* Число моделей стоит прямо в имени теста, источники — в диагностике: по
653+
выводу должно быть видно, каким был охват именно этого прогона. */
654+
test(`корпус моделей найден — ${охват[0]}`, (t) => {
655+
for (const строка of охват) t.diagnostic(строка)
662656
assert.ok(корпус.length >= 40, `моделей: ${корпус.length}`)
663657
})
664658

flang/test/core-parser.test.mjs

Lines changed: 20 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22
* Парсер ядра FTS на flang — `flang/core/parser.flang`.
33
*
44
* Главная проверка здесь одна и она сквозная: для каждой модели `.fts`
5-
* репозитория (и внешнего каталога моделей, если он есть) строится вся цепочка
6-
* ядра на flang — текст → лексер (`core/lexer.flang`) → парсер
7-
* (`core/parser.flang`) → печать JSON (`core/json.flang`) — и результат обязан
5+
* репозитория (и внешних каталогов, если они перечислены в `FTS_MODEL_PATH`)
6+
* строится вся цепочка ядра на flang — текст → лексер (`core/lexer.flang`) →
7+
* парсер (`core/parser.flang`) → печать JSON (`core/json.flang`) — и результат обязан
88
* совпасть с `JSON.stringify(compile(текст))` настоящего ядра на TypeScript
99
* **побайтово**. Критерий готовности из `flang/core/SPEC.md`, раздел 5: ядро
1010
* верно не тогда, когда проходят его собственные тесты. Сверяются обе
@@ -21,7 +21,7 @@
2121
* всех видов в утверждении скобочной поверхности.
2222
*/
2323
import assert from "node:assert/strict"
24-
import { existsSync, readFileSync } from "node:fs"
24+
import { readFileSync } from "node:fs"
2525
import test from "node:test"
2626
import { fileURLToPath } from "node:url"
2727

@@ -31,9 +31,8 @@ import { linkProgram } from "../src/link.mjs"
3131
import { parse } from "../src/parser.mjs"
3232
import { checkTotality } from "../src/totality.mjs"
3333
import { checkTypes } from "../src/types.mjs"
34-
import { globSync } from "./glob.mjs"
34+
import { строкиОхвата, текстМодели, файлыКорпуса } from "./corpus.mjs"
3535

36-
const root = fileURLToPath(new URL("../..", import.meta.url))
3736
const файл = fileURLToPath(new URL("../core/parser.flang", import.meta.url))
3837
const исходник = readFileSync(файл, "utf8")
3938

@@ -455,24 +454,16 @@ for (const [имя, src] of Object.entries(СЛОМАННЫЕ_СКОБКИ)) {
455454
/* ─────────────────── сквозная сверка на моделях репозитория ─────────────── */
456455

457456
/**
458-
* Корпус тот же, что у печати JSON: все `.fts` репозитория плюс внешний
459-
* каталог моделей, если он есть на машине. Внешний каталог не обязателен —
460-
* тест не имеет права зависеть от чужого рабочего дерева.
457+
* Корпус тот же, что у печати JSON: все `.fts` репозитория плюс модели из
458+
* каталогов, явно перечисленных в `FTS_MODEL_PATH`. Охват печатается ниже
459+
* отдельным тестом — по выводу должно быть видно, сколько моделей проверено и
460+
* откуда они взяты (почему это обязательно — `flang/test/corpus.mjs`).
461461
*/
462462
function модели() {
463-
const пути = globSync("**/*.fts", { cwd: root, exclude: (path) => path.includes("node_modules") })
464-
.sort()
465-
.map((path) => ({ имя: path, путь: root + path }))
466-
const внешний = "/home/m/projects/courses/static/fts/models/"
467-
if (existsSync(внешний)) {
468-
for (const path of globSync("*.fts", { cwd: внешний }).sort()) {
469-
пути.push({ имя: `courses/${path}`, путь: внешний + path })
470-
}
471-
}
472-
473463
const найденные = []
474-
for (const { имя, путь } of пути) {
475-
const текст = readFileSync(путь, "utf8")
464+
for (const запись of файлы) {
465+
const { имя, источник } = запись
466+
const текст = текстМодели(запись)
476467
let тело = текст
477468
try {
478469
/* Файлы `tools/**` начинаются с заголовка `модуль …`, которого ядро не
@@ -494,16 +485,22 @@ function модели() {
494485
каждого диалекта: сверка для обоих одна и та же — побайтовая. */
495486
const первая = тело.replace(/^/u, "").split(/\r?\n/u).map((строка) => строка.trim()).find((строка) => строка.length > 0 && !строка.startsWith("//"))
496487
const натуральная = /^(?:категория|category)(?:\s|$)/u.test(первая ?? "") && !(первая ?? "").includes("{")
497-
найденные.push({ имя, тело, документ, натуральная })
488+
найденные.push({ имя, источник, тело, документ, натуральная })
498489
}
499490
return найденные
500491
}
501492

493+
const файлы = файлыКорпуса()
502494
const корпус = модели()
503495
const натуральные = корпус.filter(({ натуральная }) => натуральная)
504496
const скобочные = корпус.filter(({ натуральная }) => !натуральная)
497+
const охват = строкиОхвата(корпус, файлы)
505498

506-
test("корпус моделей найден, и обе поверхности в нём есть", () => {
499+
/* Число моделей стоит прямо в имени теста, источники — в диагностике: по
500+
выводу должно быть видно, каким был охват именно этого прогона. */
501+
test(`корпус моделей найден, и обе поверхности в нём есть — ${охват[0]}`, (t) => {
502+
for (const строка of охват) t.diagnostic(строка)
503+
t.diagnostic(` поверхности: натуральных ${натуральные.length}, скобочных ${скобочные.length}`)
507504
assert.ok(корпус.length >= 40, `моделей: ${корпус.length}`)
508505
assert.ok(натуральные.length >= 40, `натуральных моделей: ${натуральные.length}`)
509506
assert.ok(скобочные.length >= 3, `скобочных моделей: ${скобочные.length}`)

0 commit comments

Comments
 (0)