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