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"))));
105 ProxyObject::Spy clientSpy, serverSpy;
106 ProxyObject clientObject{&clientSpy, _clientPeer};
107 ProxyObject serverObject{&serverSpy, _serverPeer};
109 // Deliberately not normalize some of the macro invocations
110 _clientProxy.attachSignal(&clientObject, SIGNAL(sendData(int, const QString&)));
111 _serverProxy.attachSlot(SIGNAL(sendData(int,QString)), &serverObject, SLOT(receiveData(int, const QString&)));
113 _clientProxy.attachSignal(&clientObject, SIGNAL(sendMoreData(int,QString)), SIGNAL(sendExtraData(int,QString)));
114 _serverProxy.attachSlot(SIGNAL(sendExtraData(int, const QString&)), &serverObject, SLOT(receiveExtraData(int,QString)));
116 _serverProxy.attachSignal(&serverObject, SIGNAL(sendData(int,QString)));
117 _clientProxy.attachSlot(SIGNAL(sendData(int, const QString&)), &clientObject, SLOT(receiveData(int,QString)));
119 emit clientObject.sendData(42, "Hello");
120 ASSERT_TRUE(serverSpy.wait());
121 EXPECT_EQ(ProxyObject::Data(42, "Hello"), serverSpy.value());
123 emit clientObject.sendMoreData(42, "Hello");
124 ASSERT_TRUE(serverSpy.wait());
125 EXPECT_EQ(ProxyObject::Data(-42, "HELLO"), serverSpy.value());
127 emit serverObject.sendData(23, "World");
128 ASSERT_TRUE(clientSpy.wait());
129 EXPECT_EQ(ProxyObject::Data(23, "World"), clientSpy.value());
132 // -----------------------------------------------------------------------------------------------------------------------------------------
134 class SyncObj : public SyncableObject
139 Q_PROPERTY(int intProperty READ intProperty WRITE setIntProperty NOTIFY intPropertyChanged)
140 Q_PROPERTY(QString stringProperty READ stringProperty WRITE setStringProperty NOTIFY stringPropertyChanged)
141 Q_PROPERTY(double doubleProperty READ doubleProperty WRITE setDoubleProperty)
144 int intProperty() const
149 QString stringProperty() const
151 return _stringProperty;
154 double doubleProperty() const
156 return _doubleProperty;
159 int syncedInt() const
164 QString syncedString() const
166 return _syncedString;
170 QByteArray initFooData() const
175 void setInitFooData(const QByteArray& data)
178 emit fooDataChanged(data);
181 void setIntProperty(int value)
183 _intProperty = value;
185 emit intPropertyChanged(value);
188 void setStringProperty(const QString& value)
190 _stringProperty = value;
192 emit stringPropertyChanged(value);
195 // Deliberately no sync nor changed signal
196 void setDoubleProperty(double value)
198 _doubleProperty = value;
201 void syncMethod(int intArg, const QString& stringArg)
204 _syncedString = stringArg;
205 SYNC(ARG(intArg), ARG(stringArg));
206 SYNC_OTHER(setIntProperty, ARG(intArg));
207 SYNC_OTHER(setStringProperty, ARG(stringArg));
208 emit syncMethodCalled(intArg, stringArg);
211 void requestMethod(const QString& stringArg, int intArg)
213 REQUEST(ARG(stringArg), ARG(intArg));
214 REQUEST_OTHER(setStringProperty, ARG(stringArg));
215 emit requestMethodCalled(stringArg, intArg);
219 void intPropertyChanged(int);
220 void stringPropertyChanged(const QString&);
221 void fooDataChanged(const QByteArray&);
222 void syncMethodCalled(int, const QString&);
223 void requestMethodCalled(const QString&, int);
227 QString _stringProperty;
228 double _doubleProperty{};
229 QByteArray _fooData{"FOO"};
231 QString _syncedString;
234 TEST_F(SignalProxyTest, syncableObject)
240 EXPECT_CALL(*_clientPeer, Dispatches(InitRequest(Eq("SyncObj"), Eq("Foo"))));
241 EXPECT_CALL(*_serverPeer, Dispatches(InitData(Eq("SyncObj"), Eq("Foo"), QVariantMap{
242 {"stringProperty", "Hello"},
244 {"doubleProperty", 4.2},
249 EXPECT_CALL(*_serverPeer, Dispatches(SyncMessage(Eq("SyncObj"), Eq("Foo"), Eq("setIntProperty"), ElementsAre(23))));
252 EXPECT_CALL(*_serverPeer, Dispatches(SyncMessage(Eq("SyncObj"), Eq("Foo"), Eq("syncMethod"), ElementsAre(42, "World"))));
253 EXPECT_CALL(*_serverPeer, Dispatches(SyncMessage(Eq("SyncObj"), Eq("Foo"), Eq("setIntProperty"), ElementsAre(42))));
254 EXPECT_CALL(*_serverPeer, Dispatches(SyncMessage(Eq("SyncObj"), Eq("Foo"), Eq("setStringProperty"), ElementsAre("World"))));
257 EXPECT_CALL(*_clientPeer, Dispatches(SyncMessage(Eq("SyncObj"), Eq("Foo"), Eq("requestMethod"), ElementsAre("Hello", 23))));
258 EXPECT_CALL(*_clientPeer, Dispatches(SyncMessage(Eq("SyncObj"), Eq("Foo"), Eq("setStringProperty"), ElementsAre("Hello"))));
260 // Update properties (twice)
261 EXPECT_CALL(*_clientPeer, Dispatches(SyncMessage(Eq("SyncObj"), Eq("Foo"), Eq("requestUpdate"), ElementsAre(QVariantMap{
262 {"stringProperty", "Quassel"},
264 {"doubleProperty", 2.3}
266 EXPECT_CALL(*_serverPeer, Dispatches(SyncMessage(Eq("SyncObj"), Eq("Foo"), Eq("setIntProperty"), ElementsAre(17))));
267 EXPECT_CALL(*_serverPeer, Dispatches(SyncMessage(Eq("SyncObj"), Eq("Foo"), Eq("setStringProperty"), ElementsAre("Quassel"))));
268 EXPECT_CALL(*_serverPeer, Dispatches(SyncMessage(Eq("SyncObj"), Eq("Foo"), Eq("update"), ElementsAre(QVariantMap{
269 {"stringProperty", "Quassel"},
271 {"doubleProperty", 2.3}
275 EXPECT_CALL(*_serverPeer, Dispatches(RpcCall(Eq("__objectRenamed__"), ElementsAre("SyncObj", "Bar", "Foo"))));
276 EXPECT_CALL(*_serverPeer, Dispatches(SyncMessage(Eq("SyncObj"), Eq("Bar"), Eq("setStringProperty"), ElementsAre("Hi Universe"))));
281 SyncObj clientObject;
282 SyncObj serverObject;
284 // -- Set initial data
286 serverObject.setIntProperty(42);
287 serverObject.setStringProperty("Hello");
288 serverObject.setDoubleProperty(4.2);
289 serverObject.setObjectName("Foo");
290 clientObject.setObjectName("Foo");
294 spy.connect(&serverObject, &SyncableObject::initDone);
295 _serverProxy.synchronize(&serverObject);
296 ASSERT_TRUE(spy.wait());
297 spy.connect(&clientObject, &SyncableObject::initDone);
298 _clientProxy.synchronize(&clientObject);
299 ASSERT_TRUE(spy.wait());
301 // -- Check if client-side values are as expected
303 EXPECT_EQ(42, clientObject.intProperty());
304 EXPECT_EQ("Hello", clientObject.stringProperty());
305 EXPECT_EQ(4.2, clientObject.doubleProperty());
306 EXPECT_EQ("FOO", clientObject.initFooData());
308 // -- Set int property
309 spy.connect(&clientObject, &SyncObj::intPropertyChanged);
310 serverObject.setIntProperty(23);
311 ASSERT_TRUE(spy.wait());
312 EXPECT_EQ(23, clientObject.intProperty());
316 spy.connect(&clientObject, &SyncObj::syncMethodCalled);
317 serverObject.syncMethod(42, "World");
318 ASSERT_TRUE(spy.wait());
319 EXPECT_EQ(42, clientObject.syncedInt());
320 EXPECT_EQ(42, clientObject.intProperty());
321 EXPECT_EQ("World", clientObject.syncedString());
322 EXPECT_EQ("World", clientObject.stringProperty());
326 spy.connect(&serverObject, &SyncObj::requestMethodCalled);
327 clientObject.requestMethod("Hello", 23);
328 ASSERT_TRUE(spy.wait());
329 EXPECT_EQ("Hello", serverObject.stringProperty());
331 // -- Property update
333 QVariantMap propMap{{"intProperty", 17}, {"stringProperty", "Quassel"}, {"doubleProperty", 2.3}};
334 spy.connect(&serverObject, &SyncableObject::updatedRemotely);
335 clientObject.requestUpdate(propMap);
336 ASSERT_TRUE(spy.wait());
337 // We don't allow client updates yet, so the values shouldn't have changed
338 EXPECT_EQ(23, serverObject.intProperty());
339 EXPECT_EQ("Hello", serverObject.stringProperty());
340 EXPECT_EQ(4.2, serverObject.doubleProperty());
341 // Allow client updates, try again
342 serverObject.setAllowClientUpdates(true);
343 spy.connect(&clientObject, &SyncableObject::updated);
344 clientObject.requestUpdate(propMap);
345 ASSERT_TRUE(spy.wait());
346 EXPECT_EQ(17, serverObject.intProperty());
347 EXPECT_EQ("Quassel", serverObject.stringProperty());
348 EXPECT_EQ(2.3, serverObject.doubleProperty());
349 EXPECT_EQ(17, clientObject.intProperty());
350 EXPECT_EQ("Quassel", clientObject.stringProperty());
351 EXPECT_EQ(2.3, clientObject.doubleProperty());
354 spy.connect(&clientObject, &SyncObj::stringPropertyChanged);
355 serverObject.setObjectName("Bar");
356 serverObject.setStringProperty("Hi Universe");
357 ASSERT_TRUE(spy.wait());
358 EXPECT_EQ("Bar", clientObject.objectName());
359 EXPECT_EQ("Hi Universe", clientObject.stringProperty());
362 #include "signalproxytest.moc"