1 /*
2 * Copyright (c) 2025 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <gtest/gtest.h>
17
18 #include "drawing_font_collection.h"
19 #include "drawing_text_typography.h"
20
21 using namespace testing;
22 using namespace testing::ext;
23
24 namespace OHOS {
25 namespace Rosen {
26 class NdkAddTextTest : public testing::Test {};
27
GetUnresolvedGlyphCount(const void * text,size_t length,OH_Drawing_TextEncoding encode)28 static int32_t GetUnresolvedGlyphCount(const void* text, size_t length, OH_Drawing_TextEncoding encode)
29 {
30 auto typoStyle = OH_Drawing_CreateTypographyStyle();
31 EXPECT_NE(typoStyle, nullptr);
32 auto handler = OH_Drawing_CreateTypographyHandler(typoStyle, OH_Drawing_GetFontCollectionGlobalInstance());
33 EXPECT_NE(handler, nullptr);
34 OH_Drawing_TypographyHandlerAddEncodedText(handler, text, length, encode);
35 auto typography = OH_Drawing_CreateTypography(handler);
36 EXPECT_NE(typography, nullptr);
37 OH_Drawing_TypographyLayout(typography, 100.0f);
38 int32_t unresolved = OH_Drawing_TypographyGetUnresolvedGlyphsCount(typography);
39 OH_Drawing_DestroyTypography(typography);
40 OH_Drawing_DestroyTypographyHandler(handler);
41 OH_Drawing_DestroyTypographyStyle(typoStyle);
42 return unresolved;
43 }
44 /**
45 * @tc.name: AddValidUTF8TextTest
46 * @tc.desc: Test valid UTF-8 text input scenarios
47 * @tc.type: FUNC
48 */
49 HWTEST_F(NdkAddTextTest, AddValidUTF8TextTest, TestSize.Level0)
50 {
51 // Basic ASCII characters
52 const char ascii[] = u8"Hello World";
53 EXPECT_EQ(GetUnresolvedGlyphCount(ascii, sizeof(ascii), TEXT_ENCODING_UTF8), 0);
54
55 // Non-ASCII characters (Chinese)
56 const char chinese[] = u8"你好世界";
57 EXPECT_EQ(GetUnresolvedGlyphCount(chinese, sizeof(chinese), TEXT_ENCODING_UTF8), 0);
58
59 // Special characters
60 const char tabsNewline[] = u8"Tabs\tNewline\n";
61 EXPECT_EQ(GetUnresolvedGlyphCount(tabsNewline, sizeof(tabsNewline), TEXT_ENCODING_UTF8), 0);
62
63 // 4-byte emoji characters
64 const char emoji[] = u8"";
65 EXPECT_EQ(GetUnresolvedGlyphCount(emoji, sizeof(emoji), TEXT_ENCODING_UTF8), 0);
66
67 // Mixed case and symbols
68 const char mixedCaseSymbols[] = u8"Aa1!Ωπ";
69 EXPECT_EQ(GetUnresolvedGlyphCount(mixedCaseSymbols, sizeof(mixedCaseSymbols), TEXT_ENCODING_UTF8), 0);
70 }
71
72 /**
73 * @tc.name: AddInvalidUTF8TextTest
74 * @tc.desc: Test invalid UTF-8 text input scenarios
75 * @tc.type: FUNC
76 */
77 HWTEST_F(NdkAddTextTest, AddInvalidUTF8TextTest, TestSize.Level0)
78 {
79 // Invalid continuation bytes
80 const char invalid1[] = "abc\x80\xff";
81 EXPECT_EQ(GetUnresolvedGlyphCount(invalid1, sizeof(invalid1), TEXT_ENCODING_UTF8), 0);
82
83 // Truncated multi-byte sequence
84 const char invalid2[] = u8"正常\xE6\x97继续";
85 EXPECT_EQ(GetUnresolvedGlyphCount(invalid2, sizeof(invalid2), TEXT_ENCODING_UTF8), 0);
86
87 // Overlong encoding
88 const char invalid3[] = "\xF0\x82\x82\xAC"; // Overlong € symbol
89 EXPECT_EQ(GetUnresolvedGlyphCount(invalid3, sizeof(invalid3), TEXT_ENCODING_UTF8), 0);
90 }
91
92 /**
93 * @tc.name: AddValidUTF16TextTest
94 * @tc.desc: Test valid UTF-16 text input scenarios
95 * @tc.type: FUNC
96 */
97 HWTEST_F(NdkAddTextTest, AddValidUTF16TextTest, TestSize.Level0)
98 {
99 // Basic BMP characters
100 const char16_t ascii16[] = u"Hello World";
101 EXPECT_EQ(GetUnresolvedGlyphCount(ascii16, sizeof(ascii16), TEXT_ENCODING_UTF16), 0);
102
103 // Non-BMP characters (emoji)
104 const char16_t emoji16[] = u"";
105 EXPECT_EQ(GetUnresolvedGlyphCount(emoji16, sizeof(emoji16), TEXT_ENCODING_UTF16), 0); //
106
107 // RTL text with control characters
108 const char16_t rtlText16[] = u"\x202E右到左文本";
109 EXPECT_EQ(GetUnresolvedGlyphCount(rtlText16, sizeof(rtlText16), TEXT_ENCODING_UTF16), 0);
110
111 // Combining characters
112 const char16_t combiningChars16[] = u"A\u0300\u0301";
113 EXPECT_EQ(GetUnresolvedGlyphCount(combiningChars16, sizeof(combiningChars16), TEXT_ENCODING_UTF16), 0); // À́
114 }
115
116 /**
117 * @tc.name: AddInvalidUTF16TextTest
118 * @tc.desc: Test invalid UTF-16 text input scenarios
119 * @tc.type: FUNC
120 */
121 HWTEST_F(NdkAddTextTest, AddInvalidUTF16TextTest, TestSize.Level0)
122 {
123 // Unpaired high surrogate
124 const char16_t invalid1[] = u"\xD800\x0041";
125 EXPECT_EQ(GetUnresolvedGlyphCount(invalid1, sizeof(invalid1), TEXT_ENCODING_UTF16), 0);
126
127 // Unpaired low surrogate
128 const char16_t invalid2[] = u"\xDC00";
129 EXPECT_EQ(GetUnresolvedGlyphCount(invalid2, sizeof(invalid2), TEXT_ENCODING_UTF16), 0);
130
131 // Swapped surrogate pair
132 const char16_t invalid3[] = u"\xDC00\xD800";
133 EXPECT_EQ(GetUnresolvedGlyphCount(invalid3, sizeof(invalid3), TEXT_ENCODING_UTF16), 0);
134 }
135
136 /**
137 * @tc.name: AddValidUTF32TextTest
138 * @tc.desc: Test valid UTF-32 text input scenarios
139 * @tc.type: FUNC
140 */
141 HWTEST_F(NdkAddTextTest, AddValidUTF32TextTest, TestSize.Level0)
142 {
143 // Basic ASCII range
144 const char32_t ascii32[] = U"ASCII Text!";
145 EXPECT_EQ(GetUnresolvedGlyphCount(ascii32, sizeof(ascii32), TEXT_ENCODING_UTF32), 0);
146
147 // Non-BMP characters
148 const char32_t emoji32[] = { 0x1F600, 0x1F308, 0 }; //
149 EXPECT_EQ(GetUnresolvedGlyphCount(emoji32, sizeof(emoji32), TEXT_ENCODING_UTF32), 0);
150
151 // Maximum valid code point
152 const char32_t maxUnicode32[] = { 0x10FFFF };
153 EXPECT_EQ(GetUnresolvedGlyphCount(maxUnicode32, sizeof(maxUnicode32), TEXT_ENCODING_UTF32), 1);
154 }
155 /**
156 * @tc.name: AddInvalidUTF32TextTest
157 * @tc.desc: Test invalid UTF-32 text input scenarios
158 * @tc.type: FUNC
159 */
160 HWTEST_F(NdkAddTextTest, AddInvalidUTF32TextTest, TestSize.Level0)
161 {
162 // Code point beyond U+10FFFF
163 const char32_t invalid1[] = { 0x110000 };
164 EXPECT_EQ(GetUnresolvedGlyphCount(invalid1, sizeof(invalid1), TEXT_ENCODING_UTF32), 0);
165
166 // Surrogate code points
167 const char32_t invalid2[] = { 0xD800, 0xDFFF };
168 EXPECT_EQ(GetUnresolvedGlyphCount(invalid2, sizeof(invalid2), TEXT_ENCODING_UTF32), 0);
169
170 // Negative value
171 const char32_t invalid3[] = { -100 };
172 EXPECT_EQ(GetUnresolvedGlyphCount(invalid3, sizeof(invalid3), TEXT_ENCODING_UTF32), 0);
173 }
174
175 /**
176 * @tc.name: AddTextBoundaryTest
177 * @tc.desc: Test boundary cases and edge conditions
178 * @tc.type: FUNC
179 */
180 HWTEST_F(NdkAddTextTest, AddTextBoundaryTest, TestSize.Level0)
181 {
182 // Empty input with different encodings
183 EXPECT_EQ(GetUnresolvedGlyphCount("", 0, TEXT_ENCODING_UTF8), -1);
184 EXPECT_EQ(GetUnresolvedGlyphCount(u"", 0, TEXT_ENCODING_UTF16), -1);
185 EXPECT_EQ(GetUnresolvedGlyphCount(U"", 0, TEXT_ENCODING_UTF32), -1);
186
187 // Null pointer with zero length
188 EXPECT_EQ(GetUnresolvedGlyphCount(nullptr, 0, TEXT_ENCODING_UTF8), -1);
189
190 // Maximum code point boundary
191 const char32_t boundary1[] = { 0x10FFFF, 0x0000 };
192 EXPECT_EQ(GetUnresolvedGlyphCount(boundary1, sizeof(boundary1), TEXT_ENCODING_UTF32), 1);
193
194 // Minimum code point boundary
195 const char32_t boundary2[] = { 0x0000 };
196 EXPECT_EQ(GetUnresolvedGlyphCount(boundary2, sizeof(boundary2), TEXT_ENCODING_UTF32), 0);
197 }
198
199 /**
200 * @tc.name: AddTextStressTest
201 * @tc.desc: Test stress and performance scenarios
202 * @tc.type: PERF
203 */
204 HWTEST_F(NdkAddTextTest, AddTextStressTest, TestSize.Level0)
205 {
206 // Large UTF-8 text
207 std::vector<char> bigUtf8(10000, 'A');
208 EXPECT_EQ(GetUnresolvedGlyphCount(bigUtf8.data(), bigUtf8.size(), TEXT_ENCODING_UTF8), 0);
209
210 // Large UTF-16 text with surrogate pairs
211 std::vector<char16_t> bigUtf16;
212 for (int i = 0; i < 10000; ++i) {
213 bigUtf16.push_back(0xD83D);
214 bigUtf16.push_back(0xDE00);
215 }
216 EXPECT_EQ(GetUnresolvedGlyphCount(bigUtf16.data(), bigUtf16.size(), TEXT_ENCODING_UTF16), 0);
217
218 // Mixed valid/invalid UTF-32 data
219 std::vector<char32_t> mixed_utf32(10000, 0x1F600);
220 mixed_utf32[5000] = 0x110000; // Insert invalid code point
221 EXPECT_EQ(GetUnresolvedGlyphCount(mixed_utf32.data(), mixed_utf32.size(), TEXT_ENCODING_UTF32), 0);
222 }
223
224 /**
225 * @tc.name: AddTextInvalidEncodingTest
226 * @tc.desc: Test invalid encoding type scenarios
227 * @tc.type: FUNC
228 */
229 HWTEST_F(NdkAddTextTest, AddTextInvalidEncodingTest, TestSize.Level0)
230 {
231 // Invalid encoding type
232 const char testStr[] = "test";
233 EXPECT_EQ(GetUnresolvedGlyphCount(testStr, sizeof(testStr), TEXT_ENCODING_GLYPH_ID), -1);
234
235 // Mismatched encoding and data
236 const char16_t utf16Data[] = u"test";
237 EXPECT_EQ(GetUnresolvedGlyphCount(utf16Data, sizeof(utf16Data), TEXT_ENCODING_UTF8), 0);
238
239 // Null pointer with non-zero length
240 EXPECT_EQ(GetUnresolvedGlyphCount(nullptr, 5, TEXT_ENCODING_UTF16), -1);
241 }
242 } // namespace Rosen
243 } // namespace OHOS