[gjs/ewlsh/interface-resolution: 6/6] (review and squash) Documentation and tests improvements




commit 766c647e14c6933e64cd76222789eaf2c83cb625
Author: Philip Chimento <philip chimento gmail com>
Date:   Fri Oct 15 15:17:30 2021 -0700

    (review and squash) Documentation and tests improvements

 gi/object.cpp                              | 27 ++++++++++++++++++++-------
 installed-tests/js/testGObjectInterface.js | 11 +++++++++++
 2 files changed, 31 insertions(+), 7 deletions(-)
---
diff --git a/gi/object.cpp b/gi/object.cpp
index 85cc9a60..4493dd60 100644
--- a/gi/object.cpp
+++ b/gi/object.cpp
@@ -688,24 +688,37 @@ static bool interface_setter(JSContext* cx, unsigned argc, JS::Value* vp) {
 static bool resolve_on_interface_prototype(JSContext* cx,
                                            GIObjectInfo* iface_info,
                                            JS::HandleId identifier,
-                                           JS::HandleObject target_prototype,
+                                           JS::HandleObject class_prototype,
                                            bool* found) {
     GType gtype = g_base_info_get_type(iface_info);
-    JS::RootedObject prototype(
+    JS::RootedObject interface_prototype(
         cx, gjs_lookup_object_prototype_from_info(cx, iface_info, gtype));
-    if (!prototype)
+    if (!interface_prototype)
         return false;
 
     JS::Rooted<JS::PropertyDescriptor> desc(cx);
-    if (!JS_GetPropertyDescriptorById(cx, prototype, identifier, &desc))
+    if (!JS_GetPropertyDescriptorById(cx, interface_prototype, identifier,
+                                      &desc))
         return false;
 
-    // Check if the property exists on the prototype...
+    // If the property doesn't exist on the interface prototype, we don't need
+    // to perform this trick.
     if (!desc.object()) {
         *found = false;
         return true;
     }
 
+    // We are lazily defining a property on the class prototype, and a property
+    // of that name is present on the interface prototype that the class
+    // implements. Define a property of that name on the class prototype, with a
+    // getter and setter. This is so that e.g. file.dup() calls the _current_,
+    // not the original, value of Gio.File.prototype.dup(), so that it can be
+    // monkeypatched.
+    //
+    // The setter (interface_setter() above) marks the property as overridden if
+    // it is set from user code. The getter (interface_getter() above) proxies
+    // the interface prototype's property, unless it was marked as overridden.
+
     JS::Rooted<JS::PropertyDescriptor> target_desc(cx, desc);
     JS::RootedObject getter(
         cx, JS_GetFunctionObject(js::NewFunctionByIdWithReserved(
@@ -729,7 +742,7 @@ static bool resolve_on_interface_prototype(JSContext* cx,
                                   JS::ObjectValue(*accessor));
 
     const GjsAtoms& atoms = GjsContextPrivate::atoms(cx);
-    JS::RootedValue v_prototype(cx, JS::ObjectValue(*prototype));
+    JS::RootedValue v_prototype(cx, JS::ObjectValue(*interface_prototype));
     if (!JS_SetPropertyById(cx, accessor, atoms.prototype(), v_prototype))
         return false;
 
@@ -738,7 +751,7 @@ static bool resolve_on_interface_prototype(JSContext* cx,
     target_desc.setGetterObject(getter);
     target_desc.setSetterObject(setter);
 
-    if (!JS_DefinePropertyById(cx, target_prototype, identifier, target_desc))
+    if (!JS_DefinePropertyById(cx, class_prototype, identifier, target_desc))
         return false;
 
     *found = true;
diff --git a/installed-tests/js/testGObjectInterface.js b/installed-tests/js/testGObjectInterface.js
index 2451de06..cbeaa4f9 100644
--- a/installed-tests/js/testGObjectInterface.js
+++ b/installed-tests/js/testGObjectInterface.js
@@ -330,6 +330,9 @@ describe('GObject interface', function () {
 
             Gio.File.prototype._originalDup = 5;
             expect(file._originalDup).toBe(5);
+
+            delete Gio.File.prototype._originalDup;
+            expect(file._originalDup).not.toBeDefined();
         });
 
         it('original property can be shadowed by class prototype property', function () {
@@ -347,6 +350,14 @@ describe('GObject interface', function () {
             expect(Gio._LocalFilePrototype.dup).toHaveBeenCalled();
             expect(Gio.File.prototype.dup).not.toHaveBeenCalled();
         });
+
+        it('shadowed property can be restored', function () {
+            Gio._LocalFilePrototype.dup = 5;
+            expect(file.dup).toBe(5);
+
+            delete Gio._LocalFilePrototype.dup;
+            expect(file.dup).toBeInstanceOf(Function);
+        });
     });
 });
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]