Tizen 2.0 Release
[framework/web/wrt-commons.git] / tests / dpl / event / test_controller.cpp
1 /*
2  * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *    Licensed under the Apache License, Version 2.0 (the "License");
5  *    you may not use this file except in compliance with the License.
6  *    You may obtain a copy of the License at
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *    Unless required by applicable law or agreed to in writing, software
11  *    distributed under the License is distributed on an "AS IS" BASIS,
12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *    See the License for the specific language governing permissions and
14  *    limitations under the License.
15  */
16 /*
17  * @file        test_controller.cpp
18  * @author      Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com)
19  * @version     1.0
20  * @brief       This file is the implementation file of test controller
21  */
22 #include <dpl/test/test_runner.h>
23 #include <dpl/event/controller.h>
24 #include <dpl/thread.h>
25 #include <dpl/generic_event.h>
26 #include <dpl/waitable_handle.h>
27 #include <dpl/waitable_event.h>
28 #include <dpl/type_list.h>
29 #include <dpl/application.h>
30 #include <dpl/atomic.h>
31 #include <list>
32 #include <vector>
33 #include <memory>
34
35 RUNNER_TEST_GROUP_INIT(DPL)
36
37 class IntController :
38     public DPL::Event::Controller<DPL::TypeListDecl<int>::Type>
39 {
40   private:
41     int m_value;
42
43   protected:
44     virtual void OnEventReceived(const int &event)
45     {
46         m_value = event;
47     }
48
49   public:
50     IntController() :
51         m_value(-1)
52     {}
53
54     int Value() const
55     {
56         return m_value;
57     }
58 };
59
60 DECLARE_GENERIC_EVENT_1(DoneSignalEvent, DPL::WaitableEvent *)
61
62 class ThreadController :
63     public DPL::Event::Controller<DPL::TypeListDecl<DoneSignalEvent>::Type>
64 {
65   private:
66     DPL::Thread *m_value;
67
68   protected:
69     virtual void OnEventReceived(const DoneSignalEvent &event)
70     {
71         m_value = DPL::Thread::GetCurrentThread();
72         event.GetArg0()->Signal();
73     }
74
75   public:
76     ThreadController() :
77         m_value(NULL)
78     {}
79
80     DPL::Thread *Value() const
81     {
82         return m_value;
83     }
84 };
85
86 struct StrangeStruct
87 {
88     int a;
89     float b;
90     double c;
91 };
92
93 class StrangeController :
94     public DPL::Event::Controller<DPL::TypeListDecl<char, short, int, long,
95                                                     unsigned char,
96                                                     unsigned short,
97                                                     unsigned int, unsigned long,
98                                                     float, double,
99                                                     StrangeStruct>::Type>
100 {
101   protected:
102     virtual void OnEventReceived(const char &event)
103     {
104         (void)event;
105     }
106     virtual void OnEventReceived(const short &event)
107     {
108         (void)event;
109     }
110     virtual void OnEventReceived(const int &event)
111     {
112         (void)event;
113     }
114     virtual void OnEventReceived(const long &event)
115     {
116         (void)event;
117     }
118     virtual void OnEventReceived(const unsigned char &event)
119     {
120         (void)event;
121     }
122     virtual void OnEventReceived(const unsigned short &event)
123     {
124         (void)event;
125     }
126     virtual void OnEventReceived(const unsigned int &event)
127     {
128         (void)event;
129     }
130     virtual void OnEventReceived(const unsigned long &event)
131     {
132         (void)event;
133     }
134     virtual void OnEventReceived(const float &event)
135     {
136         (void)event;
137     }
138     virtual void OnEventReceived(const double &event)
139     {
140         (void)event;
141     }
142     virtual void OnEventReceived(const StrangeStruct &event)
143     {
144         (void)event;
145     }
146 };
147
148 /*
149 Name: Controller_InitSimple
150 Description: tests initialization of simple int controller
151 Expected: no exceptions
152 */
153 RUNNER_TEST(Controller_InitSimple)
154 {
155     IntController controller;
156     controller.Touch();
157     RUNNER_ASSERT(controller.Value() == -1);
158 }
159
160 /*
161 Name: Controller_InitStrange
162 Description: tests initialization of struct controller
163 Expected: no exceptions
164 */
165 RUNNER_TEST(Controller_InitStrange)
166 {
167     StrangeController controller;
168     controller.Touch();
169 }
170
171 /*
172 Name: Controller_PostEventToThread
173 Description: tests post events to other thread
174 Expected: thread id gathered in event handling method should match id of created thread
175 */
176 RUNNER_TEST(Controller_PostEventToThread)
177 {
178     ThreadController controller;
179     controller.Touch();
180
181     DPL::Thread thread;
182     thread.Run();
183
184     controller.SwitchToThread(&thread);
185
186     DPL::WaitableEvent waitHandle;
187
188     controller.PostEvent(DoneSignalEvent(&waitHandle));
189
190     DPL::WaitForSingleHandle(waitHandle.GetHandle());
191
192     controller.SwitchToThread(NULL);
193
194     RUNNER_ASSERT(controller.Value() == &thread);
195 }
196
197 /*
198 Name: Controller_PostTimedEventToThread
199 Description: tests post events to other thread with time delay
200 Expected: thread id gathered in event handling method should match id of created thread
201 */
202 RUNNER_TEST(Controller_PostTimedEventToThread)
203 {
204     ThreadController controller;
205     controller.Touch();
206
207     DPL::Thread thread;
208     thread.Run();
209
210     controller.SwitchToThread(&thread);
211
212     DPL::WaitableEvent waitHandle;
213
214     controller.PostTimedEvent(DoneSignalEvent(&waitHandle), 0.5);
215
216     DPL::WaitForSingleHandle(waitHandle.GetHandle());
217
218     controller.SwitchToThread(NULL);
219
220     RUNNER_ASSERT(controller.Value() == &thread);
221 }
222
223 DECLARE_GENERIC_EVENT_2(TouchInThread, DPL::WaitableEvent *, DPL::Thread * *)
224 DECLARE_GENERIC_EVENT_2(TouchedControllerSignal,
225                         DPL::WaitableEvent *,
226                         DPL::Thread * *)
227
228 class TouchInThreadController :
229     public DPL::Event::Controller<DPL::TypeListDecl<TouchInThread>::Type>,
230     private DPL::Event::Controller<DPL::TypeListDecl<TouchedControllerSignal>::
231                                        Type>
232 {
233   public:
234     typedef DPL::Event::Controller<DPL::TypeListDecl<TouchInThread>::Type>
235     PublicController;
236     typedef DPL::Event::Controller<DPL::TypeListDecl<TouchedControllerSignal>::
237                                        Type> PrivateController;
238
239     virtual void OnEventReceived(const TouchInThread &event)
240     {
241         // Touch controller in thread
242         PrivateController::Touch();
243
244         // Post signal
245         PrivateController::PostEvent(TouchedControllerSignal(event.GetArg0(),
246                                                              event.GetArg1()));
247     }
248
249     virtual void OnEventReceived(const TouchedControllerSignal &event)
250     {
251         // Return touched thread
252         *event.GetArg1() = DPL::Thread::GetCurrentThread();
253
254         // Signal waitable event
255         event.GetArg0()->Signal();
256     }
257 };
258
259 /*
260 Name: Controller_TouchInThread
261 Description: tests ability to touch (initizilize / set destination thread) in creatd thread
262  other than thread were controlelr object was created
263 Expected: thread id gathered in event handling method should match id of created thread
264 */
265 RUNNER_TEST(Controller_TouchInThread)
266 {
267     TouchInThreadController controller;
268     controller.PublicController::Touch();
269
270     DPL::Thread thread;
271     thread.Run();
272
273     controller.PublicController::SwitchToThread(&thread);
274
275     DPL::WaitableEvent waitHandle;
276     DPL::Thread *touchedThread = NULL;
277
278     controller.PublicController::PostEvent(TouchInThread(&waitHandle,
279                                                          &touchedThread));
280
281     DPL::WaitForSingleHandle(waitHandle.GetHandle());
282
283     controller.PublicController::SwitchToThread(NULL);
284
285     RUNNER_ASSERT(touchedThread == &thread);
286 }
287
288 /*
289 Name: Controller_SynchronizedEvent
290 Description: tests ability to post synchronized events to ther thread
291 Expected: correct value should be saved when event was handled
292 */
293 RUNNER_TEST(Controller_SynchronizedEvent)
294 {
295     IntController controller;
296     controller.Touch();
297
298     DPL::Thread thread;
299     thread.Run();
300
301     controller.SwitchToThread(&thread);
302     controller.PostSyncEvent(12345);
303     controller.SwitchToThread(NULL);
304
305     RUNNER_ASSERT(controller.Value() == 12345);
306 }
307
308 const int ControllersNumber = 5;
309 const int MaxEventsPerController = 1;
310 const int MaxEvents = ControllersNumber * MaxEventsPerController;
311 const int ControllersPerThread = 1;
312
313 class TestController; //Forward Declaration
314
315 typedef std::shared_ptr<TestController> ControllerPtr;
316 typedef std::shared_ptr<DPL::Thread> ThreadPtr;
317 typedef std::vector<ControllerPtr> ControllerList;
318 typedef std::list<ThreadPtr> ThreadList;
319
320 DECLARE_GENERIC_EVENT_0(QuitEvent)
321 class QuitController :
322     public DPL::Event::Controller<DPL::TypeListDecl<QuitEvent>::Type>,
323     public DPL::ApplicationExt
324 {
325   public:
326     explicit QuitController() : DPL::ApplicationExt(1, NULL, "test-app")
327     {
328         Touch();
329     }
330
331   protected:
332     virtual void OnEventReceived(const QuitEvent &)
333     {
334         Quit();
335     }
336 };
337
338 struct TestContext
339 {
340     ControllerList controllers;
341     ThreadList threads;
342     QuitController quitter;
343     DPL::Atomic g_ReceivedCounter;
344     DPL::Atomic g_SentCounter;
345 };
346 typedef std::unique_ptr<TestContext> TestContextPtr;
347 TestContextPtr testContextPtr;
348
349 DECLARE_GENERIC_EVENT_0(StartSendEvent)
350 DECLARE_GENERIC_EVENT_0(RandomEvent)
351 class TestController :
352     public DPL::Event::Controller<DPL::TypeListDecl<RandomEvent,
353                                                     StartSendEvent>::Type>
354 {
355   public:
356     explicit TestController()
357     {
358         Touch();
359     }
360
361   protected:
362     virtual void OnEventReceived(const RandomEvent &)
363     {
364         ++testContextPtr->g_ReceivedCounter;
365         if (testContextPtr->g_ReceivedCounter == MaxEvents) {
366             testContextPtr->quitter.DPL::Event::ControllerEventHandler<
367                 QuitEvent>::PostEvent(QuitEvent());
368             return;
369         }
370     }
371     virtual void OnEventReceived(const StartSendEvent &)
372     {
373         for (int i = 0; i < MaxEventsPerController; ++i) {
374             if (testContextPtr->g_SentCounter > MaxEvents) {
375                 return;
376             }
377             ++testContextPtr->g_SentCounter;
378             int id = rand() % static_cast<int>(testContextPtr->controllers.size());
379             testContextPtr->controllers.at(id)->DPL::Event::
380                 ControllerEventHandler<RandomEvent>::PostEvent(RandomEvent());
381         }
382     }
383 };
384
385 /*
386 Name: Controllers_MultipleEvents
387 Description: tests controller coooperation.
388  This runs many controllers in many threads. Each controller sends
389  to other randomly chosen controller events.
390 Expected: Test is supposed to be ended when all limits of sent event will be reach
391  -> all scheduled event will be sent and received.
392 */
393 RUNNER_TEST(Controllers_MultipleEvents)
394 {
395     srand(time(NULL) );
396
397     testContextPtr.reset(new TestContext());
398     testContextPtr->controllers.reserve(ControllersNumber);
399
400     for (int i = 0; i < ControllersNumber; ++i) {
401         if (testContextPtr->controllers.size() % ControllersPerThread == 0) {
402             ThreadPtr thread = ThreadPtr(new DPL::Thread());
403             testContextPtr->threads.push_back(thread);
404             thread->Run();
405         }
406
407         ControllerPtr controller = ControllerPtr(new TestController());
408         testContextPtr->controllers.push_back(controller);
409         if (testContextPtr->controllers.size() % 2 == 0) {
410             //This controller is being switched to thread (otherwise it is
411             // touched to main thread)
412             ThreadPtr thread = testContextPtr->threads.back();
413             controller->SwitchToThread(thread.get());
414         }
415         controller->DPL::Event::ControllerEventHandler<StartSendEvent>::
416             PostEvent(StartSendEvent());
417     }
418     testContextPtr->quitter.Exec();
419     RUNNER_ASSERT(
420         testContextPtr->g_SentCounter == testContextPtr->g_ReceivedCounter);
421     testContextPtr.reset();
422 }