Arcane  v4.1.0.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
TestString.cc
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2025 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com)
4// See the top-level COPYRIGHT file for details.
5// SPDX-License-Identifier: Apache-2.0
6//-----------------------------------------------------------------------------
7#include <gtest/gtest.h>
8
9#include "arccore/base/String.h"
10#include "arccore/base/TraceInfo.h"
11#include "arccore/base/StringView.h"
13#include "arccore/base/CoreArray.h"
14#include "arccore/base/BasicTranscoder.h"
15
16#include <vector>
17#include <array>
18
19#ifdef ARCCORE_OS_WIN32
20#include <windows.h>
21#endif
22
23using namespace Arcane;
24using namespace Arcane::Impl;
25
26namespace
27{
28// Classe pour restaurer automatiquement les flags() d'un 'std::ostream'
29 // To Test
30class IosFlagsWrapper
31{
32 public:
33
34 explicit IosFlagsWrapper(std::ostream* o)
35 : m_stream(o)
36 , m_flags(o->flags())
37 {}
38 ~IosFlagsWrapper() { m_stream->flags(m_flags); }
39
40 private:
41
42 std::ostream* m_stream;
43 std::ios_base::fmtflags m_flags;
44};
45
46#ifdef ARCCORE_OS_WIN32
47void _testWStringWin32(const char* str0)
48{
49 std::wstring wideWhat;
50 int str0len = (int)std::strlen(str0);
51 int convertResult = MultiByteToWideChar(CP_UTF8, 0, str0, str0len, NULL, 0);
52 if (convertResult <= 0) {
53 wideWhat = L"Exception occurred: Failure to convert its message text using MultiByteToWideChar: convertResult=";
54 }
55 else {
56 wideWhat.resize(convertResult + 10);
57 convertResult = MultiByteToWideChar(CP_UTF8, 0, str0, str0len, wideWhat.data(), (int)wideWhat.size());
58 if (convertResult <= 0) {
59 wideWhat = L"Exception occurred: Failure to convert its message text using MultiByteToWideChar: convertResult=";
60 }
61 else {
62 wideWhat.resize(convertResult);
63 //wideWhat.insert(0, L"Exception occurred: ");
64 }
65 }
66 std::cout << "STR0=" << str0 << " len=" << str0len << "\n";
67 std::cout << "convertResult=" << convertResult << "\n";
68 std::wcout << "WSTR0 len=" << wideWhat.length() << " v='" << wideWhat << "'\n ";
69 for (int i = 0; i < convertResult; ++i)
70 std::wcout << "PRINT1 I=" << i << " V=" << wideWhat[i] << "\n";
71 std::wcout.flush();
72 for (int i = 0; i < convertResult; ++i)
73 std::cout << "PRINT2 I=" << i << " V=" << std::hex << static_cast<int>(wideWhat[i]) << "\n";
74}
75#endif
76
77void _doConvertTest(const char* name, const String& str)
78{
79 std::cout << "Name=" << name << "\n";
80 std::cout << "OrigUtf8 size=" << str.utf8() << "\n";
81 {
82 CoreArray<Byte> utf8_orig_bytes(str.bytes());
83 CoreArray<Byte> utf8_final_bytes;
84 CoreArray<UChar> utf16_bytes;
85 BasicTranscoder::transcodeFromUtf8ToUtf16(utf8_orig_bytes, utf16_bytes);
86 BasicTranscoder::transcodeFromUtf16ToUtf8(utf16_bytes, utf8_final_bytes);
87 std::cout << "OrigBytes=" << utf8_orig_bytes.constView() << "\n";
88 std::cout << "FinalTranscoderUtf16=" << utf16_bytes.constView() << "\n";
89 std::cout << "FinalTranscoderUtf8=" << utf8_final_bytes.constView() << "\n";
90 ASSERT_EQ(utf8_orig_bytes.constView(), utf8_final_bytes.constView());
91 }
93 ASSERT_EQ(str, str2);
94
95 std::vector<UChar> utf16_vector{ StringUtils::asUtf16BE(str) };
96 Span<const UChar> utf16_bytes(utf16_vector.data(), utf16_vector.size());
97 std::cout << "Utf16 bytes = " << utf16_bytes << "\n";
98 String str3(utf16_bytes.smallView());
99 std::cout << "ToUtf8 size=" << str3.bytes() << "\n";
100 ASSERT_EQ(str, str3);
101}
102
103} // namespace
104
105// TODO: Regarder pourquoi le test ne passe pas sous windows sur le CI de github
106// (alors qu'il fonctionne sur un PC perso. Il faudrait regarder si cela n'est pas
107// un problème d'encodage par défaut).
108TEST(String, Utf8AndUtf16)
109{
110 IosFlagsWrapper io_wrapper(&std::cout);
111 {
112 String str1_direct = "▲▼●■◆éà😀a😈";
113 std::cout << "STR1_UTF8=" << str1_direct << "\n";
114
115 std::array<Byte, 28> str1_bytes = { 0xE2, 0x96, 0xB2, 0xE2, 0x96, 0xBC, 0xE2, 0x97, 0x8F, 0xE2, 0x96, 0xA0, 0xE2, 0x97,
116 0x86, 0xC3, 0xA9, 0xC3, 0xA0, 0xF0, 0x9F, 0x98, 0x80, 0x61, 0xF0, 0x9F, 0x98, 0x88 };
117 String str1(str1_bytes);
118 String str1_orig("▲▼●■◆");
119 //String str1(str1_bytes);
120#ifdef ARCCORE_OS_WIN32
121 _testWStringWin32(str1.localstr());
122#endif
123 std::vector < UChar> utf16_vector_direct{ StringUtils::asUtf16BE(str1_direct) };
124 std::vector<UChar> utf16_vector{ StringUtils::asUtf16BE(str1) };
125 std::vector<UChar> big_endian_ref_vector{ 0x25b2, 0x25bc, 0x25cf, 0x25a0, 0x25c6, 0x00E9, 0x00E0, 0xD83D, 0xDE00, 0x0061, 0xD83D, 0xDE08 };
126 //std::vector<UChar> big_endian_ref_vector{ 0x25b2, 0x25bc, 0x25cf, 0x25a0, 0x25c6 };
127 for (int x : utf16_vector)
128 std::cout << "Utf16: " << std::hex << x << "\n";
129 ASSERT_EQ(big_endian_ref_vector, utf16_vector_direct);
130 ASSERT_EQ(big_endian_ref_vector, utf16_vector);
131 Span<const UChar> utf16_bytes(utf16_vector.data(), utf16_vector.size());
132 std::cout << "Utf16_size=" << utf16_bytes.smallView() << "\n";
133
134 std::cout << "BEFORE_CREATE_STR2\n";
135 String str2(utf16_bytes.smallView());
136 std::cout << "str1.utf16=" << str1.utf16() << "\n";
137 std::cout << "str2.utf16=" << str2.utf16() << "\n";
138
139 bool is_same = (str1 == str2);
140
141 std::cout << "is_same=" << is_same << "\n";
142 ASSERT_EQ(str1, str2);
143
144 std::cout << "str1.utf16=" << str1.utf16() << "\n";
145 std::cout << "str2.utf16=" << str2.utf16() << "\n";
146 std::cout.flush();
147
148 ASSERT_EQ(str1.utf16().size(), 13);
149 ASSERT_EQ(str2.utf16().size(), 13);
150
151 ASSERT_EQ(str1.utf8().size(), str2.utf8().size());
152 ASSERT_EQ(str1.utf16().size(), str2.utf16().size());
153 }
154 {
155 String str2;
156 Span<const Byte> b = str2.bytes();
157 ASSERT_EQ(b.size(), 0);
158 ByteConstArrayView u = str2.utf8();
159 ASSERT_EQ(u.size(), 0);
160 }
161
162 {
163 String str3("TX");
164 Span<const Byte> b = str3.bytes();
165 ASSERT_EQ(b.size(), 2);
166 ByteConstArrayView u = str3.utf8();
167 ASSERT_EQ(u.size(), 3);
168 ASSERT_EQ(u[2], 0);
169 }
170 {
171 String str4("€");
172 std::array<Byte, 3> ref_a{ 0xe2, 0x82, 0xac };
173 Span<const Byte> ref_a_view{ ref_a };
174 Span<const Byte> b = str4.bytes();
175 ASSERT_EQ(b.size(), 3);
176 ASSERT_EQ(b, ref_a_view);
177 ByteConstArrayView u = str4.utf8();
178 ASSERT_EQ(u.size(), 4);
179 ASSERT_EQ(u[3], 0);
180 for (Integer i = 0; i < 3; ++i) {
181 ASSERT_EQ(u[i], ref_a[i]);
182 ASSERT_EQ(b[i], ref_a[i]);
183 }
184 }
185 {
186 String x2 = "\xc3\xb1";
187 _doConvertTest("X2", x2);
188 String x3 = "\xe2\x82\xa1";
189 _doConvertTest("X3", x3);
190 String x4 = "\xf0\x90\x8c\xbc";
191 _doConvertTest("X4", x4);
192 }
193}
194
195TEST(String, Misc)
196{
197 String e = "Titi";
198 String f = "Toto23";
199 ASSERT_TRUE(f.endsWith("23")) << "Bad compare 1";
200 ASSERT_TRUE(f.startsWith("Toto")) << "Bad compare 2";
201 ASSERT_FALSE(f.startsWith("Toto1")) << "Bad compare 3";
202 ASSERT_FALSE(f.endsWith("Toto1")) << "Bad compare 4";
203 ASSERT_FALSE(f.startsWith("Toto234")) << "Bad compare 5";
204
205 ASSERT_FALSE(f.endsWith("Toto234")) << "Bad compare 6";
206
207 String s2 = f.substring(3);
208 ASSERT_TRUE(s2=="o23") << "Bad compare 7";
209
210 s2 = f.substring(3,2);
211 std::cout << "S2_8=" << s2 << '\n';
212 ASSERT_FALSE(s2!="o2") << "Bad compare 8";
213
214 s2 = f.substring(1,2);
215 std::cout << "S2_9=" << s2 << '\n';
216 ASSERT_FALSE(s2!="ot") << "Bad compare 9";
217
218 s2 = f.substring(7,2);
219 std::cout << "S2_10=" << s2 << '\n';
220 ASSERT_FALSE(s2!="") << "Bad compare 10";
221
222 s2 = f.substring(2,1);
223 std::cout << "S2_11=" << s2 << '\n';
224 ASSERT_FALSE(s2!="t") << "Bad compare 11";
225
226 s2 = f.substring(5,1);
227 std::cout << "S2_12=" << s2 << '\n';
228 ASSERT_FALSE(s2!="3") << "Bad compare 12";
229
230 s2 = f.substring(0);
231 std::cout << "S2_13=" << s2 << '\n';
232 ASSERT_FALSE(s2!=f) << "Bad compare 13";
233
234 String g = " \tceci \tcela ";
235 std::cout << " G= '" << g << "'" << '\n';
237 std::cout << " G2= '" << g2 << "'" << '\n';
239 std::cout << " G3= '" << g3 << "'" << '\n';
240 String expected_g3 =" ceci cela ";
241 ASSERT_EQ(g3,expected_g3);
242 String expected_g2 ="ceci cela";
243 ASSERT_EQ(g2,expected_g2);
244
245 String gnull;
246 String gnull2 = String::collapseWhiteSpace(gnull);
247 std::cout << "GNULL2='" << gnull2 << "'" << '\n';
248 ASSERT_EQ(gnull2,String());
249
250 String gempty("");
251 String gempty2 = String::collapseWhiteSpace(gempty);
252 std::cout << "GEMPTY2='" << gempty2 << "'" << '\n';
253 String expected_gempty2 = "";
254 ASSERT_EQ(gempty2,expected_gempty2);
255
256 {
257 String knull;
258 String kempty { gempty };
259 String k1 { "titi" };
260 String k2 { "ti" };
261 String k3 { "to" };
262 ASSERT_TRUE(knull.contains(gnull)) << "Bad null contains null";
263 ASSERT_FALSE(knull.contains(gempty)) << "Bad null contains empty";
264 ASSERT_TRUE(kempty.contains(gnull)) << "Bad empty contains null";
265 ASSERT_TRUE(kempty.contains(gempty)) << "Bad empty contains null";
266 ASSERT_TRUE(k1.contains(gnull)) << "Bad null contains null";
267 ASSERT_TRUE(k1.contains(gempty)) << "Bad contains empty";
268 ASSERT_TRUE(k1.contains(k2)) << "Bad k1 contains k2";
269 ASSERT_FALSE(k2.contains(k1)) << "Bad k2 contains k1";
270 ASSERT_FALSE(k1.contains(k3)) << "Bad k1 contains k3";
271 }
272 {
273 String k0 = ":Toto::Titi:::Tata::::Tutu:Tete:";
274 //String k0 = ":Toto:Titi";
275 //String k0 = ":Toto::Titi";
276 std::cout << "ORIGINAL STRING TO STRING = '" << k0 << "'" << '\n';
277 std::vector<String> k0_list;
278 k0.split(k0_list,':');
279 for( size_t i=0, n=k0_list.size(); i<n; ++i ){
280 std::cout << "K i=" << i << " v='" << k0_list[i] << "' is_null?=" << k0_list[i].null() << '\n';
281 }
282 ASSERT_EQ(k0_list[0],String(":Toto"));
283 ASSERT_EQ(k0_list[1],String(":Titi"));
284 ASSERT_EQ(k0_list[2],String(":"));
285 ASSERT_EQ(k0_list[3],String("Tata"));
286 ASSERT_EQ(k0_list[4],String(":"));
287 ASSERT_EQ(k0_list[5],String(":Tutu"));
288 ASSERT_EQ(k0_list[6],String("Tete"));
289 }
290}
291
292TEST(String, StdStringView)
293{
294 const char* ref1 = "S1éà";
295 const char* ref2 = "ù*aXZáé";
296 // Ref3 = Ref1 + Ref2
297 const char* ref3 = "S1éàù*aXZáé";
298 std::string std_ref3 { ref3 };
299 String snull;
300 String sempty { "" };
301 String s1 = ref1;
302 String s2 = ref2;
303 String s3 = ref1;
304 s3 = s3 + ref2;
305 std::cout << "S1 '" << s1 << "'_SIZE=" << s1.length() << '\n';
306 std::cout << "S2 '" << s2 << "'_SIZE=" << s2.length() << '\n';
307 std::cout << "S3 '" << s3 << "'_SIZE=" << s3.length() << '\n';
308 std::string_view vempty = sempty.toStdStringView();
309 ASSERT_EQ((Int64)vempty.size(),0) << "vempty.size()==0";
310 std::string_view vnull = snull.toStdStringView();
311 ASSERT_EQ((Int64)vnull.size(),0) << "vnull.size()==0";
312 std::string_view v1 = s1.toStdStringView();
313 ASSERT_EQ(v1,ref1) << "v1==ref1";
314 std::string_view v2 = s2.toStdStringView();
315 ASSERT_EQ(v2,ref2) << "v2==ref2";
316 std::string_view v3 = s3.toStdStringView();
317 ASSERT_EQ(v3,std_ref3) << "v3==ref3";
318
319 String s4 = s3 + snull;
320 std::string_view v4 = s4.toStdStringView();
321 ASSERT_EQ(v4,v3) << "v4==v3";
322
323 String s5 = s3 + sempty;
324 std::string_view v5 = s5.toStdStringView();
325 ASSERT_EQ(v5,v4) << "v5==v4";
326
327 String s6 = s2;
328 const char* t1 = "testà1";
329 const char* t2 = "testé2";
330 std::string st1 = t1;
331 std::string_view st1v = st1;
332 std::string st1_2 = st1 + t2;
333 s6 = t1;
334 ASSERT_EQ(s6.toStdStringView(),st1v) << "s6==st1";
335
336 String s7 = s3;
337 s7 = st1_2;
338 ASSERT_EQ(s7,st1_2) << "s7==st1_2";
339 String s8 = s6 + t2;
340 ASSERT_EQ(s8,st1_2) << "s8==st1_2";
341 String s9 = s7 + snull;
342 ASSERT_EQ(s9,st1_2) << "s9==st1_2";
343 String s10 = s7 + sempty;
344 ASSERT_EQ(s10,st1_2) << "s10==st1_2";
345}
#define ASSERT_FALSE(condition)
Vérifie que condition est faux.
Definition Assertion.h:137
#define ASSERT_TRUE(condition)
Vérifie que condition est vrai.
Definition Assertion.h:125
Fonctions utilitaires sur les chaînes de caractères.
ARCCORE_BASE_EXPORT std::vector< UChar > asUtf16BE(const String &str)
Retourne la conversion de l'instance dans l'encodage UTF-16BE.
Definition String.cc:1279
constexpr Integer size() const noexcept
Nombre d'éléments du tableau.
static void transcodeFromUtf16ToUtf8(Span< const UChar > utf16, CoreArray< Byte > &utf8)
Traduit depuis UTF16 vers UTF8.
ConstArrayView< DataType > constView() const
Vue constante.
constexpr __host__ __device__ SizeType size() const noexcept
Retourne la taille du tableau.
Definition Span.h:304
Vue d'un tableau d'éléments de type T.
Definition Span.h:612
Chaîne de caractères unicode.
bool startsWith(const String &s) const
Indique si la chaîne commence par les caractères de s.
Definition String.cc:1100
Int64 length() const
Retourne la longueur de la chaîne.
Definition String.cc:339
ByteConstArrayView utf8() const
Retourne la conversion de l'instance dans l'encodage UTF-8.
Definition String.cc:276
static String replaceWhiteSpace(const String &rhs)
Effectue une normalisation des caractères espaces.
Definition String.cc:441
Span< const Byte > bytes() const
Retourne la conversion de l'instance dans l'encodage UTF-8.
Definition String.cc:292
bool endsWith(const String &s) const
Indique si la chaîne se termine par les caractères de s.
Definition String.cc:1084
void split(StringContainer &str_array, char c) const
Découpe la chaîne suivant le caractère c.
static String collapseWhiteSpace(const String &rhs)
Effectue une normalisation des caractères espaces.
Definition String.cc:453
bool contains(const String &s) const
Indique si la chaîne contient s.
Definition String.cc:1068
std::string_view toStdStringView() const
Retourne une vue de la STL sur la chaîne actuelle.
Definition String.cc:349
String substring(Int64 pos) const
Sous-chaîne commençant à la position pos.
Definition String.cc:1115
-*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
Int32 Integer
Type représentant un entier.
ConstArrayView< Byte > ByteConstArrayView
Equivalent C d'un tableau à une dimension de caractères.
Definition UtilsTypes.h:492