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