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)
145 int intProperty() const
150 QString stringProperty() const
152 return _stringProperty;
155 double doubleProperty() const
157 return _doubleProperty;
160 int syncedInt() const
165 QString syncedString() const
167 return _syncedString;
171 QByteArray initFooData() const
176 void setInitFooData(const QByteArray& data)
179 emit fooDataChanged(data);
182 void setIntProperty(int value)
184 _intProperty = value;
186 emit intPropertyChanged(value);
189 void setStringProperty(const QString& value)
191 _stringProperty = value;
193 emit stringPropertyChanged(value);
196 // Deliberately no sync nor changed signal
197 void setDoubleProperty(double value)
199 _doubleProperty = value;
202 void syncMethod(int intArg, const QString& stringArg)
205 _syncedString = stringArg;
206 SYNC(ARG(intArg), ARG(stringArg));
207 SYNC_OTHER(setIntProperty, ARG(intArg));
208 SYNC_OTHER(setStringProperty, ARG(stringArg));
209 emit syncMethodCalled(intArg, stringArg);
212 void requestMethod(const QString& stringArg, int intArg)
214 REQUEST(ARG(stringArg), ARG(intArg));
215 REQUEST_OTHER(setStringProperty, ARG(stringArg));
216 emit requestMethodCalled(stringArg, intArg);
220 void intPropertyChanged(int);
221 void stringPropertyChanged(const QString&);
222 void fooDataChanged(const QByteArray&);
223 void syncMethodCalled(int, const QString&);
224 void requestMethodCalled(const QString&, int);
228 QString _stringProperty;
229 double _doubleProperty{};
230 QByteArray _fooData{"FOO"};
232 QString _syncedString;
235 TEST_F(SignalProxyTest, syncableObject)
241 EXPECT_CALL(*_clientPeer, Dispatches(InitRequest(Eq("SyncObj"), Eq("Foo"))));
242 EXPECT_CALL(*_serverPeer, Dispatches(InitData(Eq("SyncObj"), Eq("Foo"), QVariantMap{
243 {"stringProperty", "Hello"},
245 {"doubleProperty", 4.2},
250 EXPECT_CALL(*_serverPeer, Dispatches(SyncMessage(Eq("SyncObj"), Eq("Foo"), Eq("setIntProperty"), ElementsAre(23))));
253 EXPECT_CALL(*_serverPeer, Dispatches(SyncMessage(Eq("SyncObj"), Eq("Foo"), Eq("syncMethod"), ElementsAre(42, "World"))));
254 EXPECT_CALL(*_serverPeer, Dispatches(SyncMessage(Eq("SyncObj"), Eq("Foo"), Eq("setIntProperty"), ElementsAre(42))));
255 EXPECT_CALL(*_serverPeer, Dispatches(SyncMessage(Eq("SyncObj"), Eq("Foo"), Eq("setStringProperty"), ElementsAre("World"))));
258 EXPECT_CALL(*_clientPeer, Dispatches(SyncMessage(Eq("SyncObj"), Eq("Foo"), Eq("requestMethod"), ElementsAre("Hello", 23))));
259 EXPECT_CALL(*_clientPeer, Dispatches(SyncMessage(Eq("SyncObj"), Eq("Foo"), Eq("setStringProperty"), ElementsAre("Hello"))));
261 // Update properties (twice)
262 EXPECT_CALL(*_clientPeer, Dispatches(SyncMessage(Eq("SyncObj"), Eq("Foo"), Eq("requestUpdate"), ElementsAre(QVariantMap{
263 {"stringProperty", "Quassel"},
265 {"doubleProperty", 2.3}
267 EXPECT_CALL(*_serverPeer, Dispatches(SyncMessage(Eq("SyncObj"), Eq("Foo"), Eq("setIntProperty"), ElementsAre(17))));
268 EXPECT_CALL(*_serverPeer, Dispatches(SyncMessage(Eq("SyncObj"), Eq("Foo"), Eq("setStringProperty"), ElementsAre("Quassel"))));
269 EXPECT_CALL(*_serverPeer, Dispatches(SyncMessage(Eq("SyncObj"), Eq("Foo"), Eq("update"), ElementsAre(QVariantMap{
270 {"stringProperty", "Quassel"},
272 {"doubleProperty", 2.3}
278 SyncObj clientObject;
279 SyncObj serverObject;
281 // -- Set initial data
283 serverObject.setIntProperty(42);
284 serverObject.setStringProperty("Hello");
285 serverObject.setDoubleProperty(4.2);
286 serverObject.setObjectName("Foo");
287 clientObject.setObjectName("Foo");
291 spy.connect(&serverObject, &SyncableObject::initDone);
292 _serverProxy.synchronize(&serverObject);
293 ASSERT_TRUE(spy.wait());
294 spy.connect(&clientObject, &SyncableObject::initDone);
295 _clientProxy.synchronize(&clientObject);
296 ASSERT_TRUE(spy.wait());
298 // -- Check if client-side values are as expected
300 EXPECT_EQ(42, clientObject.intProperty());
301 EXPECT_EQ("Hello", clientObject.stringProperty());
302 EXPECT_EQ(4.2, clientObject.doubleProperty());
303 EXPECT_EQ("FOO", clientObject.initFooData());
305 // -- Set int property
306 spy.connect(&clientObject, &SyncObj::intPropertyChanged);
307 serverObject.setIntProperty(23);
308 ASSERT_TRUE(spy.wait());
309 EXPECT_EQ(23, clientObject.intProperty());
313 spy.connect(&clientObject, &SyncObj::syncMethodCalled);
314 serverObject.syncMethod(42, "World");
315 ASSERT_TRUE(spy.wait());
316 EXPECT_EQ(42, clientObject.syncedInt());
317 EXPECT_EQ(42, clientObject.intProperty());
318 EXPECT_EQ("World", clientObject.syncedString());
319 EXPECT_EQ("World", clientObject.stringProperty());
323 spy.connect(&serverObject, &SyncObj::requestMethodCalled);
324 clientObject.requestMethod("Hello", 23);
325 ASSERT_TRUE(spy.wait());
326 EXPECT_EQ("Hello", serverObject.stringProperty());
328 // -- Property update
330 QVariantMap propMap{{"intProperty", 17}, {"stringProperty", "Quassel"}, {"doubleProperty", 2.3}};
331 spy.connect(&serverObject, &SyncableObject::updatedRemotely);
332 clientObject.requestUpdate(propMap);
333 ASSERT_TRUE(spy.wait());
334 // We don't allow client updates yet, so the values shouldn't have changed
335 EXPECT_EQ(23, serverObject.intProperty());
336 EXPECT_EQ("Hello", serverObject.stringProperty());
337 EXPECT_EQ(4.2, serverObject.doubleProperty());
338 // Allow client updates, try again
339 serverObject.setAllowClientUpdates(true);
340 spy.connect(&clientObject, &SyncableObject::updated);
341 clientObject.requestUpdate(propMap);
342 ASSERT_TRUE(spy.wait());
343 EXPECT_EQ(17, serverObject.intProperty());
344 EXPECT_EQ("Quassel", serverObject.stringProperty());
345 EXPECT_EQ(2.3, serverObject.doubleProperty());
346 EXPECT_EQ(17, clientObject.intProperty());
347 EXPECT_EQ("Quassel", clientObject.stringProperty());
348 EXPECT_EQ(2.3, clientObject.doubleProperty());
351 #include "signalproxytest.moc"