const JsUnit = imports.jsUnit; import GObject from 'gi://GObject'; import 'resource:///org/gnome/shell/ui/environment.js'; import {InjectionManager} from 'resource:///org/gnome/shell/extensions/extension.js'; class Object1 { count = 0; getNumber() { return 42; } getCount() { return ++this.count; } } class GObject1 extends GObject.Object { static [GObject.properties] = { 'plonked': GObject.ParamSpec.boolean( 'plonked', '', '', GObject.ParamFlags.READWRITE, false), }; static { GObject.registerClass(this); } plonk() { this.set_property('plonked', true); } } /** * @param {object} object to modify */ function addInjections(object) { // extend original method injectionManager.overrideMethod( object, 'getNumber', originalMethod => { return function () { // eslint-disable-next-line no-invalid-this const num = originalMethod.call(this); return 2 * num; }; }); // override original method injectionManager.overrideMethod( object, 'getCount', () => { return function () { return 42; }; }); // inject new method injectionManager.overrideMethod( object, 'getOtherNumber', () => { return function () { return 42; }; }); } const injectionManager = new InjectionManager(); let obj; // Prototype injections addInjections(Object1.prototype); obj = new Object1(); // new obj is modified JsUnit.assertEquals(obj.getNumber(), 84); JsUnit.assertEquals(obj.getCount(), 42); JsUnit.assertEquals(obj.count, 0); JsUnit.assertEquals(obj.getOtherNumber(), 42); injectionManager.clear(); obj = new Object1(); // new obj is unmodified JsUnit.assertEquals(obj.getNumber(), 42); JsUnit.assertEquals(obj.getCount(), obj.count); JsUnit.assert(obj.count > 0); JsUnit.assertRaises(() => obj.getOtherNumber()); // instance injections addInjections(obj); // obj is now modified JsUnit.assertEquals(obj.getNumber(), 84); JsUnit.assertEquals(obj.getCount(), 42); JsUnit.assertEquals(obj.count, 1); JsUnit.assertEquals(obj.getOtherNumber(), 42); injectionManager.restoreMethod(obj, 'getNumber'); JsUnit.assertEquals(obj.getNumber(), 42); injectionManager.clear(); // obj is unmodified again JsUnit.assertEquals(obj.getNumber(), 42); JsUnit.assertEquals(obj.getCount(), obj.count); JsUnit.assert(obj.count > 0); JsUnit.assertRaises(() => obj.getOtherNumber()); // GObject injections const gobj = new GObject1(); let vfuncCalled; injectionManager.overrideMethod( GObject1.prototype, 'vfunc_set_property', originalMethod => { return function (...args) { // eslint-disable-next-line no-invalid-this originalMethod.apply(this, args); vfuncCalled = true; }; }); // gobj is now modified vfuncCalled = false; gobj.plonk(); JsUnit.assertTrue(vfuncCalled); injectionManager.clear(); // gobj is unmodified again vfuncCalled = false; gobj.plonk(); JsUnit.assertFalse(vfuncCalled);