diff --git a/libraries/metavoxels/src/SharedObject.cpp b/libraries/metavoxels/src/SharedObject.cpp index c3a224103d..b542299d00 100644 --- a/libraries/metavoxels/src/SharedObject.cpp +++ b/libraries/metavoxels/src/SharedObject.cpp @@ -63,6 +63,12 @@ SharedObject* SharedObject::clone() const { bool SharedObject::equals(const SharedObject* other) const { // default behavior is to compare the properties + if (!other) { + return false; + } + if (other == this) { + return true; + } const QMetaObject* metaObject = this->metaObject(); if (metaObject != other->metaObject()) { return false; diff --git a/libraries/metavoxels/src/SharedObject.h b/libraries/metavoxels/src/SharedObject.h index 44bfb73a22..f83079b0fa 100644 --- a/libraries/metavoxels/src/SharedObject.h +++ b/libraries/metavoxels/src/SharedObject.h @@ -173,6 +173,11 @@ template<class T, SharedObjectFn Inc, SharedObjectFn Dec> uint qHash( return qHash(pointer.data(), seed); } +template<class T, SharedObjectFn Inc, SharedObjectFn Dec, class X, SharedObjectFn Inc2, SharedObjectFn Dec2> bool equals( + const SharedObjectPointerTemplate<T, Inc, Dec>& first, const SharedObjectPointerTemplate<X, Inc2, Dec2>& second) { + return first ? first->equals(second) : !second; +} + typedef SharedObjectPointerTemplate<SharedObject> SharedObjectPointer; Q_DECLARE_METATYPE(SharedObjectPointer) diff --git a/tests/metavoxels/src/MetavoxelTests.cpp b/tests/metavoxels/src/MetavoxelTests.cpp index 530f7e3108..f06658da68 100644 --- a/tests/metavoxels/src/MetavoxelTests.cpp +++ b/tests/metavoxels/src/MetavoxelTests.cpp @@ -12,6 +12,9 @@ #include "MetavoxelTests.h" +REGISTER_META_OBJECT(TestSharedObjectA) +REGISTER_META_OBJECT(TestSharedObjectB) + MetavoxelTests::MetavoxelTests(int& argc, char** argv) : QCoreApplication(argc, argv) { } @@ -26,6 +29,8 @@ static int reliableMessagesSent = 0; static int reliableMessagesReceived = 0; static int streamedBytesSent = 0; static int streamedBytesReceived = 0; +static int sharedObjectsCreated = 0; +static int sharedObjectsDestroyed = 0; bool MetavoxelTests::run() { @@ -54,6 +59,7 @@ bool MetavoxelTests::run() { qDebug() << "Sent" << reliableMessagesSent << "reliable messages, received" << reliableMessagesReceived; qDebug() << "Sent" << streamedBytesSent << "streamed bytes, received" << streamedBytesReceived; qDebug() << "Sent" << datagramsSent << "datagrams, received" << datagramsReceived; + qDebug() << "Created" << sharedObjectsCreated << "shared objects, destroyed" << sharedObjectsDestroyed; qDebug() << "All tests passed!"; @@ -74,6 +80,15 @@ static QByteArray createRandomBytes() { return createRandomBytes(MIN_BYTES, MAX_BYTES); } +static SharedObjectPointer createRandomSharedObject() { + switch (randIntInRange(0, 2)) { + case 0: return new TestSharedObjectA(randFloat()); + case 1: return new TestSharedObjectB(); + case 2: + default: return SharedObjectPointer(); + } +} + Endpoint::Endpoint(const QByteArray& datagramHeader) : _sequencer(new DatagramSequencer(datagramHeader, this)), _highPriorityMessagesToSend(0.0f), @@ -110,7 +125,7 @@ static QVariant createRandomMessage() { return QVariant::fromValue(message); } case 1: { - TestMessageB message = { createRandomBytes() }; + TestMessageB message = { createRandomBytes(), createRandomSharedObject() }; return QVariant::fromValue(message); } case 2: @@ -132,10 +147,15 @@ static bool messagesEqual(const QVariant& firstMessage, const QVariant& secondMe } if (type == TestMessageA::Type) { return firstMessage.value<TestMessageA>() == secondMessage.value<TestMessageA>(); + } else if (type == TestMessageB::Type) { - return firstMessage.value<TestMessageB>() == secondMessage.value<TestMessageB>(); + TestMessageB first = firstMessage.value<TestMessageB>(); + TestMessageB second = secondMessage.value<TestMessageB>(); + return first.foo == second.foo && equals(first.bar, second.bar); + } else if (type == TestMessageC::Type) { return firstMessage.value<TestMessageC>() == secondMessage.value<TestMessageC>(); + } else { return firstMessage == secondMessage; } @@ -277,3 +297,26 @@ void Endpoint::readReliableChannel() { } streamedBytesReceived += bytes.size(); } + +TestSharedObjectA::TestSharedObjectA(float foo) : + _foo(foo) { + sharedObjectsCreated++; +} + +TestSharedObjectA::~TestSharedObjectA() { + sharedObjectsDestroyed++; +} + +void TestSharedObjectA::setFoo(float foo) { + if (_foo != foo) { + emit fooChanged(_foo = foo); + } +} + +TestSharedObjectB::TestSharedObjectB() { + sharedObjectsCreated++; +} + +TestSharedObjectB::~TestSharedObjectB() { + sharedObjectsDestroyed++; +} diff --git a/tests/metavoxels/src/MetavoxelTests.h b/tests/metavoxels/src/MetavoxelTests.h index f19870ac15..3b69c28f79 100644 --- a/tests/metavoxels/src/MetavoxelTests.h +++ b/tests/metavoxels/src/MetavoxelTests.h @@ -64,6 +64,38 @@ private: CircularBuffer _dataStreamed; }; +/// A simple shared object. +class TestSharedObjectA : public SharedObject { + Q_OBJECT + Q_PROPERTY(float foo READ getFoo WRITE setFoo NOTIFY fooChanged) + +public: + + Q_INVOKABLE TestSharedObjectA(float foo = 0.0f); + virtual ~TestSharedObjectA(); + + void setFoo(float foo); + float getFoo() const { return _foo; } + +signals: + + void fooChanged(float foo); + +private: + + float _foo; +}; + +/// Another simple shared object. +class TestSharedObjectB : public SharedObject { + Q_OBJECT + +public: + + Q_INVOKABLE TestSharedObjectB(); + virtual ~TestSharedObjectB(); +}; + /// A simple test message. class TestMessageA { STREAMABLE @@ -84,6 +116,7 @@ class TestMessageB { public: STREAM QByteArray foo; + STREAM SharedObjectPointer bar; }; DECLARE_STREAMABLE_METATYPE(TestMessageB)