[IMP] web: patch/unpatch: better error handling

Before this commit, calling unpatch on an object that hasn't been
patched before crashed (before reaching the code that handles the
case by throwing an Error). This scenario is now properly handled.

This commit also defines specific Error classes for the patch and
unpatch faulty cases, so that they can be elegantly catched (in
tests for example).

closes odoo/odoo#68057

Signed-off-by: Géry Debongnie (ged) <ged@openerp.com>
This commit is contained in:
Aaron Bohy
2021-03-18 10:25:31 +00:00
parent 6418a55fe4
commit 98ede6e553
2 changed files with 30 additions and 6 deletions
+18 -3
View File
@@ -227,7 +227,22 @@ function _getExtractorFrom(criterion) {
}
}
class AlreadyDefinedPatchError extends Error {
constructor() {
super(...arguments);
this.name = 'AlreadyDefinedPatchError';
}
}
class UnknownPatchError extends Error {
constructor() {
super(...arguments);
this.name = 'UnknownPatchError';
}
}
var utils = {
AlreadyDefinedPatchError,
UnknownPatchError,
/**
* Throws an error if the given condition is not true
@@ -627,7 +642,7 @@ var utils = {
}
const objDesc = patchMap.get(obj);
if (objDesc.patches.some(p => p.name === patchName)) {
throw new Error(`Class ${obj.name} already has a patch ${patchName}`);
throw new AlreadyDefinedPatchError(`Patch ${patchName} is already defined`);
}
objDesc.patches.push({
name: patchName,
@@ -901,8 +916,8 @@ var utils = {
*/
unpatch: function (obj, patchName) {
const objDesc = patchMap.get(obj);
if (!objDesc.patches.some(p => p.name === patchName)) {
throw new Error(`Class ${obj.name} does not have any patch ${patchName}`);
if (!objDesc || !objDesc.patches.some(p => p.name === patchName)) {
throw new UnknownPatchError(`Could not find patch ${patchName}`);
}
patchMap.delete(obj);
+12 -3
View File
@@ -1,7 +1,7 @@
odoo.define("web.patch_tests", function (require) {
"use strict";
const { patch, unpatch } = require('web.utils');
const { AlreadyDefinedPatchError, patch, unpatch, UnknownPatchError } = require('web.utils');
function makeBaseClass(assert, assertInSetup) {
class BaseClass {
@@ -122,7 +122,7 @@ QUnit.module('core', {}, function () {
// keys should be unique
assert.throws(() => {
patch(A.prototype, 'patch');
});
}, AlreadyDefinedPatchError);
});
QUnit.test('unpatch', async function (assert) {
@@ -278,6 +278,15 @@ QUnit.module('core', {}, function () {
]);
});
QUnit.test('unpatch a class that has not been patched', async function (assert) {
assert.expect(1);
const A = class {};
assert.throws(() => {
unpatch(A.prototype, 'patch');
}, UnknownPatchError);
});
QUnit.test('unpatch twice the same patch name', async function (assert) {
assert.expect(1);
@@ -287,7 +296,7 @@ QUnit.module('core', {}, function () {
unpatch(A.prototype, 'patch');
assert.throws(() => {
unpatch(A.prototype, 'patch');
});
}, UnknownPatchError);
});
QUnit.test('unpatch and re-patch', async function (assert) {