From 880ea7c9986b038ead9ac39a62cd7f76a530457b Mon Sep 17 00:00:00 2001 From: Simon Edwards Date: Thu, 5 May 2022 17:10:40 +0200 Subject: [PATCH] Add `QObject.parent()` and infra for correct subclass wrappers --- .../QAbstractItemModel/nabstractitemmodel.hpp | 4 +- .../nodegui/QtCore/QObject/qobject_macro.h | 33 +++++++-- .../QtGui/QApplication/napplication.hpp | 9 +-- .../nodegui/QtWidgets/QWidget/qwidget_macro.h | 2 +- .../nodegui/core/WrapperCache/wrappercache.h | 74 ++++++++----------- src/cpp/lib/QtCore/QObject/qobject_wrap.cpp | 8 +- .../QtGui/QApplication/qapplication_wrap.cpp | 8 +- .../lib/QtGui/QClipboard/qclipboard_wrap.cpp | 1 + src/cpp/lib/QtGui/QScreen/qscreen_wrap.cpp | 1 + src/cpp/lib/QtGui/QWindow/qwindow_wrap.cpp | 5 +- .../lib/QtWidgets/QWidget/qwidget_wrap.cpp | 1 + src/cpp/lib/test/cachetestqobject_wrap.cpp | 7 +- src/lib/core/WrapperCache.ts | 24 +++++- src/lib/core/__test__/CacheTestQObject.ts | 7 +- src/lib/core/__test__/WrapperCache.test.ts | 11 ++- 15 files changed, 109 insertions(+), 86 deletions(-) diff --git a/src/cpp/include/nodegui/QtCore/QAbstractItemModel/nabstractitemmodel.hpp b/src/cpp/include/nodegui/QtCore/QAbstractItemModel/nabstractitemmodel.hpp index 4a79fe8d5..e5e9d4095 100644 --- a/src/cpp/include/nodegui/QtCore/QAbstractItemModel/nabstractitemmodel.hpp +++ b/src/cpp/include/nodegui/QtCore/QAbstractItemModel/nabstractitemmodel.hpp @@ -35,9 +35,7 @@ class DLL_EXPORT NAbstractItemModel : public QAbstractItemModel, return *newIndex; } - QObject *parent() const { - return nullptr; - } + QObject* parent() const { return nullptr; } QModelIndex parent(const QModelIndex& child) const override { Napi::Env env = this->dispatchOnNode.Env(); diff --git a/src/cpp/include/nodegui/QtCore/QObject/qobject_macro.h b/src/cpp/include/nodegui/QtCore/QObject/qobject_macro.h index 13c4859bf..b77773d48 100644 --- a/src/cpp/include/nodegui/QtCore/QObject/qobject_macro.h +++ b/src/cpp/include/nodegui/QtCore/QObject/qobject_macro.h @@ -8,10 +8,9 @@ #include "core/WrapperCache/wrappercache.h" /* - - This macro adds common QObject exported methods - The exported methods are taken into this macro to avoid writing them in each - and every widget we export. + This macro adds common QObject exported methods + The exported methods are taken into this macro to avoid writing them in each + and every widget we export. */ #ifndef QOBJECT_WRAPPED_METHODS_DECLARATION_WITH_EVENT_SOURCE @@ -22,7 +21,8 @@ Napi::Value __id__(const Napi::CallbackInfo& info) { \ Napi::Env env = info.Env(); \ return Napi::Value::From( \ - env, extrautils::hashPointerTo53bit(this->instance.data())); \ + env, extrautils::hashPointerTo53bit( \ + static_cast(this->instance.data()))); \ } \ Napi::Value inherits(const Napi::CallbackInfo& info) { \ Napi::Env env = info.Env(); \ @@ -93,7 +93,7 @@ } \ Napi::Value parent(const Napi::CallbackInfo& info) { \ Napi::Env env = info.Env(); \ - QObject *parent = this->instance->parent(); \ + QObject* parent = this->instance->parent(); \ if (parent) { \ return WrapperCache::instance.getWrapper(env, parent); \ } else { \ @@ -109,8 +109,7 @@ Napi::Env env = info.Env(); \ delete static_cast(this->instance); \ return env.Null(); \ - } \ - + } // Ideally this macro below should go in // QOBJECT_WRAPPED_METHODS_DECLARATION_WITH_EVENT_SOURCE but some wrappers @@ -176,4 +175,22 @@ #define QOBJECT_SIGNALS QOBJECT_SIGNALS_ON_TARGET(this) #endif // QOBJECT_SIGNALS +/* + Macro to register a function to wrap QObject pointers of a + given subclass to wrapper instances. First parameter is the + plain name of the QObject subclass (no quotes), seconds is the + name of the wrapper class. + */ +#ifndef QOBJECT_REGISTER_WRAPPER +#define QOBJECT_REGISTER_WRAPPER(qobjectType, ComponentWrapName) \ + WrapperCache::instance.registerWrapper( \ + QString(#qobjectType), \ + [](Napi::Env env, QObject* qobject) -> Napi::Object { \ + qobjectType* exactQObject = dynamic_cast(qobject); \ + Napi::Object wrapper = ComponentWrapName::constructor.New( \ + {Napi::External::New(env, exactQObject)}); \ + return wrapper; \ + }); +#endif // QOBJECT_REGISTER_WRAPPER + #include "QtCore/QObject/qobject_wrap.h" diff --git a/src/cpp/include/nodegui/QtGui/QApplication/napplication.hpp b/src/cpp/include/nodegui/QtGui/QApplication/napplication.hpp index 7280d9336..4e58fd592 100644 --- a/src/cpp/include/nodegui/QtGui/QApplication/napplication.hpp +++ b/src/cpp/include/nodegui/QtGui/QApplication/napplication.hpp @@ -29,8 +29,7 @@ class DLL_EXPORT NApplication : public QApplication, public EventWidget { this, &QGuiApplication::primaryScreenChanged, [=](QScreen* screen) { Napi::Env env = this->emitOnNode.Env(); Napi::HandleScope scope(env); - auto instance = - WrapperCache::instance.get(env, screen, &QScreenWrap::constructor, false); + auto instance = WrapperCache::instance.getWrapper(env, screen, true); this->emitOnNode.Call( {Napi::String::New(env, "primaryScreenChanged"), instance}); }); @@ -38,8 +37,7 @@ class DLL_EXPORT NApplication : public QApplication, public EventWidget { QObject::connect(this, &QGuiApplication::screenAdded, [=](QScreen* screen) { Napi::Env env = this->emitOnNode.Env(); Napi::HandleScope scope(env); - auto instance = - WrapperCache::instance.get(env, screen, &QScreenWrap::constructor, false); + auto instance = WrapperCache::instance.getWrapper(env, screen, true); this->emitOnNode.Call({Napi::String::New(env, "screenAdded"), instance}); }); @@ -47,8 +45,7 @@ class DLL_EXPORT NApplication : public QApplication, public EventWidget { this, &QGuiApplication::screenRemoved, [=](QScreen* screen) { Napi::Env env = this->emitOnNode.Env(); Napi::HandleScope scope(env); - auto instance = - WrapperCache::instance.get(env, screen, &QScreenWrap::constructor, false); + auto instance = WrapperCache::instance.getWrapper(env, screen, true); this->emitOnNode.Call( {Napi::String::New(env, "screenRemoved"), instance}); }); diff --git a/src/cpp/include/nodegui/QtWidgets/QWidget/qwidget_macro.h b/src/cpp/include/nodegui/QtWidgets/QWidget/qwidget_macro.h index 4dd0f1c27..93e313677 100644 --- a/src/cpp/include/nodegui/QtWidgets/QWidget/qwidget_macro.h +++ b/src/cpp/include/nodegui/QtWidgets/QWidget/qwidget_macro.h @@ -427,7 +427,7 @@ Napi::Env env = info.Env(); \ QWindow* window = this->instance->windowHandle(); \ if (window) { \ - return WrapperCache::instance.get(env, window, &QWindowWrap::constructor, false); \ + return WrapperCache::instance.getWrapper(env, window, true); \ } else { \ return env.Null(); \ } \ diff --git a/src/cpp/include/nodegui/core/WrapperCache/wrappercache.h b/src/cpp/include/nodegui/core/WrapperCache/wrappercache.h index 7c8037c53..b633c8890 100644 --- a/src/cpp/include/nodegui/core/WrapperCache/wrappercache.h +++ b/src/cpp/include/nodegui/core/WrapperCache/wrappercache.h @@ -2,19 +2,19 @@ #include +#include #include #include #include "Extras/Export/export.h" #include "Extras/Utils/nutils.h" - struct CachedObject { napi_ref ref; napi_env env; }; -typedef Napi::Object (*WrapFunc)(Napi::Env, QObject *); +typedef Napi::Object (*WrapFunc)(Napi::Env, QObject*); /** * C++ side cache for wrapper objects. @@ -37,41 +37,28 @@ class DLL_EXPORT WrapperCache : public QObject { static WrapperCache instance; /** - * Get a wrapper for a given Qt object. + * Register a function to wrap certain instances of a `QObject` subclass. * - * @param T - (template argument) The Qt class of the object being cached, - * e.g. `QScreen`. - * @param W - (template argument) The wrapper type which matches the object - * `QScreenWrap`. - * @param env = Napi environment - * @param object - Pointer to the QObject for which a wrapper is required. - * @return The JS wrapper object. + * @param typeName - The name of the `QObject` subclass this wrapper function + * applies to. + * @param wrapFunc - Function to wrap `QObject` instances. */ - template - Napi::Object get(Napi::Env env, T* object, Napi::FunctionReference* constructorFunc, bool isCreatedByNodeGui) { - uint64_t ptrHash = extrautils::hashPointerTo53bit(object); - if (this->cache.contains(ptrHash)) { - napi_value result = nullptr; - napi_get_reference_value(env, this->cache[ptrHash].ref, &result); - - napi_valuetype valuetype; - napi_typeof(env, result, &valuetype); - if (valuetype != napi_null) { - return Napi::Object(env, result); - } - } - - Napi::Object wrapper = constructorFunc->New({Napi::External::New(env, object)}); - - store(env, extrautils::hashPointerTo53bit(object), object, wrapper, isCreatedByNodeGui); - return wrapper; - } - void registerWrapper(QString typeName, WrapFunc wrapFunc) { this->wrapperRegistry[typeName] = wrapFunc; } - Napi::Value getWrapper(Napi::Env env, QObject* qobject) { + /** + * Get a wrapper for a QObject + * + * @param env - Napi environment + * @param qobject - The QObject or subclass instance to wrap + * @param keepAlive - Set this to true if the wrapper object should be kept + * alive until the underlying QObject is destroyed regardless of whether + * the JS side holding a reference to it or not. (Defaults to false). + * @return Napi object wrapping the object + */ + Napi::Value getWrapper(Napi::Env env, QObject* qobject, + bool keepAlive = false) { if (qobject == nullptr) { return env.Null(); } @@ -88,10 +75,15 @@ class DLL_EXPORT WrapperCache : public QObject { } } - // QString className(object->metaObject()->className()); - // if (this->wrapperRegistry.contains(className)) { - // this->wrapperRegistry[className] - // } + QString className(qobject->metaObject()->className()); + if (this->wrapperRegistry.contains(className)) { + Napi::Object wrapper = this->wrapperRegistry[className](env, qobject); + store(env, ptrHash, qobject, wrapper, !keepAlive); + return wrapper; + } else { + qDebug() << "NodeGui: Unable to find wrapper for instance of class " + << className << ".\n\n"; + } return env.Null(); } @@ -107,7 +99,8 @@ class DLL_EXPORT WrapperCache : public QObject { * @param object - Pointer to the QObject for which a wrapper is required. * @param wrapper - The wrapper object matching `object`. */ - void store(Napi::Env env, uint64_t ptrHash, QObject *qobject, Napi::Object wrapper, bool isWeak) { + void store(Napi::Env env, uint64_t ptrHash, QObject* qobject, + Napi::Object wrapper, bool isWeak) { napi_ref ref = nullptr; napi_create_reference(env, wrapper, isWeak ? 0 : 1, &ref); @@ -121,8 +114,7 @@ class DLL_EXPORT WrapperCache : public QObject { static Napi::Object init(Napi::Env env, Napi::Object exports) { exports.Set("WrapperCache_injectCallback", Napi::Function::New(env)); - exports.Set("WrapperCache_store", - Napi::Function::New(env)); + exports.Set("WrapperCache_store", Napi::Function::New(env)); return exports; } @@ -158,14 +150,10 @@ class DLL_EXPORT WrapperCache : public QObject { if (destroyedCallback) { Napi::Env env = destroyedCallback.Env(); Napi::HandleScope scope(env); - destroyedCallback.Call( - env.Global(), - {Napi::Value::From(env, ptrHash)}); + destroyedCallback.Call(env.Global(), {Napi::Value::From(env, ptrHash)}); } uint32_t result = 0; -// TODO: Grab the wrapper C++ object and null out its ref to the Qt object. - napi_reference_unref(this->cache[ptrHash].env, this->cache[ptrHash].ref, &result); this->cache.remove(ptrHash); diff --git a/src/cpp/lib/QtCore/QObject/qobject_wrap.cpp b/src/cpp/lib/QtCore/QObject/qobject_wrap.cpp index 1a467a95d..61aff178f 100644 --- a/src/cpp/lib/QtCore/QObject/qobject_wrap.cpp +++ b/src/cpp/lib/QtCore/QObject/qobject_wrap.cpp @@ -12,13 +12,7 @@ Napi::Object QObjectWrap::init(Napi::Env env, Napi::Object exports) { env, CLASSNAME, {QOBJECT_WRAPPED_METHODS_EXPORT_DEFINE(QObjectWrap)}); constructor = Napi::Persistent(func); exports.Set(CLASSNAME, func); - - WrapperCache::instance.registerWrapper(QString("NObject"), - [](Napi::Env env, QObject *qobject) -> Napi::Object { - QObject *exactQObject = dynamic_cast(qobject); - Napi::Object wrapper = QObjectWrap::constructor.New({Napi::External::New(env, exactQObject)}); - return wrapper; - }); + QOBJECT_REGISTER_WRAPPER(NObject, QObjectWrap); return exports; } diff --git a/src/cpp/lib/QtGui/QApplication/qapplication_wrap.cpp b/src/cpp/lib/QtGui/QApplication/qapplication_wrap.cpp index a17e33367..32739150b 100644 --- a/src/cpp/lib/QtGui/QApplication/qapplication_wrap.cpp +++ b/src/cpp/lib/QtGui/QApplication/qapplication_wrap.cpp @@ -118,8 +118,7 @@ Napi::Value StaticQApplicationWrapMethods::clipboard( Napi::Env env = info.Env(); QClipboard* clipboard = QApplication::clipboard(); if (clipboard) { - return WrapperCache::instance.get(env, - clipboard, &QClipboardWrap::constructor, false); + return WrapperCache::instance.getWrapper(env, clipboard, true); } else { return env.Null(); } @@ -163,7 +162,7 @@ Napi::Value StaticQApplicationWrapMethods::primaryScreen( Napi::Env env = info.Env(); auto screen = QApplication::primaryScreen(); if (screen) { - return WrapperCache::instance.get(env, screen, &QScreenWrap::constructor, false); + return WrapperCache::instance.getWrapper(env, screen, true); } else { return env.Null(); } @@ -176,8 +175,7 @@ Napi::Value StaticQApplicationWrapMethods::screens( Napi::Array jsArray = Napi::Array::New(env, screens.size()); for (int i = 0; i < screens.size(); i++) { QScreen* screen = screens[i]; - auto instance = - WrapperCache::instance.get(env, screen, &QScreenWrap::constructor, false); + auto instance = WrapperCache::instance.getWrapper(env, screen, true); jsArray[i] = instance; } return jsArray; diff --git a/src/cpp/lib/QtGui/QClipboard/qclipboard_wrap.cpp b/src/cpp/lib/QtGui/QClipboard/qclipboard_wrap.cpp index 68d00e6d1..0eca693d9 100644 --- a/src/cpp/lib/QtGui/QClipboard/qclipboard_wrap.cpp +++ b/src/cpp/lib/QtGui/QClipboard/qclipboard_wrap.cpp @@ -19,6 +19,7 @@ Napi::Object QClipboardWrap::init(Napi::Env env, Napi::Object exports) { QOBJECT_WRAPPED_METHODS_EXPORT_DEFINE(QClipboardWrap)}); constructor = Napi::Persistent(func); exports.Set(CLASSNAME, func); + QOBJECT_REGISTER_WRAPPER(QClipboard, QClipboardWrap); return exports; } diff --git a/src/cpp/lib/QtGui/QScreen/qscreen_wrap.cpp b/src/cpp/lib/QtGui/QScreen/qscreen_wrap.cpp index 24ef717b7..f3a8064e4 100644 --- a/src/cpp/lib/QtGui/QScreen/qscreen_wrap.cpp +++ b/src/cpp/lib/QtGui/QScreen/qscreen_wrap.cpp @@ -16,6 +16,7 @@ Napi::Object QScreenWrap::init(Napi::Env env, Napi::Object exports) { QOBJECT_WRAPPED_METHODS_EXPORT_DEFINE(QScreenWrap)}); constructor = Napi::Persistent(func); exports.Set(CLASSNAME, func); + QOBJECT_REGISTER_WRAPPER(QScreen, QScreenWrap); return exports; } diff --git a/src/cpp/lib/QtGui/QWindow/qwindow_wrap.cpp b/src/cpp/lib/QtGui/QWindow/qwindow_wrap.cpp index 0058cf299..78fdc4333 100644 --- a/src/cpp/lib/QtGui/QWindow/qwindow_wrap.cpp +++ b/src/cpp/lib/QtGui/QWindow/qwindow_wrap.cpp @@ -55,8 +55,7 @@ void QWindowWrap::connectSignalsToEventEmitter() { this->instance.data(), &QWindow::screenChanged, [=](QScreen* screen) { Napi::Env env = this->emitOnNode.Env(); Napi::HandleScope scope(env); - auto instance = - WrapperCache::instance.get(env, screen, &QScreenWrap::constructor, false); + auto instance = WrapperCache::instance.getWrapper(env, screen, true); this->emitOnNode.Call( {Napi::String::New(env, "screenChanged"), instance}); }); @@ -81,7 +80,7 @@ Napi::Value QWindowWrap::screen(const Napi::CallbackInfo& info) { Napi::Env env = info.Env(); QScreen* screen = this->instance->screen(); if (screen) { - return WrapperCache::instance.get(env, screen, &QScreenWrap::constructor, false); + return WrapperCache::instance.getWrapper(env, screen, true); } else { return env.Null(); } diff --git a/src/cpp/lib/QtWidgets/QWidget/qwidget_wrap.cpp b/src/cpp/lib/QtWidgets/QWidget/qwidget_wrap.cpp index 4079a0b12..3d0976535 100644 --- a/src/cpp/lib/QtWidgets/QWidget/qwidget_wrap.cpp +++ b/src/cpp/lib/QtWidgets/QWidget/qwidget_wrap.cpp @@ -12,6 +12,7 @@ Napi::Object QWidgetWrap::init(Napi::Env env, Napi::Object exports) { env, CLASSNAME, {QWIDGET_WRAPPED_METHODS_EXPORT_DEFINE(QWidgetWrap)}); constructor = Napi::Persistent(func); exports.Set(CLASSNAME, func); + QOBJECT_REGISTER_WRAPPER(NWidget, QWidgetWrap); return exports; } diff --git a/src/cpp/lib/test/cachetestqobject_wrap.cpp b/src/cpp/lib/test/cachetestqobject_wrap.cpp index 2f2624d51..ccb040fe9 100644 --- a/src/cpp/lib/test/cachetestqobject_wrap.cpp +++ b/src/cpp/lib/test/cachetestqobject_wrap.cpp @@ -16,6 +16,7 @@ Napi::Object CacheTestQObjectWrap::init(Napi::Env env, Napi::Object exports) { QOBJECT_WRAPPED_METHODS_EXPORT_DEFINE(CacheTestQObjectWrap)}); constructor = Napi::Persistent(func); exports.Set(CLASSNAME, func); + QOBJECT_REGISTER_WRAPPER(CacheTestQObject, CacheTestQObjectWrap); return exports; } @@ -47,8 +48,7 @@ void CacheTestQObjectWrap::connectSignalsToEventEmitter() { Napi::Value CacheTestQObjectWrap::foo(const Napi::CallbackInfo& info) { Napi::Env env = info.Env(); CacheTestQObject* foo = this->instance->foo(); - return WrapperCache::instance.get( - env, foo, &CacheTestQObjectWrap::constructor, false); + return WrapperCache::instance.getWrapper(env, foo); } Napi::Value CacheTestQObjectWrap::clearFoo(const Napi::CallbackInfo& info) { @@ -60,6 +60,5 @@ Napi::Value CacheTestQObjectWrap::clearFoo(const Napi::CallbackInfo& info) { Napi::Value CacheTestQObjectWrap::bar(const Napi::CallbackInfo& info) { Napi::Env env = info.Env(); CacheTestQObject* bar = this->instance->bar(); - return WrapperCache::instance.get( - env, bar, &CacheTestQObjectWrap::constructor, false); + return WrapperCache::instance.getWrapper(env, bar); } diff --git a/src/lib/core/WrapperCache.ts b/src/lib/core/WrapperCache.ts index ae07fb28b..61e036cfa 100644 --- a/src/lib/core/WrapperCache.ts +++ b/src/lib/core/WrapperCache.ts @@ -1,3 +1,4 @@ +import { QObject } from '../QtCore/QObject'; import addon from '../utils/addon'; import { NativeElement } from './Component'; @@ -15,11 +16,17 @@ import { NativeElement } from './Component'; export class WrapperCache { private _strongCache = new Map(); private _weakCache = new Map>(); + private _wrapperRegistry = new Map(); constructor() { addon.WrapperCache_injectCallback(this._objectDestroyedCallback.bind(this)); } + _flush(): void { + this._strongCache = new Map(); + this._weakCache = new Map>(); + } + private _objectDestroyedCallback(objectId: number): void { if (this._strongCache.has(objectId)) { const wrapper = this._strongCache.get(objectId); @@ -47,12 +54,13 @@ export class WrapperCache { return wrapper; } + // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types getWrapper(native: any): QObject | null { if (native == null) { return null; } - const id = native.__id__(); + const id = native.__id__(); if (this._strongCache.has(id)) { return this._strongCache.get(id); } @@ -65,7 +73,19 @@ export class WrapperCache { } } - return null; // FIXME: Create new wrapper on demand. + if (this._wrapperRegistry.has(native.wrapperType)) { + const wrapper = new (this._wrapperRegistry.get(native.wrapperType))(native); + this.store(wrapper); + return wrapper; + } else { + console.log(`NodeGui: Unable to find JS wrapper for type '${native.wrapperType}'.`); + } + + return null; + } + + registerWrapper(qobjectClassName: string, wrapperConstructor: { new (native: any): QObject }): void { + this._wrapperRegistry.set(qobjectClassName, wrapperConstructor); } store(wrapper: QObject): void { diff --git a/src/lib/core/__test__/CacheTestQObject.ts b/src/lib/core/__test__/CacheTestQObject.ts index b3235bfa8..3ee23ea0e 100644 --- a/src/lib/core/__test__/CacheTestQObject.ts +++ b/src/lib/core/__test__/CacheTestQObject.ts @@ -6,7 +6,7 @@ import { wrapperCache } from '../../core/WrapperCache'; export class CacheTestQObject extends QObject { constructor(arg?: NativeElement) { let native; - if (native == null) { + if (arg == null) { native = new addon.CacheTestQObject(); } else { native = arg; @@ -16,7 +16,7 @@ export class CacheTestQObject extends QObject { } foo(): CacheTestQObject { - return wrapperCache.get(CacheTestQObject, this.native.foo()); + return wrapperCache.getWrapper(this.native.foo()) as CacheTestQObject; } clearFoo(): void { @@ -24,6 +24,7 @@ export class CacheTestQObject extends QObject { } bar(): CacheTestQObject { - return wrapperCache.get(CacheTestQObject, this.native.bar()); + return wrapperCache.getWrapper(this.native.bar()) as CacheTestQObject; } } +wrapperCache.registerWrapper('CacheTestQObjectWrap', CacheTestQObject); diff --git a/src/lib/core/__test__/WrapperCache.test.ts b/src/lib/core/__test__/WrapperCache.test.ts index 4f614b762..ddae7f3cf 100644 --- a/src/lib/core/__test__/WrapperCache.test.ts +++ b/src/lib/core/__test__/WrapperCache.test.ts @@ -1,12 +1,14 @@ import { QObject } from '../../QtCore/QObject'; import { QApplication } from '../../QtGui/QApplication'; import { CacheTestQObject } from './CacheTestQObject'; +import { wrapperCache } from '../WrapperCache'; describe('WrapperCache using CacheTestQObject', () => { const qApp = QApplication.instance(); qApp.setQuitOnLastWindowClosed(true); it('Cached foo', () => { + wrapperCache._flush(); const a = new CacheTestQObject(); expect(a).not.toBeNull(); @@ -14,11 +16,12 @@ describe('WrapperCache using CacheTestQObject', () => { expect(foo).not.toBeNull(); const foo2 = a.foo(); - expect(foo).toBe(foo2); expect(foo.native.__id__()).toBe(foo2.native.__id__()); + expect(foo).toBe(foo2); }); it('clearFoo() and wrapper expiration', () => { + wrapperCache._flush(); const a = new CacheTestQObject(); const foo = a.foo(); a.clearFoo(); @@ -26,6 +29,7 @@ describe('WrapperCache using CacheTestQObject', () => { }); it('clearFoo() and new wrapper', () => { + wrapperCache._flush(); const a = new CacheTestQObject(); const foo = a.foo(); const fooId = foo.native.__id__(); @@ -38,6 +42,7 @@ describe('WrapperCache using CacheTestQObject', () => { }); it('Cached foo and bar', () => { + wrapperCache._flush(); const a = new CacheTestQObject(); const foo = a.foo(); const bar = a.bar(); @@ -46,11 +51,13 @@ describe('WrapperCache using CacheTestQObject', () => { }); it('QObject.parent() can be null', () => { + wrapperCache._flush(); const a = new QObject(); expect(a.parent()).toBeNull(); }); it('QObject.parent() === QObject.parent()', () => { + wrapperCache._flush(); const a = new QObject(); const b = new QObject(a); expect(a.native.__id__()).toEqual(b.parent().native.__id__()); @@ -60,12 +67,14 @@ describe('WrapperCache using CacheTestQObject', () => { }); it('QObject.delete() clears the native field', () => { + wrapperCache._flush(); const a = new QObject(); a.delete(); expect(a.native).toBeNull(); }); it('QObject.delete() clears chains of QObjects and their native field', () => { + wrapperCache._flush(); const a = new QObject(); const b = new QObject(a); a.delete();