Change RegisterGlCallback function name of GlView
[platform/core/uifw/dali-toolkit.git] / automated-tests / src / dali-scene-loader / utc-Dali-DliLoader.cpp
1 /*
2  * Copyright (c) 2020 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 // Enable debug log for test coverage
19 #define DEBUG_ENABLED 1
20
21 #include "dali-scene-loader/public-api/dli-loader.h"
22 #include "dali-scene-loader/public-api/resource-bundle.h"
23 #include "dali-scene-loader/public-api/scene-definition.h"
24 #include "dali-scene-loader/public-api/load-result.h"
25 #include "dali-scene-loader/internal/json-util.h"
26 #include <dali-test-suite-utils.h>
27 #include <string_view>
28
29 using namespace Dali;
30 using namespace Dali::SceneLoader;
31
32 namespace
33 {
34
35 void ConfigureBlendShapeShaders(ResourceBundle& resources, const SceneDefinition& scene, Actor root,
36   std::vector<BlendshapeShaderConfigurationRequest>&& requests)
37 {
38   std::vector<std::string> errors;
39   auto onError = [&errors](const std::string& msg) {
40     errors.push_back(msg);
41   };
42
43   if (!scene.ConfigureBlendshapeShaders(resources, root, std::move(requests), onError))
44   {
45     ExceptionFlinger flinger(ASSERT_LOCATION);
46     for (auto& msg : errors)
47     {
48       flinger << msg << '\n';
49     }
50   }
51 }
52
53 struct Context
54 {
55   ResourceBundle::PathProvider pathProvider = [](ResourceType::Value type) {
56     return TEST_RESOURCE_DIR "/";
57   };
58
59   ResourceBundle resources;
60   SceneDefinition scene;
61   std::vector<CameraParameters> cameraParameters;
62   std::vector<LightParameters> lights;
63   std::vector<AnimationDefinition> animations;
64   std::vector<AnimationGroupDefinition> animGroups;
65
66   LoadResult output {
67     resources,
68     scene,
69     animations,
70     animGroups,
71     cameraParameters,
72     lights
73   };
74
75   DliLoader::InputParams input {
76     pathProvider(ResourceType::Mesh),
77     nullptr,
78     {},
79     {},
80     nullptr,
81   };
82   DliLoader::LoadParams loadParams{ input, output };
83
84   std::vector<std::string> errors;
85   DliLoader loader;
86
87   StringCallback onError = [this](const std::string& error) {
88     errors.push_back(error);
89     printf("%s\n", error.c_str());
90   };
91
92   Context()
93   {
94     loader.SetErrorCallback(onError);
95   }
96 };
97
98 bool StringHasTokens(const char* string, const std::vector<const char*>& tokens)
99 {
100   for (auto& token: tokens)
101   {
102     auto result = strstr(string, token);
103     if(nullptr == result)
104     {
105       return false;
106     }
107     string = result + strlen(token);
108   }
109   return true;
110 }
111
112 }
113
114 int UtcDaliDliLoaderLoadSceneNotFound(void)
115 {
116   Context ctx;
117
118   DALI_TEST_EQUAL(ctx.loader.LoadScene("does_not_exist.dli", ctx.loadParams), false);
119
120   auto error = ctx.loader.GetParseError();
121   DALI_TEST_CHECK(StringHasTokens(error.c_str(), { "Empty source buffer to parse." }));
122
123   END_TEST;
124 }
125
126 int UtcDaliDliLoaderLoadSceneFailParse(void)
127 {
128   Context ctx;
129
130   auto path = ctx.pathProvider(ResourceType::Mesh) + "invalid.gltf";
131   DALI_TEST_EQUAL(ctx.loader.LoadScene(path, ctx.loadParams), false);
132
133   auto error = ctx.loader.GetParseError();
134   DALI_TEST_CHECK(StringHasTokens(error.c_str(), { "Unexpected character." }));
135
136   END_TEST;
137 }
138
139 int UtcDaliDliLoaderLoadSceneAssertions(void)
140 {
141   const std::pair<std::string, std::string> pathExceptionPairs[] {
142      // from RequireChild()
143     { "scenes-nodes-missing", "Failed to find child node" },
144     { "scenes-missing", "Failed to find child node" },
145     { "nodes-missing", "Failed to find child node" },
146     // from ParseSceneInternal()
147     { "scene-out-of-bounds", "out of bounds" },
148     { "nodes-invalid-type", "invalid type; array required" },
149     { "nodes-array-empty", "must define a node id" },
150     { "root-id-invalid", "invalid value for root node index" },
151     { "root-id-out-of-bounds", "out of bounds" },
152     { "root-node-invalid-type", "invalid JSON type; object required" },
153     // from ParseSkeletons()
154     { "skeleton-node-missing", "Missing required attribute" },
155     { "skeleton-root-not-found", "not defined" },
156     // from ParseShaders()
157     { "shader-vertex-missing", "Missing vertex / fragment shader" },
158     { "shader-fragment-missing", "Missing vertex / fragment shader" },
159     // from ParseMeshes()
160     { "mesh-uri-missing", "Missing required attribute" },
161     { "mesh-indices-read-fail", "Failed to read indices" },
162     { "mesh-positions-read-fail", "Failed to read positions" },
163     // from ParseMaterials()
164     { "material-environment-out-of-bounds", "out of bounds" },
165     // from ParseNodes()
166     { "node-model-mesh-missing", "Missing mesh" },
167     { "node-arc-mesh-missing", "Missing mesh" },
168     { "node-animated-image-mesh-missing", "Missing mesh" },
169     { "node-renderable-mesh-invalid-type", "Invalid Mesh index type" },
170     { "node-renderable-mesh-out-of-bounds", "out of bounds" },
171     { "node-child-invalid-type", "invalid index type" },
172     { "node-name-already-used", "name already used" },
173     // from ParseAnimations()
174     { "animation-failed-to-open", "Failed to open animation data" }
175   };
176   for (auto& i: pathExceptionPairs)
177   {
178     Context ctx;
179
180     auto path = ctx.pathProvider(ResourceType::Mesh) + "dli/" + i.first + ".dli";
181     printf("\n\n%s: %s\n", path.c_str(), i.second.c_str());
182     DALI_TEST_ASSERTION(ctx.loader.LoadScene(path, ctx.loadParams), i.second.c_str());
183   }
184
185   END_TEST;
186 }
187
188 int UtcDaliDliLoaderLoadSceneExercise(void)
189 {
190   Context ctx;
191
192   auto path = ctx.pathProvider(ResourceType::Mesh) + "exercise.dli";
193   DALI_TEST_CHECK(ctx.loader.LoadScene(path, ctx.loadParams));
194   DALI_TEST_CHECK(ctx.errors.empty());
195
196   auto& scene = ctx.scene;
197   auto& roots = scene.GetRoots();
198   DALI_TEST_EQUAL(roots.size(), 2u);
199   DALI_TEST_EQUAL(scene.GetNode(roots[0])->mName, "Backdrop"); // default scene is scene 1 - this one.
200   DALI_TEST_EQUAL(scene.GetNode(roots[1])->mName, "ExerciseDemo");
201
202   DALI_TEST_EQUAL(scene.GetNodeCount(), 96u);
203
204   auto& resources = ctx.resources;
205   DALI_TEST_EQUAL(resources.mMeshes.size(), 11u);
206   DALI_TEST_EQUAL(resources.mMaterials.size(), 13u);
207   DALI_TEST_EQUAL(resources.mShaders.size(), 5u);
208   DALI_TEST_EQUAL(resources.mEnvironmentMaps.size(), 2u);
209   DALI_TEST_EQUAL(resources.mSkeletons.size(), 1u);
210
211   DALI_TEST_EQUAL(ctx.cameraParameters.size(), 1u);
212   DALI_TEST_EQUAL(ctx.lights.size(), 1u);
213   DALI_TEST_EQUAL(ctx.animations.size(), 18u);
214   DALI_TEST_EQUAL(ctx.animGroups.size(), 16u);
215
216   ViewProjection viewProjection;
217   Transforms xforms {
218     MatrixStack{},
219     viewProjection
220   };
221   NodeDefinition::CreateParams nodeParams{
222     resources,
223     xforms,
224   };
225
226   Customization::Choices choices;
227
228   TestApplication app;
229
230   Actor root = Actor::New();
231   SetActorCentered(root);
232   for (auto iRoot : scene.GetRoots())
233   {
234     auto resourceRefs = resources.CreateRefCounter();
235     scene.CountResourceRefs(iRoot, choices, resourceRefs);
236     resources.CountEnvironmentReferences(resourceRefs);
237     resources.LoadResources(resourceRefs, ctx.pathProvider);
238     if (auto actor = scene.CreateNodes(iRoot, choices, nodeParams))
239     {
240       scene.ConfigureSkeletonJoints(iRoot, resources.mSkeletons, actor);
241       scene.ConfigureSkinningShaders(resources, actor, std::move(nodeParams.mSkinnables));
242       ConfigureBlendShapeShaders(resources, scene, actor, std::move(nodeParams.mBlendshapeRequests));
243       scene.ApplyConstraints(actor, std::move(nodeParams.mConstrainables));
244       root.Add(actor);
245     }
246   }
247
248   DALI_TEST_EQUAL(root.GetChildCount(), 2u);
249   DALI_TEST_EQUAL(root.GetChildAt(0).GetProperty(Actor::Property::NAME).Get<std::string>(), "Backdrop");
250   DALI_TEST_EQUAL(root.GetChildAt(1).GetProperty(Actor::Property::NAME).Get<std::string>(), "ExerciseDemo");
251
252   END_TEST;
253 }
254
255 int UtcDaliDliLoaderLoadSceneMorph(void)
256 {
257   Context ctx;
258
259   std::vector<std::string> metadata;
260   uint32_t metadataCount = 0;
261   ctx.input.mPreNodeCategoryProcessors.push_back({ "metadata",
262     [&](const Property::Array& array, StringCallback) {
263       std::string key, value;
264       for (uint32_t i0 = 0, i1 = array.Count(); i0 < i1; ++i0)
265       {
266         auto& data = array.GetElementAt(i0);
267         DALI_TEST_EQUAL(data.GetType(), Property::MAP);
268
269         auto map = data.GetMap();
270         auto key = map->Find("key");
271         auto value = map->Find("value");
272         DALI_TEST_EQUAL(key->GetType(), Property::STRING);
273         DALI_TEST_EQUAL(value->GetType(), Property::STRING);
274         metadata.push_back(key->Get<std::string>() + ":" + value->Get<std::string>());
275
276         ++metadataCount;
277       }
278     }
279   });
280
281   std::vector<std::string> behaviors;
282   uint32_t behaviorCount = 0;
283   ctx.input.mPostNodeCategoryProcessors.push_back({ "behaviors",
284     [&](const Property::Array& array, StringCallback) {
285       for (uint32_t i0 = 0, i1 = array.Count(); i0 < i1; ++i0)
286       {
287         auto& data = array.GetElementAt(i0);
288         DALI_TEST_EQUAL(data.GetType(), Property::MAP);
289
290         auto map = data.GetMap();
291         auto event = map->Find("event");
292         auto url = map->Find("url");
293         DALI_TEST_EQUAL(event->GetType(), Property::STRING);
294         DALI_TEST_EQUAL(url->GetType(), Property::STRING);
295         behaviors.push_back(event->Get<std::string>() + ":" + url->Get<std::string>());
296
297         ++behaviorCount;
298       }
299     }
300   });
301
302   size_t numNodes = 0;
303   ctx.input.mNodePropertyProcessor = [&](const NodeDefinition&, const Property::Map&, StringCallback) {
304     ++numNodes;
305   };
306
307   auto path = ctx.pathProvider(ResourceType::Mesh) + "morph.dli";
308   DALI_TEST_CHECK(ctx.loader.LoadScene(path, ctx.loadParams));
309   DALI_TEST_CHECK(ctx.errors.empty());
310
311   auto& scene = ctx.scene;
312   auto& roots = scene.GetRoots();
313   DALI_TEST_EQUAL(roots.size(), 1u);
314   DALI_TEST_EQUAL(scene.GetNode(roots[0])->mName, "HeadTest_002");
315
316   DALI_TEST_EQUAL(numNodes, 3u);
317   DALI_TEST_EQUAL(scene.GetNodeCount(), numNodes);
318
319   auto& resources = ctx.resources;
320   DALI_TEST_EQUAL(resources.mMeshes.size(), 2u);
321   DALI_TEST_EQUAL(resources.mMaterials.size(), 1u);
322   DALI_TEST_EQUAL(resources.mShaders.size(), 5u);
323   DALI_TEST_EQUAL(resources.mEnvironmentMaps.size(), 2u);
324   DALI_TEST_EQUAL(resources.mSkeletons.size(), 0u);
325
326   DALI_TEST_EQUAL(ctx.cameraParameters.size(), 1u);
327   DALI_TEST_EQUAL(ctx.lights.size(), 1u);
328   DALI_TEST_EQUAL(ctx.animations.size(), 1u);
329   DALI_TEST_EQUAL(ctx.animGroups.size(), 0u);
330
331   DALI_TEST_EQUAL(metadata.size(), 4u);
332   DALI_TEST_EQUAL(behaviors.size(), 1u);
333
334   ViewProjection viewProjection;
335   Transforms xforms {
336     MatrixStack{},
337     viewProjection
338   };
339   NodeDefinition::CreateParams nodeParams{
340     resources,
341     xforms,
342   };
343
344   Customization::Choices choices;
345
346   TestApplication app;
347
348   Actor root = Actor::New();
349   SetActorCentered(root);
350   for (auto iRoot : scene.GetRoots())
351   {
352     auto resourceRefs = resources.CreateRefCounter();
353     scene.CountResourceRefs(iRoot, choices, resourceRefs);
354     resources.CountEnvironmentReferences(resourceRefs);
355     resources.LoadResources(resourceRefs, ctx.pathProvider);
356     if (auto actor = scene.CreateNodes(iRoot, choices, nodeParams))
357     {
358       scene.ConfigureSkeletonJoints(iRoot, resources.mSkeletons, actor);
359       scene.ConfigureSkinningShaders(resources, actor, std::move(nodeParams.mSkinnables));
360       ConfigureBlendShapeShaders(resources, scene, actor, std::move(nodeParams.mBlendshapeRequests));
361       scene.ApplyConstraints(actor, std::move(nodeParams.mConstrainables));
362       root.Add(actor);
363     }
364   }
365
366   DALI_TEST_EQUAL(root.GetChildCount(), 1u);
367   DALI_TEST_EQUAL(root.GetChildAt(0).GetProperty(Actor::Property::NAME).Get<std::string>(), "HeadTest_002");
368
369   END_TEST;
370 }
371
372 int UtcDaliDliLoaderLoadSceneArc(void)
373 {
374   Context ctx;
375
376   auto path = ctx.pathProvider(ResourceType::Mesh) + "arc.dli";
377   DALI_TEST_CHECK(ctx.loader.LoadScene(path, ctx.loadParams));
378   DALI_TEST_CHECK(ctx.errors.empty());
379
380   auto& scene = ctx.scene;
381   auto& roots = scene.GetRoots();
382   DALI_TEST_EQUAL(roots.size(), 1u);
383   DALI_TEST_EQUAL(scene.GetNode(roots[0])->mName, "root");
384
385   DALI_TEST_EQUAL(scene.GetNodeCount(), 2u);
386
387   auto& resources = ctx.resources;
388   DALI_TEST_EQUAL(resources.mMeshes.size(), 1u);
389   DALI_TEST_EQUAL(resources.mMaterials.size(), 1u);
390   DALI_TEST_EQUAL(resources.mShaders.size(), 1u);
391   DALI_TEST_EQUAL(resources.mEnvironmentMaps.size(), 1u);
392   DALI_TEST_EQUAL(resources.mSkeletons.size(), 0u);
393
394   DALI_TEST_EQUAL(ctx.cameraParameters.size(), 0u);
395   DALI_TEST_EQUAL(ctx.lights.size(), 0u);
396   DALI_TEST_EQUAL(ctx.animations.size(), 0u);
397   DALI_TEST_EQUAL(ctx.animGroups.size(), 0u);
398
399   ViewProjection viewProjection;
400   Transforms xforms {
401     MatrixStack{},
402     viewProjection
403   };
404   NodeDefinition::CreateParams nodeParams{
405     resources,
406     xforms,
407   };
408
409   Customization::Choices choices;
410
411   TestApplication app;
412
413   Actor root = Actor::New();
414   SetActorCentered(root);
415   for (auto iRoot : scene.GetRoots())
416   {
417     auto resourceRefs = resources.CreateRefCounter();
418     scene.CountResourceRefs(iRoot, choices, resourceRefs);
419     resources.CountEnvironmentReferences(resourceRefs);
420     resources.LoadResources(resourceRefs, ctx.pathProvider);
421     if (auto actor = scene.CreateNodes(iRoot, choices, nodeParams))
422     {
423       scene.ConfigureSkeletonJoints(iRoot, resources.mSkeletons, actor);
424       scene.ConfigureSkinningShaders(resources, actor, std::move(nodeParams.mSkinnables));
425       ConfigureBlendShapeShaders(resources, scene, actor, std::move(nodeParams.mBlendshapeRequests));
426       scene.ApplyConstraints(actor, std::move(nodeParams.mConstrainables));
427       root.Add(actor);
428     }
429   }
430
431   DALI_TEST_EQUAL(root.GetChildCount(), 1u);
432   DALI_TEST_EQUAL(root.GetChildAt(0).GetProperty(Actor::Property::NAME).Get<std::string>(), "root");
433
434   END_TEST;
435 }
436
437 int UtcDaliDliLoaderLoadSceneShaderUniforms(void)
438 {
439   Context ctx;
440
441   auto path = ctx.pathProvider(ResourceType::Mesh) + "dli/shader-uniforms.dli";
442   DALI_TEST_CHECK(ctx.loader.LoadScene(path, ctx.loadParams));
443   DALI_TEST_EQUAL(ctx.errors.size(), 1u);
444   DALI_TEST_CHECK(ctx.errors[0].find("failed to infer type") != std::string::npos);
445
446   auto& scene = ctx.scene;
447   auto& roots = scene.GetRoots();
448   DALI_TEST_EQUAL(roots.size(), 1u);
449   DALI_TEST_EQUAL(scene.GetNode(roots[0])->mName, "root");
450
451   DALI_TEST_EQUAL(scene.GetNodeCount(), 1u);
452
453   auto& resources = ctx.resources;
454   DALI_TEST_EQUAL(resources.mMeshes.size(), 0u);
455   DALI_TEST_EQUAL(resources.mMaterials.size(), 0u);
456   DALI_TEST_EQUAL(resources.mShaders.size(), 1u);
457   DALI_TEST_EQUAL(resources.mEnvironmentMaps.size(), 0u);
458   DALI_TEST_EQUAL(resources.mSkeletons.size(), 0u);
459
460   auto raw = resources.mShaders[0].first.LoadRaw(ctx.pathProvider(ResourceType::Shader));
461
462   TestApplication app;
463
464   auto shader = resources.mShaders[0].first.Load(std::move(raw));
465   DALI_TEST_EQUAL(shader.GetProperty(shader.GetPropertyIndex("uBool")).Get<float>(), 1.0f);
466   DALI_TEST_EQUAL(shader.GetProperty(shader.GetPropertyIndex("uInt")).Get<float>(), 255.0f);
467   DALI_TEST_EQUAL(shader.GetProperty(shader.GetPropertyIndex("uFloat")).Get<float>(), -0.5f);
468   DALI_TEST_EQUAL(shader.GetProperty(shader.GetPropertyIndex("uVec2")).Get<Vector2>(), Vector2(100.0f, -100.0f));
469   DALI_TEST_EQUAL(shader.GetProperty(shader.GetPropertyIndex("uVec3")).Get<Vector3>(), Vector3(50.0f, 0.f, -200.0f));
470   DALI_TEST_EQUAL(shader.GetProperty(shader.GetPropertyIndex("uVec4")).Get<Vector4>(), Vector4(0.1774f, 1.0f, 0.5333f, 0.7997f));
471   DALI_TEST_EQUAL(shader.GetProperty(shader.GetPropertyIndex("uMat3")).Get<Matrix3>(), Matrix3(9.0f, 8.0f, 7.0f, 6.0f, 5.0f, 4.0f, 3.0f, 2.0f, 1.0f));
472
473   Matrix expectedMatrix;
474   expectedMatrix.SetTransformComponents(Vector3::ONE * 8.0, Quaternion::IDENTITY, Vector3::ZERO);
475   DALI_TEST_EQUAL(shader.GetProperty(shader.GetPropertyIndex("uMat4")).Get<Matrix>(), expectedMatrix);
476
477   END_TEST;
478 }
479
480 int UtcDaliDliLoaderLoadSceneExtras(void)
481 {
482   Context ctx;
483
484   auto path = ctx.pathProvider(ResourceType::Mesh) + "dli/extras.dli";
485   DALI_TEST_CHECK(ctx.loader.LoadScene(path, ctx.loadParams));
486   DALI_TEST_EQUAL(ctx.errors.size(), 3u);
487   DALI_TEST_CHECK(ctx.errors[0].find("already defined; overriding") != std::string::npos);
488   DALI_TEST_CHECK(ctx.errors[1].find("empty string is invalid for name") != std::string::npos);
489   DALI_TEST_CHECK(ctx.errors[2].find("failed to interpret value") != std::string::npos);
490
491   auto& scene = ctx.scene;
492   auto& roots = scene.GetRoots();
493   DALI_TEST_EQUAL(roots.size(), 1u);
494   DALI_TEST_EQUAL(scene.GetNode(roots[0])->mName, "root");
495
496   DALI_TEST_EQUAL(scene.GetNodeCount(), 1u);
497
498   ViewProjection viewProjection;
499   Transforms xforms {
500     MatrixStack{},
501     viewProjection
502   };
503   auto& resources = ctx.resources;
504   NodeDefinition::CreateParams nodeParams{
505     resources,
506     xforms,
507   };
508
509   Customization::Choices choices;
510
511   TestApplication app;
512   Actor actor = scene.CreateNodes(0, choices, nodeParams);
513
514   DALI_TEST_EQUAL(actor.GetProperty(actor.GetPropertyIndex("fudgeFactor")).Get<float>(), 9000.1f);
515   DALI_TEST_EQUAL(actor.GetProperty(actor.GetPropertyIndex("fudgeVector")).Get<Vector2>(), Vector2(-.25f, 17.f));
516   DALI_TEST_EQUAL(actor.GetProperty(actor.GetPropertyIndex("isThisTheRealLife")).Get<bool>(), true);
517   DALI_TEST_EQUAL(actor.GetProperty(actor.GetPropertyIndex("isThisJustFantasy")).Get<bool>(), false);
518   DALI_TEST_EQUAL(actor.GetProperty(actor.GetPropertyIndex("velocity")).Get<Vector3>(), Vector3(.1f, 58.f, -.2f));
519   DALI_TEST_EQUAL(actor.GetProperty(actor.GetPropertyIndex("frameOfReference")).Get<Matrix>(), Matrix::IDENTITY);
520
521   END_TEST;
522 }
523
524 int UtcDaliDliLoaderLoadSceneConstraints(void)
525 {
526   Context ctx;
527
528   auto path = ctx.pathProvider(ResourceType::Mesh) + "dli/constraints.dli";
529   DALI_TEST_CHECK(ctx.loader.LoadScene(path, ctx.loadParams));
530   DALI_TEST_EQUAL(ctx.errors.size(), 1u);
531   DALI_TEST_CHECK(ctx.errors[0].find("invalid", ctx.errors[0].find("node ID")) != std::string::npos);
532
533   auto& scene = ctx.scene;
534   auto& roots = scene.GetRoots();
535   DALI_TEST_EQUAL(roots.size(), 1u);
536   DALI_TEST_EQUAL(scene.GetNode(0)->mName, "root");
537   DALI_TEST_EQUAL(scene.GetNode(1)->mName, "Alice");
538   DALI_TEST_EQUAL(scene.GetNode(2)->mName, "Bob");
539   DALI_TEST_EQUAL(scene.GetNode(3)->mName, "Charlie");
540
541   DALI_TEST_EQUAL(scene.GetNodeCount(), 4u);
542
543   ViewProjection viewProjection;
544   Transforms xforms {
545     MatrixStack{},
546     viewProjection
547   };
548   auto& resources = ctx.resources;
549   NodeDefinition::CreateParams nodeParams{
550     resources,
551     xforms,
552   };
553
554   Customization::Choices choices;
555
556   TestApplication app;
557
558   Actor root = scene.CreateNodes(0, choices, nodeParams);
559   Actor alice = root.FindChildByName("Alice");
560   Actor bob = root.FindChildByName("Bob");
561   Actor charlie = root.FindChildByName("Charlie");
562
563   DALI_TEST_EQUAL(nodeParams.mConstrainables.size(), 3u);
564   DALI_TEST_EQUAL(bob.GetProperty(bob.GetPropertyIndex("angularVelocity")).Get<Vector2>(), Vector2(-0.5, 0.0004));
565
566   ctx.errors.clear();
567   scene.ApplyConstraints(root, std::move(nodeParams.mConstrainables), ctx.onError);
568   DALI_TEST_CHECK(ctx.errors.empty());
569
570   app.GetScene().Add(root);
571   app.SendNotification();
572   app.Render();
573   app.SendNotification();
574   app.Render();
575
576   DALI_TEST_EQUAL(charlie.GetCurrentProperty(Actor::Property::ORIENTATION), alice.GetProperty(Actor::Property::ORIENTATION));
577   DALI_TEST_EQUAL(charlie.GetCurrentProperty(Actor::Property::POSITION), bob.GetProperty(Actor::Property::POSITION));
578   DALI_TEST_EQUAL(charlie.GetCurrentProperty(charlie.GetPropertyIndex("angularVelocity")), bob.GetProperty(bob.GetPropertyIndex("angularVelocity")));
579
580   END_TEST;
581 }
582
583 int UtcDaliDliLoaderNodeProcessor(void)
584 {
585   Context ctx;
586
587   std::vector<Property::Map> nodeMaps;
588   ctx.input.mNodePropertyProcessor = [&](const NodeDefinition&, Property::Map&& map, StringCallback) {
589     nodeMaps.push_back(map);
590   };
591
592   auto path = ctx.pathProvider(ResourceType::Mesh) + "dli/node-processor.dli";
593   DALI_TEST_CHECK(ctx.loader.LoadScene(path, ctx.loadParams));
594
595   DALI_TEST_EQUAL(nodeMaps.size(), 2u);
596   DALI_TEST_EQUAL(nodeMaps[0].Count(), 5u);
597   DALI_TEST_EQUAL(nodeMaps[0].Find("name")->Get<std::string>(), "rootA");
598   DALI_TEST_EQUAL(nodeMaps[0].Find("nickname")->Get<std::string>(), "same as name");
599   DALI_TEST_EQUAL(nodeMaps[0].Find("favourite number")->Get<int32_t>(), 63478);
600
601   auto propArray = nodeMaps[0].Find("array");
602   DALI_TEST_EQUAL(propArray->GetType(), Property::ARRAY);
603
604   auto array = propArray->GetArray();
605   DALI_TEST_EQUAL(array->Count(), 5);
606   DALI_TEST_EQUAL(array->GetElementAt(0).Get<int32_t>(), 1);
607   DALI_TEST_EQUAL(array->GetElementAt(1).Get<int32_t>(), 2);
608   DALI_TEST_EQUAL(array->GetElementAt(2).Get<int32_t>(), 4);
609   DALI_TEST_EQUAL(array->GetElementAt(3).Get<int32_t>(), 8);
610   DALI_TEST_EQUAL(array->GetElementAt(4).Get<int32_t>(), -500);
611
612   auto propObject = nodeMaps[0].Find("object");
613   DALI_TEST_EQUAL(propObject->GetType(), Property::MAP);
614
615   auto object = propObject->GetMap();
616   DALI_TEST_EQUAL(object->Count(), 5);
617   DALI_TEST_EQUAL(object->Find("physics")->Get<bool>(), true);
618   DALI_TEST_EQUAL(object->Find("elasticity")->Get<float>(), .27f);
619   DALI_TEST_EQUAL(object->Find("drag")->Get<float>(), .91f);
620
621   auto propInnerArray = object->Find("inner array");
622   DALI_TEST_EQUAL(propInnerArray->GetType(), Property::ARRAY);
623
624   auto innerArray = propInnerArray->GetArray();
625   DALI_TEST_EQUAL(innerArray->Count(), 3);
626   DALI_TEST_EQUAL(innerArray->GetElementAt(0).Get<std::string>(), "why");
627   DALI_TEST_EQUAL(innerArray->GetElementAt(1).Get<std::string>(), "not");
628   DALI_TEST_EQUAL(innerArray->GetElementAt(2).Get<bool>(), false);
629
630   auto propInnerObject = object->Find("inner object");
631   DALI_TEST_EQUAL(propInnerObject->GetType(), Property::MAP);
632
633   auto innerObject = propInnerObject->GetMap();
634   DALI_TEST_EQUAL(innerObject->Count(), 1);
635   DALI_TEST_EQUAL(innerObject->Find("supported")->Get<bool>(), true);
636
637   DALI_TEST_EQUAL(nodeMaps[1].Count(), 1u);
638   DALI_TEST_EQUAL(nodeMaps[1].Find("name")->Get<std::string>(), "rootB");
639
640   END_TEST;
641 }