test: F3 acceptance — the classroom classics on FILIUS' examples against Java
A web page by its DNS name (internetwork_komplett), an e-mail between two networks through NAT and MX relay (Internet_Komplett_..._DE), a file found and fetched with Gnutella across a router (zwei_rechnernetze_komplett): ExampleRun records frames, tables, program lines and end states; the core plays the same calls and matches card by card. Equal RIP ties take Java's choice, RIP beacons are left out, the search's two connections compared flow by flow. Also: a core test that an equal RIP route from another router neither replaces nor refreshes the route, and nine stale type errors in core tests fixed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -8,12 +8,10 @@
|
||||
// table rows (javaRun.ts, cards by their MAC address from the file), the
|
||||
// calls must return the same, the hosts must end with the same addresses.
|
||||
|
||||
import { readFileSync } from 'node:fs';
|
||||
import { dirname, join } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { interfaceKey, NetworkRuntimeEngine, stableMacAddress, type DnsAddressResolution, type Id, type IPv4DeliveryResult } from '@mdg-filius/core';
|
||||
import { openProjectArchive, projectSnapshot, type ImportedProject } from '../src/index.js';
|
||||
import { projectSnapshot } from '../src/index.js';
|
||||
import { exampleCards, exampleRecording, namesInJavaOrder, openExample } from './exampleRun.js';
|
||||
import {
|
||||
engineText,
|
||||
expectSameCaptures,
|
||||
@@ -21,14 +19,11 @@ import {
|
||||
gaps,
|
||||
javaFrames,
|
||||
withClientPortText,
|
||||
type CaptureCard,
|
||||
type JavaFrame,
|
||||
type JavaTables,
|
||||
type SeenFrame,
|
||||
} from '../../core/test/javaRun.js';
|
||||
|
||||
const here = dirname(fileURLToPath(import.meta.url));
|
||||
const examples = join(here, '../../../corpus/java-examples');
|
||||
const SEED = 14;
|
||||
|
||||
interface JavaRun extends JavaTables {
|
||||
@@ -160,31 +155,19 @@ const JAVA_BUGS: Record<string, (java: JavaRun) => JavaRun> = {
|
||||
},
|
||||
};
|
||||
|
||||
/** Java's names as ScenarioNetwork.fromFile gives them: a repeated name gets #2, #3, … in the file's order. */
|
||||
function namesInJavaOrder(project: ImportedProject): Map<string, Id> {
|
||||
const names = new Map<string, Id>();
|
||||
for (const node of project.graph.nodes) {
|
||||
let name = node.displayName;
|
||||
for (let count = 2; names.has(name); count += 1) name = `${node.displayName}#${count}`;
|
||||
names.set(name, node.id);
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
describe("FILIUS' examples as Java FILIUS runs them", () => {
|
||||
it('corrects Java only where it errs', () => {
|
||||
for (const [name, correct] of Object.entries(JAVA_BUGS)) {
|
||||
const java = JSON.parse(readFileSync(join(here, 'examples', `${name}.java.json`), 'utf8')) as JavaRun;
|
||||
const java = exampleRecording<JavaRun>(name);
|
||||
expect(JSON.stringify(correct(java)), name).not.toBe(JSON.stringify(java));
|
||||
}
|
||||
});
|
||||
|
||||
for (const [name, story] of Object.entries(STORIES)) {
|
||||
it(`${name}: ${story.file}`, () => {
|
||||
const measured = JSON.parse(readFileSync(join(here, 'examples', `${name}.java.json`), 'utf8')) as JavaRun;
|
||||
const measured = exampleRecording<JavaRun>(name);
|
||||
const java = JAVA_BUGS[name]?.(measured) ?? measured;
|
||||
let counter = 0;
|
||||
const project = openProjectArchive(new Uint8Array(readFileSync(join(examples, story.file))), () => `00000000-0000-0000-0000-${(++counter).toString(16).padStart(12, '0')}`);
|
||||
const project = openExample(story.file);
|
||||
const names = namesInJavaOrder(project);
|
||||
const engine = new NetworkRuntimeEngine(SEED);
|
||||
engine.handle({ type: 'start', snapshot: projectSnapshot(project), seed: SEED, initialTimeMilliseconds: 0 });
|
||||
@@ -199,17 +182,7 @@ describe("FILIUS' examples as Java FILIUS runs them", () => {
|
||||
engine.handle({ type: 'advance', toMilliseconds: Math.max(engine.state.currentTimeMilliseconds, last) + 1_000 });
|
||||
|
||||
expect(events.map(([, event]) => event)).toEqual(java.events.map(([, event]) => event));
|
||||
// Each card by its node and index. A card the file has no MAC address for gets one Java rolls at
|
||||
// each load, and the model one derived from its port: Java's stands for the engine's in the texts.
|
||||
const engineMacByJavaMac = new Map<string, string>();
|
||||
const cards: CaptureCard[] = Object.entries(java.cards).map(([mac, card]) => {
|
||||
const [nodeName, index] = card.split('/') as [string, string];
|
||||
const node = project.graph.nodes.find((each) => each.id === names.get(nodeName))!;
|
||||
const port = node.ports[Number(index)]!;
|
||||
engineMacByJavaMac.set(mac.toUpperCase(), (port.importedMacAddress ?? stableMacAddress(port.id)).toUpperCase());
|
||||
return { key: mac, portId: port.id };
|
||||
});
|
||||
const withEngineMacs = (text: string) => text.replace(/[0-9A-Fa-f]{2}(:[0-9A-Fa-f]{2}){5}/g, (mac) => engineMacByJavaMac.get(mac.toUpperCase()) ?? mac);
|
||||
const { cards, withEngineMacs } = exampleCards(project, names, java.cards);
|
||||
const javaStoryStart = java.events[0]?.[0];
|
||||
if (story.storyStart !== undefined) {
|
||||
expectSameCaptures(engine, cards, java.frames, {
|
||||
|
||||
Reference in New Issue
Block a user