If a RenderTask's exclusive actor is destoryed, then ensure the RenderTaskList of...
[platform/core/uifw/dali-core.git] / automated-tests / src / dali-internal / utc-Dali-Internal-ActorObserver.cpp
1 /*
2  * Copyright (c) 2019 Samsung Electronics Co., Ltd.
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
18 #include <iostream>
19
20 #include <stdlib.h>
21
22 #include <dali-test-suite-utils.h>
23 #include <dali/public-api/signals/callback.h>
24
25 // Internal headers are allowed here
26 #include <dali/internal/event/actors/actor-impl.h>
27 #include <dali/internal/event/events/actor-observer.h>
28
29 using namespace Dali;
30 using ActorObserver = Internal::ActorObserver;
31
32 namespace TestCallback
33 {
34 Internal::Actor* disconnectedActor = nullptr;
35 int callCount = 0;
36 void Function( Internal::Actor* actor )
37 {
38   disconnectedActor = actor;
39   ++callCount;
40 }
41
42 void Reset()
43 {
44   callCount = 0;
45   disconnectedActor = nullptr;
46 }
47
48 } // namespace TestCallback
49
50 void utc_dali_internal_actor_observer_startup()
51 {
52   test_return_value = TET_UNDEF;
53 }
54
55 void utc_dali_internal_actor_observer_cleanup()
56 {
57   test_return_value = TET_PASS;
58 }
59
60 int UtcDaliActorObserverTests(void)
61 {
62   TestApplication application;
63
64   auto stage = Stage::GetCurrent();
65   auto actor = Actor::New();
66   auto& actorImpl = GetImplementation( actor );
67
68   // Ensure we're not observing anything at the start
69   ActorObserver actorObserver;
70   DALI_TEST_EQUALS( actorObserver.GetActor(), nullptr, TEST_LOCATION );
71
72   // Set the actor and ensure GetActor returns the correct pointer
73   actorObserver.SetActor( &actorImpl );
74   DALI_TEST_EQUALS( actorObserver.GetActor(), &actorImpl, TEST_LOCATION );
75
76   stage.Add( actor );
77   DALI_TEST_EQUALS( actorObserver.GetActor(), &actorImpl, TEST_LOCATION );
78
79   // Removing the actor from the stage should make it return null
80   stage.Remove( actor );
81   DALI_TEST_EQUALS( actorObserver.GetActor(), nullptr, TEST_LOCATION );
82
83   // Adding the actor back to the scene should mean it returning the actor again
84   stage.Add( actor );
85   DALI_TEST_EQUALS( actorObserver.GetActor(), &actorImpl, TEST_LOCATION );
86
87   // Resetting the actor should return nullptr
88   actorObserver.ResetActor();
89   DALI_TEST_EQUALS( actorObserver.GetActor(), nullptr, TEST_LOCATION );
90
91   // Set the actor again
92   actorObserver.SetActor( &actorImpl );
93   DALI_TEST_EQUALS( actorObserver.GetActor(), &actorImpl, TEST_LOCATION );
94
95   // Create another Actor and observe that (don't add it to the stage just yet)
96   {
97     auto actor2 = Actor::New();
98     auto& actor2Impl = GetImplementation( actor2 );
99     actorObserver.SetActor( &actor2Impl );
100     DALI_TEST_EQUALS( actorObserver.GetActor(), &actor2Impl, TEST_LOCATION );
101   }
102
103   // Actor destroyed now, should return nullptr
104   DALI_TEST_EQUALS( actorObserver.GetActor(), nullptr, TEST_LOCATION );
105
106   END_TEST;
107 }
108
109 int UtcDaliActorObserverGracefulDeletion(void)
110 {
111   TestApplication application;
112
113   // Create an ActorObserver and observe an actor that outlives the observer...
114   // when the actor is destroyed, there should be no segmentation fault,
115   // i.e. the ActorObserver should unregister itself
116   try
117   {
118     {
119       // Scope lifetime of Actor
120       auto actor = Actor::New();
121       auto& actorImpl = GetImplementation( actor );
122
123       // Now scope the lifetime of ActorObserver
124       {
125         ActorObserver actorObserver;
126         actorObserver.SetActor( &actorImpl );
127       } // ActorObserver goes out of scope
128     } // Actor goes out of scope
129
130     // If we get here without a crash, then it's all good
131     DALI_TEST_CHECK( true );
132   }
133   catch( ... )
134   {
135     tet_infoline( "ActorObserver did not clean up properly" );
136     DALI_TEST_CHECK( false );
137   }
138
139   END_TEST;
140 }
141
142 int UtcDaliActorObserverMoveConstructorAndAssignmentEmpty(void)
143 {
144   TestApplication application;
145
146   // Copy empty observer
147   ActorObserver observer1;
148   ActorObserver observer2( std::move( observer1 ) );
149   DALI_TEST_EQUALS( observer1.GetActor(), nullptr, TEST_LOCATION );
150   DALI_TEST_EQUALS( observer2.GetActor(), nullptr, TEST_LOCATION );
151
152   // Assign empty observer
153   observer1 = std::move( observer2 );
154   DALI_TEST_EQUALS( observer1.GetActor(), nullptr, TEST_LOCATION );
155   DALI_TEST_EQUALS( observer2.GetActor(), nullptr, TEST_LOCATION );
156
157   // Ensure self assignment doesn't change anything
158   observer1 = std::move( observer1 );
159   observer2 = std::move( observer2 );
160   DALI_TEST_EQUALS( observer1.GetActor(), nullptr, TEST_LOCATION );
161   DALI_TEST_EQUALS( observer2.GetActor(), nullptr, TEST_LOCATION );
162
163   END_TEST;
164 }
165
166 int UtcDaliActorObserverMoveConstructorAndAssignment(void)
167 {
168   TestApplication application;
169
170   // Ensure new observer is observing the correct actor
171   // Ensure previous observer is not observing anything any more
172   auto actor = Actor::New();
173   auto& actorImpl = GetImplementation( actor );
174
175   ActorObserver observer1;
176   observer1.SetActor( &actorImpl );
177   DALI_TEST_EQUALS( observer1.GetActor(), &actorImpl, TEST_LOCATION );
178
179   // Move constructor
180   ActorObserver observer2( std::move( observer1 ) );
181   DALI_TEST_EQUALS( observer1.GetActor(), nullptr, TEST_LOCATION );
182   DALI_TEST_EQUALS( observer2.GetActor(), &actorImpl, TEST_LOCATION );
183
184   // Move assignment
185   observer1 = std::move( observer2 );
186   DALI_TEST_EQUALS( observer1.GetActor(), &actorImpl, TEST_LOCATION );
187   DALI_TEST_EQUALS( observer2.GetActor(), nullptr, TEST_LOCATION );
188
189   // Self assignment
190   observer1 = std::move( observer1 );
191   observer2 = std::move( observer2 );
192   DALI_TEST_EQUALS( observer1.GetActor(), &actorImpl, TEST_LOCATION );
193   DALI_TEST_EQUALS( observer2.GetActor(), nullptr, TEST_LOCATION );
194
195   END_TEST;
196 }
197
198 int UtcDaliActorObserverEnsureRValueCleansUp(void)
199 {
200   TestApplication application;
201
202   // ActorObservers observe the actors
203   // When an actor observer is moved, we need to ensure that the r-value observer cleans up after itself
204
205   // Here we're testing that we're handling this correctly by scoping the lifetime of the observer and actor
206   try
207   {
208     {
209       // Scope lifetime of Actor
210       auto actor = Actor::New();
211       auto& actorImpl = GetImplementation( actor );
212
213       // Score lifetime of observers
214       {
215         ActorObserver observer1;
216         observer1.SetActor( &actorImpl );
217         ActorObserver observer2( std::move( observer1 ) );
218       } // Both observers die here
219     } // Actor goes out of scope
220
221     // If we get here without a crash, then it's all good
222     DALI_TEST_CHECK( true );
223   }
224   catch( ... )
225   {
226     tet_infoline( "ActorObserver did not clean up properly" );
227     DALI_TEST_CHECK( false );
228   }
229
230   END_TEST;
231 }
232
233 int UtcDaliActorObserverFunctionCallback(void)
234 {
235   TestApplication application;
236
237   // Test to ensure the passed in callback is called when the observed actor is disconnected
238   TestCallback::Reset();
239
240   auto stage = Stage::GetCurrent();
241   auto actor = Actor::New();
242   auto& actorImpl = GetImplementation( actor );
243   stage.Add( actor );
244
245   ActorObserver actorObserver( MakeCallback( &TestCallback::Function ) );
246   actorObserver.SetActor( &actorImpl );
247   DALI_TEST_EQUALS( actorObserver.GetActor(), &actorImpl, TEST_LOCATION );
248   DALI_TEST_EQUALS( TestCallback::disconnectedActor, nullptr, TEST_LOCATION );
249
250   // Unstage Actor
251   actor.Unparent();
252   DALI_TEST_EQUALS( actorObserver.GetActor(), nullptr, TEST_LOCATION );
253   DALI_TEST_EQUALS( TestCallback::disconnectedActor, &actorImpl, TEST_LOCATION );
254
255   END_TEST;
256 }
257
258 int UtcDaliActorObserverFunctionCallbackEnsureNoDoubleDelete(void)
259 {
260   TestApplication application;
261
262   // When we move an observer, we need to make sure we pass the ownership of a connected callback
263   // to ensure no double deletion.
264   TestCallback::Reset();
265
266   try
267   {
268     auto stage = Stage::GetCurrent();
269     auto actor = Actor::New();
270     auto& actorImpl = GetImplementation( actor );
271     stage.Add( actor );
272
273     ActorObserver *observer1 = new ActorObserver( MakeCallback( &TestCallback::Function ) );
274     observer1->SetActor( &actorImpl );
275
276     // Move observer1 into a new observer
277     ActorObserver* observer2 = new ActorObserver( std::move( *observer1 ) );
278
279     // Unstage Actor, function should be called only once
280     actor.Unparent();
281     DALI_TEST_EQUALS( TestCallback::disconnectedActor, &actorImpl, TEST_LOCATION );
282     DALI_TEST_EQUALS( TestCallback::callCount, 1, TEST_LOCATION );
283
284     // Delete both observers here, only one of them should delete the callback
285     delete observer1;
286     delete observer2;
287
288     // If we get here without a crash, then the callback has NOT been double-freed
289     DALI_TEST_CHECK( true );
290   }
291   catch( ... )
292   {
293     DALI_TEST_CHECK( false );
294     tet_infoline( "Callback double Freed" );
295   }
296
297   END_TEST;
298 }