Revert "[Tizen] Appendix log for ttrace + Print keycode and timestamp"
[platform/core/uifw/dali-core.git] / automated-tests / src / dali / utc-Dali-VertexBuffer.cpp
1 /*
2  * Copyright (c) 2023 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 <dali-test-suite-utils.h>
19 #include <dali/public-api/dali-core.h>
20 #include <chrono>
21 using namespace std::chrono_literals;
22 using namespace Dali;
23
24 #include <mesh-builder.h>
25 #include <future>
26
27 struct VertexBufferUpdater
28 {
29   struct Diagnostics
30   {
31     uint32_t counter{0};
32     void*    lastPtr{nullptr};
33     size_t   lastSize{0};
34     size_t   lastReturned{0};
35   };
36
37   VertexBufferUpdater() = default;
38
39   uint32_t UpdateVertices(void* ptr, size_t size)
40   {
41     diagnostics.lastPtr      = ptr;
42     diagnostics.lastSize     = size;
43     diagnostics.lastReturned = returnSize;
44     diagnostics.counter++;
45
46     promise.set_value(diagnostics);
47     return returnSize;
48   }
49
50   void SetCallbackReturnValue(size_t size)
51   {
52     returnSize = size;
53   }
54
55   void Reset()
56   {
57     promise = std::promise<Diagnostics>();
58   }
59
60   std::unique_ptr<VertexBufferUpdateCallback> CreateCallback()
61   {
62     return VertexBufferUpdateCallback::New(this, &VertexBufferUpdater::UpdateVertices);
63   }
64
65   Diagnostics GetValue()
66   {
67     auto value = promise.get_future().get();
68
69     // reset promise automatically
70     promise = {};
71     return value;
72   }
73
74   bool IsValueReady()
75   {
76     // fake-wait for two frames
77     auto status = promise.get_future().wait_for(32ms);
78     return status == std::future_status::ready;
79   }
80
81   Diagnostics               diagnostics;
82   size_t                    returnSize{0u};
83   std::promise<Diagnostics> promise;
84 };
85
86 void vertexBuffer_test_startup(void)
87 {
88   test_return_value = TET_UNDEF;
89 }
90
91 void vertexBuffer_test_cleanup(void)
92 {
93   test_return_value = TET_PASS;
94 }
95
96 int UtcDaliVertexBufferNew01(void)
97 {
98   TestApplication application;
99
100   Property::Map texturedQuadVertexFormat;
101   texturedQuadVertexFormat["aPosition"]    = Property::VECTOR2;
102   texturedQuadVertexFormat["aVertexCoord"] = Property::VECTOR2;
103
104   VertexBuffer vertexBuffer = VertexBuffer::New(texturedQuadVertexFormat);
105
106   DALI_TEST_EQUALS((bool)vertexBuffer, true, TEST_LOCATION);
107   END_TEST;
108 }
109
110 int UtcDaliVertexBufferNew02(void)
111 {
112   TestApplication application;
113   VertexBuffer    vertexBuffer;
114   DALI_TEST_EQUALS((bool)vertexBuffer, false, TEST_LOCATION);
115   END_TEST;
116 }
117
118 int UtcDaliVertexBufferDownCast01(void)
119 {
120   TestApplication application;
121
122   Property::Map texturedQuadVertexFormat;
123   texturedQuadVertexFormat["aPosition"]    = Property::VECTOR2;
124   texturedQuadVertexFormat["aVertexCoord"] = Property::VECTOR2;
125
126   VertexBuffer vertexBuffer = VertexBuffer::New(texturedQuadVertexFormat);
127
128   BaseHandle   handle(vertexBuffer);
129   VertexBuffer vertexBuffer2 = VertexBuffer::DownCast(handle);
130   DALI_TEST_EQUALS((bool)vertexBuffer2, true, TEST_LOCATION);
131   END_TEST;
132 }
133
134 int UtcDaliVertexBufferDownCast02(void)
135 {
136   TestApplication application;
137
138   Handle       handle       = Handle::New(); // Create a custom object
139   VertexBuffer vertexBuffer = VertexBuffer::DownCast(handle);
140   DALI_TEST_EQUALS((bool)vertexBuffer, false, TEST_LOCATION);
141   END_TEST;
142 }
143
144 int UtcDaliVertexBufferCopyConstructor(void)
145 {
146   TestApplication application;
147
148   VertexBuffer vertexBuffer = CreateVertexBuffer();
149
150   VertexBuffer vertexBufferCopy(vertexBuffer);
151
152   DALI_TEST_EQUALS((bool)vertexBufferCopy, true, TEST_LOCATION);
153   DALI_TEST_EQUALS(vertexBufferCopy.GetSize(), 0u, TEST_LOCATION);
154
155   END_TEST;
156 }
157
158 int UtcDaliVertexBufferAssignmentOperator(void)
159 {
160   TestApplication application;
161
162   VertexBuffer vertexBuffer = CreateVertexBuffer();
163
164   VertexBuffer vertexBuffer2;
165   DALI_TEST_EQUALS((bool)vertexBuffer2, false, TEST_LOCATION);
166
167   vertexBuffer2 = vertexBuffer;
168   DALI_TEST_EQUALS((bool)vertexBuffer2, true, TEST_LOCATION);
169   DALI_TEST_EQUALS(vertexBuffer2.GetSize(), 0u, TEST_LOCATION);
170
171   END_TEST;
172 }
173
174 int UtcDaliVertexBufferMoveConstructor(void)
175 {
176   TestApplication application;
177
178   VertexBuffer vertexBuffer = CreateVertexBuffer();
179   DALI_TEST_CHECK(vertexBuffer);
180   DALI_TEST_EQUALS(1, vertexBuffer.GetBaseObject().ReferenceCount(), TEST_LOCATION);
181   DALI_TEST_EQUALS(0u, vertexBuffer.GetSize(), TEST_LOCATION);
182
183   VertexBuffer move = std::move(vertexBuffer);
184   DALI_TEST_CHECK(move);
185   DALI_TEST_EQUALS(1, move.GetBaseObject().ReferenceCount(), TEST_LOCATION);
186   DALI_TEST_EQUALS(0u, move.GetSize(), TEST_LOCATION);
187   DALI_TEST_CHECK(!vertexBuffer);
188
189   END_TEST;
190 }
191
192 int UtcDaliVertexBufferMoveAssignment(void)
193 {
194   TestApplication application;
195
196   VertexBuffer vertexBuffer = CreateVertexBuffer();
197   DALI_TEST_CHECK(vertexBuffer);
198   DALI_TEST_EQUALS(1, vertexBuffer.GetBaseObject().ReferenceCount(), TEST_LOCATION);
199   DALI_TEST_EQUALS(0u, vertexBuffer.GetSize(), TEST_LOCATION);
200
201   VertexBuffer move;
202   move = std::move(vertexBuffer);
203   DALI_TEST_CHECK(move);
204   DALI_TEST_EQUALS(1, move.GetBaseObject().ReferenceCount(), TEST_LOCATION);
205   DALI_TEST_EQUALS(0u, move.GetSize(), TEST_LOCATION);
206   DALI_TEST_CHECK(!vertexBuffer);
207
208   END_TEST;
209 }
210
211 int UtcDaliVertexBufferSetData01(void)
212 {
213   TestApplication application;
214
215   Property::Map texturedQuadVertexFormat;
216   texturedQuadVertexFormat["aPosition"]    = Property::VECTOR2;
217   texturedQuadVertexFormat["aVertexCoord"] = Property::VECTOR2;
218
219   {
220     VertexBuffer vertexBuffer = VertexBuffer::New(texturedQuadVertexFormat);
221     DALI_TEST_EQUALS((bool)vertexBuffer, true, TEST_LOCATION);
222
223     const float halfQuadSize = .5f;
224     struct TexturedQuadVertex
225     {
226       Vector2 position;
227       Vector2 textureCoordinates;
228     };
229     TexturedQuadVertex texturedQuadVertexData[4] = {
230       {Vector2(-halfQuadSize, -halfQuadSize), Vector2(0.f, 0.f)},
231       {Vector2(halfQuadSize, -halfQuadSize), Vector2(1.f, 0.f)},
232       {Vector2(-halfQuadSize, halfQuadSize), Vector2(0.f, 1.f)},
233       {Vector2(halfQuadSize, halfQuadSize), Vector2(1.f, 1.f)}};
234
235     vertexBuffer.SetData(texturedQuadVertexData, 4);
236
237     Geometry geometry = Geometry::New();
238     geometry.AddVertexBuffer(vertexBuffer);
239
240     Shader   shader   = CreateShader();
241     Renderer renderer = Renderer::New(geometry, shader);
242     Actor    actor    = Actor::New();
243     actor.SetProperty(Actor::Property::SIZE, Vector3::ONE * 100.f);
244     actor.AddRenderer(renderer);
245     application.GetScene().Add(actor);
246
247     auto& drawTrace = application.GetGlAbstraction().GetDrawTrace();
248     drawTrace.Enable(true);
249
250     application.SendNotification();
251     application.Render(0);
252     application.Render();
253     application.SendNotification();
254
255     const TestGlAbstraction::BufferDataCalls& bufferDataCalls =
256       application.GetGlAbstraction().GetBufferDataCalls();
257
258     DALI_TEST_CHECK(drawTrace.FindMethod("DrawArrays"));
259
260     DALI_TEST_EQUALS(bufferDataCalls.size(), 3u, TEST_LOCATION);
261
262     DALI_TEST_EQUALS(bufferDataCalls[0], sizeof(texturedQuadVertexData), TEST_LOCATION);
263   }
264   // end of scope to let the buffer and geometry die; do another notification and render to get the deletion processed
265   application.SendNotification();
266   application.Render(0);
267
268   END_TEST;
269 }
270
271 int UtcDaliVertexBufferSetData02(void)
272 {
273   TestApplication application;
274
275   Property::Map texturedQuadVertexFormat;
276   texturedQuadVertexFormat["aPosition"]    = Property::VECTOR2;
277   texturedQuadVertexFormat["aVertexCoord"] = Property::VECTOR2;
278
279   VertexBuffer vertexBuffer = VertexBuffer::New(texturedQuadVertexFormat);
280   DALI_TEST_EQUALS((bool)vertexBuffer, true, TEST_LOCATION);
281
282   const float halfQuadSize = .5f;
283   struct TexturedQuadVertex
284   {
285     Vector2 position;
286     Vector2 textureCoordinates;
287   };
288   TexturedQuadVertex texturedQuadVertexData[4] = {
289     {Vector2(-halfQuadSize, -halfQuadSize), Vector2(0.f, 0.f)},
290     {Vector2(halfQuadSize, -halfQuadSize), Vector2(1.f, 0.f)},
291     {Vector2(-halfQuadSize, halfQuadSize), Vector2(0.f, 1.f)},
292     {Vector2(halfQuadSize, halfQuadSize), Vector2(1.f, 1.f)}};
293
294   vertexBuffer.SetData(texturedQuadVertexData, 4);
295
296   Geometry geometry = Geometry::New();
297   geometry.AddVertexBuffer(vertexBuffer);
298
299   Shader   shader   = CreateShader();
300   Renderer renderer = Renderer::New(geometry, shader);
301   Actor    actor    = Actor::New();
302   actor.SetProperty(Actor::Property::SIZE, Vector3::ONE * 100.f);
303   actor.AddRenderer(renderer);
304   application.GetScene().Add(actor);
305
306   application.SendNotification();
307   application.Render();
308
309   {
310     const TestGlAbstraction::BufferSubDataCalls& bufferSubDataCalls =
311       application.GetGlAbstraction().GetBufferSubDataCalls();
312
313     const TestGlAbstraction::BufferDataCalls& bufferDataCalls =
314       application.GetGlAbstraction().GetBufferDataCalls();
315
316     // Should be 1 (Flush standalone uniform buffer per each RenderScene)
317     DALI_TEST_EQUALS(bufferSubDataCalls.size(), 1u, TEST_LOCATION);
318     DALI_TEST_EQUALS(bufferDataCalls.size(), 2u, TEST_LOCATION);
319
320     DALI_TEST_EQUALS(bufferDataCalls[0], sizeof(texturedQuadVertexData), TEST_LOCATION);
321   }
322
323   // Re-upload the data on the vertexBuffer
324   vertexBuffer.SetData(texturedQuadVertexData, 4);
325
326   application.SendNotification();
327   application.Render(0);
328
329   END_TEST;
330 }
331
332 int UtcDaliVertexBufferMapInitializerList(void)
333 {
334   TestApplication application;
335
336   Property::Map texturedQuadVertexFormat = Property::Map{{"aPosition", Property::VECTOR2},
337                                                          {"aTexCoord", Property::VECTOR2},
338                                                          {"aColor", Property::VECTOR4}};
339
340   try
341   {
342     VertexBuffer vertexBuffer = VertexBuffer::New(texturedQuadVertexFormat);
343     tet_result(TET_PASS);
344   }
345   catch(Dali::DaliException& e)
346   {
347     // Shouldn't assert any more
348     tet_result(TET_FAIL);
349   }
350   END_TEST;
351 }
352
353 int UtcDaliVertexBufferInvalidTypeN01(void)
354 {
355   TestApplication application;
356
357   Property::Map texturedQuadVertexFormat;
358   texturedQuadVertexFormat["aPosition"]    = Property::MAP;
359   texturedQuadVertexFormat["aVertexCoord"] = Property::STRING;
360
361   try
362   {
363     VertexBuffer vertexBuffer = VertexBuffer::New(texturedQuadVertexFormat);
364     tet_result(TET_FAIL);
365   }
366   catch(Dali::DaliException& e)
367   {
368     DALI_TEST_ASSERT(e, "Property::Type not supported in VertexBuffer", TEST_LOCATION);
369   }
370   END_TEST;
371 }
372
373 int UtcDaliVertexBufferInvalidTypeN02(void)
374 {
375   TestApplication application;
376
377   Property::Map texturedQuadVertexFormat = Property::Map{{"aPosition", Property::MAP},
378                                                          {"aTexCoord", Property::STRING},
379                                                          {"aColor", Property::VECTOR4}};
380
381   try
382   {
383     VertexBuffer vertexBuffer = VertexBuffer::New(texturedQuadVertexFormat);
384     tet_result(TET_FAIL);
385   }
386   catch(Dali::DaliException& e)
387   {
388     DALI_TEST_ASSERT(e, "Property::Type not supported in VertexBuffer", TEST_LOCATION);
389   }
390   END_TEST;
391 }
392
393 int UtcDaliVertexBufferSetDataNegative(void)
394 {
395   TestApplication    application;
396   Dali::VertexBuffer instance;
397   try
398   {
399     void*         arg1(nullptr);
400     unsigned long arg2(0u);
401     instance.SetData(arg1, arg2);
402     DALI_TEST_CHECK(false); // Should not get here
403   }
404   catch(...)
405   {
406     DALI_TEST_CHECK(true); // We expect an assert
407   }
408   END_TEST;
409 }
410
411 int UtcDaliVertexBufferGetSizeNegative(void)
412 {
413   TestApplication    application;
414   Dali::VertexBuffer instance;
415   try
416   {
417     instance.GetSize();
418     DALI_TEST_CHECK(false); // Should not get here
419   }
420   catch(...)
421   {
422     DALI_TEST_CHECK(true); // We expect an assert
423   }
424   END_TEST;
425 }
426
427 int UtcDaliVertexBufferSetDivisor(void)
428 {
429   TestApplication application;
430
431   Property::Map texturedQuadVertexFormat;
432   texturedQuadVertexFormat["aPosition"] = Property::VECTOR2;
433   texturedQuadVertexFormat["aTexCoord"] = Property::VECTOR2;
434
435   Property::Map instanceFormat{{"aTranslate", Property::VECTOR2}, {"aColor", Property::VECTOR4}};
436
437   VertexBuffer vertexBuffer = VertexBuffer::New(texturedQuadVertexFormat);
438   DALI_TEST_EQUALS((bool)vertexBuffer, true, TEST_LOCATION);
439
440   DALI_TEST_EQUALS(0, vertexBuffer.GetDivisor(), TEST_LOCATION);
441
442   VertexBuffer instanceBuffer = VertexBuffer::New(instanceFormat);
443   DALI_TEST_EQUALS((bool)instanceBuffer, true, TEST_LOCATION);
444
445   const float halfQuadSize = .5f;
446   struct TexturedQuadVertex
447   {
448     Vector2 position;
449     Vector2 textureCoordinates;
450   };
451   TexturedQuadVertex texturedQuadVertexData[4] = {
452     {Vector2(-halfQuadSize, -halfQuadSize), Vector2(0.f, 0.f)},
453     {Vector2(halfQuadSize, -halfQuadSize), Vector2(1.f, 0.f)},
454     {Vector2(-halfQuadSize, halfQuadSize), Vector2(0.f, 1.f)},
455     {Vector2(halfQuadSize, halfQuadSize), Vector2(1.f, 1.f)}};
456
457   vertexBuffer.SetData(texturedQuadVertexData, 4);
458
459   struct InstanceData
460   {
461     Vector2 translate;
462     Vector4 color;
463   };
464
465   InstanceData instanceData[] = {{Vector2(12, 33), Color::WHITE},
466                                  {Vector2(-2000, 43), Color::BLUE},
467                                  {Vector2(200, 43), Color::GREEN},
468                                  {Vector2(-243, 43), Color::TURQUOISE},
469                                  {Vector2(192, 43), Color::CYAN},
470                                  {Vector2(-2000, 43), Color::MAGENTA},
471                                  {Vector2(-292, 393), Color::BLUE},
472                                  {Vector2(-499, 128), Color::BLUE},
473                                  {Vector2(328, 43), Color::BLUE},
474                                  {Vector2(726, 43), Color::BLUE}};
475   instanceBuffer.SetData(instanceData, sizeof(instanceData) / sizeof(InstanceData));
476   instanceBuffer.SetDivisor(1);
477   DALI_TEST_EQUALS(1, instanceBuffer.GetDivisor(), TEST_LOCATION);
478
479   Geometry geometry = Geometry::New();
480   geometry.AddVertexBuffer(vertexBuffer);
481   geometry.AddVertexBuffer(instanceBuffer);
482
483   Shader   shader   = CreateShader();
484   Renderer renderer = Renderer::New(geometry, shader);
485   Actor    actor    = Actor::New();
486   actor.SetProperty(Actor::Property::SIZE, Vector3::ONE * 100.f);
487   actor.AddRenderer(renderer);
488   application.GetScene().Add(actor);
489
490   TestGlAbstraction& gl          = application.GetGlAbstraction();
491   auto&              bufferTrace = gl.GetBufferTrace();
492   auto&              drawTrace   = gl.GetDrawTrace();
493   bufferTrace.Enable(true);
494   drawTrace.Enable(true);
495
496   application.SendNotification();
497   application.Render();
498
499   TraceCallStack::NamedParams params;
500   params["divisor"] << "1";
501   DALI_TEST_CHECK(bufferTrace.FindMethodAndParams("VertexAttribDivisor", params));
502
503   TraceCallStack::NamedParams params2;
504   DALI_TEST_CHECK(drawTrace.FindMethodAndGetParameters("DrawArraysInstanced", params2));
505   std::ostringstream oss;
506   oss << sizeof(instanceData) / sizeof(InstanceData);
507   DALI_TEST_EQUALS(params2["instanceCount"].str(), oss.str(), TEST_LOCATION);
508   END_TEST;
509 }
510
511 int UtcDaliVertexBufferUpdateCallback(void)
512 {
513   TestApplication application;
514
515   // Create vertex buffer
516   VertexBuffer vertexBuffer = VertexBuffer::New(Property::Map() = {
517                                                   {"aPosition", Property::Type::VECTOR2},
518                                                   {"aTexCoord", Property::Type::VECTOR2}});
519
520   // set callback
521   auto callback = std::make_unique<VertexBufferUpdater>();
522   vertexBuffer.SetVertexBufferUpdateCallback(callback->CreateCallback());
523
524   struct Vertex
525   {
526     Vector2 pos;
527     Vector2 uv;
528   };
529
530   std::vector<Vertex> vertices;
531   vertices.resize(16);
532   vertexBuffer.SetData(vertices.data(), 16);
533
534   Geometry geometry = Geometry::New();
535   geometry.AddVertexBuffer(vertexBuffer);
536   Shader   shader   = CreateShader();
537   Renderer renderer = Renderer::New(geometry, shader);
538   Actor    actor    = Actor::New();
539   actor.SetProperty(Actor::Property::SIZE, Vector3::ONE * 100.f);
540   actor.AddRenderer(renderer);
541   application.GetScene().Add(actor);
542
543   auto& gl    = application.GetGlAbstraction();
544   auto& trace = gl.GetDrawTrace();
545   trace.Enable(true);
546   trace.EnableLogging(true);
547
548   callback->SetCallbackReturnValue(16 * sizeof(Vertex));
549
550   application.SendNotification();
551   application.Render();
552
553   auto value = callback->GetValue();
554
555   // Test whether callback ran
556   DALI_TEST_EQUALS(value.counter, 1, TEST_LOCATION);
557   DALI_TEST_EQUALS(value.lastSize, 16 * sizeof(Vertex), TEST_LOCATION);
558   DALI_TEST_EQUALS(value.lastReturned, 16 * sizeof(Vertex), TEST_LOCATION);
559   DALI_TEST_NOT_EQUALS(value.lastPtr, (void*)nullptr, 0, TEST_LOCATION);
560
561   // test whether draw call has been issued (return value indicates end of array to be drawn)
562   auto result = trace.FindMethod("DrawArrays");
563   DALI_TEST_EQUALS(result, true, TEST_LOCATION);
564   result = trace.FindMethodAndParams("DrawArrays", "4, 0, 16");
565   DALI_TEST_EQUALS(result, true, TEST_LOCATION);
566
567   // Test 2. Update and render only half of vertex buffer
568   callback->SetCallbackReturnValue(8 * sizeof(Vertex));
569   trace.Reset();
570
571   application.SendNotification();
572   application.Render();
573
574   value = callback->GetValue();
575   // Test whether callback ran
576   DALI_TEST_EQUALS(value.counter, 2, TEST_LOCATION);
577   DALI_TEST_EQUALS(value.lastSize, 16 * sizeof(Vertex), TEST_LOCATION);
578   DALI_TEST_EQUALS(value.lastReturned, 8 * sizeof(Vertex), TEST_LOCATION);
579   DALI_TEST_NOT_EQUALS(value.lastPtr, (void*)nullptr, 0, TEST_LOCATION);
580   result = trace.FindMethod("DrawArrays");
581   DALI_TEST_EQUALS(result, true, TEST_LOCATION);
582   result = trace.FindMethodAndParams("DrawArrays", "4, 0, 8");
583   DALI_TEST_EQUALS(result, true, TEST_LOCATION);
584
585   // Test 3. callback returns 0 elements to render, the draw call shouldn't happen.
586   callback->SetCallbackReturnValue(0);
587   trace.Reset();
588
589   application.SendNotification();
590   application.Render();
591
592   value = callback->GetValue();
593   // Test whether callback ran
594   DALI_TEST_EQUALS(value.counter, 3, TEST_LOCATION);
595   DALI_TEST_EQUALS(value.lastSize, 16 * sizeof(Vertex), TEST_LOCATION);
596   DALI_TEST_EQUALS(value.lastReturned, 0, TEST_LOCATION);
597   DALI_TEST_NOT_EQUALS(value.lastPtr, (void*)nullptr, 0, TEST_LOCATION);
598   result = trace.FindMethod("DrawArrays");
599   DALI_TEST_EQUALS(result, false, TEST_LOCATION);
600
601   // Test 4. removing callback, original behaviour should kick in
602   vertexBuffer.SetVertexBufferUpdateCallback(nullptr);
603   trace.Reset();
604   callback->Reset();
605
606   application.SendNotification();
607   application.Render();
608
609   auto valueReady = callback->IsValueReady();
610   DALI_TEST_EQUALS(valueReady, false, TEST_LOCATION);
611   DALI_TEST_EQUALS(callback->diagnostics.counter, 3, TEST_LOCATION);
612   result = trace.FindMethod("DrawArrays");
613   DALI_TEST_EQUALS(result, true, TEST_LOCATION);
614   result = trace.FindMethodAndParams("DrawArrays", "4, 0, 16");
615   DALI_TEST_EQUALS(result, true, TEST_LOCATION);
616
617   END_TEST;
618 }