From 30fce04357ae9b0add53a654fa6215eb9a8ffaee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9ry=20Debongnie?= Date: Mon, 21 Jun 2021 20:39:49 +0000 Subject: [PATCH] [FIX] web: tolerate empty string as action context Before this commit, calling "makeContext" with an empty string as context description crashed. For instance, this happened with at least two actions in Odoo: Elearning > Courses > Contents Fleet > Vehicules > Odometers In both cases, the context in the action is the empty string. Issue spotted thanks to the clickEverywhere test. The crash was caused by the pyjs parser. This is correct (even though the error was not clear), since an empty list of token do not represent a valid python AST. So, the fix is to make the makeContext function more tolerant. closes odoo/odoo#72490 Signed-off-by: Aaron Bohy (aab) --- addons/web/static/src/core/context.js | 6 ++++-- addons/web/static/src/core/py_js/py_parser.js | 5 ++++- addons/web/static/tests/core/context_tests.js | 4 +++- addons/web/static/tests/core/py_js/py_interpreter_tests.js | 4 ++++ addons/web/static/tests/core/py_js/py_parser_tests.js | 4 ++++ 5 files changed, 19 insertions(+), 4 deletions(-) diff --git a/addons/web/static/src/core/context.js b/addons/web/static/src/core/context.js index 79eb31de874..8b6f30e2dd6 100644 --- a/addons/web/static/src/core/context.js +++ b/addons/web/static/src/core/context.js @@ -16,8 +16,10 @@ import { evaluateExpr } from "./py_js/py"; export function makeContext(...contexts) { let context = {}; for (let ctx of contexts) { - const subCtx = typeof ctx === "string" ? evaluateExpr(ctx, context) : ctx; - Object.assign(context, subCtx); + if (ctx !== "") { + const subCtx = typeof ctx === "string" ? evaluateExpr(ctx, context) : ctx; + Object.assign(context, subCtx); + } } return context; } diff --git a/addons/web/static/src/core/py_js/py_parser.js b/addons/web/static/src/core/py_js/py_parser.js index ddaedfbef9f..52b4d776deb 100644 --- a/addons/web/static/src/core/py_js/py_parser.js +++ b/addons/web/static/src/core/py_js/py_parser.js @@ -364,5 +364,8 @@ function _parse(tokens, bp = 0) { * @returns {AST} */ export function parse(tokens) { - return _parse(tokens, 0); + if (tokens.length) { + return _parse(tokens, 0); + } + throw new ParserError("Missing token"); } diff --git a/addons/web/static/tests/core/context_tests.js b/addons/web/static/tests/core/context_tests.js index ebfb0a30194..315e600712a 100644 --- a/addons/web/static/tests/core/context_tests.js +++ b/addons/web/static/tests/core/context_tests.js @@ -16,9 +16,11 @@ QUnit.module("utils", {}, () => { assert.deepEqual(ctx1, ctx2); }); - QUnit.test("can accept undefined", (assert) => { + QUnit.test("can accept undefined or empty string", (assert) => { assert.deepEqual(makeContext(undefined), {}); assert.deepEqual(makeContext({ a: 1 }, undefined, { b: 2 }), { a: 1, b: 2 }); + assert.deepEqual(makeContext(""), {}); + assert.deepEqual(makeContext({ a: 1 }, "", { b: 2 }), { a: 1, b: 2 }); }); QUnit.test("evaluate strings", (assert) => { diff --git a/addons/web/static/tests/core/py_js/py_interpreter_tests.js b/addons/web/static/tests/core/py_js/py_interpreter_tests.js index c603f2e7297..5d969a7d9e8 100644 --- a/addons/web/static/tests/core/py_js/py_interpreter_tests.js +++ b/addons/web/static/tests/core/py_js/py_interpreter_tests.js @@ -12,6 +12,10 @@ QUnit.module("py", {}, () => { assert.strictEqual(evaluateExpr('"foo"'), "foo"); }); + QUnit.test("empty expression", (assert) => { + assert.throws(() => evaluateExpr(""), /Error: Missing token/); + }); + QUnit.test("numbers", (assert) => { assert.strictEqual(evaluateExpr("1.2"), 1.2); assert.strictEqual(evaluateExpr(".12"), 0.12); diff --git a/addons/web/static/tests/core/py_js/py_parser_tests.js b/addons/web/static/tests/core/py_js/py_parser_tests.js index 76d0dcb4f34..cb48fcf6456 100644 --- a/addons/web/static/tests/core/py_js/py_parser_tests.js +++ b/addons/web/static/tests/core/py_js/py_parser_tests.js @@ -14,6 +14,10 @@ QUnit.module("py", {}, () => { assert.deepEqual(parseExpr("None"), { type: 3 /* None */ }); }); + QUnit.test("cannot parse empty string", (assert) => { + assert.throws(() => parseExpr(""), /Error: Missing token/); + }); + QUnit.test("can parse unary operator -", (assert) => { assert.deepEqual(parseExpr("-1"), { type: 6 /* UnaryOperator */,