xref: /aosp_15_r20/frameworks/minikin/tests/unittest/LayoutSplitterTest.cpp (revision 834a2baab5fdfc28e9a428ee87c7ea8f6a06a53d)
1*834a2baaSAndroid Build Coastguard Worker /*
2*834a2baaSAndroid Build Coastguard Worker  * Copyright (C) 2018 The Android Open Source Project
3*834a2baaSAndroid Build Coastguard Worker  *
4*834a2baaSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*834a2baaSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*834a2baaSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*834a2baaSAndroid Build Coastguard Worker  *
8*834a2baaSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*834a2baaSAndroid Build Coastguard Worker  *
10*834a2baaSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*834a2baaSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*834a2baaSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*834a2baaSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*834a2baaSAndroid Build Coastguard Worker  * limitations under the License.
15*834a2baaSAndroid Build Coastguard Worker  */
16*834a2baaSAndroid Build Coastguard Worker 
17*834a2baaSAndroid Build Coastguard Worker #include <gtest/gtest.h>
18*834a2baaSAndroid Build Coastguard Worker 
19*834a2baaSAndroid Build Coastguard Worker #include "minikin/FontCollection.h"
20*834a2baaSAndroid Build Coastguard Worker #include "minikin/LayoutPieces.h"
21*834a2baaSAndroid Build Coastguard Worker 
22*834a2baaSAndroid Build Coastguard Worker #include "FontTestUtils.h"
23*834a2baaSAndroid Build Coastguard Worker #include "LayoutSplitter.h"
24*834a2baaSAndroid Build Coastguard Worker #include "UnicodeUtils.h"
25*834a2baaSAndroid Build Coastguard Worker 
26*834a2baaSAndroid Build Coastguard Worker namespace minikin {
27*834a2baaSAndroid Build Coastguard Worker namespace {
28*834a2baaSAndroid Build Coastguard Worker 
parseTestString(const std::string & text)29*834a2baaSAndroid Build Coastguard Worker std::pair<std::vector<uint16_t>, Range> parseTestString(const std::string& text) {
30*834a2baaSAndroid Build Coastguard Worker     auto utf16 = utf8ToUtf16(text);
31*834a2baaSAndroid Build Coastguard Worker     Range range;
32*834a2baaSAndroid Build Coastguard Worker     std::vector<uint16_t> outText;
33*834a2baaSAndroid Build Coastguard Worker     for (uint16_t c : utf16) {
34*834a2baaSAndroid Build Coastguard Worker         switch (c) {
35*834a2baaSAndroid Build Coastguard Worker             case '(':
36*834a2baaSAndroid Build Coastguard Worker                 range.setStart(outText.size());
37*834a2baaSAndroid Build Coastguard Worker                 break;
38*834a2baaSAndroid Build Coastguard Worker             case ')':
39*834a2baaSAndroid Build Coastguard Worker                 range.setEnd(outText.size());
40*834a2baaSAndroid Build Coastguard Worker                 break;
41*834a2baaSAndroid Build Coastguard Worker             default:
42*834a2baaSAndroid Build Coastguard Worker                 outText.push_back(c);
43*834a2baaSAndroid Build Coastguard Worker         }
44*834a2baaSAndroid Build Coastguard Worker     }
45*834a2baaSAndroid Build Coastguard Worker     return std::make_pair(outText, range);
46*834a2baaSAndroid Build Coastguard Worker }
47*834a2baaSAndroid Build Coastguard Worker 
parseExpectString(const std::string & text)48*834a2baaSAndroid Build Coastguard Worker std::pair<Range, Range> parseExpectString(const std::string& text) {
49*834a2baaSAndroid Build Coastguard Worker     auto utf16 = utf8ToUtf16(text);
50*834a2baaSAndroid Build Coastguard Worker     Range context;
51*834a2baaSAndroid Build Coastguard Worker     Range piece;
52*834a2baaSAndroid Build Coastguard Worker     uint32_t textPos = 0;
53*834a2baaSAndroid Build Coastguard Worker     for (uint16_t c : utf16) {
54*834a2baaSAndroid Build Coastguard Worker         switch (c) {
55*834a2baaSAndroid Build Coastguard Worker             case '[':
56*834a2baaSAndroid Build Coastguard Worker                 context.setStart(textPos);
57*834a2baaSAndroid Build Coastguard Worker                 break;
58*834a2baaSAndroid Build Coastguard Worker             case ']':
59*834a2baaSAndroid Build Coastguard Worker                 context.setEnd(textPos);
60*834a2baaSAndroid Build Coastguard Worker                 break;
61*834a2baaSAndroid Build Coastguard Worker             case '(':
62*834a2baaSAndroid Build Coastguard Worker                 piece.setStart(textPos);
63*834a2baaSAndroid Build Coastguard Worker                 break;
64*834a2baaSAndroid Build Coastguard Worker             case ')':
65*834a2baaSAndroid Build Coastguard Worker                 piece.setEnd(textPos);
66*834a2baaSAndroid Build Coastguard Worker                 break;
67*834a2baaSAndroid Build Coastguard Worker             default:
68*834a2baaSAndroid Build Coastguard Worker                 textPos++;
69*834a2baaSAndroid Build Coastguard Worker         }
70*834a2baaSAndroid Build Coastguard Worker     }
71*834a2baaSAndroid Build Coastguard Worker     return std::make_pair(context, piece);
72*834a2baaSAndroid Build Coastguard Worker }
73*834a2baaSAndroid Build Coastguard Worker 
buildDebugString(const U16StringPiece & textBuf,const Range & context,const Range & piece)74*834a2baaSAndroid Build Coastguard Worker std::string buildDebugString(const U16StringPiece& textBuf, const Range& context,
75*834a2baaSAndroid Build Coastguard Worker                              const Range& piece) {
76*834a2baaSAndroid Build Coastguard Worker     std::vector<uint16_t> out;
77*834a2baaSAndroid Build Coastguard Worker     out.reserve(textBuf.size() + 4);
78*834a2baaSAndroid Build Coastguard Worker     for (uint32_t i = 0; i < textBuf.size() + 1; ++i) {
79*834a2baaSAndroid Build Coastguard Worker         if (i == context.getStart()) {
80*834a2baaSAndroid Build Coastguard Worker             out.push_back('[');
81*834a2baaSAndroid Build Coastguard Worker         }
82*834a2baaSAndroid Build Coastguard Worker         if (i == piece.getStart()) {
83*834a2baaSAndroid Build Coastguard Worker             out.push_back('(');
84*834a2baaSAndroid Build Coastguard Worker         }
85*834a2baaSAndroid Build Coastguard Worker         if (i == piece.getEnd()) {
86*834a2baaSAndroid Build Coastguard Worker             out.push_back(')');
87*834a2baaSAndroid Build Coastguard Worker         }
88*834a2baaSAndroid Build Coastguard Worker         if (i == context.getEnd()) {
89*834a2baaSAndroid Build Coastguard Worker             out.push_back(']');
90*834a2baaSAndroid Build Coastguard Worker         }
91*834a2baaSAndroid Build Coastguard Worker         if (i != textBuf.size()) {
92*834a2baaSAndroid Build Coastguard Worker             out.push_back(textBuf[i]);
93*834a2baaSAndroid Build Coastguard Worker         }
94*834a2baaSAndroid Build Coastguard Worker     }
95*834a2baaSAndroid Build Coastguard Worker     return utf16ToUtf8(out);
96*834a2baaSAndroid Build Coastguard Worker }
97*834a2baaSAndroid Build Coastguard Worker 
TEST(LayoutSplitterTest,LTR_Latin)98*834a2baaSAndroid Build Coastguard Worker TEST(LayoutSplitterTest, LTR_Latin) {
99*834a2baaSAndroid Build Coastguard Worker     struct TestCase {
100*834a2baaSAndroid Build Coastguard Worker         std::string testStr;
101*834a2baaSAndroid Build Coastguard Worker         std::vector<std::string> expects;
102*834a2baaSAndroid Build Coastguard Worker     } testCases[] = {
103*834a2baaSAndroid Build Coastguard Worker             {"(This is an example text.)",
104*834a2baaSAndroid Build Coastguard Worker              {
105*834a2baaSAndroid Build Coastguard Worker                      "[(This)] is an example text.", "This[( )]is an example text.",
106*834a2baaSAndroid Build Coastguard Worker                      "This [(is)] an example text.", "This is[( )]an example text.",
107*834a2baaSAndroid Build Coastguard Worker                      "This is [(an)] example text.", "This is an[( )]example text.",
108*834a2baaSAndroid Build Coastguard Worker                      "This is an [(example)] text.", "This is an example[( )]text.",
109*834a2baaSAndroid Build Coastguard Worker                      "This is an example [(text.)]",
110*834a2baaSAndroid Build Coastguard Worker              }},
111*834a2baaSAndroid Build Coastguard Worker             {"This( is an example )text.",
112*834a2baaSAndroid Build Coastguard Worker              {
113*834a2baaSAndroid Build Coastguard Worker                      "This[( )]is an example text.", "This [(is)] an example text.",
114*834a2baaSAndroid Build Coastguard Worker                      "This is[( )]an example text.", "This is [(an)] example text.",
115*834a2baaSAndroid Build Coastguard Worker                      "This is an[( )]example text.", "This is an [(example)] text.",
116*834a2baaSAndroid Build Coastguard Worker                      "This is an example[( )]text.",
117*834a2baaSAndroid Build Coastguard Worker              }},
118*834a2baaSAndroid Build Coastguard Worker             {"This (is an example) text.",
119*834a2baaSAndroid Build Coastguard Worker              {
120*834a2baaSAndroid Build Coastguard Worker                      "This [(is)] an example text.", "This is[( )]an example text.",
121*834a2baaSAndroid Build Coastguard Worker                      "This is [(an)] example text.", "This is an[( )]example text.",
122*834a2baaSAndroid Build Coastguard Worker                      "This is an [(example)] text.",
123*834a2baaSAndroid Build Coastguard Worker              }},
124*834a2baaSAndroid Build Coastguard Worker             {"Th(is is an example te)xt.",
125*834a2baaSAndroid Build Coastguard Worker              {
126*834a2baaSAndroid Build Coastguard Worker                      "[Th(is)] is an example text.", "This[( )]is an example text.",
127*834a2baaSAndroid Build Coastguard Worker                      "This [(is)] an example text.", "This is[( )]an example text.",
128*834a2baaSAndroid Build Coastguard Worker                      "This is [(an)] example text.", "This is an[( )]example text.",
129*834a2baaSAndroid Build Coastguard Worker                      "This is an [(example)] text.", "This is an example[( )]text.",
130*834a2baaSAndroid Build Coastguard Worker                      "This is an example [(te)xt.]",
131*834a2baaSAndroid Build Coastguard Worker              }},
132*834a2baaSAndroid Build Coastguard Worker             {"This is an ex(amp)le text.",
133*834a2baaSAndroid Build Coastguard Worker              {
134*834a2baaSAndroid Build Coastguard Worker                      "This is an [ex(amp)le] text.",
135*834a2baaSAndroid Build Coastguard Worker              }},
136*834a2baaSAndroid Build Coastguard Worker             {"There are (three   spaces.)",
137*834a2baaSAndroid Build Coastguard Worker              {
138*834a2baaSAndroid Build Coastguard Worker                      "There are [(three)]   spaces.", "There are three[( )]  spaces.",
139*834a2baaSAndroid Build Coastguard Worker                      "There are three [( )] spaces.", "There are three  [( )]spaces.",
140*834a2baaSAndroid Build Coastguard Worker                      "There are three   [(spaces.)]",
141*834a2baaSAndroid Build Coastguard Worker              }},
142*834a2baaSAndroid Build Coastguard Worker     };
143*834a2baaSAndroid Build Coastguard Worker 
144*834a2baaSAndroid Build Coastguard Worker     for (const auto& testCase : testCases) {
145*834a2baaSAndroid Build Coastguard Worker         auto[text, range] = parseTestString(testCase.testStr);
146*834a2baaSAndroid Build Coastguard Worker         uint32_t expectationIndex = 0;
147*834a2baaSAndroid Build Coastguard Worker         for (auto[acContext, acPiece] : LayoutSplitter(text, range, false /* isRtl */)) {
148*834a2baaSAndroid Build Coastguard Worker             ASSERT_NE(expectationIndex, testCase.expects.size());
149*834a2baaSAndroid Build Coastguard Worker             const std::string expectString = testCase.expects[expectationIndex++];
150*834a2baaSAndroid Build Coastguard Worker             auto[exContext, exPiece] = parseExpectString(expectString);
151*834a2baaSAndroid Build Coastguard Worker             EXPECT_EQ(acContext, exContext)
152*834a2baaSAndroid Build Coastguard Worker                     << expectString << " vs " << buildDebugString(text, acContext, acPiece);
153*834a2baaSAndroid Build Coastguard Worker             EXPECT_EQ(acPiece, exPiece)
154*834a2baaSAndroid Build Coastguard Worker                     << expectString << " vs " << buildDebugString(text, acContext, acPiece);
155*834a2baaSAndroid Build Coastguard Worker         }
156*834a2baaSAndroid Build Coastguard Worker         EXPECT_EQ(expectationIndex, testCase.expects.size()) << "Expectations Remains";
157*834a2baaSAndroid Build Coastguard Worker     }
158*834a2baaSAndroid Build Coastguard Worker }
159*834a2baaSAndroid Build Coastguard Worker 
TEST(LayoutSplitterTest,RTL_Latin)160*834a2baaSAndroid Build Coastguard Worker TEST(LayoutSplitterTest, RTL_Latin) {
161*834a2baaSAndroid Build Coastguard Worker     struct TestCase {
162*834a2baaSAndroid Build Coastguard Worker         std::string testStr;
163*834a2baaSAndroid Build Coastguard Worker         std::vector<std::string> expects;
164*834a2baaSAndroid Build Coastguard Worker     } testCases[] = {
165*834a2baaSAndroid Build Coastguard Worker             {"(This is an example text.)",
166*834a2baaSAndroid Build Coastguard Worker              {
167*834a2baaSAndroid Build Coastguard Worker                      "This is an example [(text.)]", "This is an example[( )]text.",
168*834a2baaSAndroid Build Coastguard Worker                      "This is an [(example)] text.", "This is an[( )]example text.",
169*834a2baaSAndroid Build Coastguard Worker                      "This is [(an)] example text.", "This is[( )]an example text.",
170*834a2baaSAndroid Build Coastguard Worker                      "This [(is)] an example text.", "This[( )]is an example text.",
171*834a2baaSAndroid Build Coastguard Worker                      "[(This)] is an example text.",
172*834a2baaSAndroid Build Coastguard Worker              }},
173*834a2baaSAndroid Build Coastguard Worker             {"This( is an example )text.",
174*834a2baaSAndroid Build Coastguard Worker              {
175*834a2baaSAndroid Build Coastguard Worker                      "This is an example[( )]text.", "This is an [(example)] text.",
176*834a2baaSAndroid Build Coastguard Worker                      "This is an[( )]example text.", "This is [(an)] example text.",
177*834a2baaSAndroid Build Coastguard Worker                      "This is[( )]an example text.", "This [(is)] an example text.",
178*834a2baaSAndroid Build Coastguard Worker                      "This[( )]is an example text.",
179*834a2baaSAndroid Build Coastguard Worker              }},
180*834a2baaSAndroid Build Coastguard Worker             {"This (is an example) text.",
181*834a2baaSAndroid Build Coastguard Worker              {
182*834a2baaSAndroid Build Coastguard Worker                      "This is an [(example)] text.", "This is an[( )]example text.",
183*834a2baaSAndroid Build Coastguard Worker                      "This is [(an)] example text.", "This is[( )]an example text.",
184*834a2baaSAndroid Build Coastguard Worker                      "This [(is)] an example text.",
185*834a2baaSAndroid Build Coastguard Worker              }},
186*834a2baaSAndroid Build Coastguard Worker             {"Th(is is an example te)xt.",
187*834a2baaSAndroid Build Coastguard Worker              {
188*834a2baaSAndroid Build Coastguard Worker                      "This is an example [(te)xt.]", "This is an example[( )]text.",
189*834a2baaSAndroid Build Coastguard Worker                      "This is an [(example)] text.", "This is an[( )]example text.",
190*834a2baaSAndroid Build Coastguard Worker                      "This is [(an)] example text.", "This is[( )]an example text.",
191*834a2baaSAndroid Build Coastguard Worker                      "This [(is)] an example text.", "This[( )]is an example text.",
192*834a2baaSAndroid Build Coastguard Worker                      "[Th(is)] is an example text.",
193*834a2baaSAndroid Build Coastguard Worker              }},
194*834a2baaSAndroid Build Coastguard Worker             {"This is an ex(amp)le text.",
195*834a2baaSAndroid Build Coastguard Worker              {
196*834a2baaSAndroid Build Coastguard Worker                      "This is an [ex(amp)le] text.",
197*834a2baaSAndroid Build Coastguard Worker              }},
198*834a2baaSAndroid Build Coastguard Worker             {"There are (three   spaces.)",
199*834a2baaSAndroid Build Coastguard Worker              {
200*834a2baaSAndroid Build Coastguard Worker                      "There are three   [(spaces.)]", "There are three  [( )]spaces.",
201*834a2baaSAndroid Build Coastguard Worker                      "There are three [( )] spaces.", "There are three[( )]  spaces.",
202*834a2baaSAndroid Build Coastguard Worker                      "There are [(three)]   spaces.",
203*834a2baaSAndroid Build Coastguard Worker              }},
204*834a2baaSAndroid Build Coastguard Worker     };
205*834a2baaSAndroid Build Coastguard Worker 
206*834a2baaSAndroid Build Coastguard Worker     for (const auto& testCase : testCases) {
207*834a2baaSAndroid Build Coastguard Worker         auto[text, range] = parseTestString(testCase.testStr);
208*834a2baaSAndroid Build Coastguard Worker         uint32_t expectationIndex = 0;
209*834a2baaSAndroid Build Coastguard Worker         for (auto[acContext, acPiece] : LayoutSplitter(text, range, true /* isRtl */)) {
210*834a2baaSAndroid Build Coastguard Worker             ASSERT_NE(expectationIndex, testCase.expects.size());
211*834a2baaSAndroid Build Coastguard Worker             const std::string expectString = testCase.expects[expectationIndex++];
212*834a2baaSAndroid Build Coastguard Worker             auto[exContext, exPiece] = parseExpectString(expectString);
213*834a2baaSAndroid Build Coastguard Worker             EXPECT_EQ(acContext, exContext)
214*834a2baaSAndroid Build Coastguard Worker                     << expectString << " vs " << buildDebugString(text, acContext, acPiece);
215*834a2baaSAndroid Build Coastguard Worker             EXPECT_EQ(acPiece, exPiece)
216*834a2baaSAndroid Build Coastguard Worker                     << expectString << " vs " << buildDebugString(text, acContext, acPiece);
217*834a2baaSAndroid Build Coastguard Worker         }
218*834a2baaSAndroid Build Coastguard Worker         EXPECT_EQ(expectationIndex, testCase.expects.size()) << "Expectations Remains";
219*834a2baaSAndroid Build Coastguard Worker     }
220*834a2baaSAndroid Build Coastguard Worker }
221*834a2baaSAndroid Build Coastguard Worker 
TEST(LayoutSplitterTest,LTR_CJK)222*834a2baaSAndroid Build Coastguard Worker TEST(LayoutSplitterTest, LTR_CJK) {
223*834a2baaSAndroid Build Coastguard Worker     struct TestCase {
224*834a2baaSAndroid Build Coastguard Worker         std::string testStr;
225*834a2baaSAndroid Build Coastguard Worker         std::vector<std::string> expects;
226*834a2baaSAndroid Build Coastguard Worker     } testCases[] = {
227*834a2baaSAndroid Build Coastguard Worker             {// All Kanji text
228*834a2baaSAndroid Build Coastguard Worker              "(\u6614\u8005\u8358\u5468\u5922\u70BA\u80E1\u8776)",
229*834a2baaSAndroid Build Coastguard Worker              {
230*834a2baaSAndroid Build Coastguard Worker                      "[(\u6614)]\u8005\u8358\u5468\u5922\u70BA\u80E1\u8776",
231*834a2baaSAndroid Build Coastguard Worker                      "\u6614[(\u8005)]\u8358\u5468\u5922\u70BA\u80E1\u8776",
232*834a2baaSAndroid Build Coastguard Worker                      "\u6614\u8005[(\u8358)]\u5468\u5922\u70BA\u80E1\u8776",
233*834a2baaSAndroid Build Coastguard Worker                      "\u6614\u8005\u8358[(\u5468)]\u5922\u70BA\u80E1\u8776",
234*834a2baaSAndroid Build Coastguard Worker                      "\u6614\u8005\u8358\u5468[(\u5922)]\u70BA\u80E1\u8776",
235*834a2baaSAndroid Build Coastguard Worker                      "\u6614\u8005\u8358\u5468\u5922[(\u70BA)]\u80E1\u8776",
236*834a2baaSAndroid Build Coastguard Worker                      "\u6614\u8005\u8358\u5468\u5922\u70BA[(\u80E1)]\u8776",
237*834a2baaSAndroid Build Coastguard Worker                      "\u6614\u8005\u8358\u5468\u5922\u70BA\u80E1[(\u8776)]",
238*834a2baaSAndroid Build Coastguard Worker              }},
239*834a2baaSAndroid Build Coastguard Worker             {// Japanese text like as follows
240*834a2baaSAndroid Build Coastguard Worker              // [Kanji][Kanji][Kana][Kanji][Kanji][Kana][Kana][Kana]
241*834a2baaSAndroid Build Coastguard Worker              "(\u672C\u65E5\u306F\u6674\u5929\u306A\u308A\u3002)",
242*834a2baaSAndroid Build Coastguard Worker              {
243*834a2baaSAndroid Build Coastguard Worker                      "[(\u672C)]\u65E5\u306F\u6674\u5929\u306A\u308A\u3002",
244*834a2baaSAndroid Build Coastguard Worker                      "\u672C[(\u65E5\u306F)]\u6674\u5929\u306A\u308A\u3002",
245*834a2baaSAndroid Build Coastguard Worker                      "\u672C\u65E5\u306F[(\u6674)]\u5929\u306A\u308A\u3002",
246*834a2baaSAndroid Build Coastguard Worker                      "\u672C\u65E5\u306F\u6674[(\u5929\u306A\u308A\u3002)]",
247*834a2baaSAndroid Build Coastguard Worker              }},
248*834a2baaSAndroid Build Coastguard Worker             {// Japanese text like as follows
249*834a2baaSAndroid Build Coastguard Worker              // [Kanji][Kanji][Kana][Kanji][Kanji][Kana][Kana][Kana]
250*834a2baaSAndroid Build Coastguard Worker              "\u672C\u65E5(\u306F\u6674\u5929\u306A)\u308A\u3002",
251*834a2baaSAndroid Build Coastguard Worker              {
252*834a2baaSAndroid Build Coastguard Worker                      "\u672C[\u65E5(\u306F)]\u6674\u5929\u306A\u308A\u3002",
253*834a2baaSAndroid Build Coastguard Worker                      "\u672C\u65E5\u306F[(\u6674)]\u5929\u306A\u308A\u3002",
254*834a2baaSAndroid Build Coastguard Worker                      "\u672C\u65E5\u306F\u6674[(\u5929\u306A)\u308A\u3002]",
255*834a2baaSAndroid Build Coastguard Worker              }},
256*834a2baaSAndroid Build Coastguard Worker     };
257*834a2baaSAndroid Build Coastguard Worker 
258*834a2baaSAndroid Build Coastguard Worker     for (const auto& testCase : testCases) {
259*834a2baaSAndroid Build Coastguard Worker         auto[text, range] = parseTestString(testCase.testStr);
260*834a2baaSAndroid Build Coastguard Worker         uint32_t expectationIndex = 0;
261*834a2baaSAndroid Build Coastguard Worker         for (auto[acContext, acPiece] : LayoutSplitter(text, range, false /* isRtl */)) {
262*834a2baaSAndroid Build Coastguard Worker             ASSERT_NE(expectationIndex, testCase.expects.size());
263*834a2baaSAndroid Build Coastguard Worker             const std::string expectString = testCase.expects[expectationIndex++];
264*834a2baaSAndroid Build Coastguard Worker             auto[exContext, exPiece] = parseExpectString(expectString);
265*834a2baaSAndroid Build Coastguard Worker             EXPECT_EQ(acContext, exContext)
266*834a2baaSAndroid Build Coastguard Worker                     << expectString << " vs " << buildDebugString(text, acContext, acPiece);
267*834a2baaSAndroid Build Coastguard Worker             EXPECT_EQ(acPiece, exPiece)
268*834a2baaSAndroid Build Coastguard Worker                     << expectString << " vs " << buildDebugString(text, acContext, acPiece);
269*834a2baaSAndroid Build Coastguard Worker         }
270*834a2baaSAndroid Build Coastguard Worker         EXPECT_EQ(expectationIndex, testCase.expects.size()) << "Expectations Remains";
271*834a2baaSAndroid Build Coastguard Worker     }
272*834a2baaSAndroid Build Coastguard Worker }
273*834a2baaSAndroid Build Coastguard Worker 
TEST(LayoutSplitterTest,RTL_CJK)274*834a2baaSAndroid Build Coastguard Worker TEST(LayoutSplitterTest, RTL_CJK) {
275*834a2baaSAndroid Build Coastguard Worker     struct TestCase {
276*834a2baaSAndroid Build Coastguard Worker         std::string testStr;
277*834a2baaSAndroid Build Coastguard Worker         std::vector<std::string> expects;
278*834a2baaSAndroid Build Coastguard Worker     } testCases[] = {
279*834a2baaSAndroid Build Coastguard Worker             {// All Kanji text
280*834a2baaSAndroid Build Coastguard Worker              "(\u6614\u8005\u8358\u5468\u5922\u70BA\u80E1\u8776)",
281*834a2baaSAndroid Build Coastguard Worker              {
282*834a2baaSAndroid Build Coastguard Worker                      "\u6614\u8005\u8358\u5468\u5922\u70BA\u80E1[(\u8776)]",
283*834a2baaSAndroid Build Coastguard Worker                      "\u6614\u8005\u8358\u5468\u5922\u70BA[(\u80E1)]\u8776",
284*834a2baaSAndroid Build Coastguard Worker                      "\u6614\u8005\u8358\u5468\u5922[(\u70BA)]\u80E1\u8776",
285*834a2baaSAndroid Build Coastguard Worker                      "\u6614\u8005\u8358\u5468[(\u5922)]\u70BA\u80E1\u8776",
286*834a2baaSAndroid Build Coastguard Worker                      "\u6614\u8005\u8358[(\u5468)]\u5922\u70BA\u80E1\u8776",
287*834a2baaSAndroid Build Coastguard Worker                      "\u6614\u8005[(\u8358)]\u5468\u5922\u70BA\u80E1\u8776",
288*834a2baaSAndroid Build Coastguard Worker                      "\u6614[(\u8005)]\u8358\u5468\u5922\u70BA\u80E1\u8776",
289*834a2baaSAndroid Build Coastguard Worker                      "[(\u6614)]\u8005\u8358\u5468\u5922\u70BA\u80E1\u8776",
290*834a2baaSAndroid Build Coastguard Worker              }},
291*834a2baaSAndroid Build Coastguard Worker             {// Japanese text like as follows
292*834a2baaSAndroid Build Coastguard Worker              // [Kanji][Kanji][Kana][Kanji][Kanji][Kana][Kana][Kana]
293*834a2baaSAndroid Build Coastguard Worker              "(\u672C\u65E5\u306F\u6674\u5929\u306A\u308A\u3002)",
294*834a2baaSAndroid Build Coastguard Worker              {
295*834a2baaSAndroid Build Coastguard Worker                      "\u672C\u65E5\u306F\u6674[(\u5929\u306A\u308A\u3002)]",
296*834a2baaSAndroid Build Coastguard Worker                      "\u672C\u65E5\u306F[(\u6674)]\u5929\u306A\u308A\u3002",
297*834a2baaSAndroid Build Coastguard Worker                      "\u672C[(\u65E5\u306F)]\u6674\u5929\u306A\u308A\u3002",
298*834a2baaSAndroid Build Coastguard Worker                      "[(\u672C)]\u65E5\u306F\u6674\u5929\u306A\u308A\u3002",
299*834a2baaSAndroid Build Coastguard Worker              }},
300*834a2baaSAndroid Build Coastguard Worker             {// Japanese text like as follows
301*834a2baaSAndroid Build Coastguard Worker              // [Kanji][Kanji][Kana][Kanji][Kanji][Kana][Kana][Kana]
302*834a2baaSAndroid Build Coastguard Worker              "\u672C\u65E5(\u306F\u6674\u5929\u306A)\u308A\u3002",
303*834a2baaSAndroid Build Coastguard Worker              {
304*834a2baaSAndroid Build Coastguard Worker                      "\u672C\u65E5\u306F\u6674[(\u5929\u306A)\u308A\u3002]",
305*834a2baaSAndroid Build Coastguard Worker                      "\u672C\u65E5\u306F[(\u6674)]\u5929\u306A\u308A\u3002",
306*834a2baaSAndroid Build Coastguard Worker                      "\u672C[\u65E5(\u306F)]\u6674\u5929\u306A\u308A\u3002",
307*834a2baaSAndroid Build Coastguard Worker              }},
308*834a2baaSAndroid Build Coastguard Worker     };
309*834a2baaSAndroid Build Coastguard Worker 
310*834a2baaSAndroid Build Coastguard Worker     for (const auto& testCase : testCases) {
311*834a2baaSAndroid Build Coastguard Worker         auto[text, range] = parseTestString(testCase.testStr);
312*834a2baaSAndroid Build Coastguard Worker         uint32_t expectationIndex = 0;
313*834a2baaSAndroid Build Coastguard Worker         for (auto[acContext, acPiece] : LayoutSplitter(text, range, true /* isRtl */)) {
314*834a2baaSAndroid Build Coastguard Worker             ASSERT_NE(expectationIndex, testCase.expects.size());
315*834a2baaSAndroid Build Coastguard Worker             const std::string expectString = testCase.expects[expectationIndex++];
316*834a2baaSAndroid Build Coastguard Worker             auto[exContext, exPiece] = parseExpectString(expectString);
317*834a2baaSAndroid Build Coastguard Worker             EXPECT_EQ(acContext, exContext)
318*834a2baaSAndroid Build Coastguard Worker                     << expectString << " vs " << buildDebugString(text, acContext, acPiece);
319*834a2baaSAndroid Build Coastguard Worker             EXPECT_EQ(acPiece, exPiece)
320*834a2baaSAndroid Build Coastguard Worker                     << expectString << " vs " << buildDebugString(text, acContext, acPiece);
321*834a2baaSAndroid Build Coastguard Worker         }
322*834a2baaSAndroid Build Coastguard Worker         EXPECT_EQ(expectationIndex, testCase.expects.size()) << "Expectations Remains";
323*834a2baaSAndroid Build Coastguard Worker     }
324*834a2baaSAndroid Build Coastguard Worker }
325*834a2baaSAndroid Build Coastguard Worker 
TEST(LayoutSplitterTest,BidiCtrl)326*834a2baaSAndroid Build Coastguard Worker TEST(LayoutSplitterTest, BidiCtrl) {
327*834a2baaSAndroid Build Coastguard Worker     struct TestCase {
328*834a2baaSAndroid Build Coastguard Worker         std::string testStr;
329*834a2baaSAndroid Build Coastguard Worker         std::vector<std::string> expects;
330*834a2baaSAndroid Build Coastguard Worker     } testCases[] = {
331*834a2baaSAndroid Build Coastguard Worker             {// Repeated Bidi sequence
332*834a2baaSAndroid Build Coastguard Worker              "(a\u2066\u2069\u202A\u202E\u200E\u200Fb)",
333*834a2baaSAndroid Build Coastguard Worker              {
334*834a2baaSAndroid Build Coastguard Worker                      "[(a)]\u2066\u2069\u202A\u202E\u200E\u200Fb",
335*834a2baaSAndroid Build Coastguard Worker                      "a[(\u2066)]\u2069\u202A\u202E\u200E\u200Fb",
336*834a2baaSAndroid Build Coastguard Worker                      "a\u2066[(\u2069)]\u202A\u202E\u200E\u200Fb",
337*834a2baaSAndroid Build Coastguard Worker                      "a\u2066\u2069[(\u202A)]\u202E\u200E\u200Fb",
338*834a2baaSAndroid Build Coastguard Worker                      "a\u2066\u2069\u202A[(\u202E)]\u200E\u200Fb",
339*834a2baaSAndroid Build Coastguard Worker                      "a\u2066\u2069\u202A\u202E[(\u200E)]\u200Fb",
340*834a2baaSAndroid Build Coastguard Worker                      "a\u2066\u2069\u202A\u202E\u200E[(\u200F)]b",
341*834a2baaSAndroid Build Coastguard Worker                      "a\u2066\u2069\u202A\u202E\u200E\u200F[(b)]",
342*834a2baaSAndroid Build Coastguard Worker              }},
343*834a2baaSAndroid Build Coastguard Worker     };
344*834a2baaSAndroid Build Coastguard Worker 
345*834a2baaSAndroid Build Coastguard Worker     for (const auto& testCase : testCases) {
346*834a2baaSAndroid Build Coastguard Worker         auto [text, range] = parseTestString(testCase.testStr);
347*834a2baaSAndroid Build Coastguard Worker         uint32_t expectationIndex = 0;
348*834a2baaSAndroid Build Coastguard Worker         for (auto [acContext, acPiece] : LayoutSplitter(text, range, false /* isRtl */)) {
349*834a2baaSAndroid Build Coastguard Worker             ASSERT_NE(expectationIndex, testCase.expects.size());
350*834a2baaSAndroid Build Coastguard Worker             const std::string expectString = testCase.expects[expectationIndex++];
351*834a2baaSAndroid Build Coastguard Worker             auto [exContext, exPiece] = parseExpectString(expectString);
352*834a2baaSAndroid Build Coastguard Worker             EXPECT_EQ(acContext, exContext)
353*834a2baaSAndroid Build Coastguard Worker                     << expectString << " vs " << buildDebugString(text, acContext, acPiece);
354*834a2baaSAndroid Build Coastguard Worker             EXPECT_EQ(acPiece, exPiece)
355*834a2baaSAndroid Build Coastguard Worker                     << expectString << " vs " << buildDebugString(text, acContext, acPiece);
356*834a2baaSAndroid Build Coastguard Worker         }
357*834a2baaSAndroid Build Coastguard Worker         EXPECT_EQ(expectationIndex, testCase.expects.size()) << "Expectations Remains";
358*834a2baaSAndroid Build Coastguard Worker     }
359*834a2baaSAndroid Build Coastguard Worker }
360*834a2baaSAndroid Build Coastguard Worker 
361*834a2baaSAndroid Build Coastguard Worker }  // namespace
362*834a2baaSAndroid Build Coastguard Worker }  // namespace minikin
363