xref: /aosp_15_r20/external/pigweed/pw_string/utf_codecs_test.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1*61c4878aSAndroid Build Coastguard Worker // Copyright 2024 The Pigweed Authors
2*61c4878aSAndroid Build Coastguard Worker //
3*61c4878aSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4*61c4878aSAndroid Build Coastguard Worker // use this file except in compliance with the License. You may obtain a copy of
5*61c4878aSAndroid Build Coastguard Worker // the License at
6*61c4878aSAndroid Build Coastguard Worker //
7*61c4878aSAndroid Build Coastguard Worker //     https://www.apache.org/licenses/LICENSE-2.0
8*61c4878aSAndroid Build Coastguard Worker //
9*61c4878aSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*61c4878aSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11*61c4878aSAndroid Build Coastguard Worker // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12*61c4878aSAndroid Build Coastguard Worker // License for the specific language governing permissions and limitations under
13*61c4878aSAndroid Build Coastguard Worker // the License.
14*61c4878aSAndroid Build Coastguard Worker 
15*61c4878aSAndroid Build Coastguard Worker #include "pw_string/utf_codecs.h"
16*61c4878aSAndroid Build Coastguard Worker 
17*61c4878aSAndroid Build Coastguard Worker #include <array>
18*61c4878aSAndroid Build Coastguard Worker #include <string>
19*61c4878aSAndroid Build Coastguard Worker #include <string_view>
20*61c4878aSAndroid Build Coastguard Worker 
21*61c4878aSAndroid Build Coastguard Worker #include "pw_unit_test/framework.h"
22*61c4878aSAndroid Build Coastguard Worker 
23*61c4878aSAndroid Build Coastguard Worker namespace pw {
24*61c4878aSAndroid Build Coastguard Worker namespace {
25*61c4878aSAndroid Build Coastguard Worker 
TEST(UtfCodecs,IsValidCodepoint)26*61c4878aSAndroid Build Coastguard Worker TEST(UtfCodecs, IsValidCodepoint) {
27*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(utf::IsValidCodepoint(0u));
28*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(utf::IsValidCodepoint(0xD800u - 1u));
29*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(utf::IsValidCodepoint(0xD800u));
30*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(utf::IsValidCodepoint(0xE000u - 1u));
31*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(utf::IsValidCodepoint(0xE000u));
32*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(utf::IsValidCodepoint(0x10FFFFu));
33*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(utf::IsValidCodepoint(0x10FFFFu + 1));
34*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(utf::IsValidCodepoint(0xFFFFFFFFu));
35*61c4878aSAndroid Build Coastguard Worker }
36*61c4878aSAndroid Build Coastguard Worker 
TEST(UtfCodecs,IsValidCharacter)37*61c4878aSAndroid Build Coastguard Worker TEST(UtfCodecs, IsValidCharacter) {
38*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(utf::IsValidCharacter(0u));
39*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(utf::IsValidCharacter(0xD800u - 1u));
40*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(utf::IsValidCharacter(0xD800u));
41*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(utf::IsValidCharacter(0xE000u - 1u));
42*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(utf::IsValidCharacter(0xE000u));
43*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(utf::IsValidCharacter(0xFDD0u - 1u));
44*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(utf::IsValidCharacter(0xFDD0u));
45*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(utf::IsValidCharacter(0xFDEFu));
46*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(utf::IsValidCharacter(0xFDEFu + 1u));
47*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(utf::IsValidCharacter(0x10FFFFu - 2u));
48*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(utf::IsValidCharacter(0x10FFFFu + 1u));
49*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(utf::IsValidCharacter(0xFFFEu));
50*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(utf::IsValidCharacter(0x1FFFEu));
51*61c4878aSAndroid Build Coastguard Worker }
52*61c4878aSAndroid Build Coastguard Worker 
TEST(UtfCodecs,IsStringUTF8)53*61c4878aSAndroid Build Coastguard Worker TEST(UtfCodecs, IsStringUTF8) {
54*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(pw::utf8::IsStringValid("Just some ascii!"));
55*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(pw::utf8::IsStringValid("Test��"));
56*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(pw::utf8::IsStringValid(""));
57*61c4878aSAndroid Build Coastguard Worker   std::array<char, 4> invalid = {
58*61c4878aSAndroid Build Coastguard Worker       char(0xFF), char(0xFF), char(0xFF), char(0xFF)};
59*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(pw::utf8::IsStringValid({invalid.data(), invalid.size()}));
60*61c4878aSAndroid Build Coastguard Worker }
61*61c4878aSAndroid Build Coastguard Worker 
TEST(UtfCodecs,ReadCharacter)62*61c4878aSAndroid Build Coastguard Worker TEST(UtfCodecs, ReadCharacter) {
63*61c4878aSAndroid Build Coastguard Worker   {
64*61c4878aSAndroid Build Coastguard Worker     const char str[] = "$";
65*61c4878aSAndroid Build Coastguard Worker     const size_t char_byte_size = sizeof(str) - 1;
66*61c4878aSAndroid Build Coastguard Worker 
67*61c4878aSAndroid Build Coastguard Worker     auto rslt = pw::utf8::ReadCodePoint(str);
68*61c4878aSAndroid Build Coastguard Worker     EXPECT_TRUE(rslt.ok());
69*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(rslt->size(), char_byte_size);
70*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(rslt->code_point(), 0x0024u);
71*61c4878aSAndroid Build Coastguard Worker   }
72*61c4878aSAndroid Build Coastguard Worker 
73*61c4878aSAndroid Build Coastguard Worker   {
74*61c4878aSAndroid Build Coastguard Worker     const char str[] = "£";
75*61c4878aSAndroid Build Coastguard Worker     const size_t char_byte_size = sizeof(str) - 1;
76*61c4878aSAndroid Build Coastguard Worker 
77*61c4878aSAndroid Build Coastguard Worker     auto rslt = pw::utf8::ReadCodePoint(str);
78*61c4878aSAndroid Build Coastguard Worker     EXPECT_TRUE(rslt.ok());
79*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(rslt->size(), char_byte_size);
80*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(rslt->code_point(), 0x00A3u);
81*61c4878aSAndroid Build Coastguard Worker 
82*61c4878aSAndroid Build Coastguard Worker     // Read too small.
83*61c4878aSAndroid Build Coastguard Worker     rslt = pw::utf8::ReadCodePoint({str, char_byte_size - 1});
84*61c4878aSAndroid Build Coastguard Worker     EXPECT_FALSE(rslt.ok());
85*61c4878aSAndroid Build Coastguard Worker 
86*61c4878aSAndroid Build Coastguard Worker     // Continuation bits are incorrect.
87*61c4878aSAndroid Build Coastguard Worker     std::string bad_continuation{str};
88*61c4878aSAndroid Build Coastguard Worker     uint8_t last_byte = static_cast<uint8_t>(bad_continuation.back());
89*61c4878aSAndroid Build Coastguard Worker     last_byte &= 0x7F;
90*61c4878aSAndroid Build Coastguard Worker     bad_continuation.back() = static_cast<char>(last_byte);
91*61c4878aSAndroid Build Coastguard Worker     rslt = pw::utf8::ReadCodePoint(bad_continuation);
92*61c4878aSAndroid Build Coastguard Worker     EXPECT_FALSE(rslt.ok());
93*61c4878aSAndroid Build Coastguard Worker   }
94*61c4878aSAndroid Build Coastguard Worker 
95*61c4878aSAndroid Build Coastguard Worker   {
96*61c4878aSAndroid Build Coastguard Worker     const char str[] = "€";
97*61c4878aSAndroid Build Coastguard Worker     const size_t char_byte_size = sizeof(str) - 1;
98*61c4878aSAndroid Build Coastguard Worker 
99*61c4878aSAndroid Build Coastguard Worker     auto rslt = pw::utf8::ReadCodePoint(str);
100*61c4878aSAndroid Build Coastguard Worker     EXPECT_TRUE(rslt.ok());
101*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(rslt->size(), char_byte_size);
102*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(rslt->code_point(), 0x20ACu);
103*61c4878aSAndroid Build Coastguard Worker 
104*61c4878aSAndroid Build Coastguard Worker     // Read too small.
105*61c4878aSAndroid Build Coastguard Worker     rslt = pw::utf8::ReadCodePoint({str, char_byte_size - 1});
106*61c4878aSAndroid Build Coastguard Worker     EXPECT_FALSE(rslt.ok());
107*61c4878aSAndroid Build Coastguard Worker 
108*61c4878aSAndroid Build Coastguard Worker     // Continuation bits are incorrect.
109*61c4878aSAndroid Build Coastguard Worker     std::string bad_continuation{str};
110*61c4878aSAndroid Build Coastguard Worker     uint8_t last_byte = static_cast<uint8_t>(bad_continuation.back());
111*61c4878aSAndroid Build Coastguard Worker     last_byte &= 0x7F;
112*61c4878aSAndroid Build Coastguard Worker     bad_continuation.back() = static_cast<char>(last_byte);
113*61c4878aSAndroid Build Coastguard Worker     rslt = pw::utf8::ReadCodePoint(bad_continuation);
114*61c4878aSAndroid Build Coastguard Worker     EXPECT_FALSE(rslt.ok());
115*61c4878aSAndroid Build Coastguard Worker   }
116*61c4878aSAndroid Build Coastguard Worker 
117*61c4878aSAndroid Build Coastguard Worker   {
118*61c4878aSAndroid Build Coastguard Worker     const char str[] = "��";
119*61c4878aSAndroid Build Coastguard Worker     const size_t char_byte_size = sizeof(str) - 1;
120*61c4878aSAndroid Build Coastguard Worker 
121*61c4878aSAndroid Build Coastguard Worker     auto rslt = pw::utf8::ReadCodePoint(str);
122*61c4878aSAndroid Build Coastguard Worker     EXPECT_TRUE(rslt.ok());
123*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(rslt->size(), char_byte_size);
124*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(rslt->code_point(), 0x10348u);
125*61c4878aSAndroid Build Coastguard Worker 
126*61c4878aSAndroid Build Coastguard Worker     // Read too small.
127*61c4878aSAndroid Build Coastguard Worker     rslt = pw::utf8::ReadCodePoint({str, char_byte_size - 1});
128*61c4878aSAndroid Build Coastguard Worker     EXPECT_FALSE(rslt.ok());
129*61c4878aSAndroid Build Coastguard Worker 
130*61c4878aSAndroid Build Coastguard Worker     // Continuation bits are incorrect.
131*61c4878aSAndroid Build Coastguard Worker     std::string bad_continuation{str};
132*61c4878aSAndroid Build Coastguard Worker     uint8_t last_byte = static_cast<uint8_t>(bad_continuation.back());
133*61c4878aSAndroid Build Coastguard Worker     last_byte &= 0x7F;
134*61c4878aSAndroid Build Coastguard Worker     bad_continuation.back() = static_cast<char>(last_byte);
135*61c4878aSAndroid Build Coastguard Worker     rslt = pw::utf8::ReadCodePoint(bad_continuation);
136*61c4878aSAndroid Build Coastguard Worker     EXPECT_FALSE(rslt.ok());
137*61c4878aSAndroid Build Coastguard Worker   }
138*61c4878aSAndroid Build Coastguard Worker 
139*61c4878aSAndroid Build Coastguard Worker   {
140*61c4878aSAndroid Build Coastguard Worker     const char str[] = {
141*61c4878aSAndroid Build Coastguard Worker         char(0xFF), char(0xFF), char(0xFF), char(0xFF), char(0)};
142*61c4878aSAndroid Build Coastguard Worker 
143*61c4878aSAndroid Build Coastguard Worker     auto rslt = pw::utf8::ReadCodePoint(str);
144*61c4878aSAndroid Build Coastguard Worker     EXPECT_FALSE(rslt.ok());
145*61c4878aSAndroid Build Coastguard Worker     EXPECT_TRUE(rslt.status().IsInvalidArgument());
146*61c4878aSAndroid Build Coastguard Worker   }
147*61c4878aSAndroid Build Coastguard Worker 
148*61c4878aSAndroid Build Coastguard Worker   {
149*61c4878aSAndroid Build Coastguard Worker     const char str[] = "";
150*61c4878aSAndroid Build Coastguard Worker 
151*61c4878aSAndroid Build Coastguard Worker     auto rslt = pw::utf8::ReadCodePoint(str);
152*61c4878aSAndroid Build Coastguard Worker     EXPECT_FALSE(rslt.ok());
153*61c4878aSAndroid Build Coastguard Worker     EXPECT_TRUE(rslt.status().IsInvalidArgument());
154*61c4878aSAndroid Build Coastguard Worker   }
155*61c4878aSAndroid Build Coastguard Worker 
156*61c4878aSAndroid Build Coastguard Worker   {
157*61c4878aSAndroid Build Coastguard Worker     // Encode a code point that ends up being an invalid utf-8 encoding.
158*61c4878aSAndroid Build Coastguard Worker     const uint32_t invalid_utf8_code_point = 0xD800u + 1u;
159*61c4878aSAndroid Build Coastguard Worker     auto encoded = pw::utf8::EncodeCodePoint(invalid_utf8_code_point);
160*61c4878aSAndroid Build Coastguard Worker     EXPECT_TRUE(encoded.ok());
161*61c4878aSAndroid Build Coastguard Worker 
162*61c4878aSAndroid Build Coastguard Worker     // Reading it back should fail validation.
163*61c4878aSAndroid Build Coastguard Worker     auto rslt = pw::utf8::ReadCodePoint(encoded->as_view());
164*61c4878aSAndroid Build Coastguard Worker     EXPECT_FALSE(rslt.ok());
165*61c4878aSAndroid Build Coastguard Worker     EXPECT_TRUE(rslt.status().IsOutOfRange());
166*61c4878aSAndroid Build Coastguard Worker   }
167*61c4878aSAndroid Build Coastguard Worker }
168*61c4878aSAndroid Build Coastguard Worker 
TEST(UtfCodecs,FunctionsAreConstexpr)169*61c4878aSAndroid Build Coastguard Worker TEST(UtfCodecs, FunctionsAreConstexpr) {
170*61c4878aSAndroid Build Coastguard Worker   {
171*61c4878aSAndroid Build Coastguard Worker     constexpr char str[] = "$";
172*61c4878aSAndroid Build Coastguard Worker     constexpr size_t char_byte_size = sizeof(str) - 1;
173*61c4878aSAndroid Build Coastguard Worker     const uint32_t code_point = 0x0024u;
174*61c4878aSAndroid Build Coastguard Worker 
175*61c4878aSAndroid Build Coastguard Worker     constexpr pw::Result<pw::utf::CodePointAndSize> rslt =
176*61c4878aSAndroid Build Coastguard Worker         pw::utf8::ReadCodePoint(str);
177*61c4878aSAndroid Build Coastguard Worker     static_assert(rslt.ok());
178*61c4878aSAndroid Build Coastguard Worker 
179*61c4878aSAndroid Build Coastguard Worker     EXPECT_TRUE(rslt.ok());
180*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(rslt->size(), char_byte_size);
181*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(rslt->code_point(), 0x0024u);
182*61c4878aSAndroid Build Coastguard Worker 
183*61c4878aSAndroid Build Coastguard Worker     constexpr bool valid_str = pw::utf8::IsStringValid(str);
184*61c4878aSAndroid Build Coastguard Worker     static_assert(valid_str);
185*61c4878aSAndroid Build Coastguard Worker 
186*61c4878aSAndroid Build Coastguard Worker     EXPECT_TRUE(valid_str);
187*61c4878aSAndroid Build Coastguard Worker 
188*61c4878aSAndroid Build Coastguard Worker     constexpr auto encoded = pw::utf8::EncodeCodePoint(code_point);
189*61c4878aSAndroid Build Coastguard Worker     static_assert(encoded.ok());
190*61c4878aSAndroid Build Coastguard Worker   }
191*61c4878aSAndroid Build Coastguard Worker }
192*61c4878aSAndroid Build Coastguard Worker 
TEST(UtfCodecs,WriteCodePoint)193*61c4878aSAndroid Build Coastguard Worker TEST(UtfCodecs, WriteCodePoint) {
194*61c4878aSAndroid Build Coastguard Worker   {
195*61c4878aSAndroid Build Coastguard Worker     const char str[] = "$";
196*61c4878aSAndroid Build Coastguard Worker     const size_t char_byte_size = sizeof(str) - 1;
197*61c4878aSAndroid Build Coastguard Worker     const uint32_t code_point = 0x0024u;
198*61c4878aSAndroid Build Coastguard Worker 
199*61c4878aSAndroid Build Coastguard Worker     std::array<char, 2> buffer{};
200*61c4878aSAndroid Build Coastguard Worker     pw::StringBuilder out(buffer);
201*61c4878aSAndroid Build Coastguard Worker     auto rslt = pw::utf8::WriteCodePoint(code_point, out);
202*61c4878aSAndroid Build Coastguard Worker     EXPECT_TRUE(rslt.ok());
203*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(out.size(), char_byte_size);
204*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(out, std::string_view(str, char_byte_size));
205*61c4878aSAndroid Build Coastguard Worker   }
206*61c4878aSAndroid Build Coastguard Worker 
207*61c4878aSAndroid Build Coastguard Worker   {
208*61c4878aSAndroid Build Coastguard Worker     const char str[] = "£";
209*61c4878aSAndroid Build Coastguard Worker     const size_t char_byte_size = sizeof(str) - 1;
210*61c4878aSAndroid Build Coastguard Worker     const uint32_t code_point = 0x00A3u;
211*61c4878aSAndroid Build Coastguard Worker 
212*61c4878aSAndroid Build Coastguard Worker     std::array<char, 3> buffer{};
213*61c4878aSAndroid Build Coastguard Worker     pw::StringBuilder out(buffer);
214*61c4878aSAndroid Build Coastguard Worker     auto rslt = pw::utf8::WriteCodePoint(code_point, out);
215*61c4878aSAndroid Build Coastguard Worker     EXPECT_TRUE(rslt.ok());
216*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(out.size(), char_byte_size);
217*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(out, std::string_view(str, char_byte_size));
218*61c4878aSAndroid Build Coastguard Worker   }
219*61c4878aSAndroid Build Coastguard Worker 
220*61c4878aSAndroid Build Coastguard Worker   {
221*61c4878aSAndroid Build Coastguard Worker     const char str[] = "€";
222*61c4878aSAndroid Build Coastguard Worker     const size_t char_byte_size = sizeof(str) - 1;
223*61c4878aSAndroid Build Coastguard Worker     const uint32_t code_point = 0x20ACu;
224*61c4878aSAndroid Build Coastguard Worker 
225*61c4878aSAndroid Build Coastguard Worker     std::array<char, 4> buffer{};
226*61c4878aSAndroid Build Coastguard Worker     pw::StringBuilder out(buffer);
227*61c4878aSAndroid Build Coastguard Worker     auto rslt = pw::utf8::WriteCodePoint(code_point, out);
228*61c4878aSAndroid Build Coastguard Worker     EXPECT_TRUE(rslt.ok());
229*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(out.size(), char_byte_size);
230*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(out, std::string_view(str, char_byte_size));
231*61c4878aSAndroid Build Coastguard Worker   }
232*61c4878aSAndroid Build Coastguard Worker 
233*61c4878aSAndroid Build Coastguard Worker   {
234*61c4878aSAndroid Build Coastguard Worker     const char str[] = "��";
235*61c4878aSAndroid Build Coastguard Worker     const size_t char_byte_size = sizeof(str) - 1;
236*61c4878aSAndroid Build Coastguard Worker     const uint32_t code_point = 0x10348u;
237*61c4878aSAndroid Build Coastguard Worker 
238*61c4878aSAndroid Build Coastguard Worker     std::array<char, 5> buffer{};
239*61c4878aSAndroid Build Coastguard Worker     pw::StringBuilder out(buffer);
240*61c4878aSAndroid Build Coastguard Worker     auto rslt = pw::utf8::WriteCodePoint(code_point, out);
241*61c4878aSAndroid Build Coastguard Worker     EXPECT_TRUE(rslt.ok());
242*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(out.size(), char_byte_size);
243*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(out, std::string_view(str, char_byte_size));
244*61c4878aSAndroid Build Coastguard Worker   }
245*61c4878aSAndroid Build Coastguard Worker 
246*61c4878aSAndroid Build Coastguard Worker   {
247*61c4878aSAndroid Build Coastguard Worker     const uint32_t code_point = 0xFFFFFFFFu;
248*61c4878aSAndroid Build Coastguard Worker 
249*61c4878aSAndroid Build Coastguard Worker     std::array<char, 4> buffer{};
250*61c4878aSAndroid Build Coastguard Worker     pw::StringBuilder out(buffer);
251*61c4878aSAndroid Build Coastguard Worker     EXPECT_FALSE(pw::utf8::WriteCodePoint(code_point, out).ok());
252*61c4878aSAndroid Build Coastguard Worker     // Nothing should be written.
253*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(out.view(), std::string_view{});
254*61c4878aSAndroid Build Coastguard Worker   }
255*61c4878aSAndroid Build Coastguard Worker 
256*61c4878aSAndroid Build Coastguard Worker   {
257*61c4878aSAndroid Build Coastguard Worker     const char str[] = "��";
258*61c4878aSAndroid Build Coastguard Worker     const uint32_t code_point = 0x10348u;
259*61c4878aSAndroid Build Coastguard Worker 
260*61c4878aSAndroid Build Coastguard Worker     std::array<char, 3> buffer{};
261*61c4878aSAndroid Build Coastguard Worker     pw::StringBuilder out(buffer);
262*61c4878aSAndroid Build Coastguard Worker     // Buffer was too small so it should have a failure status.
263*61c4878aSAndroid Build Coastguard Worker     EXPECT_FALSE(pw::utf8::WriteCodePoint(code_point, out).ok());
264*61c4878aSAndroid Build Coastguard Worker     // We expect the first two code units to be written.
265*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(out.view(), std::string_view(str, 2));
266*61c4878aSAndroid Build Coastguard Worker   }
267*61c4878aSAndroid Build Coastguard Worker }
268*61c4878aSAndroid Build Coastguard Worker 
TEST(UtfCodecs,EncodeCodePoint)269*61c4878aSAndroid Build Coastguard Worker TEST(UtfCodecs, EncodeCodePoint) {
270*61c4878aSAndroid Build Coastguard Worker   {
271*61c4878aSAndroid Build Coastguard Worker     const char str[] = "$";
272*61c4878aSAndroid Build Coastguard Worker     const size_t char_byte_size = sizeof(str) - 1;
273*61c4878aSAndroid Build Coastguard Worker     const uint32_t code_point = 0x0024u;
274*61c4878aSAndroid Build Coastguard Worker 
275*61c4878aSAndroid Build Coastguard Worker     auto rslt = pw::utf8::EncodeCodePoint(code_point);
276*61c4878aSAndroid Build Coastguard Worker     EXPECT_TRUE(rslt.ok());
277*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(rslt->as_view(), std::string_view(str, char_byte_size));
278*61c4878aSAndroid Build Coastguard Worker   }
279*61c4878aSAndroid Build Coastguard Worker 
280*61c4878aSAndroid Build Coastguard Worker   {
281*61c4878aSAndroid Build Coastguard Worker     const char str[] = "£";
282*61c4878aSAndroid Build Coastguard Worker     const size_t char_byte_size = sizeof(str) - 1;
283*61c4878aSAndroid Build Coastguard Worker     const uint32_t code_point = 0x00A3u;
284*61c4878aSAndroid Build Coastguard Worker 
285*61c4878aSAndroid Build Coastguard Worker     auto rslt = pw::utf8::EncodeCodePoint(code_point);
286*61c4878aSAndroid Build Coastguard Worker     EXPECT_TRUE(rslt.ok());
287*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(rslt->as_view(), std::string_view(str, char_byte_size));
288*61c4878aSAndroid Build Coastguard Worker   }
289*61c4878aSAndroid Build Coastguard Worker 
290*61c4878aSAndroid Build Coastguard Worker   {
291*61c4878aSAndroid Build Coastguard Worker     const char str[] = "€";
292*61c4878aSAndroid Build Coastguard Worker     const size_t char_byte_size = sizeof(str) - 1;
293*61c4878aSAndroid Build Coastguard Worker     const uint32_t code_point = 0x20ACu;
294*61c4878aSAndroid Build Coastguard Worker 
295*61c4878aSAndroid Build Coastguard Worker     auto rslt = pw::utf8::EncodeCodePoint(code_point);
296*61c4878aSAndroid Build Coastguard Worker     EXPECT_TRUE(rslt.ok());
297*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(rslt->as_view(), std::string_view(str, char_byte_size));
298*61c4878aSAndroid Build Coastguard Worker   }
299*61c4878aSAndroid Build Coastguard Worker 
300*61c4878aSAndroid Build Coastguard Worker   {
301*61c4878aSAndroid Build Coastguard Worker     const char str[] = "��";
302*61c4878aSAndroid Build Coastguard Worker     const size_t char_byte_size = sizeof(str) - 1;
303*61c4878aSAndroid Build Coastguard Worker     const uint32_t code_point = 0x10348u;
304*61c4878aSAndroid Build Coastguard Worker 
305*61c4878aSAndroid Build Coastguard Worker     auto rslt = pw::utf8::EncodeCodePoint(code_point);
306*61c4878aSAndroid Build Coastguard Worker     EXPECT_TRUE(rslt.ok());
307*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(rslt->as_view(), std::string_view(str, char_byte_size));
308*61c4878aSAndroid Build Coastguard Worker   }
309*61c4878aSAndroid Build Coastguard Worker 
310*61c4878aSAndroid Build Coastguard Worker   {
311*61c4878aSAndroid Build Coastguard Worker     const uint32_t code_point = 0xFFFFFFFFu;
312*61c4878aSAndroid Build Coastguard Worker 
313*61c4878aSAndroid Build Coastguard Worker     EXPECT_FALSE(pw::utf8::EncodeCodePoint(code_point).ok());
314*61c4878aSAndroid Build Coastguard Worker   }
315*61c4878aSAndroid Build Coastguard Worker }
316*61c4878aSAndroid Build Coastguard Worker 
317*61c4878aSAndroid Build Coastguard Worker }  // namespace
318*61c4878aSAndroid Build Coastguard Worker }  // namespace pw
319