Add text wrapping hyphen mode support
[platform/core/uifw/dali-toolkit.git] / automated-tests / src / dali-toolkit-internal / utc-Dali-BidirectionalSupport.cpp
1 /*
2  * Copyright (c) 2021 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 #include <stdlib.h>
20
21 #include <dali/devel-api/text-abstraction/bidirectional-support.h>
22 #include <dali-toolkit/internal/text/bidirectional-support.h>
23 #include <dali-toolkit/internal/text/character-set-conversion.h>
24 #include <dali-toolkit/internal/text/text-run-container.h>
25 #include <dali-toolkit-test-suite-utils.h>
26 #include <dali-toolkit/dali-toolkit.h>
27 #include <toolkit-text-utils.h>
28
29 using namespace Dali;
30 using namespace Toolkit;
31 using namespace Text;
32
33 // Tests the following functions.
34 //
35 // void SetBidirectionalInfo( const Vector<Character>& text,
36 //                            const Vector<ScriptRun>& scripts,
37 //                            const Vector<LineBreakInfo>& lineBreakInfo,
38 //                            CharacterIndex startIndex,
39 //                            Length numberOfCharacters,
40 //                            Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo )
41 // bool GetMirroredText( const Vector<Character>& text,
42 //                       Vector<CharacterDirection>& directions,
43 //                       const Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo,
44 //                       CharacterIndex startIndex,
45 //                       Length numberOfCharacters,
46 //                       Vector<Character>& mirroredText )
47 // void GetCharactersDirection( const Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo,
48 //                              Length totalNumberOfCharacters,
49 //                              CharacterIndex startIndex,
50 //                              Length numberOfCharacters,
51 //                              Vector<CharacterDirection>& directions )
52
53 //////////////////////////////////////////////////////////
54
55 namespace
56 {
57
58 struct SetBidirectionalInfoData
59 {
60   std::string   description;                 ///< Description of the test.
61   std::string   text;                        ///< Input text.
62   unsigned int  startIndex;                  ///< The index from where the model is updated.
63   unsigned int  numberOfCharacters;          ///< The number of characters to update.
64   unsigned int  numberOfParagraphs;          ///< The expected number of bidirectional paragraphs.
65   unsigned int* indices;                     ///< The expected indices to the first character of each paragraph.
66   unsigned int* numberOfParagraphCharacters; ///< The expected number of characters of each paragraph.
67   bool*         directions;                  ///< The expected direction of each paragraph.
68 };
69
70 struct BidiLineData
71 {
72   unsigned int  characterIndex;
73   unsigned int  numberOfCharacters;
74   unsigned int* visualToLogical;
75 };
76
77 struct GetMirroredTextData
78 {
79   std::string  description;        ///< Description of the test.
80   std::string  text;               ///< Input text.
81   unsigned int startIndex;         ///< The index from where the model is updated.
82   unsigned int numberOfCharacters; ///< The number of the characters.
83   std::string  mirroredText;       ///< The expected result.
84 };
85
86 struct GetCharactersDirectionData
87 {
88   std::string  description;            ///< Description of the test.
89   std::string  text;                   ///< Input text.
90   unsigned int startIndex;             ///< The index from where the model is updated.
91   unsigned int numberOfCharacters;     ///< The number of characters.
92   bool*        directions;             ///< The expected directions.
93   bool         markupProcessorEnabled; ///< Enable markup processor to use markup text.
94 };
95
96 bool SetBidirectionalInfoTest( const SetBidirectionalInfoData& data )
97 {
98   // 1) Create the model.
99   ModelPtr textModel;
100   MetricsPtr metrics;
101   Size textArea(100.f, 60.f);
102   Size layoutSize;
103
104   // Create the model.
105   const Vector<FontDescriptionRun> fontDescriptions;
106   const LayoutOptions options;
107   CreateTextModel( data.text,
108                    textArea,
109                    fontDescriptions,
110                    options,
111                    layoutSize,
112                    textModel,
113                    metrics,
114                    false,
115                    LineWrap::WORD );
116
117   LogicalModelPtr logicalModel = textModel->mLogicalModel;
118   VisualModelPtr visualModel = textModel->mVisualModel;
119
120   // 2) Clear the bidirectional paragraph info data.
121   Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = logicalModel->mBidirectionalParagraphInfo;
122   if( 0u != data.numberOfCharacters )
123   {
124     ClearCharacterRuns( data.startIndex,
125                         data.startIndex + data.numberOfCharacters - 1u,
126                         bidirectionalInfo );
127   }
128
129   // 3) Call the SetBidirectionalInfo() function.
130   SetBidirectionalInfo( logicalModel->mText,
131                         logicalModel->mScriptRuns,
132                         logicalModel->mLineBreakInfo,
133                         data.startIndex,
134                         data.numberOfCharacters,
135                         bidirectionalInfo );
136
137   // 4) Compare with the expected results.
138   TextAbstraction::BidirectionalSupport bidirectionalSupport = TextAbstraction::BidirectionalSupport::Get();
139
140   if( data.numberOfParagraphs != bidirectionalInfo.Count() )
141   {
142     // Different number of expected bidirectional paragraphs.
143     std::cout << "  Different number of bidi paragraphs : " << bidirectionalInfo.Count() << ", expected : " << data.numberOfParagraphs << std::endl;
144     return false;
145   }
146
147   for( unsigned int index = 0u; index < data.numberOfParagraphs; ++index )
148   {
149     const BidirectionalParagraphInfoRun& run = bidirectionalInfo[index];
150
151     const CharacterDirection direction = bidirectionalSupport.GetParagraphDirection( run.bidirectionalInfoIndex );
152     if( direction != data.directions[index] )
153     {
154       std::cout << "  Different direction" << std::endl;
155       std::cout << "        paragraph : " << index << std::endl;
156       std::cout << "            index : " << run.characterRun.characterIndex << ", num chars : " << run.characterRun.numberOfCharacters << ", direction : " << direction << std::endl;
157       std::cout << "  expected, index : " << data.indices[index] << ", num chars : " << data.numberOfParagraphCharacters[index] << ", direction : " << data.directions[index] << std::endl;
158       return false;
159     }
160
161     if( run.characterRun.characterIndex != data.indices[index] )
162     {
163       std::cout << "  Different index" << std::endl;
164       std::cout << "        paragraph : " << index << std::endl;
165       std::cout << "            index : " << run.characterRun.characterIndex << ", num chars : " << run.characterRun.numberOfCharacters << ", direction : " << direction << std::endl;
166       std::cout << "  expected, index : " << data.indices[index] << ", num chars : " << data.numberOfParagraphCharacters[index] << ", direction : " << data.directions[index] << std::endl;
167       return false;
168     }
169     if( run.characterRun.numberOfCharacters != data.numberOfParagraphCharacters[index] )
170     {
171       std::cout << "  Different number of characters" << std::endl;
172       std::cout << "        paragraph : " << index << std::endl;
173       std::cout << "            index : " << run.characterRun.characterIndex << ", num chars : " << run.characterRun.numberOfCharacters << ", direction : " << direction << std::endl;
174       std::cout << "  expected, index : " << data.indices[index] << ", num chars : " << data.numberOfParagraphCharacters[index] << ", direction : " << data.directions[index] << std::endl;
175       return false;
176     }
177   }
178
179   return true;
180 }
181
182 bool GetMirroredTextTest( const GetMirroredTextData& data )
183 {
184   // 1) Create the model.
185   ModelPtr textModel;
186   MetricsPtr metrics;
187   Size textArea(100.f, 60.f);
188   Size layoutSize;
189
190   // Create the model.
191   const Vector<FontDescriptionRun> fontDescriptions;
192   const LayoutOptions options;
193   CreateTextModel( data.text,
194                    textArea,
195                    fontDescriptions,
196                    options,
197                    layoutSize,
198                    textModel,
199                    metrics,
200                    false,
201                    LineWrap::WORD );
202
203   LogicalModelPtr logicalModel = textModel->mLogicalModel;
204   VisualModelPtr visualModel = textModel->mVisualModel;
205
206   // 2) Call the GetMirroredText() function for the whole text
207   Vector<Character> mirroredText;
208   bool mirrored = false;
209   mirrored = GetMirroredText( logicalModel->mText,
210                               logicalModel->mCharacterDirections,
211                               logicalModel->mBidirectionalParagraphInfo,
212                               0u,
213                               logicalModel->mText.Count(),
214                               mirroredText );
215
216   // 3) Call the GetMirroredText() function for the given index + number of characters
217   mirrored = GetMirroredText( logicalModel->mText,
218                               logicalModel->mCharacterDirections,
219                               logicalModel->mBidirectionalParagraphInfo,
220                               data.startIndex,
221                               data.numberOfCharacters,
222                               mirroredText );
223
224   // 4) Compare the results.
225
226   // Convert to utf8
227   std::string mirroredString;
228   Utf32ToUtf8( mirroredText.Begin(),
229                mirroredText.Count(),
230                mirroredString );
231
232   if( !mirrored && ( mirroredString != data.text ) )
233   {
234     std::cout << "  No mirrored text and mirroredString != data.text." << std::endl;
235     std::cout << "  mirrored string : [" << mirroredString << "]" << std::endl;
236     std::cout << "             text : [" << data.text << "]" << std::endl;
237     return false;
238   }
239
240   if( mirrored && ( mirroredString == data.text ) )
241   {
242     std::cout << "  Mirrored text and mirroredString == data.text." << std::endl;
243     std::cout << "  mirrored string : [" << mirroredString << "]" << std::endl;
244     std::cout << "             text : [" << data.text << "]" << std::endl;
245     return false;
246   }
247
248   if( mirrored && ( mirroredString != data.mirroredText ) )
249   {
250     std::cout << "  Mirrored text and mirroredString != data.mirroredText." << std::endl;
251     std::cout << "  mirrored string : [" << mirroredString << "]" << std::endl;
252     std::cout << "             text : [" << data.mirroredText << "]" << std::endl;
253     return false;
254   }
255
256   return true;
257 }
258
259 bool GetCharactersDirectionTest( const GetCharactersDirectionData& data )
260 {
261   // 1) Create the model.
262   ModelPtr textModel;
263   MetricsPtr metrics;
264   Size textArea(100.f, 60.f);
265   Size layoutSize;
266
267   // Create the model.
268   const Vector<FontDescriptionRun> fontDescriptions;
269   const LayoutOptions options;
270   CreateTextModel( data.text,
271                    textArea,
272                    fontDescriptions,
273                    options,
274                    layoutSize,
275                    textModel,
276                    metrics,
277                    data.markupProcessorEnabled,
278                    LineWrap::WORD );
279
280   LogicalModelPtr logicalModel = textModel->mLogicalModel;
281   VisualModelPtr visualModel = textModel->mVisualModel;
282
283   Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = logicalModel->mBidirectionalParagraphInfo;
284
285   // 2) Clear the direction info data.
286   Vector<CharacterDirection>& directions = logicalModel->mCharacterDirections;
287
288   if( directions.Count() >= data.startIndex + data.numberOfCharacters )
289   {
290     directions.Erase( directions.Begin() + data.startIndex,
291                       directions.Begin() + data.startIndex + data.numberOfCharacters );
292   }
293
294   // 3) Call GetCharactersDirection() function.
295
296   GetCharactersDirection( bidirectionalInfo,
297                           logicalModel->mText.Count(),
298                           data.startIndex,
299                           data.numberOfCharacters,
300                           directions );
301
302   for( unsigned int index = 0u; index < logicalModel->mText.Count(); ++index )
303   {
304     if( data.directions[index] != directions[index] )
305     {
306       return false;
307     }
308   }
309
310   return true;
311 }
312
313 } // namespace
314
315 //////////////////////////////////////////////////////////
316
317 int UtcDaliSetBidirectionalInfo(void)
318 {
319   tet_infoline(" UtcDaliSetBidirectionalInfo");
320
321   unsigned int indices01[] = {};
322   unsigned int numberOfCharacters01[] = {};
323   bool         direction01[] = {};
324   unsigned int indices02[] = {};
325   unsigned int numberOfCharacters02[] = {};
326   bool         direction02[] = {};
327   unsigned int indices03[] = { 17u, 48u };
328   unsigned int numberOfCharacters03[] = { 14u, 14u };
329   bool         direction03[] = { true, true };
330   unsigned int indices04[] = { 17u, 31u, 79u };
331   unsigned int numberOfCharacters04[] = { 14u, 48u, 31u };
332   bool         direction04[] = { true, false, true };
333   unsigned int indices05[] = { 17u, 41u, 117u };
334   unsigned int numberOfCharacters05[] = { 24u, 76u, 49u };
335   bool         direction05[] = { true, false, true };
336   unsigned int indices06[] = { 17u, 48u };
337   unsigned int numberOfCharacters06[] = { 14u, 14u };
338   bool         direction06[] = { true, true };
339   unsigned int indices07[] = { 17u, 31u, 79u };
340   unsigned int numberOfCharacters07[] = { 14u, 48u, 31u };
341   bool         direction07[] = { true, false, true };
342   unsigned int indices08[] = { 17u, 41u, 117u };
343   unsigned int numberOfCharacters08[] = { 24u, 76u, 49u };
344   bool         direction08[] = { true, false, true };
345
346   struct SetBidirectionalInfoData data[] =
347   {
348     {
349       "Zero characters",
350       "",
351       0u,
352       0u,
353       0u,
354       indices01,
355       numberOfCharacters01,
356       direction01
357     },
358     {
359       "Some left to right paragraphs",
360       "Hello world\ndemo\n\n",
361       0u,
362       18u,
363       0u,
364       indices02,
365       numberOfCharacters02,
366       direction02
367     },
368     {
369       "A mix of left to right and right to left paragraphs.",
370       "Hello world demo\nمرحبا بالعالم\nhello world demo\nمرحبا بالعالم\nhello world demo",
371       0u,
372       78u,
373       2u,
374       indices03,
375       numberOfCharacters03,
376       direction03
377     },
378     {
379       "A mix of left to right and right to left paragraphs. Paragraphs also contain a mix of bidirectional text.",
380       "Hello world demo\nمرحبا بالعالم\nhello world demo مرحبا بالعالم hello world demo\nمرحبا hello world demo بالعالم\nhello world demo",
381       0u,
382       126u,
383       3u,
384       indices04,
385       numberOfCharacters04,
386       direction04
387     },
388     {
389       "A mix of left to right and right to left paragraphs. Paragraphs also contain a mix of bidirectional text and a mix of right to left scripts.",
390       "Hello world demo\nمرحبا שלום עולם بالعالم\nhello world שלום بالعالم עולם demo مرحبا שלום עולם بالعالم hello world demo\nمرحبا hello שלום بالعالم עולם world demo بالعالم\nhello world demo",
391       0u,
392       182u,
393       3u,
394       indices05,
395       numberOfCharacters05,
396       direction05
397     },
398     {
399       "A mix of left to right and right to left paragraphs. Updates a left to right paragraph.",
400       "Hello world demo\nمرحبا بالعالم\nhello world demo\nمرحبا بالعالم\nhello world demo",
401       31u,
402       17u,
403       2u,
404       indices06,
405       numberOfCharacters06,
406       direction06
407     },
408     {
409       "A mix of left to right and right to left paragraphs. Paragraphs also contain a mix of bidirectional text.",
410       "Hello world demo\nمرحبا بالعالم\nhello world demo مرحبا بالعالم hello world demo\nمرحبا hello world demo بالعالم\nhello world demo",
411       0u,
412       126u,
413       3u,
414       indices07,
415       numberOfCharacters07,
416       direction07
417     },
418     {
419       "A mix of left to right and right to left paragraphs. Paragraphs also contain a mix of bidirectional text and a mix of right to left scripts. Updates initial paragraphs.",
420       "Hello world demo\nمرحبا שלום עולם بالعالم\nhello world שלום بالعالم עולם demo مرحبا שלום עולם بالعالم hello world demo\nمرحبا hello שלום بالعالم עולם world demo بالعالم\nhello world demo",
421       0u,
422       41u,
423       3u,
424       indices08,
425       numberOfCharacters08,
426       direction08
427     },
428     {
429       "A mix of left to right and right to left paragraphs. Paragraphs also contain a mix of bidirectional text and a mix of right to left scripts. Updates mid paragraphs.",
430       "Hello world demo\nمرحبا שלום עולם بالعالم\nhello world שלום بالعالم עולם demo مرحبا שלום עולם بالعالم hello world demo\nمرحبا hello שלום بالعالم עולם world demo بالعالم\nhello world demo",
431       41u,
432       76u,
433       3u,
434       indices08,
435       numberOfCharacters08,
436       direction08
437     },
438     {
439       "A mix of left to right and right to left paragraphs. Paragraphs also contain a mix of bidirectional text and a mix of right to left scripts. Updates from character 85",
440       "Hello world demo\nمرحبا שלום עולם بالعالم\nhello world שלום بالعالم עולם demo مرحبا שלום עולם بالعالم hello world demo\nمرحبا hello שלום بالعالم עולם world demo بالعالم\nhello world demo",
441       117u,
442       65u,
443       3u,
444       indices08,
445       numberOfCharacters08,
446       direction08
447     },
448   };
449   const unsigned int numberOfTests = 10u;
450
451   for( unsigned int index = 0u; index < numberOfTests; ++index )
452   {
453     ToolkitTestApplication application;
454     if( !SetBidirectionalInfoTest( data[index] ) )
455     {
456       tet_result(TET_FAIL);
457     }
458   }
459
460   tet_result(TET_PASS);
461   END_TEST;
462 }
463
464 int UtcDaliGetMirroredText(void)
465 {
466   tet_infoline(" UtcDaliGetMirroredText");
467
468   struct GetMirroredTextData data[] =
469   {
470     {
471       "Zero characters.",
472       "",
473       0u,
474       0u,
475       ""
476     },
477     {
478       "Left to right characters only.",
479       "Hello world\nhello world demo.",
480       0u,
481       29u,
482       "Hello world\nhello world demo."
483     },
484     {
485       "Right to left characters but with no characters to mirror.",
486       "שלום עולם\nمرحبا بالعالم",
487       0u,
488       23u,
489       "שלום עולם\nمرحبا بالعالم"
490     },
491     {
492       "Right to left characters with some characters to mirror.",
493       "שלום עולם\n(مرحبا بالعالم)",
494       0u,
495       25u,
496       "שלום עולם\n)مرحبا بالعالم("
497     },
498     {
499       "Right to left characters with some characters to mirror. Update last paragraph.",
500       "שלום עולם\n(مرحبا بالعالم)",
501       10u,
502       15u,
503       "שלום עולם\n)مرحبا بالعالم("
504     },
505     {
506       "Mix of bidirectional text. With more paragraphs.",
507       "Hello world demo\nhello world\nhello world (مرحبا بالعالم שלום) עולם\nשלום مرحبا بالعالم עולם (hello) مرحبا بالعالم world"
508       " مرحبا بالعالم שלום עולם hello world hello world\nبالعالم שלום (hello) world demo (עולם)\nשלום (مرحبا بالعالم עולם) (hello)",
509       0u,
510       239u,
511       "Hello world demo\nhello world\nhello world (مرحبا بالعالم שלום( עולם\nשלום مرحبا بالعالم עולם )hello( مرحبا بالعالم world"
512       " مرحبا بالعالم שלום עולם hello world hello world\nبالعالم שלום )hello) world demo )עולם(\nשלום )مرحبا بالعالم עולם( )hello("
513     },
514     {
515       "Mix of bidirectional text. With more paragraphs. Update middle paragraphs.",
516       "Hello world demo\nhello world\nhello world (مرحبا بالعالم שלום) עולם\nשלום مرحبا بالعالم עולם (hello) مرحبا بالعالم world"
517       " مرحبا بالعالم שלום עולם hello world hello world\nبالعالم שלום (hello) world demo (עולם)\nשלום (مرحبا بالعالم עולם) (hello)",
518       29u,
519       38u,
520       "Hello world demo\nhello world\nhello world (مرحبا بالعالم שלום( עולם\nשלום مرحبا بالعالم עולם (hello) مرحبا بالعالم world"
521       " مرحبا بالعالم שלום עולם hello world hello world\nبالعالم שלום (hello) world demo (עולם)\nשלום (مرحبا بالعالم עולם) (hello)"
522     },
523     {
524       "Mix of bidirectional text. With more paragraphs. Update middle paragraphs (2).",
525       "Hello world demo\nhello world\nhello world (مرحبا بالعالم שלום) עולם\nשלום مرحبا بالعالم עולם (hello) مرحبا بالعالم world"
526       " مرحبا بالعالم שלום עולם hello world hello world\nبالعالم שלום (hello) world demo (עולם)\nשלום (مرحبا بالعالم עולם) (hello)",
527       67u,
528       100u,
529       "Hello world demo\nhello world\nhello world (مرحبا بالعالم שלום) עולם\nשלום مرحبا بالعالم עולם )hello( مرحبا بالعالم world"
530       " مرحبا بالعالم שלום עולם hello world hello world\nبالعالم שלום (hello) world demo (עולם)\nשלום (مرحبا بالعالم עולם) (hello)"
531     },
532   };
533   const unsigned int numberOfTests = 8u;
534
535   for( unsigned int index = 0u; index < numberOfTests; ++index )
536   {
537     ToolkitTestApplication application;
538     if( !GetMirroredTextTest( data[index] ) )
539     {
540       tet_result(TET_FAIL);
541     }
542   }
543
544   tet_result(TET_PASS);
545   END_TEST;
546 }
547
548 int UtcDaliGetCharactersDirection(void)
549 {
550   tet_infoline(" UtcDaliGetCharactersDirection");
551
552   bool directions01[] = {};
553   bool directions02[] = {
554     false, false, false, false, false, false, false, false, false, false,
555     false, false, false, false, false, false, false, false, false, false,
556     false, false, false, false, false, false, false, false };
557   bool directions03[] = {
558     true,  true,  true,  true,  true,  true,  true,  true,  true,  true,
559     true,  true,  true,  true,  true,  true,  true,  true,  true };
560   bool directions04[] = {
561     false, false, false, false, false, false, false, false, false, false,
562     false, false, false, false, false, false, false, false, false, false,
563     false, false, false, false, true,  true,  true,  true,  true,  true,
564     true,  true,  true,  false, true,  true,  true,  true,  true,  true,
565     true,  true,  true,  true,  false, false, false, false, false, false,
566     false, false, false, false, false };
567   bool directions05[] = {
568     false, false, false, false, false, false, false, false, false, false,
569     false, false, false, false, false, false, false, false, false, false,
570     false, false, false, false, false, false, false, false, false, false,
571     false, false, false, false, false, false, false, false, false, false,
572     false, true,  true,  true,  true,  true,  true,  true,  true,  true,
573     true,  true,  true,  true,  true,  true,  true,  true,  true,  true,
574     true,  true,  true,  true,  false, true,  true,  true,  true,  true,
575     true,  true,  true,  true,  true,  true,  true,  true,  true,  true,
576     true,  true,  true,  true,  true,  true,  true,  true,  true,  false,
577     false, false, false, false, true,  true,  true,  true,  true,  true,
578     true,  true,  true,  true,  true,  true,  true,  true,  true,  false,
579     false, false, false, false, true,  true,  true,  true,  true,  true,
580     true,  true,  true,  true,  true,  true,  true,  true,  true,  true,
581     true,  true,  true,  true,  true,  true,  true,  true,  true,  false,
582     false, false, false, false, false, false, false, false, false, false,
583     false, false, false, false, false, false, false, false, false, false,
584     false, false, true,  true,  true,  true,  true,  true,  true,  true,
585     true,  true,  true,  true,  true,  true,  false, false, false, false,
586     false, false, false, false, false, false, false, false, false, false,
587     false, false, true,  true,  true,  true,  true,  true,  true,  true,
588     true,  true,  true,  true,  true,  true,  true,  true,  true,  true,
589     true,  true,  true,  true,  true,  true,  true,  true,  true,  true,
590     true,  true,  false, false, false, false, false };
591
592     bool directions06[] = {
593     true,  true,  true,  true,  true,  true,  true,  true,  true, true,
594     false, false, false, false, false, false, false, false, false, false,
595     false, false, false, false, false, false };
596
597   struct GetCharactersDirectionData data[] =
598   {
599     {
600       "Zero characters",
601       "",
602       0u,
603       0u,
604       directions01,
605       false
606     },
607     {
608       "Left to right characters only",
609       "Hello world\nhello world demo",
610       0u,
611       28u,
612       directions02,
613       false
614     },
615     {
616       "Right to left characters only",
617       "שלום עולם\nשלום עולם",
618       0u,
619       19u,
620       directions03,
621       false
622     },
623     {
624       "Mix of bidirectional text",
625       "Hello world\nhello world שלום עולם\nשלום עולם hello world",
626       0u,
627       55u,
628       directions04,
629       false
630     },
631     {
632       "Mix of bidirectional text. With more paragraphs.",
633       "Hello world demo\nhello world\nhello world مرحبا بالعالم שלום עולם\nשלום مرحبا بالعالم עולם hello مرحبا بالعالم world"
634       " مرحبا بالعالم שלום עולם hello world hello world\nبالعالم שלום hello world demo עולם\nשלום مرحبا بالعالم עולם hello",
635       0u,
636       227u,
637       directions05,
638       false
639     },
640     {
641       "Mix of bidirectional text. With more paragraphs. Update first paragraph.",
642       "Hello world demo\nhello world\nhello world مرحبا بالعالم שלום עולם\nשלום مرحبا بالعالم עולם hello مرحبا بالعالم world"
643       " مرحبا بالعالم שלום עולם hello world hello world\nبالعالم שלום hello world demo עולם\nשלום مرحبا بالعالم עולם hello",
644       0u,
645       17u,
646       directions05,
647       false
648     },
649     {
650       "Mix of bidirectional text. With more paragraphs. Update from character 29",
651       "Hello world demo\nhello world\nhello world مرحبا بالعالم שלום עולם\nשלום مرحبا بالعالم עולם hello مرحبا بالعالم world"
652       " مرحبا بالعالم שלום עולם hello world hello world\nبالعالم שלום hello world demo עולם\nשלום مرحبا بالعالم עולם hello",
653       29u,
654       134u,
655       directions05,
656       false
657     },
658     {
659       "Mix of bidirectional text. With more paragraphs. Update from character 163",
660       "Hello world demo\nhello world\nhello world مرحبا بالعالم שלום עולם\nשלום مرحبا بالعالم עולם hello مرحبا بالعالم world"
661       " مرحبا بالعالم שלום עולם hello world hello world\nبالعالم שלום hello world demo עולם\nשלום مرحبا بالعالم עולם hello",
662       163u,
663       35u,
664       directions05,
665       false
666     },
667     {
668       "Mix of bidirectional text. With brackets and LRM",
669       "שלום עולם &lrm;(hello)[world]&lrm;",
670       0u,
671       26u,
672       directions06,
673       true
674     }
675   };
676   const unsigned int numberOfTests = 9u;
677
678   for( unsigned int index = 0u; index < numberOfTests; ++index )
679   {
680     ToolkitTestApplication application;
681     if( !GetCharactersDirectionTest( data[index] ) )
682     {
683       tet_result(TET_FAIL);
684     }
685   }
686
687   tet_result(TET_PASS);
688   END_TEST;
689 }