1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #include "ags/shared/core/platform.h"
24 #include "ags/lib/std/vector.h"
25 #include "ags/shared/util/path.h"
26 #include "ags/shared/util/string.h"
27 #include "ags/shared/debugging/assert.h"
28 
29 namespace AGS3 {
30 
31 using namespace AGS::Shared;
32 
Test_Path()33 void Test_Path() {
34 	assert(Path::IsSameOrSubDir(".", "dir1/") == true);
35 	assert(Path::IsSameOrSubDir(".", "dir1/dir2/dir3/") == true);
36 	assert(Path::IsSameOrSubDir(".", "dir1/../") == true);
37 	assert(Path::IsSameOrSubDir(".", "dir1/dir2/../../") == true);
38 	assert(Path::IsSameOrSubDir(".", "dir1/../dir2/../dir3/") == true);
39 	assert(Path::IsSameOrSubDir(".", "..dir/") == true);
40 
41 	assert(Path::IsSameOrSubDir(".", "../") == false);
42 	assert(Path::IsSameOrSubDir(".", "../") == false);
43 	assert(Path::IsSameOrSubDir(".", "/dir1/") == false);
44 	assert(Path::IsSameOrSubDir(".", "dir1/../../") == false);
45 	assert(Path::IsSameOrSubDir(".", "dir1/../dir2/../../dir3/") == false);
46 }
47 
Test_String()48 void Test_String() {
49 	// Test string's internal work
50 	{
51 		String s1 = "abcdefghijklmnop";
52 		String s2 = s1;
53 		String s3 = s1;
54 		assert(s1.GetRefCount() == 3);
55 		assert(s1.GetBuffer() == s2.GetBuffer());
56 		assert(s2.GetBuffer() == s3.GetBuffer());
57 
58 		size_t cap1 = s1.GetCapacity();
59 		assert(cap1 == s1.GetLength());
60 
61 		s2.TruncateToLeft(10);
62 		assert(cap1 == s2.GetCapacity());
63 		s3.TruncateToRight(10);
64 		assert(cap1 == s3.GetCapacity());
65 		assert(s1.GetRefCount() == 1);
66 
67 		s2.AppendChar('z');
68 		assert(cap1 == s2.GetCapacity());
69 
70 		s3.Append("1234");
71 		assert(cap1 == s3.GetCapacity());
72 		s3.Append("1234567890123");
73 		assert(27 == s3.GetCapacity());
74 		s3.Append("1234567890123");
75 		assert(40 == s3.GetCapacity());
76 		s3.Append("1234567890123");
77 		assert(60 == s3.GetCapacity());
78 
79 		String s4 = "12345678901234567890";
80 		const char *cstr = s4.GetCStr();
81 		s4.ClipLeft(10);
82 		assert(s4.GetCStr() == cstr + 10);
83 		s4.Prepend("12345");
84 		assert(s4.GetCStr() == cstr + 5);
85 		s4.Append("12345");
86 		assert(s4.GetCStr() == cstr);
87 		assert(strcmp(s4, "12345123456789012345") == 0);
88 	}
89 
90 	// Test Compare
91 	{
92 		String s1 = "abcdabcdabcd";
93 		String s2 = "abcdbfghijklmn";
94 		int cmp1 = s1.Compare(s2);
95 		int cmp2 = s1.CompareLeft("abcd");
96 		int cmp3 = s1.CompareLeft("abcdxxx");
97 		int cmp4 = s1.CompareLeft("abcdxxx", 4);
98 		int cmp5 = s1.CompareMid(s2, 2, 4);
99 		int cmp6 = s1.CompareMid(s2, 8, 4);
100 		int cmp7 = s1.CompareMid(s2, 8, 9);
101 		int cmp8 = s1.CompareLeft("abcdabcdabcdxxxx");
102 		int cmp9 = s1.CompareMid("ab", 8);
103 		int cmp10 = s1.CompareMid("ab", 8, 4);
104 		int cmp11 = s1.CompareRight("abcd");
105 		int cmp12 = s1.CompareRight("bcdxxx", 3);
106 		int cmp13 = s1.CompareRight("abc", 4);
107 		int cmp14 = s1.CompareRight("abcdxxxx");
108 		assert(cmp1 < 0);
109 		assert(cmp2 == 0);
110 		assert(cmp3 < 0);
111 		assert(cmp4 == 0);
112 		assert(cmp5 > 0);
113 		assert(cmp6 == 0);
114 		assert(cmp7 < 0);
115 		assert(cmp8 < 0);
116 		assert(cmp9 == 0);
117 		assert(cmp10 > 0);
118 		assert(cmp11 == 0);
119 		assert(cmp12 == 0);
120 		assert(cmp13 > 0);
121 		assert(cmp14 < 0);
122 	}
123 
124 	// Test FindChar
125 	{
126 		String s1 = "findsomethinginhere";
127 		String s2 = "stringtofindsomethinginside";
128 		String s3 = "findsomethinginherex";
129 		String s4 = "xstringtofindsomethinginside";
130 		String s5;
131 		size_t find1 = s1.FindChar('o');
132 		size_t find2 = s2.FindCharReverse('o');
133 		size_t find3 = s1.FindChar('x');
134 		size_t find4 = s2.FindCharReverse('x');
135 		size_t find5 = s3.FindChar('x');
136 		size_t find6 = s4.FindCharReverse('x');
137 		size_t find7 = s5.FindChar('x');
138 		size_t find8 = s5.FindCharReverse('x');
139 		size_t find9 = s1.FindChar('i', 2);
140 		size_t find10 = s1.FindCharReverse('i', 12);
141 		assert(find1 == 5);
142 		assert(find2 == 13);
143 		assert(find3 == -1);
144 		assert(find4 == -1);
145 		assert(find5 == 19);
146 		assert(find6 == 0);
147 		assert(find7 == -1);
148 		assert(find8 == -1);
149 		assert(find9 == 10);
150 		assert(find10 == 10);
151 	}
152 
153 	// Test GetAt
154 	{
155 		String s1 = "abcdefghijklmnop";
156 		String s2;
157 		char c1 = s1.GetAt(0);
158 		char c2 = s1.GetAt(15);
159 		char c3 = s1.GetAt(16);
160 		char c4 = s2.GetAt(0);
161 		assert(c1 == 'a');
162 		assert(c2 == 'p');
163 		assert(c3 == 0);
164 		assert(c4 == 0);
165 	}
166 
167 	// Test ToInt
168 	{
169 		String s1;
170 		String s2 = "100";
171 		String s3 = "202aaa";
172 		String s4 = "aaa333";
173 		int i1 = s1.ToInt();
174 		int i2 = s2.ToInt();
175 		int i3 = s3.ToInt();
176 		int i4 = s4.ToInt();
177 		assert(i1 == 0);
178 		assert(i2 == 100);
179 		assert(i3 == 202);
180 		assert(i4 == 0);
181 	}
182 
183 	// Test Left/Right/Mid
184 	{
185 		String s1 = "this is a string to be split";
186 		String s2 = s1.Left(4);
187 		String s3 = s1.Left(100);
188 		String s4 = s1.Mid(10);
189 		String s5 = s1.Mid(10, 6);
190 		String s6 = s1.Mid(0, 200);
191 		String s7 = s1.Right(5);
192 		String s8 = s1.Right(100);
193 		String s9 = s1.Left(0);
194 		String s10 = s1.Mid((size_t) - 1, 0);
195 		String s11 = s1.Right(0);
196 
197 		assert(strcmp(s2, "this") == 0);
198 		assert(strcmp(s3, "this is a string to be split") == 0);
199 		assert(strcmp(s4, "string to be split") == 0);
200 		assert(strcmp(s5, "string") == 0);
201 		assert(strcmp(s6, "this is a string to be split") == 0);
202 		assert(strcmp(s7, "split") == 0);
203 		assert(strcmp(s8, "this is a string to be split") == 0);
204 		assert(strcmp(s9, "") == 0);
205 		assert(strcmp(s10, "") == 0);
206 		assert(strcmp(s11, "") == 0);
207 	}
208 
209 	// Test Section
210 	{
211 		String s = "_123_567_";
212 		size_t from;
213 		size_t to;
214 		assert(s.FindSection('_', 0, 0, true, true, from, to));
215 		assert(from == 0 && to == 0);
216 		assert(s.FindSection('_', 0, 0, false, true, from, to));
217 		assert(from == 0 && to == 0);
218 		assert(s.FindSection('_', 0, 0, true, false, from, to));
219 		assert(from == 0 && to == 1);
220 		assert(s.FindSection('_', 0, 0, false, false, from, to));
221 		assert(from == 0 && to == 1);
222 		assert(s.FindSection('_', 3, 3, true, true, from, to));
223 		assert(from == 9 && to == 9);
224 		assert(s.FindSection('_', 3, 3, false, true, from, to));
225 		assert(from == 8 && to == 9);
226 		assert(s.FindSection('_', 3, 3, true, false, from, to));
227 		assert(from == 9 && to == 9);
228 		assert(s.FindSection('_', 3, 3, false, false, from, to));
229 		assert(from == 8 && to == 9);
230 		assert(s.FindSection('_', 1, 1, true, true, from, to));
231 		assert(from == 1 && to == 4);
232 		assert(s.FindSection('_', 1, 1, false, true, from, to));
233 		assert(from == 0 && to == 4);
234 		assert(s.FindSection('_', 1, 1, true, false, from, to));
235 		assert(from == 1 && to == 5);
236 		assert(s.FindSection('_', 1, 1, false, false, from, to));
237 		assert(from == 0 && to == 5);
238 	}
239 
240 	// Test Append
241 	{
242 		String s1 = "a string to enlarge - ";
243 		s1.Append("make it bigger");
244 		assert(strcmp(s1, "a string to enlarge - make it bigger") == 0);
245 		s1.AppendChar('!');
246 		assert(strcmp(s1, "a string to enlarge - make it bigger!") == 0);
247 		s1.AppendChar(' ');
248 		assert(strcmp(s1, "a string to enlarge - make it bigger! ") == 0);
249 		s1.Append("much much bigger!");
250 		assert(strcmp(s1, "a string to enlarge - make it bigger! much much bigger!") == 0);
251 	}
252 
253 	// Test Clip
254 	{
255 		String str1 = "long truncateable string";
256 		String str2 = str1;
257 		String str3 = str1;
258 		String str4 = str1;
259 		String str5 = str1;
260 
261 		str1.ClipLeft(4);
262 		str2.ClipRight(6);
263 		str3.ClipMid(5, 12);
264 		str4.ClipMid(5, 0);
265 		str5.ClipMid(0);
266 		assert(strcmp(str1, " truncateable string") == 0);
267 		assert(strcmp(str2, "long truncateable ") == 0);
268 		assert(strcmp(str3, "long  string") == 0);
269 		assert(strcmp(str4, "long truncateable string") == 0);
270 		assert(strcmp(str5, "") == 0);
271 	}
272 
273 	// Test ClipSection
274 	{
275 		String str1 = "C:\\Games\\AGS\\MyNewGame";
276 		String str2 = str1;
277 		String str3 = str1;
278 		String str4 = str1;
279 		String str5 = str1;
280 		String str6 = str1;
281 		String str7 = str1;
282 		String str8 = str1;
283 		String str9 = str1;
284 		String str10 = str1;
285 		String str11 = str1;
286 
287 		str1.ClipLeftSection('\\');
288 		str2.ClipLeftSection('\\', false);
289 		str3.ClipRightSection('\\');
290 		str4.ClipRightSection('\\', false);
291 		str5.ClipSection('\\', 1, 2);
292 		str6.ClipSection('\\', 1, 2, false, false);
293 		str7.ClipSection('|', 1, 2);
294 		str8.ClipSection('\\', 0, 2);
295 		str9.ClipSection('\\', 1, 3);
296 		str10.ClipSection('\\', 3, 1);
297 		str11.ClipSection('\\', 0, 4);
298 		assert(strcmp(str1, "Games\\AGS\\MyNewGame") == 0);
299 		assert(strcmp(str2, "\\Games\\AGS\\MyNewGame") == 0);
300 		assert(strcmp(str3, "C:\\Games\\AGS") == 0);
301 		assert(strcmp(str4, "C:\\Games\\AGS\\") == 0);
302 		assert(strcmp(str5, "C:MyNewGame") == 0);
303 		assert(strcmp(str6, "C:\\\\MyNewGame") == 0);
304 		assert(strcmp(str7, "C:\\Games\\AGS\\MyNewGame") == 0);
305 		assert(strcmp(str8, "MyNewGame") == 0);
306 		assert(strcmp(str9, "C:") == 0);
307 		assert(strcmp(str10, "C:\\Games\\AGS\\MyNewGame") == 0);
308 		assert(strcmp(str11, "") == 0);
309 	}
310 
311 	// Test making new string
312 	{
313 		String s1 = "we have some string here";
314 		assert(strcmp(s1, "we have some string here") == 0);
315 		s1.Empty();
316 		assert(strcmp(s1, "") == 0);
317 		s1.FillString('z', 10);
318 		assert(strcmp(s1, "zzzzzzzzzz") == 0);
319 		s1.FillString('a', 0);
320 		assert(strcmp(s1, "") == 0);
321 		s1.Format("this %d is %9ld a %x formatted %0.2f string %s", 1, 2, 100, 22.55F, "abcd");
322 		assert(strcmp(s1, "this 1 is         2 a 64 formatted 22.55 string abcd") == 0);
323 		s1.SetString("some string");
324 		assert(strcmp(s1, "some string") == 0);
325 		s1.SetString("some string", 4);
326 		assert(strcmp(s1, "some") == 0);
327 	}
328 
329 	// Test Upper/Lower case
330 	{
331 		String s1 = "ThIs StRiNg Is TwIsTeD";
332 		String s2 = s1;
333 		String s3 = s1;
334 		s2.MakeLower();
335 		s3.MakeUpper();
336 		assert(strcmp(s2, "this string is twisted") == 0);
337 		assert(strcmp(s3, "THIS STRING IS TWISTED") == 0);
338 	}
339 
340 	// Test Prepend
341 	{
342 		String s1 = "- a string to enlarge";
343 		s1.Prepend("make it bigger ");
344 		assert(strcmp(s1, "make it bigger - a string to enlarge") == 0);
345 		s1.PrependChar('!');
346 		assert(strcmp(s1, "!make it bigger - a string to enlarge") == 0);
347 		s1.PrependChar(' ');
348 		assert(strcmp(s1, " !make it bigger - a string to enlarge") == 0);
349 		s1.Prepend("much much bigger!");
350 		assert(strcmp(s1, "much much bigger! !make it bigger - a string to enlarge") == 0);
351 	}
352 
353 	// Test ReplaceMid
354 	{
355 		String s1 = "we need to replace PRECISELY THIS PART in this string";
356 		String s2 = s1;
357 		String new_long = "WITH A NEW TAD LONGER SUBSTRING";
358 		String new_short = "SMALL STRING";
359 		s1.ReplaceMid(19, 19, new_long);
360 		assert(strcmp(s1, "we need to replace WITH A NEW TAD LONGER SUBSTRING in this string") == 0);
361 		s2.ReplaceMid(19, 19, new_short);
362 		assert(strcmp(s2, "we need to replace SMALL STRING in this string") == 0);
363 		String s3 = "insert new string here: ";
364 		s3.ReplaceMid(s3.GetLength(), 0, "NEW STRING");
365 		assert(strcmp(s3, "insert new string here: NEW STRING") == 0);
366 	}
367 
368 	// Test SetAt
369 	{
370 		String s1 = "strimg wiyh typos";
371 		s1.SetAt((size_t) - 1, 'a');
372 		assert(strcmp(s1, "strimg wiyh typos") == 0);
373 		s1.SetAt(100, 'a');
374 		assert(strcmp(s1, "strimg wiyh typos") == 0);
375 		s1.SetAt(1, 0);
376 		assert(strcmp(s1, "strimg wiyh typos") == 0);
377 		s1.SetAt(4, 'n');
378 		s1.SetAt(9, 't');
379 		assert(strcmp(s1, "string with typos") == 0);
380 	}
381 
382 	// Test Trim
383 	{
384 		String str1 = "\t   This string is quite long and should be cut a little bit\r\n    ";
385 		String str2 = str1;
386 		String str3 = str1;
387 		String str4 = str1;
388 		String str5 = "There's nothing to trim here";
389 
390 		str1.TrimLeft();
391 		str2.TrimRight();
392 		str3.Trim();
393 		str4.Trim('|');
394 		str5.Trim();
395 
396 		assert(strcmp(str1, "This string is quite long and should be cut a little bit\r\n    ") == 0);
397 		assert(strcmp(str2, "\t   This string is quite long and should be cut a little bit") == 0);
398 		assert(strcmp(str3, "This string is quite long and should be cut a little bit") == 0);
399 		assert(strcmp(str4, "\t   This string is quite long and should be cut a little bit\r\n    ") == 0);
400 		assert(strcmp(str5, "There's nothing to trim here") == 0);
401 	}
402 
403 	// Test Truncate
404 	{
405 		String str1 = "long truncateable string";
406 		String str2 = str1;
407 		String str3 = str1;
408 		String str4 = str1;
409 		String str5 = str1;
410 
411 		str1.TruncateToLeft(4);
412 		str2.TruncateToRight(6);
413 		str3.TruncateToMid(5, 12);
414 		str4.TruncateToMid(5, 0);
415 		str5.TruncateToMid(0);
416 		assert(strcmp(str1, "long") == 0);
417 		assert(strcmp(str2, "string") == 0);
418 		assert(strcmp(str3, "truncateable") == 0);
419 		assert(strcmp(str4, "") == 0);
420 		assert(strcmp(str5, "long truncateable string") == 0);
421 	}
422 
423 	// Test TruncateToSection
424 	{
425 		String str1 = "C:\\Games\\AGS\\MyNewGame";
426 		String str2 = str1;
427 		String str3 = str1;
428 		String str4 = str1;
429 		String str5 = str1;
430 		String str6 = str1;
431 		String str7 = str1;
432 		String str8 = str1;
433 		String str9 = str1;
434 		String str10 = str1;
435 		String str11 = str1;
436 		String str12 = str1;
437 
438 		str1.TruncateToLeftSection('\\');
439 		str2.TruncateToLeftSection('\\', false);
440 		str3.TruncateToRightSection('\\');
441 		str4.TruncateToRightSection('\\', false);
442 		str5.TruncateToSection('\\', 1, 2);
443 		str6.TruncateToSection('\\', 1, 2, false, false);
444 		str7.TruncateToSection('|', 1, 3);
445 		str8.TruncateToSection('\\', 0, 2);
446 		str9.TruncateToSection('\\', 1, 3);
447 		str10.TruncateToSection('\\', 3, 1);
448 		str11.TruncateToSection('\\', 3, 3);
449 		str12.TruncateToSection('\\', 3, 3, false, false);
450 		assert(strcmp(str1, "C:") == 0);
451 		assert(strcmp(str2, "C:\\") == 0);
452 		assert(strcmp(str3, "MyNewGame") == 0);
453 		assert(strcmp(str4, "\\MyNewGame") == 0);
454 		assert(strcmp(str5, "Games\\AGS") == 0);
455 		assert(strcmp(str6, "\\Games\\AGS\\") == 0);
456 		assert(strcmp(str7, "") == 0);
457 		assert(strcmp(str8, "C:\\Games\\AGS") == 0);
458 		assert(strcmp(str9, "Games\\AGS\\MyNewGame") == 0);
459 		assert(strcmp(str10, "") == 0);
460 		assert(strcmp(str11, "MyNewGame") == 0);
461 		assert(strcmp(str12, "\\MyNewGame") == 0);
462 	}
463 
464 	// Test Split
465 	{
466 		String str1 = "C:\\Games\\AGS\\MyNewGame\\";
467 		std::vector<String> result = str1.Split('\\');
468 		assert(result.size() == 5);
469 		assert(strcmp(result[0], "C:") == 0);
470 		assert(strcmp(result[1], "Games") == 0);
471 		assert(strcmp(result[2], "AGS") == 0);
472 		assert(strcmp(result[3], "MyNewGame") == 0);
473 		assert(strcmp(result[4], "") == 0);
474 		String str2 = "test,,,test";
475 		result = str2.Split(',');
476 		assert(result.size() == 4);
477 		assert(strcmp(result[0], "test") == 0);
478 		assert(strcmp(result[1], "") == 0);
479 		assert(strcmp(result[2], "") == 0);
480 		assert(strcmp(result[3], "test") == 0);
481 		String str3 = ",,test,,";
482 		result = str3.Split(',');
483 		assert(result.size() == 5);
484 		assert(strcmp(result[0], "") == 0);
485 		assert(strcmp(result[1], "") == 0);
486 		assert(strcmp(result[2], "test") == 0);
487 		assert(strcmp(result[3], "") == 0);
488 		assert(strcmp(result[4], "") == 0);
489 	}
490 
491 	// Test Wrap
492 	{
493 		const char *cstr = "This is a string literal";
494 		String str1 = String::Wrapper(cstr);
495 		String str2 = str1;
496 		assert(str1.GetCStr() == cstr);
497 		assert(str2.GetCStr() == cstr);
498 		assert(str1.GetRefCount() == 0);
499 		assert(str2.GetRefCount() == 0);
500 		str2.SetAt(0, 'A');
501 		assert(str2.GetCStr() != cstr);
502 		assert(str2.GetRefCount() == 1);
503 	}
504 }
505 
506 } // namespace AGS3
507