1 /***************************************************************************
2 * Copyright (C) 2005-2018 by the Quassel Project *
3 * devel@quassel-irc.org *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) version 3. *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
19 ***************************************************************************/
21 #include "signalproxy.h"
28 #include "invocationspy.h"
29 #include "mockedpeer.h"
30 #include "syncableobject.h"
31 #include "testglobal.h"
33 using namespace ::testing;
36 class SignalProxyTest : public QObject, public ::testing::Test
43 // Set up peers and connect the signal proxies so they're ready to use
44 _clientPeer->setPeer(_serverPeer);
45 _serverPeer->setPeer(_clientPeer);
46 _clientProxy.addPeer(_clientPeer);
47 _serverProxy.addPeer(_serverPeer);
51 SignalProxy _clientProxy{SignalProxy::ProxyMode::Client, this};
52 SignalProxy _serverProxy{SignalProxy::ProxyMode::Server, this};
53 MockedPeer* _clientPeer{new MockedPeer{this}};
54 MockedPeer* _serverPeer{new MockedPeer{this}};
57 // -----------------------------------------------------------------------------------------------------------------------------------------
59 // Object for testing attached signals
60 class ProxyObject : public QObject
65 using Data = std::pair<int, QString>;
66 using Spy = ValueSpy<Data>;
68 ProxyObject(Spy* spy, Peer* expectedPeer)
70 , _expectedPeer{expectedPeer}
74 void sendData(int, const QString&);
75 void sendMoreData(int, const QString&);
76 void sendToFunctor(int, const QString&);
79 void receiveData(int i, const QString& s)
81 EXPECT_EQ(_expectedPeer, SignalProxy::current()->sourcePeer());
82 _spy->notify(std::make_pair(i, s));
85 void receiveExtraData(int i, const QString& s)
87 EXPECT_EQ(_expectedPeer, SignalProxy::current()->sourcePeer());
88 _spy->notify(std::make_pair(-i, s.toUpper()));
96 TEST_F(SignalProxyTest, attachSignal)
100 EXPECT_CALL(*_clientPeer, Dispatches(RpcCall(Eq(SIGNAL(sendData(int,QString))), ElementsAre(42, "Hello"))));
101 EXPECT_CALL(*_clientPeer, Dispatches(RpcCall(Eq(SIGNAL(sendExtraData(int,QString))), ElementsAre(42, "Hello"))));
102 EXPECT_CALL(*_serverPeer, Dispatches(RpcCall(Eq("2sendData(int,QString)"), ElementsAre(23, "World"))));
103 EXPECT_CALL(*_serverPeer, Dispatches(RpcCall(Eq("2sendToFunctor(int,QString)"), ElementsAre(17, "Hi Universe"))));
106 ProxyObject::Spy clientSpy, serverSpy;
107 ProxyObject clientObject{&clientSpy, _clientPeer};
108 ProxyObject serverObject{&serverSpy, _serverPeer};
110 // Deliberately not normalize some of the macro invocations
111 _clientProxy.attachSignal(&clientObject, &ProxyObject::sendData);
112 _serverProxy.attachSlot(SIGNAL(sendData(int,QString)), &serverObject, &ProxyObject::receiveData);
114 _clientProxy.attachSignal(&clientObject, &ProxyObject::sendMoreData, SIGNAL(sendExtraData(int, const QString&)));
115 _serverProxy.attachSlot(SIGNAL(sendExtraData(int, const QString&)), &serverObject, &ProxyObject::receiveExtraData);
117 _serverProxy.attachSignal(&serverObject, &ProxyObject::sendData);
118 //_clientProxy.attachSlot(SIGNAL(sendData(int, const QString&)), &clientObject, SLOT(receiveData(int,QString)));
119 _clientProxy.attachSlot(SIGNAL(sendData(int, const QString&)), &clientObject, &ProxyObject::receiveData);
121 _serverProxy.attachSignal(&serverObject, &ProxyObject::sendToFunctor);
122 _clientProxy.attachSlot(SIGNAL(sendToFunctor(int, const QString&)), this, [this, &clientSpy](int i, const QString& s) {
123 EXPECT_EQ(_clientPeer, SignalProxy::current()->sourcePeer());
124 clientSpy.notify(std::make_pair(i, s));
127 emit clientObject.sendData(42, "Hello");
128 ASSERT_TRUE(serverSpy.wait());
129 EXPECT_EQ(ProxyObject::Data(42, "Hello"), serverSpy.value());
131 emit clientObject.sendMoreData(42, "Hello");
132 ASSERT_TRUE(serverSpy.wait());
133 EXPECT_EQ(ProxyObject::Data(-42, "HELLO"), serverSpy.value());
135 emit serverObject.sendData(23, "World");
136 ASSERT_TRUE(clientSpy.wait());
137 EXPECT_EQ(ProxyObject::Data(23, "World"), clientSpy.value());
139 emit serverObject.sendToFunctor(17, "Hi Universe");
140 ASSERT_TRUE(clientSpy.wait());
141 EXPECT_EQ(ProxyObject::Data(17, "Hi Universe"), clientSpy.value());
144 // -----------------------------------------------------------------------------------------------------------------------------------------
146 class SyncObj : public SyncableObject
151 Q_PROPERTY(int intProperty READ intProperty WRITE setIntProperty NOTIFY intPropertyChanged)
152 Q_PROPERTY(QString stringProperty READ stringProperty WRITE setStringProperty NOTIFY stringPropertyChanged)
153 Q_PROPERTY(double doubleProperty READ doubleProperty WRITE setDoubleProperty)
156 int intProperty() const
161 QString stringProperty() const
163 return _stringProperty;
166 double doubleProperty() const
168 return _doubleProperty;
171 int syncedInt() const
176 QString syncedString() const
178 return _syncedString;
182 QByteArray initFooData() const
187 void setInitFooData(const QByteArray& data)
190 emit fooDataChanged(data);
193 void setIntProperty(int value)
195 _intProperty = value;
197 emit intPropertyChanged(value);
200 void setStringProperty(const QString& value)
202 _stringProperty = value;
204 emit stringPropertyChanged(value);
207 // Deliberately no sync nor changed signal
208 void setDoubleProperty(double value)
210 _doubleProperty = value;
213 void syncMethod(int intArg, const QString& stringArg)
216 _syncedString = stringArg;
217 SYNC(ARG(intArg), ARG(stringArg));
218 SYNC_OTHER(setIntProperty, ARG(intArg));
219 SYNC_OTHER(setStringProperty, ARG(stringArg));
220 emit syncMethodCalled(intArg, stringArg);
223 void requestMethod(const QString& stringArg, int intArg)
225 REQUEST(ARG(stringArg), ARG(intArg));
226 REQUEST_OTHER(setStringProperty, ARG(stringArg));
227 emit requestMethodCalled(stringArg, intArg);
231 void intPropertyChanged(int);
232 void stringPropertyChanged(const QString&);
233 void fooDataChanged(const QByteArray&);
234 void syncMethodCalled(int, const QString&);
235 void requestMethodCalled(const QString&, int);
239 QString _stringProperty;
240 double _doubleProperty{};
241 QByteArray _fooData{"FOO"};
243 QString _syncedString;
246 TEST_F(SignalProxyTest, syncableObject)
252 EXPECT_CALL(*_clientPeer, Dispatches(InitRequest(Eq("SyncObj"), Eq("Foo"))));
253 EXPECT_CALL(*_serverPeer, Dispatches(InitData(Eq("SyncObj"), Eq("Foo"), QVariantMap{
254 {"stringProperty", "Hello"},
256 {"doubleProperty", 4.2},
261 EXPECT_CALL(*_serverPeer, Dispatches(SyncMessage(Eq("SyncObj"), Eq("Foo"), Eq("setIntProperty"), ElementsAre(23))));
264 EXPECT_CALL(*_serverPeer, Dispatches(SyncMessage(Eq("SyncObj"), Eq("Foo"), Eq("syncMethod"), ElementsAre(42, "World"))));
265 EXPECT_CALL(*_serverPeer, Dispatches(SyncMessage(Eq("SyncObj"), Eq("Foo"), Eq("setIntProperty"), ElementsAre(42))));
266 EXPECT_CALL(*_serverPeer, Dispatches(SyncMessage(Eq("SyncObj"), Eq("Foo"), Eq("setStringProperty"), ElementsAre("World"))));
269 EXPECT_CALL(*_clientPeer, Dispatches(SyncMessage(Eq("SyncObj"), Eq("Foo"), Eq("requestMethod"), ElementsAre("Hello", 23))));
270 EXPECT_CALL(*_clientPeer, Dispatches(SyncMessage(Eq("SyncObj"), Eq("Foo"), Eq("setStringProperty"), ElementsAre("Hello"))));
272 // Update properties (twice)
273 EXPECT_CALL(*_clientPeer, Dispatches(SyncMessage(Eq("SyncObj"), Eq("Foo"), Eq("requestUpdate"), ElementsAre(QVariantMap{
274 {"stringProperty", "Quassel"},
276 {"doubleProperty", 2.3}
278 EXPECT_CALL(*_serverPeer, Dispatches(SyncMessage(Eq("SyncObj"), Eq("Foo"), Eq("setIntProperty"), ElementsAre(17))));
279 EXPECT_CALL(*_serverPeer, Dispatches(SyncMessage(Eq("SyncObj"), Eq("Foo"), Eq("setStringProperty"), ElementsAre("Quassel"))));
280 EXPECT_CALL(*_serverPeer, Dispatches(SyncMessage(Eq("SyncObj"), Eq("Foo"), Eq("update"), ElementsAre(QVariantMap{
281 {"stringProperty", "Quassel"},
283 {"doubleProperty", 2.3}
287 EXPECT_CALL(*_serverPeer, Dispatches(RpcCall(Eq("__objectRenamed__"), ElementsAre("SyncObj", "Bar", "Foo"))));
288 EXPECT_CALL(*_serverPeer, Dispatches(SyncMessage(Eq("SyncObj"), Eq("Bar"), Eq("setStringProperty"), ElementsAre("Hi Universe"))));
293 SyncObj clientObject;
294 SyncObj serverObject;
296 // -- Set initial data
298 serverObject.setIntProperty(42);
299 serverObject.setStringProperty("Hello");
300 serverObject.setDoubleProperty(4.2);
301 serverObject.setObjectName("Foo");
302 clientObject.setObjectName("Foo");
306 spy.connect(&serverObject, &SyncableObject::initDone);
307 _serverProxy.synchronize(&serverObject);
308 ASSERT_TRUE(spy.wait());
309 spy.connect(&clientObject, &SyncableObject::initDone);
310 _clientProxy.synchronize(&clientObject);
311 ASSERT_TRUE(spy.wait());
313 // -- Check if client-side values are as expected
315 EXPECT_EQ(42, clientObject.intProperty());
316 EXPECT_EQ("Hello", clientObject.stringProperty());
317 EXPECT_EQ(4.2, clientObject.doubleProperty());
318 EXPECT_EQ("FOO", clientObject.initFooData());
320 // -- Set int property
321 spy.connect(&clientObject, &SyncObj::intPropertyChanged);
322 serverObject.setIntProperty(23);
323 ASSERT_TRUE(spy.wait());
324 EXPECT_EQ(23, clientObject.intProperty());
328 spy.connect(&clientObject, &SyncObj::syncMethodCalled);
329 serverObject.syncMethod(42, "World");
330 ASSERT_TRUE(spy.wait());
331 EXPECT_EQ(42, clientObject.syncedInt());
332 EXPECT_EQ(42, clientObject.intProperty());
333 EXPECT_EQ("World", clientObject.syncedString());
334 EXPECT_EQ("World", clientObject.stringProperty());
338 spy.connect(&serverObject, &SyncObj::requestMethodCalled);
339 clientObject.requestMethod("Hello", 23);
340 ASSERT_TRUE(spy.wait());
341 EXPECT_EQ("Hello", serverObject.stringProperty());
343 // -- Property update
345 QVariantMap propMap{{"intProperty", 17}, {"stringProperty", "Quassel"}, {"doubleProperty", 2.3}};
346 spy.connect(&serverObject, &SyncableObject::updatedRemotely);
347 clientObject.requestUpdate(propMap);
348 ASSERT_TRUE(spy.wait());
349 // We don't allow client updates yet, so the values shouldn't have changed
350 EXPECT_EQ(23, serverObject.intProperty());
351 EXPECT_EQ("Hello", serverObject.stringProperty());
352 EXPECT_EQ(4.2, serverObject.doubleProperty());
353 // Allow client updates, try again
354 serverObject.setAllowClientUpdates(true);
355 spy.connect(&clientObject, &SyncableObject::updated);
356 clientObject.requestUpdate(propMap);
357 ASSERT_TRUE(spy.wait());
358 EXPECT_EQ(17, serverObject.intProperty());
359 EXPECT_EQ("Quassel", serverObject.stringProperty());
360 EXPECT_EQ(2.3, serverObject.doubleProperty());
361 EXPECT_EQ(17, clientObject.intProperty());
362 EXPECT_EQ("Quassel", clientObject.stringProperty());
363 EXPECT_EQ(2.3, clientObject.doubleProperty());
366 spy.connect(&clientObject, &SyncObj::stringPropertyChanged);
367 serverObject.setObjectName("Bar");
368 serverObject.setStringProperty("Hi Universe");
369 ASSERT_TRUE(spy.wait());
370 EXPECT_EQ("Bar", clientObject.objectName());
371 EXPECT_EQ("Hi Universe", clientObject.stringProperty());
374 #include "signalproxytest.moc"