arepl-backend
Version:
JS interface to python evaluator for AREPL
290 lines (287 loc) • 11.4 kB
JavaScript
;
/*global suite, test*/ //comment for eslint
Object.defineProperty(exports, "__esModule", { value: true });
// This test uses TDD Mocha. see https://mochajs.org/ for help
// http://ricostacruz.com/cheatsheets/mocha-tdd
// The module 'assert' provides assertion methods from node
const assert = require("assert");
const pythonExecutor_1 = require("./pythonExecutor");
const os_1 = require("os");
function isEmpty(obj) {
return Object.keys(obj).length === 0;
}
suite("python_evaluator Tests", () => {
let pyEvaluator = new pythonExecutor_1.PythonExecutor();
let input = {
evalCode: "",
filePath: "",
usePreviousVariables: false,
show_global_vars: true,
default_filter_vars: [],
default_filter_types: ["<class 'module'>", "<class 'function'>"]
};
const pythonStartupTime = 3000;
suiteSetup(function () {
this.timeout(pythonStartupTime + 500);
});
setup(function (done) {
pyEvaluator.onPrint = () => { };
pyEvaluator.onStderr = () => { };
pyEvaluator.onResult = () => { };
pyEvaluator.start(done);
});
teardown(function () {
pyEvaluator.stop(true);
});
test("sanity check: 1+1=2", () => {
assert.strictEqual(1 + 1, 2);
});
test("returns result", function (done) {
pyEvaluator.onResult = (result) => {
assert.notStrictEqual(result, null);
done();
};
pyEvaluator.onStderr = (err) => {
done(err);
};
pyEvaluator.onPrint = (msg) => {
done(msg);
};
input.evalCode = "x";
pyEvaluator.execCode(input);
});
test("returns user variables", function (done) {
pyEvaluator.onResult = (result) => {
assert.strictEqual(result.userVariables['x'], 1);
done();
};
input.evalCode = "x=1";
pyEvaluator.execCode(input);
});
test("can import importlib", function (done) {
pyEvaluator.onResult = (result) => {
assert.strictEqual(result.userErrorMsg, undefined);
done();
};
input.evalCode = "import importlib.resources as rsrc";
pyEvaluator.execCode(input);
});
test("returns user variables properly when there is a lot of content", function (done) {
pyEvaluator.onResult = (result) => {
assert.strictEqual(result.userVariables['x'], 1);
done();
};
input.evalCode = "x=1;y='a'*80000";
pyEvaluator.execCode(input);
});
suite("stdout/stderr tests", () => {
test("can print stdout", function (done) {
let hasPrinted = false;
pyEvaluator.onPrint = (stdout) => {
assert.strictEqual(stdout, "hello world" + os_1.EOL);
hasPrinted = true;
};
pyEvaluator.onResult = () => {
if (!hasPrinted)
assert.fail("program has returned result", "program should still be printing");
else
done();
};
input.evalCode = "print('hello world')";
pyEvaluator.execCode(input);
});
test("can print stdout if no newline", function (done) {
let hasPrinted = false;
pyEvaluator.onPrint = (stdout) => {
assert.strictEqual(stdout, "hello world");
hasPrinted = true;
};
pyEvaluator.onResult = () => {
if (!hasPrinted)
assert.fail("program has returned result", "program should still be printing");
else
done();
};
input.evalCode = "print('hello world', end='')";
pyEvaluator.execCode(input);
});
test("can print stderr", function (done) {
let hasLogged = false;
pyEvaluator.onStderr = (stderr) => {
assert.strictEqual(stderr, "hello world");
hasLogged = true;
done();
};
pyEvaluator.onResult = (result) => {
setTimeout(() => {
if (!hasLogged)
assert.fail("program has returned result " + JSON.stringify(result), "program should still be logging");
}, 100); //to avoid race conditions wait a bit in case stderr arrives later
};
input.evalCode = "import sys;sys.stderr.write('hello world')";
pyEvaluator.execCode(input);
});
test("can print multiple lines", function (done) {
let firstPrint = false;
pyEvaluator.onPrint = (stdout) => {
// not sure why it is doing this.. stdout should be line buffered
// so we should get 1 and 2 seperately
assert.strictEqual(stdout, '1' + os_1.EOL + '2' + os_1.EOL);
firstPrint = true;
};
pyEvaluator.onResult = () => {
if (!firstPrint)
assert.fail("program has returned result", "program should still be printing");
else
done();
};
input.evalCode = "[print(x) for x in [1,2]]";
pyEvaluator.execCode(input);
});
test("prints in real-time", function (done) {
let printed = false;
pyEvaluator.onPrint = (stdout) => { printed = true; };
pyEvaluator.onResult = () => { done(); };
setTimeout(() => { if (!printed)
assert.fail(""); }, 25);
input.evalCode = "from time import sleep\nprint('a')\nsleep(.05)\nprint(b)";
pyEvaluator.execCode(input);
});
test("returns result after print", function (done) {
pyEvaluator.onPrint = (stdout) => {
assert.strictEqual(stdout, "hello world" + os_1.EOL);
assert.strictEqual(pyEvaluator.state, pythonExecutor_1.PythonState.Executing);
};
pyEvaluator.onResult = () => {
assert.strictEqual(pyEvaluator.state, pythonExecutor_1.PythonState.DirtyFree);
done();
};
input.evalCode = "print('hello world')";
pyEvaluator.execCode(input);
});
});
test("no encoding errors with utf8 on windows", function (done) {
// other platforms may have the locale encoding
// so we just test windows
// see https://docs.python.org/3/library/sys.html#sys.stdout
if (process.platform != "win32") {
done();
return;
}
pyEvaluator.onResult = (result) => {
assert.strictEqual(result.userErrorMsg, undefined);
assert.strictEqual(result.internalError, null);
done();
};
input.evalCode = "#㍦";
pyEvaluator.execCode(input);
});
test("dump returns result", function (done) {
let gotDump = false;
pyEvaluator.onResult = (result) => {
if (gotDump)
return;
assert.notStrictEqual(result, null);
assert.strictEqual(isEmpty(result.userError), true);
assert.strictEqual(result.internalError, null);
assert.strictEqual(result.userVariables['dump output'], 5);
assert.strictEqual(result.caller, '<module>');
assert.strictEqual(result.lineno, 1);
gotDump = true;
done();
};
input.evalCode = "from arepl_dump import dump;dump(5)";
pyEvaluator.execCode(input);
});
test("returns syntax error when incorrect syntax", function (done) {
pyEvaluator.onResult = (result) => {
assert.notStrictEqual(result.userError, null);
assert.strictEqual(result.userError.filename, '<string>');
assert.strictEqual(result.userError.lineno, '1');
assert.strictEqual(result.userError.msg, 'invalid syntax');
done();
};
input.evalCode = "x=";
pyEvaluator.execCode(input);
});
test("uses previousRun variables asked", function (done) {
function onSecondResult(result) {
assert.strictEqual(result.userVariables['y'], 1);
done();
}
pyEvaluator.onResult = (result) => {
pyEvaluator.onResult = onSecondResult;
input.usePreviousVariables = true;
pyEvaluator.execCode(input);
input.usePreviousVariables = false;
};
input.evalCode = "x=1";
pyEvaluator.execCode(input);
input.evalCode = "y=x";
});
test("can restart", function (done) {
this.timeout(this.timeout() + pythonStartupTime);
assert.strictEqual(pyEvaluator.state, pythonExecutor_1.PythonState.FreshFree);
pyEvaluator.restart(() => {
assert.strictEqual(pyEvaluator.state, pythonExecutor_1.PythonState.FreshFree);
pyEvaluator.onResult = () => done();
input.evalCode = "x";
pyEvaluator.execCode(input);
});
});
test("strips out unnecessary error info", function (done) {
pyEvaluator.onResult = (result) => {
assert.strictEqual(result.userErrorMsg, "Traceback (most recent call last):\n line 1, in <module>\nNameError: name 'x' is not defined\n");
done();
};
input.evalCode = "x";
pyEvaluator.execCode(input);
});
test("strips out unnecessary error info even with long tracebacks", function (done) {
pyEvaluator.onResult = (result) => {
// asserting the exact string would result in flaky tests
// because internal python code could change & the traceback would be different
// so we just do some generic checks
assert.strictEqual(result.userErrorMsg.includes("TypeError"), true);
assert.strictEqual(result.userErrorMsg.split('File ').length > 1, true);
assert.strictEqual(result.userErrorMsg.includes("python_evaluator.py"), false);
assert.strictEqual(result.userErrorMsg.includes("exec(data['evalCode'], evalLocals)"), false);
done();
};
input.evalCode = "import json;json.dumps(json)";
pyEvaluator.execCode(input);
});
test("strips out unnecessary error info even with multiple tracebacks", function (done) {
pyEvaluator.onResult = (result) => {
assert.strictEqual(result.userErrorMsg, `Traceback (most recent call last):
line 6, in <module>
line 3, in foo
Exception
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
line 8, in <module>
NameError: name 'fah' is not defined
`);
done();
};
input.evalCode = `
def foo():
raise Exception
try:
foo()
except Exception as e:
fah`;
pyEvaluator.execCode(input);
});
test("checks syntax", function (done) {
pyEvaluator.checkSyntax("x=").then(() => {
assert.fail("promise should have been rejected");
}).catch(() => { });
pyEvaluator.checkSyntax("x=1").then(() => {
done();
}).catch((err) => {
assert.fail("syntax was correct there should not have been an error");
});
});
});
//# sourceMappingURL=pythonExecutor.test.js.map