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