feat(fls): DHCP, static NAT and modem settings as Java loads them
readSystemSoftware adds the DHCP client switch and server settings of every IP stack, a home router's static NAT table (port forwarding) and a modem's mode, port and address. All 23 corpus files match Java. Static DHCP assignments follow setStaticAssignedAddresses: each entry is split at Java whitespace (the same 25 characters as Character.isWhitespace, measured over the BMP), and an entry without MAC and IP ends the list, as Java throws there. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -7,7 +7,15 @@ import { readdirSync, readFileSync, statSync } from 'node:fs';
|
||||
import { dirname, join, relative } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { decodeJavaBeans, readFlsArchive, readTopology, type FlsNodeClass, type FlsTopology } from '../src/index.js';
|
||||
import {
|
||||
decodeJavaBeans,
|
||||
readFlsArchive,
|
||||
readTopology,
|
||||
type FlsDhcpServer,
|
||||
type FlsModem,
|
||||
type FlsNodeClass,
|
||||
type FlsTopology,
|
||||
} from '../src/index.js';
|
||||
|
||||
const corpusRoot = join(dirname(fileURLToPath(import.meta.url)), '../../../corpus');
|
||||
const javaView = JSON.parse(readFileSync(join(corpusRoot, 'corpus.java.json'), 'utf8')) as Record<string, unknown>;
|
||||
@@ -34,6 +42,23 @@ const TYPE_LABELS: Record<FlsNodeClass, string> = {
|
||||
Modem: 'Modem',
|
||||
};
|
||||
|
||||
/** Java's property names, as FlsOracle.java writes them. */
|
||||
function javaDhcpServer(server: FlsDhcpServer) {
|
||||
return {
|
||||
aktiv: server.isActive,
|
||||
untergrenze: server.lowerBound,
|
||||
obergrenze: server.upperBound,
|
||||
gatewayip: server.gateway,
|
||||
dnsserverip: server.dnsServer,
|
||||
ownSettings: server.useOwnSettings,
|
||||
staticAssignedAddresses: server.staticAssignedAddresses.map((entry) => `${entry.mac} ${entry.ip}`),
|
||||
};
|
||||
}
|
||||
|
||||
function javaModem(modem: FlsModem) {
|
||||
return { mode: modem.mode, port: modem.port, ipAdresse: modem.ipAddress };
|
||||
}
|
||||
|
||||
/** The topology in the shape FlsOracle.java writes, less what Swing computes (label width and height). */
|
||||
function asJavaView(topology: FlsTopology, javaBounds: (number[] | null)[]) {
|
||||
return {
|
||||
@@ -53,6 +78,12 @@ function asJavaView(topology: FlsTopology, javaBounds: (number[] | null)[]) {
|
||||
system: {
|
||||
...node.system,
|
||||
...('ssid' in node.system ? { ssid: node.system.ssid ?? null } : {}),
|
||||
...(node.system.dhcpServer === undefined
|
||||
? {}
|
||||
: {
|
||||
dhcpServer: javaDhcpServer(node.system.dhcpServer),
|
||||
}),
|
||||
...(node.system.modem === undefined ? {} : { modem: javaModem(node.system.modem) }),
|
||||
...(node.system.firewall === undefined
|
||||
? {}
|
||||
: {
|
||||
@@ -235,6 +266,49 @@ describe('readTopology rules', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('splits static DHCP assignments at Java whitespace and stops where Java throws', () => {
|
||||
// U+3000 separates, U+00A0 does not; the third entry has no IP, so Java
|
||||
// throws there and the fourth is never read.
|
||||
const { nodes, warnings } = topologyOf(`<object class="java.util.LinkedList">${nodeItem(`<object class="filius.hardware.knoten.Rechner">
|
||||
<void property="systemSoftware"><void property="DHCPServer">
|
||||
<void property="staticAssignedAddresses"><object class="java.util.ArrayList">
|
||||
<void method="add"><string>0A:00:00:00:00:01<char code="#3000"/>10.0.0.1<char code="#9"/>extra</string></void>
|
||||
<void method="add"><string>0A:00:00:00:00:02 10.0.0.2<char code="#A0"/>x</string></void>
|
||||
<void method="add"><string>0A:00:00:00:00:03</string></void>
|
||||
<void method="add"><string>0A:00:00:00:00:04 10.0.0.4</string></void>
|
||||
</object></void>
|
||||
</void></void></object>`)}</object>`);
|
||||
|
||||
expect(nodes[0]!.system.dhcpServer).toEqual({
|
||||
isActive: false,
|
||||
lowerBound: '0.0.0.0',
|
||||
upperBound: '0.0.0.0',
|
||||
gateway: '0.0.0.0',
|
||||
dnsServer: '0.0.0.0',
|
||||
useOwnSettings: false,
|
||||
staticAssignedAddresses: [
|
||||
{ mac: '0A:00:00:00:00:01', ip: '10.0.0.1' },
|
||||
{ mac: '0A:00:00:00:00:02', ip: '10.0.0.2\u00A0x' },
|
||||
],
|
||||
});
|
||||
expect(warnings).toEqual([
|
||||
'node 1: DHCPServer: static assignment "0A:00:00:00:00:03" has no MAC and IP; Java stops reading here',
|
||||
]);
|
||||
});
|
||||
|
||||
it("gives a modem Java's defaults and keeps an address the file sets to null", () => {
|
||||
const { nodes } = topologyOf(`<object class="java.util.LinkedList">
|
||||
${nodeItem('<object class="filius.hardware.knoten.Modem"/>')}
|
||||
${nodeItem(`<object class="filius.hardware.knoten.Modem"><void property="systemSoftware">
|
||||
<void property="ipAdresse"><null/></void><void property="mode"><int>1</int></void>
|
||||
</void></object>`)}</object>`);
|
||||
|
||||
expect(nodes.map((node) => node.system.modem)).toEqual([
|
||||
{ mode: 2, port: 12_345, ipAddress: 'localhost' },
|
||||
{ mode: 1, port: 12_345, ipAddress: null },
|
||||
]);
|
||||
});
|
||||
|
||||
it("reads colors as Java's constructors do and keeps an invalid one unset", () => {
|
||||
const colors = ['<int>16711935</int>', '<int>1</int><int>2</int><int>3</int>', '<int>1</int><int>2</int><int>300</int><int>4</int>'];
|
||||
const { documentation, warnings } = topologyOf(`<object class="java.util.LinkedList"/><object class="java.util.LinkedList"/>
|
||||
|
||||
Reference in New Issue
Block a user