Tizen 2.0 Release
[framework/web/wrt-commons.git] / tests / dpl / event / test_ic_delegate.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_ic_delegate.cpp
18  * @author      Pawel Sikorski (p.sikorski@samsung.com)
19  * @author      Lukasz Wrzosek (l.wrzosek@samsung.com)
20  * @version     1.0
21  * @brief       This file is the implementation file of fast delegate tests.
22  */
23 #include <dpl/test/test_runner.h>
24 #include <dpl/application.h>
25 #include <dpl/event/controller.h>
26 #include <dpl/log/log.h>
27 #include <dpl/fast_delegate.h>
28 #include <dpl/event/inter_context_delegate.h>
29 #include <dpl/thread.h>
30 #include <dpl/waitable_event.h>
31 #include <dpl/assert.h>
32 #include <dpl/mutex.h>
33 #include <dpl/type_list.h>
34 #include <memory>
35 RUNNER_TEST_GROUP_INIT(DPL)
36
37 const int IntVal = 123;
38 const std::string StringVal = "someString";
39
40 typedef DPL::Event::ICDelegate<> GetNothingDlpType;
41 typedef DPL::Event::ICDelegate<int> GetIntDlgType;
42 typedef DPL::Event::ICDelegate<int, std::string> GetIntAndStringDlgType;
43 DECLARE_GENERIC_EVENT_1(GetNothingEvent, GetNothingDlpType)
44 DECLARE_GENERIC_EVENT_1(GetIntEvent, GetIntDlgType)
45 DECLARE_GENERIC_EVENT_1(GetIntAndStringEvent, GetIntAndStringDlgType)
46
47 class ICTestController
48 : public DPL::Event::Controller<DPL::TypeListDecl<GetNothingEvent,
49                                                   GetIntEvent,
50                                                   GetIntAndStringEvent>::Type>
51 {
52   public:
53     ICTestController() { }
54
55   protected:
56     virtual void OnEventReceived(const GetNothingEvent& event)
57     {
58         event.GetArg0()(); //calling intercontext delegate
59     }
60     virtual void OnEventReceived(const GetIntEvent& event)
61     {
62         event.GetArg0()(IntVal); //calling intercontext delegate
63     }
64
65     virtual void OnEventReceived(const GetIntAndStringEvent& event)
66     {
67         event.GetArg0()(IntVal, StringVal); //calling intercontext delegate
68     }
69 };
70
71 struct TestResult
72 {
73     TestResult() :
74         m_correctThread0(false),
75         m_correctThread1(false),
76         m_correctThread2(false),
77         m_int(-1),
78         m_int2(-1),
79         m_string("")
80     {
81     }
82
83     void TestEventsPassed()
84     {
85         RUNNER_ASSERT(m_correctThread0);
86         RUNNER_ASSERT(m_correctThread1);
87         RUNNER_ASSERT(m_int == IntVal);
88         RUNNER_ASSERT(m_correctThread2);
89         RUNNER_ASSERT(m_int2 == IntVal);
90         RUNNER_ASSERT(m_string == StringVal);
91     }
92
93     void TestEventsDidNotPass()
94     {
95         RUNNER_ASSERT(!m_correctThread0);
96         RUNNER_ASSERT(!m_correctThread1);
97         RUNNER_ASSERT(m_int == -1);
98         RUNNER_ASSERT(!m_correctThread2);
99         RUNNER_ASSERT(m_int2 == -1);
100         RUNNER_ASSERT(m_string == "");
101     }
102
103     bool m_correctThread0;
104     bool m_correctThread1;
105     bool m_correctThread2;
106     int m_int;
107     int m_int2;
108     std::string m_string;
109 };
110
111 class TestContextFreeClass :
112     protected DPL::Thread,
113     public DPL::Event::ICDelegateSupport<TestContextFreeClass>
114 {
115   public:
116     TestContextFreeClass(ICTestController* controller, TestResult* result) :
117         Thread(),
118         m_testResult(result),
119         m_controller(controller)
120     {
121         LogDebug("Context thread id = " << this);
122     }
123
124     void Run()
125     {
126         LogDebug("Running Context Free thread");
127         Thread::Run();
128     }
129
130     void Quit()
131     {
132         LogDebug("Exiting Context Free thread");
133         Thread::Quit();
134     }
135
136
137     void Wait()
138     {
139         LogDebug("Waiting for thread");
140         DPL::WaitForSingleHandle(m_waitable.GetHandle());
141     }
142
143   protected:
144     void OnNothing()
145     {
146         LogDebug("Received nothing in thread = " << GetCurrentThread());
147         m_testResult->m_correctThread0 = (GetCurrentThread() == this);
148     }
149
150     void OnIntReceive(int val)
151     {
152         LogDebug("Received int in thread = " << GetCurrentThread());
153         m_testResult->m_correctThread1 = (GetCurrentThread() == this);
154         m_testResult->m_int = val;
155     }
156
157     void OnIntAndStringReceive(int val, std::string stringval)
158     {
159         LogDebug("Received int and string in thread = " << GetCurrentThread());
160         m_testResult->m_correctThread2 = (GetCurrentThread() == this);
161         m_testResult->m_int2 = val;
162         m_testResult->m_string = stringval;
163         m_waitable.Signal();
164     }
165
166     virtual int ThreadEntry()
167     {
168         GetNothingEvent getNothingEvent(
169             makeICDelegate(
170                 &TestContextFreeClass::OnNothing));
171         m_controller->DPL::Event::ControllerEventHandler<GetNothingEvent>::PostEvent(
172             getNothingEvent);
173
174         GetIntEvent getIntEvent(
175             makeICDelegate(
176                 &TestContextFreeClass::OnIntReceive));
177         m_controller->DPL::Event::ControllerEventHandler<GetIntEvent>::PostEvent(
178             getIntEvent);
179
180         GetIntAndStringEvent getIntAndStringEvent(
181             makeICDelegate(
182                 &TestContextFreeClass::OnIntAndStringReceive));
183         m_controller->DPL::Event::ControllerEventHandler<GetIntAndStringEvent>::PostEvent(
184             getIntAndStringEvent);
185
186         return Thread::ThreadEntry();
187     }
188
189   private:
190     TestResult* m_testResult;
191     DPL::WaitableEvent m_waitable;
192     ICTestController* m_controller;
193 };
194
195 RUNNER_TEST(ICDelegate_0)
196 {
197     DPL::Thread thread;
198     thread.Run();
199     LogDebug("Controller thread id = " << &thread);
200
201     ICTestController testController;
202     testController.Touch();
203     testController.SwitchToThread(&thread);
204
205     TestResult result;
206     TestContextFreeClass* contextFree =
207         new TestContextFreeClass(&testController, &result);
208     result.TestEventsDidNotPass();
209
210     thread.Run();
211     contextFree->Run();
212     contextFree->Wait();
213     contextFree->Quit();
214     thread.Quit();
215
216     delete contextFree;
217
218     result.TestEventsPassed();
219 }
220
221 RUNNER_TEST(ICDelegate_1)
222 {
223     DPL::Thread thread;
224     LogDebug("Controller thread id = " << &thread);
225
226     ICTestController testController;
227     testController.Touch();
228     testController.SwitchToThread(&thread);
229
230     TestResult result;
231     TestContextFreeClass* contextFree =
232         new TestContextFreeClass(&testController, &result);
233     result.TestEventsDidNotPass();
234
235     contextFree->Run();
236     contextFree->Quit();
237     delete contextFree; //deleting Delegates before actual Events are worked out
238     thread.Run();
239     thread.Quit();
240
241     result.TestEventsDidNotPass();
242 }
243
244 class TestContextFree;
245 class TestRunnerInThread;
246
247 namespace
248 {
249 const int ControllersPerThread = 40;
250 const int ContextFreePerThread = 180;
251 const int TestsPerController = 110;
252 const int TestThreads = 23;
253 const int TestsPerThread = 100;
254 const int NumberOfEvents = 230;
255
256 typedef std::shared_ptr<ICTestController> ICTestControllerPtr;
257 typedef std::shared_ptr<TestContextFree> TestContextFreePtr;
258 typedef std::shared_ptr<TestRunnerInThread> TestRunnerInThreadPtr;
259 typedef std::shared_ptr<DPL::Thread> ThreadPtr;
260
261 DPL::Mutex mutex;
262 std::list<TestContextFreePtr> frees;
263 std::list<ICTestControllerPtr> ctrls;
264 std::list<TestRunnerInThreadPtr> frees_threads;
265 std::list<ThreadPtr> ctrls_threads;
266
267 }
268
269 class TestContextFree : public DPL::Event::ICDelegateSupport<TestContextFree>
270 {
271   public:
272     TestContextFree(ICTestController* controller,
273                     int eventsCount) :
274         m_controller(controller),
275         m_eventsCount(eventsCount)
276     {
277     }
278
279     void Wait()
280     {
281         LogDebug("Waiting for thread");
282         DPL::WaitForSingleHandle(m_waitable.GetHandle());
283     }
284
285
286     void OnNothing()
287     {
288         LogDebug("Got");
289         m_eventsCount--;
290         if (m_eventsCount > 0) {
291             LogDebug("posting next event");
292             GetIntAndStringEvent getIntAndStringEvent(
293                 makeICDelegate(
294                     &TestContextFree::OnIntAndStringReceive));
295             LogDebug("posting next event ...");
296             m_controller->DPL::Event::ControllerEventHandler<GetIntAndStringEvent>::PostEvent(
297                 getIntAndStringEvent);
298             LogDebug("posting next event done");
299         } else {
300             LogDebug("test finished");
301             m_waitable.Signal();
302         }
303     }
304
305     void OnIntReceive(int)
306     {
307         LogDebug("Got");
308         m_eventsCount--;
309         if (m_eventsCount > 0) {
310             LogDebug("posting next event");
311             GetNothingEvent getNothingEvent(
312                 makeICDelegate(
313                     &TestContextFree::OnNothing));
314             LogDebug("posting next event ...");
315             m_controller->DPL::Event::ControllerEventHandler<GetNothingEvent>::PostEvent(
316                 getNothingEvent);
317             LogDebug("posting next event done");
318         } else {
319             LogDebug("test finished");
320             m_waitable.Signal();
321         }
322     }
323
324     void OnIntAndStringReceive(int, std::string)
325     {
326         LogDebug("Got");
327         m_eventsCount--;
328         if (m_eventsCount > 0) {
329             LogDebug("posting next event");
330
331             GetIntEvent getIntEvent(
332                 makeICDelegate(
333                     &TestContextFree::OnIntReceive));
334             LogDebug("posting next event ...");
335             m_controller->DPL::Event::ControllerEventHandler<GetIntEvent>::PostEvent(
336                 getIntEvent);
337             LogDebug("posting next event done");
338         } else {
339             LogDebug("test finished");
340             m_waitable.Signal();
341         }
342     }
343
344     void StartTestOnNothing()
345     {
346         GetNothingEvent getNothingEvent(
347             makeICDelegate(
348                 &TestContextFree::OnNothing));
349         m_controller->DPL::Event::ControllerEventHandler<GetNothingEvent>::PostEvent(
350             getNothingEvent);
351     }
352
353     void StartTestOnInt()
354     {
355         GetIntEvent getIntEvent(
356             makeICDelegate(
357                 &TestContextFree::OnIntReceive));
358         m_controller->DPL::Event::ControllerEventHandler<GetIntEvent>::PostEvent(
359             getIntEvent);
360     }
361
362     void StartTestOnIntAndString()
363     {
364         GetIntAndStringEvent getIntAndStringEvent(
365             makeICDelegate(
366                 &TestContextFree::OnIntAndStringReceive));
367         m_controller->DPL::Event::ControllerEventHandler<GetIntAndStringEvent>::PostEvent(
368             getIntAndStringEvent);
369     }
370
371     bool CheckTest()
372     {
373         LogDebug("Checking test result");
374         return m_eventsCount == 0;
375     }
376
377   private:
378     ICTestController* m_controller;
379     int m_eventsCount;
380     DPL::WaitableEvent m_waitable;
381 };
382
383 class TestRunnerInThread : public DPL::Thread
384 {
385   public:
386     TestRunnerInThread(int events, int tests) :
387         m_eventsCount(events),
388         m_tests(tests) {}
389
390     void WaitForInit()
391     {
392         LogDebug("Waiting for thread");
393         DPL::WaitForSingleHandle(m_init.GetHandle());
394     }
395
396   protected:
397     virtual int ThreadEntry()
398     {
399         LogDebug("Thread starts");
400         {
401             DPL::Mutex::ScopedLock lock(&mutex);
402             for (int i = 0; i < m_tests; ++i)
403             {
404                 if (i % TestsPerController == 0) {
405                     if (ctrls.size() % ControllersPerThread == 0) {
406                         ThreadPtr thread(new DPL::Thread());
407                         thread->Run();
408                         ctrls_threads.push_back(thread);
409                     }
410                     ICTestControllerPtr ptr(new ICTestController());
411                     ptr->Touch();
412                     ptr->SwitchToThread(ctrls_threads.back().get());
413                     ctrls.push_back(ptr);
414
415                     TestContextFreePtr t(new TestContextFree(ctrls.back().get(),
416                                                              m_eventsCount));
417                     t->StartTestOnNothing();
418                     LogDebug("");
419                     frees.push_back(t);
420                 }
421             }
422         }
423         m_init.Signal();
424         LogDebug("Thread starts loop");
425         return DPL::Thread::ThreadEntry();
426     }
427
428   private:
429     DPL::WaitableEvent m_init;
430     int m_eventsCount;
431     int m_tests;
432 };
433
434 RUNNER_TEST(ICDelegate_2)
435 {
436     LogDebug("Creating test threads");
437     for (int i = 0; i < TestThreads; ++i)
438     {
439         TestRunnerInThreadPtr ptr(
440             new TestRunnerInThread(NumberOfEvents, TestsPerThread));
441         frees_threads.push_back(ptr);
442         frees_threads.back()->Run();
443     }
444
445     FOREACH(it, frees_threads) {
446         (*it)->WaitForInit();
447     }
448     LogDebug("Creating test threads done");
449
450     FOREACH(it, frees) {
451         LogDebug("...");
452         (*it)->Wait();
453     }
454
455     FOREACH(it, frees) {
456         RUNNER_ASSERT((*it)->CheckTest());
457     }
458
459     frees.clear();
460
461     FOREACH(it, frees_threads) {
462         (*it)->Quit();
463     }
464
465     frees_threads.clear();
466
467     FOREACH(it, ctrls) {
468         (*it)->SwitchToThread(NULL);
469     }
470
471     FOREACH(it, ctrls_threads) {
472         (*it)->Quit();
473     }
474
475     ctrls.clear();
476     ctrls_threads.clear();
477 }
478
479 namespace ReuseCheck {
480 const int ReuseCount = 5;
481 typedef DPL::Event::ICDelegate<> GetNothingDlpType;
482 DECLARE_GENERIC_EVENT_1(ReuseCountEvent, GetNothingDlpType)
483
484 class ICReuseTestController
485 : public DPL::Event::Controller<DPL::TypeListDecl<ReuseCountEvent>::Type>
486 {
487   public:
488     ICReuseTestController() { m_reuseCount = 0; }
489
490   protected:
491     virtual void OnEventReceived(const ReuseCountEvent& event)
492     {
493         event.GetArg0()(); //calling intercontext delegate
494         if(++m_reuseCount < ReuseCount){
495             LogInfo("[Send] Reuse: " << m_reuseCount);
496             DPL::Event::ControllerEventHandler<ReuseCountEvent>::PostEvent(event);
497         }
498     }
499
500     int m_reuseCount;
501 };
502
503 class ReuseTestContextFreeClass :
504     protected DPL::Thread,
505     public DPL::Event::ICDelegateSupport<ReuseTestContextFreeClass>
506 {
507   public:
508     ReuseTestContextFreeClass(ICReuseTestController* controller) :
509         Thread(),
510         m_controller(controller),
511         m_reuseCount(0)
512     { }
513
514     void Run() { Thread::Run(); }
515     void Quit() { Thread::Quit(); }
516     void Wait() { DPL::WaitForSingleHandle(m_waitable.GetHandle()); }
517
518   protected:
519     void OnReuseReceive()
520     {
521         LogDebug("[Received] : " << ++m_reuseCount);
522         if(m_reuseCount == ReuseCount)
523             m_waitable.Signal();
524     }
525
526     virtual int ThreadEntry()
527     {
528         ReuseCountEvent reuseEvent(
529             makeICDelegate(
530                 &ReuseTestContextFreeClass::OnReuseReceive,
531                 DPL::Event::ICD::Reuse::Yes));
532         m_controller->DPL::Event::ControllerEventHandler<ReuseCountEvent>::PostEvent(
533             reuseEvent);
534
535         return Thread::ThreadEntry();
536     }
537
538   private:
539     DPL::WaitableEvent m_waitable;
540     ICReuseTestController* m_controller;
541     int m_reuseCount;
542 };
543
544 RUNNER_TEST(ICDelegate_3)
545 {
546     DPL::Thread thread;
547     thread.Run();
548     LogDebug("Controller thread id = " << &thread);
549
550     ICReuseTestController testController;
551     testController.Touch();
552     testController.SwitchToThread(&thread);
553
554     ReuseTestContextFreeClass* contextFree =
555         new ReuseTestContextFreeClass(&testController);
556
557     thread.Run();
558     contextFree->Run();
559     contextFree->Wait();
560     contextFree->Quit();
561     thread.Quit();
562
563     delete contextFree;
564
565     RUNNER_ASSERT(true);
566 }
567 } //namespace ReuseCheck