summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarco Trevisan (Treviño) <mail@3v1n0.net>2020-10-09 22:21:20 +0200
committerMarco Trevisan (Treviño) <mail@3v1n0.net>2020-10-14 02:02:35 +0200
commitc20a5168119324d29547eb2013041bbb4a644224 (patch)
tree99ee4dbceed16203a9b0a917ba403c66be467246
parent17217a35238f1001ab2b545b9bddfe4689bf0f38 (diff)
downloadgjs-c20a5168119324d29547eb2013041bbb4a644224.tar.gz
arg-cache: Use simple boxed marshaller if we're handling a GValue method
If our argument is a GValue and it's marked as the instance parameter, then it means we're calling a g_value_* function, and as per this we should not pass a temporary value but we can just pass the object we've initialized locally.
-rw-r--r--gi/arg-cache.cpp4
-rw-r--r--installed-tests/js/meson.build1
-rw-r--r--installed-tests/js/testGObjectValue.js77
3 files changed, 81 insertions, 1 deletions
diff --git a/gi/arg-cache.cpp b/gi/arg-cache.cpp
index c053865e..cb5d660d 100644
--- a/gi/arg-cache.cpp
+++ b/gi/arg-cache.cpp
@@ -1363,7 +1363,9 @@ static bool gjs_arg_cache_build_interface_in_arg(JSContext* cx,
// marshallers know not to copy stuff if we don't need to.
if (gtype == G_TYPE_VALUE) {
- if (self->transfer == GI_TRANSFER_NOTHING && !is_instance_param)
+ if (self->arg_pos == GjsArgumentCache::INSTANCE_PARAM)
+ self->marshallers = &boxed_in_marshallers;
+ else if (self->transfer == GI_TRANSFER_NOTHING && !is_instance_param)
self->marshallers = &gvalue_in_transfer_none_marshallers;
else
self->marshallers = &gvalue_in_marshallers;
diff --git a/installed-tests/js/meson.build b/installed-tests/js/meson.build
index bd80555b..3ea141e0 100644
--- a/installed-tests/js/meson.build
+++ b/installed-tests/js/meson.build
@@ -100,6 +100,7 @@ jasmine_tests = [
'GObject',
'GObjectClass',
'GObjectInterface',
+ 'GObjectValue',
'GTypeClass',
'Importer',
'Introspection',
diff --git a/installed-tests/js/testGObjectValue.js b/installed-tests/js/testGObjectValue.js
new file mode 100644
index 00000000..4e5d03ce
--- /dev/null
+++ b/installed-tests/js/testGObjectValue.js
@@ -0,0 +1,77 @@
+// SPDX-License-Identifier: MIT OR LGPL-2.0-or-later
+// SPDX-FileCopyrightText: 2020 Marco Trevisan <marco.trevisan@canonical.com>
+
+const {GLib, GObject} = imports.gi;
+
+GObject.TYPE_SCHAR = GObject.TYPE_CHAR;
+
+const SIGNED_TYPES = ['schar', 'int', 'int64', 'long'];
+const UNSIGNED_TYPES = ['char', 'uchar', 'uint', 'uint64', 'ulong'];
+const FLOATING_TYPES = ['double', 'float'];
+const SPECIFIC_TYPES = ['gtype', 'boolean', 'string', 'variant'];
+const ALL_TYPES = [...SIGNED_TYPES, ...UNSIGNED_TYPES, ...FLOATING_TYPES, ...SPECIFIC_TYPES];
+
+describe('GObject value (GValue)', function () {
+ let v;
+ beforeEach(function () {
+ v = new GObject.Value();
+ });
+
+ function getDefaultContentByType(type) {
+ if (SIGNED_TYPES.includes(type))
+ return -((Math.random() * 100 | 0) + 1);
+ if (UNSIGNED_TYPES.includes(type))
+ return -getDefaultContentByType('int') + 2;
+ if (FLOATING_TYPES.includes(type))
+ return getDefaultContentByType('uint') + 0.5;
+ if (type === 'string')
+ return `Hello GValue! ${getDefaultContentByType('uint')}`;
+ if (type === 'boolean')
+ return !!(getDefaultContentByType('int') % 2);
+ if (type === 'gtype') {
+ const other = ALL_TYPES[Math.random() * ALL_TYPES.length | 0];
+ return GObject[`TYPE_${other.toUpperCase()}`];
+ }
+ if (type === 'variant') {
+ return new GLib.Variant('a{sv}', {
+ pasta: new GLib.Variant('s', 'Carbonara (con guanciale)'),
+ pizza: new GLib.Variant('s', 'Verace'),
+ randomString: new GLib.Variant('s', getDefaultContentByType('string')),
+ });
+ }
+
+ throw new Error(`No default content set for type ${type}`);
+ }
+
+ ALL_TYPES.forEach(type => {
+ const gtype = GObject[`TYPE_${type.toUpperCase()}`];
+ it(`initializes ${type}`, function () {
+ v.init(gtype);
+ });
+
+ it(`${type} is compatible with itself`, function () {
+ expect(GObject.Value.type_compatible(gtype, gtype)).toBeTruthy();
+ });
+
+ it(`${type} is transformable to itself`, function () {
+ expect(GObject.Value.type_transformable(gtype, gtype)).toBeTruthy();
+ });
+
+ describe('initialized', function () {
+ let randomContent;
+ beforeEach(function () {
+ v.init(gtype);
+ randomContent = getDefaultContentByType(type);
+ });
+
+ it(`sets and gets ${type}`, function () {
+ v[`set_${type}`](randomContent);
+ expect(v[`get_${type}`]()).toEqual(randomContent);
+ });
+ });
+ });
+
+ afterEach(function () {
+ v.unset();
+ });
+});