// The drawing of a document against the project it holds, for every file of // the corpus: the same devices in the same order at the same places, Java's // labels, the cables as the export draws them (wireless or not), the // documentation items in the model's render order. import { readdirSync, readFileSync } from 'node:fs'; import { dirname, join } from 'node:path'; import { fileURLToPath } from 'node:url'; import { describe, expect, it } from 'vitest'; import * as Y from 'yjs'; import { stableGeneratedMacAddress } from '@mdg-filius/core'; import { exportProject, openProjectArchive, type ImportedProject } from '@mdg-filius/fls'; import { readProject, topologyView, writeProject } from '../src/index.js'; const corpus = join(dirname(fileURLToPath(import.meta.url)), '../../../corpus'); const files = ['java-examples', 'java-tests', 'ipad-fixtures'].flatMap((folder) => readdirSync(join(corpus, folder)) .filter((name) => name.endsWith('.fls')) .map((name) => join(folder, name)), ); function docOf(file: string, change: (project: ImportedProject) => void = () => {}): Y.Doc { let counter = 0; const project = openProjectArchive(new Uint8Array(readFileSync(join(corpus, file))), () => `00000000-0000-0000-0000-${(0xffff_ffff - ++counter).toString(16).padStart(12, '0')}`); change(project); const doc = new Y.Doc(); writeProject(doc, project); return doc; } describe('the drawing of a document', () => { for (const file of files) { it(file, () => { const doc = docOf(file); const project = readProject(doc); const view = topologyView(doc); expect(view.nodes.map((node) => [node.id, node.kind, node.name, node.x, node.y])).toEqual( project.graph.nodes.map((node) => [node.id, node.kind, node.displayName, node.position.x, node.position.y]), ); expect(view.nodes.map((node) => node.ports)).toEqual(project.graph.nodes.map((node) => node.ports.map((port) => ({ id: port.id, label: port.label })))); expect(view.links.map((link) => [link.id, link.sourceNode, link.sourcePort, link.targetNode, link.targetPort])).toEqual( project.graph.links.map((link) => [link.id, link.sourceNodeId, link.sourcePortId, link.targetNodeId, link.targetPortId]), ); expect(view.links.map((link) => link.wireless)).toEqual(exportProject(project).topology.links.map((link) => link.wireless)); expect(view.docs.map(({ id, kind, x, y, width, height, text, color, font, size, bold, order }) => ({ id, kind, frame: { x, y, width, height }, text, color, fontName: font, fontSize: size, isBold: bold, order }))).toEqual(project.documentationItems); }); } it('draws the Internet of the NAT example as a cloud', () => { const view = topologyView(docOf('java-examples/nat.fls')); expect(view.nodes.filter((node) => node.cloud).map((node) => node.name)).toEqual(['Internet']); }); it("writes a host's label as Java does: its name, address, MAC address or both", () => { const labels = (policy: 'manual' | 'ipAddress' | 'macAddress' | 'ipAndMAC') => { const doc = docOf('java-examples/zwei_rechnernetze_komplett.fls', (project) => { for (const node of project.graph.nodes) node.hostLabelPolicy = policy; }); const project = readProject(doc); const notebook = project.graph.nodes.find((node) => node.displayName === 'Notebook 1.10')!; const view = topologyView(doc); return { label: view.nodes.find((node) => node.id === notebook.id)!.label, mac: notebook.ports[0]!.importedMacAddress ?? stableGeneratedMacAddress(notebook.ports[0]!.id), switchLabel: view.nodes.find((node) => node.kind === 'networkSwitch')!.label }; }; expect(labels('manual').label).toBe('Notebook 1.10'); expect(labels('ipAddress').label).toBe('141.99.1.10'); const { label, mac, switchLabel } = labels('ipAndMAC'); expect(label).toBe(`141.99.1.10 (${mac})`); expect(labels('macAddress').label).toBe(mac); // Only hosts show an address (Host.holeAnzeigeName). expect(switchLabel).toBe('Switch 1'); }); });