feat(fls): write the file systems of a .fls, loaded by Java as the original
topologyWriter.ts adds each node's file tree to the root its constructor makes, as XMLEncoder does (arbeitsVerzeichnis, files as new Datei(name, typ, inhalt)); a root of its own is set anew. The reader now reads the files of routers and home routers too: their constructor makes files from templates (the web interface), and the file adds to them (a web server's www.conf). systemSoftware.ts keeps what the file adds, and templateFiles says whether the constructor's files stay in front (false when the file sets a root of its own). The topology test finds our part at the end of Java's tree and the template in front, the same for every router of a class across the corpus. Checked by Java against Java: every corpus file, read and written again, loads with the same file systems as the original. The synthetic topology adds a nested tree with a renamed root, a nameless directory, a file without type, content with CR, CRLF and beyond-BMP characters, router files after the template and a home router with a root of its own. 9 mutation probes, each loaded by Java, were all caught. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -11,11 +11,12 @@
|
||||
// table (port forwarding) and a modem's connection settings.
|
||||
// Java counterparts as well: filius.software.dhcp.DHCPServer, ModemFirmware.
|
||||
//
|
||||
// And the file system of a PC or notebook: Java's tree of
|
||||
// DefaultMutableTreeNodes, a directory's user object its name, a file's a
|
||||
// filius.software.system.Datei. Routers and home routers have files too, but
|
||||
// Java's constructor makes them from its own templates (the start page of
|
||||
// the firewall's web interface); they are not in the file.
|
||||
// And the file system: Java's tree of DefaultMutableTreeNodes, a
|
||||
// directory's user object its name, a file's a filius.software.system.Datei.
|
||||
// A PC's or notebook's constructor leaves the root empty. A router's or home
|
||||
// router's makes files from its own templates (the start page of the
|
||||
// firewall's web interface), which are not in the file; what the file adds
|
||||
// to that root (a web server's www.conf) comes after them.
|
||||
//
|
||||
// Checked against Java (corpus.java.json, `system`). Applications are a
|
||||
// later layer.
|
||||
@@ -198,8 +199,17 @@ export interface FlsSystemSoftware {
|
||||
modem?: FlsModem;
|
||||
/** Rechner, Notebook: the installed applications, in the file's order. */
|
||||
applications?: FlsApplication[];
|
||||
/** Rechner, Notebook: the root directory (named "root" by Java's constructor). */
|
||||
/**
|
||||
* Every node with an IP stack: the root directory (named "root" by Java's
|
||||
* constructor) as the file has it. A router's or home router's holds only
|
||||
* what the file adds to the constructor's, see `templateFiles`.
|
||||
*/
|
||||
fileSystem?: FlsFileTree;
|
||||
/**
|
||||
* Vermittlungsrechner, Gateway: whether the files the constructor makes
|
||||
* stay in front of the file's — false when the file sets a root of its own.
|
||||
*/
|
||||
templateFiles?: boolean;
|
||||
}
|
||||
|
||||
type Warn = (message: string) => void;
|
||||
@@ -231,6 +241,10 @@ export function readSystemSoftware(device: JavaObject, javaClass: FlsNodeClass,
|
||||
case 'Modem':
|
||||
break;
|
||||
}
|
||||
if (javaClass === 'Vermittlungsrechner' || javaClass === 'Gateway') {
|
||||
result.fileSystem = fileSystem(value('dateisystem'), warn);
|
||||
result.templateFiles = constructedRoot(value('dateisystem'));
|
||||
}
|
||||
if (javaClass !== 'Switch' && javaClass !== 'Modem') {
|
||||
result.manualRoutes = manualRoutes(value('weiterleitungstabelle'), warn);
|
||||
result.dhcpClient = boolean(value('DHCPKonfiguration'), false, 'DHCPKonfiguration', warn);
|
||||
@@ -343,12 +357,23 @@ function applications(map: JavaValue | undefined, root: FlsFileTree, warn: Warn)
|
||||
* file makes with `new DefaultMutableTreeNode()` has no user object.
|
||||
*/
|
||||
function fileSystem(system: JavaValue | undefined, warn: Warn): FlsFileTree {
|
||||
const at = (property: string) => (isJavaObject(system) ? system.properties.get(property) : undefined);
|
||||
const root = at('root') ?? at('arbeitsVerzeichnis');
|
||||
const root = fileSystemRoot(system);
|
||||
if (root === undefined) return { kind: 'directory', name: 'root', children: [] };
|
||||
return fileTreeNode(root, true, warn);
|
||||
}
|
||||
|
||||
function fileSystemRoot(system: JavaValue | undefined): JavaValue | undefined {
|
||||
const at = (property: string) => (isJavaObject(system) ? system.properties.get(property) : undefined);
|
||||
return at('root') ?? at('arbeitsVerzeichnis');
|
||||
}
|
||||
|
||||
/** Whether the root is the one the constructor made: none set, or reached through the getter. */
|
||||
function constructedRoot(system: JavaValue | undefined): boolean {
|
||||
if (system !== undefined && !(isJavaObject(system) && system.fromGetter)) return false;
|
||||
const root = fileSystemRoot(system);
|
||||
return root === undefined || (isJavaObject(root) && root.fromGetter);
|
||||
}
|
||||
|
||||
function fileTreeNode(node: JavaValue, constructorRoot: boolean, warn: Warn): FlsFileTree {
|
||||
if (!isJavaObject(node)) {
|
||||
warn(`file system: a node is ${describe(node)}, left empty`);
|
||||
|
||||
Reference in New Issue
Block a user