Mercurial > hg > orthanc-stone
comparison UnitTestsSources/TestMessageBroker.cpp @ 428:751fb354149e am-vsol-upgrade
ability to change the scene of the RadiographyWidget
author | am@osimis.io |
---|---|
date | Wed, 28 Nov 2018 10:44:28 +0100 |
parents | 1d9dd542adfe |
children | a750f11892ec |
comparison
equal
deleted
inserted
replaced
426:660fe6f6bf4a | 428:751fb354149e |
---|---|
1 ///** | 1 /** |
2 // * Stone of Orthanc | 2 * Stone of Orthanc |
3 // * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics | 3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics |
4 // * Department, University Hospital of Liege, Belgium | 4 * Department, University Hospital of Liege, Belgium |
5 // * Copyright (C) 2017-2018 Osimis S.A., Belgium | 5 * Copyright (C) 2017-2018 Osimis S.A., Belgium |
6 // * | 6 * |
7 // * This program is free software: you can redistribute it and/or | 7 * This program is free software: you can redistribute it and/or |
8 // * modify it under the terms of the GNU Affero General Public License | 8 * modify it under the terms of the GNU Affero General Public License |
9 // * as published by the Free Software Foundation, either version 3 of | 9 * as published by the Free Software Foundation, either version 3 of |
10 // * the License, or (at your option) any later version. | 10 * the License, or (at your option) any later version. |
11 // * | 11 * |
12 // * This program is distributed in the hope that it will be useful, but | 12 * This program is distributed in the hope that it will be useful, but |
13 // * WITHOUT ANY WARRANTY; without even the implied warranty of | 13 * WITHOUT ANY WARRANTY; without even the implied warranty of |
14 // * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
15 // * Affero General Public License for more details. | 15 * Affero General Public License for more details. |
16 // * | 16 * |
17 // * You should have received a copy of the GNU Affero General Public License | 17 * You should have received a copy of the GNU Affero General Public License |
18 // * along with this program. If not, see <http://www.gnu.org/licenses/>. | 18 * along with this program. If not, see <http://www.gnu.org/licenses/>. |
19 // **/ | 19 **/ |
20 | 20 |
21 | 21 |
22 //#include "gtest/gtest.h" | 22 #include "gtest/gtest.h" |
23 | 23 |
24 //#include "../Framework/Messages/MessageBroker.h" | 24 #include "Framework/Messages/MessageBroker.h" |
25 //#include "../Framework/Messages/IMessage.h" | 25 #include "Framework/Messages/Promise.h" |
26 //#include "../Framework/Messages/IObservable.h" | 26 #include "Framework/Messages/IObservable.h" |
27 //#include "../Framework/Messages/IObserver.h" | 27 #include "Framework/Messages/IObserver.h" |
28 //#include "../Framework/StoneEnumerations.h" | 28 #include "Framework/Messages/MessageForwarder.h" |
29 | 29 |
30 | 30 |
31 //static int test1Counter = 0; | 31 int testCounter = 0; |
32 //static int test2Counter = 0; | 32 namespace { |
33 //class MyFullObserver : public OrthancStone::IObserver | 33 |
34 //{ | 34 using namespace OrthancStone; |
35 | 35 |
36 //public: | 36 |
37 // MyFullObserver(OrthancStone::MessageBroker& broker) | 37 enum CustomMessageType |
38 // : OrthancStone::IObserver(broker) | 38 { |
39 // { | 39 CustomMessageType_First = MessageType_CustomMessage + 1, |
40 //// DeclareHandledMessage(OrthancStone::MessageType_Test1); | 40 |
41 //// DeclareIgnoredMessage(OrthancStone::MessageType_Test2); | 41 CustomMessageType_Completed, |
42 // } | 42 CustomMessageType_Increment |
43 | 43 }; |
44 | 44 |
45 // void HandleMessage(OrthancStone::IObservable& from, const OrthancStone::IMessage& message) { | 45 |
46 // switch (message.GetType()) | 46 class MyObservable : public IObservable |
47 // { | 47 { |
48 // case OrthancStone::MessageType_Test1: | 48 public: |
49 // test1Counter++; | 49 struct MyCustomMessage: public BaseMessage<CustomMessageType_Completed> |
50 // break; | 50 { |
51 // case OrthancStone::MessageType_Test2: | 51 int payload_; |
52 // test2Counter++; | 52 |
53 // break; | 53 MyCustomMessage(int payload) |
54 // default: | 54 : BaseMessage(), |
55 // throw OrthancStone::MessageNotDeclaredException(message.GetType()); | 55 payload_(payload) |
56 // } | 56 {} |
57 // } | 57 }; |
58 | 58 |
59 //}; | 59 MyObservable(MessageBroker& broker) |
60 | 60 : IObservable(broker) |
61 //class MyPartialObserver : public OrthancStone::IObserver | 61 {} |
62 //{ | 62 |
63 | 63 }; |
64 //public: | 64 |
65 // MyPartialObserver(OrthancStone::MessageBroker& broker) | 65 class MyObserver : public IObserver |
66 // : OrthancStone::IObserver(broker) | 66 { |
67 // { | 67 public: |
68 //// DeclareHandledMessage(OrthancStone::MessageType_Test1); | 68 MyObserver(MessageBroker& broker) |
69 // // don't declare Test2 on purpose | 69 : IObserver(broker) |
70 // } | 70 {} |
71 | 71 |
72 | 72 void HandleCompletedMessage(const MyObservable::MyCustomMessage& message) |
73 // void HandleMessage(OrthancStone::IObservable& from, const OrthancStone::IMessage& message) { | 73 { |
74 // switch (message.GetType()) | 74 testCounter += message.payload_; |
75 // { | 75 } |
76 // case OrthancStone::MessageType_Test1: | 76 |
77 // test1Counter++; | 77 }; |
78 // break; | 78 |
79 // case OrthancStone::MessageType_Test2: | 79 |
80 // test2Counter++; | 80 class MyIntermediate : public IObserver, public IObservable |
81 // break; | 81 { |
82 // default: | 82 IObservable& observedObject_; |
83 // throw OrthancStone::MessageNotDeclaredException(message.GetType()); | 83 public: |
84 // } | 84 MyIntermediate(MessageBroker& broker, IObservable& observedObject) |
85 // } | 85 : IObserver(broker), |
86 | 86 IObservable(broker), |
87 //}; | 87 observedObject_(observedObject) |
88 | 88 { |
89 | 89 observedObject_.RegisterObserverCallback(new MessageForwarder<MyObservable::MyCustomMessage>(broker, *this)); |
90 //class MyObservable : public OrthancStone::IObservable | 90 } |
91 //{ | 91 }; |
92 | 92 |
93 //public: | 93 |
94 // MyObservable(OrthancStone::MessageBroker& broker) | 94 class MyPromiseSource : public IObservable |
95 // : OrthancStone::IObservable(broker) | 95 { |
96 // { | 96 Promise* currentPromise_; |
97 // DeclareEmittableMessage(OrthancStone::MessageType_Test1); | 97 public: |
98 // DeclareEmittableMessage(OrthancStone::MessageType_Test2); | 98 struct MyPromiseMessage: public BaseMessage<MessageType_Test1> |
99 // } | 99 { |
100 | 100 int increment; |
101 //}; | 101 |
102 | 102 MyPromiseMessage(int increment) |
103 | 103 : BaseMessage(), |
104 //TEST(MessageBroker, NormalUsage) | 104 increment(increment) |
105 //{ | 105 {} |
106 // OrthancStone::MessageBroker broker; | 106 }; |
107 // MyObservable observable(broker); | 107 |
108 | 108 MyPromiseSource(MessageBroker& broker) |
109 // test1Counter = 0; | 109 : IObservable(broker), |
110 | 110 currentPromise_(NULL) |
111 // // no observers have been registered -> nothing shall happen | 111 {} |
112 // observable.EmitMessage(OrthancStone::IMessage(OrthancStone::MessageType_Test1)); | 112 |
113 | 113 Promise& StartSomethingAsync() |
114 // ASSERT_EQ(0, test1Counter); | 114 { |
115 | 115 currentPromise_ = new Promise(GetBroker()); |
116 // // register an observer, check it is called | 116 return *currentPromise_; |
117 // MyFullObserver fullObserver(broker); | 117 } |
118 // ASSERT_NO_THROW(observable.RegisterObserver(fullObserver)); | 118 |
119 | 119 void CompleteSomethingAsyncWithSuccess(int payload) |
120 // observable.EmitMessage(OrthancStone::IMessage(OrthancStone::MessageType_Test1)); | 120 { |
121 | 121 currentPromise_->Success(MyPromiseMessage(payload)); |
122 // ASSERT_EQ(1, test1Counter); | 122 delete currentPromise_; |
123 | 123 } |
124 // // register an invalid observer, check it raises an exception | 124 |
125 // MyPartialObserver partialObserver(broker); | 125 void CompleteSomethingAsyncWithFailure(int payload) |
126 // ASSERT_THROW(observable.RegisterObserver(partialObserver), OrthancStone::MessageNotDeclaredException); | 126 { |
127 | 127 currentPromise_->Failure(MyPromiseMessage(payload)); |
128 // // check an exception is thrown when the observable emits an undeclared message | 128 delete currentPromise_; |
129 // ASSERT_THROW(observable.EmitMessage(OrthancStone::IMessage(OrthancStone::MessageType_VolumeSlicer_GeometryReady)), OrthancStone::MessageNotDeclaredException); | 129 } |
130 | 130 }; |
131 // // unregister the observer, make sure nothing happens afterwards | 131 |
132 // observable.UnregisterObserver(fullObserver); | 132 |
133 // observable.EmitMessage(OrthancStone::IMessage(OrthancStone::MessageType_Test1)); | 133 class MyPromiseTarget : public IObserver |
134 // ASSERT_EQ(1, test1Counter); | 134 { |
135 //} | 135 public: |
136 | 136 MyPromiseTarget(MessageBroker& broker) |
137 //TEST(MessageBroker, DeleteObserverWhileRegistered) | 137 : IObserver(broker) |
138 //{ | 138 {} |
139 // OrthancStone::MessageBroker broker; | 139 |
140 // MyObservable observable(broker); | 140 void IncrementCounter(const MyPromiseSource::MyPromiseMessage& args) |
141 | 141 { |
142 // test1Counter = 0; | 142 testCounter += args.increment; |
143 | 143 } |
144 // { | 144 |
145 // // register an observer, check it is called | 145 void DecrementCounter(const MyPromiseSource::MyPromiseMessage& args) |
146 // MyFullObserver observer(broker); | 146 { |
147 // observable.RegisterObserver(observer); | 147 testCounter -= args.increment; |
148 | 148 } |
149 // observable.EmitMessage(OrthancStone::IMessage(OrthancStone::MessageType_Test1)); | 149 }; |
150 | 150 } |
151 // ASSERT_EQ(1, test1Counter); | 151 |
152 // } | 152 |
153 | 153 TEST(MessageBroker, TestPermanentConnectionSimpleUseCase) |
154 // // at this point, the observer has been deleted, the handle shall not be called again (and it shall not crash !) | 154 { |
155 // observable.EmitMessage(OrthancStone::IMessage(OrthancStone::MessageType_Test1)); | 155 MessageBroker broker; |
156 | 156 MyObservable observable(broker); |
157 // ASSERT_EQ(1, test1Counter); | 157 MyObserver observer(broker); |
158 //} | 158 |
159 // create a permanent connection between an observable and an observer | |
160 observable.RegisterObserverCallback(new Callable<MyObserver, MyObservable::MyCustomMessage>(observer, &MyObserver::HandleCompletedMessage)); | |
161 | |
162 testCounter = 0; | |
163 observable.EmitMessage(MyObservable::MyCustomMessage(12)); | |
164 ASSERT_EQ(12, testCounter); | |
165 | |
166 // the connection is permanent; if we emit the same message again, the observer will be notified again | |
167 testCounter = 0; | |
168 observable.EmitMessage(MyObservable::MyCustomMessage(20)); | |
169 ASSERT_EQ(20, testCounter); | |
170 | |
171 // Unregister the observer; make sure it's not called anymore | |
172 observable.Unregister(&observer); | |
173 testCounter = 0; | |
174 observable.EmitMessage(MyObservable::MyCustomMessage(20)); | |
175 ASSERT_EQ(0, testCounter); | |
176 } | |
177 | |
178 TEST(MessageBroker, TestMessageForwarderSimpleUseCase) | |
179 { | |
180 MessageBroker broker; | |
181 MyObservable observable(broker); | |
182 MyIntermediate intermediate(broker, observable); | |
183 MyObserver observer(broker); | |
184 | |
185 // let the observer observers the intermediate that is actually forwarding the messages from the observable | |
186 intermediate.RegisterObserverCallback(new Callable<MyObserver, MyObservable::MyCustomMessage>(observer, &MyObserver::HandleCompletedMessage)); | |
187 | |
188 testCounter = 0; | |
189 observable.EmitMessage(MyObservable::MyCustomMessage(12)); | |
190 ASSERT_EQ(12, testCounter); | |
191 | |
192 // the connection is permanent; if we emit the same message again, the observer will be notified again | |
193 testCounter = 0; | |
194 observable.EmitMessage(MyObservable::MyCustomMessage(20)); | |
195 ASSERT_EQ(20, testCounter); | |
196 } | |
197 | |
198 TEST(MessageBroker, TestPermanentConnectionDeleteObserver) | |
199 { | |
200 MessageBroker broker; | |
201 MyObservable observable(broker); | |
202 MyObserver* observer = new MyObserver(broker); | |
203 | |
204 // create a permanent connection between an observable and an observer | |
205 observable.RegisterObserverCallback(new Callable<MyObserver, MyObservable::MyCustomMessage>(*observer, &MyObserver::HandleCompletedMessage)); | |
206 | |
207 testCounter = 0; | |
208 observable.EmitMessage(MyObservable::MyCustomMessage(12)); | |
209 ASSERT_EQ(12, testCounter); | |
210 | |
211 // delete the observer and check that the callback is not called anymore | |
212 delete observer; | |
213 | |
214 // the connection is permanent; if we emit the same message again, the observer will be notified again | |
215 testCounter = 0; | |
216 observable.EmitMessage(MyObservable::MyCustomMessage(20)); | |
217 ASSERT_EQ(0, testCounter); | |
218 } | |
219 | |
220 TEST(MessageBroker, TestMessageForwarderDeleteIntermediate) | |
221 { | |
222 MessageBroker broker; | |
223 MyObservable observable(broker); | |
224 MyIntermediate* intermediate = new MyIntermediate(broker, observable); | |
225 MyObserver observer(broker); | |
226 | |
227 // let the observer observers the intermediate that is actually forwarding the messages from the observable | |
228 intermediate->RegisterObserverCallback(new Callable<MyObserver, MyObservable::MyCustomMessage>(observer, &MyObserver::HandleCompletedMessage)); | |
229 | |
230 testCounter = 0; | |
231 observable.EmitMessage(MyObservable::MyCustomMessage(12)); | |
232 ASSERT_EQ(12, testCounter); | |
233 | |
234 delete intermediate; | |
235 | |
236 observable.EmitMessage(MyObservable::MyCustomMessage(20)); | |
237 ASSERT_EQ(12, testCounter); | |
238 } | |
239 | |
240 TEST(MessageBroker, TestCustomMessage) | |
241 { | |
242 MessageBroker broker; | |
243 MyObservable observable(broker); | |
244 MyIntermediate intermediate(broker, observable); | |
245 MyObserver observer(broker); | |
246 | |
247 // let the observer observers the intermediate that is actually forwarding the messages from the observable | |
248 intermediate.RegisterObserverCallback(new Callable<MyObserver, MyObservable::MyCustomMessage>(observer, &MyObserver::HandleCompletedMessage)); | |
249 | |
250 testCounter = 0; | |
251 observable.EmitMessage(MyObservable::MyCustomMessage(12)); | |
252 ASSERT_EQ(12, testCounter); | |
253 | |
254 // the connection is permanent; if we emit the same message again, the observer will be notified again | |
255 testCounter = 0; | |
256 observable.EmitMessage(MyObservable::MyCustomMessage(20)); | |
257 ASSERT_EQ(20, testCounter); | |
258 } | |
259 | |
260 | |
261 TEST(MessageBroker, TestPromiseSuccessFailure) | |
262 { | |
263 MessageBroker broker; | |
264 MyPromiseSource source(broker); | |
265 MyPromiseTarget target(broker); | |
266 | |
267 // test a successful promise | |
268 source.StartSomethingAsync() | |
269 .Then(new Callable<MyPromiseTarget, MyPromiseSource::MyPromiseMessage>(target, &MyPromiseTarget::IncrementCounter)) | |
270 .Else(new Callable<MyPromiseTarget, MyPromiseSource::MyPromiseMessage>(target, &MyPromiseTarget::DecrementCounter)); | |
271 | |
272 testCounter = 0; | |
273 source.CompleteSomethingAsyncWithSuccess(10); | |
274 ASSERT_EQ(10, testCounter); | |
275 | |
276 // test a failing promise | |
277 source.StartSomethingAsync() | |
278 .Then(new Callable<MyPromiseTarget, MyPromiseSource::MyPromiseMessage>(target, &MyPromiseTarget::IncrementCounter)) | |
279 .Else(new Callable<MyPromiseTarget, MyPromiseSource::MyPromiseMessage>(target, &MyPromiseTarget::DecrementCounter)); | |
280 | |
281 testCounter = 0; | |
282 source.CompleteSomethingAsyncWithFailure(15); | |
283 ASSERT_EQ(-15, testCounter); | |
284 } | |
285 | |
286 TEST(MessageBroker, TestPromiseDeleteTarget) | |
287 { | |
288 MessageBroker broker; | |
289 MyPromiseSource source(broker); | |
290 MyPromiseTarget* target = new MyPromiseTarget(broker); | |
291 | |
292 // create the promise | |
293 source.StartSomethingAsync() | |
294 .Then(new Callable<MyPromiseTarget, MyPromiseSource::MyPromiseMessage>(*target, &MyPromiseTarget::IncrementCounter)) | |
295 .Else(new Callable<MyPromiseTarget, MyPromiseSource::MyPromiseMessage>(*target, &MyPromiseTarget::DecrementCounter)); | |
296 | |
297 // delete the promise target | |
298 delete target; | |
299 | |
300 // trigger the promise, make sure it does not throw and does not call the callback | |
301 testCounter = 0; | |
302 source.CompleteSomethingAsyncWithSuccess(10); | |
303 ASSERT_EQ(0, testCounter); | |
304 | |
305 // test a failing promise | |
306 source.StartSomethingAsync() | |
307 .Then(new Callable<MyPromiseTarget, MyPromiseSource::MyPromiseMessage>(*target, &MyPromiseTarget::IncrementCounter)) | |
308 .Else(new Callable<MyPromiseTarget, MyPromiseSource::MyPromiseMessage>(*target, &MyPromiseTarget::DecrementCounter)); | |
309 | |
310 testCounter = 0; | |
311 source.CompleteSomethingAsyncWithFailure(15); | |
312 ASSERT_EQ(0, testCounter); | |
313 } | |
314 | |
315 #if __cplusplus >= 201103L | |
316 | |
317 #include <functional> | |
318 | |
319 namespace OrthancStone { | |
320 | |
321 template <typename TMessage> | |
322 class LambdaCallable : public MessageHandler<TMessage> | |
323 { | |
324 private: | |
325 | |
326 IObserver& observer_; | |
327 std::function<void (const TMessage&)> lambda_; | |
328 | |
329 public: | |
330 LambdaCallable(IObserver& observer, | |
331 std::function<void (const TMessage&)> lambdaFunction) : | |
332 observer_(observer), | |
333 lambda_(lambdaFunction) | |
334 { | |
335 } | |
336 | |
337 virtual void Apply(const IMessage& message) | |
338 { | |
339 lambda_(dynamic_cast<const TMessage&>(message)); | |
340 } | |
341 | |
342 virtual MessageType GetMessageType() const | |
343 { | |
344 return static_cast<MessageType>(TMessage::Type); | |
345 } | |
346 | |
347 virtual IObserver* GetObserver() const | |
348 { | |
349 return &observer_; | |
350 } | |
351 }; | |
352 | |
353 | |
354 } | |
355 | |
356 TEST(MessageBroker, TestLambdaSimpleUseCase) | |
357 { | |
358 MessageBroker broker; | |
359 MyObservable observable(broker); | |
360 MyObserver* observer = new MyObserver(broker); | |
361 | |
362 // create a permanent connection between an observable and an observer | |
363 observable.RegisterObserverCallback(new LambdaCallable<MyObservable::MyCustomMessage>(*observer, [&](const MyObservable::MyCustomMessage& message) {testCounter += 2 * message.payload_;})); | |
364 | |
365 testCounter = 0; | |
366 observable.EmitMessage(MyObservable::MyCustomMessage(12)); | |
367 ASSERT_EQ(24, testCounter); | |
368 | |
369 // delete the observer and check that the callback is not called anymore | |
370 delete observer; | |
371 | |
372 // the connection is permanent; if we emit the same message again, the observer will be notified again | |
373 testCounter = 0; | |
374 observable.EmitMessage(MyObservable::MyCustomMessage(20)); | |
375 ASSERT_EQ(0, testCounter); | |
376 } | |
377 | |
378 namespace { | |
379 class MyObserverWithLambda : public IObserver { | |
380 private: | |
381 int multiplier_; // this is a private variable we want to access in a lambda | |
382 | |
383 public: | |
384 MyObserverWithLambda(MessageBroker& broker, int multiplier, MyObservable& observable) | |
385 : IObserver(broker), | |
386 multiplier_(multiplier) | |
387 { | |
388 // register a callable to a lambda that access private members | |
389 observable.RegisterObserverCallback(new LambdaCallable<MyObservable::MyCustomMessage>(*this, [this](const MyObservable::MyCustomMessage& message) { | |
390 testCounter += multiplier_ * message.payload_; | |
391 })); | |
392 | |
393 } | |
394 }; | |
395 } | |
396 | |
397 TEST(MessageBroker, TestLambdaCaptureThisAndAccessPrivateMembers) | |
398 { | |
399 MessageBroker broker; | |
400 MyObservable observable(broker); | |
401 MyObserverWithLambda* observer = new MyObserverWithLambda(broker, 3, observable); | |
402 | |
403 testCounter = 0; | |
404 observable.EmitMessage(MyObservable::MyCustomMessage(12)); | |
405 ASSERT_EQ(36, testCounter); | |
406 | |
407 // delete the observer and check that the callback is not called anymore | |
408 delete observer; | |
409 | |
410 // the connection is permanent; if we emit the same message again, the observer will be notified again | |
411 testCounter = 0; | |
412 observable.EmitMessage(MyObservable::MyCustomMessage(20)); | |
413 ASSERT_EQ(0, testCounter); | |
414 } | |
415 | |
416 #endif // C++ 11 |