test.web/core/converters/grammar.converter.test.ts
test.web/core/converters/grammar.converter.test.ts is a file in Codebase Testing. 93 lines of code and 0 definitions.
import { describe, expect, it } from "vitest";
import {
joinRules,
keywordsOf,
productionsOf,
templateBodyOf,
templateConstraintsOf,
} from "@banes-lab/web/core/converters/grammar.converter.ts";
import {
missingKeywordCategory,
missingProductionGroup,
missingTemplate,
} from "@banes-lab/web/configuration/strings/report.strings.ts";
import { ONTOLOGY } from "@banes-lab/web/core/generated/ontology.generated.ts";
const FIRST = { grammar: "<a> ::= b", title: "First" };
const SECOND = { grammar: "<c> ::= d", title: "Second" };
const firstOf = function firstOf<T>(items: readonly T[]): T {
const [first] = items;
if (first === undefined) {
throw new Error("The snapshot's grammar carries no records.");
}
return first;
};
describe("joinRules", () => {
it("prefixes each rule with a heading and separates rules by a blank line", () => {
expect(joinRules([FIRST, SECOND])).toBe(
`# ${FIRST.title}\n${FIRST.grammar}\n\n# ${SECOND.title}\n${SECOND.grammar}`,
);
});
it("yields an empty string for no rules", () => {
expect(joinRules([])).toBe("");
});
});
describe("keywordsOf", () => {
it("reads one category of the snapshot's grammar into a keyword block, the role's meaning as description", () => {
const category = firstOf(ONTOLOGY.grammar.categories);
const keyword = firstOf(category.keywords);
const block = keywordsOf(category.category);
expect(block.kind).toBe("keyword");
expect(block.keywords[0]).toStrictEqual({
description: keyword.roles[0].meaning,
example: keyword.roles[0].example,
name: keyword.name,
});
});
it("lists a keyword under every category it plays a role in", () => {
const shared = ONTOLOGY.grammar.categories
.flatMap((group) => group.keywords)
.find((keyword) => keyword.roles.length > 1);
expect(shared).toBeDefined();
for (const role of shared?.roles ?? []) {
const names = keywordsOf(role.category).keywords.map((entry) =>
typeof entry === "string" ? entry : entry.name,
);
expect(names).toContain(shared?.name);
}
});
it("lists a category's own keywords first and the further roles of other keywords after them", () => {
const names = keywordsOf("contextual").keywords.map((entry) =>
typeof entry === "string" ? entry : entry.name,
);
expect(names.indexOf("INTO")).toBeLessThan(names.indexOf("FOR"));
expect(names.slice(-4)).toStrictEqual(["FOR", "IN", "FROM", "TO"]);
});
it("refuses a category no keyword plays a role in", () => {
expect(() => keywordsOf("no-such-category")).toThrow(missingKeywordCategory("no-such-category"));
});
});
describe("productionsOf", () => {
it("renders one production group as BNF lines under the given title", () => {
const group = firstOf(ONTOLOGY.grammar.groups);
const production = firstOf(group.productions);
const rule = productionsOf(group.group, "Title");
const lines = rule.grammar.split("\n");
expect(rule.title).toBe("Title");
expect(lines).toHaveLength(group.productions.length);
expect(lines[0]).toBe(`<${production.lhs}> ::= ${production.rhs}`);
});
it("refuses a group the snapshot does not carry", () => {
expect(() => productionsOf("no-such-group", "Title")).toThrow(missingProductionGroup("no-such-group"));
});
});
describe("templateBodyOf and templateConstraintsOf", () => {
it("read the body and the constraints of a template record by type", () => {
const template = firstOf(ONTOLOGY.grammar.templates);
expect(templateBodyOf(template.type)).toBe(template.body);
expect(templateConstraintsOf(template.type)).toStrictEqual(template.constraints);
});
it("refuse a type the snapshot does not carry", () => {
expect(() => templateBodyOf("NO_SUCH_TYPE")).toThrow(missingTemplate("NO_SUCH_TYPE"));
expect(() => templateConstraintsOf("NO_SUCH_TYPE")).toThrow(missingTemplate("NO_SUCH_TYPE"));
});
});