One row per frame (its highest layer's), Java's detail tree, the table as Java's text file, "Tabellen löschen" for every card (clearCapture in the room), a tab per card with Java's title, Java's layer colours as tokens, the chosen frame and autoscroll per tab. New oracle ExchangeWindowRun. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
79 lines
4.1 KiB
TypeScript
79 lines
4.1 KiB
TypeScript
// What the data exchange window writes of a frame in the viewer's language:
|
|
// Java's words of both bundles, the locale's numbers ("1.000.000" in German,
|
|
// "1,000,000" in English), the time of day with milliseconds, the row of the
|
|
// highest layer, the details from the layered rows, the text file.
|
|
|
|
import { describe, expect, it } from 'vitest';
|
|
import { captureRows, TCP_FLAG, type CapturedFrame, type EthernetFrame } from '@mdg-filius/core';
|
|
import type { TraceFrame } from '@mdg-filius/protocol';
|
|
import { translate } from '../src/i18n/i18n.js';
|
|
import { captureWords, exportText, frameCells, frameDetails } from '../src/simulation/captureCells.js';
|
|
|
|
/** A TCP segment with data from 10.0.0.1:50000 to 10.0.0.2:80, as the room sends it. */
|
|
function frame(number: number, timeMilliseconds: number): TraceFrame {
|
|
const ethernet: EthernetFrame = {
|
|
identity: number,
|
|
sourceMacAddress: '02:00:00:00:00:01',
|
|
destinationMacAddress: '02:00:00:00:00:02',
|
|
payload: {
|
|
kind: 'ipv4',
|
|
packet: {
|
|
identity: 9,
|
|
senderIPAddress: '10.0.0.1',
|
|
receiverIPAddress: '10.0.0.2',
|
|
timeToLive: 64,
|
|
protocol: 'tcp',
|
|
payload: {
|
|
kind: 'tcp',
|
|
segment: {
|
|
sourcePort: 50_000,
|
|
destinationPort: 80,
|
|
sequenceNumber: 2_000_001,
|
|
acknowledgementNumber: 1_000_001,
|
|
flags: TCP_FLAG.acknowledgement,
|
|
payload: new TextEncoder().encode('GET / HTTP/1.1\nHost: x\n'),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
};
|
|
const captured: CapturedFrame[] = [{ number, timeMilliseconds, frame: ethernet }];
|
|
return { number, rows: captureRows(captured, { withAddresses: true }), layeredRows: captureRows(captured, { withAddresses: false }) };
|
|
}
|
|
|
|
const words = (language: 'de' | 'en') => captureWords((key) => translate(language, key), language);
|
|
const clock = new Date(2026, 9, 4, 8, 30, 0, 0).getTime();
|
|
|
|
describe("the data exchange window's cells", () => {
|
|
it("writes a frame's row by its highest layer, in either language", () => {
|
|
expect(frameCells(frame(3, 1_234), clock, words('de'))).toEqual(['3', '08:30:01.234', '10.0.0.1:50000', '10.0.0.2:80', 'HTTP', 'Anwendung', 'GET / HTTP/1.1\nHost: x\n']);
|
|
expect(frameCells(frame(3, 1_234), clock, words('en'))).toEqual(['3', '08:30:01.234', '10.0.0.1:50000', '10.0.0.2:80', 'HTTP', 'Application', 'GET / HTTP/1.1\nHost: x\n']);
|
|
expect(words('de').header).toEqual(['Nr.', 'Zeit', 'Quelle', 'Ziel', 'Protokoll', 'Schicht', 'Bemerkungen / Details']);
|
|
expect(words('en').header).toEqual(['No.', 'Time', 'Source', 'Destination', 'Protocol', 'Layer', 'Comment / Details']);
|
|
});
|
|
|
|
it("writes the details with the locale's numbers and Java's words", () => {
|
|
const german = frameDetails(frame(3, 0), clock, words('de')).map((line) => line.text);
|
|
expect(german[0]).toBe('Nr.: 3 / Zeit: 08:30:00.000');
|
|
expect(german).toContain('Bemerkungen / Details: SEQ: 2.000.001, ACK: 1.000.001');
|
|
expect(german).toContain('Bemerkungen / Details: Protokoll: 6, TTL: 64');
|
|
expect(german).toContain('Bemerkungen / Details (23 Bytes): ');
|
|
const english = frameDetails(frame(3, 0), clock, words('en')).map((line) => line.text);
|
|
expect(english[0]).toBe('No.: 3 / Time: 08:30:00.000');
|
|
expect(english).toContain('Comment / Details: SEQ: 2,000,001, ACK: 1,000,001');
|
|
expect(english).toContain('Comment / Details: Protocol: 6, TTL: 64');
|
|
expect(frameDetails({ number: 1, rows: [], layeredRows: [] }, clock, words('de'))).toEqual([]);
|
|
});
|
|
|
|
it('exports the table with the words of its header', () => {
|
|
const text = exportText([frame(1, 0), frame(2, 5)], clock, words('en'));
|
|
expect(text.split('\r\n')[1]).toBe(
|
|
`| No. | Time | Source | Destination | Protocol | Layer | ${'Comment / Details'.padEnd(40)} | `,
|
|
);
|
|
expect(text.split('\r\n')[3]).toBe(
|
|
`| 1 | 08:30:00.000 | 10.0.0.1:50000 | 10.0.0.2:80 | HTTP | Application | ${'GET / HTTP/1.1 Host: x'.padEnd(40)} | `,
|
|
);
|
|
expect(text.match(/^\+-/gm)).toHaveLength(2);
|
|
});
|
|
});
|