tests: Check that sourcePeer() is set in SignalProxyTest
[quassel.git] / tests / common / signalproxytest.cpp
1 /***************************************************************************
2  *   Copyright (C) 2005-2018 by the Quassel Project                        *
3  *   devel@quassel-irc.org                                                 *
4  *                                                                         *
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.                                           *
9  *                                                                         *
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.                          *
14  *                                                                         *
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  ***************************************************************************/
20
21 #include "signalproxy.h"
22
23 #include <utility>
24
25 #include <QByteArray>
26 #include <QTest>
27
28 #include "invocationspy.h"
29 #include "mockedpeer.h"
30 #include "syncableobject.h"
31 #include "testglobal.h"
32
33 using namespace ::testing;
34 using namespace test;
35
36 class SignalProxyTest : public QObject, public ::testing::Test
37 {
38     Q_OBJECT
39
40 public:
41     void SetUp() override
42     {
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);
48     }
49
50 protected:
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}};
55 };
56
57 // -----------------------------------------------------------------------------------------------------------------------------------------
58
59 // Object for testing attached signals
60 class ProxyObject : public QObject
61 {
62     Q_OBJECT
63
64 public:
65     using Data = std::pair<int, QString>;
66     using Spy = ValueSpy<Data>;
67
68     ProxyObject(Spy* spy, Peer* expectedPeer)
69         : _spy{spy}
70         , _expectedPeer{expectedPeer}
71     {}
72
73 signals:
74     void sendData(int, const QString&);
75     void sendMoreData(int, const QString&);
76     void sendToFunctor(int, const QString&);
77
78 public slots:
79     void receiveData(int i, const QString& s)
80     {
81         EXPECT_EQ(_expectedPeer, SignalProxy::current()->sourcePeer());
82         _spy->notify(std::make_pair(i, s));
83     }
84
85     void receiveExtraData(int i, const QString& s)
86     {
87         EXPECT_EQ(_expectedPeer, SignalProxy::current()->sourcePeer());
88         _spy->notify(std::make_pair(-i, s.toUpper()));
89     }
90
91 private:
92     Spy* _spy;
93     Peer* _expectedPeer;
94 };
95
96 TEST_F(SignalProxyTest, attachSignal)
97 {
98     {
99         InSequence s;
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     }
104
105     ProxyObject::Spy clientSpy, serverSpy;
106     ProxyObject clientObject{&clientSpy, _clientPeer};
107     ProxyObject serverObject{&serverSpy, _serverPeer};
108
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&)));
112
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)));
115
116     _serverProxy.attachSignal(&serverObject, SIGNAL(sendData(int,QString)));
117     _clientProxy.attachSlot(SIGNAL(sendData(int, const QString&)), &clientObject, SLOT(receiveData(int,QString)));
118
119     emit clientObject.sendData(42, "Hello");
120     ASSERT_TRUE(serverSpy.wait());
121     EXPECT_EQ(ProxyObject::Data(42, "Hello"), serverSpy.value());
122
123     emit clientObject.sendMoreData(42, "Hello");
124     ASSERT_TRUE(serverSpy.wait());
125     EXPECT_EQ(ProxyObject::Data(-42, "HELLO"), serverSpy.value());
126
127     emit serverObject.sendData(23, "World");
128     ASSERT_TRUE(clientSpy.wait());
129     EXPECT_EQ(ProxyObject::Data(23, "World"), clientSpy.value());
130 }
131
132 // -----------------------------------------------------------------------------------------------------------------------------------------
133
134 class SyncObj : public SyncableObject
135 {
136     Q_OBJECT
137     SYNCABLE_OBJECT
138
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)
142
143 public:
144
145     int intProperty() const
146     {
147         return _intProperty;
148     }
149
150     QString stringProperty() const
151     {
152         return _stringProperty;
153     }
154
155     double doubleProperty() const
156     {
157         return _doubleProperty;
158     }
159
160     int syncedInt() const
161     {
162         return _syncedInt;
163     }
164
165     QString syncedString() const
166     {
167         return _syncedString;
168     }
169
170 public slots:
171     QByteArray initFooData() const
172     {
173         return _fooData;
174     }
175
176     void setInitFooData(const QByteArray& data)
177     {
178         _fooData = data;
179         emit fooDataChanged(data);
180     }
181
182     void setIntProperty(int value)
183     {
184         _intProperty = value;
185         SYNC(ARG(value));
186         emit intPropertyChanged(value);
187     }
188
189     void setStringProperty(const QString& value)
190     {
191         _stringProperty = value;
192         SYNC(ARG(value));
193         emit stringPropertyChanged(value);
194     }
195
196     // Deliberately no sync nor changed signal
197     void setDoubleProperty(double value)
198     {
199         _doubleProperty = value;
200     }
201
202     void syncMethod(int intArg, const QString& stringArg)
203     {
204         _syncedInt = intArg;
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);
210     }
211
212     void requestMethod(const QString& stringArg, int intArg)
213     {
214         REQUEST(ARG(stringArg), ARG(intArg));
215         REQUEST_OTHER(setStringProperty, ARG(stringArg));
216         emit requestMethodCalled(stringArg, intArg);
217     }
218
219 signals:
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);
225
226 private:
227     int _intProperty{};
228     QString _stringProperty;
229     double _doubleProperty{};
230     QByteArray _fooData{"FOO"};
231     int _syncedInt{};
232     QString _syncedString;
233 };
234
235 TEST_F(SignalProxyTest, syncableObject)
236 {
237     {
238         InSequence s;
239
240         // Synchronize
241         EXPECT_CALL(*_clientPeer, Dispatches(InitRequest(Eq("SyncObj"), Eq("Foo"))));
242         EXPECT_CALL(*_serverPeer, Dispatches(InitData(Eq("SyncObj"), Eq("Foo"), QVariantMap{
243                                                           {"stringProperty", "Hello"},
244                                                           {"intProperty", 42},
245                                                           {"doubleProperty", 4.2},
246                                                           {"FooData", "FOO"}
247                                                       })));
248
249         // Set int property
250         EXPECT_CALL(*_serverPeer, Dispatches(SyncMessage(Eq("SyncObj"), Eq("Foo"), Eq("setIntProperty"), ElementsAre(23))));
251
252         // Sync method
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"))));
256
257         // Request method
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"))));
260
261         // Update properties (twice)
262         EXPECT_CALL(*_clientPeer, Dispatches(SyncMessage(Eq("SyncObj"), Eq("Foo"), Eq("requestUpdate"), ElementsAre(QVariantMap{
263                                                              {"stringProperty", "Quassel"},
264                                                              {"intProperty", 17},
265                                                              {"doubleProperty", 2.3}
266                                                          })))).Times(2);
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"},
271                                                              {"intProperty", 17},
272                                                              {"doubleProperty", 2.3}
273                                                          }))));
274     }
275
276     SignalSpy spy;
277
278     SyncObj clientObject;
279     SyncObj serverObject;
280
281     // -- Set initial data
282
283     serverObject.setIntProperty(42);
284     serverObject.setStringProperty("Hello");
285     serverObject.setDoubleProperty(4.2);
286     serverObject.setObjectName("Foo");
287     clientObject.setObjectName("Foo");
288
289     // -- Synchronize
290
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());
297
298     // -- Check if client-side values are as expected
299
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());
304
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());
310
311     // -- Sync method
312
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());
320
321     // -- Request method
322
323     spy.connect(&serverObject, &SyncObj::requestMethodCalled);
324     clientObject.requestMethod("Hello", 23);
325     ASSERT_TRUE(spy.wait());
326     EXPECT_EQ("Hello", serverObject.stringProperty());
327
328     // -- Property update
329
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());
349 }
350
351 #include "signalproxytest.moc"