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
55     int Value() const
56     {
57         return m_value;
58     }
59 };
60
61 DECLARE_GENERIC_EVENT_1(DoneSignalEvent, DPL::WaitableEvent *)
62
63 class ThreadController
64     : public DPL::Event::Controller<DPL::TypeListDecl<DoneSignalEvent>::Type>
65 {
66 private:
67     DPL::Thread *m_value;
68
69 protected:
70     virtual void OnEventReceived(const DoneSignalEvent &event)
71     {
72         m_value = DPL::Thread::GetCurrentThread();
73         event.GetArg0()->Signal();
74     }
75
76 public:
77     ThreadController()
78         : m_value(NULL)
79     {
80     }
81
82     DPL::Thread *Value() const
83     {
84         return m_value;
85     }
86 };
87
88 struct StrangeStruct
89 {
90     int a;
91     float b;
92     double c;
93 };
94
95 class StrangeController
96     : public DPL::Event::Controller<DPL::TypeListDecl<char, short, int, long,
97                                                unsigned char, unsigned short, unsigned int, unsigned long,
98                                                float, double, StrangeStruct>::Type>
99 {
100 protected:
101     virtual void OnEventReceived(const char &event) { (void)event; }
102     virtual void OnEventReceived(const short &event) { (void)event; }
103     virtual void OnEventReceived(const int &event) { (void)event; }
104     virtual void OnEventReceived(const long &event) { (void)event; }
105     virtual void OnEventReceived(const unsigned char &event) { (void)event; }
106     virtual void OnEventReceived(const unsigned short &event) { (void)event; }
107     virtual void OnEventReceived(const unsigned int &event) { (void)event; }
108     virtual void OnEventReceived(const unsigned long &event) { (void)event; }
109     virtual void OnEventReceived(const float &event) { (void)event; }
110     virtual void OnEventReceived(const double &event) { (void)event; }
111     virtual void OnEventReceived(const StrangeStruct &event) { (void)event; }
112 };
113
114 RUNNER_TEST(Controller_InitSimple)
115 {
116     IntController controller;
117     controller.Touch();
118     RUNNER_ASSERT(controller.Value() == -1);
119 }
120
121 RUNNER_TEST(Controller_InitStrange)
122 {
123     StrangeController controller;
124     controller.Touch();
125 }
126
127 RUNNER_TEST(Controller_PostEventToThread)
128 {
129     ThreadController controller;
130     controller.Touch();
131
132     DPL::Thread thread;
133     thread.Run();
134
135     controller.SwitchToThread(&thread);
136
137     DPL::WaitableEvent waitHandle;
138
139     controller.PostEvent(DoneSignalEvent(&waitHandle));
140
141     DPL::WaitForSingleHandle(waitHandle.GetHandle());
142
143     controller.SwitchToThread(NULL);
144
145     RUNNER_ASSERT(controller.Value() == &thread);
146 }
147
148 RUNNER_TEST(Controller_PostTimedEventToThread)
149 {
150     ThreadController controller;
151     controller.Touch();
152
153     DPL::Thread thread;
154     thread.Run();
155
156     controller.SwitchToThread(&thread);
157
158     DPL::WaitableEvent waitHandle;
159
160     controller.PostTimedEvent(DoneSignalEvent(&waitHandle), 0.5);
161
162     DPL::WaitForSingleHandle(waitHandle.GetHandle());
163
164     controller.SwitchToThread(NULL);
165
166     RUNNER_ASSERT(controller.Value() == &thread);
167 }
168
169 DECLARE_GENERIC_EVENT_2(TouchInThread, DPL::WaitableEvent *, DPL::Thread **)
170 DECLARE_GENERIC_EVENT_2(TouchedControllerSignal, DPL::WaitableEvent *, DPL::Thread **)
171
172 class TouchInThreadController
173     : public DPL::Event::Controller<DPL::TypeListDecl<TouchInThread>::Type>,
174       private DPL::Event::Controller<DPL::TypeListDecl<TouchedControllerSignal>::Type>
175 {
176 public:
177     typedef DPL::Event::Controller<DPL::TypeListDecl<TouchInThread>::Type> PublicController;
178     typedef DPL::Event::Controller<DPL::TypeListDecl<TouchedControllerSignal>::Type> PrivateController;
179
180     virtual void OnEventReceived(const TouchInThread &event)
181     {
182         // Touch controller in thread
183         PrivateController::Touch();
184
185         // Post signal
186         PrivateController::PostEvent(TouchedControllerSignal(event.GetArg0(), event.GetArg1()));
187     }
188
189     virtual void OnEventReceived(const TouchedControllerSignal &event)
190     {
191         // Return touched thread
192         *event.GetArg1() = DPL::Thread::GetCurrentThread();
193
194         // Signal waitable event
195         event.GetArg0()->Signal();
196     }
197 };
198
199 RUNNER_TEST(Controller_TouchInThread)
200 {
201     TouchInThreadController controller;
202     controller.PublicController::Touch();
203
204     DPL::Thread thread;
205     thread.Run();
206
207     controller.PublicController::SwitchToThread(&thread);
208
209     DPL::WaitableEvent waitHandle;
210     DPL::Thread *touchedThread = NULL;
211
212     controller.PublicController::PostEvent(TouchInThread(&waitHandle, &touchedThread));
213
214     DPL::WaitForSingleHandle(waitHandle.GetHandle());
215
216     controller.PublicController::SwitchToThread(NULL);
217
218     RUNNER_ASSERT(touchedThread == &thread);
219 }
220
221 RUNNER_TEST(Controller_SynchronizedEvent)
222 {
223     IntController controller;
224     controller.Touch();
225
226     DPL::Thread thread;
227     thread.Run();
228
229     controller.SwitchToThread(&thread);
230     controller.PostSyncEvent(12345);
231     controller.SwitchToThread(NULL);
232
233     RUNNER_ASSERT(controller.Value() == 12345);
234 }
235
236 const int ControllersNumber = 5;
237 const int MaxEventsPerController = 1;
238 const int MaxEvents = ControllersNumber * MaxEventsPerController;
239 const int ControllersPerThread = 1;
240
241 class TestController; //Forward Declaration
242
243 typedef std::shared_ptr<TestController> ControllerPtr;
244 typedef std::shared_ptr<DPL::Thread> ThreadPtr;
245 typedef std::vector<ControllerPtr> ControllerList;
246 typedef std::list<ThreadPtr> ThreadList;
247
248 DECLARE_GENERIC_EVENT_0(QuitEvent)
249 class QuitController
250     : public DPL::Event::Controller<DPL::TypeListDecl<QuitEvent>::Type>,
251       public DPL::ApplicationExt
252 {
253 public:
254     explicit QuitController( ) : DPL::ApplicationExt(1, NULL, "test-app") { Touch(); }
255 protected:
256     virtual void OnEventReceived(const QuitEvent &) { Quit(); }
257 };
258
259 struct TestContext
260 {
261     ControllerList controllers;
262     ThreadList threads;
263     QuitController quitter;
264     DPL::Atomic g_ReceivedCounter;
265     DPL::Atomic g_SentCounter;
266 };
267 typedef std::unique_ptr<TestContext> TestContextPtr;
268 TestContextPtr testContextPtr;
269
270 DECLARE_GENERIC_EVENT_0(StartSendEvent)
271 DECLARE_GENERIC_EVENT_0(RandomEvent)
272 class TestController
273     : public DPL::Event::Controller<DPL::TypeListDecl<RandomEvent, StartSendEvent>::Type>
274 {
275 public:
276     explicit TestController() { Touch(); }
277 protected:
278     virtual void OnEventReceived(const RandomEvent &)
279     {
280         ++testContextPtr->g_ReceivedCounter;
281         if(testContextPtr->g_ReceivedCounter == MaxEvents)
282         {
283             testContextPtr->quitter.DPL::Event::ControllerEventHandler<QuitEvent>::PostEvent(QuitEvent());
284             return;
285         }
286     }
287     virtual void OnEventReceived(const StartSendEvent &)
288     {
289         for (int i=0 ; i<MaxEventsPerController ;++i)
290         {
291             if(testContextPtr->g_SentCounter > MaxEvents)
292             {
293                 return;
294             }
295             ++testContextPtr->g_SentCounter;
296             int id = rand() % static_cast<int>(testContextPtr->controllers.size());
297             testContextPtr->controllers.at(id)->DPL::Event::ControllerEventHandler<RandomEvent>::PostEvent(RandomEvent());
298         }
299     }
300 };
301
302 RUNNER_TEST(Controllers_MultipleEvents)
303 {
304     srand ( time(NULL) );
305
306     testContextPtr.reset(new TestContext());
307     testContextPtr->controllers.reserve(ControllersNumber);
308
309     for (int i = 0; i < ControllersNumber ; ++i)
310     {
311         if(testContextPtr->controllers.size() % ControllersPerThread ==0)
312         {
313             ThreadPtr thread = ThreadPtr(new DPL::Thread());
314             testContextPtr->threads.push_back(thread);
315             thread->Run();
316         }
317
318         ControllerPtr controller = ControllerPtr(new TestController());
319         testContextPtr->controllers.push_back(controller);
320         if(testContextPtr->controllers.size() % 2 == 0)
321         {
322             //This controller is being switched to thread (otherwise it is touched to main thread)
323             ThreadPtr thread = testContextPtr->threads.back();
324             controller->SwitchToThread(thread.get());
325         }
326         controller->DPL::Event::ControllerEventHandler<StartSendEvent>::PostEvent(StartSendEvent());
327     }
328     testContextPtr->quitter.Exec();
329     RUNNER_ASSERT(testContextPtr->g_SentCounter == testContextPtr->g_ReceivedCounter);
330     testContextPtr.reset();
331 }