按规划继续工作

结论:补齐 LinuxCNC tooldata_common.cc 随机换刀器 load/save 验证边界,WASM/SDK/OPFS 只透传 random-toolchanger 配置;native、WASM、OPFS 和浏览器 smoke 验证已通过。
This commit is contained in:
2026-06-08 08:39:26 +08:00
parent a16f3605fa
commit 3f4eb06b47
12 changed files with 211 additions and 28 deletions

View File

@@ -243,17 +243,21 @@ restore/save behavior through the exported C ABI, including out-of-order file
rejection, missing-file success, required numeric parameter writeback, removal rejection, missing-file success, required numeric parameter writeback, removal
of named-parameter-only lines from saved output, and the `.bak` backup produced of named-parameter-only lines from saved output, and the `.bak` backup produced
by vendored `save_parameters()`. It also covers LinuxCNC tool-table by vendored `save_parameters()`. It also covers LinuxCNC tool-table
load/save behavior through vendored `tooldata_common.cc`, with the SDK only load/save behavior through vendored `tooldata_common.cc`, including the
copying text into the Emscripten filesystem and calling the exported C ABI. non-random and random-toolchanger `tooldata_init()` branches, with the SDK
only copying text into the Emscripten filesystem and calling the exported C
ABI.
OPFS validation covers the JavaScript host-boundary adapter, the INI browser OPFS validation covers the JavaScript host-boundary adapter, the INI browser
smoke harness, the INI panel UI's machine-session load and G-code run buttons, smoke harness, the INI panel UI's machine-session load and G-code run buttons,
the raw canonical-event display fed directly by LinuxCNC interpreter WASM the raw canonical-event display fed directly by LinuxCNC interpreter WASM
output, the Node parameter/tool-table bridges that copy OPFS text through the output, the Node parameter/tool-table bridges that copy OPFS text through the
SDK into vendored LinuxCNC file APIs, the Node machine-session bridge that SDK into vendored LinuxCNC file APIs, the Node machine-session bridge that
groups INI, parameter, and tool-table loading, and a browser interpreter smoke groups INI, parameter, and tool-table loading, the random-toolchanger flag as
that uses the same session bridge before saving OPFS-backed parameter and a host boundary passed through to the LinuxCNC-backed tool-table ABI, and a
tool-table text through vendored LinuxCNC file APIs. Full browser coverage, browser interpreter smoke that uses the same session bridge before saving
full SDK coverage, and richer machine-state validation remain future work. OPFS-backed parameter and tool-table text through vendored LinuxCNC file APIs.
Full browser coverage, full SDK coverage, and richer machine-state validation
remain future work.
## WASM/Browser Fixture Matrix ## WASM/Browser Fixture Matrix

View File

@@ -28,7 +28,7 @@ semantic rewrites:
| Canonical output | Canonical calls are captured as test events instead of driving hardware. | | Canonical output | Canonical calls are captured as test events instead of driving hardware. |
| Feed-rate state | `SET_FEED_RATE` updates standalone canonical runtime state so vendored `convert_length_units()` can read it back through `GET_EXTERNAL_FEED_RATE()` during G20/G21 changes. | | Feed-rate state | `SET_FEED_RATE` updates standalone canonical runtime state so vendored `convert_length_units()` can read it back through `GET_EXTERNAL_FEED_RATE()` during G20/G21 changes. |
| Tool-data reload | LinuxCNC `RELOAD_TOOLDATA` is captured as a canonical test event; browser/native tool-table reload plumbing remains a future host/runtime adapter. | | Tool-data reload | LinuxCNC `RELOAD_TOOLDATA` is captured as a canonical test event; browser/native tool-table reload plumbing remains a future host/runtime adapter. |
| Tool table storage | Vendored LinuxCNC `tooldata_common.cc` owns tool-table parsing and formatting; the standalone boundary only supplies the in-memory `tooldata_get()`/`tooldata_put()` callbacks and exposes load/save through the WASM C ABI. | | Tool table storage | Vendored LinuxCNC `tooldata_common.cc` owns tool-table parsing and formatting; the standalone boundary only supplies the in-memory `tooldata_get()`/`tooldata_put()` callbacks, exposes load/save through the WASM C ABI, and forwards the host random-toolchanger flag to LinuxCNC `tooldata_init()`. |
| Tool slot status | Standalone tool adapter state supplies `GET_EXTERNAL_TOOL_SLOT()` and `GET_EXTERNAL_SELECTED_TOOL_SLOT()` for vendored `Interp::synch()`; `linuxcnc_interp_init_harness` guards current/selected slot synchronization. | | Tool slot status | Standalone tool adapter state supplies `GET_EXTERNAL_TOOL_SLOT()` and `GET_EXTERNAL_SELECTED_TOOL_SLOT()` for vendored `Interp::synch()`; `linuxcnc_interp_init_harness` guards current/selected slot synchronization. |
| Interpreter state tags | LinuxCNC `UPDATE_TAG` callbacks are captured from the state tags packed by vendored interpreter code; standalone code does not derive modal state. | | Interpreter state tags | LinuxCNC `UPDATE_TAG` callbacks are captured from the state tags packed by vendored interpreter code; standalone code does not derive modal state. |
| Rotary indexer lock state | LinuxCNC `UNLOCK_ROTARY` and `LOCK_ROTARY` callbacks are captured from the vendored single-axis indexer path; standalone code does not implement rotary-indexing semantics. | | Rotary indexer lock state | LinuxCNC `UNLOCK_ROTARY` and `LOCK_ROTARY` callbacks are captured from the vendored single-axis indexer path; standalone code does not implement rotary-indexing semantics. |

View File

@@ -47,7 +47,7 @@ Current validation is intentionally mechanical:
| RS274 interpreter state and parser | `src/emc/rs274ngc/modal_state.*`, `interp_internal.*`, `interp_read.cc`, `interp_check.cc`, `interp_execute.cc`, `interp_find.cc`, `interp_array.cc`, `interp_queue.*`, `rs274ngc*`, `units.h` | Copy unchanged | Python/remap/runtime edges are isolated in standalone wrappers and shims; parser and execution logic remain LinuxCNC source | Vendor byte sync, per-file source probes, interpreter harness fixtures | | RS274 interpreter state and parser | `src/emc/rs274ngc/modal_state.*`, `interp_internal.*`, `interp_read.cc`, `interp_check.cc`, `interp_execute.cc`, `interp_find.cc`, `interp_array.cc`, `interp_queue.*`, `rs274ngc*`, `units.h` | Copy unchanged | Python/remap/runtime edges are isolated in standalone wrappers and shims; parser and execution logic remain LinuxCNC source | Vendor byte sync, per-file source probes, interpreter harness fixtures |
| RS274 conversion semantics | `src/emc/rs274ngc/interp_convert.cc`, `interp_arc.cc`, `interp_inverse.cc`, `interp_cycles.cc`, `interp_g7x.cc`, `interp_o_word.cc`, `interp_write.cc` | Copy unchanged | Canonical calls are captured by standalone event sink functions; conversion behavior stays in vendored LinuxCNC files; feed-rate state is read back through the canonical runtime boundary during length-unit conversion | Vendor byte sync, per-file source probes, canonical fixture suite, no standalone `Interp::convert_g()` guard | | RS274 conversion semantics | `src/emc/rs274ngc/interp_convert.cc`, `interp_arc.cc`, `interp_inverse.cc`, `interp_cycles.cc`, `interp_g7x.cc`, `interp_o_word.cc`, `interp_write.cc` | Copy unchanged | Canonical calls are captured by standalone event sink functions; conversion behavior stays in vendored LinuxCNC files; feed-rate state is read back through the canonical runtime boundary during length-unit conversion | Vendor byte sync, per-file source probes, canonical fixture suite, no standalone `Interp::convert_g()` guard |
| Named parameters and tool slot status | `src/emc/rs274ngc/interp_namedparams.cc`, related interpreter headers | Copy unchanged | `_ini[...]` and `_hal[...]` resolve through standalone INI/HAL adapters while lookup order stays LinuxCNC-derived; current/selected tool slot reads for vendored `Interp::synch()` come from the standalone tool adapter | Vendor byte sync, source probe, `linuxcnc_namedparam_harness`, `linuxcnc_interp_init_harness` | | Named parameters and tool slot status | `src/emc/rs274ngc/interp_namedparams.cc`, related interpreter headers | Copy unchanged | `_ini[...]` and `_hal[...]` resolve through standalone INI/HAL adapters while lookup order stays LinuxCNC-derived; current/selected tool slot reads for vendored `Interp::synch()` come from the standalone tool adapter | Vendor byte sync, source probe, `linuxcnc_namedparam_harness`, `linuxcnc_interp_init_harness` |
| Tool table parsing and formatting | `src/emc/tooldata/tooldata_common.cc` | Copy unchanged plus standalone storage callbacks | Native file parsing/formatting stays in vendored LinuxCNC source; the standalone tool adapter supplies `tooldata_get()`/`tooldata_put()` storage and index lookup, while OPFS remains a host-side persistence boundary | Vendor byte sync, `linuxcnc_tooldata_common_source_probe`, `tests/wasm/node/verify_interp_wasm.sh` load/save tool-table assertions | | Tool table parsing and formatting | `src/emc/tooldata/tooldata_common.cc` | Copy unchanged plus standalone storage callbacks | Native file parsing/formatting stays in vendored LinuxCNC source; the standalone tool adapter supplies `tooldata_get()`/`tooldata_put()` storage and index lookup, the WASM boundary only selects the LinuxCNC non-random or random-toolchanger branch via `tooldata_init()`, and OPFS remains a host-side persistence boundary | Vendor byte sync, `linuxcnc_tooldata_common_source_probe`, `tests/wasm/node/verify_interp_wasm.sh` non-random/random load/save tool-table assertions |
| Dynamic interpreter base | `src/emc/rs274ngc/interp_base.*` | Copy unchanged | `interp_base.cc` source probe uses standalone `EMC2_HOME` compile-time path boundary for LinuxCNC dynamic interpreter lookup | Vendor byte sync, `linuxcnc_interp_base_source_probe` | | Dynamic interpreter base | `src/emc/rs274ngc/interp_base.*` | Copy unchanged | `interp_base.cc` source probe uses standalone `EMC2_HOME` compile-time path boundary for LinuxCNC dynamic interpreter lookup | Vendor byte sync, `linuxcnc_interp_base_source_probe` |
## Dependency Matrix ## Dependency Matrix
@@ -75,9 +75,10 @@ Current validation is intentionally mechanical:
the current interpreter-core smoke scope. The interpreter SDK is a thin the current interpreter-core smoke scope. The interpreter SDK is a thin
allocation, filesystem, and C ABI wrapper over vendored LinuxCNC execution allocation, filesystem, and C ABI wrapper over vendored LinuxCNC execution
paths, including parameter-file restore/save through vendored paths, including parameter-file restore/save through vendored
`rs274ngc_pre.cc` and tool-table load/save through vendored `rs274ngc_pre.cc` and non-random/random tool-table load/save through
`tooldata_common.cc`; it does not define G-code, parameter, or tool-table vendored `tooldata_common.cc`; it does not define G-code, parameter, or
semantics. Full planner/session SDK coverage remains future work. tool-table semantics. Full planner/session SDK coverage remains future
work.
- OPFS persistence is connected to the INI panel through the host-side - OPFS persistence is connected to the INI panel through the host-side
`runtime/opfs/file-service.js` adapter. `runtime/opfs/path-model.js` now `runtime/opfs/file-service.js` adapter. `runtime/opfs/path-model.js` now
defines paths for INI, tool table, parameter file, G-code program, defines paths for INI, tool table, parameter file, G-code program,

View File

@@ -172,6 +172,13 @@ void append_tool_table_state(std::ostringstream &output)
if (standalone::get_tool_entry(&tool, 2) == 0) { if (standalone::get_tool_entry(&tool, 2) == 0) {
append_tool_entry(output, "tool_2", tool); append_tool_entry(output, "tool_2", tool);
} }
for (int idx = 0; idx < CANON_POCKETS_MAX; ++idx) {
if (standalone::get_tool_entry(&tool, idx) == 0 && tool.toolno != -1) {
std::ostringstream prefix;
prefix << "tool_pocket_" << idx;
append_tool_entry(output, prefix.str().c_str(), tool);
}
}
output << "tool_index_for_tool_2=" << standalone::find_tool_index_for_tool(2) << "\n"; output << "tool_index_for_tool_2=" << standalone::find_tool_index_for_tool(2) << "\n";
} }
@@ -196,6 +203,20 @@ void apply_parameter_assignments(Interp &interp, const char *assignments)
} }
} }
char *load_tool_table_with_mode(const char *path, bool random_tool_changer)
{
standalone::reset_tool_adapter();
tooldata_init(random_tool_changer);
tooldata_set_db(DB_NOTUSED);
std::ostringstream output;
output << "tooldata_random_toolchanger=" << (random_tool_changer ? 1 : 0) << "\n";
const int rc = tooldata_load(path);
output << "tooldata_load=" << rc << "\n";
append_tool_table_state(output);
return copy_result(output.str());
}
} // namespace } // namespace
extern "C" { extern "C" {
@@ -350,15 +371,13 @@ char *lcinterp_save_parameters(const char *path, const char *assignments)
EMSCRIPTEN_KEEPALIVE EMSCRIPTEN_KEEPALIVE
char *lcinterp_load_tool_table(const char *path) char *lcinterp_load_tool_table(const char *path)
{ {
standalone::reset_tool_adapter(); return load_tool_table_with_mode(path, false);
tooldata_init(false); }
tooldata_set_db(DB_NOTUSED);
std::ostringstream output; EMSCRIPTEN_KEEPALIVE
const int rc = tooldata_load(path); char *lcinterp_load_tool_table_random(const char *path)
output << "tooldata_load=" << rc << "\n"; {
append_tool_table_state(output); return load_tool_table_with_mode(path, true);
return copy_result(output.str());
} }
EMSCRIPTEN_KEEPALIVE EMSCRIPTEN_KEEPALIVE

View File

@@ -45,6 +45,7 @@ export async function loadMachineSessionFromOpfs(interp, machineId, options = {}
storage: options.storage, storage: options.storage,
opfsPath: paths.toolTableOpfsPath, opfsPath: paths.toolTableOpfsPath,
wasmPath: paths.toolTableWasmPath, wasmPath: paths.toolTableWasmPath,
randomToolChanger: options.randomToolChanger === true,
}); });
return { return {

View File

@@ -25,7 +25,9 @@ export async function loadMachineToolTableFromOpfs(interp, machineId, options =
return { return {
opfsPath, opfsPath,
wasmPath, wasmPath,
result: interp.loadToolTable(wasmPath), result: interp.loadToolTable(wasmPath, {
randomToolChanger: options.randomToolChanger === true,
}),
}; };
} }

View File

@@ -40,7 +40,11 @@ vendored LinuxCNC RS274NGC sources and exposes:
- `runFileWithIni(path, iniPath)` - `runFileWithIni(path, iniPath)`
- `restoreParameters(path)` - `restoreParameters(path)`
- `saveParameters(path, values)` - `saveParameters(path, values)`
- `loadToolTable(path)` - `loadToolTable(path, options)`
- `saveToolTable(path)` - `saveToolTable(path)`
- `writeTextFile(path, text)` - `writeTextFile(path, text)`
- `readTextFile(path)` - `readTextFile(path)`
`loadToolTable()` accepts `{ randomToolChanger: true }` to select the
LinuxCNC random-toolchanger branch before calling vendored
`tooldata_load()`. The SDK only forwards that runtime boundary flag.

View File

@@ -85,8 +85,11 @@ export async function createLinuxCncInterpSdk(moduleOptions = {}) {
return callStringResult(mod, "lcinterp_save_parameters", path, assignments); return callStringResult(mod, "lcinterp_save_parameters", path, assignments);
}, },
loadToolTable(path) { loadToolTable(path, options = {}) {
return callStringResult(mod, "lcinterp_load_tool_table", path); const functionName = options.randomToolChanger
? "lcinterp_load_tool_table_random"
: "lcinterp_load_tool_table";
return callStringResult(mod, functionName, path);
}, },
saveToolTable(path) { saveToolTable(path) {

View File

@@ -235,6 +235,72 @@
].join("\n"), ].join("\n"),
); );
await saveMachineTextFiles("browser-random-toolchanger", {
ini: "[EMC]\nMACHINE = browser-random-toolchanger\n",
toolTable: [
"T2 P7 Z3.125 D1.5 I12 J34 Q4 ;browser random finish tool",
"T5 P9 X1 Y2 Z3 ;browser random rough tool",
"",
].join("\n"),
parameters: [
"5161 10.5",
"5162 20.25",
"5220 1",
"5221 2.25",
"5399 44",
"",
].join("\n"),
});
const loadedRandomSession = await loadMachineSessionFromOpfs(
interp,
"browser-random-toolchanger",
{
iniWasmPath: "/work/browser-random-machine.ini",
parameterWasmPath: "/work/browser-random-linuxcnc.var",
toolTableWasmPath: "/work/browser-random-tool.tbl",
randomToolChanger: true,
},
);
verifyExpectedOutput(
"opfs_load_random_tool_table",
loadedRandomSession.toolTable.result,
[
"tooldata_random_toolchanger=1",
"tooldata_load=0",
"tool_pocket_7.toolno=2",
"tool_pocket_7.pocketno=7",
"tool_pocket_7.z=3.125",
"tool_pocket_7.diameter=1.5",
"tool_pocket_7.frontangle=12",
"tool_pocket_7.backangle=34",
"tool_pocket_7.orientation=4",
"tool_pocket_7.comment=browser random finish tool",
"tool_pocket_9.toolno=5",
"tool_pocket_9.pocketno=9",
"tool_index_for_tool_2=7",
].join("\n"),
);
await saveMachineToolTableToOpfs(
interp,
"browser-random-toolchanger",
{ wasmPath: "/work/browser-random-tool.tbl" },
);
const savedRandomMachineFiles = await loadMachineTextFiles(
"browser-random-toolchanger",
);
verifyExpectedOutput(
"opfs_saved_random_tool_table_text",
savedRandomMachineFiles.toolTable,
[
"T2",
"P7",
";browser random finish tool",
"T5",
"P9",
";browser random rough tool",
].join("\n"),
);
status.textContent = "browser_interp_smoke=ok"; status.textContent = "browser_interp_smoke=ok";
} catch (error) { } catch (error) {
status.textContent = `browser_interp_smoke=fail ${error.stack || error.message}`; status.textContent = `browser_interp_smoke=fail ${error.stack || error.message}`;

View File

@@ -183,8 +183,13 @@ const bridgeInterp = {
bridgeFiles.set(`${path}.bak`, "5161 0.0\n5162 0.0\n"); bridgeFiles.set(`${path}.bak`, "5161 0.0\n5162 0.0\n");
return `save_parameters=0\nsave_path=${path}\nvalues=${Object.keys(values).join(",")}\n`; return `save_parameters=0\nsave_path=${path}\nvalues=${Object.keys(values).join(",")}\n`;
}, },
loadToolTable(path) { loadToolTable(path, options = {}) {
return `tooldata_load=0\nload_tool_path=${path}\n`; return [
"tooldata_load=0",
`load_tool_path=${path}`,
`random_toolchanger=${options.randomToolChanger === true ? 1 : 0}`,
"",
].join("\n");
}, },
saveToolTable(path) { saveToolTable(path) {
bridgeFiles.set(path, "T2 P2 Z+1.250000 D+0.250000 ;loaded by LinuxCNC\n"); bridgeFiles.set(path, "T2 P2 Z+1.250000 D+0.250000 ;loaded by LinuxCNC\n");
@@ -230,10 +235,22 @@ const loadedToolTable = await loadMachineToolTableFromOpfs(
assert.deepEqual(loadedToolTable, { assert.deepEqual(loadedToolTable, {
opfsPath: "linuxcnc/machines/xyzab-tdr/tool.tbl", opfsPath: "linuxcnc/machines/xyzab-tdr/tool.tbl",
wasmPath: "/work/bridge-tool.tbl", wasmPath: "/work/bridge-tool.tbl",
result: "tooldata_load=0\nload_tool_path=/work/bridge-tool.tbl\n", result: "tooldata_load=0\nload_tool_path=/work/bridge-tool.tbl\nrandom_toolchanger=0\n",
}); });
assert.equal(bridgeFiles.get("/work/bridge-tool.tbl"), "T0 P0 ; no tool\nT2 P2 Z1.25 D0.25\n"); assert.equal(bridgeFiles.get("/work/bridge-tool.tbl"), "T0 P0 ; no tool\nT2 P2 Z1.25 D0.25\n");
const loadedRandomToolTable = await loadMachineToolTableFromOpfs(
bridgeInterp,
"xyzab-tdr",
{ storage, wasmPath: "/work/random-bridge-tool.tbl", randomToolChanger: true },
);
assert.deepEqual(loadedRandomToolTable, {
opfsPath: "linuxcnc/machines/xyzab-tdr/tool.tbl",
wasmPath: "/work/random-bridge-tool.tbl",
result:
"tooldata_load=0\nload_tool_path=/work/random-bridge-tool.tbl\nrandom_toolchanger=1\n",
});
const savedToolTable = await saveMachineToolTableToOpfs( const savedToolTable = await saveMachineToolTableToOpfs(
bridgeInterp, bridgeInterp,
"xyzab-tdr", "xyzab-tdr",
@@ -271,7 +288,7 @@ assert.deepEqual(loadedSession, {
toolTable: { toolTable: {
opfsPath: "linuxcnc/machines/xyzab-tdr/tool.tbl", opfsPath: "linuxcnc/machines/xyzab-tdr/tool.tbl",
wasmPath: "/work/session-tool.tbl", wasmPath: "/work/session-tool.tbl",
result: "tooldata_load=0\nload_tool_path=/work/session-tool.tbl\n", result: "tooldata_load=0\nload_tool_path=/work/session-tool.tbl\nrandom_toolchanger=0\n",
}, },
}); });
assert.equal(bridgeFiles.get("/work/session.ini"), "[EMC]\nMACHINE = xyzab-tdr\n"); assert.equal(bridgeFiles.get("/work/session.ini"), "[EMC]\nMACHINE = xyzab-tdr\n");
@@ -281,6 +298,22 @@ assert.equal(
"T2 P2 Z+1.250000 D+0.250000 ;loaded by LinuxCNC\n", "T2 P2 Z+1.250000 D+0.250000 ;loaded by LinuxCNC\n",
); );
const loadedRandomSession = await loadMachineSessionFromOpfs(
bridgeInterp,
"xyzab-tdr",
{
storage,
iniWasmPath: "/work/random-session.ini",
parameterWasmPath: "/work/random-session.var",
toolTableWasmPath: "/work/random-session-tool.tbl",
randomToolChanger: true,
},
);
assert.equal(
loadedRandomSession.toolTable.result,
"tooldata_load=0\nload_tool_path=/work/random-session-tool.tbl\nrandom_toolchanger=1\n",
);
await assert.rejects( await assert.rejects(
() => loadTextFile("linuxcnc/machines/missing.ini", storage), () => loadTextFile("linuxcnc/machines/missing.ini", storage),
/missing file/, /missing file/,

View File

@@ -256,4 +256,54 @@ assert.equal(savedToolTable.includes(";finish tool"), true);
assert.equal(savedToolTable.includes("T5"), true); assert.equal(savedToolTable.includes("T5"), true);
assert.equal(savedToolTable.includes("P9"), true); assert.equal(savedToolTable.includes("P9"), true);
assert.equal(savedToolTable.includes(";rough tool"), true); assert.equal(savedToolTable.includes(";rough tool"), true);
const randomToolTablePath = "/work/random-tool.tbl";
interp.writeTextFile(
randomToolTablePath,
[
"T2 P7 Z3.125 D1.5 I12 J34 Q4 ;random finish tool",
"T5 P9 X1 Y2 Z3 ;random rough tool",
"",
].join("\n"),
);
verifyExpectedOutput(
"load_tool_table_random",
interp.loadToolTable(randomToolTablePath, { randomToolChanger: true }),
[
"tooldata_random_toolchanger=1",
"tooldata_load=0",
"tooldata_last_index=9",
"tool_1.toolno=-1",
"tool_2.toolno=-1",
"tool_pocket_7.toolno=2",
"tool_pocket_7.pocketno=7",
"tool_pocket_7.z=3.125",
"tool_pocket_7.diameter=1.5",
"tool_pocket_7.frontangle=12",
"tool_pocket_7.backangle=34",
"tool_pocket_7.orientation=4",
"tool_pocket_7.comment=random finish tool",
"tool_pocket_9.toolno=5",
"tool_pocket_9.pocketno=9",
"tool_pocket_9.z=3",
"tool_pocket_9.comment=random rough tool",
"tool_index_for_tool_2=7",
].join("\n"),
);
verifyExpectedOutput(
"save_tool_table_random",
interp.saveToolTable(randomToolTablePath),
[
"tooldata_save=0",
"tool_pocket_7.toolno=2",
"tool_pocket_9.toolno=5",
].join("\n"),
);
const savedRandomToolTable = interp.readTextFile(randomToolTablePath);
assert.equal(savedRandomToolTable.includes("T2"), true);
assert.equal(savedRandomToolTable.includes("P7"), true);
assert.equal(savedRandomToolTable.includes(";random finish tool"), true);
assert.equal(savedRandomToolTable.includes("T5"), true);
assert.equal(savedRandomToolTable.includes("P9"), true);
assert.equal(savedRandomToolTable.includes(";random rough tool"), true);
console.log("interp_wasm_node_smoke=ok"); console.log("interp_wasm_node_smoke=ok");

View File

@@ -96,5 +96,5 @@ link_wasm_module \
-s STACK_SIZE=2MB \ -s STACK_SIZE=2MB \
-s NO_EXIT_RUNTIME=1 \ -s NO_EXIT_RUNTIME=1 \
-s FORCE_FILESYSTEM=1 \ -s FORCE_FILESYSTEM=1 \
-s EXPORTED_FUNCTIONS='["_malloc","_free","_lcinterp_run_program","_lcinterp_run_program_with_ini","_lcinterp_run_file","_lcinterp_run_file_with_ini","_lcinterp_restore_parameters","_lcinterp_save_parameters","_lcinterp_load_tool_table","_lcinterp_save_tool_table","_lcinterp_free_string"]' \ -s EXPORTED_FUNCTIONS='["_malloc","_free","_lcinterp_run_program","_lcinterp_run_program_with_ini","_lcinterp_run_file","_lcinterp_run_file_with_ini","_lcinterp_restore_parameters","_lcinterp_save_parameters","_lcinterp_load_tool_table","_lcinterp_load_tool_table_random","_lcinterp_save_tool_table","_lcinterp_free_string"]' \
-s EXPORTED_RUNTIME_METHODS='["FS","UTF8ToString","stringToUTF8","lengthBytesUTF8"]' -s EXPORTED_RUNTIME_METHODS='["FS","UTF8ToString","stringToUTF8","lengthBytesUTF8"]'