2023-06-23 17:53:05 +00:00
|
|
|
const JsUnit = imports.jsUnit;
|
|
|
|
|
2023-07-22 16:44:08 +00:00
|
|
|
import GObject from 'gi://GObject';
|
|
|
|
|
2023-08-10 15:50:08 +00:00
|
|
|
import 'resource:///org/gnome/shell/ui/environment.js';
|
2023-06-23 17:53:05 +00:00
|
|
|
|
2023-08-10 15:50:08 +00:00
|
|
|
import {InjectionManager} from 'resource:///org/gnome/shell/extensions/extension.js';
|
2023-06-23 17:53:05 +00:00
|
|
|
|
|
|
|
class Object1 {
|
|
|
|
count = 0;
|
|
|
|
|
|
|
|
getNumber() {
|
|
|
|
return 42;
|
|
|
|
}
|
|
|
|
|
|
|
|
getCount() {
|
|
|
|
return ++this.count;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-22 16:44:08 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-23 17:53:05 +00:00
|
|
|
/**
|
|
|
|
* @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());
|
2023-07-22 16:44:08 +00:00
|
|
|
|
|
|
|
// 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);
|