feat:更改配置项

This commit is contained in:
Evan
2026-09-20 13:59:10 +08:00
parent c4641aee19
commit bb78d8bf5c
4 changed files with 98 additions and 34 deletions

View File

@@ -1,4 +1,4 @@
// Regression tests for variable scopes in the editor interpreter.
// Regression tests for variable scopes and return control flow in the editor interpreter.
// Run: node scripts/test-cpp-regressions.cjs
const assert = require('assert');
const fs = require('fs');
@@ -15,7 +15,7 @@ const compiled = babel.transformSync(source, {
const silentConsole = {log() {}, warn() {}, error() {}};
const context = {exports: {}, require, setTimeout, console: silentConsole, window: {}};
vm.runInNewContext(compiled, context, {filename: parserPath});
const {CppCodeExecutor, validateCppSyntax} = context.exports;
const {CppCodeExecutor, validateCppSyntax, createCppExecutor} = context.exports;
const main = body => `int main() {\n${body}\n}`;
// Complete program from the first email screenshot; the second repeats this issue.
const customerEmailCode = `void test() {
@@ -44,15 +44,30 @@ async function run(code, expected, configure) {
if (configure) configure(executor, context.window);
const validation = await validateCppSyntax(code);
assert.strictEqual(validation.isValid, true, JSON.stringify(validation.errors));
await executor.run();
const exitCode = await executor.run();
if (Object.prototype.hasOwnProperty.call(expected, 'exitCode')) assert.strictEqual(exitCode, expected.exitCode);
if (expected.moves) assert.deepStrictEqual(moves, expected.moves);
if (expected.turns) assert.deepStrictEqual(turns, expected.turns);
assert.strictEqual(executor.variables, executor.globalVariables, 'scope must unwind after execution');
assert.strictEqual(executor.callStack.length, 0);
assert.strictEqual(executor.currentExecutionContext, null);
assert.strictEqual(executor.isRunning, false);
return executor;
}
const cases = [
['screenshot: main return 1 is a normal exit', main('playerMove(4);\nreturn 1;'), {moves: [4], exitCode: 1}],
['return 1 skips remaining main statements', main('return 1;\nplayerMove(9);'), {moves: [], exitCode: 1}],
['return 0 also stops main early', main('return 0;\nplayerMove(9);'), {moves: [], exitCode: 0}],
['negative exit code', main('return -1;'), {moves: [], exitCode: -1}],
['parenthesized return expression', main('int status = 2;\nreturn (status + 1);'), {moves: [], exitCode: 3}],
['main fallthrough returns zero', main('playerMove(1);'), {moves: [1], exitCode: 0}],
['return from for loop exits main', main('for (int i = 0; i < 3; i++) {\nplayerMove(i);\nreturn 1;\n}\nplayerMove(9);'), {moves: [0], exitCode: 1}],
['return zero inside loop is not ignored', main('for (int i = 0; i < 3; i++) {\nreturn 0;\n}\nplayerMove(9);'), {moves: [], exitCode: 0}],
['return through while and if exits main', main('while (true) {\nif (true) {\nreturn 2;\n}\nplayerMove(9);\n}\nplayerMove(8);'), {moves: [], exitCode: 2}],
['function return 0 skips only its own remaining statements', 'int f() {\nreturn 0;\nplayerMove(9);\n}\n' + main('f();\nplayerMove(1);\nreturn 1;'), {moves: [1], exitCode: 1}],
['function return inside loop resumes caller', 'int f() {\nfor (int i = 0; i < 3; i++) {\nreturn 1;\n}\nplayerMove(9);\n}\n' + main('f();\nplayerMove(1);'), {moves: [1], exitCode: 0}],
['identifier starting with return is not a return statement', main('int returnValue = 1;\nreturnValue = 2;\nplayerMove(returnValue);\nreturn 0;'), {moves: [2], exitCode: 0}],
['customer email complete program (screenshots 1 and 2)', customerEmailCode, {moves: [0], turns: [-1]}],
['nested loops', main('for (int i = 0; i < 2; i++) {\nfor (int i = 0; i < 2; i++) {\n}\nplayerMove(i);\n}'), {moves: [0, 1]}],
['loop initializer restores shadowed value', main('int i = 9;\nfor (int i = 0; i < 2; i++) {\n}\nplayerMove(i);'), {moves: [9]}],
@@ -104,5 +119,21 @@ const cases = [
console.log(`PASS scope cleanup on ${stop ? 'stop' : 'error'}`);
}
console.log(`${cases.length + 4} regression checks passed`);
const highlighted = [];
context.window = {isScriptRunOver: false, setHighlightedLine: line => highlighted.push(line)};
const manager = createCppExecutor();
for (const status of [1, 0]) {
assert.strictEqual(await manager.execute(main(`return ${status};`)), status);
assert.strictEqual(manager.currentExecutor, null);
assert.strictEqual(highlighted[highlighted.length - 1], null);
}
console.log('PASS editor executor manager resolves nonzero exit and can run again');
context.window.cppGameAPI = {playerMove: async () => {throw new Error('RETURN_INTERRUPT');}};
await assert.rejects(manager.execute('void f() {\nplayerMove(1);\n}\n' + main('f();')), /RETURN_INTERRUPT/);
assert.strictEqual(manager.currentExecutor, null);
assert.strictEqual(highlighted[highlighted.length - 1], null);
console.log('PASS real game errors are not mistaken for a return signal');
console.log(`${cases.length + 6} regression checks passed`);
})().catch(error => {console.error(error); process.exitCode = 1;});